mirror of
https://github.com/nestriness/nestri.git
synced 2026-09-19 09:15:19 +03:00
Moving the issuer's state into Postgres removed the last thing that tied either app to one hosting provider. What was left was a deployment tool describing resources that no longer existed — so this replaces it with `wrangler`, which is what actually deploys a Worker, and adds a second way to run each app that involves no provider at all. Each app now has a `wrangler.jsonc` with an environment per stage, and a `Dockerfile` beside it. The handler is the same one in both cases; what differs is only where its settings come from. Two of them gained a second spelling so that nothing has to branch on the runtime: Postgres arrives as a pooled binding or as `DATABASE_URL`, and the route to the issuer is a service binding or `AUTH_INTERNAL_URL`. That last one is new, and it is a split the binding was already making without saying so. `AUTH_ISSUER_URL` has to be the issuer's public name, because it is compared literally against every token's `iss` claim — but the public name is often not routable from inside a deployment. So the name and the route are two settings now rather than one that cannot be both. DNS moves out of code and into `docs/dns.md`, which lists every hostname and what it is for. Six records that change roughly never did not need a tool, and the table outlives whatever is answering the names — which is the point, since some of them will stop being Workers. The sandbox hostnames are hyphenated rather than nested for the same reason: a certificate covering `*.nestri.io` covers one label and not two, so `api-sandbox.nestri.io` can become an ordinary origin later without a certificate having to be ordered for it first. Also drops `EMAIL_DEV_LOG` from committed configuration into `.dev.vars`, which `wrangler deploy` cannot upload. Printing a live sign-in code to a log should not be one forgotten override away from production.
41 lines
1.4 KiB
TypeScript
41 lines
1.4 KiB
TypeScript
/**
|
|
* The API as an ordinary HTTP server.
|
|
*
|
|
* `index.ts` exports a handler taking `(request, env)` — the shape a Worker is
|
|
* invoked with, and also the shape of a plain function from a request to a
|
|
* response. So there is nothing here but the loop that calls it: the process
|
|
* environment stands in for the bindings, and a port stands in for the route.
|
|
*
|
|
* With no `AUTH` binding in that environment the middleware reaches the issuer
|
|
* over plain HTTP at `AUTH_ISSUER_URL`, which is a setting this deployment has
|
|
* either way. Nothing else differs.
|
|
*/
|
|
import handler, { type ApiEnv } from './index.js';
|
|
|
|
const port = Number(process.env.PORT ?? 3000);
|
|
|
|
Bun.serve({
|
|
port,
|
|
hostname: '0.0.0.0',
|
|
// A Worker runtime hands the handler a context whose `waitUntil` keeps the
|
|
// invocation alive past the response. A process does not need convincing to
|
|
// stay alive, so the equivalent is to let the promise run — with a catch,
|
|
// because an unobserved rejection here would take the server down rather
|
|
// than the request that caused it.
|
|
fetch: (request) =>
|
|
handler.fetch(
|
|
request,
|
|
process.env as unknown as ApiEnv,
|
|
{
|
|
waitUntil: (promise: Promise<unknown>) => {
|
|
void Promise.resolve(promise).catch((error: unknown) => {
|
|
console.error('[api] background task failed:', error);
|
|
});
|
|
},
|
|
passThroughOnException: () => {}
|
|
} as unknown as ExecutionContext
|
|
)
|
|
});
|
|
|
|
console.log(`[api] listening on http://0.0.0.0:${port}`);
|