@dragonmastery/tamer 0.31.5 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +2 -0
  2. package/dist/{apply-C_70Hgcf.mjs → apply-BsVQ9cbK.mjs} +25 -11
  3. package/dist/apply-BsVQ9cbK.mjs.map +1 -0
  4. package/dist/{applyTarget-Ce_mtRQX.mjs → applyTarget-BJlVrED9.mjs} +3 -3
  5. package/dist/{applyTarget-Ce_mtRQX.mjs.map → applyTarget-BJlVrED9.mjs.map} +1 -1
  6. package/dist/{bootstrap-CQS5s33A.mjs → bootstrap-CV6OT-c9.mjs} +2 -2
  7. package/dist/{bootstrap-CQS5s33A.mjs.map → bootstrap-CV6OT-c9.mjs.map} +1 -1
  8. package/dist/{buildDispatchUploadForm-CVnPmHg4.mjs → buildDispatchUploadForm-BNDcS5_9.mjs} +1 -1
  9. package/dist/{buildDispatchUploadForm-CVnPmHg4.mjs.map → buildDispatchUploadForm-BNDcS5_9.mjs.map} +1 -1
  10. package/dist/{cloudflareSnapshot-CFErW72O.mjs → cloudflareSnapshot-CMbPQIsN.mjs} +4 -4
  11. package/dist/{cloudflareSnapshot-CFErW72O.mjs.map → cloudflareSnapshot-CMbPQIsN.mjs.map} +1 -1
  12. package/dist/{deploy-D-GXzsWR.mjs → deploy-BP65Wvm1.mjs} +18 -7
  13. package/dist/deploy-BP65Wvm1.mjs.map +1 -0
  14. package/dist/{destroy-DJRw_qLX.mjs → destroy-DPSuQg9v.mjs} +9 -9
  15. package/dist/{destroy-DJRw_qLX.mjs.map → destroy-DPSuQg9v.mjs.map} +1 -1
  16. package/dist/{destroy-tenant-DFHfNImL.mjs → destroy-tenant-hyEb1gEz.mjs} +1 -1
  17. package/dist/{destroy-tenant-DFHfNImL.mjs.map → destroy-tenant-hyEb1gEz.mjs.map} +1 -1
  18. package/dist/{dev-caJxohHI.mjs → dev-Bug5l5OZ.mjs} +6 -6
  19. package/dist/{dev-caJxohHI.mjs.map → dev-Bug5l5OZ.mjs.map} +1 -1
  20. package/dist/{dns-records.resolve-8a_eHfVI.mjs → dns-records.resolve-BBTlY3T5.mjs} +1 -1
  21. package/dist/{dns-records.resolve-BB2agPAb.mjs → dns-records.resolve-DV6XBZf3.mjs} +1 -1
  22. package/dist/{dns-records.resolve-BB2agPAb.mjs.map → dns-records.resolve-DV6XBZf3.mjs.map} +1 -1
  23. package/dist/{dns-records.sync-Ck0Q2OK3.mjs → dns-records.sync-FyzKl-Ph.mjs} +2 -2
  24. package/dist/{dns-records.sync-Ck0Q2OK3.mjs.map → dns-records.sync-FyzKl-Ph.mjs.map} +1 -1
  25. package/dist/{doctor-32YLAXXl.mjs → doctor-BwuEPYM6.mjs} +1 -1
  26. package/dist/{doctor-32YLAXXl.mjs.map → doctor-BwuEPYM6.mjs.map} +1 -1
  27. package/dist/{drift-C-qnJ-mH.mjs → drift-Bp-P13-B.mjs} +6 -6
  28. package/dist/{drift-C-qnJ-mH.mjs.map → drift-Bp-P13-B.mjs.map} +1 -1
  29. package/dist/drift-RM0vq3uF.mjs +8 -0
  30. package/dist/emit-DTpaIMkn.mjs +141 -0
  31. package/dist/emit-DTpaIMkn.mjs.map +1 -0
  32. package/dist/{events-Bor7XgLC.mjs → events-B7Lencm8.mjs} +1 -1
  33. package/dist/{events-Bor7XgLC.mjs.map → events-B7Lencm8.mjs.map} +1 -1
  34. package/dist/{generator-gvCy7ouY.mjs → generator-ZTEeHlft.mjs} +2 -2
  35. package/dist/{generator-gvCy7ouY.mjs.map → generator-ZTEeHlft.mjs.map} +1 -1
  36. package/dist/{import-Vn9lhWic.mjs → import-Ciq9MN3v.mjs} +4 -4
  37. package/dist/{import-Vn9lhWic.mjs.map → import-Ciq9MN3v.mjs.map} +1 -1
  38. package/dist/index.d.mts +121 -21
  39. package/dist/index.d.mts.map +1 -1
  40. package/dist/{logpush-job-DJPlpnRu.mjs → logpush-job-GqVKG_HI.mjs} +1 -1
  41. package/dist/{logpush-job-DJPlpnRu.mjs.map → logpush-job-GqVKG_HI.mjs.map} +1 -1
  42. package/dist/{migrate-skvsDG6d.mjs → migrate-ODEnh6Tv.mjs} +4 -4
  43. package/dist/{migrate-skvsDG6d.mjs.map → migrate-ODEnh6Tv.mjs.map} +1 -1
  44. package/dist/normalize-DVSTRZhO.mjs.map +1 -1
  45. package/dist/{plan-BLy8FaE2.mjs → plan-BuG21Atq.mjs} +9 -9
  46. package/dist/{plan-BLy8FaE2.mjs.map → plan-BuG21Atq.mjs.map} +1 -1
  47. package/dist/{provision-tenant-CleOYFwr.mjs → provision-tenant-BHDWTC2U.mjs} +3 -3
  48. package/dist/{provision-tenant-CleOYFwr.mjs.map → provision-tenant-BHDWTC2U.mjs.map} +1 -1
  49. package/dist/{registry-EWWdkLf7.mjs → registry-BlHEOKlN.mjs} +75 -28
  50. package/dist/registry-BlHEOKlN.mjs.map +1 -0
  51. package/dist/{stackOutputs-BLvUMsQO.mjs → stackOutputs-CkpNSng8.mjs} +1 -1
  52. package/dist/{stackOutputs-BLvUMsQO.mjs.map → stackOutputs-CkpNSng8.mjs.map} +1 -1
  53. package/dist/{status-BxStsax8.mjs → status-PlMHsDzT.mjs} +5 -5
  54. package/dist/{status-BxStsax8.mjs.map → status-PlMHsDzT.mjs.map} +1 -1
  55. package/dist/{sync-KTzMVc_o.mjs → sync-YKZ5HD8v.mjs} +5 -5
  56. package/dist/{sync-KTzMVc_o.mjs.map → sync-YKZ5HD8v.mjs.map} +1 -1
  57. package/dist/tamer.mjs +35 -19
  58. package/dist/tamer.mjs.map +1 -1
  59. package/dist/{tamerArtifactsR2-DnUJmxnO.mjs → tamerArtifactsR2-Ba29OVp9.mjs} +1 -1
  60. package/dist/{tamerArtifactsR2-DnUJmxnO.mjs.map → tamerArtifactsR2-Ba29OVp9.mjs.map} +1 -1
  61. package/dist/{types-D7qKnGsm.mjs → types-DuK39eYA.mjs} +4 -4
  62. package/dist/{types-D7qKnGsm.mjs.map → types-DuK39eYA.mjs.map} +1 -1
  63. package/dist/{verifyPlanFile-CR2bELdE.mjs → verifyPlanFile-BBAwWzUo.mjs} +2 -2
  64. package/dist/{verifyPlanFile-CR2bELdE.mjs.map → verifyPlanFile-BBAwWzUo.mjs.map} +1 -1
  65. package/dist/{wfp-delete-CDBFqmrM.mjs → wfp-delete-CQc9tveU.mjs} +1 -1
  66. package/dist/{wfp-delete-CDBFqmrM.mjs.map → wfp-delete-CQc9tveU.mjs.map} +1 -1
  67. package/dist/{wfp-put-BrwICc9i.mjs → wfp-put-CVw8cloM.mjs} +2 -2
  68. package/dist/{wfp-put-BrwICc9i.mjs.map → wfp-put-CVw8cloM.mjs.map} +1 -1
  69. package/dist/{worker-route-tOqVbhv3.mjs → worker-route-CqBDvjgo.mjs} +2 -2
  70. package/dist/{worker-route-tOqVbhv3.mjs.map → worker-route-CqBDvjgo.mjs.map} +1 -1
  71. package/dist/{workers-6r2ONF9J.mjs → workers-DAv1ze8_.mjs} +2 -2
  72. package/dist/{workers-6r2ONF9J.mjs.map → workers-DAv1ze8_.mjs.map} +1 -1
  73. package/dist/{wranglerSpawn-CUlo2qOJ.mjs → wranglerSpawn-B3TKjpt2.mjs} +1 -1
  74. package/dist/{wranglerSpawn-CUlo2qOJ.mjs.map → wranglerSpawn-B3TKjpt2.mjs.map} +1 -1
  75. package/dist/{zoneResolver-DNNNmO_w.mjs → zoneResolver-D9bz6-0l.mjs} +1 -1
  76. package/dist/{zoneResolver-DNNNmO_w.mjs.map → zoneResolver-D9bz6-0l.mjs.map} +1 -1
  77. package/package.json +1 -1
  78. package/dist/apply-C_70Hgcf.mjs.map +0 -1
  79. package/dist/deploy-D-GXzsWR.mjs.map +0 -1
  80. package/dist/drift-5_LwAdZo.mjs +0 -8
  81. package/dist/registry-EWWdkLf7.mjs.map +0 -1
