@dragonmastery/tamer 0.34.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{apply-BsVQ9cbK.mjs → apply-B2wMY64Q.mjs} +10 -10
- package/dist/{apply-BsVQ9cbK.mjs.map → apply-B2wMY64Q.mjs.map} +1 -1
- package/dist/{applyTarget-BJlVrED9.mjs → applyTarget-KBomh7SL.mjs} +2 -2
- package/dist/{applyTarget-BJlVrED9.mjs.map → applyTarget-KBomh7SL.mjs.map} +1 -1
- package/dist/{bootstrap-CV6OT-c9.mjs → bootstrap-C7CZYHzb.mjs} +7 -7
- package/dist/bootstrap-C7CZYHzb.mjs.map +1 -0
- package/dist/{cloudflareSnapshot-CMbPQIsN.mjs → cloudflareSnapshot-BVlpH5K6.mjs} +3 -3
- package/dist/{cloudflareSnapshot-CMbPQIsN.mjs.map → cloudflareSnapshot-BVlpH5K6.mjs.map} +1 -1
- package/dist/{deploy-dNygCucr.mjs → deploy-C4Mi_qwz.mjs} +7 -7
- package/dist/{deploy-dNygCucr.mjs.map → deploy-C4Mi_qwz.mjs.map} +1 -1
- package/dist/{destroy-C0cKkpWe.mjs → destroy-DDVWxl7U.mjs} +18 -12
- package/dist/destroy-DDVWxl7U.mjs.map +1 -0
- package/dist/{destroy-tenant-hyEb1gEz.mjs → destroy-tenant-DL99EoRZ.mjs} +2 -2
- package/dist/{destroy-tenant-hyEb1gEz.mjs.map → destroy-tenant-DL99EoRZ.mjs.map} +1 -1
- package/dist/{dev-Bug5l5OZ.mjs → dev-BiPXBOKk.mjs} +6 -6
- package/dist/{dev-Bug5l5OZ.mjs.map → dev-BiPXBOKk.mjs.map} +1 -1
- package/dist/{doctor-BwuEPYM6.mjs → doctor-DDwsA2V6.mjs} +2 -2
- package/dist/{doctor-BwuEPYM6.mjs.map → doctor-DDwsA2V6.mjs.map} +1 -1
- package/dist/{drift-DENAf1Oe.mjs → drift-DqMtlwkg.mjs} +4 -4
- package/dist/{drift-B5y9LF5X.mjs → drift-RpShXwG7.mjs} +5 -5
- package/dist/{drift-B5y9LF5X.mjs.map → drift-RpShXwG7.mjs.map} +1 -1
- package/dist/{emit-DTpaIMkn.mjs → emit-BUPlQH-r.mjs} +2 -2
- package/dist/{emit-DTpaIMkn.mjs.map → emit-BUPlQH-r.mjs.map} +1 -1
- package/dist/{events-B7Lencm8.mjs → events-D9kQWwH8.mjs} +2 -2
- package/dist/{events-B7Lencm8.mjs.map → events-D9kQWwH8.mjs.map} +1 -1
- package/dist/{generator-ZTEeHlft.mjs → generator-BCcu_eoO.mjs} +2 -2
- package/dist/{generator-ZTEeHlft.mjs.map → generator-BCcu_eoO.mjs.map} +1 -1
- package/dist/{import-Ciq9MN3v.mjs → import-DHmLtue3.mjs} +3 -3
- package/dist/{import-Ciq9MN3v.mjs.map → import-DHmLtue3.mjs.map} +1 -1
- package/dist/{migrate-DWyUVN1I.mjs → migrate-36WDEaFz.mjs} +4 -4
- package/dist/{migrate-DWyUVN1I.mjs.map → migrate-36WDEaFz.mjs.map} +1 -1
- package/dist/{plan-Blxn-yKr.mjs → plan-k0jLGYyw.mjs} +8 -8
- package/dist/{plan-Blxn-yKr.mjs.map → plan-k0jLGYyw.mjs.map} +1 -1
- package/dist/{provision-tenant-BHDWTC2U.mjs → provision-tenant-BjFpVm-y.mjs} +6 -5
- package/dist/provision-tenant-BjFpVm-y.mjs.map +1 -0
- package/dist/{registry-BlHEOKlN.mjs → registry-DyToEush.mjs} +2 -2
- package/dist/{registry-BlHEOKlN.mjs.map → registry-DyToEush.mjs.map} +1 -1
- package/dist/{status-PlMHsDzT.mjs → status-DaaOPBEf.mjs} +3 -3
- package/dist/{status-PlMHsDzT.mjs.map → status-DaaOPBEf.mjs.map} +1 -1
- package/dist/{sync-YKZ5HD8v.mjs → sync-DEudPgQc.mjs} +4 -4
- package/dist/{sync-YKZ5HD8v.mjs.map → sync-DEudPgQc.mjs.map} +1 -1
- package/dist/tamer.mjs +135 -85
- package/dist/tamer.mjs.map +1 -1
- package/dist/tamerArtifactsR2-7qUbhOLD.mjs +51 -0
- package/dist/tamerArtifactsR2-7qUbhOLD.mjs.map +1 -0
- package/dist/{types-CADr4Kck.mjs → types-BQajHdJb.mjs} +4 -4
- package/dist/{types-CADr4Kck.mjs.map → types-BQajHdJb.mjs.map} +1 -1
- package/dist/{verifyPlanFile-BBAwWzUo.mjs → verifyPlanFile-CpxwOxrV.mjs} +2 -2
- package/dist/{verifyPlanFile-BBAwWzUo.mjs.map → verifyPlanFile-CpxwOxrV.mjs.map} +1 -1
- package/dist/{wfp-delete-CQc9tveU.mjs → wfp-delete-DsfqSBxt.mjs} +2 -2
- package/dist/{wfp-delete-CQc9tveU.mjs.map → wfp-delete-DsfqSBxt.mjs.map} +1 -1
- package/dist/{wfp-put-CVw8cloM.mjs → wfp-put-DX_bH-s7.mjs} +2 -2
- package/dist/{wfp-put-CVw8cloM.mjs.map → wfp-put-DX_bH-s7.mjs.map} +1 -1
- package/dist/{worker-route-CqBDvjgo.mjs → worker-route-CUQBu9xe.mjs} +2 -2
- package/dist/{worker-route-CqBDvjgo.mjs.map → worker-route-CUQBu9xe.mjs.map} +1 -1
- package/dist/{workers-y9RTOzbC.mjs → workers-BjDCuyVv.mjs} +2 -2
- package/dist/{workers-y9RTOzbC.mjs.map → workers-BjDCuyVv.mjs.map} +1 -1
- package/package.json +6 -2
- package/dist/bootstrap-CV6OT-c9.mjs.map +0 -1
- package/dist/destroy-C0cKkpWe.mjs.map +0 -1
- package/dist/provision-tenant-BHDWTC2U.mjs.map +0 -1
- package/dist/tamerArtifactsR2-Ba29OVp9.mjs +0 -52
- package/dist/tamerArtifactsR2-Ba29OVp9.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"destroy-DDVWxl7U.mjs","names":[],"sources":["../src/features/dispatch-namespace/dispatch-namespace.destroy.ts","../src/features/dns-records/dns-records.destroy.ts","../src/cli/destroyGuard.ts","../src/cli/commands/destroy.ts"],"sourcesContent":["import type { CfiConfig } from \"../../types.js\";\nimport { getDispatchNamespaces } from \"../../types.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { DispatchNamespaceStateEntry } from \"../../types.js\";\nimport { isEphemeralEnv } from \"./dispatch-namespace.resolve.js\";\n\n/**\n * Tear down every dispatch namespace recorded in state.\n *\n * Cloudflare refuses to delete a namespace that still contains scripts, so we\n * enumerate `/dispatch/namespaces/{ns}/scripts` and delete each (with `force`\n * so dependents like service-bind targets don't block the removal). This\n * covers tenant scripts uploaded by `tamer wfp put` / `provision-workflow`\n * that aren't otherwise tracked in Tamer state.\n */\nexport async function dispatchNamespaceDestroy(\n env: string,\n state: StateManager,\n api: CFApiClient,\n config: CfiConfig,\n _force?: boolean,\n): Promise<void> {\n const allowedLogical = new Set(\n getDispatchNamespaces(config).map((d) => d.logicalName),\n );\n if (allowedLogical.size === 0) return;\n\n for (const [key, entry] of Object.entries(state.getAll())) {\n if (entry.type !== \"dispatch_namespace\") continue;\n const ns = entry as DispatchNamespaceStateEntry;\n if (!allowedLogical.has(ns.logicalName)) continue;\n const isSharedEphemeral = ns.derivedName.endsWith(\"-ephemeral\");\n try {\n const scripts = await api.dispatchNamespaceScriptList(ns.derivedName);\n for (const s of scripts) {\n if (isEphemeralEnv(env, config.tenant) && isSharedEphemeral) {\n if (!s.id.endsWith(`-${env}`)) continue;\n }\n try {\n await api.dispatchNamespaceScriptDelete(ns.derivedName, s.id, {\n force: true,\n });\n console.log(\n `Deleted tenant script \"${s.id}\" from namespace ${ns.derivedName}.`,\n );\n } catch (err) {\n console.warn(\n `Failed to delete tenant script ${s.id} in ${ns.derivedName}:`,\n err instanceof Error ? err.message : err,\n );\n }\n }\n if (isEphemeralEnv(env, config.tenant) && isSharedEphemeral) {\n console.log(\n `Left shared dispatch namespace ${ns.derivedName} (removed only scripts suffixed -${env}).`,\n );\n continue;\n }\n await api.dispatchNamespaceDelete(ns.derivedName);\n state.delete(key);\n } catch (err) {\n console.warn(\n `Failed to delete dispatch namespace ${ns.derivedName}:`,\n err instanceof Error ? err.message : err,\n );\n }\n }\n}\n","import type { CfiConfig, DnsRecordStateEntry } from \"../../types.js\";\nimport { getDnsRecords } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\n\n/**\n * Tear down every DNS record this stack owns. Restricted to records\n * whose `logicalName` is declared in the current `CfiConfig.dnsRecords`\n * (matches `runDestroy` semantics for shared state rows). Records flagged\n * `preserveOnDestroy: true` are left in place but still dropped from\n * state — the operator is responsible for re-importing them later.\n */\nexport async function dnsRecordDestroy(\n env: string,\n state: StateManager,\n api: CFApiClient,\n config: CfiConfig,\n _force?: boolean,\n): Promise<void> {\n if (env === \"local\") return;\n const declared = getDnsRecords(config);\n if (declared.length === 0) return;\n const preserve = new Map<string, boolean>(\n declared.map((c) => [c.logicalName, !!c.preserveOnDestroy]),\n );\n const allowedLogical = new Set(declared.map((c) => c.logicalName));\n\n for (const [key, entry] of Object.entries(state.getAll())) {\n if (entry.type !== \"dns_record\") continue;\n const rec = entry as DnsRecordStateEntry;\n if (!allowedLogical.has(rec.logicalName)) continue;\n if (preserve.get(rec.logicalName)) {\n console.log(\n `Preserved DNS record ${rec.recordType} ${rec.name} (preserveOnDestroy).`,\n );\n state.delete(key);\n continue;\n }\n try {\n await api.zoneDnsRecordDelete(rec.zoneId, rec.recordId);\n state.delete(key);\n } catch (err) {\n console.warn(\n `Failed to delete DNS record ${rec.recordType} ${rec.name}:`,\n err instanceof Error ? err.message : err,\n );\n }\n }\n}\n","/** Shared envs where destroy must be confirmed with `--confirm-env <same>`. */\nexport const SHARED_ENV_DESTROY = [\n \"dev\",\n \"staging\",\n \"prod\",\n \"production\",\n] as const;\n\n/**\n * @param force When true, skips the typed confirmation (break-glass).\n */\nexport function assertDestroyEnvAllowed(\n env: string,\n force: boolean,\n confirmEnv?: string,\n): void {\n if (force) return;\n if (!SHARED_ENV_DESTROY.includes(env as (typeof SHARED_ENV_DESTROY)[number])) {\n return;\n }\n if (confirmEnv !== env) {\n throw new Error(\n `Destroying shared environment \"${env}\" requires --confirm-env ${env}`,\n );\n }\n}\n","import { loadConfig, getWorkers } from \"../../core/config/loader.js\";\nimport { logicalNamesForResourceKind } from \"../../core/config/resourcesFromConfig.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { deleteEnvStateRows } from \"../../core/state/tamerStateDb.js\";\nimport { deleteEnvArtifacts } from \"../../core/state/tamerArtifactsR2.js\";\nimport { deleteEnvSecretRows } from \"../../core/secrets/secretsDb.js\";\nimport { getDispatchNamespaces, getDnsRecords } from \"../../types.js\";\nimport { logpushJobDestroy } from \"../../features/logpush-job/index.js\";\nimport { assertDestroyEnvAllowed } from \"../destroyGuard.js\";\nimport { dispatchNamespaceDestroy } from \"../../features/dispatch-namespace/index.js\";\nimport { dnsRecordDestroy } from \"../../features/dns-records/index.js\";\nimport { workersDestroy } from \"../../features/workers/index.js\";\nimport { workerRoutesDestroy } from \"../../features/worker-route/index.js\";\nimport { runSync } from \"./sync.js\";\nimport { resourceModules } from \"../../core/registry/registry.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport { verifyPlanFile } from \"../../core/plan/verifyPlanFile.js\";\nimport { hashCloudflareSnapshot } from \"../../core/plan/planFile.js\";\nimport { buildCloudflareSnapshot } from \"../../core/plan/cloudflareSnapshot.js\";\n\nexport async function runDestroy(options: {\n env: string;\n force?: boolean;\n skipWorkers?: boolean;\n confirmEnv?: string;\n configPath?: string;\n /** When true, delete the shared `tamer-state-{env}` D1 after other resources (use on last stack teardown). */\n wipeMetadata?: boolean;\n /**\n * Path to a destroy plan file from `tamer plan --destroy --out`. Destroy\n * recomputes the `(config, state, cloudflare)` attestation hashes and\n * refuses to proceed if any drifted (override with `allowStale`). The\n * pinned plan ensures the operator destroys exactly what they reviewed.\n */\n planFile?: string;\n allowStale?: boolean;\n}): Promise<void> {\n const {\n env,\n force = false,\n skipWorkers = false,\n confirmEnv,\n configPath,\n wipeMetadata = false,\n } = options;\n const baseDir = process.cwd();\n\n assertDestroyEnvAllowed(env, force, confirmEnv);\n\n const config = await loadConfig(configPath, { env });\n const accountId =\n config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n if (options.planFile) {\n const verifyApi = new CFApiClient(accountId);\n const verifyState = new StateManager(\n config.tenant.id,\n env,\n stackNameForConfig(config),\n );\n await verifyState.hydrate(verifyApi);\n const liveSnapshot =\n env === \"local\"\n ? undefined\n : await buildCloudflareSnapshot({\n config,\n env,\n api: verifyApi,\n baseDir,\n });\n verifyPlanFile({\n planPath: options.planFile,\n command: \"destroy\",\n expectedMode: \"destroy\",\n env,\n tenantId: config.tenant.id,\n config,\n stateAtPlanCheck: verifyState.load(),\n liveCloudflareHash: liveSnapshot\n ? hashCloudflareSnapshot(liveSnapshot)\n : undefined,\n allowStale: !!options.allowStale,\n });\n }\n\n if (env !== \"local\") {\n console.log(`Syncing state from Cloudflare for env: ${env}...`);\n await runSync({ env, configPath });\n }\n\n const api = new CFApiClient(accountId);\n const naming = namingFromConfig(config);\n const state = new StateManager(\n config.tenant.id,\n env,\n stackNameForConfig(config),\n );\n await state.hydrate(api);\n state.beginOperation(\"destroy\", wipeMetadata ? \"wipe-metadata\" : undefined);\n try {\n await state.persist(api);\n } catch {\n /* in-progress marker best-effort */\n }\n\n try {\n if (!skipWorkers) {\n await workerRoutesDestroy(env, config, baseDir, state, api);\n await state.persist(api);\n await workersDestroy(env, baseDir, accountId, config, state, api, force);\n }\n\n const ownedByKind = await Promise.all(\n resourceModules.map((m) =>\n logicalNamesForResourceKind(config, baseDir, m.kind).then((set) => ({\n mod: m,\n owned: set,\n })),\n ),\n );\n const workers = await getWorkers(config, baseDir);\n\n // Always run Logpush + Pipelines teardown: state may still hold\n // `logpush_pipelines` even if logpush was removed from tamer.config.ts,\n // and destroy must still delete the Pipelines stream/sink in that case.\n await logpushJobDestroy(env, state, api, config);\n await state.persist(api);\n\n for (const { mod, owned } of ownedByKind) {\n if (owned.size === 0) continue;\n // Aggregate this kind's resources across all workers in the config — the\n // destroy hook only needs them for stack-scope filtering and may walk\n // state directly. Empty array is acceptable when state holds entries\n // owned by another stack we still want to filter against `owned`.\n const resources = workers.flatMap(([, wc]) => mod.pickResources(wc));\n await mod.destroy({\n resources,\n tenant: config.tenant,\n env,\n api,\n state,\n naming,\n config,\n baseDir,\n force,\n });\n }\n\n if (getDispatchNamespaces(config).length > 0) {\n await dispatchNamespaceDestroy(env, state, api, config, force);\n }\n\n if (getDnsRecords(config).length > 0) {\n await dnsRecordDestroy(env, state, api, config, force);\n }\n\n // Clear `stackOutputs` after every successful destroy — the values\n // pointed at resources we just deleted, so leaving them in state would\n // mislead a future `tamer status` and (post-imports) leak dangling\n // refs into sibling stacks. The state row itself is dropped further\n // below when `wipeMetadata` is set.\n state.replaceStackOutputs({});\n\n if (env !== \"local\" && wipeMetadata) {\n state.clearDirty();\n const deletedState = await deleteEnvStateRows(api, env);\n if (deletedState) {\n console.log(`Cleared Tamer state rows for env ${env}.`);\n }\n try {\n await deleteEnvArtifacts(api, env);\n } catch (err) {\n console.warn(\n `Failed to clean Tamer artifacts for env ${env}:`,\n err instanceof Error ? err.message : err,\n );\n }\n try {\n const deletedSecrets = await deleteEnvSecretRows(api, env);\n if (deletedSecrets) {\n console.log(`Cleared Tamer secret rows for env ${env}.`);\n }\n } catch (err) {\n console.warn(\n `Failed to clean Tamer secrets for env ${env}:`,\n err instanceof Error ? err.message : err,\n );\n }\n }\n\n if (env !== \"local\" && !wipeMetadata) {\n state.finishOperation();\n try {\n await state.persist(api);\n } catch {\n /* state row may have been wiped by sub-steps */\n }\n }\n state.clearDirty();\n console.log(`Destroyed all resources for env: ${env}`);\n } catch (err) {\n if (env !== \"local\") {\n state.failOperation(err instanceof Error ? err.message : String(err));\n try {\n await state.persist(api);\n } catch {\n /* swallow secondary persist failure */\n }\n }\n throw err;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { H as loadConfig, R as CFApiClient, h as StateManager, w as stackNameForConfig, y as tenantStateKey, z as cloudflareAccountIdFromEnv } from "./tamer.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/core/env/protectedEnvs.ts
|
|
4
4
|
/**
|
|
@@ -98,4 +98,4 @@ async function runDestroyTenant(options) {
|
|
|
98
98
|
|
|
99
99
|
//#endregion
|
|
100
100
|
export { runDestroyTenant };
|
|
101
|
-
//# sourceMappingURL=destroy-tenant-
|
|
101
|
+
//# sourceMappingURL=destroy-tenant-DL99EoRZ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"destroy-tenant-
|
|
1
|
+
{"version":3,"file":"destroy-tenant-DL99EoRZ.mjs","names":["DEFAULT_PROTECTED_ENVS: readonly string[]","result: DestroyTenantResult","errors: string[]","removedShards: { role: string; derivedName: string; cfId: string }[]"],"sources":["../src/core/env/protectedEnvs.ts","../src/cli/commands/destroy-tenant.ts"],"sourcesContent":["import type { CfiConfig } from \"../../types.js\";\n\n/**\n * Default set of envs that require explicit confirmation before\n * `destroy-tenant` will run. Used when the loaded config doesn't pin\n * `tenant.protectedEnvs` — these two names are universal-enough across\n * accounts that \"destroying prod by accident\" stays guarded by default,\n * but the operator is free to override the list (e.g. a multi-region\n * account with `production-eu` / `production-us` / `canary` adds those\n * here, and a personal account passes `[]` to disable the prompt).\n */\nconst DEFAULT_PROTECTED_ENVS: readonly string[] = [\"prod\", \"production\"];\n\n/**\n * `true` when `env` is in `tenant.protectedEnvs` from the loaded\n * `tamer.config.ts` (or in the default set when the config doesn't\n * pin its own list). Single source of truth for the destroy\n * confirmation check — call this **after** `loadConfig` so the\n * config-pinned list is honored.\n */\nexport function isProtectedEnv(env: string, config: CfiConfig): boolean {\n const list = config.tenant.protectedEnvs ?? DEFAULT_PROTECTED_ENVS;\n return list.includes(env);\n}\n\nexport { DEFAULT_PROTECTED_ENVS };\n","import { loadConfig } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { tenantStateKey } from \"../../core/tenant/tenantKeys.js\";\nimport { isProtectedEnv } from \"../../core/env/protectedEnvs.js\";\n\n/**\n * Machine-readable result envelope emitted on the final stdout line\n * when `--json` is passed. Mirrors `ProvisionTenantResult` so the\n * Cloudflare Container caller (`provision-workflow`, see\n * `docs/handoff.md` §7) can consume both commands with the same\n * parsing path. `removed.shards` lists every D1 we attempted to\n * delete; `errors` lists any best-effort delete failures so the\n * Workflow can surface them without re-parsing logs.\n */\nexport interface DestroyTenantResult {\n status: \"destroyed\" | \"noop\" | \"failed\";\n tenantKey: string;\n product: string;\n workspace: string;\n env: string;\n removed: {\n scriptName?: string;\n dispatchNamespaceName?: string;\n shards: { role: string; derivedName: string; cfId: string }[];\n };\n errors: string[];\n error?: string;\n}\n\nexport async function runDestroyTenant(options: {\n env: string;\n product: string;\n workspace: string;\n force?: boolean;\n confirmTenant?: string;\n configPath?: string;\n json?: boolean;\n}): Promise<void> {\n const env = options.env;\n if (env === \"local\") {\n throw new Error(\"destroy-tenant requires a non-local --env.\");\n }\n\n // Load config FIRST so the protection prompt can read\n // `tenant.protectedEnvs` from `tamer.config.ts`. This intentionally\n // ignores `--force` so a misconfigured CLI invocation can't\n // bypass even the load step — we want the parsed config in hand\n // before we accept any confirmation flag.\n const config = await loadConfig(options.configPath, { env });\n\n if (isProtectedEnv(env, config) && !options.force) {\n if (options.confirmTenant !== options.workspace) {\n throw new Error(\n `destroy-tenant: env \"${env}\" is in tenant.protectedEnvs ` +\n `(or the default [\"prod\",\"production\"]); pass ` +\n `--confirm-tenant ${options.workspace} (must match --workspace) or use --force`,\n );\n }\n }\n\n const accountId = config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n const api = new CFApiClient(accountId);\n const state = new StateManager(\n config.tenant.id,\n env,\n stackNameForConfig(config),\n );\n await state.hydrate(api);\n\n const t = state.getTenant(options.product, options.workspace);\n if (!t) {\n if (!options.force) {\n throw new Error(\n `No tenant state for ${tenantStateKey(options.product, options.workspace)}; pass --force to skip state check`,\n );\n }\n console.log(\"No tenant record in state; nothing to remove.\");\n if (options.json) {\n const result: DestroyTenantResult = {\n status: \"noop\",\n tenantKey: tenantStateKey(options.product, options.workspace),\n product: options.product,\n workspace: options.workspace,\n env,\n removed: { shards: [] },\n errors: [],\n };\n process.stdout.write(JSON.stringify(result) + \"\\n\");\n }\n return;\n }\n\n const errors: string[] = [];\n try {\n await api.dispatchNamespaceScriptDelete(\n t.dispatchNamespaceName,\n t.scriptName,\n { force: true },\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[destroy-tenant] script delete: ${msg}`);\n errors.push(`script:${t.scriptName}:${msg}`);\n }\n\n const removedShards: { role: string; derivedName: string; cfId: string }[] =\n [];\n for (const shard of t.d1Shards ?? []) {\n try {\n await api.d1Delete(shard.cfId);\n removedShards.push({\n role: shard.role,\n derivedName: shard.derivedName,\n cfId: shard.cfId,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[destroy-tenant] D1 ${shard.derivedName}: ${msg}`);\n errors.push(`d1:${shard.derivedName}:${msg}`);\n }\n }\n\n state.deleteTenant(options.product, options.workspace);\n await state.persist(api);\n\n console.log(\n `Destroyed tenant ${tenantStateKey(options.product, options.workspace)}`,\n );\n\n if (options.json) {\n const result: DestroyTenantResult = {\n status: \"destroyed\",\n tenantKey: tenantStateKey(options.product, options.workspace),\n product: options.product,\n workspace: options.workspace,\n env,\n removed: {\n scriptName: t.scriptName,\n dispatchNamespaceName: t.dispatchNamespaceName,\n shards: removedShards,\n },\n errors,\n };\n process.stdout.write(JSON.stringify(result) + \"\\n\");\n }\n}\n"],"mappings":";;;;;;;;;;;;AAWA,MAAMA,yBAA4C,CAAC,QAAQ,aAAa;;;;;;;;AASxE,SAAgB,eAAe,KAAa,QAA4B;AAEtE,SADa,OAAO,OAAO,iBAAiB,wBAChC,SAAS,IAAI;;;;;ACU3B,eAAsB,iBAAiB,SAQrB;CAChB,MAAM,MAAM,QAAQ;AACpB,KAAI,QAAQ,QACV,OAAM,IAAI,MAAM,6CAA6C;CAQ/D,MAAM,SAAS,MAAM,WAAW,QAAQ,YAAY,EAAE,KAAK,CAAC;AAE5D,KAAI,eAAe,KAAK,OAAO,IAAI,CAAC,QAAQ,OAC1C;MAAI,QAAQ,kBAAkB,QAAQ,UACpC,OAAM,IAAI,MACR,wBAAwB,IAAI,6FAEN,QAAQ,UAAU,0CACzC;;CAIL,MAAM,YAAY,OAAO,cAAc,4BAA4B;AACnE,KAAI,CAAC,UACH,OAAM,IAAI,MACR,iEACD;CAGH,MAAM,MAAM,IAAI,YAAY,UAAU;CACtC,MAAM,QAAQ,IAAI,aAChB,OAAO,OAAO,IACd,KACA,mBAAmB,OAAO,CAC3B;AACD,OAAM,MAAM,QAAQ,IAAI;CAExB,MAAM,IAAI,MAAM,UAAU,QAAQ,SAAS,QAAQ,UAAU;AAC7D,KAAI,CAAC,GAAG;AACN,MAAI,CAAC,QAAQ,MACX,OAAM,IAAI,MACR,uBAAuB,eAAe,QAAQ,SAAS,QAAQ,UAAU,CAAC,oCAC3E;AAEH,UAAQ,IAAI,gDAAgD;AAC5D,MAAI,QAAQ,MAAM;GAChB,MAAMC,SAA8B;IAClC,QAAQ;IACR,WAAW,eAAe,QAAQ,SAAS,QAAQ,UAAU;IAC7D,SAAS,QAAQ;IACjB,WAAW,QAAQ;IACnB;IACA,SAAS,EAAE,QAAQ,EAAE,EAAE;IACvB,QAAQ,EAAE;IACX;AACD,WAAQ,OAAO,MAAM,KAAK,UAAU,OAAO,GAAG,KAAK;;AAErD;;CAGF,MAAMC,SAAmB,EAAE;AAC3B,KAAI;AACF,QAAM,IAAI,8BACR,EAAE,uBACF,EAAE,YACF,EAAE,OAAO,MAAM,CAChB;UACM,KAAK;EACZ,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC5D,UAAQ,KAAK,mCAAmC,MAAM;AACtD,SAAO,KAAK,UAAU,EAAE,WAAW,GAAG,MAAM;;CAG9C,MAAMC,gBACJ,EAAE;AACJ,MAAK,MAAM,SAAS,EAAE,YAAY,EAAE,CAClC,KAAI;AACF,QAAM,IAAI,SAAS,MAAM,KAAK;AAC9B,gBAAc,KAAK;GACjB,MAAM,MAAM;GACZ,aAAa,MAAM;GACnB,MAAM,MAAM;GACb,CAAC;UACK,KAAK;EACZ,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC5D,UAAQ,KAAK,uBAAuB,MAAM,YAAY,IAAI,MAAM;AAChE,SAAO,KAAK,MAAM,MAAM,YAAY,GAAG,MAAM;;AAIjD,OAAM,aAAa,QAAQ,SAAS,QAAQ,UAAU;AACtD,OAAM,MAAM,QAAQ,IAAI;AAExB,SAAQ,IACN,oBAAoB,eAAe,QAAQ,SAAS,QAAQ,UAAU,GACvE;AAED,KAAI,QAAQ,MAAM;EAChB,MAAMF,SAA8B;GAClC,QAAQ;GACR,WAAW,eAAe,QAAQ,SAAS,QAAQ,UAAU;GAC7D,SAAS,QAAQ;GACjB,WAAW,QAAQ;GACnB;GACA,SAAS;IACP,YAAY,EAAE;IACd,uBAAuB,EAAE;IACzB,QAAQ;IACT;GACD;GACD;AACD,UAAQ,OAAO,MAAM,KAAK,UAAU,OAAO,GAAG,KAAK"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "./registry-
|
|
1
|
+
import { H as loadConfig, M as wranglerConfigCliArgs, R as CFApiClient, V as getWorkers, f as fetchStackImports, h as StateManager, k as resolveWorkerConfig, u as namingFromConfig, w as stackNameForConfig, z as cloudflareAccountIdFromEnv } from "./tamer.mjs";
|
|
2
|
+
import "./registry-DyToEush.mjs";
|
|
3
3
|
import "./r2S3EmptyBucket-B9_pHfvB.mjs";
|
|
4
|
-
import { n as writeWranglerJson, t as generateWranglerConfig } from "./generator-
|
|
4
|
+
import { n as writeWranglerJson, t as generateWranglerConfig } from "./generator-BCcu_eoO.mjs";
|
|
5
5
|
import "./logpush-job-GqVKG_HI.mjs";
|
|
6
|
-
import "./worker-route-
|
|
7
|
-
import { runSync } from "./sync-
|
|
6
|
+
import "./worker-route-CUQBu9xe.mjs";
|
|
7
|
+
import { runSync } from "./sync-DEudPgQc.mjs";
|
|
8
8
|
import { spawn } from "child_process";
|
|
9
9
|
|
|
10
10
|
//#region src/cli/commands/dev.ts
|
|
@@ -98,4 +98,4 @@ async function runDev(options) {
|
|
|
98
98
|
|
|
99
99
|
//#endregion
|
|
100
100
|
export { runDev };
|
|
101
|
-
//# sourceMappingURL=dev-
|
|
101
|
+
//# sourceMappingURL=dev-BiPXBOKk.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-
|
|
1
|
+
{"version":3,"file":"dev-BiPXBOKk.mjs","names":["workerKey","workerConfig","resolved","children: ChildProcess[]"],"sources":["../src/cli/commands/dev.ts"],"sourcesContent":["import type { ChildProcess } from \"child_process\";\nimport { spawn } from \"child_process\";\nimport { loadConfig, getWorkers } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport { wranglerConfigCliArgs } from \"../../core/wrangler/wranglerOutFile.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport { resolveWorkerConfig } from \"../../core/config/resolver.js\";\nimport {\n generateWranglerConfig,\n writeWranglerJson,\n} from \"../../core/wrangler/generator.js\";\nimport { runSync } from \"./sync.js\";\nimport { fetchStackImports } from \"../../core/imports/fetchStackImports.js\";\n\nexport async function runDev(options: {\n worker?: string;\n env?: string;\n configPath?: string;\n /** Run every selected worker as a separate `wrangler dev` on incrementing ports (from TAMER_DEV_BASE_PORT or 8787). */\n all?: boolean;\n}): Promise<void> {\n const workerFilter = options.worker;\n const env = options.env ?? \"local\";\n const configPath = options.configPath;\n const baseDir = process.cwd();\n\n const config = await loadConfig(configPath, { env });\n const accountId =\n config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n const naming = namingFromConfig(config);\n const api = new CFApiClient(accountId);\n const state = new StateManager(\n config.tenant.id,\n env,\n stackNameForConfig(config),\n );\n await state.hydrate(api);\n\n if (\n env !== \"local\" &&\n Object.keys(state.load().resources).length === 0\n ) {\n console.log(\"Tamer state is empty; running sync...\");\n await runSync({ env, configPath });\n state.reset();\n await state.hydrate(api);\n }\n\n // Pre-fetch sibling stack outputs so worker `vars` / `tamerRoutes`\n // can reference `${tamer:import:<stack>.<output>}` even in dev mode.\n // No-op in local env (returns `{}`); when missing in non-local, the\n // import resolver will throw with a clear \"run apply on <stack>\" hint.\n const imports = await fetchStackImports(api, config, env);\n\n const workers = await getWorkers(config, baseDir);\n const toRun = workerFilter\n ? workers.filter(([k]) => k === workerFilter)\n : workers;\n\n if (toRun.length === 0) {\n throw new Error(\n workerFilter\n ? `Worker \"${workerFilter}\" not found`\n : \"No workers configured\",\n );\n }\n\n for (const [workerKey, workerConfig] of toRun) {\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n workerConfig,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { imports },\n );\n const wranglerConfig = generateWranglerConfig(resolved, state, naming);\n writeWranglerJson(resolved.workerDir, wranglerConfig, resolved.wranglerOutFile);\n }\n\n if (options.all && toRun.length > 0) {\n const basePort = Number(process.env.TAMER_DEV_BASE_PORT) || 8787;\n const children: ChildProcess[] = [];\n\n for (let i = 0; i < toRun.length; i++) {\n const [workerKey, workerConfig] = toRun[i];\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n workerConfig,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { imports },\n );\n const port = basePort + i;\n const devArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"dev\",\n \"--port\",\n String(port),\n ];\n console.log(`Starting ${workerKey} on http://127.0.0.1:${port}`);\n const proc = spawn(\"bunx\", devArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n shell: true,\n });\n children.push(proc);\n }\n\n const shutdown = () => {\n for (const c of children) {\n if (!c.killed) c.kill(\"SIGTERM\");\n }\n };\n process.once(\"SIGINT\", () => {\n shutdown();\n process.exit(0);\n });\n process.once(\"SIGTERM\", () => {\n shutdown();\n process.exit(0);\n });\n\n await new Promise<void>((resolve) => {\n let remaining = children.length;\n for (const c of children) {\n c.on(\"exit\", () => {\n remaining -= 1;\n if (remaining <= 0) resolve();\n });\n }\n });\n return;\n }\n\n const [workerKey, workerConfig] = toRun[0];\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n workerConfig,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { imports },\n );\n\n console.log(`Starting wrangler dev for ${workerKey}...`);\n const devArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"dev\",\n ];\n const proc = spawn(\"bunx\", devArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n shell: true,\n });\n\n proc.on(\"exit\", (code) => {\n process.exit(code ?? 0);\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { B as cloudflareApiTokenFromEnv, R as CFApiClient, z as cloudflareAccountIdFromEnv } from "./tamer.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/cli/commands/doctor.ts
|
|
4
4
|
async function runDoctor(options) {
|
|
@@ -31,4 +31,4 @@ async function runDoctor(options) {
|
|
|
31
31
|
|
|
32
32
|
//#endregion
|
|
33
33
|
export { runDoctor };
|
|
34
|
-
//# sourceMappingURL=doctor-
|
|
34
|
+
//# sourceMappingURL=doctor-DDwsA2V6.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor-
|
|
1
|
+
{"version":3,"file":"doctor-DDwsA2V6.mjs","names":["report: DoctorReport"],"sources":["../src/cli/commands/doctor.ts"],"sourcesContent":["import {\n cloudflareAccountIdFromEnv,\n cloudflareApiTokenFromEnv,\n} from \"../../core/cloudflareEnv.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\n\nexport interface DoctorReport {\n ok: boolean;\n accountIdPresent: boolean;\n apiTokenPresent: boolean;\n accountReadable: boolean;\n error?: string;\n}\n\nexport async function runDoctor(options: { json?: boolean }): Promise<number> {\n const accountId = cloudflareAccountIdFromEnv();\n const token = cloudflareApiTokenFromEnv();\n const report: DoctorReport = {\n ok: false,\n accountIdPresent: !!accountId,\n apiTokenPresent: !!token && token.length > 0,\n accountReadable: false,\n };\n\n if (!accountId || token.length === 0) {\n report.error = \"CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN must be set\";\n if (options.json) console.log(JSON.stringify(report, null, 2));\n else console.error(report.error);\n return 1;\n }\n\n try {\n const api = new CFApiClient(accountId, token);\n await api.accountRead();\n report.accountReadable = true;\n report.ok = true;\n } catch (err) {\n report.error = err instanceof Error ? err.message : String(err);\n }\n\n if (options.json) {\n console.log(JSON.stringify(report, null, 2));\n } else {\n console.log(\n report.ok\n ? \"doctor: account token can read Cloudflare account API.\"\n : `doctor: failed — ${report.error ?? \"unknown\"}`,\n );\n }\n\n if (!report.ok) {\n return 1;\n }\n return 0;\n}\n"],"mappings":";;;AAcA,eAAsB,UAAU,SAA8C;CAC5E,MAAM,YAAY,4BAA4B;CAC9C,MAAM,QAAQ,2BAA2B;CACzC,MAAMA,SAAuB;EAC3B,IAAI;EACJ,kBAAkB,CAAC,CAAC;EACpB,iBAAiB,CAAC,CAAC,SAAS,MAAM,SAAS;EAC3C,iBAAiB;EAClB;AAED,KAAI,CAAC,aAAa,MAAM,WAAW,GAAG;AACpC,SAAO,QAAQ;AACf,MAAI,QAAQ,KAAM,SAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;MACzD,SAAQ,MAAM,OAAO,MAAM;AAChC,SAAO;;AAGT,KAAI;AAEF,QADY,IAAI,YAAY,WAAW,MAAM,CACnC,aAAa;AACvB,SAAO,kBAAkB;AACzB,SAAO,KAAK;UACL,KAAK;AACZ,SAAO,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;;AAGjE,KAAI,QAAQ,KACV,SAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;KAE5C,SAAQ,IACN,OAAO,KACH,2DACA,oBAAoB,OAAO,SAAS,YACzC;AAGH,KAAI,CAAC,OAAO,GACV,QAAO;AAET,QAAO"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import "./registry-
|
|
1
|
+
import "./registry-DyToEush.mjs";
|
|
2
2
|
import "./r2S3EmptyBucket-B9_pHfvB.mjs";
|
|
3
|
-
import { n as runDrift, t as computeDriftReport } from "./drift-
|
|
3
|
+
import { n as runDrift, t as computeDriftReport } from "./drift-RpShXwG7.mjs";
|
|
4
4
|
import "./logpush-job-GqVKG_HI.mjs";
|
|
5
|
-
import "./worker-route-
|
|
6
|
-
import "./workers-
|
|
5
|
+
import "./worker-route-CUQBu9xe.mjs";
|
|
6
|
+
import "./workers-BjDCuyVv.mjs";
|
|
7
7
|
|
|
8
8
|
export { runDrift };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { f as getDispatchNamespaces, m as getLogpushJobs, p as getDnsRecords } from "./normalize-DVSTRZhO.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { n as resourceModules } from "./registry-
|
|
2
|
+
import { E as mergeWorkerConfigForResourcePick, H as loadConfig, N as effectiveDispatchNamespaceName, O as resolveDeployedWorkerName, R as CFApiClient, V as getWorkers, a as reconcileSecrets, c as vaultReaderFromMap, d as requiredSecretsForWorker, f as fetchStackImports, h as StateManager, o as secretsDrift, u as namingFromConfig, w as stackNameForConfig, y as tenantStateKey, z as cloudflareAccountIdFromEnv } from "./tamer.mjs";
|
|
3
|
+
import { n as resourceModules } from "./registry-DyToEush.mjs";
|
|
4
4
|
import { n as dnsRecordCommentMarker, r as dnsRecordStateKey, t as dnsRecordAppliesToEnv } from "./dns-records.resolve-DV6XBZf3.mjs";
|
|
5
5
|
import { r as logpushJobDrift } from "./logpush-job-GqVKG_HI.mjs";
|
|
6
|
-
import { t as workerRoutesDrift } from "./worker-route-
|
|
7
|
-
import { t as workersDrift } from "./workers-
|
|
6
|
+
import { t as workerRoutesDrift } from "./worker-route-CUQBu9xe.mjs";
|
|
7
|
+
import { t as workersDrift } from "./workers-BjDCuyVv.mjs";
|
|
8
8
|
|
|
9
9
|
//#region src/features/dispatch-namespace/dispatch-namespace.drift.ts
|
|
10
10
|
function dispatchNamespaceDrift(allDispatch, resources, env, tenant, state) {
|
|
@@ -348,4 +348,4 @@ async function buildSecretWorkerInputs(workers, config, env, baseDir, accountId,
|
|
|
348
348
|
|
|
349
349
|
//#endregion
|
|
350
350
|
export { runDrift as n, computeDriftReport as t };
|
|
351
|
-
//# sourceMappingURL=drift-
|
|
351
|
+
//# sourceMappingURL=drift-RpShXwG7.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drift-B5y9LF5X.mjs","names":["drift: ResourceDrift","drift: ResourceDrift","drift: ResourceDrift","byZone: DnsRecordsByZone","out: T[]","REGISTRY_LABELS: Record<string, string>","out: Array<{\n workerKey: string;\n required: string[];\n workerSecretNames: string[];\n }>","workerSecretNames: string[]"],"sources":["../src/features/dispatch-namespace/dispatch-namespace.drift.ts","../src/features/dns-records/dns-records.drift.ts","../src/core/drift/drift.types.ts","../src/core/drift/tenantDrift.ts","../src/cli/commands/drift.ts"],"sourcesContent":["import type {\n DispatchNamespaceResourceConfig,\n DispatchNamespaceStateEntry,\n TenantMeta,\n} from \"../../types.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { ResourceDrift } from \"../../core/drift/drift.types.js\";\nimport { effectiveDispatchNamespaceName } from \"./dispatch-namespace.resolve.js\";\n\ninterface CFDispatchNamespace {\n namespace_name: string;\n}\n\nexport function dispatchNamespaceDrift(\n allDispatch: CFDispatchNamespace[],\n resources: DispatchNamespaceResourceConfig[],\n env: string,\n tenant: TenantMeta,\n state: StateManager,\n): ResourceDrift {\n const drift: ResourceDrift = {\n kind: \"dispatch_namespace\",\n missingFromCloudflare: [],\n unrecordedInState: [],\n undeployed: [],\n };\n\n const cfNames = new Set(allDispatch.map((d) => d.namespace_name));\n const allState = state.getAll();\n const nsState = Object.values(allState).filter(\n (e): e is DispatchNamespaceStateEntry => e.type === \"dispatch_namespace\",\n );\n\n for (const config of resources) {\n const derivedName = effectiveDispatchNamespaceName(config, env, tenant);\n const stateEntry = nsState.find(\n (e) => e.logicalName === config.logicalName && e.derivedName === derivedName,\n );\n const onCf = cfNames.has(derivedName);\n\n if (stateEntry && !onCf) {\n drift.missingFromCloudflare.push({\n logicalName: stateEntry.logicalName,\n derivedName: stateEntry.derivedName,\n });\n } else if (onCf && !stateEntry) {\n drift.unrecordedInState.push({\n logicalName: config.logicalName,\n derivedName,\n });\n } else if (!onCf && !stateEntry) {\n drift.undeployed.push({\n logicalName: config.logicalName,\n derivedName,\n });\n }\n }\n\n return drift;\n}\n","import type {\n DnsRecordResourceConfig,\n DnsRecordStateEntry,\n TenantMeta,\n} from \"../../types.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { ResourceDrift } from \"../../core/drift/drift.types.js\";\nimport {\n dnsRecordAppliesToEnv,\n dnsRecordCommentMarker,\n dnsRecordStateKey,\n} from \"./dns-records.resolve.js\";\n\ninterface CFDnsRecord {\n id: string;\n type: string;\n name: string;\n content: string;\n ttl?: number;\n proxied?: boolean;\n priority?: number;\n comment?: string | null;\n}\n\n/**\n * Map of `zoneId → live records`. The drift caller pre-fetches because\n * other resource modules also iterate zones (worker routes), so we\n * accept the snapshot rather than refetching here.\n */\nexport type DnsRecordsByZone = Map<string, CFDnsRecord[]>;\n\nexport function dnsRecordDrift(\n byZone: DnsRecordsByZone,\n resources: DnsRecordResourceConfig[],\n tenant: TenantMeta,\n env: string,\n state: StateManager,\n): ResourceDrift {\n const drift: ResourceDrift = {\n kind: \"dns_record\",\n missingFromCloudflare: [],\n unrecordedInState: [],\n undeployed: [],\n };\n\n const stateRecords = Object.values(state.getAll()).filter(\n (e): e is DnsRecordStateEntry => e.type === \"dns_record\",\n );\n\n for (const config of resources) {\n if (!dnsRecordAppliesToEnv(config, env)) continue;\n const live = byZone.get(config.zoneId) ?? [];\n const marker = dnsRecordCommentMarker(tenant, env, config.logicalName);\n const stateKey = dnsRecordStateKey(config.zoneId, config.type, config.name);\n const entry = stateRecords.find(\n (e) =>\n e.zoneId === config.zoneId &&\n e.recordType === config.type &&\n e.logicalName === config.logicalName,\n );\n const onCf = entry\n ? live.find((r) => r.id === entry.recordId)\n : live.find(\n (r) =>\n r.type === config.type &&\n typeof r.comment === \"string\" &&\n r.comment.startsWith(marker),\n );\n\n if (entry && !onCf) {\n drift.missingFromCloudflare.push({\n logicalName: entry.logicalName,\n derivedName: `${entry.recordType} ${entry.name}`,\n cfId: entry.recordId,\n });\n } else if (onCf && !entry) {\n drift.unrecordedInState.push({\n logicalName: config.logicalName,\n derivedName: `${config.type} ${onCf.name}`,\n cfId: onCf.id,\n });\n } else if (!onCf && !entry) {\n drift.undeployed.push({\n logicalName: config.logicalName,\n derivedName: `${config.type} ${config.name}`,\n detail: stateKey,\n });\n }\n }\n\n return drift;\n}\n","/**\n * Read-only drift report comparing recorded state vs. Cloudflare reality vs.\n * the current `tamer.config.ts`.\n */\n\nexport type DriftKind =\n | \"d1\"\n | \"r2\"\n | \"kv\"\n | \"queue\"\n | \"hyperdrive\"\n | \"vectorize\"\n | \"ai_gateway\"\n | \"pipeline\"\n | \"workflow\"\n | \"secret_store\"\n | \"secret\"\n | \"dns_record\"\n | \"dispatch_namespace\"\n | \"logpush_job\"\n | \"tenant\"\n | \"worker_route\"\n | \"worker_script\";\n\nexport interface DriftEntry {\n /** Logical resource name from `tamer.config.ts`. */\n logicalName: string;\n /** Cloudflare-side name (or `(unknown)` when no CF or state side knows it). */\n derivedName: string;\n /** Cloudflare resource ID, when known (D1 uuid, KV id). */\n cfId?: string;\n /** Optional human-readable detail (e.g. shard date). */\n detail?: string;\n}\n\nexport interface ResourceDrift {\n kind: DriftKind;\n /** Tracked in state but no longer present on Cloudflare. */\n missingFromCloudflare: DriftEntry[];\n /**\n * Present on Cloudflare and matches a declared resource in this config,\n * but no state entry tracks it (e.g. created out-of-band).\n */\n unrecordedInState: DriftEntry[];\n /**\n * Declared in this stack's config but neither tracked in state nor present\n * on Cloudflare (run `tamer apply`).\n */\n undeployed: DriftEntry[];\n}\n\nexport interface DriftReport {\n tenantId: string;\n env: string;\n generatedAt: string;\n resources: ResourceDrift[];\n /** True iff any of the three categories has at least one entry. */\n hasDrift: boolean;\n}\n\nexport function resourceDriftIsClean(d: ResourceDrift): boolean {\n return (\n d.missingFromCloudflare.length === 0 &&\n d.unrecordedInState.length === 0 &&\n d.undeployed.length === 0\n );\n}\n\nexport function reportHasDrift(resources: ResourceDrift[]): boolean {\n return resources.some((d) => !resourceDriftIsClean(d));\n}\n","import type { CFApiClient } from \"../api/CFApiClient.js\";\nimport type { StateManager } from \"../state/StateManager.js\";\nimport type { ResourceDrift } from \"./drift.types.js\";\nimport { tenantStateKey } from \"../tenant/tenantKeys.js\";\n\ninterface CFD1 {\n uuid: string;\n name: string;\n}\n\n/**\n * Drift for workspace tenants in {@link CfiState.tenants}: dispatch script and\n * recorded D1 shards must still exist on Cloudflare.\n *\n * `unrecordedInState` / `undeployed` are intentionally empty here — tenant\n * discovery from CF alone is heuristic until product/script naming is fully\n * pinned (`docs/scope-remaining.md` D-1).\n */\nexport async function tenantDrift(\n state: StateManager,\n api: CFApiClient,\n allD1: CFD1[],\n): Promise<ResourceDrift> {\n const drift: ResourceDrift = {\n kind: \"tenant\",\n missingFromCloudflare: [],\n unrecordedInState: [],\n undeployed: [],\n };\n\n const d1ById = new Map(allD1.map((d) => [d.uuid, d.name]));\n const tenants = state\n .listTenants()\n .filter((t) => t.provisioningStatus !== \"tombstoned\");\n if (tenants.length === 0) return drift;\n\n const scriptLists = new Map<string, Set<string>>();\n async function scriptsInNs(ns: string): Promise<Set<string>> {\n let set = scriptLists.get(ns);\n if (!set) {\n const list = await api.dispatchNamespaceScriptList(ns);\n set = new Set(list.map((s) => s.id));\n scriptLists.set(ns, set);\n }\n return set;\n }\n\n for (const t of tenants) {\n const logical = tenantStateKey(t.product, t.workspace);\n try {\n const ids = await scriptsInNs(t.dispatchNamespaceName);\n if (!ids.has(t.scriptName)) {\n drift.missingFromCloudflare.push({\n logicalName: logical,\n derivedName: t.scriptName,\n detail: \"dispatch_script\",\n });\n }\n } catch {\n drift.missingFromCloudflare.push({\n logicalName: logical,\n derivedName: t.dispatchNamespaceName,\n detail: \"dispatch_namespace_list_failed\",\n });\n }\n\n for (const shard of t.d1Shards ?? []) {\n if (!d1ById.has(shard.cfId)) {\n drift.missingFromCloudflare.push({\n logicalName: logical,\n derivedName: shard.derivedName,\n cfId: shard.cfId,\n detail: `d1:${shard.role}`,\n });\n }\n }\n }\n\n return drift;\n}\n","import { loadConfig, getWorkers } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport { dispatchNamespaceDrift } from \"../../features/dispatch-namespace/index.js\";\nimport {\n dnsRecordDrift,\n type DnsRecordsByZone,\n} from \"../../features/dns-records/index.js\";\nimport { getDispatchNamespaces, getDnsRecords, getLogpushJobs } from \"../../types.js\";\nimport { logpushJobDrift } from \"../../features/logpush-job/index.js\";\nimport type {\n DriftReport,\n ResourceDrift,\n} from \"../../core/drift/drift.types.js\";\nimport { reportHasDrift } from \"../../core/drift/drift.types.js\";\nimport { tenantDrift } from \"../../core/drift/tenantDrift.js\";\nimport { workerRoutesDrift } from \"../../features/worker-route/index.js\";\nimport { workersDrift } from \"../../features/workers/index.js\";\nimport { resourceModules } from \"../../core/registry/registry.js\";\nimport { fetchStackImports } from \"../../core/imports/fetchStackImports.js\";\nimport { mergeWorkerConfigForResourcePick } from \"../../core/config/resolver.js\";\nimport { resolveDeployedWorkerName } from \"../../core/config/resolver.js\";\nimport { requiredSecretsForWorker } from \"../../core/secrets/declared.js\";\nimport {\n reconcileSecrets,\n secretsDrift,\n vaultReaderFromMap,\n type SecretsVaultReader,\n} from \"../../core/secrets/reconcile.js\";\n\n/**\n * Compute a read-only drift report for the given env.\n *\n * Compares Tamer state (D1 `tamer-state-{env}`) against the Cloudflare API\n * and the resources declared in `tamer.config.ts`. Reports three categories:\n *\n * - `missingFromCloudflare` — tracked in state but the CF resource is gone.\n * - `unrecordedInState` — exists on CF and matches a declared resource, but\n * no state entry tracks it (e.g. created out-of-band; run `tamer sync`).\n * - `undeployed` — declared in this stack's config, present in neither\n * state nor CF (run `tamer apply`).\n *\n * Pure: never writes to state. Returns the report so callers can choose how to\n * render or consume it.\n */\nexport async function computeDriftReport(options: {\n env?: string;\n configPath?: string;\n /** Optional vault reader for secret reconciliation (defaults to empty). */\n secretsVault?: SecretsVaultReader;\n}): Promise<DriftReport> {\n const env = options.env ?? \"local\";\n const configPath = options.configPath;\n const baseDir = process.cwd();\n\n const config = await loadConfig(configPath, { env });\n const accountId = config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n const api = new CFApiClient(accountId);\n const naming = namingFromConfig(config);\n const state = new StateManager(\n config.tenant.id,\n env,\n stackNameForConfig(config),\n );\n await state.hydrate(api);\n // Tolerant pre-fetch keeps drift accurate when worker `tamerRoutes`\n // depend on sibling-stack outputs (otherwise the placeholder pattern\n // would never match anything CF returned).\n const imports = await fetchStackImports(api, config, env).catch(() => ({}));\n\n async function safeList<T>(\n label: string,\n fn: () => Promise<T[]>,\n ): Promise<T[]> {\n try {\n return await fn();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[drift] skipping ${label}: ${msg}`);\n return [];\n }\n }\n\n const lists = await Promise.all(\n resourceModules.map((m) =>\n safeList(`${m.label} list`, () => m.fetchAll(api)),\n ),\n );\n\n const allDispatch =\n getDispatchNamespaces(config).length > 0\n ? await safeList(\"dispatch namespaces\", () =>\n api.dispatchNamespaceListAll(),\n )\n : [];\n\n const allLogpushJobs =\n getLogpushJobs(config).length > 0 && env !== \"local\"\n ? await safeList(\"logpush jobs\", () => api.logpushAccountJobsList())\n : [];\n\n const workers = await getWorkers(config, baseDir);\n\n const aggregated = new Map<string, ResourceDrift>();\n function merge(d: ResourceDrift): void {\n const existing = aggregated.get(d.kind);\n if (!existing) {\n aggregated.set(d.kind, d);\n return;\n }\n existing.missingFromCloudflare.push(...d.missingFromCloudflare);\n existing.unrecordedInState.push(...d.unrecordedInState);\n existing.undeployed.push(...d.undeployed);\n }\n\n for (const [workerKey, workerConfig] of workers) {\n const mergedWorker = mergeWorkerConfigForResourcePick(\n config,\n workerKey,\n workerConfig,\n env,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\", imports },\n );\n resourceModules.forEach((mod, i) => {\n const resources = mod.pickResources(mergedWorker);\n if (resources.length === 0) return;\n merge(\n mod.drift({\n resources,\n all: lists[i],\n tenant: config.tenant,\n env,\n api,\n state,\n naming,\n config,\n baseDir,\n }),\n );\n });\n }\n\n const dispatchResources = getDispatchNamespaces(config);\n if (dispatchResources.length > 0) {\n merge(\n dispatchNamespaceDrift(\n allDispatch,\n dispatchResources,\n env,\n config.tenant,\n state,\n ),\n );\n }\n\n const dnsResources = getDnsRecords(config);\n if (dnsResources.length > 0 && env !== \"local\") {\n const byZone: DnsRecordsByZone = new Map();\n const zones = Array.from(new Set(dnsResources.map((r) => r.zoneId)));\n for (const zoneId of zones) {\n const live = await safeList(`dns records (zone ${zoneId})`, () =>\n api.zoneDnsRecordListAll(zoneId),\n );\n byZone.set(zoneId, live);\n }\n merge(dnsRecordDrift(byZone, dnsResources, config.tenant, env, state));\n }\n\n const logpushResources = getLogpushJobs(config);\n if (logpushResources.length > 0 && env !== \"local\") {\n merge(\n logpushJobDrift(\n allLogpushJobs,\n logpushResources,\n env,\n config.tenant,\n state,\n ),\n );\n }\n\n if (state.listTenants().length > 0) {\n const allD1Idx = resourceModules.findIndex((m) => m.kind === \"d1\");\n const allD1 =\n allD1Idx >= 0\n ? (lists[allD1Idx] as Array<{ uuid: string; name: string }>)\n : [];\n merge(await tenantDrift(state, api, allD1));\n }\n\n const workerRouteReport = await workerRoutesDrift(\n env,\n config,\n baseDir,\n accountId,\n naming,\n state,\n api,\n { imports },\n );\n if (workerRouteReport) merge(workerRouteReport);\n\n const workerScriptReport = await workersDrift(\n env,\n config,\n baseDir,\n accountId,\n naming,\n state,\n api,\n { imports },\n );\n if (workerScriptReport) merge(workerScriptReport);\n\n const secretWorkers = await buildSecretWorkerInputs(\n workers,\n config,\n env,\n baseDir,\n accountId,\n naming,\n state,\n api,\n imports,\n );\n if (secretWorkers.length > 0) {\n const secretEntries = await reconcileSecrets({\n workers: secretWorkers,\n vault: options.secretsVault ?? vaultReaderFromMap({}),\n state,\n });\n merge(secretsDrift(secretEntries));\n }\n\n const dedupedResources = Array.from(aggregated.values()).map((d) => ({\n ...d,\n missingFromCloudflare: dedupe(d.missingFromCloudflare),\n unrecordedInState: dedupe(d.unrecordedInState),\n undeployed: dedupe(d.undeployed),\n }));\n\n return {\n tenantId: config.tenant.id,\n env,\n generatedAt: new Date().toISOString(),\n resources: dedupedResources,\n hasDrift: reportHasDrift(dedupedResources),\n };\n}\n\nfunction dedupe<T extends { logicalName: string; derivedName: string }>(\n list: T[],\n): T[] {\n const seen = new Set<string>();\n const out: T[] = [];\n for (const item of list) {\n const key = `${item.logicalName}::${item.derivedName}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(item);\n }\n return out;\n}\n\n/**\n * CLI entry point. Prints a human report (or JSON when `--json`) and sets a\n * non-zero process exit code when drift is found.\n */\nexport async function runDrift(options: {\n env?: string;\n configPath?: string;\n json?: boolean;\n}): Promise<number> {\n const report = await computeDriftReport({\n env: options.env,\n configPath: options.configPath,\n });\n\n if (options.json) {\n console.log(JSON.stringify(report, null, 2));\n } else {\n printHumanReport(report);\n }\n\n return report.hasDrift ? 1 : 0;\n}\n\nfunction printHumanReport(report: DriftReport): void {\n console.log(\n `\\nDrift report — tenant ${report.tenantId}, env ${report.env}\\n`,\n );\n if (report.resources.length === 0) {\n console.log(\" (no managed resource kinds in this config)\\n\");\n return;\n }\n for (const d of report.resources) {\n const total =\n d.missingFromCloudflare.length +\n d.unrecordedInState.length +\n d.undeployed.length;\n console.log(`${labelFor(d.kind)} (${total} drift):`);\n if (total === 0) {\n console.log(\" ok\");\n continue;\n }\n if (d.missingFromCloudflare.length) {\n console.log(\" missing from Cloudflare (state references gone):\");\n for (const e of d.missingFromCloudflare) {\n console.log(` - ${e.logicalName} -> ${e.derivedName}${suffix(e.cfId)}`);\n }\n }\n if (d.unrecordedInState.length) {\n console.log(\" unrecorded in state (run `tamer sync`):\");\n for (const e of d.unrecordedInState) {\n console.log(` - ${e.logicalName} -> ${e.derivedName}${suffix(e.cfId)}`);\n }\n }\n if (d.undeployed.length) {\n console.log(\" undeployed (run `tamer apply`):\");\n for (const e of d.undeployed) {\n console.log(` - ${e.logicalName} -> ${e.derivedName}`);\n }\n }\n }\n console.log(report.hasDrift ? \"\\nDrift detected.\\n\" : \"\\nNo drift.\\n\");\n}\n\nconst REGISTRY_LABELS: Record<string, string> = Object.fromEntries(\n resourceModules.map((m) => [m.kind, m.label]),\n);\n\nfunction labelFor(kind: ResourceDrift[\"kind\"]): string {\n if (REGISTRY_LABELS[kind]) return REGISTRY_LABELS[kind];\n switch (kind) {\n case \"dispatch_namespace\":\n return \"Dispatch namespaces\";\n case \"logpush_job\":\n return \"Logpush jobs\";\n case \"dns_record\":\n return \"DNS records\";\n case \"tenant\":\n return \"Workspace tenants\";\n case \"worker_route\":\n return \"HTTP routes (Workers Routes API)\";\n case \"worker_script\":\n return \"Worker scripts\";\n case \"secret\":\n return \"Worker secrets\";\n default:\n return kind;\n }\n}\n\nfunction suffix(cfId?: string): string {\n return cfId ? ` [${cfId}]` : \"\";\n}\n\nasync function buildSecretWorkerInputs(\n workers: Awaited<ReturnType<typeof getWorkers>>,\n config: Awaited<ReturnType<typeof loadConfig>>,\n env: string,\n baseDir: string,\n accountId: string,\n naming: ReturnType<typeof namingFromConfig>,\n state: StateManager,\n api: CFApiClient,\n imports: Awaited<ReturnType<typeof fetchStackImports>>,\n): Promise<\n Array<{\n workerKey: string;\n required: string[];\n workerSecretNames: string[];\n }>\n> {\n const out: Array<{\n workerKey: string;\n required: string[];\n workerSecretNames: string[];\n }> = [];\n\n for (const [workerKey, workerConfig] of workers) {\n const merged = mergeWorkerConfigForResourcePick(\n config,\n workerKey,\n workerConfig,\n env,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\", imports },\n );\n const required = requiredSecretsForWorker(merged);\n if (required.length === 0) continue;\n\n const deployedName = resolveDeployedWorkerName(\n config,\n workerKey,\n workerConfig,\n env,\n naming,\n );\n let workerSecretNames: string[] = [];\n if (env !== \"local\") {\n try {\n workerSecretNames = await api.workersSecretsList(deployedName);\n } catch {\n workerSecretNames = [];\n }\n }\n\n out.push({ workerKey, required, workerSecretNames });\n }\n\n return out;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"drift-RpShXwG7.mjs","names":["drift: ResourceDrift","drift: ResourceDrift","drift: ResourceDrift","byZone: DnsRecordsByZone","out: T[]","REGISTRY_LABELS: Record<string, string>","out: Array<{\n workerKey: string;\n required: string[];\n workerSecretNames: string[];\n }>","workerSecretNames: string[]"],"sources":["../src/features/dispatch-namespace/dispatch-namespace.drift.ts","../src/features/dns-records/dns-records.drift.ts","../src/core/drift/drift.types.ts","../src/core/drift/tenantDrift.ts","../src/cli/commands/drift.ts"],"sourcesContent":["import type {\n DispatchNamespaceResourceConfig,\n DispatchNamespaceStateEntry,\n TenantMeta,\n} from \"../../types.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { ResourceDrift } from \"../../core/drift/drift.types.js\";\nimport { effectiveDispatchNamespaceName } from \"./dispatch-namespace.resolve.js\";\n\ninterface CFDispatchNamespace {\n namespace_name: string;\n}\n\nexport function dispatchNamespaceDrift(\n allDispatch: CFDispatchNamespace[],\n resources: DispatchNamespaceResourceConfig[],\n env: string,\n tenant: TenantMeta,\n state: StateManager,\n): ResourceDrift {\n const drift: ResourceDrift = {\n kind: \"dispatch_namespace\",\n missingFromCloudflare: [],\n unrecordedInState: [],\n undeployed: [],\n };\n\n const cfNames = new Set(allDispatch.map((d) => d.namespace_name));\n const allState = state.getAll();\n const nsState = Object.values(allState).filter(\n (e): e is DispatchNamespaceStateEntry => e.type === \"dispatch_namespace\",\n );\n\n for (const config of resources) {\n const derivedName = effectiveDispatchNamespaceName(config, env, tenant);\n const stateEntry = nsState.find(\n (e) => e.logicalName === config.logicalName && e.derivedName === derivedName,\n );\n const onCf = cfNames.has(derivedName);\n\n if (stateEntry && !onCf) {\n drift.missingFromCloudflare.push({\n logicalName: stateEntry.logicalName,\n derivedName: stateEntry.derivedName,\n });\n } else if (onCf && !stateEntry) {\n drift.unrecordedInState.push({\n logicalName: config.logicalName,\n derivedName,\n });\n } else if (!onCf && !stateEntry) {\n drift.undeployed.push({\n logicalName: config.logicalName,\n derivedName,\n });\n }\n }\n\n return drift;\n}\n","import type {\n DnsRecordResourceConfig,\n DnsRecordStateEntry,\n TenantMeta,\n} from \"../../types.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { ResourceDrift } from \"../../core/drift/drift.types.js\";\nimport {\n dnsRecordAppliesToEnv,\n dnsRecordCommentMarker,\n dnsRecordStateKey,\n} from \"./dns-records.resolve.js\";\n\ninterface CFDnsRecord {\n id: string;\n type: string;\n name: string;\n content: string;\n ttl?: number;\n proxied?: boolean;\n priority?: number;\n comment?: string | null;\n}\n\n/**\n * Map of `zoneId → live records`. The drift caller pre-fetches because\n * other resource modules also iterate zones (worker routes), so we\n * accept the snapshot rather than refetching here.\n */\nexport type DnsRecordsByZone = Map<string, CFDnsRecord[]>;\n\nexport function dnsRecordDrift(\n byZone: DnsRecordsByZone,\n resources: DnsRecordResourceConfig[],\n tenant: TenantMeta,\n env: string,\n state: StateManager,\n): ResourceDrift {\n const drift: ResourceDrift = {\n kind: \"dns_record\",\n missingFromCloudflare: [],\n unrecordedInState: [],\n undeployed: [],\n };\n\n const stateRecords = Object.values(state.getAll()).filter(\n (e): e is DnsRecordStateEntry => e.type === \"dns_record\",\n );\n\n for (const config of resources) {\n if (!dnsRecordAppliesToEnv(config, env)) continue;\n const live = byZone.get(config.zoneId) ?? [];\n const marker = dnsRecordCommentMarker(tenant, env, config.logicalName);\n const stateKey = dnsRecordStateKey(config.zoneId, config.type, config.name);\n const entry = stateRecords.find(\n (e) =>\n e.zoneId === config.zoneId &&\n e.recordType === config.type &&\n e.logicalName === config.logicalName,\n );\n const onCf = entry\n ? live.find((r) => r.id === entry.recordId)\n : live.find(\n (r) =>\n r.type === config.type &&\n typeof r.comment === \"string\" &&\n r.comment.startsWith(marker),\n );\n\n if (entry && !onCf) {\n drift.missingFromCloudflare.push({\n logicalName: entry.logicalName,\n derivedName: `${entry.recordType} ${entry.name}`,\n cfId: entry.recordId,\n });\n } else if (onCf && !entry) {\n drift.unrecordedInState.push({\n logicalName: config.logicalName,\n derivedName: `${config.type} ${onCf.name}`,\n cfId: onCf.id,\n });\n } else if (!onCf && !entry) {\n drift.undeployed.push({\n logicalName: config.logicalName,\n derivedName: `${config.type} ${config.name}`,\n detail: stateKey,\n });\n }\n }\n\n return drift;\n}\n","/**\n * Read-only drift report comparing recorded state vs. Cloudflare reality vs.\n * the current `tamer.config.ts`.\n */\n\nexport type DriftKind =\n | \"d1\"\n | \"r2\"\n | \"kv\"\n | \"queue\"\n | \"hyperdrive\"\n | \"vectorize\"\n | \"ai_gateway\"\n | \"pipeline\"\n | \"workflow\"\n | \"secret_store\"\n | \"secret\"\n | \"dns_record\"\n | \"dispatch_namespace\"\n | \"logpush_job\"\n | \"tenant\"\n | \"worker_route\"\n | \"worker_script\";\n\nexport interface DriftEntry {\n /** Logical resource name from `tamer.config.ts`. */\n logicalName: string;\n /** Cloudflare-side name (or `(unknown)` when no CF or state side knows it). */\n derivedName: string;\n /** Cloudflare resource ID, when known (D1 uuid, KV id). */\n cfId?: string;\n /** Optional human-readable detail (e.g. shard date). */\n detail?: string;\n}\n\nexport interface ResourceDrift {\n kind: DriftKind;\n /** Tracked in state but no longer present on Cloudflare. */\n missingFromCloudflare: DriftEntry[];\n /**\n * Present on Cloudflare and matches a declared resource in this config,\n * but no state entry tracks it (e.g. created out-of-band).\n */\n unrecordedInState: DriftEntry[];\n /**\n * Declared in this stack's config but neither tracked in state nor present\n * on Cloudflare (run `tamer apply`).\n */\n undeployed: DriftEntry[];\n}\n\nexport interface DriftReport {\n tenantId: string;\n env: string;\n generatedAt: string;\n resources: ResourceDrift[];\n /** True iff any of the three categories has at least one entry. */\n hasDrift: boolean;\n}\n\nexport function resourceDriftIsClean(d: ResourceDrift): boolean {\n return (\n d.missingFromCloudflare.length === 0 &&\n d.unrecordedInState.length === 0 &&\n d.undeployed.length === 0\n );\n}\n\nexport function reportHasDrift(resources: ResourceDrift[]): boolean {\n return resources.some((d) => !resourceDriftIsClean(d));\n}\n","import type { CFApiClient } from \"../api/CFApiClient.js\";\nimport type { StateManager } from \"../state/StateManager.js\";\nimport type { ResourceDrift } from \"./drift.types.js\";\nimport { tenantStateKey } from \"../tenant/tenantKeys.js\";\n\ninterface CFD1 {\n uuid: string;\n name: string;\n}\n\n/**\n * Drift for workspace tenants in {@link CfiState.tenants}: dispatch script and\n * recorded D1 shards must still exist on Cloudflare.\n *\n * `unrecordedInState` / `undeployed` are intentionally empty here — tenant\n * discovery from CF alone is heuristic until product/script naming is fully\n * pinned (`docs/scope-remaining.md` D-1).\n */\nexport async function tenantDrift(\n state: StateManager,\n api: CFApiClient,\n allD1: CFD1[],\n): Promise<ResourceDrift> {\n const drift: ResourceDrift = {\n kind: \"tenant\",\n missingFromCloudflare: [],\n unrecordedInState: [],\n undeployed: [],\n };\n\n const d1ById = new Map(allD1.map((d) => [d.uuid, d.name]));\n const tenants = state\n .listTenants()\n .filter((t) => t.provisioningStatus !== \"tombstoned\");\n if (tenants.length === 0) return drift;\n\n const scriptLists = new Map<string, Set<string>>();\n async function scriptsInNs(ns: string): Promise<Set<string>> {\n let set = scriptLists.get(ns);\n if (!set) {\n const list = await api.dispatchNamespaceScriptList(ns);\n set = new Set(list.map((s) => s.id));\n scriptLists.set(ns, set);\n }\n return set;\n }\n\n for (const t of tenants) {\n const logical = tenantStateKey(t.product, t.workspace);\n try {\n const ids = await scriptsInNs(t.dispatchNamespaceName);\n if (!ids.has(t.scriptName)) {\n drift.missingFromCloudflare.push({\n logicalName: logical,\n derivedName: t.scriptName,\n detail: \"dispatch_script\",\n });\n }\n } catch {\n drift.missingFromCloudflare.push({\n logicalName: logical,\n derivedName: t.dispatchNamespaceName,\n detail: \"dispatch_namespace_list_failed\",\n });\n }\n\n for (const shard of t.d1Shards ?? []) {\n if (!d1ById.has(shard.cfId)) {\n drift.missingFromCloudflare.push({\n logicalName: logical,\n derivedName: shard.derivedName,\n cfId: shard.cfId,\n detail: `d1:${shard.role}`,\n });\n }\n }\n }\n\n return drift;\n}\n","import { loadConfig, getWorkers } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport { dispatchNamespaceDrift } from \"../../features/dispatch-namespace/index.js\";\nimport {\n dnsRecordDrift,\n type DnsRecordsByZone,\n} from \"../../features/dns-records/index.js\";\nimport { getDispatchNamespaces, getDnsRecords, getLogpushJobs } from \"../../types.js\";\nimport { logpushJobDrift } from \"../../features/logpush-job/index.js\";\nimport type {\n DriftReport,\n ResourceDrift,\n} from \"../../core/drift/drift.types.js\";\nimport { reportHasDrift } from \"../../core/drift/drift.types.js\";\nimport { tenantDrift } from \"../../core/drift/tenantDrift.js\";\nimport { workerRoutesDrift } from \"../../features/worker-route/index.js\";\nimport { workersDrift } from \"../../features/workers/index.js\";\nimport { resourceModules } from \"../../core/registry/registry.js\";\nimport { fetchStackImports } from \"../../core/imports/fetchStackImports.js\";\nimport { mergeWorkerConfigForResourcePick } from \"../../core/config/resolver.js\";\nimport { resolveDeployedWorkerName } from \"../../core/config/resolver.js\";\nimport { requiredSecretsForWorker } from \"../../core/secrets/declared.js\";\nimport {\n reconcileSecrets,\n secretsDrift,\n vaultReaderFromMap,\n type SecretsVaultReader,\n} from \"../../core/secrets/reconcile.js\";\n\n/**\n * Compute a read-only drift report for the given env.\n *\n * Compares Tamer state (D1 `tamer-state-{env}`) against the Cloudflare API\n * and the resources declared in `tamer.config.ts`. Reports three categories:\n *\n * - `missingFromCloudflare` — tracked in state but the CF resource is gone.\n * - `unrecordedInState` — exists on CF and matches a declared resource, but\n * no state entry tracks it (e.g. created out-of-band; run `tamer sync`).\n * - `undeployed` — declared in this stack's config, present in neither\n * state nor CF (run `tamer apply`).\n *\n * Pure: never writes to state. Returns the report so callers can choose how to\n * render or consume it.\n */\nexport async function computeDriftReport(options: {\n env?: string;\n configPath?: string;\n /** Optional vault reader for secret reconciliation (defaults to empty). */\n secretsVault?: SecretsVaultReader;\n}): Promise<DriftReport> {\n const env = options.env ?? \"local\";\n const configPath = options.configPath;\n const baseDir = process.cwd();\n\n const config = await loadConfig(configPath, { env });\n const accountId = config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n const api = new CFApiClient(accountId);\n const naming = namingFromConfig(config);\n const state = new StateManager(\n config.tenant.id,\n env,\n stackNameForConfig(config),\n );\n await state.hydrate(api);\n // Tolerant pre-fetch keeps drift accurate when worker `tamerRoutes`\n // depend on sibling-stack outputs (otherwise the placeholder pattern\n // would never match anything CF returned).\n const imports = await fetchStackImports(api, config, env).catch(() => ({}));\n\n async function safeList<T>(\n label: string,\n fn: () => Promise<T[]>,\n ): Promise<T[]> {\n try {\n return await fn();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[drift] skipping ${label}: ${msg}`);\n return [];\n }\n }\n\n const lists = await Promise.all(\n resourceModules.map((m) =>\n safeList(`${m.label} list`, () => m.fetchAll(api)),\n ),\n );\n\n const allDispatch =\n getDispatchNamespaces(config).length > 0\n ? await safeList(\"dispatch namespaces\", () =>\n api.dispatchNamespaceListAll(),\n )\n : [];\n\n const allLogpushJobs =\n getLogpushJobs(config).length > 0 && env !== \"local\"\n ? await safeList(\"logpush jobs\", () => api.logpushAccountJobsList())\n : [];\n\n const workers = await getWorkers(config, baseDir);\n\n const aggregated = new Map<string, ResourceDrift>();\n function merge(d: ResourceDrift): void {\n const existing = aggregated.get(d.kind);\n if (!existing) {\n aggregated.set(d.kind, d);\n return;\n }\n existing.missingFromCloudflare.push(...d.missingFromCloudflare);\n existing.unrecordedInState.push(...d.unrecordedInState);\n existing.undeployed.push(...d.undeployed);\n }\n\n for (const [workerKey, workerConfig] of workers) {\n const mergedWorker = mergeWorkerConfigForResourcePick(\n config,\n workerKey,\n workerConfig,\n env,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\", imports },\n );\n resourceModules.forEach((mod, i) => {\n const resources = mod.pickResources(mergedWorker);\n if (resources.length === 0) return;\n merge(\n mod.drift({\n resources,\n all: lists[i],\n tenant: config.tenant,\n env,\n api,\n state,\n naming,\n config,\n baseDir,\n }),\n );\n });\n }\n\n const dispatchResources = getDispatchNamespaces(config);\n if (dispatchResources.length > 0) {\n merge(\n dispatchNamespaceDrift(\n allDispatch,\n dispatchResources,\n env,\n config.tenant,\n state,\n ),\n );\n }\n\n const dnsResources = getDnsRecords(config);\n if (dnsResources.length > 0 && env !== \"local\") {\n const byZone: DnsRecordsByZone = new Map();\n const zones = Array.from(new Set(dnsResources.map((r) => r.zoneId)));\n for (const zoneId of zones) {\n const live = await safeList(`dns records (zone ${zoneId})`, () =>\n api.zoneDnsRecordListAll(zoneId),\n );\n byZone.set(zoneId, live);\n }\n merge(dnsRecordDrift(byZone, dnsResources, config.tenant, env, state));\n }\n\n const logpushResources = getLogpushJobs(config);\n if (logpushResources.length > 0 && env !== \"local\") {\n merge(\n logpushJobDrift(\n allLogpushJobs,\n logpushResources,\n env,\n config.tenant,\n state,\n ),\n );\n }\n\n if (state.listTenants().length > 0) {\n const allD1Idx = resourceModules.findIndex((m) => m.kind === \"d1\");\n const allD1 =\n allD1Idx >= 0\n ? (lists[allD1Idx] as Array<{ uuid: string; name: string }>)\n : [];\n merge(await tenantDrift(state, api, allD1));\n }\n\n const workerRouteReport = await workerRoutesDrift(\n env,\n config,\n baseDir,\n accountId,\n naming,\n state,\n api,\n { imports },\n );\n if (workerRouteReport) merge(workerRouteReport);\n\n const workerScriptReport = await workersDrift(\n env,\n config,\n baseDir,\n accountId,\n naming,\n state,\n api,\n { imports },\n );\n if (workerScriptReport) merge(workerScriptReport);\n\n const secretWorkers = await buildSecretWorkerInputs(\n workers,\n config,\n env,\n baseDir,\n accountId,\n naming,\n state,\n api,\n imports,\n );\n if (secretWorkers.length > 0) {\n const secretEntries = await reconcileSecrets({\n workers: secretWorkers,\n vault: options.secretsVault ?? vaultReaderFromMap({}),\n state,\n });\n merge(secretsDrift(secretEntries));\n }\n\n const dedupedResources = Array.from(aggregated.values()).map((d) => ({\n ...d,\n missingFromCloudflare: dedupe(d.missingFromCloudflare),\n unrecordedInState: dedupe(d.unrecordedInState),\n undeployed: dedupe(d.undeployed),\n }));\n\n return {\n tenantId: config.tenant.id,\n env,\n generatedAt: new Date().toISOString(),\n resources: dedupedResources,\n hasDrift: reportHasDrift(dedupedResources),\n };\n}\n\nfunction dedupe<T extends { logicalName: string; derivedName: string }>(\n list: T[],\n): T[] {\n const seen = new Set<string>();\n const out: T[] = [];\n for (const item of list) {\n const key = `${item.logicalName}::${item.derivedName}`;\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(item);\n }\n return out;\n}\n\n/**\n * CLI entry point. Prints a human report (or JSON when `--json`) and sets a\n * non-zero process exit code when drift is found.\n */\nexport async function runDrift(options: {\n env?: string;\n configPath?: string;\n json?: boolean;\n}): Promise<number> {\n const report = await computeDriftReport({\n env: options.env,\n configPath: options.configPath,\n });\n\n if (options.json) {\n console.log(JSON.stringify(report, null, 2));\n } else {\n printHumanReport(report);\n }\n\n return report.hasDrift ? 1 : 0;\n}\n\nfunction printHumanReport(report: DriftReport): void {\n console.log(\n `\\nDrift report — tenant ${report.tenantId}, env ${report.env}\\n`,\n );\n if (report.resources.length === 0) {\n console.log(\" (no managed resource kinds in this config)\\n\");\n return;\n }\n for (const d of report.resources) {\n const total =\n d.missingFromCloudflare.length +\n d.unrecordedInState.length +\n d.undeployed.length;\n console.log(`${labelFor(d.kind)} (${total} drift):`);\n if (total === 0) {\n console.log(\" ok\");\n continue;\n }\n if (d.missingFromCloudflare.length) {\n console.log(\" missing from Cloudflare (state references gone):\");\n for (const e of d.missingFromCloudflare) {\n console.log(` - ${e.logicalName} -> ${e.derivedName}${suffix(e.cfId)}`);\n }\n }\n if (d.unrecordedInState.length) {\n console.log(\" unrecorded in state (run `tamer sync`):\");\n for (const e of d.unrecordedInState) {\n console.log(` - ${e.logicalName} -> ${e.derivedName}${suffix(e.cfId)}`);\n }\n }\n if (d.undeployed.length) {\n console.log(\" undeployed (run `tamer apply`):\");\n for (const e of d.undeployed) {\n console.log(` - ${e.logicalName} -> ${e.derivedName}`);\n }\n }\n }\n console.log(report.hasDrift ? \"\\nDrift detected.\\n\" : \"\\nNo drift.\\n\");\n}\n\nconst REGISTRY_LABELS: Record<string, string> = Object.fromEntries(\n resourceModules.map((m) => [m.kind, m.label]),\n);\n\nfunction labelFor(kind: ResourceDrift[\"kind\"]): string {\n if (REGISTRY_LABELS[kind]) return REGISTRY_LABELS[kind];\n switch (kind) {\n case \"dispatch_namespace\":\n return \"Dispatch namespaces\";\n case \"logpush_job\":\n return \"Logpush jobs\";\n case \"dns_record\":\n return \"DNS records\";\n case \"tenant\":\n return \"Workspace tenants\";\n case \"worker_route\":\n return \"HTTP routes (Workers Routes API)\";\n case \"worker_script\":\n return \"Worker scripts\";\n case \"secret\":\n return \"Worker secrets\";\n default:\n return kind;\n }\n}\n\nfunction suffix(cfId?: string): string {\n return cfId ? ` [${cfId}]` : \"\";\n}\n\nasync function buildSecretWorkerInputs(\n workers: Awaited<ReturnType<typeof getWorkers>>,\n config: Awaited<ReturnType<typeof loadConfig>>,\n env: string,\n baseDir: string,\n accountId: string,\n naming: ReturnType<typeof namingFromConfig>,\n state: StateManager,\n api: CFApiClient,\n imports: Awaited<ReturnType<typeof fetchStackImports>>,\n): Promise<\n Array<{\n workerKey: string;\n required: string[];\n workerSecretNames: string[];\n }>\n> {\n const out: Array<{\n workerKey: string;\n required: string[];\n workerSecretNames: string[];\n }> = [];\n\n for (const [workerKey, workerConfig] of workers) {\n const merged = mergeWorkerConfigForResourcePick(\n config,\n workerKey,\n workerConfig,\n env,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\", imports },\n );\n const required = requiredSecretsForWorker(merged);\n if (required.length === 0) continue;\n\n const deployedName = resolveDeployedWorkerName(\n config,\n workerKey,\n workerConfig,\n env,\n naming,\n );\n let workerSecretNames: string[] = [];\n if (env !== \"local\") {\n try {\n workerSecretNames = await api.workersSecretsList(deployedName);\n } catch {\n workerSecretNames = [];\n }\n }\n\n out.push({ workerKey, required, workerSecretNames });\n }\n\n return out;\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { k as resolveWorkerConfig } from "./tamer.mjs";
|
|
2
|
-
import { a as d1CloudflareDatabaseName, o as d1SkipsProvisionAndMigrate } from "./registry-
|
|
2
|
+
import { a as d1CloudflareDatabaseName, o as d1SkipsProvisionAndMigrate } from "./registry-DyToEush.mjs";
|
|
3
3
|
import { dirname, join } from "path";
|
|
4
4
|
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
5
5
|
|
|
@@ -138,4 +138,4 @@ async function assertShardRegistryPresentForDeploy(args) {
|
|
|
138
138
|
|
|
139
139
|
//#endregion
|
|
140
140
|
export { emitShardRegistryOnApply as n, assertShardRegistryPresentForDeploy as t };
|
|
141
|
-
//# sourceMappingURL=emit-
|
|
141
|
+
//# sourceMappingURL=emit-BUPlQH-r.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit-DTpaIMkn.mjs","names":["row: ShardRegistryEntryV1","shards: ShardRegistryEntryV1[]"],"sources":["../src/core/codegen/shardRegistry/build.ts","../src/core/codegen/shardRegistry/emit.ts"],"sourcesContent":["import type { WranglerD1Database } from \"../../../generated/wrangler-types.js\";\nimport type { NamingEngine } from \"../../naming/NamingEngine.js\";\nimport type { StateManager } from \"../../state/StateManager.js\";\nimport type {\n D1ResourceConfig,\n D1StateEntry,\n ShardRegistryEntryV1,\n ShardRegistryV1,\n} from \"../../../types.js\";\nimport {\n d1CloudflareDatabaseName,\n d1SkipsProvisionAndMigrate,\n} from \"../../../features/d1/d1.ownership.js\";\n\nfunction registryRoleFor(config: D1ResourceConfig): string {\n return config.registryRole?.trim() || config.logicalName;\n}\n\nfunction optionalAliases(values: string[] | undefined): string[] | undefined {\n if (!values?.length) return undefined;\n const trimmed = values.map((v) => v.trim()).filter(Boolean);\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction entryFromState(\n config: D1ResourceConfig,\n databaseName: string,\n binding: string,\n shardDate?: string,\n): ShardRegistryEntryV1 {\n const row: ShardRegistryEntryV1 = {\n id: databaseName,\n role: registryRoleFor(config),\n binding,\n databaseName,\n };\n if (shardDate) row.shardDate = shardDate;\n if (config.current === false) row.current = false;\n const legacyIds = optionalAliases(config.legacyIds);\n const legacyBindings = optionalAliases(config.legacyBindings);\n if (legacyIds) row.legacyIds = legacyIds;\n if (legacyBindings) row.legacyBindings = legacyBindings;\n return row;\n}\n\n/**\n * Build {@link ShardRegistryV1} for env `E` from merged worker D1 config +\n * hydrated state. Uses the same binding/name resolution path as wrangler\n * generation (`d1DeriveBindingKey`, state `bindingKey`, ownership helpers).\n */\nexport function buildShardRegistryV1(\n resources: D1ResourceConfig[],\n env: string,\n state: StateManager,\n naming: NamingEngine,\n): ShardRegistryV1 {\n const shards: ShardRegistryEntryV1[] = [];\n\n for (const config of resources) {\n if (config.type === \"single\") {\n const derivedName = d1CloudflareDatabaseName(config, env, naming);\n const entry = state.get(derivedName);\n if (!entry || entry.type !== \"d1_database\") {\n if (d1SkipsProvisionAndMigrate(config)) {\n throw new Error(\n `shard registry: cross-stack D1 \"${config.logicalName}\" (${derivedName}) not in state — ` +\n `deploy the owning stack first, then re-run apply for env \"${env}\".`,\n );\n }\n throw new Error(\n `shard registry: D1 \"${config.logicalName}\" not in state — run \\`tamer apply --env ${env}\\` first.`,\n );\n }\n shards.push(\n entryFromState(\n config,\n derivedName,\n entry.bindingKey,\n ),\n );\n continue;\n }\n\n const allResources = state.getAll();\n const stateShards = Object.values(allResources).filter(\n (e): e is D1StateEntry =>\n e.type === \"d1_database\" && e.logicalName === config.logicalName,\n );\n if (stateShards.length === 0) {\n throw new Error(\n `shard registry: no shards in state for \"${config.logicalName}\" — run \\`tamer apply --env ${env}\\` first.`,\n );\n }\n\n for (const shard of stateShards) {\n shards.push(\n entryFromState(\n config,\n shard.derivedName,\n shard.bindingKey,\n shard.shardDate,\n ),\n );\n }\n }\n\n shards.sort((a, b) => a.binding.localeCompare(b.binding));\n\n return { version: 1, shards };\n}\n\nexport class ShardRegistryDriftError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ShardRegistryDriftError\";\n }\n}\n\n/**\n * Assert generated wrangler D1 bindings match the registry for apply env `E`.\n */\nexport function assertShardRegistryWranglerDrift(\n registry: ShardRegistryV1,\n wranglerD1: WranglerD1Database[] | undefined,\n env: string,\n): void {\n const d1List = wranglerD1 ?? [];\n const byBinding = new Map(registry.shards.map((s) => [s.binding, s]));\n\n for (const d1 of d1List) {\n const row = byBinding.get(d1.binding);\n if (!row) {\n throw new ShardRegistryDriftError(\n `shard registry drift (${env}): wrangler binding \"${d1.binding}\" has no registry row — ` +\n `re-run \\`tamer apply --env ${env}\\` or fix resources.d1 / state.`,\n );\n }\n if (d1.database_name !== row.databaseName) {\n throw new ShardRegistryDriftError(\n `shard registry drift (${env}): binding \"${d1.binding}\" wrangler database_name ` +\n `\"${d1.database_name}\" !== registry databaseName \"${row.databaseName}\".`,\n );\n }\n if (d1.database_name !== row.id) {\n throw new ShardRegistryDriftError(\n `shard registry drift (${env}): binding \"${d1.binding}\" wrangler database_name ` +\n `\"${d1.database_name}\" !== registry id \"${row.id}\".`,\n );\n }\n byBinding.delete(d1.binding);\n }\n\n for (const [binding, row] of byBinding) {\n throw new ShardRegistryDriftError(\n `shard registry drift (${env}): registry binding \"${binding}\" (${row.role}) ` +\n `missing from generated wrangler d1_databases — re-run \\`tamer apply --env ${env}\\`.`,\n );\n }\n}\n","import { existsSync, mkdirSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport type { WranglerConfig } from \"../../../generated/wrangler-types.js\";\nimport type { NamingEngine } from \"../../naming/NamingEngine.js\";\nimport type { StateManager } from \"../../state/StateManager.js\";\nimport { resolveWorkerConfig } from \"../../config/resolver.js\";\nimport type {\n CfiConfig,\n ShardRegistryCodegenConfig,\n WorkerConfig,\n} from \"../../../types.js\";\nimport {\n assertShardRegistryWranglerDrift,\n buildShardRegistryV1,\n} from \"./build.js\";\n\nconst DEFAULT_OUT_FILE = \"src/db/shard-registry.ts\";\nconst DEFAULT_EXPORT_NAME = \"shardRegistry\";\n\nexport function resolveShardRegistryWorkerKey(\n workers: Array<[string, WorkerConfig]>,\n spec?: ShardRegistryCodegenConfig,\n): string {\n if (spec?.worker) {\n const hit = workers.find(([key]) => key === spec.worker);\n if (!hit) {\n throw new Error(\n `codegen.shardRegistry.worker \"${spec.worker}\" not found in stack workers`,\n );\n }\n return spec.worker;\n }\n if (workers.length === 1) {\n return workers[0]![0];\n }\n throw new Error(\n \"codegen.shardRegistry.worker is required when the stack declares multiple workers\",\n );\n}\n\nexport function shardRegistryOutPath(\n workerDir: string,\n spec?: ShardRegistryCodegenConfig,\n): string {\n return join(workerDir, spec?.outFile?.trim() || DEFAULT_OUT_FILE);\n}\n\nexport function renderShardRegistryModule(\n registry: ReturnType<typeof buildShardRegistryV1>,\n env: string,\n exportName: string = DEFAULT_EXPORT_NAME,\n): string {\n const body = JSON.stringify(registry, null, 2);\n return `/** Generated by @dragonmastery/tamer — do not edit. Re-run \\`tamer apply --env ${env}\\`. */\nimport type { ShardRegistryV1 } from \"@dragonmastery/tamer\";\n\nexport const ${exportName}: ShardRegistryV1 = ${body};\n`;\n}\n\nexport function writeShardRegistryModule(\n workerDir: string,\n content: string,\n spec?: ShardRegistryCodegenConfig,\n): string {\n const path = shardRegistryOutPath(workerDir, spec);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, content, \"utf-8\");\n return path;\n}\n\nexport async function emitShardRegistryOnApply(args: {\n config: CfiConfig;\n env: string;\n baseDir: string;\n accountId: string;\n naming: NamingEngine;\n state: StateManager;\n imports: Awaited<\n ReturnType<\n typeof import(\"../../imports/fetchStackImports.js\").fetchStackImports\n >\n >;\n workers: Array<[string, WorkerConfig]>;\n wranglerByWorker: Map<string, WranglerConfig>;\n}): Promise<string | undefined> {\n const spec = args.config.codegen?.shardRegistry;\n if (!spec) return undefined;\n\n const workerKey = resolveShardRegistryWorkerKey(args.workers, spec);\n const workerEntry = args.workers.find(([key]) => key === workerKey);\n if (!workerEntry) {\n throw new Error(`codegen.shardRegistry: worker \"${workerKey}\" not found`);\n }\n const [, workerConfig] = workerEntry;\n\n const resolved = await resolveWorkerConfig(\n args.config,\n workerKey,\n workerConfig,\n args.env,\n args.baseDir,\n args.accountId,\n args.naming,\n args.state,\n { imports: args.imports },\n );\n const d1Resources = resolved.resources?.d1 ?? [];\n if (d1Resources.length === 0) {\n throw new Error(\n `codegen.shardRegistry: worker \"${workerKey}\" has no resources.d1 entries`,\n );\n }\n\n const registry = buildShardRegistryV1(\n d1Resources,\n args.env,\n args.state,\n args.naming,\n );\n\n const wrangler = args.wranglerByWorker.get(workerKey);\n if (!wrangler) {\n throw new Error(\n `codegen.shardRegistry: missing generated wrangler config for worker \"${workerKey}\"`,\n );\n }\n assertShardRegistryWranglerDrift(registry, wrangler.d1_databases, args.env);\n\n const exportName = spec.exportName?.trim() || DEFAULT_EXPORT_NAME;\n const content = renderShardRegistryModule(registry, args.env, exportName);\n const written = writeShardRegistryModule(resolved.workerDir, content, spec);\n console.log(\n `Generated shard registry for ${workerKey}: ${spec.outFile ?? DEFAULT_OUT_FILE}`,\n );\n return written;\n}\n\nexport async function assertShardRegistryPresentForDeploy(args: {\n config: CfiConfig;\n env: string;\n baseDir: string;\n accountId: string;\n naming: NamingEngine;\n state: StateManager;\n imports: Awaited<\n ReturnType<\n typeof import(\"../../imports/fetchStackImports.js\").fetchStackImports\n >\n >;\n workers: Array<[string, WorkerConfig]>;\n}): Promise<void> {\n const spec = args.config.codegen?.shardRegistry;\n if (!spec) return;\n\n const workerKey = resolveShardRegistryWorkerKey(args.workers, spec);\n const workerEntry = args.workers.find(([key]) => key === workerKey);\n if (!workerEntry) {\n throw new Error(`codegen.shardRegistry: worker \"${workerKey}\" not found`);\n }\n const [, workerConfig] = workerEntry;\n\n const resolved = await resolveWorkerConfig(\n args.config,\n workerKey,\n workerConfig,\n args.env,\n args.baseDir,\n args.accountId,\n args.naming,\n args.state,\n { imports: args.imports },\n );\n const path = shardRegistryOutPath(resolved.workerDir, spec);\n if (!existsSync(path)) {\n throw new Error(\n `Missing shard registry at ${spec.outFile ?? DEFAULT_OUT_FILE} for worker \"${workerKey}\". ` +\n `Run \\`tamer apply --env ${args.env}\\` before deploy.`,\n );\n }\n}\n"],"mappings":";;;;;;AAcA,SAAS,gBAAgB,QAAkC;AACzD,QAAO,OAAO,cAAc,MAAM,IAAI,OAAO;;AAG/C,SAAS,gBAAgB,QAAoD;AAC3E,KAAI,CAAC,QAAQ,OAAQ,QAAO;CAC5B,MAAM,UAAU,OAAO,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC,OAAO,QAAQ;AAC3D,QAAO,QAAQ,SAAS,IAAI,UAAU;;AAGxC,SAAS,eACP,QACA,cACA,SACA,WACsB;CACtB,MAAMA,MAA4B;EAChC,IAAI;EACJ,MAAM,gBAAgB,OAAO;EAC7B;EACA;EACD;AACD,KAAI,UAAW,KAAI,YAAY;AAC/B,KAAI,OAAO,YAAY,MAAO,KAAI,UAAU;CAC5C,MAAM,YAAY,gBAAgB,OAAO,UAAU;CACnD,MAAM,iBAAiB,gBAAgB,OAAO,eAAe;AAC7D,KAAI,UAAW,KAAI,YAAY;AAC/B,KAAI,eAAgB,KAAI,iBAAiB;AACzC,QAAO;;;;;;;AAQT,SAAgB,qBACd,WACA,KACA,OACA,QACiB;CACjB,MAAMC,SAAiC,EAAE;AAEzC,MAAK,MAAM,UAAU,WAAW;AAC9B,MAAI,OAAO,SAAS,UAAU;GAC5B,MAAM,cAAc,yBAAyB,QAAQ,KAAK,OAAO;GACjE,MAAM,QAAQ,MAAM,IAAI,YAAY;AACpC,OAAI,CAAC,SAAS,MAAM,SAAS,eAAe;AAC1C,QAAI,2BAA2B,OAAO,CACpC,OAAM,IAAI,MACR,mCAAmC,OAAO,YAAY,KAAK,YAAY,6EACR,IAAI,IACpE;AAEH,UAAM,IAAI,MACR,uBAAuB,OAAO,YAAY,2CAA2C,IAAI,WAC1F;;AAEH,UAAO,KACL,eACE,QACA,aACA,MAAM,WACP,CACF;AACD;;EAGF,MAAM,eAAe,MAAM,QAAQ;EACnC,MAAM,cAAc,OAAO,OAAO,aAAa,CAAC,QAC7C,MACC,EAAE,SAAS,iBAAiB,EAAE,gBAAgB,OAAO,YACxD;AACD,MAAI,YAAY,WAAW,EACzB,OAAM,IAAI,MACR,2CAA2C,OAAO,YAAY,8BAA8B,IAAI,WACjG;AAGH,OAAK,MAAM,SAAS,YAClB,QAAO,KACL,eACE,QACA,MAAM,aACN,MAAM,YACN,MAAM,UACP,CACF;;AAIL,QAAO,MAAM,GAAG,MAAM,EAAE,QAAQ,cAAc,EAAE,QAAQ,CAAC;AAEzD,QAAO;EAAE,SAAS;EAAG;EAAQ;;AAG/B,IAAa,0BAAb,cAA6C,MAAM;CACjD,YAAY,SAAiB;AAC3B,QAAM,QAAQ;AACd,OAAK,OAAO;;;;;;AAOhB,SAAgB,iCACd,UACA,YACA,KACM;CACN,MAAM,SAAS,cAAc,EAAE;CAC/B,MAAM,YAAY,IAAI,IAAI,SAAS,OAAO,KAAK,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;AAErE,MAAK,MAAM,MAAM,QAAQ;EACvB,MAAM,MAAM,UAAU,IAAI,GAAG,QAAQ;AACrC,MAAI,CAAC,IACH,OAAM,IAAI,wBACR,yBAAyB,IAAI,uBAAuB,GAAG,QAAQ,qDAC/B,IAAI,iCACrC;AAEH,MAAI,GAAG,kBAAkB,IAAI,aAC3B,OAAM,IAAI,wBACR,yBAAyB,IAAI,cAAc,GAAG,QAAQ,4BAChD,GAAG,cAAc,+BAA+B,IAAI,aAAa,IACxE;AAEH,MAAI,GAAG,kBAAkB,IAAI,GAC3B,OAAM,IAAI,wBACR,yBAAyB,IAAI,cAAc,GAAG,QAAQ,4BAChD,GAAG,cAAc,qBAAqB,IAAI,GAAG,IACpD;AAEH,YAAU,OAAO,GAAG,QAAQ;;AAG9B,MAAK,MAAM,CAAC,SAAS,QAAQ,UAC3B,OAAM,IAAI,wBACR,yBAAyB,IAAI,uBAAuB,QAAQ,KAAK,IAAI,KAAK,8EACK,IAAI,KACpF;;;;;AC5IL,MAAM,mBAAmB;AACzB,MAAM,sBAAsB;AAE5B,SAAgB,8BACd,SACA,MACQ;AACR,KAAI,MAAM,QAAQ;AAEhB,MAAI,CADQ,QAAQ,MAAM,CAAC,SAAS,QAAQ,KAAK,OAAO,CAEtD,OAAM,IAAI,MACR,iCAAiC,KAAK,OAAO,8BAC9C;AAEH,SAAO,KAAK;;AAEd,KAAI,QAAQ,WAAW,EACrB,QAAO,QAAQ,GAAI;AAErB,OAAM,IAAI,MACR,oFACD;;AAGH,SAAgB,qBACd,WACA,MACQ;AACR,QAAO,KAAK,WAAW,MAAM,SAAS,MAAM,IAAI,iBAAiB;;AAGnE,SAAgB,0BACd,UACA,KACA,aAAqB,qBACb;AAER,QAAO,mFAAmF,IAAI;;;eAGjF,WAAW,sBAJX,KAAK,UAAU,UAAU,MAAM,EAAE,CAIK;;;AAIrD,SAAgB,yBACd,WACA,SACA,MACQ;CACR,MAAM,OAAO,qBAAqB,WAAW,KAAK;AAClD,WAAU,QAAQ,KAAK,EAAE,EAAE,WAAW,MAAM,CAAC;AAC7C,eAAc,MAAM,SAAS,QAAQ;AACrC,QAAO;;AAGT,eAAsB,yBAAyB,MAcf;CAC9B,MAAM,OAAO,KAAK,OAAO,SAAS;AAClC,KAAI,CAAC,KAAM,QAAO;CAElB,MAAM,YAAY,8BAA8B,KAAK,SAAS,KAAK;CACnE,MAAM,cAAc,KAAK,QAAQ,MAAM,CAAC,SAAS,QAAQ,UAAU;AACnE,KAAI,CAAC,YACH,OAAM,IAAI,MAAM,kCAAkC,UAAU,aAAa;CAE3E,MAAM,GAAG,gBAAgB;CAEzB,MAAM,WAAW,MAAM,oBACrB,KAAK,QACL,WACA,cACA,KAAK,KACL,KAAK,SACL,KAAK,WACL,KAAK,QACL,KAAK,OACL,EAAE,SAAS,KAAK,SAAS,CAC1B;CACD,MAAM,cAAc,SAAS,WAAW,MAAM,EAAE;AAChD,KAAI,YAAY,WAAW,EACzB,OAAM,IAAI,MACR,kCAAkC,UAAU,+BAC7C;CAGH,MAAM,WAAW,qBACf,aACA,KAAK,KACL,KAAK,OACL,KAAK,OACN;CAED,MAAM,WAAW,KAAK,iBAAiB,IAAI,UAAU;AACrD,KAAI,CAAC,SACH,OAAM,IAAI,MACR,wEAAwE,UAAU,GACnF;AAEH,kCAAiC,UAAU,SAAS,cAAc,KAAK,IAAI;CAE3E,MAAM,aAAa,KAAK,YAAY,MAAM,IAAI;CAC9C,MAAM,UAAU,0BAA0B,UAAU,KAAK,KAAK,WAAW;CACzE,MAAM,UAAU,yBAAyB,SAAS,WAAW,SAAS,KAAK;AAC3E,SAAQ,IACN,gCAAgC,UAAU,IAAI,KAAK,WAAW,mBAC/D;AACD,QAAO;;AAGT,eAAsB,oCAAoC,MAaxC;CAChB,MAAM,OAAO,KAAK,OAAO,SAAS;AAClC,KAAI,CAAC,KAAM;CAEX,MAAM,YAAY,8BAA8B,KAAK,SAAS,KAAK;CACnE,MAAM,cAAc,KAAK,QAAQ,MAAM,CAAC,SAAS,QAAQ,UAAU;AACnE,KAAI,CAAC,YACH,OAAM,IAAI,MAAM,kCAAkC,UAAU,aAAa;CAE3E,MAAM,GAAG,gBAAgB;AAczB,KAAI,CAAC,WADQ,sBAXI,MAAM,oBACrB,KAAK,QACL,WACA,cACA,KAAK,KACL,KAAK,SACL,KAAK,WACL,KAAK,QACL,KAAK,OACL,EAAE,SAAS,KAAK,SAAS,CAC1B,EAC0C,WAAW,KAAK,CACtC,CACnB,OAAM,IAAI,MACR,6BAA6B,KAAK,WAAW,iBAAiB,eAAe,UAAU,6BAC1D,KAAK,IAAI,mBACvC"}
|
|
1
|
+
{"version":3,"file":"emit-BUPlQH-r.mjs","names":["row: ShardRegistryEntryV1","shards: ShardRegistryEntryV1[]"],"sources":["../src/core/codegen/shardRegistry/build.ts","../src/core/codegen/shardRegistry/emit.ts"],"sourcesContent":["import type { WranglerD1Database } from \"../../../generated/wrangler-types.js\";\nimport type { NamingEngine } from \"../../naming/NamingEngine.js\";\nimport type { StateManager } from \"../../state/StateManager.js\";\nimport type {\n D1ResourceConfig,\n D1StateEntry,\n ShardRegistryEntryV1,\n ShardRegistryV1,\n} from \"../../../types.js\";\nimport {\n d1CloudflareDatabaseName,\n d1SkipsProvisionAndMigrate,\n} from \"../../../features/d1/d1.ownership.js\";\n\nfunction registryRoleFor(config: D1ResourceConfig): string {\n return config.registryRole?.trim() || config.logicalName;\n}\n\nfunction optionalAliases(values: string[] | undefined): string[] | undefined {\n if (!values?.length) return undefined;\n const trimmed = values.map((v) => v.trim()).filter(Boolean);\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction entryFromState(\n config: D1ResourceConfig,\n databaseName: string,\n binding: string,\n shardDate?: string,\n): ShardRegistryEntryV1 {\n const row: ShardRegistryEntryV1 = {\n id: databaseName,\n role: registryRoleFor(config),\n binding,\n databaseName,\n };\n if (shardDate) row.shardDate = shardDate;\n if (config.current === false) row.current = false;\n const legacyIds = optionalAliases(config.legacyIds);\n const legacyBindings = optionalAliases(config.legacyBindings);\n if (legacyIds) row.legacyIds = legacyIds;\n if (legacyBindings) row.legacyBindings = legacyBindings;\n return row;\n}\n\n/**\n * Build {@link ShardRegistryV1} for env `E` from merged worker D1 config +\n * hydrated state. Uses the same binding/name resolution path as wrangler\n * generation (`d1DeriveBindingKey`, state `bindingKey`, ownership helpers).\n */\nexport function buildShardRegistryV1(\n resources: D1ResourceConfig[],\n env: string,\n state: StateManager,\n naming: NamingEngine,\n): ShardRegistryV1 {\n const shards: ShardRegistryEntryV1[] = [];\n\n for (const config of resources) {\n if (config.type === \"single\") {\n const derivedName = d1CloudflareDatabaseName(config, env, naming);\n const entry = state.get(derivedName);\n if (!entry || entry.type !== \"d1_database\") {\n if (d1SkipsProvisionAndMigrate(config)) {\n throw new Error(\n `shard registry: cross-stack D1 \"${config.logicalName}\" (${derivedName}) not in state — ` +\n `deploy the owning stack first, then re-run apply for env \"${env}\".`,\n );\n }\n throw new Error(\n `shard registry: D1 \"${config.logicalName}\" not in state — run \\`tamer apply --env ${env}\\` first.`,\n );\n }\n shards.push(\n entryFromState(\n config,\n derivedName,\n entry.bindingKey,\n ),\n );\n continue;\n }\n\n const allResources = state.getAll();\n const stateShards = Object.values(allResources).filter(\n (e): e is D1StateEntry =>\n e.type === \"d1_database\" && e.logicalName === config.logicalName,\n );\n if (stateShards.length === 0) {\n throw new Error(\n `shard registry: no shards in state for \"${config.logicalName}\" — run \\`tamer apply --env ${env}\\` first.`,\n );\n }\n\n for (const shard of stateShards) {\n shards.push(\n entryFromState(\n config,\n shard.derivedName,\n shard.bindingKey,\n shard.shardDate,\n ),\n );\n }\n }\n\n shards.sort((a, b) => a.binding.localeCompare(b.binding));\n\n return { version: 1, shards };\n}\n\nexport class ShardRegistryDriftError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ShardRegistryDriftError\";\n }\n}\n\n/**\n * Assert generated wrangler D1 bindings match the registry for apply env `E`.\n */\nexport function assertShardRegistryWranglerDrift(\n registry: ShardRegistryV1,\n wranglerD1: WranglerD1Database[] | undefined,\n env: string,\n): void {\n const d1List = wranglerD1 ?? [];\n const byBinding = new Map(registry.shards.map((s) => [s.binding, s]));\n\n for (const d1 of d1List) {\n const row = byBinding.get(d1.binding);\n if (!row) {\n throw new ShardRegistryDriftError(\n `shard registry drift (${env}): wrangler binding \"${d1.binding}\" has no registry row — ` +\n `re-run \\`tamer apply --env ${env}\\` or fix resources.d1 / state.`,\n );\n }\n if (d1.database_name !== row.databaseName) {\n throw new ShardRegistryDriftError(\n `shard registry drift (${env}): binding \"${d1.binding}\" wrangler database_name ` +\n `\"${d1.database_name}\" !== registry databaseName \"${row.databaseName}\".`,\n );\n }\n if (d1.database_name !== row.id) {\n throw new ShardRegistryDriftError(\n `shard registry drift (${env}): binding \"${d1.binding}\" wrangler database_name ` +\n `\"${d1.database_name}\" !== registry id \"${row.id}\".`,\n );\n }\n byBinding.delete(d1.binding);\n }\n\n for (const [binding, row] of byBinding) {\n throw new ShardRegistryDriftError(\n `shard registry drift (${env}): registry binding \"${binding}\" (${row.role}) ` +\n `missing from generated wrangler d1_databases — re-run \\`tamer apply --env ${env}\\`.`,\n );\n }\n}\n","import { existsSync, mkdirSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport type { WranglerConfig } from \"../../../generated/wrangler-types.js\";\nimport type { NamingEngine } from \"../../naming/NamingEngine.js\";\nimport type { StateManager } from \"../../state/StateManager.js\";\nimport { resolveWorkerConfig } from \"../../config/resolver.js\";\nimport type {\n CfiConfig,\n ShardRegistryCodegenConfig,\n WorkerConfig,\n} from \"../../../types.js\";\nimport {\n assertShardRegistryWranglerDrift,\n buildShardRegistryV1,\n} from \"./build.js\";\n\nconst DEFAULT_OUT_FILE = \"src/db/shard-registry.ts\";\nconst DEFAULT_EXPORT_NAME = \"shardRegistry\";\n\nexport function resolveShardRegistryWorkerKey(\n workers: Array<[string, WorkerConfig]>,\n spec?: ShardRegistryCodegenConfig,\n): string {\n if (spec?.worker) {\n const hit = workers.find(([key]) => key === spec.worker);\n if (!hit) {\n throw new Error(\n `codegen.shardRegistry.worker \"${spec.worker}\" not found in stack workers`,\n );\n }\n return spec.worker;\n }\n if (workers.length === 1) {\n return workers[0]![0];\n }\n throw new Error(\n \"codegen.shardRegistry.worker is required when the stack declares multiple workers\",\n );\n}\n\nexport function shardRegistryOutPath(\n workerDir: string,\n spec?: ShardRegistryCodegenConfig,\n): string {\n return join(workerDir, spec?.outFile?.trim() || DEFAULT_OUT_FILE);\n}\n\nexport function renderShardRegistryModule(\n registry: ReturnType<typeof buildShardRegistryV1>,\n env: string,\n exportName: string = DEFAULT_EXPORT_NAME,\n): string {\n const body = JSON.stringify(registry, null, 2);\n return `/** Generated by @dragonmastery/tamer — do not edit. Re-run \\`tamer apply --env ${env}\\`. */\nimport type { ShardRegistryV1 } from \"@dragonmastery/tamer\";\n\nexport const ${exportName}: ShardRegistryV1 = ${body};\n`;\n}\n\nexport function writeShardRegistryModule(\n workerDir: string,\n content: string,\n spec?: ShardRegistryCodegenConfig,\n): string {\n const path = shardRegistryOutPath(workerDir, spec);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, content, \"utf-8\");\n return path;\n}\n\nexport async function emitShardRegistryOnApply(args: {\n config: CfiConfig;\n env: string;\n baseDir: string;\n accountId: string;\n naming: NamingEngine;\n state: StateManager;\n imports: Awaited<\n ReturnType<\n typeof import(\"../../imports/fetchStackImports.js\").fetchStackImports\n >\n >;\n workers: Array<[string, WorkerConfig]>;\n wranglerByWorker: Map<string, WranglerConfig>;\n}): Promise<string | undefined> {\n const spec = args.config.codegen?.shardRegistry;\n if (!spec) return undefined;\n\n const workerKey = resolveShardRegistryWorkerKey(args.workers, spec);\n const workerEntry = args.workers.find(([key]) => key === workerKey);\n if (!workerEntry) {\n throw new Error(`codegen.shardRegistry: worker \"${workerKey}\" not found`);\n }\n const [, workerConfig] = workerEntry;\n\n const resolved = await resolveWorkerConfig(\n args.config,\n workerKey,\n workerConfig,\n args.env,\n args.baseDir,\n args.accountId,\n args.naming,\n args.state,\n { imports: args.imports },\n );\n const d1Resources = resolved.resources?.d1 ?? [];\n if (d1Resources.length === 0) {\n throw new Error(\n `codegen.shardRegistry: worker \"${workerKey}\" has no resources.d1 entries`,\n );\n }\n\n const registry = buildShardRegistryV1(\n d1Resources,\n args.env,\n args.state,\n args.naming,\n );\n\n const wrangler = args.wranglerByWorker.get(workerKey);\n if (!wrangler) {\n throw new Error(\n `codegen.shardRegistry: missing generated wrangler config for worker \"${workerKey}\"`,\n );\n }\n assertShardRegistryWranglerDrift(registry, wrangler.d1_databases, args.env);\n\n const exportName = spec.exportName?.trim() || DEFAULT_EXPORT_NAME;\n const content = renderShardRegistryModule(registry, args.env, exportName);\n const written = writeShardRegistryModule(resolved.workerDir, content, spec);\n console.log(\n `Generated shard registry for ${workerKey}: ${spec.outFile ?? DEFAULT_OUT_FILE}`,\n );\n return written;\n}\n\nexport async function assertShardRegistryPresentForDeploy(args: {\n config: CfiConfig;\n env: string;\n baseDir: string;\n accountId: string;\n naming: NamingEngine;\n state: StateManager;\n imports: Awaited<\n ReturnType<\n typeof import(\"../../imports/fetchStackImports.js\").fetchStackImports\n >\n >;\n workers: Array<[string, WorkerConfig]>;\n}): Promise<void> {\n const spec = args.config.codegen?.shardRegistry;\n if (!spec) return;\n\n const workerKey = resolveShardRegistryWorkerKey(args.workers, spec);\n const workerEntry = args.workers.find(([key]) => key === workerKey);\n if (!workerEntry) {\n throw new Error(`codegen.shardRegistry: worker \"${workerKey}\" not found`);\n }\n const [, workerConfig] = workerEntry;\n\n const resolved = await resolveWorkerConfig(\n args.config,\n workerKey,\n workerConfig,\n args.env,\n args.baseDir,\n args.accountId,\n args.naming,\n args.state,\n { imports: args.imports },\n );\n const path = shardRegistryOutPath(resolved.workerDir, spec);\n if (!existsSync(path)) {\n throw new Error(\n `Missing shard registry at ${spec.outFile ?? DEFAULT_OUT_FILE} for worker \"${workerKey}\". ` +\n `Run \\`tamer apply --env ${args.env}\\` before deploy.`,\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { H as loadConfig, R as CFApiClient, h as StateManager, w as stackNameForConfig, z as cloudflareAccountIdFromEnv } from "./tamer.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/cli/commands/events.ts
|
|
4
4
|
function formatDuration(startedAt, completedAt) {
|
|
@@ -63,4 +63,4 @@ async function runEvents(options) {
|
|
|
63
63
|
|
|
64
64
|
//#endregion
|
|
65
65
|
export { runEvents };
|
|
66
|
-
//# sourceMappingURL=events-
|
|
66
|
+
//# sourceMappingURL=events-D9kQWwH8.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events-
|
|
1
|
+
{"version":3,"file":"events-D9kQWwH8.mjs","names":[],"sources":["../src/cli/commands/events.ts"],"sourcesContent":["import { loadConfig } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { CfiOperationRecord } from \"../../types.js\";\n\nfunction formatDuration(\n startedAt: string,\n completedAt: string | undefined,\n): string | undefined {\n if (!completedAt) return undefined;\n const a = Date.parse(startedAt);\n const b = Date.parse(completedAt);\n if (!Number.isFinite(a) || !Number.isFinite(b) || b < a) return undefined;\n const ms = b - a;\n if (ms < 1000) return `${ms}ms`;\n return `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction printOp(label: string, op: CfiOperationRecord): void {\n const dur = formatDuration(op.startedAt, op.completedAt);\n console.log(` [${label}] ${op.command}`);\n console.log(` started: ${op.startedAt}`);\n if (op.completedAt) {\n console.log(` completed: ${op.completedAt}`);\n }\n if (dur) console.log(` duration: ${dur}`);\n if (op.detail) console.log(` detail: ${op.detail}`);\n if (op.errorMessage) console.log(` error: ${op.errorMessage}`);\n console.log();\n}\n\n/**\n * Read-only: print recent completed stack operations from D1 state\n * (`operationHistory`) plus any in-progress marker (`lastOperation`).\n */\nexport async function runEvents(options: {\n env?: string;\n configPath?: string;\n limit?: number;\n json?: boolean;\n}): Promise<void> {\n const env = options.env ?? \"local\";\n const config = await loadConfig(options.configPath, { env });\n const accountId =\n config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n const stackName = stackNameForConfig(config);\n const api = new CFApiClient(accountId);\n const state = new StateManager(config.tenant.id, env, stackName);\n await state.hydrate(api);\n\n const last = state.getLastOperation();\n const inProgress =\n last?.status === \"in_progress\" ? last : undefined;\n let history = state.getOperationHistory();\n if (options.limit !== undefined) {\n history = history.slice(0, options.limit);\n }\n\n if (options.json) {\n const out = {\n stackName,\n env,\n tenantId: config.tenant.id,\n inProgress: inProgress ?? null,\n history,\n };\n console.log(JSON.stringify(out, null, 2));\n return;\n }\n\n console.log(\n `\\nStack events — ${config.tenant.name} (${config.tenant.slug}) — stack \"${stackName}\" env ${env}\\n`,\n );\n\n if (inProgress) {\n console.log(\"In progress:\\n\");\n printOp(\"in_progress\", inProgress);\n }\n\n if (history.length === 0) {\n console.log(\n inProgress\n ? \"(no completed operations in history yet)\\n\"\n : \"No completed operations recorded in state yet.\\n\",\n );\n return;\n }\n\n console.log(\"Recent completed operations (newest first):\\n\");\n for (const op of history) {\n printOp(op.status, op);\n }\n}\n"],"mappings":";;;AAOA,SAAS,eACP,WACA,aACoB;AACpB,KAAI,CAAC,YAAa,QAAO;CACzB,MAAM,IAAI,KAAK,MAAM,UAAU;CAC/B,MAAM,IAAI,KAAK,MAAM,YAAY;AACjC,KAAI,CAAC,OAAO,SAAS,EAAE,IAAI,CAAC,OAAO,SAAS,EAAE,IAAI,IAAI,EAAG,QAAO;CAChE,MAAM,KAAK,IAAI;AACf,KAAI,KAAK,IAAM,QAAO,GAAG,GAAG;AAC5B,QAAO,IAAI,KAAK,KAAM,QAAQ,EAAE,CAAC;;AAGnC,SAAS,QAAQ,OAAe,IAA8B;CAC5D,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,YAAY;AACxD,SAAQ,IAAI,MAAM,MAAM,IAAI,GAAG,UAAU;AACzC,SAAQ,IAAI,kBAAkB,GAAG,YAAY;AAC7C,KAAI,GAAG,YACL,SAAQ,IAAI,kBAAkB,GAAG,cAAc;AAEjD,KAAI,IAAK,SAAQ,IAAI,kBAAkB,MAAM;AAC7C,KAAI,GAAG,OAAQ,SAAQ,IAAI,kBAAkB,GAAG,SAAS;AACzD,KAAI,GAAG,aAAc,SAAQ,IAAI,kBAAkB,GAAG,eAAe;AACrE,SAAQ,KAAK;;;;;;AAOf,eAAsB,UAAU,SAKd;CAChB,MAAM,MAAM,QAAQ,OAAO;CAC3B,MAAM,SAAS,MAAM,WAAW,QAAQ,YAAY,EAAE,KAAK,CAAC;CAC5D,MAAM,YACJ,OAAO,cAAc,4BAA4B;AACnD,KAAI,CAAC,UACH,OAAM,IAAI,MACR,iEACD;CAEH,MAAM,YAAY,mBAAmB,OAAO;CAC5C,MAAM,MAAM,IAAI,YAAY,UAAU;CACtC,MAAM,QAAQ,IAAI,aAAa,OAAO,OAAO,IAAI,KAAK,UAAU;AAChE,OAAM,MAAM,QAAQ,IAAI;CAExB,MAAM,OAAO,MAAM,kBAAkB;CACrC,MAAM,aACJ,MAAM,WAAW,gBAAgB,OAAO;CAC1C,IAAI,UAAU,MAAM,qBAAqB;AACzC,KAAI,QAAQ,UAAU,OACpB,WAAU,QAAQ,MAAM,GAAG,QAAQ,MAAM;AAG3C,KAAI,QAAQ,MAAM;EAChB,MAAM,MAAM;GACV;GACA;GACA,UAAU,OAAO,OAAO;GACxB,YAAY,cAAc;GAC1B;GACD;AACD,UAAQ,IAAI,KAAK,UAAU,KAAK,MAAM,EAAE,CAAC;AACzC;;AAGF,SAAQ,IACN,oBAAoB,OAAO,OAAO,KAAK,IAAI,OAAO,OAAO,KAAK,aAAa,UAAU,QAAQ,IAAI,IAClG;AAED,KAAI,YAAY;AACd,UAAQ,IAAI,iBAAiB;AAC7B,UAAQ,eAAe,WAAW;;AAGpC,KAAI,QAAQ,WAAW,GAAG;AACxB,UAAQ,IACN,aACI,+CACA,mDACL;AACD;;AAGF,SAAQ,IAAI,gDAAgD;AAC5D,MAAK,MAAM,MAAM,QACf,SAAQ,GAAG,QAAQ,GAAG"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as resourceModules, r as secretsStoreDeriveName } from "./registry-
|
|
1
|
+
import { n as resourceModules, r as secretsStoreDeriveName } from "./registry-DyToEush.mjs";
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import { writeFileSync } from "fs";
|
|
4
4
|
|
|
@@ -75,4 +75,4 @@ function writeWranglerJson(workerDir, config, outFile = "wrangler.json") {
|
|
|
75
75
|
|
|
76
76
|
//#endregion
|
|
77
77
|
export { writeWranglerJson as n, generateWranglerConfig as t };
|
|
78
|
-
//# sourceMappingURL=generator-
|
|
78
|
+
//# sourceMappingURL=generator-BCcu_eoO.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator-
|
|
1
|
+
{"version":3,"file":"generator-BCcu_eoO.mjs","names":["out: GeneratedSecretsStoreSecretBinding[]","config: WranglerConfig"],"sources":["../src/features/secrets-store/secrets-store.generate.ts","../src/core/wrangler/generator.ts"],"sourcesContent":["import type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport type {\n StateEntry,\n SecretsStoreResourceConfig,\n SecretsStoreSecretBinding,\n SecretsStoreStateEntry,\n} from \"../../types.js\";\nimport { secretsStoreDeriveName } from \"./secrets-store.naming.js\";\n\nexport interface SecretsStoreStateLike {\n get(key: string): StateEntry | undefined;\n getAll(): Record<string, StateEntry>;\n}\n\n/**\n * One row of wrangler's `secrets_store_secrets[]` array. Resolved from a\n * worker's declared `secretsStoreSecrets[]` by looking up the\n * Tamer-managed store's `store_id` in state. The named secret itself must\n * already exist inside the store (created out-of-band via wrangler\n * `secrets-store secret create`); Tamer never reads or writes secret\n * values.\n */\nexport interface GeneratedSecretsStoreSecretBinding {\n binding: string;\n store_id: string;\n secret_name: string;\n}\n\n/**\n * Resolve `secretsStoreSecrets[]` worker bindings into wrangler-shape\n * `secrets_store_secrets[]` entries by looking up the referenced\n * Tamer-managed store's `store_id` in state. Throws with an actionable\n * message if a referenced store has never been applied — the binding\n * would otherwise be deployed against a non-existent store.\n */\nexport function secretsStoreSecretsGenerate(\n bindings: SecretsStoreSecretBinding[],\n env: string,\n state: SecretsStoreStateLike,\n naming: NamingEngine,\n secretsStores?: SecretsStoreResourceConfig[],\n): GeneratedSecretsStoreSecretBinding[] {\n const out: GeneratedSecretsStoreSecretBinding[] = [];\n for (const b of bindings) {\n const storeConfig = secretsStores?.find((s) => s.logicalName === b.store);\n const derivedName = storeConfig\n ? secretsStoreDeriveName(storeConfig, env, naming)\n : naming.secretsStoreName(b.store, env);\n const entry = state.get(`secrets_store:${derivedName}`) as\n | SecretsStoreStateEntry\n | undefined;\n if (!entry || entry.type !== \"secrets_store\") {\n throw new Error(\n `Secrets Store binding \"${b.binding}\" references store \"${b.store}\" — ` +\n `not in state. Declare it under \\`resources.secretsStores\\` and run ` +\n `'tamer apply --env ${env}' first.`,\n );\n }\n out.push({\n binding: b.binding,\n store_id: entry.cfId,\n secret_name: b.secretName,\n });\n }\n return out;\n}\n","import { writeFileSync } from \"fs\";\nimport { join } from \"path\";\nimport type { WranglerConfig } from \"../../generated/wrangler-types.js\";\nimport type { ResolvedWorkerConfig } from \"../config/resolver.js\";\nimport type { StateManager } from \"../state/StateManager.js\";\nimport type { NamingEngine } from \"../naming/NamingEngine.js\";\nimport { resourceModules } from \"../registry/registry.js\";\nimport { secretsStoreSecretsGenerate } from \"../../features/secrets-store/secrets-store.generate.js\";\n\nexport class CfiError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CfiError\";\n }\n}\n\n/**\n * Build the worker's `wrangler.json` by asking every registered resource\n * module for its bindings fragment, then merging on top of the\n * passthrough config (`resolved.wranglerConfig`). Adding a new resource\n * kind requires zero edits here — register the module, done.\n */\nexport function generateWranglerConfig(\n resolved: ResolvedWorkerConfig,\n state: StateManager,\n naming: NamingEngine,\n): WranglerConfig {\n let config: WranglerConfig = {\n ...resolved.wranglerConfig,\n $schema: \"node_modules/wrangler/config-schema.json\",\n };\n\n const worker = {\n workerKey: resolved.workerKey,\n deployedName: resolved.workerName,\n };\n for (const mod of resourceModules) {\n const resources = mod.pickResources(resolved.resources);\n const fragment = mod.generate({\n resources,\n env: resolved.env,\n state,\n naming,\n passthrough: resolved.wranglerConfig,\n worker,\n });\n config = { ...config, ...fragment };\n }\n\n const secretBindings = resolved.resources?.secretsStoreSecrets ?? [];\n if (secretBindings.length > 0) {\n const passthroughSecrets =\n resolved.wranglerConfig.secrets_store_secrets ?? [];\n const generated = secretsStoreSecretsGenerate(\n secretBindings,\n resolved.env,\n state,\n naming,\n resolved.resources?.secretsStores,\n );\n config = {\n ...config,\n secrets_store_secrets: [...passthroughSecrets, ...generated],\n };\n }\n\n return config;\n}\n\nexport function writeWranglerJson(\n workerDir: string,\n config: WranglerConfig,\n outFile: string = \"wrangler.json\",\n): void {\n const path = join(workerDir, outFile);\n writeFileSync(path, JSON.stringify(config, null, 2), \"utf-8\");\n}\n"],"mappings":";;;;;;;;;;;;AAmCA,SAAgB,4BACd,UACA,KACA,OACA,QACA,eACsC;CACtC,MAAMA,MAA4C,EAAE;AACpD,MAAK,MAAM,KAAK,UAAU;EACxB,MAAM,cAAc,eAAe,MAAM,MAAM,EAAE,gBAAgB,EAAE,MAAM;EACzE,MAAM,cAAc,cAChB,uBAAuB,aAAa,KAAK,OAAO,GAChD,OAAO,iBAAiB,EAAE,OAAO,IAAI;EACzC,MAAM,QAAQ,MAAM,IAAI,iBAAiB,cAAc;AAGvD,MAAI,CAAC,SAAS,MAAM,SAAS,gBAC3B,OAAM,IAAI,MACR,0BAA0B,EAAE,QAAQ,sBAAsB,EAAE,MAAM,4FAE1C,IAAI,UAC7B;AAEH,MAAI,KAAK;GACP,SAAS,EAAE;GACX,UAAU,MAAM;GAChB,aAAa,EAAE;GAChB,CAAC;;AAEJ,QAAO;;;;;;;;;;;AC1CT,SAAgB,uBACd,UACA,OACA,QACgB;CAChB,IAAIC,SAAyB;EAC3B,GAAG,SAAS;EACZ,SAAS;EACV;CAED,MAAM,SAAS;EACb,WAAW,SAAS;EACpB,cAAc,SAAS;EACxB;AACD,MAAK,MAAM,OAAO,iBAAiB;EACjC,MAAM,YAAY,IAAI,cAAc,SAAS,UAAU;EACvD,MAAM,WAAW,IAAI,SAAS;GAC5B;GACA,KAAK,SAAS;GACd;GACA;GACA,aAAa,SAAS;GACtB;GACD,CAAC;AACF,WAAS;GAAE,GAAG;GAAQ,GAAG;GAAU;;CAGrC,MAAM,iBAAiB,SAAS,WAAW,uBAAuB,EAAE;AACpE,KAAI,eAAe,SAAS,GAAG;EAC7B,MAAM,qBACJ,SAAS,eAAe,yBAAyB,EAAE;EACrD,MAAM,YAAY,4BAChB,gBACA,SAAS,KACT,OACA,QACA,SAAS,WAAW,cACrB;AACD,WAAS;GACP,GAAG;GACH,uBAAuB,CAAC,GAAG,oBAAoB,GAAG,UAAU;GAC7D;;AAGH,QAAO;;AAGT,SAAgB,kBACd,WACA,QACA,UAAkB,iBACZ;AAEN,eADa,KAAK,WAAW,QAAQ,EACjB,KAAK,UAAU,QAAQ,MAAM,EAAE,EAAE,QAAQ"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as resourceModules, t as getResourceModule } from "./registry-
|
|
1
|
+
import { H as loadConfig, R as CFApiClient, V as getWorkers, f as fetchStackImports, h as StateManager, k as resolveWorkerConfig, u as namingFromConfig, w as stackNameForConfig, z as cloudflareAccountIdFromEnv } from "./tamer.mjs";
|
|
2
|
+
import { n as resourceModules, t as getResourceModule } from "./registry-DyToEush.mjs";
|
|
3
3
|
import "./r2S3EmptyBucket-B9_pHfvB.mjs";
|
|
4
4
|
import { n as workerRouteStateKey, t as findZoneIdByName } from "./zoneResolver-D9bz6-0l.mjs";
|
|
5
5
|
|
|
@@ -161,4 +161,4 @@ async function importWorkerRoute(ctx) {
|
|
|
161
161
|
|
|
162
162
|
//#endregion
|
|
163
163
|
export { runImport };
|
|
164
|
-
//# sourceMappingURL=import-
|
|
164
|
+
//# sourceMappingURL=import-DHmLtue3.mjs.map
|