Hono
Build a self-hosted Hot Updater server with Hono framework.
Installation
Install Hono.
npm install honoSetup and security
Set up a database adapter, generate its Hot Updater
schema, and apply the schema before starting the server. Define the
server in src/hotUpdater.ts with createHotUpdater, as in the
quick start.
The recommended self-hosted setup runs the apiKeys() plugin, which requires
an API key on update-check, Insights ingestion, and plugin client routes.
Always protect admin routes with framework middleware before mounting the admin
handler. Update-check routes are usually exposed for React Native clients, but
that is a deployment choice:
- Client OTA:
/hot-updater/release-catalogs/*,/hot-updater/artifacts/* - Optional public diagnostics:
/hot-updater/version - Protected admin API:
/hot-updater/admin/*
The handlers are separate by construction. Mounting handlers.admin opts the
server into the admin API; handlers.client never serves those routes. This
example requires a nonempty token before mounting the admin handler:
import { Hono } from "hono";
import { bearerAuth } from "hono/bearer-auth";
import { hotUpdater } from "./hotUpdater";
const app = new Hono();
const adminToken = process.env.HOT_UPDATER_ADMIN_TOKEN;
if (!adminToken) {
throw new Error("HOT_UPDATER_ADMIN_TOKEN is required");
}
app.use(
"/hot-updater/admin/*",
bearerAuth({ token: adminToken }),
);
app.mount("/hot-updater/admin", hotUpdater.handlers.admin);
app.mount("/hot-updater", hotUpdater.handlers.client);
export default app;Register the middleware first, then the specific admin mount, then the broader client mount. To run a client-only server, omit the admin middleware and admin mount entirely.
Set your auth token in environment variables:
HOT_UPDATER_ADMIN_TOKEN=your-secret-auth-tokenConfigure the CLI to include the auth token when deploying bundles, beside the config's storage and plugins; see CLI Configuration:
import { standaloneRepository } from "@hot-updater/standalone";
import { defineConfig } from "hot-updater";
const adminToken = process.env.HOT_UPDATER_ADMIN_TOKEN;
if (!adminToken) {
throw new Error("HOT_UPDATER_ADMIN_TOKEN is required");
}
export default defineConfig({
// ... build, storage, plugins, and updateStrategy
database: standaloneRepository({
baseUrl: "http://localhost:3000/hot-updater/admin",
commonHeaders: {
Authorization: `Bearer ${adminToken}`,
},
}),
});Handler boundaries
With insights() in plugins, handlers.client accepts Insights events and
handlers.admin serves Insights queries; without it, the server has no such
routes, and they answer 404. Apps send reports with the
Insights client plugin.
Server plugin endpoints mount on the same two
handlers. The client API key protects catalog reads, artifact resolution,
Insights ingestion, and plugin client routes; it does not protect or authorize
the admin handler.
See the shared handler boundary for route groups and the repository server contract for exact management requests. Keep the framework-specific authentication and mount ordering shown above.
Before connecting the app, verify that /hot-updater/version responds and an
admin request without the expected token is rejected. Then use
CLI configuration to
verify authenticated management access.
React Native setup
Create a client API key
against the prepared database, then follow Set up your app.
Use the client root as baseURL and send the key through x-api-key. Never
put the admin token in the app.
For local connectivity checks, localhost reaches the host from the iOS
Simulator on the same Mac and 10.0.2.2 does so from the Android Emulator.
Before a release-build OTA test, expose the server through a reachable HTTPS
endpoint and use it in the app; changing the host address does not enable
cleartext HTTP. Complete Test an OTA update
against that HTTPS endpoint.