diff --git a/.env.example b/.env.example index e57bbf0..d31dfd9 100644 --- a/.env.example +++ b/.env.example @@ -10,3 +10,9 @@ RECFLARE_DOMAIN=rec.example.com # Kept out of the committed wrangler.jsonc (which uses a "local" placeholder) and # spliced in at deploy time. Required to deploy any worker that uses D1. # RECFLARE_D1=d44083e1-5bfe-4467-aa9a-f13c5c2496d5 + +# KV namespace ids, as a compact JSON object keyed by binding name. Each namespace +# 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"} diff --git a/.gitignore b/.gitignore index 61601bb..96672eb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ # Wrangler .wrangler .dev.vars -wrangler.generated.jsonc +wrangler.generated.* # Astro generated types .astro/ diff --git a/apps/auth/wrangler.jsonc b/apps/auth/wrangler.jsonc index 8c320f0..23037b6 100644 --- a/apps/auth/wrangler.jsonc +++ b/apps/auth/wrangler.jsonc @@ -23,7 +23,7 @@ "kv_namespaces": [ { "binding": "RECFLARE_MATCH_PRESENCE", - "id": "9f53f04b7dd244658d59f515a14748b6" + "id": "local" } ], "logpush": false, diff --git a/apps/match/wrangler.jsonc b/apps/match/wrangler.jsonc index f9120ed..6d9e8d6 100644 --- a/apps/match/wrangler.jsonc +++ b/apps/match/wrangler.jsonc @@ -4,12 +4,14 @@ "main": "src/match.app.ts", "compatibility_date": "2025-09-20", "compatibility_flags": ["nodejs_compat"], - // Per-player presence store (room instance the player is currently in). - // Create with `wrangler kv namespace create RECFLARE_MATCH_PRESENCE` and set the id. + // Per-player presence store (room instance the player is currently in). Create + // with `wrangler kv namespace create RECFLARE_MATCH_PRESENCE`, then put the id in + // the root .env under RECFLARE_KV (see .env.example) — it is spliced into the + // "local" placeholder below at deploy time. "kv_namespaces": [ { "binding": "RECFLARE_MATCH_PRESENCE", - "id": "9f53f04b7dd244658d59f515a14748b6" + "id": "local" } ], // Shared `recflare` DB (bound read-only here). The "local" placeholder is replaced diff --git a/apps/playersettings/README.md b/apps/playersettings/README.md index 62830f5..23f2bf7 100644 --- a/apps/playersettings/README.md +++ b/apps/playersettings/README.md @@ -18,7 +18,7 @@ Player-settings worker served on the `playersettings` subdomain. ## KV namespace ```sh -wrangler kv namespace create RECFLARE_PLAYER_SETTINGS # then put the id in wrangler.jsonc +wrangler kv namespace create RECFLARE_PLAYER_SETTINGS # then put the id in .env under RECFLARE_KV (see .env.example) ``` ## Development diff --git a/apps/playersettings/wrangler.jsonc b/apps/playersettings/wrangler.jsonc index 204cb4e..7f75582 100644 --- a/apps/playersettings/wrangler.jsonc +++ b/apps/playersettings/wrangler.jsonc @@ -8,7 +8,7 @@ "kv_namespaces": [ { "binding": "RECFLARE_PLAYER_SETTINGS", - "id": "d33a90014e904b0eac720bddcbe0b036" + "id": "local" } ], "upload_source_maps": true, diff --git a/packages/tools/bin/run-wrangler-deploy b/packages/tools/bin/run-wrangler-deploy index c4479da..a6f434b 100755 --- a/packages/tools/bin/run-wrangler-deploy +++ b/packages/tools/bin/run-wrangler-deploy @@ -37,24 +37,69 @@ DIR=$(basename "$PWD") SUBDOMAIN=$(printf '%s' "$SUBDOMAINS_JSON" | jq -r --arg d "$DIR" '.[$d] // $d') HOST="$SUBDOMAIN.$DOMAIN" -# Splice the shared `recflare` D1 database id from RECFLARE_D1 into a generated -# config. All D1-backed workers bind the same database, so RECFLARE_D1 is a single -# id. The committed wrangler.jsonc carries a "local" placeholder so it needs no -# per-developer edits; the real id stays in the gitignored .env / CI secrets. -# Workers without a D1 binding simply have no placeholder to replace. +# Splice deploy-time resource ids into a generated config. The committed +# wrangler.jsonc carries "local" placeholders so it needs no per-developer edits; +# the real ids stay in the gitignored .env / CI secrets. Workers without these +# bindings simply have no placeholder to replace. +# +# D1 — RECFLARE_D1: a single id (all workers share the one `recflare` database). +# KV — RECFLARE_KV: a JSON object keyed by binding name, since each KV namespace +# is distinct, e.g. {"RECFLARE_MATCH_PRESENCE":"…","RECFLARE_PLAYER_SETTINGS":"…"}. CONFIG="wrangler.jsonc" -if grep -q '"database_id": *"local"' wrangler.jsonc 2>/dev/null; then - DB_ID=${RECFLARE_D1:-} - if [ -z "$DB_ID" ]; then - echo "error: RECFLARE_D1 is not set — add the recflare D1 id to .env (see .env.example)" >&2 - exit 1 - fi +NEEDS_D1=$(grep -q '"database_id": *"local"' wrangler.jsonc 2>/dev/null && echo 1 || true) +NEEDS_KV=$(grep -q '"id": *"local"' wrangler.jsonc 2>/dev/null && echo 1 || true) + +if [ -n "$NEEDS_D1" ] || [ -n "$NEEDS_KV" ]; then CONFIG="wrangler.generated.jsonc" # Generated alongside the original so its relative paths (main, migrations_dir) # still resolve. Gitignored; removed on exit so `wrangler dev` is unaffected. - trap 'rm -f wrangler.generated.jsonc' EXIT - sed -E 's/("database_id"[[:space:]]*:[[:space:]]*")[^"]*(")/\1'"$DB_ID"'\2/' \ - wrangler.jsonc >wrangler.generated.jsonc + trap 'rm -f wrangler.generated.jsonc wrangler.generated.tmp' EXIT + cp wrangler.jsonc wrangler.generated.jsonc + + if [ -n "$NEEDS_D1" ]; then + DB_ID=${RECFLARE_D1:-} + if [ -z "$DB_ID" ]; then + echo "error: RECFLARE_D1 is not set — add the recflare D1 id to .env (see .env.example)" >&2 + exit 1 + fi + sed -E 's/("database_id"[[:space:]]*:[[:space:]]*")[^"]*(")/\1'"$DB_ID"'\2/' \ + wrangler.generated.jsonc >wrangler.generated.tmp + mv wrangler.generated.tmp wrangler.generated.jsonc + fi + + if [ -n "$NEEDS_KV" ]; then + KV_JSON=${RECFLARE_KV:-} + [ -n "$KV_JSON" ] || KV_JSON='{}' + # Map binding name -> id, then replace each kv_namespaces `"id": "local"` + # with the id for its nearest preceding "binding" line. awk keeps state so + # multiple namespaces in one file each get the right id. + KV_PAIRS=$(printf '%s' "$KV_JSON" | jq -r 'to_entries[] | "\(.key)\t\(.value)"') + awk -v pairs="$KV_PAIRS" ' + BEGIN { + n = split(pairs, lines, "\n") + for (i = 1; i <= n; i++) { + if (lines[i] == "") continue + t = index(lines[i], "\t") + id[substr(lines[i], 1, t - 1)] = substr(lines[i], t + 1) + } + } + /"binding"[[:space:]]*:/ { + b = $0 + sub(/.*"binding"[[:space:]]*:[[:space:]]*"/, "", b) + sub(/".*/, "", b) + curbind = b + } + /"id"[[:space:]]*:[[:space:]]*"local"/ { + if (!(curbind in id)) { + print "error: no KV id for binding [" curbind "] in RECFLARE_KV — add it to .env (see .env.example)" >"/dev/stderr" + exit 3 + } + sub(/"local"/, "\"" id[curbind] "\"") + } + { print } + ' wrangler.generated.jsonc >wrangler.generated.tmp || exit 1 + mv wrangler.generated.tmp wrangler.generated.jsonc + fi fi # Deploy with wrangler using the extracted values as binding variables