From a6df6a435e7cd8edd21c42b5f6aea5ca3b18a393 Mon Sep 17 00:00:00 2001 From: Devin Zuczek Date: Tue, 30 Jun 2026 15:00:22 -0400 Subject: [PATCH] naming cleanup and readme changes --- .env.example | 4 +- README.md | 75 +++++++++++++++++++++++++++++++++-- apps/notify/src/context.ts | 2 +- apps/notify/src/notify.app.ts | 6 +-- apps/notify/wrangler.jsonc | 2 +- 5 files changed, 78 insertions(+), 11 deletions(-) diff --git a/.env.example b/.env.example index d31dfd9..922f61d 100644 --- a/.env.example +++ b/.env.example @@ -3,7 +3,7 @@ RECFLARE_DOMAIN=rec.example.com # Optional per-app subdomain overrides, as a compact JSON object keyed by the # worker's directory name. Defaults to the directory name when unset. -# RECFLARE_SUBDOMAINS={"playersettings":"settings"} +# RECFLARE_SUBDOMAINS='{"playersettings":"settings"}' # Id of the shared `recflare` D1 database (create it manually with # `wrangler d1 create recflare`). All D1-backed workers bind this one database. @@ -15,4 +15,4 @@ RECFLARE_DOMAIN=rec.example.com # is distinct (create with `wrangler kv namespace create `). Kept out of # the committed wrangler.jsonc (which uses "local" placeholders) and spliced in at # deploy time. Required to deploy any worker with the matching KV binding. -# RECFLARE_KV={"RECFLARE_MATCH_PRESENCE":"9f53f04b7dd244658d59f515a14748b6","RECFLARE_PLAYER_SETTINGS":"d33a90014e904b0eac720bddcbe0b036"} +# RECFLARE_KV='{"RECFLARE_MATCH_PRESENCE":"9f53f04b7dd244658d59f515a14748b6","RECFLARE_PLAYER_SETTINGS":"d33a90014e904b0eac720bddcbe0b036"}' diff --git a/README.md b/README.md index deb7bbe..711d8f9 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,72 @@ document and the api share-link base URL are built at runtime. Nothing in versio control is rewritten; committed `wrangler.jsonc` files have no routes. Per-app subdomain overrides come from -`RECFLARE_SUBDOMAINS` (a JSON object, e.g. `{"playersettings":"settings"}`). +`RECFLARE_SUBDOMAINS` (a JSON object, e.g. `'{"playersettings":"settings"}'`). + +**Create the storage resources:** + +The workers bind Cloudflare storage primitives — one shared D1 database, two KV +namespaces, two R2 buckets, and a Durable Object. Create them once against your +Cloudflare account, then record the ids in `.env`. The committed `wrangler.jsonc` +files carry `"local"` placeholders; the real ids are spliced in at deploy time, so +nothing in version control needs editing. Authenticate wrangler first +(`wrangler login`). + +_D1 — one shared `recflare` database_ (bound by `api`, `accounts`, `auth`, `match`, +`rooms`): + +```bash +wrangler d1 create recflare +# copy the printed database_id into .env: +# RECFLARE_D1= +``` + +Then apply the schema. The `rooms` and `auth` workers own the migrations under +their `apps//migrations/` directories. Remote operations need the real id +in the config (the committed file only has the `"local"` placeholder), so splice +it in the same way the deploy does — from each owning worker, with `RECFLARE_D1` +exported: + +```bash +cd apps/rooms # then repeat for apps/auth +sed -E "s/\"database_id\": *\"local\"/\"database_id\": \"$RECFLARE_D1\"/" \ + wrangler.jsonc >wrangler.generated.jsonc +wrangler d1 migrations apply recflare --remote --config wrangler.generated.jsonc +rm wrangler.generated.jsonc +``` + +For the local dev database no id is needed — it uses the `"local"` placeholder +directly: `wrangler d1 migrations apply recflare --local`. + +_KV — two namespaces_ (`RECFLARE_MATCH_PRESENCE` for `match`/`auth`, +`RECFLARE_PLAYER_SETTINGS` for `playersettings`): + +```bash +wrangler kv namespace create RECFLARE_MATCH_PRESENCE +wrangler kv namespace create RECFLARE_PLAYER_SETTINGS +``` + +Record both ids in `.env` as a single JSON object keyed by binding name (note the +surrounding single quotes — without them the shell strips the inner quotes): + +```bash +RECFLARE_KV='{"RECFLARE_MATCH_PRESENCE":"","RECFLARE_PLAYER_SETTINGS":""}' +``` + +_R2 — two buckets_ (`recflare-cdn` for `cdn`, `recflare-img` for `api`/`img`): + +```bash +wrangler r2 bucket create recflare-cdn +wrangler r2 bucket create recflare-img +``` + +R2 buckets are referenced by name in the committed `wrangler.jsonc`, so there is +nothing to add to `.env`. See [`apps/img/README.md`](apps/img/README.md) for +seeding the default avatar/profile images. + +_Durable Objects — no manual setup_. The `notify` worker's `RECFLARE_NOTIFICATIONS_HUB` +binding (class `NotificationsHub`) is provisioned automatically from the migration +declared in its `wrangler.jsonc` on first deploy — there is no id to create or set. **Run the development microservices:** @@ -191,9 +256,11 @@ just deploy Deploying requires `wrangler` to be authenticated against your Cloudflare account (`wrangler login`, or `CLOUDFLARE_API_TOKEN` / `CLOUDFLARE_ACCOUNT_ID` -in the environment). Storage resources (D1 databases, KV namespaces, R2 buckets) -must be created and their ids set in each worker's `wrangler.jsonc` — see the -inline comments in those files for the exact `wrangler` commands. +in the environment). It also requires the storage resources to exist and their +ids to be set in `.env` — see **Create the storage resources** above. At deploy +time the deploy script splices `RECFLARE_D1` and `RECFLARE_KV` into the `"local"` +placeholders in each worker's `wrangler.jsonc`; a missing id fails the deploy with +a message naming the binding. ## Repository Structure diff --git a/apps/notify/src/context.ts b/apps/notify/src/context.ts index 7ba7e50..3f7d164 100644 --- a/apps/notify/src/context.ts +++ b/apps/notify/src/context.ts @@ -4,7 +4,7 @@ import type { SharedHonoEnv, SharedHonoVariables } from '@repo/hono-helpers/src/ export type Env = SharedHonoEnv & { /** Durable Object hosting the SignalR notifications hub. */ - NOTIFICATIONS_HUB: DurableObjectNamespace + RECFLARE_NOTIFICATIONS_HUB: DurableObjectNamespace } /** Variables can be extended */ diff --git a/apps/notify/src/notify.app.ts b/apps/notify/src/notify.app.ts index 9a1e3bb..87becb2 100644 --- a/apps/notify/src/notify.app.ts +++ b/apps/notify/src/notify.app.ts @@ -52,7 +52,7 @@ const app = new Hono() if ((c.req.header('upgrade') ?? '').toLowerCase() !== 'websocket') { return c.json({ error: 'Expected a WebSocket upgrade request' }, 426) } - return c.env.NOTIFICATIONS_HUB.getByName(HUB_INSTANCE).fetch(c.req.raw) + return c.env.RECFLARE_NOTIFICATIONS_HUB.getByName(HUB_INSTANCE).fetch(c.req.raw) }) // ---- Internal service-to-service send/broadcast -------------------------- @@ -65,7 +65,7 @@ const app = new Hono() if (!body || typeof body.playerId !== 'number' || typeof body.notificationType !== 'number') { return c.json({ error: 'playerId and notificationType are required' }, 400) } - const result = await c.env.NOTIFICATIONS_HUB.getByName(HUB_INSTANCE).notifyPlayer( + const result = await c.env.RECFLARE_NOTIFICATIONS_HUB.getByName(HUB_INSTANCE).notifyPlayer( body.playerId, body.notificationType, body.data @@ -80,7 +80,7 @@ const app = new Hono() if (!body || typeof body.notificationType !== 'number') { return c.json({ error: 'notificationType is required' }, 400) } - const result = await c.env.NOTIFICATIONS_HUB.getByName(HUB_INSTANCE).broadcast( + const result = await c.env.RECFLARE_NOTIFICATIONS_HUB.getByName(HUB_INSTANCE).broadcast( body.notificationType, body.data ) diff --git a/apps/notify/wrangler.jsonc b/apps/notify/wrangler.jsonc index 7292691..385b3e6 100644 --- a/apps/notify/wrangler.jsonc +++ b/apps/notify/wrangler.jsonc @@ -5,7 +5,7 @@ "compatibility_date": "2025-09-20", "compatibility_flags": ["nodejs_compat"], "durable_objects": { - "bindings": [{ "name": "NOTIFICATIONS_HUB", "class_name": "NotificationsHub" }] + "bindings": [{ "name": "RECFLARE_NOTIFICATIONS_HUB", "class_name": "NotificationsHub" }] }, "migrations": [{ "tag": "v1", "new_sqlite_classes": ["NotificationsHub"] }], "logpush": false,