@dragonmastery/tamer 0.28.0 → 0.30.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/README.md +2 -1
- package/dist/{StateManager-DTqtLLVX.mjs → StateManager-JLBtz9V-.mjs} +2 -2
- package/dist/{StateManager-DTqtLLVX.mjs.map → StateManager-JLBtz9V-.mjs.map} +1 -1
- package/dist/{apply-B0b_jjGv.mjs → apply-CWU3HY0P.mjs} +13 -13
- package/dist/{apply-B0b_jjGv.mjs.map → apply-CWU3HY0P.mjs.map} +1 -1
- package/dist/{applyTarget-BetDYdeS.mjs → applyTarget-D15T_q7G.mjs} +3 -3
- package/dist/{applyTarget-BetDYdeS.mjs.map → applyTarget-D15T_q7G.mjs.map} +1 -1
- package/dist/{bootstrap-CBzPilB1.mjs → bootstrap-BicPW44a.mjs} +3 -3
- package/dist/{bootstrap-CBzPilB1.mjs.map → bootstrap-BicPW44a.mjs.map} +1 -1
- package/dist/{cloudflareSnapshot-B4FOaNr0.mjs → cloudflareSnapshot-GBUHeg2m.mjs} +7 -7
- package/dist/{cloudflareSnapshot-B4FOaNr0.mjs.map → cloudflareSnapshot-GBUHeg2m.mjs.map} +1 -1
- package/dist/{deploy-gHEQxhmx.mjs → deploy-DAEjDjOm.mjs} +8 -8
- package/dist/{deploy-gHEQxhmx.mjs.map → deploy-DAEjDjOm.mjs.map} +1 -1
- package/dist/{destroy-B21f3wgq.mjs → destroy-DtgPD_bD.mjs} +11 -11
- package/dist/{destroy-B21f3wgq.mjs.map → destroy-DtgPD_bD.mjs.map} +1 -1
- package/dist/{destroy-tenant-BW2nasnK.mjs → destroy-tenant-B-VLKfc6.mjs} +3 -3
- package/dist/{destroy-tenant-BW2nasnK.mjs.map → destroy-tenant-B-VLKfc6.mjs.map} +1 -1
- package/dist/{dev-Dt26nzMJ.mjs → dev-BYItpt9U.mjs} +8 -8
- package/dist/{dev-Dt26nzMJ.mjs.map → dev-BYItpt9U.mjs.map} +1 -1
- package/dist/{dns-records.sync-Bpzz9H0s.mjs → dns-records.sync-CfI1mqXv.mjs} +2 -2
- package/dist/{dns-records.sync-Bpzz9H0s.mjs.map → dns-records.sync-CfI1mqXv.mjs.map} +1 -1
- package/dist/drift-DRnwTyZD.mjs +10 -0
- package/dist/{drift-D8ZrSgTn.mjs → drift-DncpkI2R.mjs} +8 -8
- package/dist/{drift-D8ZrSgTn.mjs.map → drift-DncpkI2R.mjs.map} +1 -1
- package/dist/{events-BSwGdkGj.mjs → events-B6oCdvSt.mjs} +3 -3
- package/dist/{events-BSwGdkGj.mjs.map → events-B6oCdvSt.mjs.map} +1 -1
- package/dist/{fetchStackImports-B4ZJahOt.mjs → fetchStackImports-ClUYZy_U.mjs} +294 -101
- package/dist/fetchStackImports-ClUYZy_U.mjs.map +1 -0
- package/dist/{generator-CIMbcPzv.mjs → generator-h_VG0Q5f.mjs} +6 -5
- package/dist/generator-h_VG0Q5f.mjs.map +1 -0
- package/dist/{import-BrduwA9Z.mjs → import-D8zaVvwK.mjs} +6 -4
- package/dist/import-D8zaVvwK.mjs.map +1 -0
- package/dist/index.d.mts +154 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{loader-DP7yXqT6.mjs → loader-DnT9iqz9.mjs} +17 -4
- package/dist/loader-DnT9iqz9.mjs.map +1 -0
- package/dist/{logpush-job-xS7270FZ.mjs → logpush-job-DsRkOORJ.mjs} +2 -2
- package/dist/{logpush-job-xS7270FZ.mjs.map → logpush-job-DsRkOORJ.mjs.map} +1 -1
- package/dist/{migrate-CahG6BYV.mjs → migrate-Bwl0w6XN.mjs} +5 -5
- package/dist/{migrate-CahG6BYV.mjs.map → migrate-Bwl0w6XN.mjs.map} +1 -1
- package/dist/{normalize-Bx0bpFop.mjs → normalize-DVSTRZhO.mjs} +18 -1
- package/dist/normalize-DVSTRZhO.mjs.map +1 -0
- package/dist/{plan-DWvsvy1U.mjs → plan-BNIAD--f.mjs} +11 -11
- package/dist/{plan-DWvsvy1U.mjs.map → plan-BNIAD--f.mjs.map} +1 -1
- package/dist/{provision-tenant-WTKo93Y0.mjs → provision-tenant-BcZocyyn.mjs} +4 -4
- package/dist/{provision-tenant-WTKo93Y0.mjs.map → provision-tenant-BcZocyyn.mjs.map} +1 -1
- package/dist/{stackOutputs-W9mnnJuj.mjs → stackOutputs-D33EmyfT.mjs} +3 -3
- package/dist/{stackOutputs-W9mnnJuj.mjs.map → stackOutputs-D33EmyfT.mjs.map} +1 -1
- package/dist/{status-DLwREPjb.mjs → status-BAPpi2Zt.mjs} +7 -7
- package/dist/{status-DLwREPjb.mjs.map → status-BAPpi2Zt.mjs.map} +1 -1
- package/dist/{sync-f2K2blwm.mjs → sync-BdJ43vO7.mjs} +8 -8
- package/dist/{sync-f2K2blwm.mjs.map → sync-BdJ43vO7.mjs.map} +1 -1
- package/dist/tamer.mjs +32 -18
- package/dist/tamer.mjs.map +1 -1
- package/dist/{types-CqxqYnrT.mjs → types-CN1BOr0U.mjs} +5 -5
- package/dist/{types-CqxqYnrT.mjs.map → types-CN1BOr0U.mjs.map} +1 -1
- package/dist/{verifyPlanFile-c16z1AMH.mjs → verifyPlanFile-BQ7GCDC2.mjs} +2 -2
- package/dist/{verifyPlanFile-c16z1AMH.mjs.map → verifyPlanFile-BQ7GCDC2.mjs.map} +1 -1
- package/dist/{wfp-delete-DysvX1u7.mjs → wfp-delete-BG9WBd7F.mjs} +2 -2
- package/dist/{wfp-delete-DysvX1u7.mjs.map → wfp-delete-BG9WBd7F.mjs.map} +1 -1
- package/dist/{wfp-put-jaVd_LjO.mjs → wfp-put-DjErqxFa.mjs} +2 -2
- package/dist/{wfp-put-jaVd_LjO.mjs.map → wfp-put-DjErqxFa.mjs.map} +1 -1
- package/dist/{worker-route-Be2IvOdr.mjs → worker-route-DY1onr-h.mjs} +3 -3
- package/dist/{worker-route-Be2IvOdr.mjs.map → worker-route-DY1onr-h.mjs.map} +1 -1
- package/dist/{workers-aGILs77X.mjs → workers-DNKsZOq4.mjs} +3 -3
- package/dist/{workers-aGILs77X.mjs.map → workers-DNKsZOq4.mjs.map} +1 -1
- package/package.json +1 -1
- package/dist/drift-D5qzCTft.mjs +0 -10
- package/dist/fetchStackImports-B4ZJahOt.mjs.map +0 -1
- package/dist/generator-CIMbcPzv.mjs.map +0 -1
- package/dist/import-BrduwA9Z.mjs.map +0 -1
- package/dist/loader-DP7yXqT6.mjs.map +0 -1
- package/dist/normalize-Bx0bpFop.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ Also requires the **`wrangler`** peer (`>=4.0.0`). Install, scripts, stack layou
|
|
|
24
24
|
|
|
25
25
|
## Consumers (downstream repos)
|
|
26
26
|
|
|
27
|
-
Install from npm and walk through bootstrap → apply → deploy in **[docs/consumer-quickstart.md](docs/consumer-quickstart.md)**. Resource kinds, `${tamer:import:…}`, outputs, and CLI flags remain documented below for reference.
|
|
27
|
+
Install from npm and walk through bootstrap → apply → deploy in **[docs/consumer-quickstart.md](docs/consumer-quickstart.md)**. Adopting **existing** D1/R2/workers without CF IDs in config: **[docs/brownfield-adoption.md](docs/brownfield-adoption.md)**. Resource kinds, `${tamer:import:…}`, outputs, and CLI flags remain documented below for reference.
|
|
28
28
|
|
|
29
29
|
## Types usage
|
|
30
30
|
|
|
@@ -588,6 +588,7 @@ bun run tamer:down -- --env dev --confirm-env dev
|
|
|
588
588
|
| Doc | Audience |
|
|
589
589
|
| --- | --- |
|
|
590
590
|
| **[Consumer quickstart](docs/consumer-quickstart.md)** | Downstream repos — install from npm, first deploy, version pinning |
|
|
591
|
+
| **[Brownfield adoption](docs/brownfield-adoption.md)** | Downstream repos — legacy CF names, `naming` hooks, sync/plan flow (no IDs in config) |
|
|
591
592
|
| **[Testing](docs/testing.md)** | Contributors — test runners, JUnit, coverage |
|
|
592
593
|
| **[Publish / integration requirements](docs/publish.md)** | Maintainers — cross-repo contracts for DragonMastery stacks |
|
|
593
594
|
| **[npm CLI packaging strategy](docs/npm-cli-packaging-strategy.md)** | Maintainers — npm package build and release layout |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as boolean, c as
|
|
1
|
+
import { a as boolean, c as literal, d as record, f as string, i as array, l as number, n as _enum, s as discriminatedUnion, t as StateConflictError, u as object } from "./tamer.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/core/state/stateSchema.ts
|
|
4
4
|
const D1StateEntrySchema = object({
|
|
@@ -757,4 +757,4 @@ function stackOutputsEqual(a, b) {
|
|
|
757
757
|
|
|
758
758
|
//#endregion
|
|
759
759
|
export { tenantStateKey as a, createEmptyCfiState as c, tamerStateDatabaseName as d, stackNameForConfig as f, tenantShardDatabaseName as i, destroyTamerStateDatabase as l, parseTenantShardRoles as n, effectiveDispatchNamespaceName as o, tenantDispatchScriptName as r, isEphemeralEnv as s, StateManager as t, ensureTamerStateDatabase as u };
|
|
760
|
-
//# sourceMappingURL=StateManager-
|
|
760
|
+
//# sourceMappingURL=StateManager-JLBtz9V-.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StateManager-DTqtLLVX.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
|
+
{"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,19 +1,19 @@
|
|
|
1
|
-
import { f as getDispatchNamespaces, m as getLogpushJobs, p as getDnsRecords } from "./normalize-
|
|
2
|
-
import { n as loadConfig, t as getWorkers } from "./loader-
|
|
1
|
+
import { f as getDispatchNamespaces, m as getLogpushJobs, p as getDnsRecords } from "./normalize-DVSTRZhO.mjs";
|
|
2
|
+
import { n as loadConfig, t as getWorkers } from "./loader-DnT9iqz9.mjs";
|
|
3
3
|
import { n as cloudflareAccountIdFromEnv, t as CFApiClient } from "./CFApiClient-DhbyyV71.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { f as stackNameForConfig, o as effectiveDispatchNamespaceName, t as StateManager } from "./StateManager-
|
|
4
|
+
import { a as resourceModules, d as mergeWorkerConfigForResourcePick, m as resolveWorkerConfig, n as importedStackNames, p as resolveDeployedWorkerName, t as fetchStackImports, v as namingFromConfig } from "./fetchStackImports-ClUYZy_U.mjs";
|
|
5
|
+
import { f as stackNameForConfig, o as effectiveDispatchNamespaceName, t as StateManager } from "./StateManager-JLBtz9V-.mjs";
|
|
6
6
|
import "./r2S3EmptyBucket-DD81ZWQ7.mjs";
|
|
7
7
|
import { i as resetApplySummary, n as logApplyChange, r as printApplySummary } from "./planFormat-CJw8Kq2s.mjs";
|
|
8
|
-
import { n as writeWranglerJson, t as generateWranglerConfig } from "./generator-
|
|
8
|
+
import { n as writeWranglerJson, t as generateWranglerConfig } from "./generator-h_VG0Q5f.mjs";
|
|
9
9
|
import { a as effectiveDnsRecordProxied, i as effectiveDnsRecordComment, n as dnsRecordCommentMarker, o as effectiveDnsRecordTtl, r as dnsRecordStateKey, t as dnsRecordAppliesToEnv } from "./dns-records.resolve-DwBR_1WI.mjs";
|
|
10
|
-
import { i as computeDnsRecordMutableChanges, r as parseApplyTarget, t as assertApplyTargetDeclared } from "./applyTarget-
|
|
11
|
-
import { a as logpushJobApply } from "./logpush-job-
|
|
12
|
-
import { n as resolveStackOutputs } from "./stackOutputs-
|
|
13
|
-
import "./worker-route-
|
|
14
|
-
import { runSync } from "./sync-
|
|
15
|
-
import { i as hashCloudflareSnapshot, t as buildCloudflareSnapshot } from "./cloudflareSnapshot-
|
|
16
|
-
import { t as verifyPlanFile } from "./verifyPlanFile-
|
|
10
|
+
import { i as computeDnsRecordMutableChanges, r as parseApplyTarget, t as assertApplyTargetDeclared } from "./applyTarget-D15T_q7G.mjs";
|
|
11
|
+
import { a as logpushJobApply } from "./logpush-job-DsRkOORJ.mjs";
|
|
12
|
+
import { n as resolveStackOutputs } from "./stackOutputs-D33EmyfT.mjs";
|
|
13
|
+
import "./worker-route-DY1onr-h.mjs";
|
|
14
|
+
import { runSync } from "./sync-BdJ43vO7.mjs";
|
|
15
|
+
import { i as hashCloudflareSnapshot, t as buildCloudflareSnapshot } from "./cloudflareSnapshot-GBUHeg2m.mjs";
|
|
16
|
+
import { t as verifyPlanFile } from "./verifyPlanFile-BQ7GCDC2.mjs";
|
|
17
17
|
|
|
18
18
|
//#region src/features/dispatch-namespace/dispatch-namespace.apply.ts
|
|
19
19
|
function uniqueResolvedNamespaces(configs, env, tenant) {
|
|
@@ -420,4 +420,4 @@ async function rollbackCreatedResources(args) {
|
|
|
420
420
|
|
|
421
421
|
//#endregion
|
|
422
422
|
export { runApply };
|
|
423
|
-
//# sourceMappingURL=apply-
|
|
423
|
+
//# sourceMappingURL=apply-CWU3HY0P.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-B0b_jjGv.mjs","names":["out: Array<{ config: DispatchNamespaceResourceConfig; name: string }>","adoptedEntry: DnsRecordStateEntry","patch: Partial<{\n content: string;\n ttl: number;\n proxied: boolean;\n priority: number;\n comment: string;\n }>","entry: DnsRecordStateEntry","target: ApplyTarget | undefined","opDetail: string[]"],"sources":["../src/features/dispatch-namespace/dispatch-namespace.apply.ts","../src/features/dns-records/dns-records.apply.ts","../src/cli/commands/apply.ts"],"sourcesContent":["import type { TenantMeta, DispatchNamespaceResourceConfig } from \"../../types.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport { effectiveDispatchNamespaceName } from \"./dispatch-namespace.resolve.js\";\n\nfunction uniqueResolvedNamespaces(\n configs: DispatchNamespaceResourceConfig[],\n env: string,\n tenant: TenantMeta,\n): Array<{ config: DispatchNamespaceResourceConfig; name: string }> {\n const seen = new Set<string>();\n const out: Array<{ config: DispatchNamespaceResourceConfig; name: string }> =\n [];\n for (const c of configs) {\n const name = effectiveDispatchNamespaceName(c, env, tenant);\n if (seen.has(name)) continue;\n seen.add(name);\n out.push({ config: c, name });\n }\n return out;\n}\n\nexport async function dispatchNamespaceApply(\n resources: DispatchNamespaceResourceConfig[],\n tenant: TenantMeta,\n env: string,\n api: CFApiClient,\n state: StateManager,\n): Promise<void> {\n if (resources.length === 0) return;\n if (env === \"local\") return;\n\n const unique = uniqueResolvedNamespaces(resources, env, tenant);\n const needsCreateLookup = unique.some(\n ({ name }) => !state.get(`dispatch_ns:${name}`),\n );\n\n // CF is the source of truth: avoid POSTing for namespaces that already exist\n // (state may be empty in CI / first-time apply). Cloudflare's create error\n // for duplicates conflates with \"invalid name\", so a pre-check is clearer.\n const existingNames = needsCreateLookup\n ? new Set((await api.dispatchNamespaceListAll()).map((n) => n.namespace_name))\n : new Set<string>();\n\n for (const { config, name } of unique) {\n const key = `dispatch_ns:${name}`;\n if (state.get(key)) continue;\n\n if (!existingNames.has(name)) {\n await api.dispatchNamespaceCreate(name);\n }\n\n state.set(key, {\n type: \"dispatch_namespace\",\n logicalName: config.logicalName,\n derivedName: name,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n });\n }\n}\n","import type {\n DnsRecordResourceConfig,\n DnsRecordStateEntry,\n TenantMeta,\n} from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport {\n dnsRecordAppliesToEnv,\n dnsRecordCommentMarker,\n dnsRecordStateKey,\n effectiveDnsRecordComment,\n effectiveDnsRecordProxied,\n effectiveDnsRecordTtl,\n} from \"./dns-records.resolve.js\";\nimport { computeDnsRecordMutableChanges } from \"./dns-records.diff.js\";\nimport { logApplyChange } from \"../../core/plan/planFormat.js\";\n\n/**\n * Reconcile every declared DNS record for `env` with Cloudflare. For each\n * config entry:\n *\n * 1. **Skip** if `env` is excluded (always: `local`; or via `skipEnvs`).\n * 2. **Resume after state loss** by scanning `/zones/{id}/dns_records` for\n * any record carrying Tamer's attribution marker comment (`tamer:\n * <tenant>:<env>:<logical>`) on the matching `(type, name)` tuple, and\n * re-adopting it into state.\n * 3. **Create** when nothing matches in state or on the zone.\n * 4. **Patch** mutable fields (`content`, `ttl`, `proxied`, `priority`,\n * `comment`) when state knows about the record but its fields drifted.\n * 5. **Replace** (delete + create) when the record `type` itself changed —\n * Cloudflare rejects type changes via PATCH per the API docs.\n */\nexport async function dnsRecordApply(\n resources: DnsRecordResourceConfig[],\n tenant: TenantMeta,\n env: string,\n api: CFApiClient,\n state: StateManager,\n): Promise<void> {\n if (resources.length === 0) return;\n const applicable = resources.filter((r) => dnsRecordAppliesToEnv(r, env));\n if (applicable.length === 0) return;\n\n const zoneCache = new Map<\n string,\n Awaited<ReturnType<CFApiClient[\"zoneDnsRecordListAll\"]>>\n >();\n const loadZone = async (\n zoneId: string,\n ): Promise<\n Awaited<ReturnType<CFApiClient[\"zoneDnsRecordListAll\"]>>\n > => {\n let cached = zoneCache.get(zoneId);\n if (cached) return cached;\n cached = await api.zoneDnsRecordListAll(zoneId);\n zoneCache.set(zoneId, cached);\n return cached;\n };\n\n for (const config of applicable) {\n const stateKey = dnsRecordStateKey(config.zoneId, config.type, config.name);\n const expected = expectedFromConfig(config, tenant, env);\n const existingEntry = state.get(stateKey);\n\n const stateEntry =\n existingEntry?.type === \"dns_record\"\n ? (existingEntry as DnsRecordStateEntry)\n : undefined;\n\n if (stateEntry) {\n if (recordTypeChanged(stateEntry, config)) {\n logApplyChange({\n kind: \"dns_record\",\n action: \"replace\",\n logical: config.logicalName,\n derived: `${config.type} ${config.name}`,\n changes: [\n {\n field: \"type\",\n from: stateEntry.recordType,\n to: config.type,\n kind: \"immutable\",\n },\n ],\n });\n await api.zoneDnsRecordDelete(config.zoneId, stateEntry.recordId);\n const created = await api.zoneDnsRecordCreate(config.zoneId, {\n type: config.type,\n name: config.name,\n content: expected.content,\n ttl: expected.ttl,\n proxied: expected.proxied,\n priority: expected.priority,\n comment: expected.comment,\n });\n persistCreated(state, stateKey, config, expected, created.id);\n continue;\n }\n const patch = computePatch(stateEntry, expected);\n if (patch) {\n const changes = computeDnsRecordMutableChanges(\n stateEntry,\n config,\n tenant,\n env,\n );\n logApplyChange({\n kind: \"dns_record\",\n action: \"update\",\n logical: config.logicalName,\n derived: `${config.type} ${config.name}`,\n changes,\n });\n await api.zoneDnsRecordPatch(config.zoneId, stateEntry.recordId, patch);\n persistUpdated(state, stateKey, stateEntry, expected);\n }\n continue;\n }\n\n const live = await loadZone(config.zoneId);\n const marker = dnsRecordCommentMarker(tenant, env, config.logicalName);\n const adopted = live.find(\n (r) =>\n r.type === config.type &&\n normalizeName(r.name, config.name) &&\n typeof r.comment === \"string\" &&\n r.comment.startsWith(marker),\n );\n if (adopted) {\n const adoptedEntry: DnsRecordStateEntry = {\n type: \"dns_record\",\n logicalName: config.logicalName,\n zoneId: config.zoneId,\n recordType: config.type,\n name: adopted.name,\n content: adopted.content,\n ttl: adopted.ttl ?? expected.ttl,\n proxied: adopted.proxied ?? false,\n priority: adopted.priority,\n comment: adopted.comment ?? marker,\n recordId: adopted.id,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n state.set(stateKey, adoptedEntry);\n const patch = computePatch(adoptedEntry, expected);\n if (patch) {\n const changes = computeDnsRecordMutableChanges(\n adoptedEntry,\n config,\n tenant,\n env,\n );\n logApplyChange({\n kind: \"dns_record\",\n action: \"update\",\n logical: config.logicalName,\n derived: `${config.type} ${config.name}`,\n changes,\n });\n await api.zoneDnsRecordPatch(config.zoneId, adopted.id, patch);\n persistUpdated(state, stateKey, adoptedEntry, expected);\n }\n continue;\n }\n\n logApplyChange({\n kind: \"dns_record\",\n action: \"create\",\n logical: config.logicalName,\n derived: `${config.type} ${config.name}`,\n });\n const created = await api.zoneDnsRecordCreate(config.zoneId, {\n type: config.type,\n name: config.name,\n content: expected.content,\n ttl: expected.ttl,\n proxied: expected.proxied,\n priority: expected.priority,\n comment: expected.comment,\n });\n persistCreated(state, stateKey, config, expected, created.id);\n }\n}\n\ninterface ExpectedFields {\n content: string;\n ttl: number;\n proxied: boolean;\n priority?: number;\n comment: string;\n}\n\nfunction expectedFromConfig(\n config: DnsRecordResourceConfig,\n tenant: TenantMeta,\n env: string,\n): ExpectedFields {\n return {\n content: config.content,\n ttl: effectiveDnsRecordTtl(config),\n proxied: effectiveDnsRecordProxied(config),\n priority: config.priority,\n comment: effectiveDnsRecordComment(config, tenant, env),\n };\n}\n\nfunction recordTypeChanged(\n state: DnsRecordStateEntry,\n config: DnsRecordResourceConfig,\n): boolean {\n return state.recordType !== config.type;\n}\n\nfunction computePatch(\n state: DnsRecordStateEntry,\n expected: ExpectedFields,\n): Partial<{\n content: string;\n ttl: number;\n proxied: boolean;\n priority: number;\n comment: string;\n}> | undefined {\n const patch: Partial<{\n content: string;\n ttl: number;\n proxied: boolean;\n priority: number;\n comment: string;\n }> = {};\n if (state.content !== expected.content) patch.content = expected.content;\n if (state.ttl !== expected.ttl) patch.ttl = expected.ttl;\n if (state.proxied !== expected.proxied) patch.proxied = expected.proxied;\n if (\n expected.priority !== undefined &&\n state.priority !== expected.priority\n ) {\n patch.priority = expected.priority;\n }\n if (state.comment !== expected.comment) patch.comment = expected.comment;\n return Object.keys(patch).length > 0 ? patch : undefined;\n}\n\nfunction persistCreated(\n state: StateManager,\n key: string,\n config: DnsRecordResourceConfig,\n expected: ExpectedFields,\n recordId: string,\n): void {\n const ts = new Date().toISOString();\n const entry: DnsRecordStateEntry = {\n type: \"dns_record\",\n logicalName: config.logicalName,\n zoneId: config.zoneId,\n recordType: config.type,\n name: config.name,\n content: expected.content,\n ttl: expected.ttl,\n proxied: expected.proxied,\n priority: expected.priority,\n comment: expected.comment,\n recordId,\n createdAt: ts,\n updatedAt: ts,\n };\n state.set(key, entry);\n}\n\nfunction persistUpdated(\n state: StateManager,\n key: string,\n prior: DnsRecordStateEntry,\n expected: ExpectedFields,\n): void {\n const entry: DnsRecordStateEntry = {\n ...prior,\n content: expected.content,\n ttl: expected.ttl,\n proxied: expected.proxied,\n priority: expected.priority,\n comment: expected.comment,\n updatedAt: new Date().toISOString(),\n };\n state.set(key, entry);\n}\n\n/**\n * Cloudflare normalizes DNS names to FQDN ('app.example.com'). The user\n * may declare them either as an apex (`@`) or as a partial — match by\n * exact equality when both look fully-qualified, otherwise by suffix.\n */\nfunction normalizeName(cfName: string, configName: string): boolean {\n if (cfName === configName) return true;\n if (configName === \"@\") return true;\n return cfName.endsWith(`.${configName}`) || cfName.endsWith(configName);\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 {\n resolveWorkerConfig,\n resolveDeployedWorkerName,\n mergeWorkerConfigForResourcePick,\n} from \"../../core/config/resolver.js\";\nimport {\n generateWranglerConfig,\n writeWranglerJson,\n} from \"../../core/wrangler/generator.js\";\nimport { dispatchNamespaceApply } from \"../../features/dispatch-namespace/index.js\";\nimport { dnsRecordApply } from \"../../features/dns-records/index.js\";\nimport {\n getDispatchNamespaces,\n getDnsRecords,\n getLogpushJobs,\n} from \"../../types.js\";\nimport { logpushJobApply } from \"../../features/logpush-job/index.js\";\nimport { resolveStackOutputs } from \"../../core/outputs/stackOutputs.js\";\nimport {\n fetchStackImports,\n importedStackNames,\n} from \"../../core/imports/fetchStackImports.js\";\nimport { runSync } from \"./sync.js\";\nimport { resourceModules } from \"../../core/registry/registry.js\";\nimport { hashCloudflareSnapshot } from \"../../core/plan/planFile.js\";\nimport { buildCloudflareSnapshot } from \"../../core/plan/cloudflareSnapshot.js\";\nimport { verifyPlanFile } from \"../../core/plan/verifyPlanFile.js\";\nimport {\n printApplySummary,\n resetApplySummary,\n} from \"../../core/plan/planFormat.js\";\nimport type { StateEntry } from \"../../types.js\";\nimport {\n parseApplyTarget,\n assertApplyTargetDeclared,\n type ApplyTarget,\n} from \"../../core/apply/applyTarget.js\";\n\nexport async function runApply(options: {\n env?: string;\n addShard?: string;\n configPath?: string;\n /**\n * Path to a plan file from `tamer plan --out`. Apply recomputes the\n * `(config, state)` attestation hashes and refuses to proceed if either\n * differs (override with `allowStale`).\n */\n planFile?: string;\n allowStale?: boolean;\n /**\n * Track every state entry created during this apply. On any failure,\n * delete the matching Cloudflare resources (best-effort) so partial\n * applies do not leak orphans into the account.\n */\n rollbackOnFailure?: boolean;\n /**\n * `kind:logicalName` — create/update only that declared resource; still\n * regenerates all wrangler.json files and resolves full `outputs:`.\n */\n target?: string;\n}): Promise<void> {\n const env = options.env ?? \"local\";\n const addShard = options.addShard;\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 let target: ApplyTarget | undefined;\n if (options.target) {\n target = parseApplyTarget(options.target);\n if (options.planFile) {\n throw new Error(\n \"Cannot combine --plan with --target: plan files attest the full stack. Omit --target, or apply without --plan.\",\n );\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: \"apply\",\n expectedMode: \"forward\",\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 const referencedStacks = importedStackNames(config);\n if (referencedStacks.length > 0) {\n console.log(\n `Pre-fetching tamer:import outputs from stack(s): ${referencedStacks.join(\", \")}…`,\n );\n }\n const imports = await fetchStackImports(api, config, env);\n console.log(\"Applying…\");\n\n if (target) {\n if (addShard) {\n if (target.kind !== \"d1\") {\n throw new Error(\n \"--add-shard only applies to D1; drop --target or use --target d1:<logical>.\",\n );\n }\n if (addShard !== target.logical) {\n throw new Error(\n `--add-shard ${addShard} does not match --target d1:${target.logical}.`,\n );\n }\n }\n await assertApplyTargetDeclared(config, baseDir, target);\n }\n\n // Imports were pre-fetched above (before this block) so every subsequent\n // `${tamer:import:<stack>.<output>}` resolution is a pure map lookup.\n\n const opDetail: string[] = [];\n if (addShard) opDetail.push(`add-shard ${addShard}`);\n if (target) opDetail.push(`target=${target.kind}:${target.logical}`);\n state.beginOperation(\n \"apply\",\n opDetail.length ? opDetail.join(\"; \") : undefined,\n );\n\n if (target) {\n console.log(\n `Scoped apply: only ${target.kind}:${target.logical} (wrangler outputs still generated for every worker)`,\n );\n }\n\n const baselineKeys = options.rollbackOnFailure\n ? new Set(Object.keys(state.getAll()))\n : null;\n\n // Reset the per-action counter so the summary at the end of this run\n // reflects only what *this* `runApply` did (matters for tests and for\n // back-to-back apply invocations from a single process).\n resetApplySummary();\n\n try {\n const dispatchResources =\n !target\n ? getDispatchNamespaces(config)\n : target.kind === \"dispatch_namespace\"\n ? getDispatchNamespaces(config).filter(\n (n) => n.logicalName === target!.logical,\n )\n : [];\n\n await dispatchNamespaceApply(\n dispatchResources,\n config.tenant,\n env,\n api,\n state,\n );\n\n const dnsResources =\n !target\n ? getDnsRecords(config)\n : target.kind === \"dns_record\"\n ? getDnsRecords(config).filter(\n (d) => d.logicalName === target!.logical,\n )\n : [];\n\n await dnsRecordApply(\n dnsResources,\n config.tenant,\n env,\n api,\n state,\n );\n\n const workers = await getWorkers(config, baseDir);\n for (const [workerKey, workerConfig] of workers) {\n const deployedName = resolveDeployedWorkerName(\n config,\n workerKey,\n workerConfig,\n env,\n naming,\n );\n const mergedWorker = mergeWorkerConfigForResourcePick(\n config,\n workerKey,\n workerConfig,\n env,\n accountId,\n naming,\n state,\n { imports },\n );\n for (const mod of resourceModules) {\n if (target) {\n if (target.kind === \"logpush_job\") {\n if (mod.kind !== \"r2\") continue;\n } else if (mod.kind !== target.kind) {\n continue;\n }\n }\n const picked = mod.pickResources(mergedWorker);\n const resources =\n target && mod.kind === target.kind\n ? picked.filter(\n (r) =>\n (r as { logicalName?: string }).logicalName ===\n target.logical,\n )\n : picked;\n if (resources.length === 0) continue;\n await mod.apply({\n resources,\n tenant: config.tenant,\n env,\n api,\n state,\n naming,\n config,\n baseDir,\n addShard,\n worker: { workerKey, deployedName },\n });\n }\n }\n\n const logpushResources = !target\n ? getLogpushJobs(config)\n : target.kind === \"logpush_job\"\n ? getLogpushJobs(config).filter(\n (j) => j.logicalName === target.logical,\n )\n : [];\n\n await logpushJobApply(\n logpushResources,\n config.tenant,\n env,\n accountId,\n api,\n state,\n );\n\n await state.persist(api);\n\n for (const [workerKey, workerConfig] of workers) {\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(\n resolved.workerDir,\n wranglerConfig,\n resolved.wranglerOutFile,\n );\n console.log(`Generated ${resolved.wranglerOutFile} for ${workerKey}`);\n }\n\n // Resolve + persist `outputs:` last — every dependency is already in\n // state by this point, so a strict resolve here surfaces typos in\n // `outputs` as a fail-the-apply error instead of a silent half-write.\n // `replaceStackOutputs` is a no-op when nothing changed, so reruns\n // don't bump `revision` unnecessarily.\n const resolvedOutputs = resolveStackOutputs(config, {\n env,\n state,\n naming,\n imports,\n accountId,\n });\n state.replaceStackOutputs(resolvedOutputs);\n if (Object.keys(resolvedOutputs).length > 0) {\n console.log(\n `Stack outputs: resolved ${Object.keys(resolvedOutputs).length} (${Object.keys(resolvedOutputs).join(\", \")})`,\n );\n } else if (config.outputs == null) {\n // Nothing declared, nothing to print — quiet path.\n } else {\n // `outputs: {}` (empty record) — config explicitly cleared.\n console.log(\"Stack outputs: cleared (empty `outputs` block in config)\");\n }\n\n state.finishOperation();\n await state.persist(api);\n console.log(`Apply complete for env: ${env}`);\n printApplySummary();\n } catch (err) {\n if (baselineKeys) {\n await rollbackCreatedResources({\n api,\n state,\n baselineKeys,\n cause: err,\n });\n }\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\n/**\n * Best-effort undo for a partially failed apply. Walks every state entry\n * created during this run (i.e. not present at apply start) in reverse\n * insertion order and asks the owning module to delete it. Failures are\n * logged and swallowed — rollback never throws so the original error from\n * apply propagates intact.\n */\nasync function rollbackCreatedResources(args: {\n api: CFApiClient;\n state: StateManager;\n baselineKeys: Set<string>;\n cause: unknown;\n}): Promise<void> {\n const { api, state, baselineKeys, cause } = args;\n const all = state.getAll();\n const newKeys = Object.keys(all).filter((k) => !baselineKeys.has(k));\n if (newKeys.length === 0) {\n console.warn(\n `Apply failed; --rollback-on-failure had nothing to undo (no new state entries).`,\n );\n return;\n }\n const causeMsg = cause instanceof Error ? cause.message : String(cause);\n console.warn(\n `Apply failed (${causeMsg}); rolling back ${newKeys.length} new resource(s)...`,\n );\n const moduleByEntryType = new Map<\n StateEntry[\"type\"],\n (typeof resourceModules)[number]\n >(resourceModules.map((m) => [m.stateEntryType, m]));\n for (const key of newKeys.reverse()) {\n const entry = all[key];\n if (!entry) continue;\n if (entry.type === \"logpush_job\") {\n try {\n await api.logpushAccountJobDelete(entry.cfJobId);\n state.delete(key);\n } catch (err) {\n console.warn(\n `Rollback: failed to delete Logpush job ${entry.cfJobId}:`,\n err,\n );\n }\n continue;\n }\n const mod = moduleByEntryType.get(entry.type);\n if (!mod) {\n console.warn(\n `Rollback: no module owns state type \"${entry.type}\" (key \"${key}\"); leaving in place.`,\n );\n continue;\n }\n await mod.destroyOne({ api, state, key, entry });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"apply-CWU3HY0P.mjs","names":["out: Array<{ config: DispatchNamespaceResourceConfig; name: string }>","adoptedEntry: DnsRecordStateEntry","patch: Partial<{\n content: string;\n ttl: number;\n proxied: boolean;\n priority: number;\n comment: string;\n }>","entry: DnsRecordStateEntry","target: ApplyTarget | undefined","opDetail: string[]"],"sources":["../src/features/dispatch-namespace/dispatch-namespace.apply.ts","../src/features/dns-records/dns-records.apply.ts","../src/cli/commands/apply.ts"],"sourcesContent":["import type { TenantMeta, DispatchNamespaceResourceConfig } from \"../../types.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport { effectiveDispatchNamespaceName } from \"./dispatch-namespace.resolve.js\";\n\nfunction uniqueResolvedNamespaces(\n configs: DispatchNamespaceResourceConfig[],\n env: string,\n tenant: TenantMeta,\n): Array<{ config: DispatchNamespaceResourceConfig; name: string }> {\n const seen = new Set<string>();\n const out: Array<{ config: DispatchNamespaceResourceConfig; name: string }> =\n [];\n for (const c of configs) {\n const name = effectiveDispatchNamespaceName(c, env, tenant);\n if (seen.has(name)) continue;\n seen.add(name);\n out.push({ config: c, name });\n }\n return out;\n}\n\nexport async function dispatchNamespaceApply(\n resources: DispatchNamespaceResourceConfig[],\n tenant: TenantMeta,\n env: string,\n api: CFApiClient,\n state: StateManager,\n): Promise<void> {\n if (resources.length === 0) return;\n if (env === \"local\") return;\n\n const unique = uniqueResolvedNamespaces(resources, env, tenant);\n const needsCreateLookup = unique.some(\n ({ name }) => !state.get(`dispatch_ns:${name}`),\n );\n\n // CF is the source of truth: avoid POSTing for namespaces that already exist\n // (state may be empty in CI / first-time apply). Cloudflare's create error\n // for duplicates conflates with \"invalid name\", so a pre-check is clearer.\n const existingNames = needsCreateLookup\n ? new Set((await api.dispatchNamespaceListAll()).map((n) => n.namespace_name))\n : new Set<string>();\n\n for (const { config, name } of unique) {\n const key = `dispatch_ns:${name}`;\n if (state.get(key)) continue;\n\n if (!existingNames.has(name)) {\n await api.dispatchNamespaceCreate(name);\n }\n\n state.set(key, {\n type: \"dispatch_namespace\",\n logicalName: config.logicalName,\n derivedName: name,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n });\n }\n}\n","import type {\n DnsRecordResourceConfig,\n DnsRecordStateEntry,\n TenantMeta,\n} from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport {\n dnsRecordAppliesToEnv,\n dnsRecordCommentMarker,\n dnsRecordStateKey,\n effectiveDnsRecordComment,\n effectiveDnsRecordProxied,\n effectiveDnsRecordTtl,\n} from \"./dns-records.resolve.js\";\nimport { computeDnsRecordMutableChanges } from \"./dns-records.diff.js\";\nimport { logApplyChange } from \"../../core/plan/planFormat.js\";\n\n/**\n * Reconcile every declared DNS record for `env` with Cloudflare. For each\n * config entry:\n *\n * 1. **Skip** if `env` is excluded (always: `local`; or via `skipEnvs`).\n * 2. **Resume after state loss** by scanning `/zones/{id}/dns_records` for\n * any record carrying Tamer's attribution marker comment (`tamer:\n * <tenant>:<env>:<logical>`) on the matching `(type, name)` tuple, and\n * re-adopting it into state.\n * 3. **Create** when nothing matches in state or on the zone.\n * 4. **Patch** mutable fields (`content`, `ttl`, `proxied`, `priority`,\n * `comment`) when state knows about the record but its fields drifted.\n * 5. **Replace** (delete + create) when the record `type` itself changed —\n * Cloudflare rejects type changes via PATCH per the API docs.\n */\nexport async function dnsRecordApply(\n resources: DnsRecordResourceConfig[],\n tenant: TenantMeta,\n env: string,\n api: CFApiClient,\n state: StateManager,\n): Promise<void> {\n if (resources.length === 0) return;\n const applicable = resources.filter((r) => dnsRecordAppliesToEnv(r, env));\n if (applicable.length === 0) return;\n\n const zoneCache = new Map<\n string,\n Awaited<ReturnType<CFApiClient[\"zoneDnsRecordListAll\"]>>\n >();\n const loadZone = async (\n zoneId: string,\n ): Promise<\n Awaited<ReturnType<CFApiClient[\"zoneDnsRecordListAll\"]>>\n > => {\n let cached = zoneCache.get(zoneId);\n if (cached) return cached;\n cached = await api.zoneDnsRecordListAll(zoneId);\n zoneCache.set(zoneId, cached);\n return cached;\n };\n\n for (const config of applicable) {\n const stateKey = dnsRecordStateKey(config.zoneId, config.type, config.name);\n const expected = expectedFromConfig(config, tenant, env);\n const existingEntry = state.get(stateKey);\n\n const stateEntry =\n existingEntry?.type === \"dns_record\"\n ? (existingEntry as DnsRecordStateEntry)\n : undefined;\n\n if (stateEntry) {\n if (recordTypeChanged(stateEntry, config)) {\n logApplyChange({\n kind: \"dns_record\",\n action: \"replace\",\n logical: config.logicalName,\n derived: `${config.type} ${config.name}`,\n changes: [\n {\n field: \"type\",\n from: stateEntry.recordType,\n to: config.type,\n kind: \"immutable\",\n },\n ],\n });\n await api.zoneDnsRecordDelete(config.zoneId, stateEntry.recordId);\n const created = await api.zoneDnsRecordCreate(config.zoneId, {\n type: config.type,\n name: config.name,\n content: expected.content,\n ttl: expected.ttl,\n proxied: expected.proxied,\n priority: expected.priority,\n comment: expected.comment,\n });\n persistCreated(state, stateKey, config, expected, created.id);\n continue;\n }\n const patch = computePatch(stateEntry, expected);\n if (patch) {\n const changes = computeDnsRecordMutableChanges(\n stateEntry,\n config,\n tenant,\n env,\n );\n logApplyChange({\n kind: \"dns_record\",\n action: \"update\",\n logical: config.logicalName,\n derived: `${config.type} ${config.name}`,\n changes,\n });\n await api.zoneDnsRecordPatch(config.zoneId, stateEntry.recordId, patch);\n persistUpdated(state, stateKey, stateEntry, expected);\n }\n continue;\n }\n\n const live = await loadZone(config.zoneId);\n const marker = dnsRecordCommentMarker(tenant, env, config.logicalName);\n const adopted = live.find(\n (r) =>\n r.type === config.type &&\n normalizeName(r.name, config.name) &&\n typeof r.comment === \"string\" &&\n r.comment.startsWith(marker),\n );\n if (adopted) {\n const adoptedEntry: DnsRecordStateEntry = {\n type: \"dns_record\",\n logicalName: config.logicalName,\n zoneId: config.zoneId,\n recordType: config.type,\n name: adopted.name,\n content: adopted.content,\n ttl: adopted.ttl ?? expected.ttl,\n proxied: adopted.proxied ?? false,\n priority: adopted.priority,\n comment: adopted.comment ?? marker,\n recordId: adopted.id,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n state.set(stateKey, adoptedEntry);\n const patch = computePatch(adoptedEntry, expected);\n if (patch) {\n const changes = computeDnsRecordMutableChanges(\n adoptedEntry,\n config,\n tenant,\n env,\n );\n logApplyChange({\n kind: \"dns_record\",\n action: \"update\",\n logical: config.logicalName,\n derived: `${config.type} ${config.name}`,\n changes,\n });\n await api.zoneDnsRecordPatch(config.zoneId, adopted.id, patch);\n persistUpdated(state, stateKey, adoptedEntry, expected);\n }\n continue;\n }\n\n logApplyChange({\n kind: \"dns_record\",\n action: \"create\",\n logical: config.logicalName,\n derived: `${config.type} ${config.name}`,\n });\n const created = await api.zoneDnsRecordCreate(config.zoneId, {\n type: config.type,\n name: config.name,\n content: expected.content,\n ttl: expected.ttl,\n proxied: expected.proxied,\n priority: expected.priority,\n comment: expected.comment,\n });\n persistCreated(state, stateKey, config, expected, created.id);\n }\n}\n\ninterface ExpectedFields {\n content: string;\n ttl: number;\n proxied: boolean;\n priority?: number;\n comment: string;\n}\n\nfunction expectedFromConfig(\n config: DnsRecordResourceConfig,\n tenant: TenantMeta,\n env: string,\n): ExpectedFields {\n return {\n content: config.content,\n ttl: effectiveDnsRecordTtl(config),\n proxied: effectiveDnsRecordProxied(config),\n priority: config.priority,\n comment: effectiveDnsRecordComment(config, tenant, env),\n };\n}\n\nfunction recordTypeChanged(\n state: DnsRecordStateEntry,\n config: DnsRecordResourceConfig,\n): boolean {\n return state.recordType !== config.type;\n}\n\nfunction computePatch(\n state: DnsRecordStateEntry,\n expected: ExpectedFields,\n): Partial<{\n content: string;\n ttl: number;\n proxied: boolean;\n priority: number;\n comment: string;\n}> | undefined {\n const patch: Partial<{\n content: string;\n ttl: number;\n proxied: boolean;\n priority: number;\n comment: string;\n }> = {};\n if (state.content !== expected.content) patch.content = expected.content;\n if (state.ttl !== expected.ttl) patch.ttl = expected.ttl;\n if (state.proxied !== expected.proxied) patch.proxied = expected.proxied;\n if (\n expected.priority !== undefined &&\n state.priority !== expected.priority\n ) {\n patch.priority = expected.priority;\n }\n if (state.comment !== expected.comment) patch.comment = expected.comment;\n return Object.keys(patch).length > 0 ? patch : undefined;\n}\n\nfunction persistCreated(\n state: StateManager,\n key: string,\n config: DnsRecordResourceConfig,\n expected: ExpectedFields,\n recordId: string,\n): void {\n const ts = new Date().toISOString();\n const entry: DnsRecordStateEntry = {\n type: \"dns_record\",\n logicalName: config.logicalName,\n zoneId: config.zoneId,\n recordType: config.type,\n name: config.name,\n content: expected.content,\n ttl: expected.ttl,\n proxied: expected.proxied,\n priority: expected.priority,\n comment: expected.comment,\n recordId,\n createdAt: ts,\n updatedAt: ts,\n };\n state.set(key, entry);\n}\n\nfunction persistUpdated(\n state: StateManager,\n key: string,\n prior: DnsRecordStateEntry,\n expected: ExpectedFields,\n): void {\n const entry: DnsRecordStateEntry = {\n ...prior,\n content: expected.content,\n ttl: expected.ttl,\n proxied: expected.proxied,\n priority: expected.priority,\n comment: expected.comment,\n updatedAt: new Date().toISOString(),\n };\n state.set(key, entry);\n}\n\n/**\n * Cloudflare normalizes DNS names to FQDN ('app.example.com'). The user\n * may declare them either as an apex (`@`) or as a partial — match by\n * exact equality when both look fully-qualified, otherwise by suffix.\n */\nfunction normalizeName(cfName: string, configName: string): boolean {\n if (cfName === configName) return true;\n if (configName === \"@\") return true;\n return cfName.endsWith(`.${configName}`) || cfName.endsWith(configName);\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 {\n resolveWorkerConfig,\n resolveDeployedWorkerName,\n mergeWorkerConfigForResourcePick,\n} from \"../../core/config/resolver.js\";\nimport {\n generateWranglerConfig,\n writeWranglerJson,\n} from \"../../core/wrangler/generator.js\";\nimport { dispatchNamespaceApply } from \"../../features/dispatch-namespace/index.js\";\nimport { dnsRecordApply } from \"../../features/dns-records/index.js\";\nimport {\n getDispatchNamespaces,\n getDnsRecords,\n getLogpushJobs,\n} from \"../../types.js\";\nimport { logpushJobApply } from \"../../features/logpush-job/index.js\";\nimport { resolveStackOutputs } from \"../../core/outputs/stackOutputs.js\";\nimport {\n fetchStackImports,\n importedStackNames,\n} from \"../../core/imports/fetchStackImports.js\";\nimport { runSync } from \"./sync.js\";\nimport { resourceModules } from \"../../core/registry/registry.js\";\nimport { hashCloudflareSnapshot } from \"../../core/plan/planFile.js\";\nimport { buildCloudflareSnapshot } from \"../../core/plan/cloudflareSnapshot.js\";\nimport { verifyPlanFile } from \"../../core/plan/verifyPlanFile.js\";\nimport {\n printApplySummary,\n resetApplySummary,\n} from \"../../core/plan/planFormat.js\";\nimport type { StateEntry } from \"../../types.js\";\nimport {\n parseApplyTarget,\n assertApplyTargetDeclared,\n type ApplyTarget,\n} from \"../../core/apply/applyTarget.js\";\n\nexport async function runApply(options: {\n env?: string;\n addShard?: string;\n configPath?: string;\n /**\n * Path to a plan file from `tamer plan --out`. Apply recomputes the\n * `(config, state)` attestation hashes and refuses to proceed if either\n * differs (override with `allowStale`).\n */\n planFile?: string;\n allowStale?: boolean;\n /**\n * Track every state entry created during this apply. On any failure,\n * delete the matching Cloudflare resources (best-effort) so partial\n * applies do not leak orphans into the account.\n */\n rollbackOnFailure?: boolean;\n /**\n * `kind:logicalName` — create/update only that declared resource; still\n * regenerates all wrangler.json files and resolves full `outputs:`.\n */\n target?: string;\n}): Promise<void> {\n const env = options.env ?? \"local\";\n const addShard = options.addShard;\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 let target: ApplyTarget | undefined;\n if (options.target) {\n target = parseApplyTarget(options.target);\n if (options.planFile) {\n throw new Error(\n \"Cannot combine --plan with --target: plan files attest the full stack. Omit --target, or apply without --plan.\",\n );\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: \"apply\",\n expectedMode: \"forward\",\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 const referencedStacks = importedStackNames(config);\n if (referencedStacks.length > 0) {\n console.log(\n `Pre-fetching tamer:import outputs from stack(s): ${referencedStacks.join(\", \")}…`,\n );\n }\n const imports = await fetchStackImports(api, config, env);\n console.log(\"Applying…\");\n\n if (target) {\n if (addShard) {\n if (target.kind !== \"d1\") {\n throw new Error(\n \"--add-shard only applies to D1; drop --target or use --target d1:<logical>.\",\n );\n }\n if (addShard !== target.logical) {\n throw new Error(\n `--add-shard ${addShard} does not match --target d1:${target.logical}.`,\n );\n }\n }\n await assertApplyTargetDeclared(config, baseDir, target);\n }\n\n // Imports were pre-fetched above (before this block) so every subsequent\n // `${tamer:import:<stack>.<output>}` resolution is a pure map lookup.\n\n const opDetail: string[] = [];\n if (addShard) opDetail.push(`add-shard ${addShard}`);\n if (target) opDetail.push(`target=${target.kind}:${target.logical}`);\n state.beginOperation(\n \"apply\",\n opDetail.length ? opDetail.join(\"; \") : undefined,\n );\n\n if (target) {\n console.log(\n `Scoped apply: only ${target.kind}:${target.logical} (wrangler outputs still generated for every worker)`,\n );\n }\n\n const baselineKeys = options.rollbackOnFailure\n ? new Set(Object.keys(state.getAll()))\n : null;\n\n // Reset the per-action counter so the summary at the end of this run\n // reflects only what *this* `runApply` did (matters for tests and for\n // back-to-back apply invocations from a single process).\n resetApplySummary();\n\n try {\n const dispatchResources =\n !target\n ? getDispatchNamespaces(config)\n : target.kind === \"dispatch_namespace\"\n ? getDispatchNamespaces(config).filter(\n (n) => n.logicalName === target!.logical,\n )\n : [];\n\n await dispatchNamespaceApply(\n dispatchResources,\n config.tenant,\n env,\n api,\n state,\n );\n\n const dnsResources =\n !target\n ? getDnsRecords(config)\n : target.kind === \"dns_record\"\n ? getDnsRecords(config).filter(\n (d) => d.logicalName === target!.logical,\n )\n : [];\n\n await dnsRecordApply(\n dnsResources,\n config.tenant,\n env,\n api,\n state,\n );\n\n const workers = await getWorkers(config, baseDir);\n for (const [workerKey, workerConfig] of workers) {\n const deployedName = resolveDeployedWorkerName(\n config,\n workerKey,\n workerConfig,\n env,\n naming,\n );\n const mergedWorker = mergeWorkerConfigForResourcePick(\n config,\n workerKey,\n workerConfig,\n env,\n accountId,\n naming,\n state,\n { imports },\n );\n for (const mod of resourceModules) {\n if (target) {\n if (target.kind === \"logpush_job\") {\n if (mod.kind !== \"r2\") continue;\n } else if (mod.kind !== target.kind) {\n continue;\n }\n }\n const picked = mod.pickResources(mergedWorker);\n const resources =\n target && mod.kind === target.kind\n ? picked.filter(\n (r) =>\n (r as { logicalName?: string }).logicalName ===\n target.logical,\n )\n : picked;\n if (resources.length === 0) continue;\n await mod.apply({\n resources,\n tenant: config.tenant,\n env,\n api,\n state,\n naming,\n config,\n baseDir,\n addShard,\n worker: { workerKey, deployedName },\n });\n }\n }\n\n const logpushResources = !target\n ? getLogpushJobs(config)\n : target.kind === \"logpush_job\"\n ? getLogpushJobs(config).filter(\n (j) => j.logicalName === target.logical,\n )\n : [];\n\n await logpushJobApply(\n logpushResources,\n config.tenant,\n env,\n accountId,\n api,\n state,\n );\n\n await state.persist(api);\n\n for (const [workerKey, workerConfig] of workers) {\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(\n resolved.workerDir,\n wranglerConfig,\n resolved.wranglerOutFile,\n );\n console.log(`Generated ${resolved.wranglerOutFile} for ${workerKey}`);\n }\n\n // Resolve + persist `outputs:` last — every dependency is already in\n // state by this point, so a strict resolve here surfaces typos in\n // `outputs` as a fail-the-apply error instead of a silent half-write.\n // `replaceStackOutputs` is a no-op when nothing changed, so reruns\n // don't bump `revision` unnecessarily.\n const resolvedOutputs = resolveStackOutputs(config, {\n env,\n state,\n naming,\n imports,\n accountId,\n });\n state.replaceStackOutputs(resolvedOutputs);\n if (Object.keys(resolvedOutputs).length > 0) {\n console.log(\n `Stack outputs: resolved ${Object.keys(resolvedOutputs).length} (${Object.keys(resolvedOutputs).join(\", \")})`,\n );\n } else if (config.outputs == null) {\n // Nothing declared, nothing to print — quiet path.\n } else {\n // `outputs: {}` (empty record) — config explicitly cleared.\n console.log(\"Stack outputs: cleared (empty `outputs` block in config)\");\n }\n\n state.finishOperation();\n await state.persist(api);\n console.log(`Apply complete for env: ${env}`);\n printApplySummary();\n } catch (err) {\n if (baselineKeys) {\n await rollbackCreatedResources({\n api,\n state,\n baselineKeys,\n cause: err,\n });\n }\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\n/**\n * Best-effort undo for a partially failed apply. Walks every state entry\n * created during this run (i.e. not present at apply start) in reverse\n * insertion order and asks the owning module to delete it. Failures are\n * logged and swallowed — rollback never throws so the original error from\n * apply propagates intact.\n */\nasync function rollbackCreatedResources(args: {\n api: CFApiClient;\n state: StateManager;\n baselineKeys: Set<string>;\n cause: unknown;\n}): Promise<void> {\n const { api, state, baselineKeys, cause } = args;\n const all = state.getAll();\n const newKeys = Object.keys(all).filter((k) => !baselineKeys.has(k));\n if (newKeys.length === 0) {\n console.warn(\n `Apply failed; --rollback-on-failure had nothing to undo (no new state entries).`,\n );\n return;\n }\n const causeMsg = cause instanceof Error ? cause.message : String(cause);\n console.warn(\n `Apply failed (${causeMsg}); rolling back ${newKeys.length} new resource(s)...`,\n );\n const moduleByEntryType = new Map<\n StateEntry[\"type\"],\n (typeof resourceModules)[number]\n >(resourceModules.map((m) => [m.stateEntryType, m]));\n for (const key of newKeys.reverse()) {\n const entry = all[key];\n if (!entry) continue;\n if (entry.type === \"logpush_job\") {\n try {\n await api.logpushAccountJobDelete(entry.cfJobId);\n state.delete(key);\n } catch (err) {\n console.warn(\n `Rollback: failed to delete Logpush job ${entry.cfJobId}:`,\n err,\n );\n }\n continue;\n }\n const mod = moduleByEntryType.get(entry.type);\n if (!mod) {\n console.warn(\n `Rollback: no module owns state type \"${entry.type}\" (key \"${key}\"); leaving in place.`,\n );\n continue;\n }\n await mod.destroyOne({ api, state, key, entry });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as getDispatchNamespaces, m as getLogpushJobs, p as getDnsRecords } from "./normalize-
|
|
2
|
-
import { a as resourceModules,
|
|
1
|
+
import { f as getDispatchNamespaces, m as getLogpushJobs, p as getDnsRecords } from "./normalize-DVSTRZhO.mjs";
|
|
2
|
+
import { a as resourceModules, s as logicalNamesForResourceKind } from "./fetchStackImports-ClUYZy_U.mjs";
|
|
3
3
|
import { a as effectiveDnsRecordProxied, i as effectiveDnsRecordComment, o as effectiveDnsRecordTtl, r as dnsRecordStateKey, t as dnsRecordAppliesToEnv } from "./dns-records.resolve-DwBR_1WI.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/features/dns-records/dns-records.diff.ts
|
|
@@ -149,4 +149,4 @@ function filterPlanItemsForTarget(items, target) {
|
|
|
149
149
|
|
|
150
150
|
//#endregion
|
|
151
151
|
export { dnsRecordDiffPlanItems as a, computeDnsRecordMutableChanges as i, filterPlanItemsForTarget as n, parseApplyTarget as r, assertApplyTargetDeclared as t };
|
|
152
|
-
//# sourceMappingURL=applyTarget-
|
|
152
|
+
//# sourceMappingURL=applyTarget-D15T_q7G.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyTarget-BetDYdeS.mjs","names":["items: PlanItem[]","changes: PlanFieldChange[]","APPLY_TARGET_KINDS: ReadonlySet<string>"],"sources":["../src/features/dns-records/dns-records.diff.ts","../src/core/apply/applyTarget.ts"],"sourcesContent":["/**\n * Plan-time field-level diff for declared DNS records. Pure: takes the\n * already-recorded {@link DnsRecordStateEntry} and the {@link\n * DnsRecordResourceConfig} the user wrote, and returns the\n * `update` / `replace` items `tamer plan` should emit.\n *\n * Mirrors the patch + delete-and-recreate decision tree in\n * {@link dnsRecordApply}:\n * - `type` change → `replace` (Cloudflare's API rejects PATCH on type per\n * https://developers.cloudflare.com/fundamentals/api/reference/deprecations/).\n * - any of `content` / `ttl` / `proxied` / `priority` / `comment` differ →\n * `update` (in-place PATCH).\n *\n * Records that don't yet have a state row are reported by `dnsRecordDrift`\n * as `undeployed` instead — those become `create` items. Records that\n * `apply` would skip (env-skipped, missing zone) are excluded here.\n */\n\nimport type {\n DnsRecordResourceConfig,\n DnsRecordStateEntry,\n TenantMeta,\n} from \"../../types.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { PlanFieldChange, PlanItem } from \"../../core/plan/plan.types.js\";\nimport {\n dnsRecordAppliesToEnv,\n dnsRecordStateKey,\n effectiveDnsRecordComment,\n effectiveDnsRecordProxied,\n effectiveDnsRecordTtl,\n} from \"./dns-records.resolve.js\";\n\nexport function dnsRecordDiffPlanItems(args: {\n resources: DnsRecordResourceConfig[];\n tenant: TenantMeta;\n env: string;\n state: StateManager;\n}): PlanItem[] {\n const { resources, tenant, env, state } = args;\n const items: PlanItem[] = [];\n\n for (const config of resources) {\n if (!dnsRecordAppliesToEnv(config, env)) continue;\n const key = dnsRecordStateKey(config.zoneId, config.type, config.name);\n const entry = state.get(key);\n if (!entry || entry.type !== \"dns_record\") continue;\n\n const stateEntry = entry as DnsRecordStateEntry;\n if (stateEntry.recordType !== config.type) {\n items.push({\n kind: \"dns_record\",\n action: \"replace\",\n logicalName: config.logicalName,\n derivedName: `${config.type} ${config.name}`,\n detail: `type ${stateEntry.recordType} -> ${config.type} (delete + recreate)`,\n changes: [\n {\n field: \"type\",\n from: stateEntry.recordType,\n to: config.type,\n kind: \"immutable\",\n },\n ],\n });\n continue;\n }\n\n const changes = computeMutableChanges(stateEntry, config, tenant, env);\n if (changes.length === 0) continue;\n items.push({\n kind: \"dns_record\",\n action: \"update\",\n logicalName: config.logicalName,\n derivedName: `${config.type} ${config.name}`,\n detail: changes\n .map((c) => `${c.field}: ${formatVal(c.from)} -> ${formatVal(c.to)}`)\n .join(\", \"),\n changes,\n });\n }\n\n return items;\n}\n\n/**\n * Pure comparison shared with `dnsRecordApply` so plan and apply agree\n * on what counts as drift on the mutable record fields. Excludes the\n * `type` change — that's an immutable replace handled separately.\n */\nexport function computeDnsRecordMutableChanges(\n state: DnsRecordStateEntry,\n config: DnsRecordResourceConfig,\n tenant: TenantMeta,\n env: string,\n): PlanFieldChange[] {\n return computeMutableChanges(state, config, tenant, env);\n}\n\nfunction computeMutableChanges(\n state: DnsRecordStateEntry,\n config: DnsRecordResourceConfig,\n tenant: TenantMeta,\n env: string,\n): PlanFieldChange[] {\n const expectedTtl = effectiveDnsRecordTtl(config);\n const expectedProxied = effectiveDnsRecordProxied(config);\n const expectedComment = effectiveDnsRecordComment(\n config,\n tenant,\n env,\n );\n\n const changes: PlanFieldChange[] = [];\n if (state.content !== config.content) {\n changes.push({\n field: \"content\",\n from: state.content,\n to: config.content,\n kind: \"mutable\",\n });\n }\n if (state.ttl !== expectedTtl) {\n changes.push({\n field: \"ttl\",\n from: state.ttl,\n to: expectedTtl,\n kind: \"mutable\",\n });\n }\n if (state.proxied !== expectedProxied) {\n changes.push({\n field: \"proxied\",\n from: state.proxied,\n to: expectedProxied,\n kind: \"mutable\",\n });\n }\n if (\n config.priority !== undefined &&\n state.priority !== config.priority\n ) {\n changes.push({\n field: \"priority\",\n from: state.priority,\n to: config.priority,\n kind: \"mutable\",\n });\n }\n if (state.comment !== expectedComment) {\n changes.push({\n field: \"comment\",\n from: state.comment,\n to: expectedComment,\n kind: \"mutable\",\n });\n }\n return changes;\n}\n\nfunction formatVal(v: unknown): string {\n if (v === undefined) return \"(unset)\";\n if (typeof v === \"string\") return v.length > 32 ? `${v.slice(0, 29)}...` : v;\n return String(v);\n}\n","import type { CfiConfig } from \"../../types.js\";\nimport {\n getDispatchNamespaces,\n getDnsRecords,\n getLogpushJobs,\n} from \"../../types.js\";\nimport { logicalNamesForResourceKind } from \"../config/resourcesFromConfig.js\";\nimport type { ResourceKind } from \"../registry/registry.js\";\nimport { resourceModules } from \"../registry/registry.js\";\nimport type { PlanItem } from \"../plan/plan.types.js\";\n\nconst APPLY_TARGET_KINDS: ReadonlySet<string> = new Set([\n ...resourceModules.map((m) => m.kind),\n \"dispatch_namespace\",\n \"dns_record\",\n \"logpush_job\",\n]);\n\nexport type ApplyTargetKind =\n | ResourceKind\n | \"dispatch_namespace\"\n | \"dns_record\"\n | \"logpush_job\";\n\nexport interface ApplyTarget {\n kind: ApplyTargetKind;\n logical: string;\n}\n\n/**\n * Parse `tamer apply --target` / `tamer plan --target` (`d1:settings`,\n * `dispatch_namespace:workspace`, …). Not valid for `worker_route` /\n * `worker_script` (routes deploy with `tamer deploy`; scripts with wrangler).\n */\nexport function parseApplyTarget(raw: string): ApplyTarget {\n const idx = raw.indexOf(\":\");\n if (idx < 1 || idx === raw.length - 1) {\n throw new Error(\n `Invalid --target \"${raw}\": expected <kind>:<logicalName> (e.g. d1:settings, dns_record:apex_txt)`,\n );\n }\n const kind = raw.slice(0, idx);\n const logical = raw.slice(idx + 1);\n if (!logical.trim()) {\n throw new Error(\n `Invalid --target \"${raw}\": missing logical name after \":\"`,\n );\n }\n if (kind === \"worker_route\" || kind === \"worker_script\") {\n throw new Error(\n `--target ${kind}:… is not supported here (worker routes are applied on \\`tamer deploy\\`; scripts via wrangler). Omit --target or pass a resource kind.`,\n );\n }\n if (!APPLY_TARGET_KINDS.has(kind)) {\n const list = [...APPLY_TARGET_KINDS].sort().join(\", \");\n throw new Error(\n `Unknown resource kind in --target: \"${kind}\". Expected one of: ${list}`,\n );\n }\n return { kind: kind as ApplyTargetKind, logical };\n}\n\nexport async function assertApplyTargetDeclared(\n config: CfiConfig,\n baseDir: string,\n target: ApplyTarget,\n): Promise<void> {\n if (target.kind === \"dispatch_namespace\") {\n const names = getDispatchNamespaces(config).map((n) => n.logicalName);\n if (!names.includes(target.logical)) {\n throw new Error(\n `No dispatch_namespace \"${target.logical}\" in the Tamer project config. Declared: ${names.length ? names.join(\", \") : \"(none)\"}`,\n );\n }\n return;\n }\n if (target.kind === \"dns_record\") {\n const names = getDnsRecords(config).map((d) => d.logicalName);\n if (!names.includes(target.logical)) {\n throw new Error(\n `No dns_record \"${target.logical}\" in the Tamer project config. Declared: ${names.length ? names.join(\", \") : \"(none)\"}`,\n );\n }\n return;\n }\n if (target.kind === \"logpush_job\") {\n const names = getLogpushJobs(config).map((j) => j.logicalName);\n if (!names.includes(target.logical)) {\n throw new Error(\n `No logpush_job \"${target.logical}\" in the Tamer project config. Declared: ${names.length ? names.join(\", \") : \"(none)\"}`,\n );\n }\n return;\n }\n const set = await logicalNamesForResourceKind(config, baseDir, target.kind);\n if (!set.has(target.logical)) {\n const arr = [...set].sort();\n throw new Error(\n `No ${target.kind} resource \"${target.logical}\" in the Tamer project config for this stack. Declared ${target.kind}: ${arr.length ? arr.join(\", \") : \"(none)\"}`,\n );\n }\n}\n\nexport function filterPlanItemsForTarget(\n items: PlanItem[],\n target: ApplyTarget,\n): PlanItem[] {\n return items.filter(\n (it) => it.kind === target.kind && it.logicalName === target.logical,\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"applyTarget-D15T_q7G.mjs","names":["items: PlanItem[]","changes: PlanFieldChange[]","APPLY_TARGET_KINDS: ReadonlySet<string>"],"sources":["../src/features/dns-records/dns-records.diff.ts","../src/core/apply/applyTarget.ts"],"sourcesContent":["/**\n * Plan-time field-level diff for declared DNS records. Pure: takes the\n * already-recorded {@link DnsRecordStateEntry} and the {@link\n * DnsRecordResourceConfig} the user wrote, and returns the\n * `update` / `replace` items `tamer plan` should emit.\n *\n * Mirrors the patch + delete-and-recreate decision tree in\n * {@link dnsRecordApply}:\n * - `type` change → `replace` (Cloudflare's API rejects PATCH on type per\n * https://developers.cloudflare.com/fundamentals/api/reference/deprecations/).\n * - any of `content` / `ttl` / `proxied` / `priority` / `comment` differ →\n * `update` (in-place PATCH).\n *\n * Records that don't yet have a state row are reported by `dnsRecordDrift`\n * as `undeployed` instead — those become `create` items. Records that\n * `apply` would skip (env-skipped, missing zone) are excluded here.\n */\n\nimport type {\n DnsRecordResourceConfig,\n DnsRecordStateEntry,\n TenantMeta,\n} from \"../../types.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { PlanFieldChange, PlanItem } from \"../../core/plan/plan.types.js\";\nimport {\n dnsRecordAppliesToEnv,\n dnsRecordStateKey,\n effectiveDnsRecordComment,\n effectiveDnsRecordProxied,\n effectiveDnsRecordTtl,\n} from \"./dns-records.resolve.js\";\n\nexport function dnsRecordDiffPlanItems(args: {\n resources: DnsRecordResourceConfig[];\n tenant: TenantMeta;\n env: string;\n state: StateManager;\n}): PlanItem[] {\n const { resources, tenant, env, state } = args;\n const items: PlanItem[] = [];\n\n for (const config of resources) {\n if (!dnsRecordAppliesToEnv(config, env)) continue;\n const key = dnsRecordStateKey(config.zoneId, config.type, config.name);\n const entry = state.get(key);\n if (!entry || entry.type !== \"dns_record\") continue;\n\n const stateEntry = entry as DnsRecordStateEntry;\n if (stateEntry.recordType !== config.type) {\n items.push({\n kind: \"dns_record\",\n action: \"replace\",\n logicalName: config.logicalName,\n derivedName: `${config.type} ${config.name}`,\n detail: `type ${stateEntry.recordType} -> ${config.type} (delete + recreate)`,\n changes: [\n {\n field: \"type\",\n from: stateEntry.recordType,\n to: config.type,\n kind: \"immutable\",\n },\n ],\n });\n continue;\n }\n\n const changes = computeMutableChanges(stateEntry, config, tenant, env);\n if (changes.length === 0) continue;\n items.push({\n kind: \"dns_record\",\n action: \"update\",\n logicalName: config.logicalName,\n derivedName: `${config.type} ${config.name}`,\n detail: changes\n .map((c) => `${c.field}: ${formatVal(c.from)} -> ${formatVal(c.to)}`)\n .join(\", \"),\n changes,\n });\n }\n\n return items;\n}\n\n/**\n * Pure comparison shared with `dnsRecordApply` so plan and apply agree\n * on what counts as drift on the mutable record fields. Excludes the\n * `type` change — that's an immutable replace handled separately.\n */\nexport function computeDnsRecordMutableChanges(\n state: DnsRecordStateEntry,\n config: DnsRecordResourceConfig,\n tenant: TenantMeta,\n env: string,\n): PlanFieldChange[] {\n return computeMutableChanges(state, config, tenant, env);\n}\n\nfunction computeMutableChanges(\n state: DnsRecordStateEntry,\n config: DnsRecordResourceConfig,\n tenant: TenantMeta,\n env: string,\n): PlanFieldChange[] {\n const expectedTtl = effectiveDnsRecordTtl(config);\n const expectedProxied = effectiveDnsRecordProxied(config);\n const expectedComment = effectiveDnsRecordComment(\n config,\n tenant,\n env,\n );\n\n const changes: PlanFieldChange[] = [];\n if (state.content !== config.content) {\n changes.push({\n field: \"content\",\n from: state.content,\n to: config.content,\n kind: \"mutable\",\n });\n }\n if (state.ttl !== expectedTtl) {\n changes.push({\n field: \"ttl\",\n from: state.ttl,\n to: expectedTtl,\n kind: \"mutable\",\n });\n }\n if (state.proxied !== expectedProxied) {\n changes.push({\n field: \"proxied\",\n from: state.proxied,\n to: expectedProxied,\n kind: \"mutable\",\n });\n }\n if (\n config.priority !== undefined &&\n state.priority !== config.priority\n ) {\n changes.push({\n field: \"priority\",\n from: state.priority,\n to: config.priority,\n kind: \"mutable\",\n });\n }\n if (state.comment !== expectedComment) {\n changes.push({\n field: \"comment\",\n from: state.comment,\n to: expectedComment,\n kind: \"mutable\",\n });\n }\n return changes;\n}\n\nfunction formatVal(v: unknown): string {\n if (v === undefined) return \"(unset)\";\n if (typeof v === \"string\") return v.length > 32 ? `${v.slice(0, 29)}...` : v;\n return String(v);\n}\n","import type { CfiConfig } from \"../../types.js\";\nimport {\n getDispatchNamespaces,\n getDnsRecords,\n getLogpushJobs,\n} from \"../../types.js\";\nimport { logicalNamesForResourceKind } from \"../config/resourcesFromConfig.js\";\nimport type { ResourceKind } from \"../registry/registry.js\";\nimport { resourceModules } from \"../registry/registry.js\";\nimport type { PlanItem } from \"../plan/plan.types.js\";\n\nconst APPLY_TARGET_KINDS: ReadonlySet<string> = new Set([\n ...resourceModules.map((m) => m.kind),\n \"dispatch_namespace\",\n \"dns_record\",\n \"logpush_job\",\n]);\n\nexport type ApplyTargetKind =\n | ResourceKind\n | \"dispatch_namespace\"\n | \"dns_record\"\n | \"logpush_job\";\n\nexport interface ApplyTarget {\n kind: ApplyTargetKind;\n logical: string;\n}\n\n/**\n * Parse `tamer apply --target` / `tamer plan --target` (`d1:settings`,\n * `dispatch_namespace:workspace`, …). Not valid for `worker_route` /\n * `worker_script` (routes deploy with `tamer deploy`; scripts with wrangler).\n */\nexport function parseApplyTarget(raw: string): ApplyTarget {\n const idx = raw.indexOf(\":\");\n if (idx < 1 || idx === raw.length - 1) {\n throw new Error(\n `Invalid --target \"${raw}\": expected <kind>:<logicalName> (e.g. d1:settings, dns_record:apex_txt)`,\n );\n }\n const kind = raw.slice(0, idx);\n const logical = raw.slice(idx + 1);\n if (!logical.trim()) {\n throw new Error(\n `Invalid --target \"${raw}\": missing logical name after \":\"`,\n );\n }\n if (kind === \"worker_route\" || kind === \"worker_script\") {\n throw new Error(\n `--target ${kind}:… is not supported here (worker routes are applied on \\`tamer deploy\\`; scripts via wrangler). Omit --target or pass a resource kind.`,\n );\n }\n if (!APPLY_TARGET_KINDS.has(kind)) {\n const list = [...APPLY_TARGET_KINDS].sort().join(\", \");\n throw new Error(\n `Unknown resource kind in --target: \"${kind}\". Expected one of: ${list}`,\n );\n }\n return { kind: kind as ApplyTargetKind, logical };\n}\n\nexport async function assertApplyTargetDeclared(\n config: CfiConfig,\n baseDir: string,\n target: ApplyTarget,\n): Promise<void> {\n if (target.kind === \"dispatch_namespace\") {\n const names = getDispatchNamespaces(config).map((n) => n.logicalName);\n if (!names.includes(target.logical)) {\n throw new Error(\n `No dispatch_namespace \"${target.logical}\" in the Tamer project config. Declared: ${names.length ? names.join(\", \") : \"(none)\"}`,\n );\n }\n return;\n }\n if (target.kind === \"dns_record\") {\n const names = getDnsRecords(config).map((d) => d.logicalName);\n if (!names.includes(target.logical)) {\n throw new Error(\n `No dns_record \"${target.logical}\" in the Tamer project config. Declared: ${names.length ? names.join(\", \") : \"(none)\"}`,\n );\n }\n return;\n }\n if (target.kind === \"logpush_job\") {\n const names = getLogpushJobs(config).map((j) => j.logicalName);\n if (!names.includes(target.logical)) {\n throw new Error(\n `No logpush_job \"${target.logical}\" in the Tamer project config. Declared: ${names.length ? names.join(\", \") : \"(none)\"}`,\n );\n }\n return;\n }\n const set = await logicalNamesForResourceKind(config, baseDir, target.kind);\n if (!set.has(target.logical)) {\n const arr = [...set].sort();\n throw new Error(\n `No ${target.kind} resource \"${target.logical}\" in the Tamer project config for this stack. Declared ${target.kind}: ${arr.length ? arr.join(\", \") : \"(none)\"}`,\n );\n }\n}\n\nexport function filterPlanItemsForTarget(\n items: PlanItem[],\n target: ApplyTarget,\n): PlanItem[] {\n return items.filter(\n (it) => it.kind === target.kind && it.logicalName === target.logical,\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { n as loadConfig } from "./loader-
|
|
1
|
+
import { n as loadConfig } from "./loader-DnT9iqz9.mjs";
|
|
2
2
|
import { n as cloudflareAccountIdFromEnv, t as CFApiClient } from "./CFApiClient-DhbyyV71.mjs";
|
|
3
|
-
import { d as tamerStateDatabaseName, f as stackNameForConfig, t as StateManager, u as ensureTamerStateDatabase } from "./StateManager-
|
|
3
|
+
import { d as tamerStateDatabaseName, f as stackNameForConfig, t as StateManager, u as ensureTamerStateDatabase } from "./StateManager-JLBtz9V-.mjs";
|
|
4
4
|
import "./r2S3EmptyBucket-DD81ZWQ7.mjs";
|
|
5
5
|
import { n as ensureTamerArtifactsBucket } from "./tamerArtifactsR2-Ccgplu2Q.mjs";
|
|
6
6
|
|
|
@@ -30,4 +30,4 @@ async function runBootstrap(options) {
|
|
|
30
30
|
|
|
31
31
|
//#endregion
|
|
32
32
|
export { runBootstrap };
|
|
33
|
-
//# sourceMappingURL=bootstrap-
|
|
33
|
+
//# sourceMappingURL=bootstrap-BicPW44a.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap-
|
|
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,10 +1,10 @@
|
|
|
1
|
-
import { f as getDispatchNamespaces, m as getLogpushJobs, p as getDnsRecords } from "./normalize-
|
|
2
|
-
import { t as getWorkers } from "./loader-
|
|
1
|
+
import { f as getDispatchNamespaces, m as getLogpushJobs, p as getDnsRecords } from "./normalize-DVSTRZhO.mjs";
|
|
2
|
+
import { t as getWorkers } from "./loader-DnT9iqz9.mjs";
|
|
3
3
|
import { n as cloudflareAccountIdFromEnv } from "./CFApiClient-DhbyyV71.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { f as stackNameForConfig, t as StateManager } from "./StateManager-
|
|
6
|
-
import { n as dispatchNamespaceSync, t as dnsRecordSync } from "./dns-records.sync-
|
|
7
|
-
import { i as logpushJobSync } from "./logpush-job-
|
|
4
|
+
import { a as resourceModules, d as mergeWorkerConfigForResourcePick, t as fetchStackImports, v as namingFromConfig } from "./fetchStackImports-ClUYZy_U.mjs";
|
|
5
|
+
import { f as stackNameForConfig, t as StateManager } from "./StateManager-JLBtz9V-.mjs";
|
|
6
|
+
import { n as dispatchNamespaceSync, t as dnsRecordSync } from "./dns-records.sync-CfI1mqXv.mjs";
|
|
7
|
+
import { i as logpushJobSync } from "./logpush-job-DsRkOORJ.mjs";
|
|
8
8
|
import { readFileSync, writeFileSync } from "fs";
|
|
9
9
|
import { createHash } from "crypto";
|
|
10
10
|
|
|
@@ -160,4 +160,4 @@ function stripVolatile(entry) {
|
|
|
160
160
|
|
|
161
161
|
//#endregion
|
|
162
162
|
export { readPlanFile as a, hashCloudflareSnapshot as i, PLAN_FILE_FORMAT as n, writePlanFile as o, computeAttestation as r, buildCloudflareSnapshot as t };
|
|
163
|
-
//# sourceMappingURL=cloudflareSnapshot-
|
|
163
|
+
//# sourceMappingURL=cloudflareSnapshot-GBUHeg2m.mjs.map
|