From ccd5adaf0a1e2b47364dffe619edffa4bf310404 Mon Sep 17 00:00:00 2001 From: mathuraditya724 Date: Wed, 9 Sep 2026 23:31:12 +0530 Subject: [PATCH] fix(tooling): Use D1 token for production migrations --- apps/server/.env.example | 4 ++- apps/server/package.json | 2 +- apps/server/scripts/migrate-prod-d1.ts | 41 ++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 apps/server/scripts/migrate-prod-d1.ts diff --git a/apps/server/.env.example b/apps/server/.env.example index eea8521..58b1408 100644 --- a/apps/server/.env.example +++ b/apps/server/.env.example @@ -46,7 +46,9 @@ GITHUB_APP_ID= GITHUB_APP_PRIVATE_KEY= GITHUB_APP_WEBHOOK_SECRET= -# For running drizzle studio for prod +# For production D1 tooling. `db:migrate:prod` maps the dedicated D1 token to +# Wrangler's CLOUDFLARE_API_TOKEN only for its child process; never use it as a +# Worker runtime secret. The token requires Account > D1 > Edit on the target account. CLOUDFLARE_ACCOUNT_ID= DATABASE= CLOUDFLARE_D1_API_TOKEN= diff --git a/apps/server/package.json b/apps/server/package.json index 002c200..373e1df 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -10,7 +10,7 @@ "db:generate": "drizzle-kit generate", "db:cleanup:dev": "tsx ./scripts/cleanup.ts", "db:migrate:dev": "wrangler d1 migrations apply --local jared", - "db:migrate:prod": "NODE_ENV=production wrangler d1 migrations apply --remote jared", + "db:migrate:prod": "tsx ./scripts/migrate-prod-d1.ts", "db:studio:dev": "drizzle-kit studio", "db:studio:prod": "NODE_ENV=production drizzle-kit studio", "sync:skills": "node container/scripts/sync-skills.mjs", diff --git a/apps/server/scripts/migrate-prod-d1.ts b/apps/server/scripts/migrate-prod-d1.ts new file mode 100644 index 0000000..3a19ead --- /dev/null +++ b/apps/server/scripts/migrate-prod-d1.ts @@ -0,0 +1,41 @@ +import { spawn } from "node:child_process" +import { fileURLToPath } from "node:url" +import { config } from "dotenv" + +const serverRoot = fileURLToPath(new URL("..", import.meta.url)) + +// Keep the D1 credential local to migration tooling. Wrangler only recognizes +// CLOUDFLARE_API_TOKEN, so map the dedicated token in the child process rather +// than exposing it to the Worker runtime or shell history. +config({ path: `${serverRoot}.env` }) + +const d1Token = process.env.CLOUDFLARE_D1_API_TOKEN +const accountId = process.env.CLOUDFLARE_ACCOUNT_ID + +if (!d1Token) { + throw new Error("CLOUDFLARE_D1_API_TOKEN must be set to run production D1 migrations") +} + +if (!accountId) { + throw new Error("CLOUDFLARE_ACCOUNT_ID must be set to run production D1 migrations") +} + +const pnpm = process.platform === "win32" ? "pnpm.cmd" : "pnpm" +const child = spawn(pnpm, ["exec", "wrangler", "d1", "migrations", "apply", "jared", "--remote"], { + cwd: serverRoot, + env: { + ...process.env, + CLOUDFLARE_API_TOKEN: d1Token, + CLOUDFLARE_ACCOUNT_ID: accountId, + }, + stdio: "inherit", +}) + +child.once("error", (error) => { + console.error(`Unable to start Wrangler: ${error.message}`) + process.exitCode = 1 +}) + +child.once("exit", (code) => { + process.exitCode = code ?? 1 +})