@@ -49,4 +49,4 @@ async function destroyTamerArtifactsBucket(api, env) {
49
49
 
50
50
  //#endregion
51
51
  export { ensureTamerArtifactsBucket as n, tamerArtifactsBucketName as r, destroyTamerArtifactsBucket as t };
52
- //# sourceMappingURL=tamerArtifactsR2-DnUJmxnO.mjs.map
52
+ //# sourceMappingURL=tamerArtifactsR2-Ba29OVp9.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"tamerArtifactsR2-DnUJmxnO.mjs","names":[],"sources":["../src/core/state/tamerArtifactsR2.ts"],"sourcesContent":["import type { CFApiClient } from \"../api/CFApiClient.js\";\nimport {\n emptyR2BucketViaS3,\n r2S3CredentialsFromEnv,\n} from \"../../features/r2/r2S3EmptyBucket.js\";\n\n/**\n * Per-env R2 bucket that holds Tamer-managed artifacts (built bundles, keyed\n * `{resource-type}/{name}/{version}/...`). Owned by Tamer itself, not by any\n * worker in `tamer.config.ts`. Created on `tamer bootstrap` and removed on\n * `tamer destroy --wipe-metadata`.\n *\n * Naming intentionally mirrors `tamer-state-{env}` (see `tamerStateDb.ts`).\n */\nexport function tamerArtifactsBucketName(env: string): string {\n return `tamer-artifacts-${env}`;\n}\n\nexport async function findTamerArtifactsBucket(\n api: CFApiClient,\n env: string,\n): Promise<{ name: string; creation_date: string } | undefined> {\n const name = tamerArtifactsBucketName(env);\n const all = await api.r2ListAll();\n return all.find((b) => b.name === name);\n}\n\n/** Create the bucket if missing. Idempotent — re-runs are safe. */\nexport async function ensureTamerArtifactsBucket(\n api: CFApiClient,\n env: string,\n): Promise<string> {\n const existing = await findTamerArtifactsBucket(api, env);\n const name = tamerArtifactsBucketName(env);\n if (existing) return name;\n await api.r2Create(name);\n return name;\n}\n\n/**\n * Best-effort delete. Returns true if the bucket existed and was removed,\n * false if it was already gone. Cloudflare refuses to delete non-empty\n * buckets; in that case the error is propagated so the operator can decide.\n */\nexport async function destroyTamerArtifactsBucket(\n api: CFApiClient,\n env: string,\n): Promise<boolean> {\n const existing = await findTamerArtifactsBucket(api, env);\n if (!existing) return false;\n const name = existing.name;\n const accountId = api.getAccountId();\n const s3creds = r2S3CredentialsFromEnv();\n if (s3creds) {\n try {\n console.log(\n `R2: emptying Tamer artifacts bucket \"${name}\" via S3 API (incomplete multipart uploads, then objects)…`,\n );\n const { uploadsAborted, objectsDeleted } = await emptyR2BucketViaS3(\n accountId,\n name,\n s3creds,\n );\n console.log(\n `R2: bucket \"${name}\" — aborted ${uploadsAborted} multipart upload(s), deleted ${objectsDeleted} object(s).`,\n );\n } catch (e) {\n console.warn(\n `R2: S3 empty failed for \"${name}\":`,\n e instanceof Error ? e.message : e,\n );\n }\n } else {\n console.warn(\n `R2: R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY not set — skipping S3 empty for \"${name}\"; bucket delete may fail if the bucket is not empty.`,\n );\n }\n await api.r2Delete(name);\n return true;\n}\n"],"mappings":";;;;;;;;;;;AAcA,SAAgB,yBAAyB,KAAqB;AAC5D,QAAO,mBAAmB;;AAG5B,eAAsB,yBACpB,KACA,KAC8D;CAC9D,MAAM,OAAO,yBAAyB,IAAI;AAE1C,SADY,MAAM,IAAI,WAAW,EACtB,MAAM,MAAM,EAAE,SAAS,KAAK;;;AAIzC,eAAsB,2BACpB,KACA,KACiB;CACjB,MAAM,WAAW,MAAM,yBAAyB,KAAK,IAAI;CACzD,MAAM,OAAO,yBAAyB,IAAI;AAC1C,KAAI,SAAU,QAAO;AACrB,OAAM,IAAI,SAAS,KAAK;AACxB,QAAO;;;;;;;AAQT,eAAsB,4BACpB,KACA,KACkB;CAClB,MAAM,WAAW,MAAM,yBAAyB,KAAK,IAAI;AACzD,KAAI,CAAC,SAAU,QAAO;CACtB,MAAM,OAAO,SAAS;CACtB,MAAM,YAAY,IAAI,cAAc;CACpC,MAAM,UAAU,wBAAwB;AACxC,KAAI,QACF,KAAI;AACF,UAAQ,IACN,wCAAwC,KAAK,4DAC9C;EACD,MAAM,EAAE,gBAAgB,mBAAmB,MAAM,mBAC/C,WACA,MACA,QACD;AACD,UAAQ,IACN,eAAe,KAAK,cAAc,eAAe,gCAAgC,eAAe,aACjG;UACM,GAAG;AACV,UAAQ,KACN,4BAA4B,KAAK,KACjC,aAAa,QAAQ,EAAE,UAAU,EAClC;;KAGH,SAAQ,KACN,kFAAkF,KAAK,uDACxF;AAEH,OAAM,IAAI,SAAS,KAAK;AACxB,QAAO"}
1
+ {"version":3,"file":"tamerArtifactsR2-Ba29OVp9.mjs","names":[],"sources":["../src/core/state/tamerArtifactsR2.ts"],"sourcesContent":["import type { CFApiClient } from \"../api/CFApiClient.js\";\nimport {\n emptyR2BucketViaS3,\n r2S3CredentialsFromEnv,\n} from \"../../features/r2/r2S3EmptyBucket.js\";\n\n/**\n * Per-env R2 bucket that holds Tamer-managed artifacts (built bundles, keyed\n * `{resource-type}/{name}/{version}/...`). Owned by Tamer itself, not by any\n * worker in `tamer.config.ts`. Created on `tamer bootstrap` and removed on\n * `tamer destroy --wipe-metadata`.\n *\n * Naming intentionally mirrors `tamer-state-{env}` (see `tamerStateDb.ts`).\n */\nexport function tamerArtifactsBucketName(env: string): string {\n return `tamer-artifacts-${env}`;\n}\n\nexport async function findTamerArtifactsBucket(\n api: CFApiClient,\n env: string,\n): Promise<{ name: string; creation_date: string } | undefined> {\n const name = tamerArtifactsBucketName(env);\n const all = await api.r2ListAll();\n return all.find((b) => b.name === name);\n}\n\n/** Create the bucket if missing. Idempotent — re-runs are safe. */\nexport async function ensureTamerArtifactsBucket(\n api: CFApiClient,\n env: string,\n): Promise<string> {\n const existing = await findTamerArtifactsBucket(api, env);\n const name = tamerArtifactsBucketName(env);\n if (existing) return name;\n await api.r2Create(name);\n return name;\n}\n\n/**\n * Best-effort delete. Returns true if the bucket existed and was removed,\n * false if it was already gone. Cloudflare refuses to delete non-empty\n * buckets; in that case the error is propagated so the operator can decide.\n */\nexport async function destroyTamerArtifactsBucket(\n api: CFApiClient,\n env: string,\n): Promise<boolean> {\n const existing = await findTamerArtifactsBucket(api, env);\n if (!existing) return false;\n const name = existing.name;\n const accountId = api.getAccountId();\n const s3creds = r2S3CredentialsFromEnv();\n if (s3creds) {\n try {\n console.log(\n `R2: emptying Tamer artifacts bucket \"${name}\" via S3 API (incomplete multipart uploads, then objects)…`,\n );\n const { uploadsAborted, objectsDeleted } = await emptyR2BucketViaS3(\n accountId,\n name,\n s3creds,\n );\n console.log(\n `R2: bucket \"${name}\" — aborted ${uploadsAborted} multipart upload(s), deleted ${objectsDeleted} object(s).`,\n );\n } catch (e) {\n console.warn(\n `R2: S3 empty failed for \"${name}\":`,\n e instanceof Error ? e.message : e,\n );\n }\n } else {\n console.warn(\n `R2: R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY not set — skipping S3 empty for \"${name}\"; bucket delete may fail if the bucket is not empty.`,\n );\n }\n await api.r2Delete(name);\n return true;\n}\n"],"mappings":";;;;;;;;;;;AAcA,SAAgB,yBAAyB,KAAqB;AAC5D,QAAO,mBAAmB;;AAG5B,eAAsB,yBACpB,KACA,KAC8D;CAC9D,MAAM,OAAO,yBAAyB,IAAI;AAE1C,SADY,MAAM,IAAI,WAAW,EACtB,MAAM,MAAM,EAAE,SAAS,KAAK;;;AAIzC,eAAsB,2BACpB,KACA,KACiB;CACjB,MAAM,WAAW,MAAM,yBAAyB,KAAK,IAAI;CACzD,MAAM,OAAO,yBAAyB,IAAI;AAC1C,KAAI,SAAU,QAAO;AACrB,OAAM,IAAI,SAAS,KAAK;AACxB,QAAO;;;;;;;AAQT,eAAsB,4BACpB,KACA,KACkB;CAClB,MAAM,WAAW,MAAM,yBAAyB,KAAK,IAAI;AACzD,KAAI,CAAC,SAAU,QAAO;CACtB,MAAM,OAAO,SAAS;CACtB,MAAM,YAAY,IAAI,cAAc;CACpC,MAAM,UAAU,wBAAwB;AACxC,KAAI,QACF,KAAI;AACF,UAAQ,IACN,wCAAwC,KAAK,4DAC9C;EACD,MAAM,EAAE,gBAAgB,mBAAmB,MAAM,mBAC/C,WACA,MACA,QACD;AACD,UAAQ,IACN,eAAe,KAAK,cAAc,eAAe,gCAAgC,eAAe,aACjG;UACM,GAAG;AACV,UAAQ,KACN,4BAA4B,KAAK,KACjC,aAAa,QAAQ,EAAE,UAAU,EAClC;;KAGH,SAAQ,KACN,kFAAkF,KAAK,uDACxF;AAEH,OAAM,IAAI,SAAS,KAAK;AACxB,QAAO"}
@@ -1,8 +1,8 @@
1
1
  import { B as getWorkers, L as CFApiClient, M as wranglerConfigCliArgs, R as cloudflareAccountIdFromEnv, V as loadConfig, f as fetchStackImports, h as StateManager, k as resolveWorkerConfig, u as namingFromConfig, w as stackNameForConfig } from "./tamer.mjs";
2
- import "./registry-EWWdkLf7.mjs";
2
+ import "./registry-BlHEOKlN.mjs";
3
3
  import "./r2S3EmptyBucket-B9_pHfvB.mjs";
4
- import { n as writeWranglerJson, t as generateWranglerConfig } from "./generator-gvCy7ouY.mjs";
5
- import { t as spawnWranglerSync } from "./wranglerSpawn-CUlo2qOJ.mjs";
4
+ import { n as writeWranglerJson, t as generateWranglerConfig } from "./generator-ZTEeHlft.mjs";
5
+ import { t as spawnWranglerSync } from "./wranglerSpawn-B3TKjpt2.mjs";
6
6
 
7
7
  //#region src/cli/commands/types.ts
8
8
  async function runTypes(options) {
@@ -39,4 +39,4 @@ async function runTypes(options) {
39
39
 
40
40
  //#endregion
41
41
  export { runTypes };
42
- //# sourceMappingURL=types-D7qKnGsm.mjs.map
42
+ //# sourceMappingURL=types-DuK39eYA.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"types-D7qKnGsm.mjs","names":[],"sources":["../src/cli/commands/types.ts"],"sourcesContent":["import { loadConfig, getWorkers } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport { wranglerConfigCliArgs } from \"../../core/wrangler/wranglerOutFile.js\";\nimport { spawnWranglerSync } from \"../../core/wrangler/wranglerSpawn.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport { resolveWorkerConfig } from \"../../core/config/resolver.js\";\nimport { fetchStackImports } from \"../../core/imports/fetchStackImports.js\";\nimport {\n generateWranglerConfig,\n writeWranglerJson,\n} from \"../../core/wrangler/generator.js\";\n\nexport async function runTypes(options: {\n worker?: string;\n env?: string;\n configPath?: string;\n}): Promise<void> {\n const workerFilter = options.worker;\n const env = options.env ?? \"local\";\n const configPath = options.configPath;\n const baseDir = process.cwd();\n\n const config = await loadConfig(configPath, { env });\n const accountId =\n config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n const naming = namingFromConfig(config);\n const api = new CFApiClient(accountId);\n const state = new StateManager(\n config.tenant.id,\n env,\n stackNameForConfig(config),\n );\n await state.hydrate(api);\n const imports = await fetchStackImports(api, config, env);\n\n const workers = await getWorkers(config, baseDir);\n const toRun = workerFilter\n ? workers.filter(([k]) => k === workerFilter)\n : workers;\n\n if (toRun.length === 0) {\n throw new Error(\n workerFilter\n ? `Worker \"${workerFilter}\" not found`\n : \"No workers configured\",\n );\n }\n\n for (const [workerKey, workerConfig] of toRun) {\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n workerConfig,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { imports },\n );\n const wranglerConfig = generateWranglerConfig(resolved, state, naming);\n writeWranglerJson(resolved.workerDir, wranglerConfig, resolved.wranglerOutFile);\n\n const typesArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"types\",\n ];\n const result = spawnWranglerSync(typesArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n });\n if (result.status !== 0) {\n throw new Error(`wrangler types failed for ${workerKey}`);\n }\n console.log(`Generated types for ${workerKey}`);\n }\n}\n"],"mappings":";;;;;;;AAeA,eAAsB,SAAS,SAIb;CAChB,MAAM,eAAe,QAAQ;CAC7B,MAAM,MAAM,QAAQ,OAAO;CAC3B,MAAM,aAAa,QAAQ;CAC3B,MAAM,UAAU,QAAQ,KAAK;CAE7B,MAAM,SAAS,MAAM,WAAW,YAAY,EAAE,KAAK,CAAC;CACpD,MAAM,YACJ,OAAO,cAAc,4BAA4B;AACnD,KAAI,CAAC,UACH,OAAM,IAAI,MACR,iEACD;CAGH,MAAM,SAAS,iBAAiB,OAAO;CACvC,MAAM,MAAM,IAAI,YAAY,UAAU;CACtC,MAAM,QAAQ,IAAI,aAChB,OAAO,OAAO,IACd,KACA,mBAAmB,OAAO,CAC3B;AACD,OAAM,MAAM,QAAQ,IAAI;CACxB,MAAM,UAAU,MAAM,kBAAkB,KAAK,QAAQ,IAAI;CAEzD,MAAM,UAAU,MAAM,WAAW,QAAQ,QAAQ;CACjD,MAAM,QAAQ,eACV,QAAQ,QAAQ,CAAC,OAAO,MAAM,aAAa,GAC3C;AAEJ,KAAI,MAAM,WAAW,EACnB,OAAM,IAAI,MACR,eACI,WAAW,aAAa,eACxB,wBACL;AAGH,MAAK,MAAM,CAAC,WAAW,iBAAiB,OAAO;EAC7C,MAAM,WAAW,MAAM,oBACrB,QACA,WACA,cACA,KACA,SACA,WACA,QACA,OACA,EAAE,SAAS,CACZ;EACD,MAAM,iBAAiB,uBAAuB,UAAU,OAAO,OAAO;AACtE,oBAAkB,SAAS,WAAW,gBAAgB,SAAS,gBAAgB;AAW/E,MAJe,kBALG;GAChB;GACA,GAAG,sBAAsB,SAAS,gBAAgB;GAClD;GACD,EAC2C;GAC1C,KAAK,SAAS;GACd,OAAO;GACR,CAAC,CACS,WAAW,EACpB,OAAM,IAAI,MAAM,6BAA6B,YAAY;AAE3D,UAAQ,IAAI,uBAAuB,YAAY"}
1
+ {"version":3,"file":"types-DuK39eYA.mjs","names":[],"sources":["../src/cli/commands/types.ts"],"sourcesContent":["import { loadConfig, getWorkers } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport { wranglerConfigCliArgs } from \"../../core/wrangler/wranglerOutFile.js\";\nimport { spawnWranglerSync } from \"../../core/wrangler/wranglerSpawn.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport { resolveWorkerConfig } from \"../../core/config/resolver.js\";\nimport { fetchStackImports } from \"../../core/imports/fetchStackImports.js\";\nimport {\n generateWranglerConfig,\n writeWranglerJson,\n} from \"../../core/wrangler/generator.js\";\n\nexport async function runTypes(options: {\n worker?: string;\n env?: string;\n configPath?: string;\n}): Promise<void> {\n const workerFilter = options.worker;\n const env = options.env ?? \"local\";\n const configPath = options.configPath;\n const baseDir = process.cwd();\n\n const config = await loadConfig(configPath, { env });\n const accountId =\n config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n const naming = namingFromConfig(config);\n const api = new CFApiClient(accountId);\n const state = new StateManager(\n config.tenant.id,\n env,\n stackNameForConfig(config),\n );\n await state.hydrate(api);\n const imports = await fetchStackImports(api, config, env);\n\n const workers = await getWorkers(config, baseDir);\n const toRun = workerFilter\n ? workers.filter(([k]) => k === workerFilter)\n : workers;\n\n if (toRun.length === 0) {\n throw new Error(\n workerFilter\n ? `Worker \"${workerFilter}\" not found`\n : \"No workers configured\",\n );\n }\n\n for (const [workerKey, workerConfig] of toRun) {\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n workerConfig,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { imports },\n );\n const wranglerConfig = generateWranglerConfig(resolved, state, naming);\n writeWranglerJson(resolved.workerDir, wranglerConfig, resolved.wranglerOutFile);\n\n const typesArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"types\",\n ];\n const result = spawnWranglerSync(typesArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n });\n if (result.status !== 0) {\n throw new Error(`wrangler types failed for ${workerKey}`);\n }\n console.log(`Generated types for ${workerKey}`);\n }\n}\n"],"mappings":";;;;;;;AAeA,eAAsB,SAAS,SAIb;CAChB,MAAM,eAAe,QAAQ;CAC7B,MAAM,MAAM,QAAQ,OAAO;CAC3B,MAAM,aAAa,QAAQ;CAC3B,MAAM,UAAU,QAAQ,KAAK;CAE7B,MAAM,SAAS,MAAM,WAAW,YAAY,EAAE,KAAK,CAAC;CACpD,MAAM,YACJ,OAAO,cAAc,4BAA4B;AACnD,KAAI,CAAC,UACH,OAAM,IAAI,MACR,iEACD;CAGH,MAAM,SAAS,iBAAiB,OAAO;CACvC,MAAM,MAAM,IAAI,YAAY,UAAU;CACtC,MAAM,QAAQ,IAAI,aAChB,OAAO,OAAO,IACd,KACA,mBAAmB,OAAO,CAC3B;AACD,OAAM,MAAM,QAAQ,IAAI;CACxB,MAAM,UAAU,MAAM,kBAAkB,KAAK,QAAQ,IAAI;CAEzD,MAAM,UAAU,MAAM,WAAW,QAAQ,QAAQ;CACjD,MAAM,QAAQ,eACV,QAAQ,QAAQ,CAAC,OAAO,MAAM,aAAa,GAC3C;AAEJ,KAAI,MAAM,WAAW,EACnB,OAAM,IAAI,MACR,eACI,WAAW,aAAa,eACxB,wBACL;AAGH,MAAK,MAAM,CAAC,WAAW,iBAAiB,OAAO;EAC7C,MAAM,WAAW,MAAM,oBACrB,QACA,WACA,cACA,KACA,SACA,WACA,QACA,OACA,EAAE,SAAS,CACZ;EACD,MAAM,iBAAiB,uBAAuB,UAAU,OAAO,OAAO;AACtE,oBAAkB,SAAS,WAAW,gBAAgB,SAAS,gBAAgB;AAW/E,MAJe,kBALG;GAChB;GACA,GAAG,sBAAsB,SAAS,gBAAgB;GAClD;GACD,EAC2C;GAC1C,KAAK,SAAS;GACd,OAAO;GACR,CAAC,CACS,WAAW,EACpB,OAAM,IAAI,MAAM,6BAA6B,YAAY;AAE3D,UAAQ,IAAI,uBAAuB,YAAY"}
@@ -1,4 +1,4 @@
1
- import { a as readPlanFile, r as computeAttestation } from "./cloudflareSnapshot-CFErW72O.mjs";
1
+ import { a as readPlanFile, r as computeAttestation } from "./cloudflareSnapshot-CMbPQIsN.mjs";
2
2
 
3
3
  //#region src/core/plan/verifyPlanFile.ts
4
4
  function verifyPlanFile(args) {
@@ -30,4 +30,4 @@ function verifyPlanFile(args) {
30
30
 
31
31
  //#endregion
32
32
  export { verifyPlanFile as t };
33
- //# sourceMappingURL=verifyPlanFile-CR2bELdE.mjs.map
33
+ //# sourceMappingURL=verifyPlanFile-BBAwWzUo.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"verifyPlanFile-CR2bELdE.mjs","names":["reasons: string[]"],"sources":["../src/core/plan/verifyPlanFile.ts"],"sourcesContent":["/**\n * Cross-check a saved {@link PlanFile} against the current `(config, state,\n * live Cloudflare)` triple. Shared by `tamer apply --plan` and `tamer\n * destroy --plan`: both commands must refuse to execute against drifted\n * inputs unless the operator explicitly passes `--allow-stale`.\n *\n * The hashes are produced by {@link computeAttestation} (config + state)\n * and {@link hashCloudflareSnapshot} (live CF snapshot). Same algorithm on\n * both sides; if either side ever changes its canonical-JSON contract,\n * older plans must be regenerated.\n */\n\nimport type { CfiConfig, CfiState } from \"../../types.js\";\nimport { computeAttestation, readPlanFile } from \"./planFile.js\";\nimport type { PlanMode } from \"./plan.types.js\";\n\nexport function verifyPlanFile(args: {\n /** Filesystem path passed by the operator (`--plan plan.json`). */\n planPath: string;\n /** \"apply\" or \"destroy\" — used for diagnostics only. */\n command: \"apply\" | \"destroy\";\n /**\n * Required mode for the plan. `apply --plan` accepts only forward plans;\n * `destroy --plan` accepts only destroy plans. Mismatch is a hard error\n * (no `--allow-stale` override) since the actions are different.\n */\n expectedMode: PlanMode;\n env: string;\n tenantId: string;\n config: CfiConfig;\n stateAtPlanCheck: CfiState;\n /**\n * Hash of the live Cloudflare snapshot computed at run time. When the\n * plan was generated with `attestation.cloudflareHash`, mismatches mean\n * infra drifted out-of-band between plan and run. Omitted for\n * `env: local` and for older plan files written before drift-aware\n * refresh.\n */\n liveCloudflareHash: string | undefined;\n allowStale: boolean;\n}): void {\n const plan = readPlanFile(args.planPath);\n const cmd = args.command;\n\n if (plan.tenantId !== args.tenantId) {\n throw new Error(\n `${cmd} --plan: plan tenant \"${plan.tenantId}\" does not match current config tenant \"${args.tenantId}\"`,\n );\n }\n if (plan.env !== args.env) {\n throw new Error(\n `${cmd} --plan: plan env \"${plan.env}\" does not match --env \"${args.env}\"`,\n );\n }\n\n const planMode = plan.report.mode ?? \"forward\";\n if (planMode !== args.expectedMode) {\n throw new Error(\n `${cmd} --plan: plan mode \"${planMode}\" does not match expected mode \"${args.expectedMode}\". ` +\n `Use \\`tamer plan${args.expectedMode === \"destroy\" ? \" --destroy\" : \"\"} --out ${args.planPath}\\` to regenerate.`,\n );\n }\n\n const current = computeAttestation(args.config, args.stateAtPlanCheck);\n const configMatches = current.configHash === plan.attestation.configHash;\n const stateMatches = current.stateHash === plan.attestation.stateHash;\n const cloudflareMatches =\n plan.attestation.cloudflareHash === undefined ||\n args.liveCloudflareHash === undefined ||\n plan.attestation.cloudflareHash === args.liveCloudflareHash;\n\n if (configMatches && stateMatches && cloudflareMatches) {\n console.log(`Plan attestation verified (${args.planPath}).`);\n return;\n }\n\n const reasons: string[] = [];\n if (!configMatches) reasons.push(\"config has changed since plan was generated\");\n if (!stateMatches) reasons.push(\"recorded state has changed since plan was generated\");\n if (!cloudflareMatches)\n reasons.push(\n \"Cloudflare-side resources drifted since plan was generated (out-of-band create/delete)\",\n );\n const detail = reasons.join(\"; \");\n\n if (args.allowStale) {\n console.warn(\n `Plan attestation mismatch (${detail}). Proceeding anyway because --allow-stale was set.`,\n );\n return;\n }\n throw new Error(\n `${cmd} --plan refused: ${detail}. Re-run \"tamer plan${args.expectedMode === \"destroy\" ? \" --destroy\" : \"\"} --out ${args.planPath}\" or pass --allow-stale to override.`,\n );\n}\n"],"mappings":";;;AAgBA,SAAgB,eAAe,MAwBtB;CACP,MAAM,OAAO,aAAa,KAAK,SAAS;CACxC,MAAM,MAAM,KAAK;AAEjB,KAAI,KAAK,aAAa,KAAK,SACzB,OAAM,IAAI,MACR,GAAG,IAAI,wBAAwB,KAAK,SAAS,0CAA0C,KAAK,SAAS,GACtG;AAEH,KAAI,KAAK,QAAQ,KAAK,IACpB,OAAM,IAAI,MACR,GAAG,IAAI,qBAAqB,KAAK,IAAI,0BAA0B,KAAK,IAAI,GACzE;CAGH,MAAM,WAAW,KAAK,OAAO,QAAQ;AACrC,KAAI,aAAa,KAAK,aACpB,OAAM,IAAI,MACR,GAAG,IAAI,sBAAsB,SAAS,kCAAkC,KAAK,aAAa,qBACrE,KAAK,iBAAiB,YAAY,eAAe,GAAG,SAAS,KAAK,SAAS,mBACjG;CAGH,MAAM,UAAU,mBAAmB,KAAK,QAAQ,KAAK,iBAAiB;CACtE,MAAM,gBAAgB,QAAQ,eAAe,KAAK,YAAY;CAC9D,MAAM,eAAe,QAAQ,cAAc,KAAK,YAAY;CAC5D,MAAM,oBACJ,KAAK,YAAY,mBAAmB,UACpC,KAAK,uBAAuB,UAC5B,KAAK,YAAY,mBAAmB,KAAK;AAE3C,KAAI,iBAAiB,gBAAgB,mBAAmB;AACtD,UAAQ,IAAI,8BAA8B,KAAK,SAAS,IAAI;AAC5D;;CAGF,MAAMA,UAAoB,EAAE;AAC5B,KAAI,CAAC,cAAe,SAAQ,KAAK,8CAA8C;AAC/E,KAAI,CAAC,aAAc,SAAQ,KAAK,sDAAsD;AACtF,KAAI,CAAC,kBACH,SAAQ,KACN,yFACD;CACH,MAAM,SAAS,QAAQ,KAAK,KAAK;AAEjC,KAAI,KAAK,YAAY;AACnB,UAAQ,KACN,8BAA8B,OAAO,qDACtC;AACD;;AAEF,OAAM,IAAI,MACR,GAAG,IAAI,mBAAmB,OAAO,sBAAsB,KAAK,iBAAiB,YAAY,eAAe,GAAG,SAAS,KAAK,SAAS,sCACnI"}
1
+ {"version":3,"file":"verifyPlanFile-BBAwWzUo.mjs","names":["reasons: string[]"],"sources":["../src/core/plan/verifyPlanFile.ts"],"sourcesContent":["/**\n * Cross-check a saved {@link PlanFile} against the current `(config, state,\n * live Cloudflare)` triple. Shared by `tamer apply --plan` and `tamer\n * destroy --plan`: both commands must refuse to execute against drifted\n * inputs unless the operator explicitly passes `--allow-stale`.\n *\n * The hashes are produced by {@link computeAttestation} (config + state)\n * and {@link hashCloudflareSnapshot} (live CF snapshot). Same algorithm on\n * both sides; if either side ever changes its canonical-JSON contract,\n * older plans must be regenerated.\n */\n\nimport type { CfiConfig, CfiState } from \"../../types.js\";\nimport { computeAttestation, readPlanFile } from \"./planFile.js\";\nimport type { PlanMode } from \"./plan.types.js\";\n\nexport function verifyPlanFile(args: {\n /** Filesystem path passed by the operator (`--plan plan.json`). */\n planPath: string;\n /** \"apply\" or \"destroy\" — used for diagnostics only. */\n command: \"apply\" | \"destroy\";\n /**\n * Required mode for the plan. `apply --plan` accepts only forward plans;\n * `destroy --plan` accepts only destroy plans. Mismatch is a hard error\n * (no `--allow-stale` override) since the actions are different.\n */\n expectedMode: PlanMode;\n env: string;\n tenantId: string;\n config: CfiConfig;\n stateAtPlanCheck: CfiState;\n /**\n * Hash of the live Cloudflare snapshot computed at run time. When the\n * plan was generated with `attestation.cloudflareHash`, mismatches mean\n * infra drifted out-of-band between plan and run. Omitted for\n * `env: local` and for older plan files written before drift-aware\n * refresh.\n */\n liveCloudflareHash: string | undefined;\n allowStale: boolean;\n}): void {\n const plan = readPlanFile(args.planPath);\n const cmd = args.command;\n\n if (plan.tenantId !== args.tenantId) {\n throw new Error(\n `${cmd} --plan: plan tenant \"${plan.tenantId}\" does not match current config tenant \"${args.tenantId}\"`,\n );\n }\n if (plan.env !== args.env) {\n throw new Error(\n `${cmd} --plan: plan env \"${plan.env}\" does not match --env \"${args.env}\"`,\n );\n }\n\n const planMode = plan.report.mode ?? \"forward\";\n if (planMode !== args.expectedMode) {\n throw new Error(\n `${cmd} --plan: plan mode \"${planMode}\" does not match expected mode \"${args.expectedMode}\". ` +\n `Use \\`tamer plan${args.expectedMode === \"destroy\" ? \" --destroy\" : \"\"} --out ${args.planPath}\\` to regenerate.`,\n );\n }\n\n const current = computeAttestation(args.config, args.stateAtPlanCheck);\n const configMatches = current.configHash === plan.attestation.configHash;\n const stateMatches = current.stateHash === plan.attestation.stateHash;\n const cloudflareMatches =\n plan.attestation.cloudflareHash === undefined ||\n args.liveCloudflareHash === undefined ||\n plan.attestation.cloudflareHash === args.liveCloudflareHash;\n\n if (configMatches && stateMatches && cloudflareMatches) {\n console.log(`Plan attestation verified (${args.planPath}).`);\n return;\n }\n\n const reasons: string[] = [];\n if (!configMatches) reasons.push(\"config has changed since plan was generated\");\n if (!stateMatches) reasons.push(\"recorded state has changed since plan was generated\");\n if (!cloudflareMatches)\n reasons.push(\n \"Cloudflare-side resources drifted since plan was generated (out-of-band create/delete)\",\n );\n const detail = reasons.join(\"; \");\n\n if (args.allowStale) {\n console.warn(\n `Plan attestation mismatch (${detail}). Proceeding anyway because --allow-stale was set.`,\n );\n return;\n }\n throw new Error(\n `${cmd} --plan refused: ${detail}. Re-run \"tamer plan${args.expectedMode === \"destroy\" ? \" --destroy\" : \"\"} --out ${args.planPath}\" or pass --allow-stale to override.`,\n );\n}\n"],"mappings":";;;AAgBA,SAAgB,eAAe,MAwBtB;CACP,MAAM,OAAO,aAAa,KAAK,SAAS;CACxC,MAAM,MAAM,KAAK;AAEjB,KAAI,KAAK,aAAa,KAAK,SACzB,OAAM,IAAI,MACR,GAAG,IAAI,wBAAwB,KAAK,SAAS,0CAA0C,KAAK,SAAS,GACtG;AAEH,KAAI,KAAK,QAAQ,KAAK,IACpB,OAAM,IAAI,MACR,GAAG,IAAI,qBAAqB,KAAK,IAAI,0BAA0B,KAAK,IAAI,GACzE;CAGH,MAAM,WAAW,KAAK,OAAO,QAAQ;AACrC,KAAI,aAAa,KAAK,aACpB,OAAM,IAAI,MACR,GAAG,IAAI,sBAAsB,SAAS,kCAAkC,KAAK,aAAa,qBACrE,KAAK,iBAAiB,YAAY,eAAe,GAAG,SAAS,KAAK,SAAS,mBACjG;CAGH,MAAM,UAAU,mBAAmB,KAAK,QAAQ,KAAK,iBAAiB;CACtE,MAAM,gBAAgB,QAAQ,eAAe,KAAK,YAAY;CAC9D,MAAM,eAAe,QAAQ,cAAc,KAAK,YAAY;CAC5D,MAAM,oBACJ,KAAK,YAAY,mBAAmB,UACpC,KAAK,uBAAuB,UAC5B,KAAK,YAAY,mBAAmB,KAAK;AAE3C,KAAI,iBAAiB,gBAAgB,mBAAmB;AACtD,UAAQ,IAAI,8BAA8B,KAAK,SAAS,IAAI;AAC5D;;CAGF,MAAMA,UAAoB,EAAE;AAC5B,KAAI,CAAC,cAAe,SAAQ,KAAK,8CAA8C;AAC/E,KAAI,CAAC,aAAc,SAAQ,KAAK,sDAAsD;AACtF,KAAI,CAAC,kBACH,SAAQ,KACN,yFACD;CACH,MAAM,SAAS,QAAQ,KAAK,KAAK;AAEjC,KAAI,KAAK,YAAY;AACnB,UAAQ,KACN,8BAA8B,OAAO,qDACtC;AACD;;AAEF,OAAM,IAAI,MACR,GAAG,IAAI,mBAAmB,OAAO,sBAAsB,KAAK,iBAAiB,YAAY,eAAe,GAAG,SAAS,KAAK,SAAS,sCACnI"}
@@ -32,4 +32,4 @@ async function runWfpDelete(options) {
32
32
 
33
33
  //#endregion
34
34
  export { parseWfpDeleteArgs, runWfpDelete };
35
- //# sourceMappingURL=wfp-delete-CDBFqmrM.mjs.map
35
+ //# sourceMappingURL=wfp-delete-CQc9tveU.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"wfp-delete-CDBFqmrM.mjs","names":["opts: Record<string, string | boolean>"],"sources":["../src/cli/commands/wfp-delete.ts"],"sourcesContent":["import { loadConfig } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\n\nexport function parseWfpDeleteArgs(argv: string[]): {\n namespace: string;\n scriptName: string;\n force?: boolean;\n configPath?: string;\n} {\n const opts: Record<string, string | boolean> = {};\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (!arg.startsWith(\"--\")) continue;\n const key = arg.slice(2).replace(/-/g, \"_\");\n const next = argv[i + 1];\n if (next && !next.startsWith(\"--\")) {\n opts[key] = next;\n i++;\n } else {\n opts[key] = true;\n }\n }\n const namespace = opts.namespace as string | undefined;\n const scriptName = opts.script_name as string | undefined;\n if (!namespace || !scriptName) {\n throw new Error(\n \"usage: tamer wfp delete --namespace <name> --script-name <name> [--force] [--config <project.config.ts>]\",\n );\n }\n return {\n namespace,\n scriptName,\n force: opts.force === true || opts.force === \"true\",\n configPath: opts.config as string | undefined,\n };\n}\n\nexport async function runWfpDelete(options: {\n namespace: string;\n scriptName: string;\n force?: boolean;\n configPath?: string;\n}): Promise<void> {\n const config = await loadConfig(options.configPath, { env: \"local\" });\n const accountId = config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n const api = new CFApiClient(accountId);\n await api.dispatchNamespaceScriptDelete(options.namespace, options.scriptName, {\n force: options.force,\n });\n console.log(\n `Deleted script \"${options.scriptName}\" from dispatch namespace \"${options.namespace}\".`,\n );\n}\n"],"mappings":";;;AAIA,SAAgB,mBAAmB,MAKjC;CACA,MAAMA,OAAyC,EAAE;AACjD,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;AACjB,MAAI,CAAC,IAAI,WAAW,KAAK,CAAE;EAC3B,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC,QAAQ,MAAM,IAAI;EAC3C,MAAM,OAAO,KAAK,IAAI;AACtB,MAAI,QAAQ,CAAC,KAAK,WAAW,KAAK,EAAE;AAClC,QAAK,OAAO;AACZ;QAEA,MAAK,OAAO;;CAGhB,MAAM,YAAY,KAAK;CACvB,MAAM,aAAa,KAAK;AACxB,KAAI,CAAC,aAAa,CAAC,WACjB,OAAM,IAAI,MACR,2GACD;AAEH,QAAO;EACL;EACA;EACA,OAAO,KAAK,UAAU,QAAQ,KAAK,UAAU;EAC7C,YAAY,KAAK;EAClB;;AAGH,eAAsB,aAAa,SAKjB;CAEhB,MAAM,aADS,MAAM,WAAW,QAAQ,YAAY,EAAE,KAAK,SAAS,CAAC,EAC5C,cAAc,4BAA4B;AACnE,KAAI,CAAC,UACH,OAAM,IAAI,MACR,iEACD;AAIH,OADY,IAAI,YAAY,UAAU,CAC5B,8BAA8B,QAAQ,WAAW,QAAQ,YAAY,EAC7E,OAAO,QAAQ,OAChB,CAAC;AACF,SAAQ,IACN,mBAAmB,QAAQ,WAAW,6BAA6B,QAAQ,UAAU,IACtF"}
1
+ {"version":3,"file":"wfp-delete-CQc9tveU.mjs","names":["opts: Record<string, string | boolean>"],"sources":["../src/cli/commands/wfp-delete.ts"],"sourcesContent":["import { loadConfig } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\n\nexport function parseWfpDeleteArgs(argv: string[]): {\n namespace: string;\n scriptName: string;\n force?: boolean;\n configPath?: string;\n} {\n const opts: Record<string, string | boolean> = {};\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (!arg.startsWith(\"--\")) continue;\n const key = arg.slice(2).replace(/-/g, \"_\");\n const next = argv[i + 1];\n if (next && !next.startsWith(\"--\")) {\n opts[key] = next;\n i++;\n } else {\n opts[key] = true;\n }\n }\n const namespace = opts.namespace as string | undefined;\n const scriptName = opts.script_name as string | undefined;\n if (!namespace || !scriptName) {\n throw new Error(\n \"usage: tamer wfp delete --namespace <name> --script-name <name> [--force] [--config <project.config.ts>]\",\n );\n }\n return {\n namespace,\n scriptName,\n force: opts.force === true || opts.force === \"true\",\n configPath: opts.config as string | undefined,\n };\n}\n\nexport async function runWfpDelete(options: {\n namespace: string;\n scriptName: string;\n force?: boolean;\n configPath?: string;\n}): Promise<void> {\n const config = await loadConfig(options.configPath, { env: \"local\" });\n const accountId = config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n const api = new CFApiClient(accountId);\n await api.dispatchNamespaceScriptDelete(options.namespace, options.scriptName, {\n force: options.force,\n });\n console.log(\n `Deleted script \"${options.scriptName}\" from dispatch namespace \"${options.namespace}\".`,\n );\n}\n"],"mappings":";;;AAIA,SAAgB,mBAAmB,MAKjC;CACA,MAAMA,OAAyC,EAAE;AACjD,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;AACjB,MAAI,CAAC,IAAI,WAAW,KAAK,CAAE;EAC3B,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC,QAAQ,MAAM,IAAI;EAC3C,MAAM,OAAO,KAAK,IAAI;AACtB,MAAI,QAAQ,CAAC,KAAK,WAAW,KAAK,EAAE;AAClC,QAAK,OAAO;AACZ;QAEA,MAAK,OAAO;;CAGhB,MAAM,YAAY,KAAK;CACvB,MAAM,aAAa,KAAK;AACxB,KAAI,CAAC,aAAa,CAAC,WACjB,OAAM,IAAI,MACR,2GACD;AAEH,QAAO;EACL;EACA;EACA,OAAO,KAAK,UAAU,QAAQ,KAAK,UAAU;EAC7C,YAAY,KAAK;EAClB;;AAGH,eAAsB,aAAa,SAKjB;CAEhB,MAAM,aADS,MAAM,WAAW,QAAQ,YAAY,EAAE,KAAK,SAAS,CAAC,EAC5C,cAAc,4BAA4B;AACnE,KAAI,CAAC,UACH,OAAM,IAAI,MACR,iEACD;AAIH,OADY,IAAI,YAAY,UAAU,CAC5B,8BAA8B,QAAQ,WAAW,QAAQ,YAAY,EAC7E,OAAO,QAAQ,OAChB,CAAC;AACF,SAAQ,IACN,mBAAmB,QAAQ,WAAW,6BAA6B,QAAQ,UAAU,IACtF"}
@@ -1,5 +1,5 @@
1
1
  import { L as CFApiClient, R as cloudflareAccountIdFromEnv, V as loadConfig } from "./tamer.mjs";
2
- import { t as buildSingleModuleDispatchForm } from "./buildDispatchUploadForm-CVnPmHg4.mjs";
2
+ import { t as buildSingleModuleDispatchForm } from "./buildDispatchUploadForm-BNDcS5_9.mjs";
3
3
  import { resolve } from "path";
4
4
 
5
5
  //#region src/cli/commands/wfp-put.ts
@@ -48,4 +48,4 @@ async function runWfpPut(options) {
48
48
 
49
49
  //#endregion
50
50
  export { parseWfpPutArgs, runWfpPut };
51
- //# sourceMappingURL=wfp-put-BrwICc9i.mjs.map
51
+ //# sourceMappingURL=wfp-put-CVw8cloM.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"wfp-put-BrwICc9i.mjs","names":["opts: Record<string, string | boolean | string[]>"],"sources":["../src/cli/commands/wfp-put.ts"],"sourcesContent":["import { resolve } from \"path\";\nimport { loadConfig } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport { buildSingleModuleDispatchForm } from \"../../core/wfp/buildDispatchUploadForm.js\";\n\nexport function parseWfpPutArgs(argv: string[]): {\n namespace: string;\n scriptName: string;\n main: string;\n compatDate?: string;\n flags?: string[];\n configPath?: string;\n} {\n const opts: Record<string, string | boolean | string[]> = {};\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (!arg.startsWith(\"--\")) continue;\n const key = arg.slice(2).replace(/-/g, \"_\");\n const next = argv[i + 1];\n if (key === \"compat_flags\") {\n if (next && !next.startsWith(\"--\")) {\n opts[key] = next.split(\",\").map((s) => s.trim()).filter(Boolean);\n i++;\n }\n } else if (next && !next.startsWith(\"--\")) {\n opts[key] = next;\n i++;\n }\n }\n const namespace = opts.namespace as string | undefined;\n const scriptName = opts.script_name as string | undefined;\n const main = opts.main as string | undefined;\n if (!namespace || !scriptName || !main) {\n throw new Error(\n \"usage: tamer wfp put --namespace <name> --script-name <name> --main <file> [--compatibility-date <yyyy-mm-dd>] [--compat-flags a,b] [--config <project.config.ts>]\",\n );\n }\n return {\n namespace,\n scriptName,\n main: resolve(process.cwd(), main),\n compatDate:\n (opts.compatibility_date as string | undefined) ??\n (opts.compat_date as string | undefined),\n flags: opts.compat_flags as string[] | undefined,\n configPath: opts.config as string | undefined,\n };\n}\n\nexport async function runWfpPut(options: {\n namespace: string;\n scriptName: string;\n main: string;\n compatDate?: string;\n flags?: string[];\n configPath?: string;\n}): Promise<void> {\n const config = await loadConfig(options.configPath, { env: \"local\" });\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 compatDate =\n options.compatDate ??\n config.compatibility_date ??\n new Date().toISOString().slice(0, 10);\n\n const form = buildSingleModuleDispatchForm(options.main, {\n compatibility_date: compatDate,\n compatibility_flags: options.flags,\n });\n\n const api = new CFApiClient(accountId);\n await api.dispatchNamespaceScriptPut(\n options.namespace,\n options.scriptName,\n form,\n );\n console.log(\n `Uploaded script \"${options.scriptName}\" to dispatch namespace \"${options.namespace}\".`,\n );\n}\n"],"mappings":";;;;;AAMA,SAAgB,gBAAgB,MAO9B;CACA,MAAMA,OAAoD,EAAE;AAC5D,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;AACjB,MAAI,CAAC,IAAI,WAAW,KAAK,CAAE;EAC3B,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC,QAAQ,MAAM,IAAI;EAC3C,MAAM,OAAO,KAAK,IAAI;AACtB,MAAI,QAAQ,gBACV;OAAI,QAAQ,CAAC,KAAK,WAAW,KAAK,EAAE;AAClC,SAAK,OAAO,KAAK,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC,OAAO,QAAQ;AAChE;;aAEO,QAAQ,CAAC,KAAK,WAAW,KAAK,EAAE;AACzC,QAAK,OAAO;AACZ;;;CAGJ,MAAM,YAAY,KAAK;CACvB,MAAM,aAAa,KAAK;CACxB,MAAM,OAAO,KAAK;AAClB,KAAI,CAAC,aAAa,CAAC,cAAc,CAAC,KAChC,OAAM,IAAI,MACR,qKACD;AAEH,QAAO;EACL;EACA;EACA,MAAM,QAAQ,QAAQ,KAAK,EAAE,KAAK;EAClC,YACG,KAAK,sBACL,KAAK;EACR,OAAO,KAAK;EACZ,YAAY,KAAK;EAClB;;AAGH,eAAsB,UAAU,SAOd;CAChB,MAAM,SAAS,MAAM,WAAW,QAAQ,YAAY,EAAE,KAAK,SAAS,CAAC;CACrE,MAAM,YACJ,OAAO,cAAc,4BAA4B;AACnD,KAAI,CAAC,UACH,OAAM,IAAI,MACR,iEACD;CAGH,MAAM,aACJ,QAAQ,cACR,OAAO,uCACP,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,GAAG,GAAG;CAEvC,MAAM,OAAO,8BAA8B,QAAQ,MAAM;EACvD,oBAAoB;EACpB,qBAAqB,QAAQ;EAC9B,CAAC;AAGF,OADY,IAAI,YAAY,UAAU,CAC5B,2BACR,QAAQ,WACR,QAAQ,YACR,KACD;AACD,SAAQ,IACN,oBAAoB,QAAQ,WAAW,2BAA2B,QAAQ,UAAU,IACrF"}
1
+ {"version":3,"file":"wfp-put-CVw8cloM.mjs","names":["opts: Record<string, string | boolean | string[]>"],"sources":["../src/cli/commands/wfp-put.ts"],"sourcesContent":["import { resolve } from \"path\";\nimport { loadConfig } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport { buildSingleModuleDispatchForm } from \"../../core/wfp/buildDispatchUploadForm.js\";\n\nexport function parseWfpPutArgs(argv: string[]): {\n namespace: string;\n scriptName: string;\n main: string;\n compatDate?: string;\n flags?: string[];\n configPath?: string;\n} {\n const opts: Record<string, string | boolean | string[]> = {};\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (!arg.startsWith(\"--\")) continue;\n const key = arg.slice(2).replace(/-/g, \"_\");\n const next = argv[i + 1];\n if (key === \"compat_flags\") {\n if (next && !next.startsWith(\"--\")) {\n opts[key] = next.split(\",\").map((s) => s.trim()).filter(Boolean);\n i++;\n }\n } else if (next && !next.startsWith(\"--\")) {\n opts[key] = next;\n i++;\n }\n }\n const namespace = opts.namespace as string | undefined;\n const scriptName = opts.script_name as string | undefined;\n const main = opts.main as string | undefined;\n if (!namespace || !scriptName || !main) {\n throw new Error(\n \"usage: tamer wfp put --namespace <name> --script-name <name> --main <file> [--compatibility-date <yyyy-mm-dd>] [--compat-flags a,b] [--config <project.config.ts>]\",\n );\n }\n return {\n namespace,\n scriptName,\n main: resolve(process.cwd(), main),\n compatDate:\n (opts.compatibility_date as string | undefined) ??\n (opts.compat_date as string | undefined),\n flags: opts.compat_flags as string[] | undefined,\n configPath: opts.config as string | undefined,\n };\n}\n\nexport async function runWfpPut(options: {\n namespace: string;\n scriptName: string;\n main: string;\n compatDate?: string;\n flags?: string[];\n configPath?: string;\n}): Promise<void> {\n const config = await loadConfig(options.configPath, { env: \"local\" });\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 compatDate =\n options.compatDate ??\n config.compatibility_date ??\n new Date().toISOString().slice(0, 10);\n\n const form = buildSingleModuleDispatchForm(options.main, {\n compatibility_date: compatDate,\n compatibility_flags: options.flags,\n });\n\n const api = new CFApiClient(accountId);\n await api.dispatchNamespaceScriptPut(\n options.namespace,\n options.scriptName,\n form,\n );\n console.log(\n `Uploaded script \"${options.scriptName}\" to dispatch namespace \"${options.namespace}\".`,\n );\n}\n"],"mappings":";;;;;AAMA,SAAgB,gBAAgB,MAO9B;CACA,MAAMA,OAAoD,EAAE;AAC5D,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,MAAM,KAAK;AACjB,MAAI,CAAC,IAAI,WAAW,KAAK,CAAE;EAC3B,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC,QAAQ,MAAM,IAAI;EAC3C,MAAM,OAAO,KAAK,IAAI;AACtB,MAAI,QAAQ,gBACV;OAAI,QAAQ,CAAC,KAAK,WAAW,KAAK,EAAE;AAClC,SAAK,OAAO,KAAK,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC,OAAO,QAAQ;AAChE;;aAEO,QAAQ,CAAC,KAAK,WAAW,KAAK,EAAE;AACzC,QAAK,OAAO;AACZ;;;CAGJ,MAAM,YAAY,KAAK;CACvB,MAAM,aAAa,KAAK;CACxB,MAAM,OAAO,KAAK;AAClB,KAAI,CAAC,aAAa,CAAC,cAAc,CAAC,KAChC,OAAM,IAAI,MACR,qKACD;AAEH,QAAO;EACL;EACA;EACA,MAAM,QAAQ,QAAQ,KAAK,EAAE,KAAK;EAClC,YACG,KAAK,sBACL,KAAK;EACR,OAAO,KAAK;EACZ,YAAY,KAAK;EAClB;;AAGH,eAAsB,UAAU,SAOd;CAChB,MAAM,SAAS,MAAM,WAAW,QAAQ,YAAY,EAAE,KAAK,SAAS,CAAC;CACrE,MAAM,YACJ,OAAO,cAAc,4BAA4B;AACnD,KAAI,CAAC,UACH,OAAM,IAAI,MACR,iEACD;CAGH,MAAM,aACJ,QAAQ,cACR,OAAO,uCACP,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,GAAG,GAAG;CAEvC,MAAM,OAAO,8BAA8B,QAAQ,MAAM;EACvD,oBAAoB;EACpB,qBAAqB,QAAQ;EAC9B,CAAC;AAGF,OADY,IAAI,YAAY,UAAU,CAC5B,2BACR,QAAQ,WACR,QAAQ,YACR,KACD;AACD,SAAQ,IACN,oBAAoB,QAAQ,WAAW,2BAA2B,QAAQ,UAAU,IACrF"}
@@ -1,5 +1,5 @@
1
1
  import { B as getWorkers, D as mergedWorkerConfigForEnv, k as resolveWorkerConfig } from "./tamer.mjs";
2
- import { n as workerRouteStateKey, t as findZoneIdByName } from "./zoneResolver-DNNNmO_w.mjs";
2
+ import { n as workerRouteStateKey, t as findZoneIdByName } from "./zoneResolver-D9bz6-0l.mjs";
3
3
 
4
4
  //#region src/features/worker-route/worker-route.sync.ts
5
5
  /**
@@ -259,4 +259,4 @@ async function workerRoutesDrift(env, config, baseDir, accountId, naming, state,
259
259
 
260
260
  //#endregion
261
261
  export { workerRouteSync as i, workerRoutesDestroy as n, workerRoutesApply as r, workerRoutesDrift as t };
262
- //# sourceMappingURL=worker-route-tOqVbhv3.mjs.map
262
+ //# sourceMappingURL=worker-route-CqBDvjgo.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker-route-tOqVbhv3.mjs","names":["list: Array<{ id: string; pattern: string; script: string }>","entry: WorkerRouteStateEntry","list: Array<{ id: string; pattern: string; script: string }>","key","entry: WorkerRouteStateEntry","drift: ResourceDrift","list: Array<{ id: string; pattern: string; script: string }>"],"sources":["../src/features/worker-route/worker-route.sync.ts","../src/features/worker-route/worker-route.prune.ts","../src/features/worker-route/worker-route.apply.ts","../src/features/worker-route/worker-route.destroy.ts","../src/features/worker-route/worker-route.drift.ts"],"sourcesContent":["import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\nimport { resolveWorkerConfig } from \"../../core/config/resolver.js\";\nimport { findZoneIdByName } from \"../../core/routes/zoneResolver.js\";\nimport { workerRouteStateKey } from \"./worker-route.stateKey.js\";\nimport type { WorkerRouteStateEntry } from \"../../types.js\";\n\n/**\n * Merge Workers zone routes for `tamerRoutes` (API-managed) into state from\n * Cloudflare listings. Drops stale `worker_route` rows for workers in this\n * config when the route no longer exists on CF.\n */\nexport async function workerRouteSync(\n env: string,\n config: CfiConfig,\n baseDir: string,\n accountId: string,\n naming: NamingEngine,\n state: StateManager,\n api: CFApiClient,\n opts: {\n /**\n * Pre-fetched sibling stack outputs so cross-stack route hosts/zones\n * resolve to real patterns (else they stay as placeholders and never\n * match anything CF returned). Optional — sync is tolerant mode.\n */\n imports?: Record<string, Record<string, string>>;\n } = {},\n): Promise<void> {\n if (env === \"local\") return;\n\n const workers = await getWorkers(config, baseDir);\n const workerKeys = new Set(workers.map(([k]) => k));\n const touchedKeys = new Set<string>();\n const ts = new Date().toISOString();\n\n for (const [workerKey, wc] of workers) {\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n wc,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\", imports: opts.imports },\n );\n for (const route of resolved.apiManagedRoutes) {\n const zoneId = await findZoneIdByName(api, route.zone_name);\n if (!zoneId) {\n console.warn(\n `[sync] worker routes: zone \"${route.zone_name}\" not found; skip ${route.pattern}`,\n );\n continue;\n }\n let list: Array<{ id: string; pattern: string; script: string }>;\n try {\n list = await api.zoneWorkerRoutesList(zoneId);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(\n `[sync] worker routes: list failed for zone ${route.zone_name}: ${msg}`,\n );\n continue;\n }\n const hit = list.find(\n (r) => r.pattern === route.pattern && r.script === resolved.workerName,\n );\n if (!hit) continue;\n\n const key = workerRouteStateKey(zoneId, hit.id);\n touchedKeys.add(key);\n const existing = state.get(key);\n const prev =\n existing?.type === \"worker_route\" ? existing : undefined;\n const entry: WorkerRouteStateEntry = {\n type: \"worker_route\",\n workerKey,\n workerName: resolved.workerName,\n zoneId,\n zoneName: route.zone_name,\n routeId: hit.id,\n pattern: route.pattern,\n createdAt: prev?.createdAt ?? ts,\n updatedAt: ts,\n };\n state.set(key, entry);\n }\n }\n\n /**\n * Dropping stale `worker_route` state without calling Cloudflare's zone route\n * delete API leaves orphaned public URL patterns on the script (common after\n * removing `tamerRoutes`).\n */\n for (const [k, e] of Object.entries(state.getAll())) {\n if (e.type !== \"worker_route\") continue;\n if (!workerKeys.has(e.workerKey)) continue;\n if (touchedKeys.has(k)) continue;\n try {\n await api.zoneWorkerRouteDelete(e.zoneId, e.routeId);\n console.log(\n `[sync] deleted stale Workers zone route ${e.pattern} → ${e.workerName} (${e.zoneName})`,\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[sync] failed to delete stale zone route ${e.pattern}: ${msg}`);\n }\n state.delete(k);\n }\n}\n","import type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { ResolvedWorkerConfig } from \"../../core/config/resolver.js\";\nimport { findZoneIdByName } from \"../../core/routes/zoneResolver.js\";\nimport { workerRouteStateKey } from \"./worker-route.stateKey.js\";\n\n/**\n * Remove Workers **zone routes** (`/zones/{id}/workers/routes`) that still point\n * at {@link ResolvedWorkerConfig.workerName} but are **not** in the resolved\n * desired set ({@link ResolvedWorkerConfig.apiManagedRoutes}), scoped to\n * {@link staleSweepZones}.\n *\n * Used on **`tamer deploy`** after removing `tamerRoutes` so orphaned patterns\n * are not left on the account. Wrangler **`routes`** / custom domains are a\n * separate surface — this only touches API-managed zone routes.\n *\n * When {@link staleSweepZones} is omitted or empty, this is a no-op (safe default).\n */\nexport async function pruneStaleApiManagedZoneRoutesForWorker(\n api: CFApiClient,\n state: StateManager,\n resolved: ResolvedWorkerConfig,\n staleSweepZones: string[] | undefined,\n): Promise<void> {\n if (!staleSweepZones?.length) return;\n\n const desired = new Set(\n resolved.apiManagedRoutes.map((r) => `${r.zone_name}\\0${r.pattern}`),\n );\n\n for (const zoneName of staleSweepZones) {\n const zoneId = await findZoneIdByName(api, zoneName);\n if (!zoneId) {\n console.warn(\n `[deploy] stale route prune: zone \"${zoneName}\" not found; skip`,\n );\n continue;\n }\n\n let list: Array<{ id: string; pattern: string; script: string }>;\n try {\n list = await api.zoneWorkerRoutesList(zoneId);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(\n `[deploy] stale route prune: list failed for \"${zoneName}\": ${msg}`,\n );\n continue;\n }\n\n for (const r of list) {\n if (r.script !== resolved.workerName) continue;\n const sig = `${zoneName}\\0${r.pattern}`;\n if (desired.has(sig)) continue;\n\n try {\n await api.zoneWorkerRouteDelete(zoneId, r.id);\n console.log(\n `[deploy] pruned stale zone route ${r.pattern} → ${resolved.workerName} (${zoneName})`,\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(\n `[deploy] stale route prune: failed to delete ${r.pattern}: ${msg}`,\n );\n }\n state.delete(workerRouteStateKey(zoneId, r.id));\n }\n }\n}\n","import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\nimport {\n mergedWorkerConfigForEnv,\n resolveWorkerConfig,\n} from \"../../core/config/resolver.js\";\nimport { findZoneIdByName } from \"../../core/routes/zoneResolver.js\";\nimport { pruneStaleApiManagedZoneRoutesForWorker } from \"./worker-route.prune.js\";\nimport { workerRouteStateKey } from \"./worker-route.stateKey.js\";\nimport type { WorkerRouteStateEntry } from \"../../types.js\";\n\n/**\n * Ensure API-managed zone routes exist after the Worker script exists (call\n * after successful `wrangler deploy`).\n */\nexport async function workerRoutesApply(\n env: string,\n config: CfiConfig,\n baseDir: string,\n accountId: string,\n naming: NamingEngine,\n state: StateManager,\n api: CFApiClient,\n opts: {\n /**\n * Pre-fetched sibling stack outputs for `${tamer:import:…}` references\n * in `tamerRoutes[].host` / `.zone`. Caller (`deploy`) is expected to\n * load these once and reuse across worker iterations to avoid repeated\n * D1 hydrate calls.\n */\n imports?: Record<string, Record<string, string>>;\n } = {},\n): Promise<void> {\n if (env === \"local\") return;\n\n const workers = await getWorkers(config, baseDir);\n const ts = new Date().toISOString();\n\n for (const [workerKey, wc] of workers) {\n const declared = mergedWorkerConfigForEnv(wc, env, config.tenant);\n const staleSweepZones = declared.tamerStaleRouteSweepZones;\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n wc,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { imports: opts.imports },\n );\n await pruneStaleApiManagedZoneRoutesForWorker(\n api,\n state,\n resolved,\n staleSweepZones,\n );\n for (const route of resolved.apiManagedRoutes) {\n const zoneId = await findZoneIdByName(api, route.zone_name);\n if (!zoneId) {\n throw new Error(\n `worker routes: zone \"${route.zone_name}\" not found (check DNS / account access)`,\n );\n }\n const list = await api.zoneWorkerRoutesList(zoneId);\n const exists = list.find(\n (r) => r.pattern === route.pattern && r.script === resolved.workerName,\n );\n if (exists) {\n const key = workerRouteStateKey(zoneId, exists.id);\n const existing = state.get(key);\n const prev =\n existing?.type === \"worker_route\" ? existing : undefined;\n state.set(key, {\n type: \"worker_route\",\n workerKey,\n workerName: resolved.workerName,\n zoneId,\n zoneName: route.zone_name,\n routeId: exists.id,\n pattern: route.pattern,\n createdAt: prev?.createdAt ?? ts,\n updatedAt: ts,\n });\n continue;\n }\n\n const created = await api.zoneWorkerRouteCreate(zoneId, {\n pattern: route.pattern,\n script: resolved.workerName,\n });\n const key = workerRouteStateKey(zoneId, created.id);\n const entry: WorkerRouteStateEntry = {\n type: \"worker_route\",\n workerKey,\n workerName: resolved.workerName,\n zoneId,\n zoneName: route.zone_name,\n routeId: created.id,\n pattern: route.pattern,\n createdAt: ts,\n updatedAt: ts,\n };\n state.set(key, entry);\n }\n }\n}\n","import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\n\n/**\n * Delete API-managed zone routes for workers declared in this stack's config\n * (before deleting Workers so routes are not left orphaned).\n */\nexport async function workerRoutesDestroy(\n env: string,\n config: CfiConfig,\n baseDir: string,\n state: StateManager,\n api: CFApiClient,\n): Promise<void> {\n if (env === \"local\") return;\n\n const workers = await getWorkers(config, baseDir);\n const allowed = new Set(workers.map(([k]) => k));\n\n for (const [k, e] of Object.entries(state.getAll())) {\n if (e.type !== \"worker_route\") continue;\n if (!allowed.has(e.workerKey)) continue;\n try {\n await api.zoneWorkerRouteDelete(e.zoneId, e.routeId);\n console.log(\n `Deleted zone route ${e.pattern} (${e.routeId}) → ${e.workerName}`,\n );\n } catch (err) {\n console.warn(\n `Failed to delete zone route ${e.pattern}:`,\n err instanceof Error ? err.message : err,\n );\n }\n state.delete(k);\n }\n}\n","import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport type { ResourceDrift } from \"../../core/drift/drift.types.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\nimport { resolveWorkerConfig } from \"../../core/config/resolver.js\";\nimport { findZoneIdByName } from \"../../core/routes/zoneResolver.js\";\nimport type { WorkerRouteStateEntry } from \"../../types.js\";\n\nfunction stateRouteForWorkerPattern(\n state: StateManager,\n workerKey: string,\n pattern: string,\n): WorkerRouteStateEntry | undefined {\n for (const e of Object.values(state.getAll())) {\n if (\n e.type === \"worker_route\" &&\n e.workerKey === workerKey &&\n e.pattern === pattern\n ) {\n return e;\n }\n }\n return undefined;\n}\n\nexport async function workerRoutesDrift(\n env: string,\n config: CfiConfig,\n baseDir: string,\n accountId: string,\n naming: NamingEngine,\n state: StateManager,\n api: CFApiClient,\n opts: {\n /** Pre-fetched sibling stack outputs; tolerant lookup. */\n imports?: Record<string, Record<string, string>>;\n } = {},\n): Promise<ResourceDrift | null> {\n if (env === \"local\") return null;\n\n const workers = await getWorkers(config, baseDir);\n const drift: ResourceDrift = {\n kind: \"worker_route\",\n missingFromCloudflare: [],\n unrecordedInState: [],\n undeployed: [],\n };\n let sawAnyApiRoute = false;\n\n for (const [workerKey, wc] of workers) {\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n wc,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\", imports: opts.imports },\n );\n for (const route of resolved.apiManagedRoutes) {\n sawAnyApiRoute = true;\n const zoneId = await findZoneIdByName(api, route.zone_name);\n if (!zoneId) {\n drift.undeployed.push({\n logicalName: workerKey,\n derivedName: route.pattern,\n detail: `zone \"${route.zone_name}\" not found`,\n });\n continue;\n }\n let list: Array<{ id: string; pattern: string; script: string }>;\n try {\n list = await api.zoneWorkerRoutesList(zoneId);\n } catch {\n continue;\n }\n const hit = list.find(\n (r) => r.pattern === route.pattern && r.script === resolved.workerName,\n );\n const st = stateRouteForWorkerPattern(state, workerKey, route.pattern);\n if (hit) {\n if (!st || st.routeId !== hit.id) {\n drift.unrecordedInState.push({\n logicalName: workerKey,\n derivedName: route.pattern,\n cfId: hit.id,\n });\n }\n } else if (st) {\n drift.missingFromCloudflare.push({\n logicalName: workerKey,\n derivedName: route.pattern,\n cfId: st.routeId,\n });\n } else {\n drift.undeployed.push({\n logicalName: workerKey,\n derivedName: route.pattern,\n });\n }\n }\n }\n\n return sawAnyApiRoute ? drift : null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"worker-route-CqBDvjgo.mjs","names":["list: Array<{ id: string; pattern: string; script: string }>","entry: WorkerRouteStateEntry","list: Array<{ id: string; pattern: string; script: string }>","key","entry: WorkerRouteStateEntry","drift: ResourceDrift","list: Array<{ id: string; pattern: string; script: string }>"],"sources":["../src/features/worker-route/worker-route.sync.ts","../src/features/worker-route/worker-route.prune.ts","../src/features/worker-route/worker-route.apply.ts","../src/features/worker-route/worker-route.destroy.ts","../src/features/worker-route/worker-route.drift.ts"],"sourcesContent":["import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\nimport { resolveWorkerConfig } from \"../../core/config/resolver.js\";\nimport { findZoneIdByName } from \"../../core/routes/zoneResolver.js\";\nimport { workerRouteStateKey } from \"./worker-route.stateKey.js\";\nimport type { WorkerRouteStateEntry } from \"../../types.js\";\n\n/**\n * Merge Workers zone routes for `tamerRoutes` (API-managed) into state from\n * Cloudflare listings. Drops stale `worker_route` rows for workers in this\n * config when the route no longer exists on CF.\n */\nexport async function workerRouteSync(\n env: string,\n config: CfiConfig,\n baseDir: string,\n accountId: string,\n naming: NamingEngine,\n state: StateManager,\n api: CFApiClient,\n opts: {\n /**\n * Pre-fetched sibling stack outputs so cross-stack route hosts/zones\n * resolve to real patterns (else they stay as placeholders and never\n * match anything CF returned). Optional — sync is tolerant mode.\n */\n imports?: Record<string, Record<string, string>>;\n } = {},\n): Promise<void> {\n if (env === \"local\") return;\n\n const workers = await getWorkers(config, baseDir);\n const workerKeys = new Set(workers.map(([k]) => k));\n const touchedKeys = new Set<string>();\n const ts = new Date().toISOString();\n\n for (const [workerKey, wc] of workers) {\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n wc,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\", imports: opts.imports },\n );\n for (const route of resolved.apiManagedRoutes) {\n const zoneId = await findZoneIdByName(api, route.zone_name);\n if (!zoneId) {\n console.warn(\n `[sync] worker routes: zone \"${route.zone_name}\" not found; skip ${route.pattern}`,\n );\n continue;\n }\n let list: Array<{ id: string; pattern: string; script: string }>;\n try {\n list = await api.zoneWorkerRoutesList(zoneId);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(\n `[sync] worker routes: list failed for zone ${route.zone_name}: ${msg}`,\n );\n continue;\n }\n const hit = list.find(\n (r) => r.pattern === route.pattern && r.script === resolved.workerName,\n );\n if (!hit) continue;\n\n const key = workerRouteStateKey(zoneId, hit.id);\n touchedKeys.add(key);\n const existing = state.get(key);\n const prev =\n existing?.type === \"worker_route\" ? existing : undefined;\n const entry: WorkerRouteStateEntry = {\n type: \"worker_route\",\n workerKey,\n workerName: resolved.workerName,\n zoneId,\n zoneName: route.zone_name,\n routeId: hit.id,\n pattern: route.pattern,\n createdAt: prev?.createdAt ?? ts,\n updatedAt: ts,\n };\n state.set(key, entry);\n }\n }\n\n /**\n * Dropping stale `worker_route` state without calling Cloudflare's zone route\n * delete API leaves orphaned public URL patterns on the script (common after\n * removing `tamerRoutes`).\n */\n for (const [k, e] of Object.entries(state.getAll())) {\n if (e.type !== \"worker_route\") continue;\n if (!workerKeys.has(e.workerKey)) continue;\n if (touchedKeys.has(k)) continue;\n try {\n await api.zoneWorkerRouteDelete(e.zoneId, e.routeId);\n console.log(\n `[sync] deleted stale Workers zone route ${e.pattern} → ${e.workerName} (${e.zoneName})`,\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(`[sync] failed to delete stale zone route ${e.pattern}: ${msg}`);\n }\n state.delete(k);\n }\n}\n","import type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { ResolvedWorkerConfig } from \"../../core/config/resolver.js\";\nimport { findZoneIdByName } from \"../../core/routes/zoneResolver.js\";\nimport { workerRouteStateKey } from \"./worker-route.stateKey.js\";\n\n/**\n * Remove Workers **zone routes** (`/zones/{id}/workers/routes`) that still point\n * at {@link ResolvedWorkerConfig.workerName} but are **not** in the resolved\n * desired set ({@link ResolvedWorkerConfig.apiManagedRoutes}), scoped to\n * {@link staleSweepZones}.\n *\n * Used on **`tamer deploy`** after removing `tamerRoutes` so orphaned patterns\n * are not left on the account. Wrangler **`routes`** / custom domains are a\n * separate surface — this only touches API-managed zone routes.\n *\n * When {@link staleSweepZones} is omitted or empty, this is a no-op (safe default).\n */\nexport async function pruneStaleApiManagedZoneRoutesForWorker(\n api: CFApiClient,\n state: StateManager,\n resolved: ResolvedWorkerConfig,\n staleSweepZones: string[] | undefined,\n): Promise<void> {\n if (!staleSweepZones?.length) return;\n\n const desired = new Set(\n resolved.apiManagedRoutes.map((r) => `${r.zone_name}\\0${r.pattern}`),\n );\n\n for (const zoneName of staleSweepZones) {\n const zoneId = await findZoneIdByName(api, zoneName);\n if (!zoneId) {\n console.warn(\n `[deploy] stale route prune: zone \"${zoneName}\" not found; skip`,\n );\n continue;\n }\n\n let list: Array<{ id: string; pattern: string; script: string }>;\n try {\n list = await api.zoneWorkerRoutesList(zoneId);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(\n `[deploy] stale route prune: list failed for \"${zoneName}\": ${msg}`,\n );\n continue;\n }\n\n for (const r of list) {\n if (r.script !== resolved.workerName) continue;\n const sig = `${zoneName}\\0${r.pattern}`;\n if (desired.has(sig)) continue;\n\n try {\n await api.zoneWorkerRouteDelete(zoneId, r.id);\n console.log(\n `[deploy] pruned stale zone route ${r.pattern} → ${resolved.workerName} (${zoneName})`,\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn(\n `[deploy] stale route prune: failed to delete ${r.pattern}: ${msg}`,\n );\n }\n state.delete(workerRouteStateKey(zoneId, r.id));\n }\n }\n}\n","import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\nimport {\n mergedWorkerConfigForEnv,\n resolveWorkerConfig,\n} from \"../../core/config/resolver.js\";\nimport { findZoneIdByName } from \"../../core/routes/zoneResolver.js\";\nimport { pruneStaleApiManagedZoneRoutesForWorker } from \"./worker-route.prune.js\";\nimport { workerRouteStateKey } from \"./worker-route.stateKey.js\";\nimport type { WorkerRouteStateEntry } from \"../../types.js\";\n\n/**\n * Ensure API-managed zone routes exist after the Worker script exists (call\n * after successful `wrangler deploy`).\n */\nexport async function workerRoutesApply(\n env: string,\n config: CfiConfig,\n baseDir: string,\n accountId: string,\n naming: NamingEngine,\n state: StateManager,\n api: CFApiClient,\n opts: {\n /**\n * Pre-fetched sibling stack outputs for `${tamer:import:…}` references\n * in `tamerRoutes[].host` / `.zone`. Caller (`deploy`) is expected to\n * load these once and reuse across worker iterations to avoid repeated\n * D1 hydrate calls.\n */\n imports?: Record<string, Record<string, string>>;\n } = {},\n): Promise<void> {\n if (env === \"local\") return;\n\n const workers = await getWorkers(config, baseDir);\n const ts = new Date().toISOString();\n\n for (const [workerKey, wc] of workers) {\n const declared = mergedWorkerConfigForEnv(wc, env, config.tenant);\n const staleSweepZones = declared.tamerStaleRouteSweepZones;\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n wc,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { imports: opts.imports },\n );\n await pruneStaleApiManagedZoneRoutesForWorker(\n api,\n state,\n resolved,\n staleSweepZones,\n );\n for (const route of resolved.apiManagedRoutes) {\n const zoneId = await findZoneIdByName(api, route.zone_name);\n if (!zoneId) {\n throw new Error(\n `worker routes: zone \"${route.zone_name}\" not found (check DNS / account access)`,\n );\n }\n const list = await api.zoneWorkerRoutesList(zoneId);\n const exists = list.find(\n (r) => r.pattern === route.pattern && r.script === resolved.workerName,\n );\n if (exists) {\n const key = workerRouteStateKey(zoneId, exists.id);\n const existing = state.get(key);\n const prev =\n existing?.type === \"worker_route\" ? existing : undefined;\n state.set(key, {\n type: \"worker_route\",\n workerKey,\n workerName: resolved.workerName,\n zoneId,\n zoneName: route.zone_name,\n routeId: exists.id,\n pattern: route.pattern,\n createdAt: prev?.createdAt ?? ts,\n updatedAt: ts,\n });\n continue;\n }\n\n const created = await api.zoneWorkerRouteCreate(zoneId, {\n pattern: route.pattern,\n script: resolved.workerName,\n });\n const key = workerRouteStateKey(zoneId, created.id);\n const entry: WorkerRouteStateEntry = {\n type: \"worker_route\",\n workerKey,\n workerName: resolved.workerName,\n zoneId,\n zoneName: route.zone_name,\n routeId: created.id,\n pattern: route.pattern,\n createdAt: ts,\n updatedAt: ts,\n };\n state.set(key, entry);\n }\n }\n}\n","import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\n\n/**\n * Delete API-managed zone routes for workers declared in this stack's config\n * (before deleting Workers so routes are not left orphaned).\n */\nexport async function workerRoutesDestroy(\n env: string,\n config: CfiConfig,\n baseDir: string,\n state: StateManager,\n api: CFApiClient,\n): Promise<void> {\n if (env === \"local\") return;\n\n const workers = await getWorkers(config, baseDir);\n const allowed = new Set(workers.map(([k]) => k));\n\n for (const [k, e] of Object.entries(state.getAll())) {\n if (e.type !== \"worker_route\") continue;\n if (!allowed.has(e.workerKey)) continue;\n try {\n await api.zoneWorkerRouteDelete(e.zoneId, e.routeId);\n console.log(\n `Deleted zone route ${e.pattern} (${e.routeId}) → ${e.workerName}`,\n );\n } catch (err) {\n console.warn(\n `Failed to delete zone route ${e.pattern}:`,\n err instanceof Error ? err.message : err,\n );\n }\n state.delete(k);\n }\n}\n","import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport type { ResourceDrift } from \"../../core/drift/drift.types.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\nimport { resolveWorkerConfig } from \"../../core/config/resolver.js\";\nimport { findZoneIdByName } from \"../../core/routes/zoneResolver.js\";\nimport type { WorkerRouteStateEntry } from \"../../types.js\";\n\nfunction stateRouteForWorkerPattern(\n state: StateManager,\n workerKey: string,\n pattern: string,\n): WorkerRouteStateEntry | undefined {\n for (const e of Object.values(state.getAll())) {\n if (\n e.type === \"worker_route\" &&\n e.workerKey === workerKey &&\n e.pattern === pattern\n ) {\n return e;\n }\n }\n return undefined;\n}\n\nexport async function workerRoutesDrift(\n env: string,\n config: CfiConfig,\n baseDir: string,\n accountId: string,\n naming: NamingEngine,\n state: StateManager,\n api: CFApiClient,\n opts: {\n /** Pre-fetched sibling stack outputs; tolerant lookup. */\n imports?: Record<string, Record<string, string>>;\n } = {},\n): Promise<ResourceDrift | null> {\n if (env === \"local\") return null;\n\n const workers = await getWorkers(config, baseDir);\n const drift: ResourceDrift = {\n kind: \"worker_route\",\n missingFromCloudflare: [],\n unrecordedInState: [],\n undeployed: [],\n };\n let sawAnyApiRoute = false;\n\n for (const [workerKey, wc] of workers) {\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n wc,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\", imports: opts.imports },\n );\n for (const route of resolved.apiManagedRoutes) {\n sawAnyApiRoute = true;\n const zoneId = await findZoneIdByName(api, route.zone_name);\n if (!zoneId) {\n drift.undeployed.push({\n logicalName: workerKey,\n derivedName: route.pattern,\n detail: `zone \"${route.zone_name}\" not found`,\n });\n continue;\n }\n let list: Array<{ id: string; pattern: string; script: string }>;\n try {\n list = await api.zoneWorkerRoutesList(zoneId);\n } catch {\n continue;\n }\n const hit = list.find(\n (r) => r.pattern === route.pattern && r.script === resolved.workerName,\n );\n const st = stateRouteForWorkerPattern(state, workerKey, route.pattern);\n if (hit) {\n if (!st || st.routeId !== hit.id) {\n drift.unrecordedInState.push({\n logicalName: workerKey,\n derivedName: route.pattern,\n cfId: hit.id,\n });\n }\n } else if (st) {\n drift.missingFromCloudflare.push({\n logicalName: workerKey,\n derivedName: route.pattern,\n cfId: st.routeId,\n });\n } else {\n drift.undeployed.push({\n logicalName: workerKey,\n derivedName: route.pattern,\n });\n }\n }\n }\n\n return sawAnyApiRoute ? drift : null;\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { B as getWorkers, k as resolveWorkerConfig, u as namingFromConfig } from "./tamer.mjs";
2
- import { t as spawnWranglerSync } from "./wranglerSpawn-CUlo2qOJ.mjs";
2
+ import { t as spawnWranglerSync } from "./wranglerSpawn-B3TKjpt2.mjs";
3
3
 
4
4
  //#region src/features/workers/workers.destroy.ts
5
5
  /**
@@ -83,4 +83,4 @@ async function workersDrift(env, config, baseDir, accountId, naming, state, api,
83
83
 
84
84
  //#endregion
85
85
  export { workersDestroy as n, workersDrift as t };
86
- //# sourceMappingURL=workers-6r2ONF9J.mjs.map
86
+ //# sourceMappingURL=workers-DAv1ze8_.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"workers-6r2ONF9J.mjs","names":["resolved: Awaited<ReturnType<typeof resolveWorkerConfig>>[]","drift: ResourceDrift","exists: boolean"],"sources":["../src/features/workers/workers.destroy.ts","../src/features/workers/workers.drift.ts"],"sourcesContent":["import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport { resolveWorkerConfig } from \"../../core/config/resolver.js\";\nimport { spawnWranglerSync } from \"../../core/wrangler/wranglerSpawn.js\";\n\n/**\n * Remove deployed Workers: dispatch-namespace scripts via CF API, then global scripts via `wrangler delete`.\n * Call before deleting D1/R2/KV/dispatch namespaces so bindings and namespace script counts are cleared.\n */\nexport async function workersDestroy(\n env: string,\n baseDir: string,\n accountId: string,\n config: CfiConfig,\n state: StateManager,\n api: CFApiClient,\n _force?: boolean,\n): Promise<void> {\n const naming = namingFromConfig(config);\n const workers = await getWorkers(config, baseDir);\n const resolved: Awaited<ReturnType<typeof resolveWorkerConfig>>[] = [];\n\n for (const [workerKey, workerConfig] of workers) {\n // Tolerant resolution: destroy only consumes `workerName` and\n // `dispatchNamespace` — both derived from naming, not references —\n // so unresolved `${tamer:import:…}` placeholders in `vars` /\n // `tamerRoutes` must not crash teardown of a stack whose siblings\n // have already been destroyed.\n resolved.push(\n await resolveWorkerConfig(\n config,\n workerKey,\n workerConfig,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\" },\n ),\n );\n }\n\n const inNamespace = resolved.filter((r) => r.dispatchNamespace);\n const globalWorkers = resolved.filter((r) => !r.dispatchNamespace);\n\n for (const r of inNamespace) {\n const ns = r.dispatchNamespace!;\n try {\n await api.dispatchNamespaceScriptDelete(ns, r.workerName, {\n force: true,\n });\n console.log(`Deleted Worker \"${r.workerName}\" from dispatch namespace \"${ns}\"`);\n } catch (err) {\n console.warn(\n `Failed to delete dispatch Worker \"${r.workerName}\" in \"${ns}\":`,\n err instanceof Error ? err.message : err,\n );\n }\n }\n\n for (const r of globalWorkers) {\n // Do not pass `--config` here: per-worker `wrangler.*.json` files are often\n // absent (gitignored / only emitted by apply/deploy). `wrangler delete` only\n // needs the script name plus account credentials from the environment.\n // Using `cwd: baseDir` keeps `.env` loading consistent with other commands\n // (stack root). Passing `--config` with a missing file also breaks on\n // Windows (malformed path: cwd + absolute config).\n const args = [\"wrangler\", \"delete\", r.workerName, \"--force\"];\n const result = spawnWranglerSync(args, {\n cwd: baseDir,\n stdio: \"inherit\",\n shell: false,\n });\n if (result.status !== 0) {\n console.warn(\n `wrangler delete failed for \"${r.workerName}\" (cwd: ${baseDir}); script may not exist.`,\n );\n } else {\n console.log(`Deleted Worker \"${r.workerName}\"`);\n }\n }\n}\n","import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport type { ResourceDrift } from \"../../core/drift/drift.types.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\nimport { resolveWorkerConfig } from \"../../core/config/resolver.js\";\n\n/**\n * Drift for declared **global** Worker scripts (not dispatch-namespace\n * tenant scripts — those are owned by `provision-tenant` / WFP).\n *\n * Tamer does not store deployed worker script ids in state today, so this\n * report only emits `undeployed` (declared but missing on Cloudflare). It\n * never claims `unrecordedInState` for scripts because the state model has\n * no `worker_script` entry to be missing.\n *\n * Returns `null` for `local` env or when there are no global workers (so\n * `computeDriftReport` can skip emitting the section entirely).\n */\nexport async function workersDrift(\n env: string,\n config: CfiConfig,\n baseDir: string,\n accountId: string,\n naming: NamingEngine,\n state: StateManager,\n api: CFApiClient,\n opts: {\n /** Pre-fetched sibling stack outputs; tolerant lookup. */\n imports?: Record<string, Record<string, string>>;\n } = {},\n): Promise<ResourceDrift | null> {\n if (env === \"local\") return null;\n\n const workers = await getWorkers(config, baseDir);\n if (workers.length === 0) return null;\n\n const drift: ResourceDrift = {\n kind: \"worker_script\",\n missingFromCloudflare: [],\n unrecordedInState: [],\n undeployed: [],\n };\n\n let sawGlobalWorker = false;\n for (const [workerKey, wc] of workers) {\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n wc,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\", imports: opts.imports },\n );\n if (resolved.dispatchNamespace) continue;\n sawGlobalWorker = true;\n\n let exists: boolean;\n try {\n const script = await api.workersScriptGet(resolved.workerName);\n exists = !!script;\n } catch {\n continue;\n }\n if (!exists) {\n drift.undeployed.push({\n logicalName: workerKey,\n derivedName: resolved.workerName,\n });\n }\n }\n\n return sawGlobalWorker ? drift : null;\n}\n"],"mappings":";;;;;;;;AAYA,eAAsB,eACpB,KACA,SACA,WACA,QACA,OACA,KACA,QACe;CACf,MAAM,SAAS,iBAAiB,OAAO;CACvC,MAAM,UAAU,MAAM,WAAW,QAAQ,QAAQ;CACjD,MAAMA,WAA8D,EAAE;AAEtE,MAAK,MAAM,CAAC,WAAW,iBAAiB,QAMtC,UAAS,KACP,MAAM,oBACJ,QACA,WACA,cACA,KACA,SACA,WACA,QACA,OACA,EAAE,gBAAgB,YAAY,CAC/B,CACF;CAGH,MAAM,cAAc,SAAS,QAAQ,MAAM,EAAE,kBAAkB;CAC/D,MAAM,gBAAgB,SAAS,QAAQ,MAAM,CAAC,EAAE,kBAAkB;AAElE,MAAK,MAAM,KAAK,aAAa;EAC3B,MAAM,KAAK,EAAE;AACb,MAAI;AACF,SAAM,IAAI,8BAA8B,IAAI,EAAE,YAAY,EACxD,OAAO,MACR,CAAC;AACF,WAAQ,IAAI,mBAAmB,EAAE,WAAW,6BAA6B,GAAG,GAAG;WACxE,KAAK;AACZ,WAAQ,KACN,qCAAqC,EAAE,WAAW,QAAQ,GAAG,KAC7D,eAAe,QAAQ,IAAI,UAAU,IACtC;;;AAIL,MAAK,MAAM,KAAK,cAad,KALe,kBADF;EAAC;EAAY;EAAU,EAAE;EAAY;EAAU,EACrB;EACrC,KAAK;EACL,OAAO;EACP,OAAO;EACR,CAAC,CACS,WAAW,EACpB,SAAQ,KACN,+BAA+B,EAAE,WAAW,UAAU,QAAQ,0BAC/D;KAED,SAAQ,IAAI,mBAAmB,EAAE,WAAW,GAAG;;;;;;;;;;;;;;;;;AC9DrD,eAAsB,aACpB,KACA,QACA,SACA,WACA,QACA,OACA,KACA,OAGI,EAAE,EACyB;AAC/B,KAAI,QAAQ,QAAS,QAAO;CAE5B,MAAM,UAAU,MAAM,WAAW,QAAQ,QAAQ;AACjD,KAAI,QAAQ,WAAW,EAAG,QAAO;CAEjC,MAAMC,QAAuB;EAC3B,MAAM;EACN,uBAAuB,EAAE;EACzB,mBAAmB,EAAE;EACrB,YAAY,EAAE;EACf;CAED,IAAI,kBAAkB;AACtB,MAAK,MAAM,CAAC,WAAW,OAAO,SAAS;EACrC,MAAM,WAAW,MAAM,oBACrB,QACA,WACA,IACA,KACA,SACA,WACA,QACA,OACA;GAAE,gBAAgB;GAAY,SAAS,KAAK;GAAS,CACtD;AACD,MAAI,SAAS,kBAAmB;AAChC,oBAAkB;EAElB,IAAIC;AACJ,MAAI;AAEF,YAAS,CAAC,CADK,MAAM,IAAI,iBAAiB,SAAS,WAAW;UAExD;AACN;;AAEF,MAAI,CAAC,OACH,OAAM,WAAW,KAAK;GACpB,aAAa;GACb,aAAa,SAAS;GACvB,CAAC;;AAIN,QAAO,kBAAkB,QAAQ"}
1
+ {"version":3,"file":"workers-DAv1ze8_.mjs","names":["resolved: Awaited<ReturnType<typeof resolveWorkerConfig>>[]","drift: ResourceDrift","exists: boolean"],"sources":["../src/features/workers/workers.destroy.ts","../src/features/workers/workers.drift.ts"],"sourcesContent":["import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport { resolveWorkerConfig } from \"../../core/config/resolver.js\";\nimport { spawnWranglerSync } from \"../../core/wrangler/wranglerSpawn.js\";\n\n/**\n * Remove deployed Workers: dispatch-namespace scripts via CF API, then global scripts via `wrangler delete`.\n * Call before deleting D1/R2/KV/dispatch namespaces so bindings and namespace script counts are cleared.\n */\nexport async function workersDestroy(\n env: string,\n baseDir: string,\n accountId: string,\n config: CfiConfig,\n state: StateManager,\n api: CFApiClient,\n _force?: boolean,\n): Promise<void> {\n const naming = namingFromConfig(config);\n const workers = await getWorkers(config, baseDir);\n const resolved: Awaited<ReturnType<typeof resolveWorkerConfig>>[] = [];\n\n for (const [workerKey, workerConfig] of workers) {\n // Tolerant resolution: destroy only consumes `workerName` and\n // `dispatchNamespace` — both derived from naming, not references —\n // so unresolved `${tamer:import:…}` placeholders in `vars` /\n // `tamerRoutes` must not crash teardown of a stack whose siblings\n // have already been destroyed.\n resolved.push(\n await resolveWorkerConfig(\n config,\n workerKey,\n workerConfig,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\" },\n ),\n );\n }\n\n const inNamespace = resolved.filter((r) => r.dispatchNamespace);\n const globalWorkers = resolved.filter((r) => !r.dispatchNamespace);\n\n for (const r of inNamespace) {\n const ns = r.dispatchNamespace!;\n try {\n await api.dispatchNamespaceScriptDelete(ns, r.workerName, {\n force: true,\n });\n console.log(`Deleted Worker \"${r.workerName}\" from dispatch namespace \"${ns}\"`);\n } catch (err) {\n console.warn(\n `Failed to delete dispatch Worker \"${r.workerName}\" in \"${ns}\":`,\n err instanceof Error ? err.message : err,\n );\n }\n }\n\n for (const r of globalWorkers) {\n // Do not pass `--config` here: per-worker `wrangler.*.json` files are often\n // absent (gitignored / only emitted by apply/deploy). `wrangler delete` only\n // needs the script name plus account credentials from the environment.\n // Using `cwd: baseDir` keeps `.env` loading consistent with other commands\n // (stack root). Passing `--config` with a missing file also breaks on\n // Windows (malformed path: cwd + absolute config).\n const args = [\"wrangler\", \"delete\", r.workerName, \"--force\"];\n const result = spawnWranglerSync(args, {\n cwd: baseDir,\n stdio: \"inherit\",\n shell: false,\n });\n if (result.status !== 0) {\n console.warn(\n `wrangler delete failed for \"${r.workerName}\" (cwd: ${baseDir}); script may not exist.`,\n );\n } else {\n console.log(`Deleted Worker \"${r.workerName}\"`);\n }\n }\n}\n","import type { CfiConfig } from \"../../types.js\";\nimport type { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport type { StateManager } from \"../../core/state/StateManager.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport type { ResourceDrift } from \"../../core/drift/drift.types.js\";\nimport { getWorkers } from \"../../core/config/loader.js\";\nimport { resolveWorkerConfig } from \"../../core/config/resolver.js\";\n\n/**\n * Drift for declared **global** Worker scripts (not dispatch-namespace\n * tenant scripts — those are owned by `provision-tenant` / WFP).\n *\n * Tamer does not store deployed worker script ids in state today, so this\n * report only emits `undeployed` (declared but missing on Cloudflare). It\n * never claims `unrecordedInState` for scripts because the state model has\n * no `worker_script` entry to be missing.\n *\n * Returns `null` for `local` env or when there are no global workers (so\n * `computeDriftReport` can skip emitting the section entirely).\n */\nexport async function workersDrift(\n env: string,\n config: CfiConfig,\n baseDir: string,\n accountId: string,\n naming: NamingEngine,\n state: StateManager,\n api: CFApiClient,\n opts: {\n /** Pre-fetched sibling stack outputs; tolerant lookup. */\n imports?: Record<string, Record<string, string>>;\n } = {},\n): Promise<ResourceDrift | null> {\n if (env === \"local\") return null;\n\n const workers = await getWorkers(config, baseDir);\n if (workers.length === 0) return null;\n\n const drift: ResourceDrift = {\n kind: \"worker_script\",\n missingFromCloudflare: [],\n unrecordedInState: [],\n undeployed: [],\n };\n\n let sawGlobalWorker = false;\n for (const [workerKey, wc] of workers) {\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n wc,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { referencesMode: \"tolerant\", imports: opts.imports },\n );\n if (resolved.dispatchNamespace) continue;\n sawGlobalWorker = true;\n\n let exists: boolean;\n try {\n const script = await api.workersScriptGet(resolved.workerName);\n exists = !!script;\n } catch {\n continue;\n }\n if (!exists) {\n drift.undeployed.push({\n logicalName: workerKey,\n derivedName: resolved.workerName,\n });\n }\n }\n\n return sawGlobalWorker ? drift : null;\n}\n"],"mappings":";;;;;;;;AAYA,eAAsB,eACpB,KACA,SACA,WACA,QACA,OACA,KACA,QACe;CACf,MAAM,SAAS,iBAAiB,OAAO;CACvC,MAAM,UAAU,MAAM,WAAW,QAAQ,QAAQ;CACjD,MAAMA,WAA8D,EAAE;AAEtE,MAAK,MAAM,CAAC,WAAW,iBAAiB,QAMtC,UAAS,KACP,MAAM,oBACJ,QACA,WACA,cACA,KACA,SACA,WACA,QACA,OACA,EAAE,gBAAgB,YAAY,CAC/B,CACF;CAGH,MAAM,cAAc,SAAS,QAAQ,MAAM,EAAE,kBAAkB;CAC/D,MAAM,gBAAgB,SAAS,QAAQ,MAAM,CAAC,EAAE,kBAAkB;AAElE,MAAK,MAAM,KAAK,aAAa;EAC3B,MAAM,KAAK,EAAE;AACb,MAAI;AACF,SAAM,IAAI,8BAA8B,IAAI,EAAE,YAAY,EACxD,OAAO,MACR,CAAC;AACF,WAAQ,IAAI,mBAAmB,EAAE,WAAW,6BAA6B,GAAG,GAAG;WACxE,KAAK;AACZ,WAAQ,KACN,qCAAqC,EAAE,WAAW,QAAQ,GAAG,KAC7D,eAAe,QAAQ,IAAI,UAAU,IACtC;;;AAIL,MAAK,MAAM,KAAK,cAad,KALe,kBADF;EAAC;EAAY;EAAU,EAAE;EAAY;EAAU,EACrB;EACrC,KAAK;EACL,OAAO;EACP,OAAO;EACR,CAAC,CACS,WAAW,EACpB,SAAQ,KACN,+BAA+B,EAAE,WAAW,UAAU,QAAQ,0BAC/D;KAED,SAAQ,IAAI,mBAAmB,EAAE,WAAW,GAAG;;;;;;;;;;;;;;;;;AC9DrD,eAAsB,aACpB,KACA,QACA,SACA,WACA,QACA,OACA,KACA,OAGI,EAAE,EACyB;AAC/B,KAAI,QAAQ,QAAS,QAAO;CAE5B,MAAM,UAAU,MAAM,WAAW,QAAQ,QAAQ;AACjD,KAAI,QAAQ,WAAW,EAAG,QAAO;CAEjC,MAAMC,QAAuB;EAC3B,MAAM;EACN,uBAAuB,EAAE;EACzB,mBAAmB,EAAE;EACrB,YAAY,EAAE;EACf;CAED,IAAI,kBAAkB;AACtB,MAAK,MAAM,CAAC,WAAW,OAAO,SAAS;EACrC,MAAM,WAAW,MAAM,oBACrB,QACA,WACA,IACA,KACA,SACA,WACA,QACA,OACA;GAAE,gBAAgB;GAAY,SAAS,KAAK;GAAS,CACtD;AACD,MAAI,SAAS,kBAAmB;AAChC,oBAAkB;EAElB,IAAIC;AACJ,MAAI;AAEF,YAAS,CAAC,CADK,MAAM,IAAI,iBAAiB,SAAS,WAAW;UAExD;AACN;;AAEF,MAAI,CAAC,OACH,OAAM,WAAW,KAAK;GACpB,aAAa;GACb,aAAa,SAAS;GACvB,CAAC;;AAIN,QAAO,kBAAkB,QAAQ"}
@@ -21,4 +21,4 @@ function spawnWranglerSync(argv, options) {
21
21
 
22
22
  //#endregion
23
23
  export { spawnWranglerSync as t };
24
- //# sourceMappingURL=wranglerSpawn-CUlo2qOJ.mjs.map
24
+ //# sourceMappingURL=wranglerSpawn-B3TKjpt2.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"wranglerSpawn-CUlo2qOJ.mjs","names":["nodeSpawnSync"],"sources":["../src/core/wrangler/wranglerSpawn.ts"],"sourcesContent":["import {\n spawnSync as nodeSpawnSync,\n type SpawnSyncOptions,\n} from \"child_process\";\n\n/** Narrow spawn signature used by `spawnWranglerSync` (easier to mock in tests). */\nexport type WranglerSpawnSyncFn = (\n command: string,\n args: readonly string[],\n options: SpawnSyncOptions,\n) => ReturnType<typeof nodeSpawnSync>;\n\n/** Injectable spawn for unit tests (defaults to Node `spawnSync`). */\nexport const wranglerSpawnDeps = {\n spawnSync: nodeSpawnSync as WranglerSpawnSyncFn,\n};\n\nexport type SpawnWranglerSyncOptions = Pick<\n SpawnSyncOptions,\n \"cwd\" | \"stdio\" | \"env\"\n> & {\n /**\n * Default `true`. Use `false` where avoiding the shell matters (e.g. some\n * Windows paths with `wrangler delete`).\n */\n shell?: boolean;\n};\n\n/**\n * Spawn Wrangler via `bunx wrangler …` so the project-local peer/devDependency\n * resolves like npm/bun scripts (`node_modules/.bin`).\n */\nexport function spawnWranglerSync(\n argv: string[],\n options: SpawnWranglerSyncOptions,\n): ReturnType<typeof nodeSpawnSync> {\n return wranglerSpawnDeps.spawnSync(\"bunx\", argv, {\n cwd: options.cwd,\n stdio: options.stdio,\n env: options.env ? { ...process.env, ...options.env } : process.env,\n shell: options.shell ?? true,\n });\n}\n"],"mappings":";;;;AAaA,MAAa,oBAAoB,EACpBA,WACZ;;;;;AAiBD,SAAgB,kBACd,MACA,SACkC;AAClC,QAAO,kBAAkB,UAAU,QAAQ,MAAM;EAC/C,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,KAAK,QAAQ,MAAM;GAAE,GAAG,QAAQ;GAAK,GAAG,QAAQ;GAAK,GAAG,QAAQ;EAChE,OAAO,QAAQ,SAAS;EACzB,CAAC"}
1
+ {"version":3,"file":"wranglerSpawn-B3TKjpt2.mjs","names":["nodeSpawnSync"],"sources":["../src/core/wrangler/wranglerSpawn.ts"],"sourcesContent":["import {\n spawnSync as nodeSpawnSync,\n type SpawnSyncOptions,\n} from \"child_process\";\n\n/** Narrow spawn signature used by `spawnWranglerSync` (easier to mock in tests). */\nexport type WranglerSpawnSyncFn = (\n command: string,\n args: readonly string[],\n options: SpawnSyncOptions,\n) => ReturnType<typeof nodeSpawnSync>;\n\n/** Injectable spawn for unit tests (defaults to Node `spawnSync`). */\nexport const wranglerSpawnDeps = {\n spawnSync: nodeSpawnSync as WranglerSpawnSyncFn,\n};\n\nexport type SpawnWranglerSyncOptions = Pick<\n SpawnSyncOptions,\n \"cwd\" | \"stdio\" | \"env\"\n> & {\n /**\n * Default `true`. Use `false` where avoiding the shell matters (e.g. some\n * Windows paths with `wrangler delete`).\n */\n shell?: boolean;\n};\n\n/**\n * Spawn Wrangler via `bunx wrangler …` so the project-local peer/devDependency\n * resolves like npm/bun scripts (`node_modules/.bin`).\n */\nexport function spawnWranglerSync(\n argv: string[],\n options: SpawnWranglerSyncOptions,\n): ReturnType<typeof nodeSpawnSync> {\n return wranglerSpawnDeps.spawnSync(\"bunx\", argv, {\n cwd: options.cwd,\n stdio: options.stdio,\n env: options.env ? { ...process.env, ...options.env } : process.env,\n shell: options.shell ?? true,\n });\n}\n"],"mappings":";;;;AAaA,MAAa,oBAAoB,EACpBA,WACZ;;;;;AAiBD,SAAgB,kBACd,MACA,SACkC;AAClC,QAAO,kBAAkB,UAAU,QAAQ,MAAM;EAC/C,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,KAAK,QAAQ,MAAM;GAAE,GAAG,QAAQ;GAAK,GAAG,QAAQ;GAAK,GAAG,QAAQ;EAChE,OAAO,QAAQ,SAAS;EACzB,CAAC"}
@@ -29,4 +29,4 @@ async function findZoneIdByName(api, zoneName) {
29
29
 
30
30
  //#endregion
31
31
  export { workerRouteStateKey as n, findZoneIdByName as t };
32
- //# sourceMappingURL=zoneResolver-DNNNmO_w.mjs.map
32
+ //# sourceMappingURL=zoneResolver-D9bz6-0l.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"zoneResolver-DNNNmO_w.mjs","names":[],"sources":["../src/features/worker-route/worker-route.stateKey.ts","../src/core/routes/zoneResolver.ts"],"sourcesContent":["/** Primary key in `CfiState.resources` for a Cloudflare Workers zone route. */\nexport function workerRouteStateKey(zoneId: string, routeId: string): string {\n return `wr_route:${zoneId}:${routeId}`;\n}\n","import type { CFApiClient } from \"../api/CFApiClient.js\";\n\n/**\n * Per-process cache of `zone_name` → `zone_id`. Zone IDs are stable for the\n * life of a Cloudflare account, so caching across a single Tamer invocation is\n * safe and avoids hammering `/zones` once per worker × env.\n */\nconst cache = new Map<string, string | null>();\n\n/**\n * Look up a Cloudflare zone ID by exact name. Returns `undefined` if no zone\n * matches under the configured account.\n *\n * Used by API-driven route operations (sync / destroy) when wrangler's\n * `zone_name` route shape needs to be reconciled to a `zone_id`.\n */\nexport async function findZoneIdByName(\n api: CFApiClient,\n zoneName: string,\n): Promise<string | undefined> {\n const cached = cache.get(zoneName);\n if (cached !== undefined) return cached ?? undefined;\n const matches = await api.zonesListByName(zoneName);\n const id = matches[0]?.id;\n cache.set(zoneName, id ?? null);\n return id;\n}\n\n/** Test-only: reset the per-process zone cache. */\nexport function resetZoneCache(): void {\n cache.clear();\n}\n"],"mappings":";;AACA,SAAgB,oBAAoB,QAAgB,SAAyB;AAC3E,QAAO,YAAY,OAAO,GAAG;;;;;;;;;;ACK/B,MAAM,wBAAQ,IAAI,KAA4B;;;;;;;;AAS9C,eAAsB,iBACpB,KACA,UAC6B;CAC7B,MAAM,SAAS,MAAM,IAAI,SAAS;AAClC,KAAI,WAAW,OAAW,QAAO,UAAU;CAE3C,MAAM,MADU,MAAM,IAAI,gBAAgB,SAAS,EAChC,IAAI;AACvB,OAAM,IAAI,UAAU,MAAM,KAAK;AAC/B,QAAO"}
1
+ {"version":3,"file":"zoneResolver-D9bz6-0l.mjs","names":[],"sources":["../src/features/worker-route/worker-route.stateKey.ts","../src/core/routes/zoneResolver.ts"],"sourcesContent":["/** Primary key in `CfiState.resources` for a Cloudflare Workers zone route. */\nexport function workerRouteStateKey(zoneId: string, routeId: string): string {\n return `wr_route:${zoneId}:${routeId}`;\n}\n","import type { CFApiClient } from \"../api/CFApiClient.js\";\n\n/**\n * Per-process cache of `zone_name` → `zone_id`. Zone IDs are stable for the\n * life of a Cloudflare account, so caching across a single Tamer invocation is\n * safe and avoids hammering `/zones` once per worker × env.\n */\nconst cache = new Map<string, string | null>();\n\n/**\n * Look up a Cloudflare zone ID by exact name. Returns `undefined` if no zone\n * matches under the configured account.\n *\n * Used by API-driven route operations (sync / destroy) when wrangler's\n * `zone_name` route shape needs to be reconciled to a `zone_id`.\n */\nexport async function findZoneIdByName(\n api: CFApiClient,\n zoneName: string,\n): Promise<string | undefined> {\n const cached = cache.get(zoneName);\n if (cached !== undefined) return cached ?? undefined;\n const matches = await api.zonesListByName(zoneName);\n const id = matches[0]?.id;\n cache.set(zoneName, id ?? null);\n return id;\n}\n\n/** Test-only: reset the per-process zone cache. */\nexport function resetZoneCache(): void {\n cache.clear();\n}\n"],"mappings":";;AACA,SAAgB,oBAAoB,QAAgB,SAAyB;AAC3E,QAAO,YAAY,OAAO,GAAG;;;;;;;;;;ACK/B,MAAM,wBAAQ,IAAI,KAA4B;;;;;;;;AAS9C,eAAsB,iBACpB,KACA,UAC6B;CAC7B,MAAM,SAAS,MAAM,IAAI,SAAS;AAClC,KAAI,WAAW,OAAW,QAAO,UAAU;CAE3C,MAAM,MADU,MAAM,IAAI,gBAAgB,SAAS,EAChC,IAAI;AACvB,OAAM,IAAI,UAAU,MAAM,KAAK;AAC/B,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dragonmastery/tamer",
3
- "version": "0.31.5",
3
+ "version": "0.33.0",
4
4
  "description": "Tamer: Cloudflare Workers infra CLI (sync, apply, deploy, migrate, destroy) and Wrangler-oriented TypeScript types.",
5
5
  "author": "DragonMastery",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -1 +0,0 @@
1
- {"version":3,"file":"apply-C_70Hgcf.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 +0,0 @@
1
- {"version":3,"file":"deploy-D-GXzsWR.mjs","names":["out: WorkerEntry[]","deploySecrets: Awaited<\n ReturnType<typeof createDeploySecretsResources>\n > | null"],"sources":["../src/cli/commands/deploy.ts"],"sourcesContent":["import type { CfiConfig, WorkerConfig } from \"../../types.js\";\nimport { loadConfig, getWorkers } from \"../../core/config/loader.js\";\nimport { cloudflareAccountIdFromEnv } from \"../../core/cloudflareEnv.js\";\nimport { namingFromConfig } from \"../../core/config/namingFromConfig.js\";\nimport type { NamingEngine } from \"../../core/naming/NamingEngine.js\";\nimport { wranglerConfigCliArgs } from \"../../core/wrangler/wranglerOutFile.js\";\nimport { spawnWranglerSync } from \"../../core/wrangler/wranglerSpawn.js\";\nimport { StateManager } from \"../../core/state/StateManager.js\";\nimport { stackNameForConfig } from \"../../core/state/stackName.js\";\nimport { CFApiClient } from \"../../core/api/CFApiClient.js\";\nimport {\n buildIntraStackScriptNameMap,\n mergedWorkerConfigForEnv,\n resolveDeployedWorkerName,\n resolveWorkerConfig,\n rewriteIntraStackServiceTargets,\n} from \"../../core/config/resolver.js\";\nimport { requiredSecretsForWorker } from \"../../core/secrets/declared.js\";\nimport { createDeploySecretsResources } from \"./secrets/context.js\";\nimport { pushSecretsForDeploy } from \"./secrets/push.js\";\nimport {\n generateWranglerConfig,\n writeWranglerJson,\n} from \"../../core/wrangler/generator.js\";\nimport { runSync } from \"./sync.js\";\nimport { workerRoutesApply } from \"../../features/worker-route/index.js\";\nimport { fetchStackImports } from \"../../core/imports/fetchStackImports.js\";\n\ntype WorkerEntry = [string, WorkerConfig];\n\n/**\n * Topologically sort workers by `services[].service` so that dependencies\n * deploy before dependents. Cloudflare rejects deploys that reference\n * service bindings to workers that don't yet exist on the account.\n * Cross-config dependencies (services not in this monorepo) are ignored.\n */\nexport function topoSortWorkersByServiceBindings(\n workers: WorkerEntry[],\n config: CfiConfig,\n naming: NamingEngine,\n env: string,\n): WorkerEntry[] {\n const intraMap = buildIntraStackScriptNameMap(config, env, naming);\n const scriptNameToKey = new Map<string, string>();\n for (const [key, cfg] of workers) {\n const name = resolveDeployedWorkerName(config, key, cfg, env, naming);\n scriptNameToKey.set(name, key);\n }\n\n const byKey = new Map(workers);\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const out: WorkerEntry[] = [];\n\n function visit(key: string): void {\n if (visited.has(key)) return;\n if (visiting.has(key)) return;\n visiting.add(key);\n const cfg = byKey.get(key);\n if (cfg) {\n const merged = rewriteIntraStackServiceTargets(\n mergedWorkerConfigForEnv(cfg, env, config.tenant),\n intraMap,\n );\n const deps = merged.services?.map((s) => s.service) ?? [];\n for (const dep of deps) {\n const depKey = scriptNameToKey.get(dep);\n if (depKey && depKey !== key) visit(depKey);\n }\n visiting.delete(key);\n visited.add(key);\n out.push([key, cfg]);\n }\n }\n\n for (const [key] of workers) visit(key);\n return out;\n}\n\nexport async function runDeploy(options: {\n worker?: string;\n env?: string;\n configPath?: string;\n /** Passed to `wrangler deploy --dispatch-namespace` when the worker has no `dispatchNamespace` in config. */\n dispatchNamespace?: string;\n}): Promise<void> {\n const workerFilter = options.worker;\n // `--env` is intentionally required (no silent default to \"prod\") to\n // match every other Tamer command and to avoid the classic \"ran\n // `tamer deploy` from the wrong shell, shipped a half-tested branch\n // to production\" footgun.\n const env = options.env;\n if (!env) {\n throw new Error(\n \"deploy: --env is required (e.g. --env staging). \" +\n \"Tamer no longer defaults to prod — pass the env explicitly.\",\n );\n }\n const configPath = options.configPath;\n const baseDir = process.cwd();\n\n const config = await loadConfig(configPath, { env });\n const accountId =\n config.account_id ?? cloudflareAccountIdFromEnv();\n if (!accountId) {\n throw new Error(\n \"account_id required in config or CLOUDFLARE_ACCOUNT_ID env var\",\n );\n }\n\n console.log(`Syncing state for env: ${env}...`);\n await runSync({ env, configPath });\n\n const naming = namingFromConfig(config);\n const api = new CFApiClient(accountId);\n const state = new StateManager(\n config.tenant.id,\n env,\n stackNameForConfig(config),\n );\n await state.hydrate(api);\n const imports = await fetchStackImports(api, config, env);\n state.beginOperation(\"deploy\", workerFilter ? `worker:${workerFilter}` : undefined);\n\n try {\n\n const workers = await getWorkers(config, baseDir);\n const toDeploy = workerFilter\n ? workers.filter(([k]) => k === workerFilter)\n : workers;\n\n if (toDeploy.length === 0) {\n throw new Error(\n workerFilter\n ? `Worker \"${workerFilter}\" not found`\n : \"No workers configured\",\n );\n }\n\n const ordered = topoSortWorkersByServiceBindings(\n toDeploy,\n config,\n naming,\n env,\n );\n\n let deploySecrets: Awaited<\n ReturnType<typeof createDeploySecretsResources>\n > | null = null;\n\n for (const [workerKey, workerConfig] of ordered) {\n const mergedForSecrets = mergedWorkerConfigForEnv(\n workerConfig,\n env,\n config.tenant,\n );\n const requiredSecrets = requiredSecretsForWorker(mergedForSecrets);\n\n if (requiredSecrets.length > 0 && env !== \"local\") {\n if (!deploySecrets) {\n deploySecrets = await createDeploySecretsResources(api, env);\n }\n const deployedName = resolveDeployedWorkerName(\n config,\n workerKey,\n workerConfig,\n env,\n naming,\n );\n await pushSecretsForDeploy({\n workerKey,\n deployedName,\n required: requiredSecrets,\n vault: deploySecrets.vault,\n state,\n api,\n masterKey: deploySecrets.masterKey,\n });\n }\n\n const resolved = await resolveWorkerConfig(\n config,\n workerKey,\n workerConfig,\n env,\n baseDir,\n accountId,\n naming,\n state,\n { imports },\n );\n const wranglerConfig = generateWranglerConfig(resolved, state, naming);\n writeWranglerJson(resolved.workerDir, wranglerConfig, resolved.wranglerOutFile);\n\n const typesArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"types\",\n ];\n const typesResult = spawnWranglerSync(typesArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n });\n if (typesResult.status !== 0) {\n throw new Error(`wrangler types failed for ${workerKey}`);\n }\n\n const dispatchNs =\n resolved.dispatchNamespace ?? options.dispatchNamespace;\n const deployArgs = [\n \"wrangler\",\n ...wranglerConfigCliArgs(resolved.wranglerOutFile),\n \"deploy\",\n ];\n if (dispatchNs) {\n deployArgs.push(\"--dispatch-namespace\", dispatchNs);\n }\n\n const deployResult = spawnWranglerSync(deployArgs, {\n cwd: resolved.workerDir,\n stdio: \"inherit\",\n });\n if (deployResult.status !== 0) {\n throw new Error(`wrangler deploy failed for ${workerKey}`);\n }\n console.log(`Deployed ${workerKey}`);\n }\n\n if (env !== \"local\") {\n try {\n await workerRoutesApply(\n env,\n config,\n baseDir,\n accountId,\n naming,\n state,\n api,\n { imports },\n );\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`worker routes apply failed after deploy: ${msg}`);\n }\n }\n\n state.finishOperation();\n await state.persist(api);\n console.log(`Deploy complete for env: ${env}`);\n } catch (err) {\n state.failOperation(err instanceof Error ? err.message : String(err));\n try {\n await state.persist(api);\n } catch {\n /* swallow secondary persist failure */\n }\n throw err;\n }\n}\n"],"mappings":"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"}
@@ -1,8 +0,0 @@
1
- import "./registry-EWWdkLf7.mjs";
2
- import "./r2S3EmptyBucket-B9_pHfvB.mjs";
3
- import { n as runDrift, t as computeDriftReport } from "./drift-C-qnJ-mH.mjs";
4
- import "./logpush-job-DJPlpnRu.mjs";
5
- import "./worker-route-tOqVbhv3.mjs";
6
- import "./workers-6r2ONF9J.mjs";
7
-
8
- export { runDrift };