68 lines · 3.1 KB
/**
 * `bun run deploy` preflight: refuses to deploy wrangler.jsonc while resource ids are still the all-zero
 * placeholders or the required production vars are empty, so a first deploy fails here with a readable list
 * instead of half-way through `wrangler deploy` (DEPLOY-P1). See docs/self-hosting.md "Production setup".
 */

type WranglerConfig = {
  vars?: Record<string, string>;
  d1_databases?: Array<{ binding: string; database_id?: string }>;
  kv_namespaces?: Array<{ binding: string; id?: string }>;
  secrets_store_secrets?: Array<{ binding: string; store_id?: string }>;
};

const PLACEHOLDER = /^[0-]*$/;

export function deployConfigProblems(config: WranglerConfig): string[] {
  const problems: string[] = [];
  const placeholder = (value: string | undefined) => !value || PLACEHOLDER.test(value);
  for (const db of config.d1_databases ?? []) {
    if (placeholder(db.database_id))
      problems.push(`D1 ${db.binding}: database_id is a placeholder (wrangler d1 create)`);
  }
  for (const kv of config.kv_namespaces ?? []) {
    if (placeholder(kv.id)) problems.push(`KV ${kv.binding}: id is a placeholder (wrangler kv namespace create)`);
  }
  for (const secret of config.secrets_store_secrets ?? []) {
    if (placeholder(secret.store_id)) {
      problems.push(`Secrets Store ${secret.binding}: store_id is a placeholder (wrangler secrets-store store create)`);
    }
  }
  const vars = config.vars ?? {};
  if (!vars.PUBLIC_URL?.startsWith("https://")) problems.push("vars.PUBLIC_URL must be your https:// forge URL");
  if (!vars.USERCONTENT_ORIGIN?.startsWith("https://")) {
    problems.push("vars.USERCONTENT_ORIGIN must be an https:// origin on a separate registrable domain");
  }
  if (vars.GITFOR_LOCAL !== undefined) problems.push("vars.GITFOR_LOCAL must not be set in wrangler.jsonc (dev only)");
  return problems;
}

/** Worth fixing before launch but not worth blocking a deploy over. */