@dragonmastery/tamer 0.30.0 → 0.31.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.
Files changed (92) hide show
  1. package/README.md +2 -1
  2. package/dist/{apply-CWU3HY0P.mjs → apply-BjrYbyHn.mjs} +14 -16
  3. package/dist/{apply-CWU3HY0P.mjs.map → apply-BjrYbyHn.mjs.map} +1 -1
  4. package/dist/{applyTarget-D15T_q7G.mjs → applyTarget-Ce_mtRQX.mjs} +3 -3
  5. package/dist/{applyTarget-D15T_q7G.mjs.map → applyTarget-Ce_mtRQX.mjs.map} +1 -1
  6. package/dist/{bootstrap-BicPW44a.mjs → bootstrap-D__dHw1w.mjs} +6 -6
  7. package/dist/bootstrap-D__dHw1w.mjs.map +1 -0
  8. package/dist/{buildDispatchUploadForm-BoUB93b3.mjs → buildDispatchUploadForm-CVnPmHg4.mjs} +1 -1
  9. package/dist/{buildDispatchUploadForm-BoUB93b3.mjs.map → buildDispatchUploadForm-CVnPmHg4.mjs.map} +1 -1
  10. package/dist/{cloudflareSnapshot-GBUHeg2m.mjs → cloudflareSnapshot-C6cF8GG8.mjs} +5 -7
  11. package/dist/{cloudflareSnapshot-GBUHeg2m.mjs.map → cloudflareSnapshot-C6cF8GG8.mjs.map} +1 -1
  12. package/dist/{deploy-DAEjDjOm.mjs → deploy-C6fX9td0.mjs} +23 -11
  13. package/dist/deploy-C6fX9td0.mjs.map +1 -0
  14. package/dist/{destroy-tenant-B-VLKfc6.mjs → destroy-tenant-T_94ed9x.mjs} +2 -4
  15. package/dist/{destroy-tenant-B-VLKfc6.mjs.map → destroy-tenant-T_94ed9x.mjs.map} +1 -1
  16. package/dist/{destroy-DtgPD_bD.mjs → destroy-vfk2Zbfj.mjs} +11 -13
  17. package/dist/{destroy-DtgPD_bD.mjs.map → destroy-vfk2Zbfj.mjs.map} +1 -1
  18. package/dist/{dev-BYItpt9U.mjs → dev-BLthyLml.mjs} +8 -10
  19. package/dist/{dev-BYItpt9U.mjs.map → dev-BLthyLml.mjs.map} +1 -1
  20. package/dist/{dns-records.resolve-C2T0m4NG.mjs → dns-records.resolve-8a_eHfVI.mjs} +1 -1
  21. package/dist/{dns-records.resolve-DwBR_1WI.mjs → dns-records.resolve-BB2agPAb.mjs} +1 -1
  22. package/dist/{dns-records.resolve-DwBR_1WI.mjs.map → dns-records.resolve-BB2agPAb.mjs.map} +1 -1
  23. package/dist/{dns-records.sync-CfI1mqXv.mjs → dns-records.sync-DqYROe07.mjs} +3 -3
  24. package/dist/{dns-records.sync-CfI1mqXv.mjs.map → dns-records.sync-DqYROe07.mjs.map} +1 -1
  25. package/dist/{doctor-C_hs7k2D.mjs → doctor-32YLAXXl.mjs} +2 -2
  26. package/dist/{doctor-C_hs7k2D.mjs.map → doctor-32YLAXXl.mjs.map} +1 -1
  27. package/dist/drift-BCxWdYHG.mjs +8 -0
  28. package/dist/{drift-DncpkI2R.mjs → drift-CeemyFqL.mjs} +37 -9
  29. package/dist/drift-CeemyFqL.mjs.map +1 -0
  30. package/dist/{events-B6oCdvSt.mjs → events-otk0l3aJ.mjs} +2 -4
  31. package/dist/{events-B6oCdvSt.mjs.map → events-otk0l3aJ.mjs.map} +1 -1
  32. package/dist/{generator-h_VG0Q5f.mjs → generator-gvCy7ouY.mjs} +2 -2
  33. package/dist/{generator-h_VG0Q5f.mjs.map → generator-gvCy7ouY.mjs.map} +1 -1
  34. package/dist/{import-D8zaVvwK.mjs → import-OvohE-H2.mjs} +6 -8
  35. package/dist/{import-D8zaVvwK.mjs.map → import-OvohE-H2.mjs.map} +1 -1
  36. package/dist/index.d.mts +264 -26
  37. package/dist/index.d.mts.map +1 -1
  38. package/dist/{logpush-job-DsRkOORJ.mjs → logpush-job-DJPlpnRu.mjs} +2 -2
  39. package/dist/{logpush-job-DsRkOORJ.mjs.map → logpush-job-DJPlpnRu.mjs.map} +1 -1
  40. package/dist/{migrate-Bwl0w6XN.mjs → migrate-CroDjbJz.mjs} +6 -8
  41. package/dist/{migrate-Bwl0w6XN.mjs.map → migrate-CroDjbJz.mjs.map} +1 -1
  42. package/dist/normalize-DVSTRZhO.mjs.map +1 -1
  43. package/dist/{plan-BNIAD--f.mjs → plan-C2urqJOz.mjs} +39 -14
  44. package/dist/plan-C2urqJOz.mjs.map +1 -0
  45. package/dist/{planFormat-CJw8Kq2s.mjs → planFormat-5XMJK879.mjs} +1 -1
  46. package/dist/{planFormat-CJw8Kq2s.mjs.map → planFormat-5XMJK879.mjs.map} +1 -1
  47. package/dist/{provision-tenant-BcZocyyn.mjs → provision-tenant-BJ1KugON.mjs} +6 -8
  48. package/dist/{provision-tenant-BcZocyyn.mjs.map → provision-tenant-BJ1KugON.mjs.map} +1 -1
  49. package/dist/{r2S3EmptyBucket-DD81ZWQ7.mjs → r2S3EmptyBucket-B9_pHfvB.mjs} +1 -1
  50. package/dist/{r2S3EmptyBucket-DD81ZWQ7.mjs.map → r2S3EmptyBucket-B9_pHfvB.mjs.map} +1 -1
  51. package/dist/{fetchStackImports-ClUYZy_U.mjs → registry-EWWdkLf7.mjs} +5 -982
  52. package/dist/registry-EWWdkLf7.mjs.map +1 -0
  53. package/dist/secrets-CnzjvndT.mjs +3 -0
  54. package/dist/{stackOutputs-D33EmyfT.mjs → stackOutputs-Cltzl2g0.mjs} +2 -2
  55. package/dist/{stackOutputs-D33EmyfT.mjs.map → stackOutputs-Cltzl2g0.mjs.map} +1 -1
  56. package/dist/{status-BAPpi2Zt.mjs → status-DkkS5lc9.mjs} +7 -9
  57. package/dist/{status-BAPpi2Zt.mjs.map → status-DkkS5lc9.mjs.map} +1 -1
  58. package/dist/{sync-BdJ43vO7.mjs → sync-CpfxqlOx.mjs} +7 -9
  59. package/dist/{sync-BdJ43vO7.mjs.map → sync-CpfxqlOx.mjs.map} +1 -1
  60. package/dist/tamer.mjs +4422 -221
  61. package/dist/tamer.mjs.map +1 -1
  62. package/dist/{tamerArtifactsR2-Ccgplu2Q.mjs → tamerArtifactsR2-DnUJmxnO.mjs} +2 -2
  63. package/dist/{tamerArtifactsR2-Ccgplu2Q.mjs.map → tamerArtifactsR2-DnUJmxnO.mjs.map} +1 -1
  64. package/dist/{types-CN1BOr0U.mjs → types-BzzHwIdw.mjs} +6 -8
  65. package/dist/{types-CN1BOr0U.mjs.map → types-BzzHwIdw.mjs.map} +1 -1
  66. package/dist/{verifyPlanFile-BQ7GCDC2.mjs → verifyPlanFile-BmEadIqm.mjs} +2 -2
  67. package/dist/{verifyPlanFile-BQ7GCDC2.mjs.map → verifyPlanFile-BmEadIqm.mjs.map} +1 -1
  68. package/dist/{wfp-delete-BG9WBd7F.mjs → wfp-delete-CDBFqmrM.mjs} +2 -3
  69. package/dist/{wfp-delete-BG9WBd7F.mjs.map → wfp-delete-CDBFqmrM.mjs.map} +1 -1
  70. package/dist/{wfp-put-DjErqxFa.mjs → wfp-put-BrwICc9i.mjs} +3 -4
  71. package/dist/{wfp-put-DjErqxFa.mjs.map → wfp-put-BrwICc9i.mjs.map} +1 -1
  72. package/dist/{worker-route-DY1onr-h.mjs → worker-route-x8q3K4-z.mjs} +3 -4
  73. package/dist/{worker-route-DY1onr-h.mjs.map → worker-route-x8q3K4-z.mjs.map} +1 -1
  74. package/dist/{workers-DNKsZOq4.mjs → workers-D3Ekf3mF.mjs} +3 -4
  75. package/dist/{workers-DNKsZOq4.mjs.map → workers-D3Ekf3mF.mjs.map} +1 -1
  76. package/dist/{wranglerSpawn-DmEz0ldT.mjs → wranglerSpawn-CUlo2qOJ.mjs} +1 -1
  77. package/dist/{wranglerSpawn-DmEz0ldT.mjs.map → wranglerSpawn-CUlo2qOJ.mjs.map} +1 -1
  78. package/dist/{zoneResolver-VoxLHM4N.mjs → zoneResolver-DNNNmO_w.mjs} +1 -1
  79. package/dist/{zoneResolver-VoxLHM4N.mjs.map → zoneResolver-DNNNmO_w.mjs.map} +1 -1
  80. package/package.json +1 -1
  81. package/dist/CFApiClient-DhbyyV71.mjs +0 -868
  82. package/dist/CFApiClient-DhbyyV71.mjs.map +0 -1
  83. package/dist/StateManager-JLBtz9V-.mjs +0 -760
  84. package/dist/StateManager-JLBtz9V-.mjs.map +0 -1
  85. package/dist/bootstrap-BicPW44a.mjs.map +0 -1
  86. package/dist/deploy-DAEjDjOm.mjs.map +0 -1
  87. package/dist/drift-DRnwTyZD.mjs +0 -10
  88. package/dist/drift-DncpkI2R.mjs.map +0 -1
  89. package/dist/fetchStackImports-ClUYZy_U.mjs.map +0 -1
  90. package/dist/loader-DnT9iqz9.mjs +0 -531
  91. package/dist/loader-DnT9iqz9.mjs.map +0 -1
  92. package/dist/plan-BNIAD--f.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"StateManager-JLBtz9V-.mjs","names":["z.object","z.literal","z.string","z.boolean","z.number","z.enum","z\n .object","z.discriminatedUnion","z.array","z.record","tenantId: string","env: string","stackName: string"],"sources":["../src/core/state/stateSchema.ts","../src/core/state/stackName.ts","../src/core/state/tamerStateDb.ts","../src/features/dispatch-namespace/dispatch-namespace.resolve.ts","../src/core/tenant/tenantKeys.ts","../src/core/state/StateManager.ts"],"sourcesContent":["import { z } from \"zod\";\n\nconst D1StateEntrySchema = z.object({\n type: z.literal(\"d1_database\"),\n logicalName: z.string(),\n shardDate: z.string().optional(),\n derivedName: z.string(),\n bindingKey: z.string(),\n cfId: z.string(),\n migrationsDir: z.string().optional(),\n preserveOnDestroy: z.boolean().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst R2StateEntrySchema = z.object({\n type: z.literal(\"r2_bucket\"),\n logicalName: z.string(),\n createdDate: z.string(),\n derivedName: z.string(),\n bindingKey: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst KVStateEntrySchema = z.object({\n type: z.literal(\"kv_namespace\"),\n logicalName: z.string(),\n derivedName: z.string(),\n bindingKey: z.string(),\n cfId: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst QueueStateEntrySchema = z.object({\n type: z.literal(\"queue\"),\n logicalName: z.string(),\n derivedName: z.string(),\n bindingKey: z.string(),\n cfId: z.string(),\n producerBinding: z.boolean(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst VectorizeStateEntrySchema = z.object({\n type: z.literal(\"vectorize\"),\n logicalName: z.string(),\n derivedName: z.string(),\n bindingKey: z.string(),\n cfId: z.string(),\n dimensions: z.number(),\n metric: z.enum([\"cosine\", \"euclidean\", \"dot-product\"]),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst AIGatewayStateEntrySchema = z.object({\n type: z.literal(\"ai_gateway\"),\n logicalName: z.string(),\n derivedName: z.string(),\n bindingKey: z.string(),\n cfId: z.string(),\n cacheTtl: z.number(),\n cacheInvalidateOnUpdate: z.boolean(),\n collectLogs: z.boolean(),\n authentication: z.boolean(),\n rateLimitingInterval: z.number(),\n rateLimitingLimit: z.number(),\n rateLimitingTechnique: z.enum([\"fixed\", \"sliding\"]),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst PipelineStateEntrySchema = z.object({\n type: z.literal(\"pipeline\"),\n logicalName: z.string(),\n derivedName: z.string(),\n bindingKey: z.string(),\n cfId: z.string(),\n sql: z.string(),\n status: z.string().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst WorkflowStateEntrySchema = z.object({\n type: z.literal(\"workflow\"),\n logicalName: z.string(),\n derivedName: z.string(),\n bindingKey: z.string(),\n cfId: z.string(),\n className: z.string(),\n scriptName: z.string(),\n limits: z\n .object({ steps: z.number().int().positive().optional() })\n .optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst SecretsStoreStateEntrySchema = z.object({\n type: z.literal(\"secrets_store\"),\n logicalName: z.string(),\n derivedName: z.string(),\n bindingKey: z.string(),\n cfId: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst HyperdriveStateEntrySchema = z.object({\n type: z.literal(\"hyperdrive\"),\n logicalName: z.string(),\n derivedName: z.string(),\n bindingKey: z.string(),\n cfId: z.string(),\n scheme: z.enum([\"postgres\", \"postgresql\", \"mysql\"]),\n originHost: z.string(),\n originDatabase: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst DnsRecordTypeSchema = z.enum([\n \"A\",\n \"AAAA\",\n \"CNAME\",\n \"TXT\",\n \"MX\",\n \"NS\",\n \"CAA\",\n \"SRV\",\n \"PTR\",\n \"HTTPS\",\n \"SVCB\",\n]);\n\nconst DnsRecordStateEntrySchema = z.object({\n type: z.literal(\"dns_record\"),\n logicalName: z.string(),\n zoneId: z.string(),\n recordType: DnsRecordTypeSchema,\n name: z.string(),\n content: z.string(),\n ttl: z.number(),\n proxied: z.boolean(),\n priority: z.number().optional(),\n comment: z.string(),\n recordId: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst DispatchNamespaceStateEntrySchema = z.object({\n type: z.literal(\"dispatch_namespace\"),\n logicalName: z.string(),\n derivedName: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst LogpushJobStateEntrySchema = z.object({\n type: z.literal(\"logpush_job\"),\n logicalName: z.string(),\n derivedName: z.string(),\n cfJobId: z.number(),\n dataset: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst LogpushPipelinesStateEntrySchema = z.object({\n type: z.literal(\"logpush_pipelines\"),\n logicalName: z.string(),\n streamId: z.string(),\n streamIngestBaseUrl: z.string().optional(),\n sinkId: z.string(),\n pipelineId: z.string(),\n streamName: z.string(),\n sinkName: z.string(),\n pipelineName: z.string(),\n r2DataCatalogTableName: z.string().optional(),\n r2DataCatalogTableNamePipelines: z.string().optional(),\n r2DataCatalogNamespace: z.string().optional(),\n catalogBucketDerivedName: z.string(),\n mintedR2CatalogTokenId: z.string().optional(),\n mintedR2CatalogTokenValue: z.string().optional(),\n mintedPipelinesSendTokenId: z.string().optional(),\n mintedPipelinesSendTokenValue: z.string().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst WorkerRouteStateEntrySchema = z.object({\n type: z.literal(\"worker_route\"),\n workerKey: z.string(),\n workerName: z.string(),\n zoneId: z.string(),\n zoneName: z.string(),\n routeId: z.string(),\n pattern: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst StateEntrySchema = z.discriminatedUnion(\"type\", [\n D1StateEntrySchema,\n R2StateEntrySchema,\n KVStateEntrySchema,\n QueueStateEntrySchema,\n HyperdriveStateEntrySchema,\n VectorizeStateEntrySchema,\n AIGatewayStateEntrySchema,\n PipelineStateEntrySchema,\n WorkflowStateEntrySchema,\n SecretsStoreStateEntrySchema,\n DnsRecordStateEntrySchema,\n DispatchNamespaceStateEntrySchema,\n LogpushJobStateEntrySchema,\n LogpushPipelinesStateEntrySchema,\n WorkerRouteStateEntrySchema,\n]);\n\nconst ProvisioningStatusSchema = z.enum([\n \"pending\",\n \"d1_created\",\n \"migrations_applied\",\n \"script_uploaded\",\n \"ready\",\n \"tombstoned\",\n]);\n\nconst TenantD1ShardRefSchema = z.object({\n role: z.string(),\n derivedName: z.string(),\n cfId: z.string(),\n});\n\nconst TenantStateEntrySchema = z.object({\n product: z.string(),\n workspace: z.string(),\n provisioningStatus: ProvisioningStatusSchema,\n dispatchNamespaceName: z.string(),\n scriptName: z.string(),\n d1Shards: z.array(TenantD1ShardRefSchema).optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nconst CfiStackMetaSchema = z.object({\n name: z.string().optional(),\n owner: z.string().optional(),\n});\n\nconst CfiOperationNameSchema = z.enum([\n \"bootstrap\",\n \"apply\",\n \"deploy\",\n \"destroy\",\n \"provision-tenant\",\n \"destroy-tenant\",\n \"import\",\n \"sync\",\n]);\n\nconst CfiOperationStatusSchema = z.enum([\n \"in_progress\",\n \"succeeded\",\n \"failed\",\n]);\n\nconst CfiStackOutputValueSchema = z.object({\n value: z.string(),\n source: z.string(),\n resolvedAt: z.string(),\n});\n\nconst CfiOperationRecordSchema = z.object({\n command: CfiOperationNameSchema,\n status: CfiOperationStatusSchema,\n startedAt: z.string(),\n completedAt: z.string().optional(),\n errorMessage: z.string().optional(),\n detail: z.string().optional(),\n});\n\nexport const CfiStateSchema = z.object({\n tenantId: z.string(),\n env: z.string(),\n schemaVersion: z.number(),\n syncedAt: z.string(),\n resources: z.record(z.string(), StateEntrySchema),\n /** Optimistic concurrency: incremented on each successful D1 persist. */\n revision: z.number().optional(),\n /** Runtime-provisioned workspace tenants (not declared in `tamer.config.ts`). */\n tenants: z.record(z.string(), TenantStateEntrySchema).optional(),\n /** Stack metadata. */\n stack: CfiStackMetaSchema.optional(),\n /** Resolved + persisted `outputs:` from `tamer.config.ts`. */\n stackOutputs: z.record(z.string(), CfiStackOutputValueSchema).optional(),\n /** Last operation that mutated this state row. */\n lastOperation: CfiOperationRecordSchema.optional(),\n /** Completed ops (newest first), capped on append. */\n operationHistory: z.array(CfiOperationRecordSchema).optional(),\n});\n\nexport type CfiStateValidated = z.infer<typeof CfiStateSchema>;\nexport type TenantStateEntryValidated = z.infer<typeof TenantStateEntrySchema>;\n","/**\n * Single source of truth for \"what stack are we?\" The value flows into the\n * D1 row key (`cfi_state:{stackName}`) and into\n * `${tamer:import:<stackName>.<output>}` lookups, so commands MUST agree\n * on the same derivation. Order: explicit `config.stack.name` →\n * `tenant.slug` → literal `\"default\"` (defensive — the loader requires\n * `tenant.slug` to be set, but the StateManager constructor accepts the\n * fallback so unit tests that build state without a config keep working).\n */\nimport type { CfiConfig } from \"../../types.js\";\n\nexport const DEFAULT_STACK_NAME = \"default\";\n\nexport function stackNameForConfig(config: CfiConfig): string {\n return config.stack?.name ?? config.tenant.slug ?? DEFAULT_STACK_NAME;\n}\n","import type { CFApiClient } from \"../api/CFApiClient.js\";\nimport type { CfiState } from \"../../types.js\";\nimport { CfiStateSchema } from \"./stateSchema.js\";\nimport { DEFAULT_STACK_NAME } from \"./stackName.js\";\n\n/**\n * Schema versions:\n * 2: original (resources only).\n * 3: + `tenants` map, + `revision` for optimistic concurrency.\n * 4: + `stack` metadata, + `lastOperation` (CloudFormation-style stack info).\n * All v4 additions are optional; existing v3 documents are upgraded\n * in-place during parse with no data loss.\n */\nconst STATE_SCHEMA_VERSION = 4;\n\n/** Cloudflare D1 database that holds JSON state for an env (`tamer-state-dev`, …). */\nexport function tamerStateDatabaseName(env: string): string {\n return `tamer-state-${env}`;\n}\n\nexport function createEmptyCfiState(tenantId: string, env: string): CfiState {\n return {\n tenantId,\n env,\n schemaVersion: STATE_SCHEMA_VERSION,\n syncedAt: new Date().toISOString(),\n resources: {},\n revision: 0,\n tenants: {},\n };\n}\n\n/** In-place upgrade for parsed JSON before Zod validation. */\nexport function migrateRawCfiStateInPlace(raw: Record<string, unknown>): void {\n const v = raw.schemaVersion;\n if (typeof v !== \"number\") {\n throw new Error(\"tamer state: schemaVersion must be a number\");\n }\n if (v < 2) {\n throw new Error(`tamer state: unsupported schemaVersion ${v}`);\n }\n if (v > STATE_SCHEMA_VERSION) {\n throw new Error(\n `tamer state: unknown schemaVersion ${v} (engine supports up to ${STATE_SCHEMA_VERSION})`,\n );\n }\n if (v === 2) {\n raw.tenants = {};\n raw.revision = 0;\n raw.schemaVersion = 3;\n }\n if (!raw.tenants || typeof raw.tenants !== \"object\") {\n raw.tenants = {};\n }\n if (typeof raw.revision !== \"number\") {\n raw.revision = 0;\n }\n if (raw.schemaVersion === 3) {\n raw.schemaVersion = STATE_SCHEMA_VERSION;\n }\n}\n\nexport async function findTamerStateDatabaseUuid(\n api: CFApiClient,\n env: string,\n): Promise<string | undefined> {\n const name = tamerStateDatabaseName(env);\n const all = await api.d1ListAll();\n return all.find((d) => d.name === name)?.uuid;\n}\n\n/**\n * Create `tamer-state-{env}` if missing, ensure `tamer_kv` table, and seed an\n * initial empty `cfi_state:{stackName}` row when this stack has no row yet.\n * Idempotent — re-running for the same stack is a no-op; re-running for a\n * different stack against the same env D1 just adds another row.\n */\nexport async function ensureTamerStateDatabase(\n api: CFApiClient,\n tenantId: string,\n env: string,\n stackName: string = DEFAULT_STACK_NAME,\n): Promise<string> {\n let uuid = await findTamerStateDatabaseUuid(api, env);\n if (!uuid) {\n const created = await api.d1Create(tamerStateDatabaseName(env));\n uuid = created.uuid;\n }\n\n await api.d1Query(\n uuid,\n `CREATE TABLE IF NOT EXISTS tamer_kv (\n k TEXT PRIMARY KEY,\n v TEXT NOT NULL\n )`,\n );\n\n const rowKey = `cfi_state:${stackName}`;\n const { rows } = await api.d1Query(\n uuid,\n `SELECT v FROM tamer_kv WHERE k = ?`,\n [rowKey],\n );\n if (rows.length === 0) {\n const initial = createEmptyCfiState(tenantId, env);\n await api.d1Query(\n uuid,\n `INSERT INTO tamer_kv (k, v) VALUES (?, ?)`,\n [rowKey, JSON.stringify(initial)],\n );\n }\n\n return uuid;\n}\n\nexport function parseCfiStateJson(json: string): CfiState {\n const raw = JSON.parse(json) as Record<string, unknown>;\n migrateRawCfiStateInPlace(raw);\n const result = CfiStateSchema.safeParse(raw);\n if (!result.success) {\n throw new Error(`Invalid tamer state JSON: ${result.error.message}`);\n }\n return result.data as CfiState;\n}\n\nexport async function destroyTamerStateDatabase(\n api: CFApiClient,\n env: string,\n): Promise<boolean> {\n const uuid = await findTamerStateDatabaseUuid(api, env);\n if (!uuid) return false;\n await api.d1Delete(uuid);\n return true;\n}\n","import type {\n DispatchNamespaceResourceConfig,\n TenantMeta,\n} from \"../../types.js\";\n\n// Tiny per-TenantMeta cache so we don't recompile the regex on every\n// resolve call (which happens once per resource, per env, per command).\n// `null` = \"config opted out\" (no `ephemeralEnvPattern`); we cache the\n// negative answer too so the predicate stays branch-free at the call\n// site. Loader has already validated the source string compiles.\nconst ephemeralPredicateCache = new WeakMap<TenantMeta, RegExp | null>();\n\nfunction ephemeralPredicateFor(tenant: TenantMeta): RegExp | null {\n if (ephemeralPredicateCache.has(tenant)) {\n return ephemeralPredicateCache.get(tenant) ?? null;\n }\n const pat = tenant.ephemeralEnvPattern;\n const compiled = pat ? new RegExp(pat) : null;\n ephemeralPredicateCache.set(tenant, compiled);\n return compiled;\n}\n\n/**\n * `true` when `env` matches `tenant.ephemeralEnvPattern` (e.g.\n * `\"^pr-\"` for PR previews, `\"^(pr|feature)-\"` for branch previews).\n *\n * Ephemeral envs share **one** dispatch namespace\n * (`{ns}-ephemeral`) so we don't churn dispatch-namespace creates per\n * preview, and dispatch-script names carry the env suffix\n * (`{product}-{workspace}-{env}`) so multiple previews can coexist\n * inside that shared namespace. When the config doesn't pin a\n * pattern, no env is ephemeral — every env gets its own dispatch\n * namespace `{ns}-{env}`.\n */\nexport function isEphemeralEnv(env: string, tenant: TenantMeta): boolean {\n const re = ephemeralPredicateFor(tenant);\n if (!re) return false;\n return re.test(env);\n}\n\n/** Resolved Cloudflare dispatch namespace name for the given env. */\nexport function effectiveDispatchNamespaceName(\n config: DispatchNamespaceResourceConfig,\n env: string,\n tenant: TenantMeta,\n): string {\n if (config.envSuffix) {\n if (env === \"local\") return config.namespace;\n if (isEphemeralEnv(env, tenant)) return `${config.namespace}-ephemeral`;\n return `${config.namespace}-${env}`;\n }\n return config.namespace;\n}\n","import type { TenantMeta } from \"../../types.js\";\nimport { isEphemeralEnv } from \"../../features/dispatch-namespace/dispatch-namespace.resolve.js\";\n\n/** Stable map key for `CfiState.tenants` (workspace-scoped product tenant). */\nexport function tenantStateKey(product: string, workspace: string): string {\n return `${product}:${workspace}`;\n}\n\n/**\n * Dispatch-namespace script name per `docs/handoff.md` §6: non-ephemeral\n * envs collapse to `{product}-{workspace}` (one script per workspace);\n * ephemeral envs (matching `tenant.ephemeralEnvPattern`) carry the env\n * in the script name (`{product}-{workspace}-{env}`) so multiple\n * previews can coexist in the shared `{ns}-ephemeral` namespace.\n */\nexport function tenantDispatchScriptName(\n product: string,\n workspace: string,\n env: string,\n tenant: TenantMeta,\n): string {\n if (isEphemeralEnv(env, tenant)) {\n return `${product}-${workspace}-${env}`;\n }\n return `${product}-${workspace}`;\n}\n\nconst SAFE = /[^a-z0-9_-]/gi;\n\n/**\n * Per-shard D1 database name for a tenant. Stable across `provision-tenant`\n * runs and across env so re-provisioning + drift detection can match by\n * name. Format: `db_{role}_{w}_{p}_t_{tid}_{env}`.\n *\n * db_system_acme_todo_t_platform_prod\n * db_app_acme_todo_t_platform_prod\n *\n * `role` is whatever the operator declared in `tenant.d1Shards` in\n * `tamer.config.ts`. Tamer is opinion-free about the shard layout — a\n * Dragoncore-style product picks `[\"system\", \"app\", \"history\"]`, a\n * single-DB tenant picks `[\"main\"]`, an audit-only tenant picks\n * `[\"audit\"]`, etc. The role itself is validated by the loader (lowercase\n * ASCII subset) so it slots cleanly into the D1 naming scheme.\n *\n * D1 names are length-bounded (Cloudflare currently allows up to 64\n * chars), and this scheme keeps every shard well under that limit even\n * for long workspace + product slugs.\n */\nexport function tenantShardDatabaseName(\n role: string,\n workspace: string,\n product: string,\n platformTenantId: string,\n env: string,\n): string {\n const w = workspace.replace(SAFE, \"_\").toLowerCase();\n const p = product.replace(SAFE, \"_\").toLowerCase();\n return `db_${role}_${w}_${p}_t_${platformTenantId}_${env}`;\n}\n\n/**\n * Parse + validate a `--shards a,b,c` CLI argument against the configured\n * shard set in `tamer.config.ts`. The CLI flag may only **trim** the\n * configured layout (e.g. `--shards system` on a stack whose config\n * declares `[\"system\",\"app\",\"history\"]` provisions just the system\n * shard for an ephemeral preview); it cannot extend it, because the\n * config is the source of truth that `apply` / `drift` / `destroy`\n * other operators read.\n *\n * Returns the requested roles in canonical order (matches `allowed`\n * order, regardless of input order) so plan/apply output is\n * deterministic and partial-failure resumes pick up at the next\n * canonical role.\n */\nexport function parseTenantShardRoles(\n raw: string,\n allowed: readonly string[],\n): string[] {\n const allowedSet = new Set(allowed);\n const requested = raw\n .split(\",\")\n .map((s) => s.trim().toLowerCase())\n .filter(Boolean);\n const unknown = requested.filter((r) => !allowedSet.has(r));\n if (unknown.length > 0) {\n const list = allowed.length > 0 ? allowed.join(\", \") : \"(none configured)\";\n throw new Error(\n `unknown tenant shard role(s) \"${unknown.join(\", \")}\"; ` +\n `must be a subset of tenant.d1Shards in the Tamer project config: ${list}`,\n );\n }\n const seen = new Set(requested);\n return allowed.filter((r) => seen.has(r));\n}\n","import type {\n CfiState,\n CfiOperationName,\n CfiOperationRecord,\n CfiStackMeta,\n CfiStackOutputValue,\n StateEntry,\n TenantStateEntry,\n} from \"../../types.js\";\nimport type { CFApiClient } from \"../api/CFApiClient.js\";\nimport {\n createEmptyCfiState,\n findTamerStateDatabaseUuid,\n parseCfiStateJson,\n tamerStateDatabaseName,\n} from \"./tamerStateDb.js\";\nimport { tenantStateKey } from \"../tenant/tenantKeys.js\";\nimport { StateConflictError } from \"./StateConflictError.js\";\nimport { DEFAULT_STACK_NAME } from \"./stackName.js\";\n\n/** D1 `tamer_kv.k` value for a given stack's state row. */\nexport function stateRowKey(stackName: string): string {\n return `cfi_state:${stackName}`;\n}\n\nconst OPERATION_HISTORY_CAP = 50;\n\n/**\n * Authoritative deployment state for an env.\n *\n * - **Non-local:** stored as JSON in Cloudflare D1 (`tamer-state-{env}`).\n * Call {@link hydrate} before {@link load}, then {@link persist} after mutations.\n * - **local:** in-memory only (no persistence).\n */\nexport class StateManager {\n private state: CfiState | null = null;\n private dirty = false;\n /** Set when {@link hydrate} loads remote state. */\n private tamerStateDbUuid: string | null = null;\n /**\n * Remote `revision` at last hydrate (or last successful persist). Used for\n * optimistic concurrency on D1 persist.\n */\n private baselineRevision = 0;\n\n /**\n * @param tenantId `config.tenant.id` — recorded on the state row for\n * diagnostics; not part of the row key.\n * @param env Cloudflare environment name; selects the\n * `tamer-state-{env}` D1 database.\n * @param stackName Stack identity (`config.stack.name ?? tenant.slug`).\n * The state row in D1 is keyed `cfi_state:{stackName}`,\n * so multiple stacks coexist in one env D1 without\n * clobbering each other. Defaults to `\"default\"` —\n * unit tests that synthesize a StateManager without\n * a config get a stable key without extra plumbing.\n */\n constructor(\n private tenantId: string,\n private env: string,\n private stackName: string = DEFAULT_STACK_NAME,\n ) {}\n\n /**\n * Load state from D1 (remote) or allocate empty state (local).\n * Required before {@link load} for every command.\n */\n async hydrate(api: CFApiClient): Promise<void> {\n if (this.state) return;\n\n if (this.env === \"local\") {\n this.state = createEmptyCfiState(this.tenantId, this.env);\n this.baselineRevision = this.state.revision ?? 0;\n return;\n }\n\n const name = tamerStateDatabaseName(this.env);\n const uuid = await findTamerStateDatabaseUuid(api, this.env);\n if (!uuid) {\n throw new Error(\n `Tamer state database \"${name}\" not found. Run: tamer bootstrap --env ${this.env}`,\n );\n }\n this.tamerStateDbUuid = uuid;\n\n const rowKey = stateRowKey(this.stackName);\n const { rows } = await api.d1Query(\n uuid,\n `SELECT v FROM tamer_kv WHERE k = ?`,\n [rowKey],\n );\n if (rows.length === 0) {\n this.state = createEmptyCfiState(this.tenantId, this.env);\n this.baselineRevision = this.state.revision ?? 0;\n this.dirty = true;\n return;\n }\n const v = rows[0]![\"v\"];\n if (typeof v !== \"string\") {\n throw new Error(`tamer_kv.${rowKey} must be a string column`);\n }\n this.state = parseCfiStateJson(v);\n this.baselineRevision = this.state.revision ?? 0;\n }\n\n /**\n * Stack identifier this manager is bound to (the `cfi_state:{name}` row\n * key suffix). Exposed so `fetchStackImports` and diagnostics can show\n * the operator which row this manager owns.\n */\n getStackName(): string {\n return this.stackName;\n }\n\n /**\n * Allocate empty in-memory state without touching D1. Use for read-only\n * \"what-would-state-look-like\" snapshots (e.g. drift-aware plan refresh)\n * where we want to drive the module `sync` hooks against a fresh slate\n * and then discard the result. {@link persist} is unsafe afterwards\n * because there is no D1 baseline to compare against.\n */\n hydrateInMemory(): void {\n if (this.state) return;\n this.state = createEmptyCfiState(this.tenantId, this.env);\n this.baselineRevision = this.state.revision ?? 0;\n }\n\n /** Clear cached state so the next {@link hydrate} reloads from D1. */\n reset(): void {\n this.state = null;\n this.tamerStateDbUuid = null;\n this.dirty = false;\n this.baselineRevision = 0;\n }\n\n load(): CfiState {\n if (!this.state) {\n throw new Error(\"StateManager: call await hydrate(api) before load()\");\n }\n return this.state;\n }\n\n get(derivedName: string): StateEntry | undefined {\n const s = this.load();\n return s.resources[derivedName];\n }\n\n set(derivedName: string, entry: StateEntry): void {\n const s = this.load();\n s.resources[derivedName] = entry;\n s.syncedAt = new Date().toISOString();\n this.dirty = true;\n }\n\n delete(derivedName: string): void {\n const s = this.load();\n delete s.resources[derivedName];\n s.syncedAt = new Date().toISOString();\n this.dirty = true;\n }\n\n getAll(): Record<string, StateEntry> {\n return this.load().resources;\n }\n\n getTenant(product: string, workspace: string): TenantStateEntry | undefined {\n const s = this.load();\n return s.tenants?.[tenantStateKey(product, workspace)];\n }\n\n setTenant(entry: TenantStateEntry): void {\n const s = this.load();\n if (!s.tenants) s.tenants = {};\n s.tenants[tenantStateKey(entry.product, entry.workspace)] = entry;\n s.syncedAt = new Date().toISOString();\n this.dirty = true;\n }\n\n deleteTenant(product: string, workspace: string): void {\n const s = this.load();\n if (!s.tenants) return;\n delete s.tenants[tenantStateKey(product, workspace)];\n s.syncedAt = new Date().toISOString();\n this.dirty = true;\n }\n\n listTenants(): TenantStateEntry[] {\n return Object.values(this.load().tenants ?? {});\n }\n\n /** CloudFormation-style stack metadata (name, owner). Returns a copy. */\n getStackMeta(): CfiStackMeta | undefined {\n const s = this.load().stack;\n return s ? { ...s } : undefined;\n }\n\n /**\n * Set or merge stack metadata. Pass `undefined` fields to clear them; only\n * provided keys are written, so callers can update one field at a time.\n */\n setStackMeta(meta: CfiStackMeta): void {\n const s = this.load();\n s.stack = { ...(s.stack ?? {}), ...meta };\n s.syncedAt = new Date().toISOString();\n this.dirty = true;\n }\n\n /**\n * Resolved + persisted `outputs:` for this stack. Returns `{}` when none\n * have been recorded yet (e.g. before the first successful `apply`). The\n * returned object is a shallow copy — mutate via {@link replaceStackOutputs}.\n */\n getStackOutputs(): Record<string, CfiStackOutputValue> {\n return { ...(this.load().stackOutputs ?? {}) };\n }\n\n /**\n * Replace this stack's `stackOutputs` map wholesale. Pass `{}` to clear\n * (e.g. when `outputs` is removed from `tamer.config.ts`); pass a fresh\n * map keyed by output name to commit a successful apply's resolved values.\n * No-op when the new map is structurally identical to the existing one\n * (avoids gratuitous `revision` bumps on no-op applies).\n */\n replaceStackOutputs(next: Record<string, CfiStackOutputValue>): void {\n const s = this.load();\n const prev = s.stackOutputs ?? {};\n if (stackOutputsEqual(prev, next)) return;\n if (Object.keys(next).length === 0) {\n delete s.stackOutputs;\n } else {\n s.stackOutputs = { ...next };\n }\n s.syncedAt = new Date().toISOString();\n this.dirty = true;\n }\n\n getLastOperation(): CfiOperationRecord | undefined {\n return this.load().lastOperation;\n }\n\n /** Completed operations (`succeeded` / `failed` only), newest first. */\n getOperationHistory(): CfiOperationRecord[] {\n const h = this.load().operationHistory;\n return h ? h.map((e) => ({ ...e })) : [];\n }\n\n /**\n * Begin recording a CloudFormation-style operation marker. Sets `status:\n * \"in_progress\"` and `startedAt`; pair with {@link finishOperation} on\n * success or {@link failOperation} on error. Persist between calls if the\n * operation may take a long time and you want concurrent operators to see\n * the in-progress marker.\n */\n beginOperation(command: CfiOperationName, detail?: string): void {\n const s = this.load();\n s.lastOperation = {\n command,\n status: \"in_progress\",\n startedAt: new Date().toISOString(),\n detail,\n };\n s.syncedAt = s.lastOperation.startedAt;\n this.dirty = true;\n }\n\n finishOperation(detail?: string): void {\n const s = this.load();\n if (!s.lastOperation) return;\n s.lastOperation.status = \"succeeded\";\n s.lastOperation.completedAt = new Date().toISOString();\n if (detail !== undefined) s.lastOperation.detail = detail;\n s.syncedAt = s.lastOperation.completedAt;\n this.appendTerminalOperationToHistory(s.lastOperation);\n this.dirty = true;\n }\n\n failOperation(errorMessage: string): void {\n const s = this.load();\n if (!s.lastOperation) return;\n s.lastOperation.status = \"failed\";\n s.lastOperation.completedAt = new Date().toISOString();\n s.lastOperation.errorMessage = errorMessage;\n s.syncedAt = s.lastOperation.completedAt;\n this.appendTerminalOperationToHistory(s.lastOperation);\n this.dirty = true;\n }\n\n private appendTerminalOperationToHistory(op: CfiOperationRecord): void {\n if (op.status !== \"succeeded\" && op.status !== \"failed\") return;\n const s = this.load();\n const entry: CfiOperationRecord = {\n command: op.command,\n status: op.status,\n startedAt: op.startedAt,\n completedAt: op.completedAt,\n errorMessage: op.errorMessage,\n detail: op.detail,\n };\n const prev = s.operationHistory ?? [];\n s.operationHistory = [entry, ...prev].slice(0, OPERATION_HISTORY_CAP);\n }\n\n /**\n * Persist to D1 (no-op for local). Uses optimistic concurrency: re-reads\n * `revision` before write; throws {@link StateConflictError} if another\n * writer advanced the row since {@link hydrate}.\n */\n async persist(api: CFApiClient): Promise<void> {\n if (this.env === \"local\") {\n this.dirty = false;\n return;\n }\n if (!this.dirty || !this.state || !this.tamerStateDbUuid) return;\n\n const rowKey = stateRowKey(this.stackName);\n const { rows } = await api.d1Query(\n this.tamerStateDbUuid,\n `SELECT v FROM tamer_kv WHERE k = ?`,\n [rowKey],\n );\n let remoteRev = 0;\n if (rows.length > 0) {\n const v = rows[0]![\"v\"];\n if (typeof v === \"string\") {\n remoteRev = parseCfiStateJson(v).revision ?? 0;\n }\n }\n if (remoteRev !== this.baselineRevision) {\n throw new StateConflictError(\n `Tamer state conflict (stack=${this.stackName}): remote revision ${remoteRev} !== expected ${this.baselineRevision}. Re-run after refresh.`,\n );\n }\n\n this.state.revision = remoteRev + 1;\n this.state.syncedAt = new Date().toISOString();\n const json = JSON.stringify(this.state);\n await api.d1Query(\n this.tamerStateDbUuid,\n `INSERT INTO tamer_kv (k, v) VALUES (?, ?)\n ON CONFLICT(k) DO UPDATE SET v = excluded.v`,\n [rowKey, json],\n );\n this.baselineRevision = this.state.revision;\n this.dirty = false;\n }\n\n /** Mark clean without writing (e.g. before deleting the state database). */\n clearDirty(): void {\n this.dirty = false;\n }\n}\n\nfunction stackOutputsEqual(\n a: Record<string, CfiStackOutputValue>,\n b: Record<string, CfiStackOutputValue>,\n): boolean {\n const ak = Object.keys(a).sort();\n const bk = Object.keys(b).sort();\n if (ak.length !== bk.length) return false;\n for (let i = 0; i < ak.length; i++) {\n if (ak[i] !== bk[i]) return false;\n const k = ak[i]!;\n const av = a[k]!;\n const bv = b[k]!;\n // `resolvedAt` is intentionally excluded — same value+source = no churn.\n if (av.value !== bv.value || av.source !== bv.source) return false;\n }\n return true;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"bootstrap-BicPW44a.mjs","names":[],"sources":["../src/cli/commands/bootstrap.ts"],"sourcesContent":["import { loadConfig } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport {\n ensureTamerStateDatabase,\n tamerStateDatabaseName,\n} from \"../../core/state/tamerStateDb.js\";\nimport {\n ensureTamerArtifactsBucket,\n} from \"../../core/state/tamerArtifactsR2.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\n\nexport async function runBootstrap(options: {\n env: string;\n configPath?: string;\n}): Promise<void> {\n const { env, configPath } = options;\n if (env === \"local\") {\n console.log(\n \"bootstrap: env=local uses in-memory state only; no D1/R2 metadata is created.\",\n );\n return;\n }\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 api = new CFApiClient(accountId);\n const stackName = stackNameForConfig(config);\n const uuid = await ensureTamerStateDatabase(\n api,\n config.tenant.id,\n env,\n stackName,\n );\n console.log(\n `Tamer state ready: D1 uuid=${uuid} name=${tamerStateDatabaseName(env)} (stack=${stackName})`,\n );\n\n const bucketName = await ensureTamerArtifactsBucket(api, env);\n console.log(`Tamer artifacts ready: R2 bucket=${bucketName}`);\n\n const state = new StateManager(config.tenant.id, env, stackName);\n await state.hydrate(api);\n state.beginOperation(\"bootstrap\");\n if (!state.getStackMeta()?.name) {\n state.setStackMeta({ name: stackName });\n }\n state.finishOperation(\"ready\");\n await state.persist(api);\n}\n"],"mappings":";;;;;;;AAaA,eAAsB,aAAa,SAGjB;CAChB,MAAM,EAAE,KAAK,eAAe;AAC5B,KAAI,QAAQ,SAAS;AACnB,UAAQ,IACN,gFACD;AACD;;CAGF,MAAM,SAAS,MAAM,WAAW,YAAY,EAAE,KAAK,CAAC;CACpD,MAAM,YACJ,OAAO,cAAc,4BAA4B;AACnD,KAAI,CAAC,UACH,OAAM,IAAI,MACR,iEACD;CAGH,MAAM,MAAM,IAAI,YAAY,UAAU;CACtC,MAAM,YAAY,mBAAmB,OAAO;CAC5C,MAAM,OAAO,MAAM,yBACjB,KACA,OAAO,OAAO,IACd,KACA,UACD;AACD,SAAQ,IACN,8BAA8B,KAAK,QAAQ,uBAAuB,IAAI,CAAC,UAAU,UAAU,GAC5F;CAED,MAAM,aAAa,MAAM,2BAA2B,KAAK,IAAI;AAC7D,SAAQ,IAAI,oCAAoC,aAAa;CAE7D,MAAM,QAAQ,IAAI,aAAa,OAAO,OAAO,IAAI,KAAK,UAAU;AAChE,OAAM,MAAM,QAAQ,IAAI;AACxB,OAAM,eAAe,YAAY;AACjC,KAAI,CAAC,MAAM,cAAc,EAAE,KACzB,OAAM,aAAa,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAM,gBAAgB,QAAQ;AAC9B,OAAM,MAAM,QAAQ,IAAI"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"deploy-DAEjDjOm.mjs","names":["out: WorkerEntry[]"],"sources":["../src/cli/commands/deploy.ts"],"sourcesContent":["import type { CfiConfig, WorkerConfig } from \"../../types.js\";\nimport { loadConfig, getWorkers } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport { wranglerConfigCliArgs } from \"../../core/wrangler/wranglerOutFile.js\";\nimport { spawnWranglerSync } from \"../../core/wrangler/wranglerSpawn.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport {\n buildIntraStackScriptNameMap,\n mergedWorkerConfigForEnv,\n resolveDeployedWorkerName,\n resolveWorkerConfig,\n rewriteIntraStackServiceTargets,\n} from \"../../core/config/resolver.js\";\nimport {\n generateWranglerConfig,\n writeWranglerJson,\n} from \"../../core/wrangler/generator.js\";\nimport { runSync } from \"./sync.js\";\nimport { workerRoutesApply } from \"../../features/worker-route/index.js\";\nimport { fetchStackImports } from \"../../core/imports/fetchStackImports.js\";\n\ntype WorkerEntry = [string, WorkerConfig];\n\n/**\n * Topologically sort workers by `services[].service` so that dependencies\n * deploy before dependents. Cloudflare rejects deploys that reference\n * service bindings to workers that don't yet exist on the account.\n * Cross-config dependencies (services not in this monorepo) are ignored.\n */\nexport function topoSortWorkersByServiceBindings(\n workers: WorkerEntry[],\n config: CfiConfig,\n naming: NamingEngine,\n env: string,\n): WorkerEntry[] {\n const intraMap = buildIntraStackScriptNameMap(config, env, naming);\n const scriptNameToKey = new Map<string, string>();\n for (const [key, cfg] of workers) {\n const name = resolveDeployedWorkerName(config, key, cfg, env, naming);\n scriptNameToKey.set(name, key);\n }\n\n const byKey = new Map(workers);\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const out: WorkerEntry[] = [];\n\n function visit(key: string): void {\n if (visited.has(key)) return;\n if (visiting.has(key)) return;\n visiting.add(key);\n const cfg = byKey.get(key);\n if (cfg) {\n const merged = rewriteIntraStackServiceTargets(\n mergedWorkerConfigForEnv(cfg, env, config.tenant),\n intraMap,\n );\n const deps = merged.services?.map((s) => s.service) ?? [];\n for (const dep of deps) {\n const depKey = scriptNameToKey.get(dep);\n if (depKey && depKey !== key) visit(depKey);\n }\n visiting.delete(key);\n visited.add(key);\n out.push([key, cfg]);\n }\n }\n\n for (const [key] of workers) visit(key);\n return out;\n}\n\nexport async function runDeploy(options: {\n worker?: string;\n env?: string;\n configPath?: string;\n /** Passed to `wrangler deploy --dispatch-namespace` when the worker has no `dispatchNamespace` in config. */\n dispatchNamespace?: string;\n}): Promise<void> {\n const workerFilter = options.worker;\n // `--env` is intentionally required (no silent default to \"prod\") to\n // match every other Tamer command and to avoid the classic \"ran\n // `tamer deploy` from the wrong shell, shipped a half-tested branch\n // to production\" footgun.\n const env = options.env;\n if (!env) {\n throw new Error(\n \"deploy: --env is required (e.g. --env staging). \" +\n \"Tamer no longer defaults to prod — pass the env explicitly.\",\n );\n }\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 console.log(`Syncing state for env: ${env}...`);\n await runSync({ env, configPath });\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 const imports = await fetchStackImports(api, config, env);\n state.beginOperation(\"deploy\", workerFilter ? `worker:${workerFilter}` : undefined);\n\n try {\n\n const workers = await getWorkers(config, baseDir);\n const toDeploy = workerFilter\n ? workers.filter(([k]) => k === workerFilter)\n : workers;\n\n if (toDeploy.length === 0) {\n throw new Error(\n workerFilter\n ? `Worker \"${workerFilter}\" not found`\n : \"No workers configured\",\n );\n }\n\n const ordered = topoSortWorkersByServiceBindings(\n toDeploy,\n config,\n naming,\n env,\n );\n\n for (const [workerKey, workerConfig] of ordered) {\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 const typesArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"types\",\n ];\n const typesResult = spawnWranglerSync(typesArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n });\n if (typesResult.status !== 0) {\n throw new Error(`wrangler types failed for ${workerKey}`);\n }\n\n const dispatchNs =\n resolved.dispatchNamespace ?? options.dispatchNamespace;\n const deployArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"deploy\",\n ];\n if (dispatchNs) {\n deployArgs.push(\"--dispatch-namespace\", dispatchNs);\n }\n\n const deployResult = spawnWranglerSync(deployArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n });\n if (deployResult.status !== 0) {\n throw new Error(`wrangler deploy failed for ${workerKey}`);\n }\n console.log(`Deployed ${workerKey}`);\n }\n\n if (env !== \"local\") {\n try {\n await workerRoutesApply(\n env,\n config,\n baseDir,\n accountId,\n naming,\n state,\n api,\n { imports },\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`worker routes apply failed after deploy: ${msg}`);\n }\n }\n\n state.finishOperation();\n await state.persist(api);\n console.log(`Deploy complete for env: ${env}`);\n } catch (err) {\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 throw err;\n }\n}\n"],"mappings":"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"}
@@ -1,10 +0,0 @@
1
- import "./loader-DnT9iqz9.mjs";
2
- import "./fetchStackImports-ClUYZy_U.mjs";
3
- import "./StateManager-JLBtz9V-.mjs";
4
- import "./r2S3EmptyBucket-DD81ZWQ7.mjs";
5
- import { n as runDrift, t as computeDriftReport } from "./drift-DncpkI2R.mjs";
6
- import "./logpush-job-DsRkOORJ.mjs";
7
- import "./worker-route-DY1onr-h.mjs";
8
- import "./workers-DNKsZOq4.mjs";
9
-
10
- export { runDrift };
@@ -1 +0,0 @@
1
- {"version":3,"file":"drift-DncpkI2R.mjs","names":["drift: ResourceDrift","drift: ResourceDrift","drift: ResourceDrift","byZone: DnsRecordsByZone","out: T[]","REGISTRY_LABELS: Record<string, 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 | \"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\";\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}): 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 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 default:\n return kind;\n }\n}\n\nfunction suffix(cfId?: string): string {\n return cfId ? ` [${cfId}]` : \"\";\n}\n"],"mappings":"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"}