@dragonmastery/tamer 0.29.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +2 -1
  2. package/dist/{apply-BOABC3UB.mjs → apply-BjrYbyHn.mjs} +14 -16
  3. package/dist/{apply-BOABC3UB.mjs.map → apply-BjrYbyHn.mjs.map} +1 -1
  4. package/dist/{applyTarget-GWDEOXeY.mjs → applyTarget-Ce_mtRQX.mjs} +3 -3
  5. package/dist/{applyTarget-GWDEOXeY.mjs.map → applyTarget-Ce_mtRQX.mjs.map} +1 -1
  6. package/dist/{bootstrap-BxwxC_2Z.mjs → bootstrap-D__dHw1w.mjs} +6 -6
  7. package/dist/bootstrap-D__dHw1w.mjs.map +1 -0
  8. package/dist/{buildDispatchUploadForm-BoUB93b3.mjs → buildDispatchUploadForm-CVnPmHg4.mjs} +1 -1
  9. package/dist/{buildDispatchUploadForm-BoUB93b3.mjs.map → buildDispatchUploadForm-CVnPmHg4.mjs.map} +1 -1
  10. package/dist/{cloudflareSnapshot-DzPuCRTh.mjs → cloudflareSnapshot-C6cF8GG8.mjs} +5 -7
  11. package/dist/{cloudflareSnapshot-DzPuCRTh.mjs.map → cloudflareSnapshot-C6cF8GG8.mjs.map} +1 -1
  12. package/dist/{deploy-C0edCpn9.mjs → deploy-C6fX9td0.mjs} +23 -11
  13. package/dist/deploy-C6fX9td0.mjs.map +1 -0
  14. package/dist/{destroy-tenant-U0t7BeJ0.mjs → destroy-tenant-T_94ed9x.mjs} +2 -4
  15. package/dist/{destroy-tenant-U0t7BeJ0.mjs.map → destroy-tenant-T_94ed9x.mjs.map} +1 -1
  16. package/dist/{destroy-DzgA4lCA.mjs → destroy-vfk2Zbfj.mjs} +11 -13
  17. package/dist/{destroy-DzgA4lCA.mjs.map → destroy-vfk2Zbfj.mjs.map} +1 -1
  18. package/dist/{dev-CZbKfdFw.mjs → dev-BLthyLml.mjs} +8 -10
  19. package/dist/{dev-CZbKfdFw.mjs.map → dev-BLthyLml.mjs.map} +1 -1
  20. package/dist/{dns-records.resolve-C2T0m4NG.mjs → dns-records.resolve-8a_eHfVI.mjs} +1 -1
  21. package/dist/{dns-records.resolve-DwBR_1WI.mjs → dns-records.resolve-BB2agPAb.mjs} +1 -1
  22. package/dist/{dns-records.resolve-DwBR_1WI.mjs.map → dns-records.resolve-BB2agPAb.mjs.map} +1 -1
  23. package/dist/{dns-records.sync-Bpzz9H0s.mjs → dns-records.sync-DqYROe07.mjs} +3 -3
  24. package/dist/{dns-records.sync-Bpzz9H0s.mjs.map → dns-records.sync-DqYROe07.mjs.map} +1 -1
  25. package/dist/{doctor-C_hs7k2D.mjs → doctor-32YLAXXl.mjs} +2 -2
  26. package/dist/{doctor-C_hs7k2D.mjs.map → doctor-32YLAXXl.mjs.map} +1 -1
  27. package/dist/drift-BCxWdYHG.mjs +8 -0
  28. package/dist/{drift-B5bpkI0i.mjs → drift-CeemyFqL.mjs} +37 -9
  29. package/dist/drift-CeemyFqL.mjs.map +1 -0
  30. package/dist/{events-BIznt8Sj.mjs → events-otk0l3aJ.mjs} +2 -4
  31. package/dist/{events-BIznt8Sj.mjs.map → events-otk0l3aJ.mjs.map} +1 -1
  32. package/dist/{generator-Ba-vqyBG.mjs → generator-gvCy7ouY.mjs} +6 -5
  33. package/dist/generator-gvCy7ouY.mjs.map +1 -0
  34. package/dist/{import-B0dlwKoQ.mjs → import-OvohE-H2.mjs} +8 -8
  35. package/dist/import-OvohE-H2.mjs.map +1 -0
  36. package/dist/index.d.mts +314 -38
  37. package/dist/index.d.mts.map +1 -1
  38. package/dist/{logpush-job-DsRkOORJ.mjs → logpush-job-DJPlpnRu.mjs} +2 -2
  39. package/dist/{logpush-job-DsRkOORJ.mjs.map → logpush-job-DJPlpnRu.mjs.map} +1 -1
  40. package/dist/{migrate-BpW6JkIg.mjs → migrate-CroDjbJz.mjs} +6 -8
  41. package/dist/{migrate-BpW6JkIg.mjs.map → migrate-CroDjbJz.mjs.map} +1 -1
  42. package/dist/normalize-DVSTRZhO.mjs.map +1 -1
  43. package/dist/{plan-Do5rE-c5.mjs → plan-C2urqJOz.mjs} +39 -14
  44. package/dist/plan-C2urqJOz.mjs.map +1 -0
  45. package/dist/{planFormat-CJw8Kq2s.mjs → planFormat-5XMJK879.mjs} +1 -1
  46. package/dist/{planFormat-CJw8Kq2s.mjs.map → planFormat-5XMJK879.mjs.map} +1 -1
  47. package/dist/{provision-tenant-Wfck-2Oa.mjs → provision-tenant-BJ1KugON.mjs} +6 -8
  48. package/dist/{provision-tenant-Wfck-2Oa.mjs.map → provision-tenant-BJ1KugON.mjs.map} +1 -1
  49. package/dist/{r2S3EmptyBucket-DD81ZWQ7.mjs → r2S3EmptyBucket-B9_pHfvB.mjs} +1 -1
  50. package/dist/{r2S3EmptyBucket-DD81ZWQ7.mjs.map → r2S3EmptyBucket-B9_pHfvB.mjs.map} +1 -1
  51. package/dist/{fetchStackImports-C-1THPYL.mjs → registry-EWWdkLf7.mjs} +272 -1065
  52. package/dist/registry-EWWdkLf7.mjs.map +1 -0
  53. package/dist/secrets-CnzjvndT.mjs +3 -0
  54. package/dist/{stackOutputs-CQQHtdPA.mjs → stackOutputs-Cltzl2g0.mjs} +2 -2
  55. package/dist/{stackOutputs-CQQHtdPA.mjs.map → stackOutputs-Cltzl2g0.mjs.map} +1 -1
  56. package/dist/{status-D5GLpWyn.mjs → status-DkkS5lc9.mjs} +7 -9
  57. package/dist/{status-D5GLpWyn.mjs.map → status-DkkS5lc9.mjs.map} +1 -1
  58. package/dist/{sync-B_pyPi7Z.mjs → sync-CpfxqlOx.mjs} +7 -9
  59. package/dist/{sync-B_pyPi7Z.mjs.map → sync-CpfxqlOx.mjs.map} +1 -1
  60. package/dist/tamer.mjs +4428 -213
  61. package/dist/tamer.mjs.map +1 -1
  62. package/dist/{tamerArtifactsR2-Ccgplu2Q.mjs → tamerArtifactsR2-DnUJmxnO.mjs} +2 -2
  63. package/dist/{tamerArtifactsR2-Ccgplu2Q.mjs.map → tamerArtifactsR2-DnUJmxnO.mjs.map} +1 -1
  64. package/dist/{types-JrdlG7Dy.mjs → types-BzzHwIdw.mjs} +6 -8
  65. package/dist/{types-JrdlG7Dy.mjs.map → types-BzzHwIdw.mjs.map} +1 -1
  66. package/dist/{verifyPlanFile-ah_4tvTu.mjs → verifyPlanFile-BmEadIqm.mjs} +2 -2
  67. package/dist/{verifyPlanFile-ah_4tvTu.mjs.map → verifyPlanFile-BmEadIqm.mjs.map} +1 -1
  68. package/dist/{wfp-delete-BhuUrBUA.mjs → wfp-delete-CDBFqmrM.mjs} +2 -3
  69. package/dist/{wfp-delete-BhuUrBUA.mjs.map → wfp-delete-CDBFqmrM.mjs.map} +1 -1
  70. package/dist/{wfp-put-DL0mJNNz.mjs → wfp-put-BrwICc9i.mjs} +3 -4
  71. package/dist/{wfp-put-DL0mJNNz.mjs.map → wfp-put-BrwICc9i.mjs.map} +1 -1
  72. package/dist/{worker-route-CMbtozNa.mjs → worker-route-x8q3K4-z.mjs} +3 -4
  73. package/dist/{worker-route-CMbtozNa.mjs.map → worker-route-x8q3K4-z.mjs.map} +1 -1
  74. package/dist/{workers-C-oeZhdD.mjs → workers-D3Ekf3mF.mjs} +3 -4
  75. package/dist/{workers-C-oeZhdD.mjs.map → workers-D3Ekf3mF.mjs.map} +1 -1
  76. package/dist/{wranglerSpawn-DmEz0ldT.mjs → wranglerSpawn-CUlo2qOJ.mjs} +1 -1
  77. package/dist/{wranglerSpawn-DmEz0ldT.mjs.map → wranglerSpawn-CUlo2qOJ.mjs.map} +1 -1
  78. package/dist/{zoneResolver-VoxLHM4N.mjs → zoneResolver-DNNNmO_w.mjs} +1 -1
  79. package/dist/{zoneResolver-VoxLHM4N.mjs.map → zoneResolver-DNNNmO_w.mjs.map} +1 -1
  80. package/package.json +1 -1
  81. package/dist/CFApiClient-DhbyyV71.mjs +0 -868
  82. package/dist/CFApiClient-DhbyyV71.mjs.map +0 -1
  83. package/dist/StateManager-DTqtLLVX.mjs +0 -760
  84. package/dist/StateManager-DTqtLLVX.mjs.map +0 -1
  85. package/dist/bootstrap-BxwxC_2Z.mjs.map +0 -1
  86. package/dist/deploy-C0edCpn9.mjs.map +0 -1
  87. package/dist/drift-B5bpkI0i.mjs.map +0 -1
  88. package/dist/drift-BNa92AK5.mjs +0 -10
  89. package/dist/fetchStackImports-C-1THPYL.mjs.map +0 -1
  90. package/dist/generator-Ba-vqyBG.mjs.map +0 -1
  91. package/dist/import-B0dlwKoQ.mjs.map +0 -1
  92. package/dist/loader-DAvCKLTT.mjs +0 -518
  93. package/dist/loader-DAvCKLTT.mjs.map +0 -1
  94. package/dist/plan-Do5rE-c5.mjs.map +0 -1
@@ -1,846 +1,69 @@
1
- import { f as getDispatchNamespaces, n as materializeTamerResolvable, r as materializeVars } from "./normalize-DVSTRZhO.mjs";
2
- import { t as getWorkers } from "./loader-DAvCKLTT.mjs";
3
- import { f as stackNameForConfig, o as effectiveDispatchNamespaceName, s as isEphemeralEnv, t as StateManager } from "./StateManager-DTqtLLVX.mjs";
4
- import { n as r2S3CredentialsFromEnv, t as emptyR2BucketViaS3 } from "./r2S3EmptyBucket-DD81ZWQ7.mjs";
5
- import { n as logApplyChange } from "./planFormat-CJw8Kq2s.mjs";
6
- import { resolve } from "path";
7
-
8
- //#region src/core/naming/NamingEngine.ts
9
- function reLiteral(s) {
10
- return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
11
- }
12
- var NamingEngine = class {
13
- constructor(tenant, conventions) {
14
- this.tenant = tenant;
15
- this.conventions = conventions;
16
- }
17
- d1SingleName(logicalName, env) {
18
- if (this.conventions?.d1Single) return this.conventions.d1Single(logicalName, this.tenant.id, env);
19
- return `db_${logicalName}_t_${this.tenant.id}_${env}`;
20
- }
21
- d1ShardName(logicalName, shardDate, env) {
22
- if (this.conventions?.d1Shard) return this.conventions.d1Shard(logicalName, shardDate, this.tenant.id, env);
23
- const dateNoDashes = shardDate.replace(/-/g, "");
24
- if (logicalName === "default" || logicalName === "") return `db_${dateNoDashes}_t_${this.tenant.id}_${env}`;
25
- return `db_${logicalName}_${dateNoDashes}_t_${this.tenant.id}_${env}`;
26
- }
27
- d1SingleBindingKey(logicalName) {
28
- return `DB_${logicalName.toUpperCase().replace(/-/g, "_")}_T_${this.tenant.id.toUpperCase()}`;
29
- }
30
- d1ShardBindingKey(logicalName, shardDate) {
31
- const dateNoDashes = shardDate.replace(/-/g, "");
32
- return `DB_${logicalName.toUpperCase().replace(/-/g, "_")}_${dateNoDashes}_T_${this.tenant.id.toUpperCase()}`;
33
- }
34
- r2BucketName(logicalName, env) {
35
- if (this.conventions?.r2Bucket) {
36
- const dateNoDashes = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10).replace(/-/g, "");
37
- return this.conventions.r2Bucket(logicalName, dateNoDashes, this.tenant.id, env);
38
- }
39
- return `r2-${logicalName}-t-${this.tenant.id}-${env}`;
40
- }
41
- /**
42
- * Wrangler `r2_buckets[].binding`: logical + tenant only (same idea as {@link kvBindingKey}).
43
- * Stable across envs; default {@link r2BucketName} is `r2-{logical}-t-{tenant}-{env}`.
44
- */
45
- r2BindingKey(logicalName) {
46
- return `R2_${logicalName.toUpperCase().replace(/-/g, "_")}_T_${this.tenant.id.toUpperCase()}`;
47
- }
48
- kvNamespaceName(logicalName, env) {
49
- return `kv_${logicalName}_t_${this.tenant.id}_${env}`;
50
- }
51
- kvBindingKey(logicalName) {
52
- return `KV_${logicalName.toUpperCase().replace(/-/g, "_")}_T_${this.tenant.id.toUpperCase()}`;
53
- }
54
- queueName(logicalName, env) {
55
- return `q-${logicalName}-t-${this.tenant.id}-${env}`;
56
- }
57
- queueBindingKey(logicalName) {
58
- return `Q_${logicalName.toUpperCase().replace(/-/g, "_")}_T_${this.tenant.id.toUpperCase()}`;
59
- }
60
- hyperdriveName(logicalName, env) {
61
- return `hd-${logicalName}-t-${this.tenant.id}-${env}`;
62
- }
63
- hyperdriveBindingKey(logicalName) {
64
- return `HD_${logicalName.toUpperCase().replace(/-/g, "_")}_T_${this.tenant.id.toUpperCase()}`;
65
- }
66
- vectorizeName(logicalName, env) {
67
- return `vec-${logicalName}-t-${this.tenant.id}-${env}`;
68
- }
69
- vectorizeBindingKey(logicalName) {
70
- return `VEC_${logicalName.toUpperCase().replace(/-/g, "_")}_T_${this.tenant.id.toUpperCase()}`;
71
- }
72
- /**
73
- * AI Gateway slug (== Cloudflare gateway id). Per the Cloudflare API,
74
- * gateway ids are case-sensitive lowercase ascii with `-`/`_`. Format:
75
- * `aigw-{logical}-t-{tenantId}-{env}`.
76
- */
77
- aiGatewayId(logicalName, env) {
78
- return `aigw-${logicalName}-t-${this.tenant.id}-${env}`.toLowerCase();
79
- }
80
- /**
81
- * Stable cross-reference binding key for AI Gateway. AI Gateway has no
82
- * Wrangler binding kind today, so this is only consumed by
83
- * `${tamer:ai_gateway:<logical>.binding}` interpolations.
84
- */
85
- aiGatewayBindingKey(logicalName) {
86
- return `AI_GW_${logicalName.toUpperCase().replace(/-/g, "_")}_T_${this.tenant.id.toUpperCase()}`;
87
- }
88
- /**
89
- * Cloudflare-side pipeline name. Pipelines V1 names must be lowercase
90
- * alphanumerics + hyphens (no underscores), so we mirror the R2 scheme.
91
- * Pattern: `pipe-{logical}-t-{tenantId}-{env}`.
92
- */
93
- pipelineName(logicalName, env) {
94
- return `pipe-${logicalName}-t-${this.tenant.id}-${env}`.toLowerCase();
95
- }
96
- /**
97
- * Wrangler binding key emitted in `pipelines[]`. Uppercased logical with
98
- * the tenant id appended so two tenants can share a worker namespace
99
- * without colliding bindings.
100
- */
101
- pipelineBindingKey(logicalName) {
102
- return `PIPE_${logicalName.toUpperCase().replace(/-/g, "_")}_T_${this.tenant.id.toUpperCase()}`;
103
- }
104
- pipelineMatchPattern(logicalName, env) {
105
- const exact = this.pipelineName(logicalName, env);
106
- return (name) => name === exact;
107
- }
108
- /**
109
- * Cloudflare-side workflow name. Workflow names accept lowercase
110
- * alphanumerics + hyphens; we mirror the pipelines/AI-Gateway hyphen
111
- * scheme. Pattern: `wf-{logical}-t-{tenantId}-{env}`.
112
- */
113
- workflowName(logicalName, env) {
114
- if (this.conventions?.workflow) return this.conventions.workflow(logicalName, this.tenant.id, env);
115
- return `wf-${logicalName}-t-${this.tenant.id}-${env}`.toLowerCase();
116
- }
117
- /**
118
- * Wrangler binding key emitted in `workflows[]`. Uppercased logical with
119
- * the tenant id appended so two tenants sharing a script can't collide.
120
- */
121
- workflowBindingKey(logicalName) {
122
- return `WF_${logicalName.toUpperCase().replace(/-/g, "_")}_T_${this.tenant.id.toUpperCase()}`;
123
- }
124
- workflowMatchPattern(logicalName, env) {
125
- const exact = this.workflowName(logicalName, env);
126
- return (name) => name === exact;
127
- }
128
- /**
129
- * Cloudflare Secrets Store name. Account-scoped — the API allows free-form
130
- * names (the dashboard examples use both `service_x_keys` and dashed
131
- * variants), so we mirror our hyphen convention for consistency with
132
- * pipelines / workflows / AI Gateway. Pattern:
133
- * `sec-{logical}-t-{tenantId}-{env}`.
134
- */
135
- secretsStoreName(logicalName, env) {
136
- return `sec-${logicalName}-t-${this.tenant.id}-${env}`.toLowerCase();
137
- }
138
- /**
139
- * Stable cross-reference key for the store. Secrets Store has no Wrangler
140
- * binding kind directly — `secrets_store_secrets[]` references the
141
- * resolved `store_id`, not the store name — so this only powers
142
- * `${tamer:secret_store:<n>.binding}` interpolations.
143
- */
144
- secretsStoreBindingKey(logicalName) {
145
- return `SEC_${logicalName.toUpperCase().replace(/-/g, "_")}_T_${this.tenant.id.toUpperCase()}`;
146
- }
147
- secretsStoreMatchPattern(logicalName, env) {
148
- const exact = this.secretsStoreName(logicalName, env);
149
- return (name) => name === exact;
150
- }
151
- workerName(workerKey, env) {
152
- if (this.conventions?.workerName) return this.conventions.workerName(this.tenant.slug, workerKey, env, this.tenant.id);
153
- if (env === "local") return `${this.tenant.slug}-${workerKey}-${this.tenant.id}`;
154
- return `${this.tenant.slug}-${workerKey}-${env}-${this.tenant.id}`;
155
- }
156
- d1MatchPattern(logicalName, env) {
157
- if (this.conventions?.d1Shard) return (name) => {
158
- const shardDate = this.extractD1ShardDate(name);
159
- if (!shardDate) return false;
160
- return this.d1ShardName(logicalName, shardDate, env) === name;
161
- };
162
- const suffix = `_t_${this.tenant.id}_${env}`;
163
- if (logicalName === "default" || logicalName === "") return (name) => /^db_\d{8}_t_/.test(name) && name.endsWith(suffix);
164
- const prefix = `db_${logicalName}_`;
165
- return (name) => name.startsWith(prefix) && name.endsWith(suffix);
166
- }
167
- /**
168
- * Default: exact {@link r2BucketName}, or legacy dated buckets
169
- * `r2-{logical}-{YYYYMMDD}-t-{tenant}-{env}` from older Tamer versions.
170
- * Custom {@link NamingConventions.r2Bucket}: exact name only (uses today's date
171
- * when calling the hook, same as apply).
172
- */
173
- r2MatchPattern(logicalName, env) {
174
- if (this.conventions?.r2Bucket) {
175
- const expected = this.r2BucketName(logicalName, env);
176
- return (name) => name === expected;
177
- }
178
- const exactNew = `r2-${logicalName}-t-${this.tenant.id}-${env}`;
179
- const legacyDated = /* @__PURE__ */ new RegExp(`^r2-${reLiteral(logicalName)}-\\d{8}-t-${reLiteral(this.tenant.id)}-${reLiteral(env)}$`);
180
- return (name) => name === exactNew || legacyDated.test(name);
181
- }
182
- extractD1ShardDate(name) {
183
- const compact = name.match(/_(\d{8})_t_/);
184
- if (compact) {
185
- const d = compact[1];
186
- return `${d.slice(0, 4)}-${d.slice(4, 6)}-${d.slice(6, 8)}`;
187
- }
188
- const underscored = name.match(/_(\d{4})_(\d{2})_(\d{2})_t_/);
189
- if (underscored) return `${underscored[1]}-${underscored[2]}-${underscored[3]}`;
190
- return null;
191
- }
192
- extractR2Date(name) {
193
- const match = name.match(/r2-\w+-(\d{8})-t-/);
194
- if (match) {
195
- const d = match[1];
196
- return `${d.slice(0, 4)}-${d.slice(4, 6)}-${d.slice(6, 8)}`;
197
- }
198
- return null;
199
- }
200
- };
201
-
202
- //#endregion
203
- //#region src/core/config/namingFromConfig.ts
204
- function namingFromConfig(config) {
205
- const conventions = "naming" in config && config.naming ? config.naming : void 0;
206
- return new NamingEngine(config.tenant, conventions);
207
- }
208
-
209
- //#endregion
210
- //#region src/core/routes/routes.resolve.ts
211
- const DEFAULT_PROD_ENVS = ["prod", "production"];
212
- const DEFAULT_SKIP_ENVS = ["local"];
213
- /**
214
- * Per `docs/handoff.md` §6:
215
- * - prod / production → bare apex (`todo.com`)
216
- * - any other env (including ephemeral `pr-*`) → `{env}.{apex}`
217
- * - `local` (or anything in `skipEnvs`) → no route
218
- *
219
- * The resource-name `-{env}` suffix on workers/D1/R2/KV is decoupled from
220
- * URLs; this function only computes the URL.
221
- */
222
- function effectiveHostForEnv(route, env) {
223
- if ((route.skipEnvs ?? DEFAULT_SKIP_ENVS).includes(env)) return void 0;
224
- if ((route.prodEnvs ?? DEFAULT_PROD_ENVS).includes(env)) return route.host;
225
- return `${env}.${route.host}`;
226
- }
227
- /**
228
- * Expand one Tamer route into a wrangler `Route` (or `undefined` if the env
229
- * should not receive the route at all).
230
- */
231
- function expandRouteForEnv(route, env) {
232
- const host = effectiveHostForEnv(route, env);
233
- if (!host) return void 0;
234
- const zone = route.zone ?? route.host;
235
- if (route.customDomain) return {
236
- pattern: host,
237
- custom_domain: true
238
- };
239
- return {
240
- pattern: `${host}${route.path ?? "/*"}`,
241
- zone_name: zone
242
- };
243
- }
244
- /**
245
- * Expand `tamerRoutes` for the given env, dropping any that resolve to
246
- * `undefined` (`local`, `skipEnvs`).
247
- *
248
- * Note: ephemeral envs (matching `tenant.ephemeralEnvPattern`) follow the
249
- * same `{env}.{apex}` prefix rule as any non-prod env — e.g. an env named
250
- * `pr-1234` resolves to `pr-1234.todo.com`. Callers that want a different
251
- * URL scheme for ephemeral envs should special-case before calling.
252
- */
253
- function effectiveRoutesForEnv(tamerRoutes, env) {
254
- if (!tamerRoutes || tamerRoutes.length === 0) return [];
255
- const out = [];
256
- for (const r of tamerRoutes) {
257
- const expanded = expandRouteForEnv(r, env);
258
- if (expanded) out.push(expanded);
259
- }
260
- return out;
261
- }
262
- /**
263
- * Zone-name routes are attached via the Cloudflare Workers Routes HTTP API
264
- * (`/zones/{id}/workers/routes`), not via `wrangler.json`, so deploys stay
265
- * consistent with `tamer drift` / destroy.
266
- */
267
- function isApiManagedZoneRoute(r) {
268
- return typeof r === "object" && r !== null && "zone_name" in r && typeof r.zone_name === "string" && "pattern" in r && typeof r.pattern === "string" && !("custom_domain" in r && r.custom_domain === true);
269
- }
270
- /** Custom-domain `tamerRoutes` stay in wrangler until a dedicated API path exists. */
271
- function isWranglerOnlyTamerRoute(r) {
272
- return typeof r === "object" && r !== null && "custom_domain" in r && r.custom_domain === true;
273
- }
274
-
275
- //#endregion
276
- //#region src/core/wrangler/wranglerOutFile.ts
277
- /** Reject path segments in generated Wrangler config filename. */
278
- function assertSafeWranglerOutFile(name) {
279
- const trimmed = name.trim();
280
- if (!trimmed) throw new Error("wranglerOutFile cannot be empty");
281
- if (trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("..")) throw new Error(`Invalid wranglerOutFile "${name}": use a basename only (e.g. wrangler.json)`);
282
- return trimmed;
283
- }
284
- /** Extra CLI args so Wrangler uses a non-default config file. */
285
- function wranglerConfigCliArgs(outFile) {
286
- if (outFile === "wrangler.json") return [];
287
- return ["--config", outFile];
288
- }
289
-
290
- //#endregion
291
- //#region src/core/references/references.ts
292
- var TamerReferenceError = class extends Error {
293
- constructor(message, fieldPath) {
294
- super(`${message} (at ${fieldPath})`);
295
- this.fieldPath = fieldPath;
296
- this.name = "TamerReferenceError";
297
- }
298
- };
299
- const REF_RE = /\$\{tamer:([a-z0-9_]+):([a-zA-Z0-9_-]+)\.([a-zA-Z0-9_-]+)\}/g;
300
- /**
301
- * Scan a string for any `${tamer:...}` references. Returns true when at
302
- * least one reference is present (used for cheap pre-checks).
303
- */
304
- function stringHasReference(s) {
305
- REF_RE.lastIndex = 0;
306
- return REF_RE.test(s);
307
- }
308
- /**
309
- * Resolve every `${tamer:...}` reference in `value`. Replacement preserves
310
- * surrounding text for partial-string interpolation. `fieldPath` is included
311
- * in any thrown {@link TamerReferenceError} for actionable diagnostics.
312
- */
313
- function resolveReferencesInString(value, ctx, fieldPath) {
314
- if (!stringHasReference(value)) return value;
315
- return value.replace(REF_RE, (match, kind, logicalName, field) => {
316
- try {
317
- return lookupReference(kind, logicalName, field, ctx, fieldPath);
318
- } catch (err) {
319
- if (ctx.tolerant && err instanceof TamerReferenceError) return match;
320
- throw err;
321
- }
322
- });
323
- }
324
- /**
325
- * Walk a `vars` record (or any flat string→string map) replacing references
326
- * in every value. Returns a new object; the input is not mutated.
327
- */
328
- function resolveReferencesInVars(vars, ctx, fieldPathPrefix) {
329
- if (!vars) return vars;
330
- const out = {};
331
- for (const [key, value] of Object.entries(vars)) {
332
- if (typeof value !== "string") {
333
- out[key] = value;
334
- continue;
335
- }
336
- out[key] = resolveReferencesInString(value, ctx, `${fieldPathPrefix}.${key}`);
337
- }
338
- return out;
339
- }
340
- function lookupReference(kind, logicalName, field, ctx, fieldPath) {
341
- switch (kind) {
342
- case "d1": return lookupResource(ctx, kind, logicalName, field, fieldPath, (entry) => entry.type === "d1_database" && entry.logicalName === logicalName);
343
- case "r2": return lookupResource(ctx, kind, logicalName, field, fieldPath, (entry) => entry.type === "r2_bucket" && entry.logicalName === logicalName);
344
- case "kv": return lookupResource(ctx, kind, logicalName, field, fieldPath, (entry) => entry.type === "kv_namespace" && entry.logicalName === logicalName);
345
- case "queue": return lookupResource(ctx, kind, logicalName, field, fieldPath, (entry) => entry.type === "queue" && entry.logicalName === logicalName);
346
- case "hyperdrive": return lookupResource(ctx, kind, logicalName, field, fieldPath, (entry) => entry.type === "hyperdrive" && entry.logicalName === logicalName);
347
- case "vectorize": return lookupResource(ctx, kind, logicalName, field, fieldPath, (entry) => entry.type === "vectorize" && entry.logicalName === logicalName);
348
- case "ai_gateway": return lookupResource(ctx, kind, logicalName, field, fieldPath, (entry) => entry.type === "ai_gateway" && entry.logicalName === logicalName);
349
- case "pipeline": return lookupResource(ctx, kind, logicalName, field, fieldPath, (entry) => entry.type === "pipeline" && entry.logicalName === logicalName);
350
- case "workflow": return lookupResource(ctx, kind, logicalName, field, fieldPath, (entry) => entry.type === "workflow" && entry.logicalName === logicalName);
351
- case "secret_store": return lookupResource(ctx, kind, logicalName, field, fieldPath, (entry) => entry.type === "secrets_store" && entry.logicalName === logicalName);
352
- case "dispatch_namespace": return lookupDispatchNamespace(ctx, logicalName, field, fieldPath);
353
- case "worker": return lookupWorker(ctx, logicalName, field, fieldPath);
354
- case "import": return lookupImport(ctx, logicalName, field, fieldPath);
355
- case "logpush_pipelines": return lookupLogpushPipelines(ctx, logicalName, field, fieldPath);
356
- case "config": return lookupConfigField(ctx, logicalName, field, fieldPath);
357
- default: throw new TamerReferenceError(`Unknown reference kind "${kind}" — expected one of d1 | r2 | kv | queue | hyperdrive | vectorize | ai_gateway | pipeline | workflow | secret_store | dispatch_namespace | worker | import | logpush_pipelines | config`, fieldPath);
358
- }
359
- }
360
- function lookupConfigField(ctx, _logicalName, field, fieldPath) {
361
- if (field === "account_id") {
362
- const id = (ctx.accountId ?? ctx.config.account_id ?? "").trim();
363
- if (!id) throw new TamerReferenceError(`Reference \${tamer:config:stack.account_id} needs the stack Cloudflare account id — set top-level account_id in tamer/project.config.ts or pass CLOUDFLARE_ACCOUNT_ID when running tamer.`, fieldPath);
364
- return id;
365
- }
366
- throw new TamerReferenceError(`Unknown field "${field}" on config reference — expected account_id`, fieldPath);
367
- }
368
- function getLogpushPipelinesEntry(ctx, logicalName, fieldPath) {
369
- const all = ctx.state.getAll();
370
- const entry = Object.values(all).find((e) => e.type === "logpush_pipelines" && e.logicalName === logicalName);
371
- if (!entry) throw new TamerReferenceError(`Reference \${tamer:logpush_pipelines:${logicalName}.…} cannot be resolved — no pipelines graph in state for logpush job "${logicalName}". Run a full \`tamer apply\` (including the Logpush / pipelinesAuto step) for env "${ctx.env}" first.`, fieldPath);
372
- return entry;
373
- }
374
- /**
375
- * Exposes fields from the `logpush_pipelines:*` D1 state row (after
376
- * `ensurePipelinesLogpushProvision` has run) for `outputs` and `vars`, e.g.
377
- * `${tamer:logpush_pipelines:workers-trace.r2_data_catalog_table_name}`.
378
- */
379
- function lookupLogpushPipelines(ctx, logicalName, field, fieldPath) {
380
- const entry = getLogpushPipelinesEntry(ctx, logicalName, fieldPath);
381
- switch (field) {
382
- case "r2_data_catalog_table_name":
383
- case "iceberg_table": {
384
- const v = entry.r2DataCatalogTableName?.trim();
385
- if (!v) throw new TamerReferenceError(`logpush_pipelines state for "${logicalName}" has no r2DataCatalogTableName (sink not yet created, or pre-upgrade state). Re-run a full \`tamer apply\` for env "${ctx.env}" after pipelinesAuto provisions the sink, or set table manually in consuming stack.`, fieldPath);
386
- return v;
387
- }
388
- case "r2_data_catalog_table_name_pipelines":
389
- case "iceberg_table_pipelines": {
390
- const v = entry.r2DataCatalogTableNamePipelines?.trim();
391
- if (v) return v;
392
- const fallback = entry.r2DataCatalogTableName?.trim();
393
- if (!fallback) throw new TamerReferenceError(`logpush_pipelines state for "${logicalName}" has no table name (sink not yet created). Re-run \`tamer apply\` for env "${ctx.env}".`, fieldPath);
394
- return fallback;
395
- }
396
- case "r2_data_catalog_namespace":
397
- case "iceberg_namespace": return (entry.r2DataCatalogNamespace ?? "default").trim() || "default";
398
- case "name": return entry.pipelineName;
399
- case "id": return entry.pipelineId;
400
- default: throw new TamerReferenceError(`Unknown field "${field}" on logpush_pipelines reference — expected r2_data_catalog_table_name | r2_data_catalog_table_name_pipelines | r2_data_catalog_namespace | name | id | iceberg_table | iceberg_table_pipelines | iceberg_namespace`, fieldPath);
401
- }
402
- }
403
- /**
404
- * Resolve a `${tamer:import:<stack>.<output>}` against pre-fetched sibling
405
- * stack outputs. The pre-fetch (`fetchStackImports`) loads every imported
406
- * stack's `cfi_state:{stack}` row before resolution begins; this lookup is
407
- * pure map access. Throws if the stack isn't in `ctx.imports` (config
408
- * never declared it / pre-fetch wasn't wired in for this command) or if
409
- * the named output hasn't been published yet (sibling stack hasn't run
410
- * `apply` since the output was declared, or has been destroyed).
411
- */
412
- function lookupImport(ctx, stackName, outputName, fieldPath) {
413
- const imports = ctx.imports;
414
- if (!imports || !(stackName in imports)) throw new TamerReferenceError(`Reference \${tamer:import:${stackName}.${outputName}} cannot be resolved — no imported stack "${stackName}" available. Ensure stack "${stackName}" exists in env "${ctx.env}" (run 'tamer apply' there first) and that the current command pre-fetches sibling stacks.`, fieldPath);
415
- const stackOutputs = imports[stackName];
416
- if (!(outputName in stackOutputs)) {
417
- const available = Object.keys(stackOutputs).sort();
418
- throw new TamerReferenceError(`Reference \${tamer:import:${stackName}.${outputName}} cannot be resolved — output "${outputName}" not found on imported stack "${stackName}".${available.length > 0 ? ` Available outputs on stack "${stackName}": ${available.join(", ")}.` : ` Stack "${stackName}" has no published outputs — run 'tamer apply' there with an \`outputs:\` block.`}`, fieldPath);
419
- }
420
- return stackOutputs[outputName];
421
- }
422
- function lookupResource(ctx, kind, logicalName, field, fieldPath, predicate) {
423
- const all = ctx.state.getAll();
424
- const entry = Object.values(all).find(predicate);
425
- if (!entry) throw new TamerReferenceError(`Reference \${tamer:${kind}:${logicalName}.${field}} cannot be resolved — no ${kind} resource named "${logicalName}" in state. Run 'tamer apply --env ${ctx.env}' first.`, fieldPath);
426
- switch (field) {
427
- case "name": return resourceName(entry);
428
- case "id": return resourceId(entry, kind, logicalName, fieldPath);
429
- case "binding": return resourceBinding(entry);
430
- default: throw new TamerReferenceError(`Unknown field "${field}" on ${kind} reference — expected name | id | binding`, fieldPath);
431
- }
432
- }
433
- function resourceName(entry) {
434
- switch (entry.type) {
435
- case "d1_database":
436
- case "kv_namespace":
437
- case "queue":
438
- case "hyperdrive":
439
- case "vectorize":
440
- case "ai_gateway":
441
- case "pipeline":
442
- case "workflow":
443
- case "secrets_store":
444
- case "dispatch_namespace":
445
- case "r2_bucket": return entry.derivedName;
446
- case "dns_record": return entry.name;
447
- case "logpush_job": return entry.derivedName;
448
- case "logpush_pipelines": return entry.pipelineName;
449
- case "worker_route": return entry.pattern;
450
- }
451
- }
452
- function resourceId(entry, kind, logicalName, fieldPath) {
453
- switch (entry.type) {
454
- case "d1_database":
455
- case "kv_namespace":
456
- case "queue":
457
- case "hyperdrive":
458
- case "vectorize":
459
- case "ai_gateway":
460
- case "pipeline":
461
- case "workflow":
462
- case "secrets_store": return entry.cfId;
463
- case "r2_bucket": throw new TamerReferenceError(`R2 bucket "${logicalName}" has no .id (R2 buckets are addressed by name); use \${tamer:${kind}:${logicalName}.name}`, fieldPath);
464
- case "dispatch_namespace": return entry.derivedName;
465
- case "dns_record": return entry.recordId;
466
- case "logpush_job": return String(entry.cfJobId);
467
- case "logpush_pipelines": return entry.pipelineId;
468
- case "worker_route": return entry.routeId;
469
- }
470
- }
471
- function resourceBinding(entry) {
472
- switch (entry.type) {
473
- case "d1_database":
474
- case "r2_bucket":
475
- case "kv_namespace":
476
- case "queue":
477
- case "hyperdrive":
478
- case "vectorize":
479
- case "ai_gateway":
480
- case "pipeline":
481
- case "workflow":
482
- case "secrets_store": return entry.bindingKey;
483
- case "dispatch_namespace": return entry.derivedName;
484
- case "dns_record": throw new Error("internal: dns_record has no .binding — use .name or .id in config references");
485
- case "logpush_job": throw new Error("internal: logpush_job has no .binding — use .name or .id in config references");
486
- case "logpush_pipelines": throw new Error("internal: logpush_pipelines has no .binding — use .name or .id in config references");
487
- case "worker_route": return entry.routeId;
488
- }
489
- }
490
- function lookupDispatchNamespace(ctx, logicalName, field, fieldPath) {
491
- if (!getDispatchNamespaces(ctx.config).find((d) => d.logicalName === logicalName)) throw new TamerReferenceError(`Reference \${tamer:dispatch_namespace:${logicalName}.${field}} cannot be resolved — no dispatchNamespaces entry named "${logicalName}" in the Tamer project config`, fieldPath);
492
- if (field !== "name" && field !== "id") throw new TamerReferenceError(`Unknown field "${field}" on dispatch_namespace reference — expected name | id`, fieldPath);
493
- const all = ctx.state.getAll();
494
- const stateEntry = Object.values(all).find((e) => e.type === "dispatch_namespace" && e.logicalName === logicalName);
495
- if (!stateEntry || stateEntry.type !== "dispatch_namespace") throw new TamerReferenceError(`Reference \${tamer:dispatch_namespace:${logicalName}.${field}} unresolved — no state entry. Run 'tamer apply --env ${ctx.env}' first.`, fieldPath);
496
- return stateEntry.derivedName;
497
- }
498
- function lookupWorker(ctx, workerKey, field, fieldPath) {
499
- let target;
500
- if (ctx.config.workers && ctx.config.workers[workerKey]) target = ctx.config.workers[workerKey];
501
- else if (ctx.config.worker && workerKey === "default") target = ctx.config.worker;
502
- if (!target) throw new TamerReferenceError(`Reference \${tamer:worker:${workerKey}.${field}} cannot be resolved — no worker key "${workerKey}" in the Tamer project config`, fieldPath);
503
- if (field !== "name") throw new TamerReferenceError(`Unknown field "${field}" on worker reference — only "name" is supported (the env-suffixed deployed script name)`, fieldPath);
504
- return resolveDeployedWorkerName(ctx.config, workerKey, target, ctx.env, ctx.naming);
505
- }
506
-
507
- //#endregion
508
- //#region src/core/config/resolver.ts
509
- /** Wrangler script name after env suffix rules (matches `tamer deploy`). */
510
- function resolveDeployedWorkerName(_config, workerKey, workerConfig, env, naming) {
511
- const sn = workerConfig.scriptName?.trim();
512
- if (sn) {
513
- if (env === "local") return sn;
514
- return `${sn}-${env}`;
515
- }
516
- return naming.workerName(workerKey, env);
517
- }
518
- /**
519
- * Map from base service-binding target name (`scriptName` for envs other than
520
- * `local`, or the local-deployed name) → env-suffixed deployed name for every
521
- * worker in `config`. Used to auto-rewrite intra-stack `services[].service`
522
- * fields so fixtures don't have to repeat env overrides for every env.
523
- */
524
- function buildIntraStackScriptNameMap(config, env, naming) {
525
- const map = /* @__PURE__ */ new Map();
526
- if (config.workers) for (const [key, wc] of Object.entries(config.workers)) {
527
- const baseName = wc.scriptName?.trim() ?? naming.workerName(key, "local");
528
- const deployed = resolveDeployedWorkerName(config, key, wc, env, naming);
529
- map.set(baseName, deployed);
530
- }
531
- if (config.worker) {
532
- const w = config.worker;
533
- const baseName = w.scriptName?.trim() ?? naming.workerName("default", "local");
534
- const deployed = resolveDeployedWorkerName(config, "default", w, env, naming);
535
- map.set(baseName, deployed);
536
- }
537
- return map;
538
- }
539
- /** Returns a worker config copy whose `services[].service` is rewritten to env-suffixed deployed names. */
540
- function rewriteIntraStackServiceTargets(workerConfig, baseToDeployed) {
541
- const services = workerConfig.services;
542
- if (!services || services.length === 0) return workerConfig;
543
- let rewroteAny = false;
544
- const rewritten = services.map((s) => {
545
- const target = baseToDeployed.get(s.service);
546
- if (!target || target === s.service) return s;
547
- rewroteAny = true;
548
- return {
549
- ...s,
550
- service: target
551
- };
552
- });
553
- if (!rewroteAny) return workerConfig;
554
- return {
555
- ...workerConfig,
556
- services: rewritten
557
- };
558
- }
559
- function mergeVars(base = {}, override = {}) {
560
- return {
561
- ...base,
562
- ...override
563
- };
564
- }
565
- /** Same env merge as `resolveWorkerConfig` (for deploy topo-sort service edges). */
566
- function mergedWorkerConfigForEnv(workerConfig, env, tenant) {
567
- let merged = { ...workerConfig };
568
- if (env === "local" && workerConfig.local) merged = {
569
- ...merged,
570
- ...workerConfig.local,
571
- vars: mergeVars(workerConfig.vars, workerConfig.local.vars)
572
- };
573
- else if (workerConfig.env?.[env]) {
574
- const envOverride = workerConfig.env[env];
575
- merged = {
576
- ...merged,
577
- ...envOverride,
578
- vars: mergeVars(workerConfig.vars, envOverride.vars)
579
- };
580
- }
581
- const mv = merged.vars;
582
- if (mv && Object.prototype.hasOwnProperty.call(mv, "BRANCH_SUFFIX")) merged = {
583
- ...merged,
584
- vars: {
585
- ...mv,
586
- BRANCH_SUFFIX: isEphemeralEnv(env, tenant) ? env : ""
587
- }
588
- };
589
- return merged;
590
- }
591
- /**
592
- * Align `dispatch_namespaces[].namespace` and `vars.WFP_NAMESPACE` with
593
- * {@link effectiveDispatchNamespaceName} for envs that have no explicit
594
- * `worker.env[env]` block (e.g. `pr-*` shared namespace).
595
- */
596
- function applyDispatchNamespaceEnvOverrides(config, merged, env) {
597
- const dns = getDispatchNamespaces(config);
598
- if (dns.length === 0) return merged;
599
- const resolved = effectiveDispatchNamespaceName(dns[0], env, config.tenant);
600
- const m = merged;
601
- let next = merged;
602
- if (m.dispatch_namespaces?.length) next = {
603
- ...next,
604
- dispatch_namespaces: m.dispatch_namespaces.map((d) => ({
605
- ...d,
606
- namespace: resolved
607
- }))
608
- };
609
- if (m.vars && typeof m.vars.WFP_NAMESPACE === "string" && m.vars.WFP_NAMESPACE === dns[0].namespace) {
610
- const v = next.vars;
611
- next = {
612
- ...next,
613
- vars: {
614
- ...v,
615
- WFP_NAMESPACE: resolved
616
- }
617
- };
618
- }
619
- return next;
620
- }
621
- /**
622
- * Walk the merged worker config and replace `${tamer:<kind>:<logical>.<field>}`
623
- * references in `vars` and `tamerRoutes[].host` / `.zone` against the current
624
- * state snapshot. Also resolves `r2_buckets[].bucket_name`,
625
- * **`services[].service`**, **`dispatch_namespaces[].namespace`**, and
626
- * `resources.d1[].databaseName` when `ownership` is `external`. Throws
627
- * `TamerReferenceError` (with field path) if any
628
- * reference is unresolved — bubbles up to the caller as a fatal.
629
- */
630
- function resolveCrossResourceReferences(merged, ctx) {
631
- const refCtx = {
632
- config: ctx.config,
633
- env: ctx.env,
634
- state: ctx.state,
635
- naming: ctx.naming,
636
- tolerant: ctx.tolerant,
637
- imports: ctx.imports,
638
- accountId: ctx.accountId
639
- };
640
- const m = merged;
641
- let next = merged;
642
- if (m.vars) {
643
- const resolvedVars = resolveReferencesInVars(materializeVars(m.vars), refCtx, `worker[${ctx.workerKey}].vars`);
644
- if (resolvedVars && resolvedVars !== m.vars) next = {
645
- ...next,
646
- vars: resolvedVars
647
- };
648
- }
649
- const tamerRoutes = next.tamerRoutes;
650
- if (tamerRoutes && tamerRoutes.length > 0) {
651
- let mutated = false;
652
- const resolvedRoutes = tamerRoutes.map((r, idx) => {
653
- const fieldBase = `worker[${ctx.workerKey}].tamerRoutes[${idx}]`;
654
- const host = resolveReferencesInString(r.host, refCtx, `${fieldBase}.host`);
655
- const zone = r.zone ? resolveReferencesInString(r.zone, refCtx, `${fieldBase}.zone`) : r.zone;
656
- if (host !== r.host || zone !== r.zone) mutated = true;
657
- return {
658
- ...r,
659
- host,
660
- ...zone !== void 0 ? { zone } : {}
661
- };
662
- });
663
- if (mutated) next = {
664
- ...next,
665
- tamerRoutes: resolvedRoutes
666
- };
667
- }
668
- const r2Buckets = next.r2_buckets;
669
- if (r2Buckets && r2Buckets.length > 0) {
670
- let mutated = false;
671
- const resolvedBuckets = r2Buckets.map((b, idx) => {
672
- const raw = b.bucket_name;
673
- if (raw === void 0) return b;
674
- const fieldBase = `worker[${ctx.workerKey}].r2_buckets[${idx}].bucket_name`;
675
- const bucket_name = resolveReferencesInString(materializeTamerResolvable(raw), refCtx, fieldBase);
676
- if (bucket_name !== raw) mutated = true;
677
- return {
678
- ...b,
679
- bucket_name
680
- };
681
- });
682
- if (mutated) next = {
683
- ...next,
684
- r2_buckets: resolvedBuckets
685
- };
686
- }
687
- const svc = next.services;
688
- if (svc && svc.length > 0) {
689
- let mutated = false;
690
- const resolvedSvc = svc.map((s, idx) => {
691
- const raw = s.service;
692
- const fieldBase = `worker[${ctx.workerKey}].services[${idx}].service`;
693
- const service = resolveReferencesInString(materializeTamerResolvable(raw), refCtx, fieldBase);
694
- if (service !== raw) mutated = true;
695
- return {
696
- ...s,
697
- service
698
- };
699
- });
700
- if (mutated) next = {
701
- ...next,
702
- services: resolvedSvc
703
- };
704
- }
705
- const dispatchNsMerged = next.dispatch_namespaces;
706
- if (dispatchNsMerged && dispatchNsMerged.length > 0) {
707
- let mutated = false;
708
- const resolvedDn = dispatchNsMerged.map((d, idx) => {
709
- const raw = d.namespace;
710
- const fieldBase = `worker[${ctx.workerKey}].dispatch_namespaces[${idx}].namespace`;
711
- const namespace = resolveReferencesInString(materializeTamerResolvable(raw), refCtx, fieldBase);
712
- if (namespace !== raw) mutated = true;
713
- return {
714
- ...d,
715
- namespace
716
- };
717
- });
718
- if (mutated) next = {
719
- ...next,
720
- dispatch_namespaces: resolvedDn
721
- };
722
- }
723
- const resBlock = next.resources;
724
- if (resBlock?.d1 && resBlock.d1.length > 0) {
725
- let mutated = false;
726
- const d1Resolved = resBlock.d1.map((d1c, idx) => {
727
- if (d1c.ownership !== "external" || !d1c.databaseName) return d1c;
728
- const fieldBase = `worker[${ctx.workerKey}].resources.d1[${idx}].databaseName`;
729
- const databaseName = resolveReferencesInString(materializeTamerResolvable(d1c.databaseName), refCtx, fieldBase);
730
- if (databaseName !== d1c.databaseName) mutated = true;
731
- return {
732
- ...d1c,
733
- databaseName
734
- };
735
- });
736
- if (mutated) next = {
737
- ...next,
738
- resources: {
739
- ...resBlock,
740
- d1: d1Resolved
741
- }
742
- };
743
- }
744
- return next;
745
- }
746
- function stripTamerFields(config) {
747
- const { path, config: configPath, resources, local, env, scriptName: _scriptName, wranglerOutFile: _out, dispatchNamespace: _dispatchNs, tamerRoutes: _tamerRoutes, tamerStaleRouteSweepZones: _tamerStaleRouteSweepZones, ...rest } = config;
748
- return rest;
749
- }
750
- /**
751
- * Env merge + intra-stack `services` rewrite + sibling-stack resolution for
752
- * **`resources.d1[].databaseName` only** when `ownership: "external"`.
753
- *
754
- * Use before {@link ResourceModule.pickResources} during `apply` / `sync` /
755
- * `drift` so imported D1 names are known **without** resolving worker `vars`
756
- * (those references often need resources created earlier in the same `apply`).
757
- */
758
- function mergeWorkerConfigForResourcePick(config, workerKey, workerConfig, env, accountId, naming, state, opts = {}) {
759
- let merged = mergedWorkerConfigForEnv(workerConfig, env, config.tenant);
760
- merged = applyDispatchNamespaceEnvOverrides(config, merged, env);
761
- const intraMap = buildIntraStackScriptNameMap(config, env, naming);
762
- merged = rewriteIntraStackServiceTargets(merged, intraMap);
763
- const refCtx = {
764
- config,
765
- env,
766
- state,
767
- naming,
768
- tolerant: opts.referencesMode === "tolerant",
769
- imports: opts.imports,
770
- accountId
771
- };
772
- const resBlock = merged.resources;
773
- if (!resBlock?.d1?.length) return merged;
774
- const d1Resolved = resBlock.d1.map((d1c, idx) => {
775
- if (d1c.ownership !== "external" || !d1c.databaseName) return d1c;
776
- const fieldBase = `worker[${workerKey}].resources.d1[${idx}].databaseName`;
777
- const databaseName = resolveReferencesInString(materializeTamerResolvable(d1c.databaseName), refCtx, fieldBase);
778
- return {
779
- ...d1c,
780
- databaseName
781
- };
782
- });
783
- return {
784
- ...merged,
785
- resources: {
786
- ...resBlock,
787
- d1: d1Resolved
788
- }
789
- };
790
- }
791
- /**
792
- * Env-merged worker config with every `${tamer:…}` site resolved for wrangler
793
- * (`vars`, `tamerRoutes`, `r2_buckets[].bucket_name`, external D1 names).
794
- * Used by {@link resolveWorkerConfig} after resource state is up to date.
795
- */
796
- function mergeWorkerConfigWithResolvedRefs(config, workerKey, workerConfig, env, accountId, naming, state, opts = {}) {
797
- let merged = mergedWorkerConfigForEnv(workerConfig, env, config.tenant);
798
- merged = applyDispatchNamespaceEnvOverrides(config, merged, env);
799
- const intraMap = buildIntraStackScriptNameMap(config, env, naming);
800
- merged = rewriteIntraStackServiceTargets(merged, intraMap);
801
- return resolveCrossResourceReferences(merged, {
802
- config,
803
- env,
804
- state,
805
- naming,
806
- workerKey,
807
- tolerant: opts.referencesMode === "tolerant",
808
- imports: opts.imports,
809
- accountId
810
- });
811
- }
812
- async function resolveWorkerConfig(config, workerKey, workerConfig, env, baseDir, accountId, naming, state, opts = {}) {
813
- const merged = mergeWorkerConfigWithResolvedRefs(config, workerKey, workerConfig, env, accountId, naming, state, opts);
814
- const workerDir = workerConfig.path ? resolve(baseDir, workerConfig.path) : baseDir;
815
- const m = merged;
816
- const workerName = resolveDeployedWorkerName(config, workerKey, merged, env, naming);
817
- const wranglerOutFile = assertSafeWranglerOutFile(m.wranglerOutFile?.trim() || "wrangler.json");
818
- const dispatchNamespace = m.dispatchNamespace?.trim() || void 0;
819
- const stripped = stripTamerFields(merged);
820
- const tamerRoutes = merged.tamerRoutes;
821
- const expandedRoutes = effectiveRoutesForEnv(tamerRoutes, env);
822
- const apiManagedRoutes = expandedRoutes.filter(isApiManagedZoneRoute);
823
- const wranglerTamerRoutes = expandedRoutes.filter(isWranglerOnlyTamerRoute);
824
- const mergedRoutes = [...stripped.routes ?? [], ...wranglerTamerRoutes];
825
- /** Non-local deploys emit `routes: []` when there are none — omitting `routes` can leave stale Wrangler-published custom domains attached from a prior config. */
826
- const wranglerRoutes = mergedRoutes.length > 0 ? mergedRoutes : env === "local" ? void 0 : [];
827
- return {
828
- workerKey,
829
- workerName,
830
- workerDir,
831
- env,
832
- wranglerOutFile,
833
- dispatchNamespace,
834
- wranglerConfig: {
835
- ...stripped,
836
- ...wranglerRoutes !== void 0 ? { routes: wranglerRoutes } : {},
837
- name: workerName,
838
- account_id: accountId,
839
- compatibility_date: stripped.compatibility_date ?? config.compatibility_date
840
- },
841
- resources: merged.resources ?? workerConfig.resources ?? {},
842
- apiManagedRoutes
843
- };
1
+ import { B as getWorkers } from "./tamer.mjs";
2
+ import { n as r2S3CredentialsFromEnv, t as emptyR2BucketViaS3 } from "./r2S3EmptyBucket-B9_pHfvB.mjs";
3
+ import { n as logApplyChange } from "./planFormat-5XMJK879.mjs";
4
+
5
+ //#region src/core/naming/resolveCloudflareName.ts
6
+ function resolveOverride(fn, tenantId, env, ctx) {
7
+ if (!fn) return void 0;
8
+ return fn(tenantId, env, ctx);
9
+ }
10
+ /** Managed D1 Cloudflare database name (not external `databaseName`). */
11
+ function resolveD1CloudflareName(config, env, naming, shardDate) {
12
+ const tenantId = naming.tenantId;
13
+ if (config.type === "single") {
14
+ const override$1 = resolveOverride(config.cloudflareName, tenantId, env);
15
+ if (override$1 !== void 0) return override$1;
16
+ return naming.d1SingleName(config.logicalName, env);
17
+ }
18
+ if (!shardDate) throw new Error(`Sharded D1 "${config.logicalName}" requires shardDate`);
19
+ const override = resolveOverride(config.cloudflareName, tenantId, env, { shardDate });
20
+ if (override !== void 0) return override;
21
+ return naming.d1ShardName(config.logicalName, shardDate, env);
22
+ }
23
+ function resolveR2CloudflareName(config, env, naming) {
24
+ const override = resolveOverride(config.cloudflareName, naming.tenantId, env);
25
+ if (override !== void 0) return override;
26
+ return naming.r2BucketName(config.logicalName, env);
27
+ }
28
+ function resolveWorkflowCloudflareName(config, env, naming) {
29
+ const override = resolveOverride(config.cloudflareName, naming.tenantId, env);
30
+ if (override !== void 0) return override;
31
+ return naming.workflowName(config.logicalName, env);
32
+ }
33
+ function resolveKVCloudflareName(config, env, naming) {
34
+ const override = resolveOverride(config.cloudflareName, naming.tenantId, env);
35
+ if (override !== void 0) return override;
36
+ return naming.kvNamespaceName(config.logicalName, env);
37
+ }
38
+ function resolveQueueCloudflareName(config, env, naming) {
39
+ const override = resolveOverride(config.cloudflareName, naming.tenantId, env);
40
+ if (override !== void 0) return override;
41
+ return naming.queueName(config.logicalName, env);
42
+ }
43
+ function resolveHyperdriveCloudflareName(config, env, naming) {
44
+ const override = resolveOverride(config.cloudflareName, naming.tenantId, env);
45
+ if (override !== void 0) return override;
46
+ return naming.hyperdriveName(config.logicalName, env);
47
+ }
48
+ function resolveVectorizeCloudflareName(config, env, naming) {
49
+ const override = resolveOverride(config.cloudflareName, naming.tenantId, env);
50
+ if (override !== void 0) return override;
51
+ return naming.vectorizeName(config.logicalName, env);
52
+ }
53
+ function resolveAIGatewayCloudflareName(config, env, naming) {
54
+ const override = resolveOverride(config.cloudflareName, naming.tenantId, env);
55
+ if (override !== void 0) return override;
56
+ return naming.aiGatewayId(config.logicalName, env);
57
+ }
58
+ function resolvePipelineCloudflareName(config, env, naming) {
59
+ const override = resolveOverride(config.cloudflareName, naming.tenantId, env);
60
+ if (override !== void 0) return override;
61
+ return naming.pipelineName(config.logicalName, env);
62
+ }
63
+ function resolveSecretsStoreCloudflareName(config, env, naming) {
64
+ const override = resolveOverride(config.cloudflareName, naming.tenantId, env);
65
+ if (override !== void 0) return override;
66
+ return naming.secretsStoreName(config.logicalName, env);
844
67
  }
845
68
 
846
69
  //#endregion
@@ -863,7 +86,34 @@ function d1CloudflareDatabaseName(config, env, naming) {
863
86
  if (typeof n !== "string" || !n.trim()) throw new Error(`D1 "${config.logicalName}" has ownership "external" but databaseName is empty — ensure imports are pre-fetched and config is merged with resolveWorkerConfig / mergeWorkerConfigWithResolvedRefs.`);
864
87
  return n.trim();
865
88
  }
866
- return naming.d1SingleName(config.logicalName, env);
89
+ return resolveD1CloudflareName(config, env, naming);
90
+ }
91
+
92
+ //#endregion
93
+ //#region src/features/d1/d1.naming.ts
94
+ function d1DeriveName(config, env, shardDate, naming) {
95
+ if (config.type === "single") return resolveD1CloudflareName(config, env, naming);
96
+ if (!shardDate) throw new Error(`Sharded D1 "${config.logicalName}" requires shardDate`);
97
+ return resolveD1CloudflareName(config, env, naming, shardDate);
98
+ }
99
+ function d1MatchPattern(config, env, naming) {
100
+ if (config.type === "single") {
101
+ const exactName = resolveD1CloudflareName(config, env, naming);
102
+ return (name) => name === exactName;
103
+ }
104
+ if (config.cloudflareName || naming.hasD1ShardConvention()) return (name) => {
105
+ const shardDate = d1ExtractShardDate(name, naming);
106
+ if (!shardDate) return false;
107
+ try {
108
+ return resolveD1CloudflareName(config, env, naming, shardDate) === name;
109
+ } catch {
110
+ return false;
111
+ }
112
+ };
113
+ return naming.d1MatchPattern(config.logicalName, env);
114
+ }
115
+ function d1ExtractShardDate(name, naming) {
116
+ return naming.extractD1ShardDate(name);
867
117
  }
868
118
 
869
119
  //#endregion
@@ -900,7 +150,7 @@ async function d1Apply(resources, tenant, env, api, state, naming, addShard) {
900
150
  if (addShard && addShard !== config.logicalName) continue;
901
151
  if (addShard && addShard === config.logicalName) {
902
152
  const shardDate$1 = todayNoDashes();
903
- const derivedName$1 = naming.d1ShardName(config.logicalName, shardDate$1, env);
153
+ const derivedName$1 = d1DeriveName(config, env, shardDate$1, naming);
904
154
  if (state.get(derivedName$1)) continue;
905
155
  const { uuid: uuid$1 } = await api.d1Create(derivedName$1);
906
156
  state.set(derivedName$1, {
@@ -919,7 +169,7 @@ async function d1Apply(resources, tenant, env, api, state, naming, addShard) {
919
169
  const allResources = state.getAll();
920
170
  if (Object.values(allResources).filter((e) => e.type === "d1_database" && "logicalName" in e && e.logicalName === config.logicalName).length > 0) continue;
921
171
  const shardDate = todayNoDashes();
922
- const derivedName = naming.d1ShardName(config.logicalName, shardDate, env);
172
+ const derivedName = d1DeriveName(config, env, shardDate, naming);
923
173
  const { uuid } = await api.d1Create(derivedName);
924
174
  state.set(derivedName, {
925
175
  type: "d1_database",
@@ -935,19 +185,6 @@ async function d1Apply(resources, tenant, env, api, state, naming, addShard) {
935
185
  }
936
186
  }
937
187
 
938
- //#endregion
939
- //#region src/features/d1/d1.naming.ts
940
- function d1MatchPattern(config, env, naming) {
941
- if (config.type === "single") {
942
- const exactName = naming.d1SingleName(config.logicalName, env);
943
- return (name) => name === exactName;
944
- }
945
- return naming.d1MatchPattern(config.logicalName, env);
946
- }
947
- function d1ExtractShardDate(name, naming) {
948
- return naming.extractD1ShardDate(name);
949
- }
950
-
951
188
  //#endregion
952
189
  //#region src/features/d1/d1.sync.ts
953
190
  function d1Sync(allD1, resources, tenant, env, state, naming) {
@@ -1024,7 +261,7 @@ function d1Drift(allD1, resources, env, state, naming) {
1024
261
  });
1025
262
  continue;
1026
263
  }
1027
- const pattern = naming.d1MatchPattern(config.logicalName, env);
264
+ const pattern = d1MatchPattern(config, env, naming);
1028
265
  const cfShards = allD1.filter((db) => pattern(db.name));
1029
266
  const cfShardNames = new Set(cfShards.map((s) => s.name));
1030
267
  const stateShards = d1State.filter((e) => e.logicalName === config.logicalName && !!e.shardDate);
@@ -1175,6 +412,22 @@ function resourcesFrom(source) {
1175
412
  return source;
1176
413
  }
1177
414
 
415
+ //#endregion
416
+ //#region src/core/registry/findResourceForImport.ts
417
+ /**
418
+ * Find the first declared resource config matching `logical` across all workers.
419
+ * Used by `tamer import` to validate CF names against {@link cloudflareName} overrides.
420
+ */
421
+ async function findWorkerResourceByLogicalName(config, configKey, logical, baseDir) {
422
+ const workers = await getWorkers(config, baseDir);
423
+ for (const [, wc] of workers) {
424
+ const list = wc.resources?.[configKey];
425
+ if (!list) continue;
426
+ const hit = list.find((r) => r.logicalName === logical);
427
+ if (hit) return hit;
428
+ }
429
+ }
430
+
1178
431
  //#endregion
1179
432
  //#region src/features/d1/d1.module.ts
1180
433
  const d1Module = {
@@ -1217,11 +470,13 @@ const d1Module = {
1217
470
  console.warn(`Rollback: failed to delete D1 ${entry.derivedName}:`, err);
1218
471
  }
1219
472
  },
1220
- async importOne({ options, env, api, state, naming, ts }) {
473
+ async importOne({ options, env, api, state, naming, config, baseDir, ts }) {
1221
474
  if (!options.cfId) throw new Error("import d1: --cf-id <uuid> is required");
475
+ const resourceConfig = await findWorkerResourceByLogicalName(config, "d1", options.logical, baseDir);
476
+ if (!resourceConfig) throw new Error(`import d1: no resources.d1 entry with logicalName "${options.logical}" in the Tamer project config`);
1222
477
  const hit = (await api.d1ListAll()).find((d) => d.uuid === options.cfId);
1223
478
  if (!hit) throw new Error(`import d1: D1 database with uuid "${options.cfId}" not found in account`);
1224
- const derivedName = options.shardDate ? naming.d1ShardName(options.logical, options.shardDate, env) : naming.d1SingleName(options.logical, env);
479
+ const derivedName = options.shardDate ? d1DeriveName(resourceConfig, env, options.shardDate, naming) : d1DeriveName(resourceConfig, env, void 0, naming);
1225
480
  if (hit.name !== derivedName) throw new Error(`import d1: cf name "${hit.name}" does not match derived "${derivedName}" — wrong --logical, missing --shard-date, or naming convention drift?`);
1226
481
  const bindingKey = options.shardDate ? naming.d1ShardBindingKey(options.logical, options.shardDate) : naming.d1SingleBindingKey(options.logical);
1227
482
  const existing = state.get(derivedName);
@@ -1240,6 +495,22 @@ const d1Module = {
1240
495
  }
1241
496
  };
1242
497
 
498
+ //#endregion
499
+ //#region src/features/r2/r2.naming.ts
500
+ function r2DeriveName(config, env, naming) {
501
+ return resolveR2CloudflareName(config, env, naming);
502
+ }
503
+ function r2MatchPattern(config, env, naming) {
504
+ if (config.cloudflareName) {
505
+ const expected = resolveR2CloudflareName(config, env, naming);
506
+ return (name) => name === expected;
507
+ }
508
+ return naming.r2MatchPattern(config.logicalName, env);
509
+ }
510
+ function r2ExtractDate(name, naming) {
511
+ return naming.extractR2Date(name);
512
+ }
513
+
1243
514
  //#endregion
1244
515
  //#region src/features/r2/r2.apply.ts
1245
516
  function existingR2ForLogical(state, logicalName) {
@@ -1257,7 +528,7 @@ function assertValidR2BucketName(name, logicalName) {
1257
528
  }
1258
529
  async function r2Apply(resources, tenant, env, api, state, naming) {
1259
530
  for (const config of resources) {
1260
- const derivedName = naming.r2BucketName(config.logicalName, env);
531
+ const derivedName = r2DeriveName(config, env, naming);
1261
532
  if (state.get(derivedName)) {
1262
533
  console.log(`R2: skip "${derivedName}" (already in state; logical "${config.logicalName}")`);
1263
534
  continue;
@@ -1282,17 +553,11 @@ async function r2Apply(resources, tenant, env, api, state, naming) {
1282
553
  }
1283
554
  }
1284
555
 
1285
- //#endregion
1286
- //#region src/features/r2/r2.naming.ts
1287
- function r2ExtractDate(name, naming) {
1288
- return naming.extractR2Date(name);
1289
- }
1290
-
1291
556
  //#endregion
1292
557
  //#region src/features/r2/r2.sync.ts
1293
558
  function r2Sync(allR2, resources, tenant, env, state, naming) {
1294
559
  for (const config of resources) {
1295
- const pattern = naming.r2MatchPattern(config.logicalName, env);
560
+ const pattern = r2MatchPattern(config, env, naming);
1296
561
  const match = allR2.find((b) => pattern(b.name));
1297
562
  if (match) {
1298
563
  const createdDate = r2ExtractDate(match.name, naming) ?? match.creation_date.slice(0, 10);
@@ -1329,7 +594,7 @@ function r2Drift(allR2, resources, env, state, naming) {
1329
594
  const allState = state.getAll();
1330
595
  const r2State = Object.values(allState).filter((e) => e.type === "r2_bucket");
1331
596
  for (const config of resources) {
1332
- const pattern = naming.r2MatchPattern(config.logicalName, env);
597
+ const pattern = r2MatchPattern(config, env, naming);
1333
598
  const cfMatch = allR2.find((b) => pattern(b.name));
1334
599
  const stateEntry = r2State.find((e) => e.logicalName === config.logicalName);
1335
600
  if (stateEntry && !cfNames.has(stateEntry.derivedName)) {
@@ -1407,7 +672,7 @@ function r2Status(resources, env, state, naming) {
1407
672
  const entry = Object.values(allResources).find((e) => e.type === "r2_bucket" && e.logicalName === config.logicalName);
1408
673
  results.push({
1409
674
  binding: entry?.bindingKey ?? naming.r2BindingKey(config.logicalName),
1410
- name: entry?.derivedName ?? naming.r2BucketName(config.logicalName, env),
675
+ name: entry?.derivedName ?? r2DeriveName(config, env, naming),
1411
676
  status: entry ? "ok" : "missing"
1412
677
  });
1413
678
  }
@@ -1455,12 +720,14 @@ const r2Module = {
1455
720
  console.warn(`Rollback: failed to delete R2 ${entry.derivedName}:`, err);
1456
721
  }
1457
722
  },
1458
- async importOne({ options, env, api, state, naming, ts }) {
723
+ async importOne({ options, env, api, state, naming, config, baseDir, ts }) {
1459
724
  const bucketName = options.cfId;
1460
725
  if (!bucketName) throw new Error("import r2: --cf-id <bucket-name> is required");
726
+ const resourceConfig = await findWorkerResourceByLogicalName(config, "r2", options.logical, baseDir);
727
+ if (!resourceConfig) throw new Error(`import r2: no resources.r2 entry with logicalName "${options.logical}" in the Tamer project config`);
1461
728
  const hit = (await api.r2ListAll()).find((b) => b.name === bucketName);
1462
729
  if (!hit) throw new Error(`import r2: bucket "${bucketName}" not found in account`);
1463
- if (!naming.r2MatchPattern(options.logical, env)(hit.name)) throw new Error(`import r2: bucket name "${hit.name}" does not match expected pattern for logical "${options.logical}" and env "${env}"`);
730
+ if (!r2MatchPattern(resourceConfig, env, naming)(hit.name)) throw new Error(`import r2: bucket name "${hit.name}" does not match expected pattern for logical "${options.logical}" and env "${env}"`);
1464
731
  const derivedName = hit.name;
1465
732
  const createdDate = options.createdDate ?? naming.extractR2Date(hit.name) ?? hit.creation_date.slice(0, 10);
1466
733
  const bindingKey = naming.r2BindingKey(options.logical);
@@ -1478,11 +745,17 @@ const r2Module = {
1478
745
  }
1479
746
  };
1480
747
 
748
+ //#endregion
749
+ //#region src/features/kv/kv.naming.ts
750
+ function kvDeriveName(config, env, naming) {
751
+ return resolveKVCloudflareName(config, env, naming);
752
+ }
753
+
1481
754
  //#endregion
1482
755
  //#region src/features/kv/kv.apply.ts
1483
756
  async function kvApply(resources, tenant, env, api, state, naming) {
1484
757
  for (const config of resources) {
1485
- const derivedName = naming.kvNamespaceName(config.logicalName, env);
758
+ const derivedName = kvDeriveName(config, env, naming);
1486
759
  if (state.get(derivedName)) continue;
1487
760
  const { id } = await api.kvCreate(derivedName);
1488
761
  state.set(derivedName, {
@@ -1501,7 +774,7 @@ async function kvApply(resources, tenant, env, api, state, naming) {
1501
774
  //#region src/features/kv/kv.sync.ts
1502
775
  function kvSync(allKV, resources, tenant, env, state, naming) {
1503
776
  for (const config of resources) {
1504
- const derivedName = naming.kvNamespaceName(config.logicalName, env);
777
+ const derivedName = kvDeriveName(config, env, naming);
1505
778
  const match = allKV.find((ns) => ns.title === derivedName);
1506
779
  if (match) state.set(derivedName, {
1507
780
  type: "kv_namespace",
@@ -1528,7 +801,7 @@ function kvDrift(allKV, resources, env, state, naming) {
1528
801
  const allState = state.getAll();
1529
802
  const kvState = Object.values(allState).filter((e) => e.type === "kv_namespace");
1530
803
  for (const config of resources) {
1531
- const derivedName = naming.kvNamespaceName(config.logicalName, env);
804
+ const derivedName = kvDeriveName(config, env, naming);
1532
805
  const cfId = cfByTitle.get(derivedName);
1533
806
  const stateEntry = kvState.find((e) => e.logicalName === config.logicalName);
1534
807
  if (stateEntry && !cfId) drift.missingFromCloudflare.push({
@@ -1571,7 +844,7 @@ async function kvDestroy(_env, state, api, config, baseDir, _force) {
1571
844
  function kvGenerate(resources, env, state, naming) {
1572
845
  const bindings = [];
1573
846
  for (const config of resources) {
1574
- const derivedName = naming.kvNamespaceName(config.logicalName, env);
847
+ const derivedName = kvDeriveName(config, env, naming);
1575
848
  const entry = state.get(derivedName);
1576
849
  if (!entry || entry.type !== "kv_namespace") throw new Error(`KV "${config.logicalName}" not in state. Run 'tamer apply --env ${env}' first.`);
1577
850
  bindings.push({
@@ -1587,7 +860,7 @@ function kvGenerate(resources, env, state, naming) {
1587
860
  function kvStatus(resources, env, state, naming) {
1588
861
  const results = [];
1589
862
  for (const config of resources) {
1590
- const derivedName = naming.kvNamespaceName(config.logicalName, env);
863
+ const derivedName = kvDeriveName(config, env, naming);
1591
864
  const entry = state.get(derivedName);
1592
865
  results.push({
1593
866
  binding: naming.kvBindingKey(config.logicalName),
@@ -1642,11 +915,13 @@ const kvModule = {
1642
915
  console.warn(`Rollback: failed to delete KV ${entry.derivedName}:`, err);
1643
916
  }
1644
917
  },
1645
- async importOne({ options, env, api, state, naming, ts }) {
918
+ async importOne({ options, env, api, state, naming, config, baseDir, ts }) {
1646
919
  if (!options.cfId) throw new Error("import kv: --cf-id <namespace-id> is required");
920
+ const resourceConfig = await findWorkerResourceByLogicalName(config, "kv", options.logical, baseDir);
921
+ if (!resourceConfig) throw new Error(`import kv: no resources.kv entry with logicalName "${options.logical}" in the Tamer project config`);
1647
922
  const hit = (await api.kvListAll()).find((k) => k.id === options.cfId);
1648
923
  if (!hit) throw new Error(`import kv: KV namespace id "${options.cfId}" not found in account`);
1649
- const derivedName = naming.kvNamespaceName(options.logical, env);
924
+ const derivedName = kvDeriveName(resourceConfig, env, naming);
1650
925
  if (hit.title !== derivedName) throw new Error(`import kv: cf title "${hit.title}" does not match derived "${derivedName}"`);
1651
926
  const bindingKey = naming.kvBindingKey(options.logical);
1652
927
  const existing = state.get(derivedName);
@@ -1663,6 +938,12 @@ const kvModule = {
1663
938
  }
1664
939
  };
1665
940
 
941
+ //#endregion
942
+ //#region src/features/queues/queues.naming.ts
943
+ function queueDeriveName(config, env, naming) {
944
+ return resolveQueueCloudflareName(config, env, naming);
945
+ }
946
+
1666
947
  //#endregion
1667
948
  //#region src/features/queues/queues.apply.ts
1668
949
  const STATE_KEY_PREFIX$6 = "queue:";
@@ -1671,7 +952,7 @@ function stateKey$6(derivedName) {
1671
952
  }
1672
953
  async function queuesApply(resources, _tenant, env, api, state, naming) {
1673
954
  for (const config of resources) {
1674
- const derivedName = naming.queueName(config.logicalName, env);
955
+ const derivedName = queueDeriveName(config, env, naming);
1675
956
  const key = stateKey$6(derivedName);
1676
957
  if (state.get(key)) continue;
1677
958
  const ts = (/* @__PURE__ */ new Date()).toISOString();
@@ -1693,7 +974,7 @@ async function queuesApply(resources, _tenant, env, api, state, naming) {
1693
974
  //#region src/features/queues/queues.sync.ts
1694
975
  function queuesSync(allQueues, resources, _tenant, env, state, naming) {
1695
976
  for (const config of resources) {
1696
- const derivedName = naming.queueName(config.logicalName, env);
977
+ const derivedName = queueDeriveName(config, env, naming);
1697
978
  const match = allQueues.find((q) => q.queue_name === derivedName);
1698
979
  if (!match) continue;
1699
980
  const key = `queue:${derivedName}`;
@@ -1724,7 +1005,7 @@ function queuesDrift(allQueues, resources, env, state, naming) {
1724
1005
  const cfByName = new Map(allQueues.map((q) => [q.queue_name, q.queue_id]));
1725
1006
  const stateEntries = Object.values(state.getAll()).filter((e) => e.type === "queue");
1726
1007
  for (const config of resources) {
1727
- const derivedName = naming.queueName(config.logicalName, env);
1008
+ const derivedName = queueDeriveName(config, env, naming);
1728
1009
  const cfId = cfByName.get(derivedName);
1729
1010
  const stateEntry = stateEntries.find((e) => e.logicalName === config.logicalName);
1730
1011
  if (stateEntry && !cfId) drift.missingFromCloudflare.push({
@@ -1773,7 +1054,7 @@ function queuesGenerate(resources, env, state, naming) {
1773
1054
  const producers = [];
1774
1055
  for (const config of resources) {
1775
1056
  if (config.consumerOnly) continue;
1776
- const derivedName = naming.queueName(config.logicalName, env);
1057
+ const derivedName = queueDeriveName(config, env, naming);
1777
1058
  const entry = state.get(`queue:${derivedName}`);
1778
1059
  if (!entry || entry.type !== "queue") throw new Error(`Queue "${config.logicalName}" not in state. Run 'tamer apply --env ${env}' first.`);
1779
1060
  producers.push({
@@ -1790,7 +1071,7 @@ function queuesGenerate(resources, env, state, naming) {
1790
1071
  function queuesStatus(resources, env, state, naming) {
1791
1072
  const out = [];
1792
1073
  for (const config of resources) {
1793
- const derivedName = naming.queueName(config.logicalName, env);
1074
+ const derivedName = queueDeriveName(config, env, naming);
1794
1075
  const entry = state.get(`queue:${derivedName}`);
1795
1076
  out.push({
1796
1077
  binding: config.binding?.trim() || naming.queueBindingKey(config.logicalName),
@@ -1853,11 +1134,13 @@ const queuesModule = {
1853
1134
  console.warn(`Rollback: failed to delete queue ${entry.derivedName}:`, err);
1854
1135
  }
1855
1136
  },
1856
- async importOne({ options, env, api, state, naming, ts }) {
1137
+ async importOne({ options, env, api, state, naming, config, baseDir, ts }) {
1857
1138
  if (!options.cfId) throw new Error("import queue: --cf-id <queue-id> is required");
1139
+ const resourceConfig = await findWorkerResourceByLogicalName(config, "queues", options.logical, baseDir);
1140
+ if (!resourceConfig) throw new Error(`import queue: no resources.queues entry with logicalName "${options.logical}" in the Tamer project config`);
1858
1141
  const hit = (await api.queuesListAll()).find((q) => q.queue_id === options.cfId);
1859
1142
  if (!hit) throw new Error(`import queue: queue id "${options.cfId}" not found in account`);
1860
- const derivedName = naming.queueName(options.logical, env);
1143
+ const derivedName = queueDeriveName(resourceConfig, env, naming);
1861
1144
  if (hit.queue_name !== derivedName) throw new Error(`import queue: cf name "${hit.queue_name}" does not match derived "${derivedName}"`);
1862
1145
  const bindingKey = naming.queueBindingKey(options.logical);
1863
1146
  const key = `queue:${derivedName}`;
@@ -1905,13 +1188,19 @@ function resolveHyperdriveOrigin(config) {
1905
1188
  };
1906
1189
  }
1907
1190
 
1191
+ //#endregion
1192
+ //#region src/features/hyperdrive/hyperdrive.naming.ts
1193
+ function hyperdriveDeriveName(config, env, naming) {
1194
+ return resolveHyperdriveCloudflareName(config, env, naming);
1195
+ }
1196
+
1908
1197
  //#endregion
1909
1198
  //#region src/features/hyperdrive/hyperdrive.diff.ts
1910
1199
  function hyperdriveDiffPlanItems(args) {
1911
1200
  const { resources, env, state, naming } = args;
1912
1201
  const items = [];
1913
1202
  for (const config of resources) {
1914
- const derivedName = naming.hyperdriveName(config.logicalName, env);
1203
+ const derivedName = hyperdriveDeriveName(config, env, naming);
1915
1204
  const entry = state.get(`hyperdrive:${derivedName}`);
1916
1205
  if (!entry || entry.type !== "hyperdrive") continue;
1917
1206
  const changes = computeChanges$1(entry, config);
@@ -1970,7 +1259,7 @@ function stateKey$5(derivedName) {
1970
1259
  }
1971
1260
  async function hyperdriveApply(resources, _tenant, env, api, state, naming) {
1972
1261
  for (const config of resources) {
1973
- const derivedName = naming.hyperdriveName(config.logicalName, env);
1262
+ const derivedName = hyperdriveDeriveName(config, env, naming);
1974
1263
  const key = stateKey$5(derivedName);
1975
1264
  const existing = state.get(key);
1976
1265
  const ts = (/* @__PURE__ */ new Date()).toISOString();
@@ -2028,7 +1317,7 @@ async function hyperdriveApply(resources, _tenant, env, api, state, naming) {
2028
1317
  //#region src/features/hyperdrive/hyperdrive.sync.ts
2029
1318
  function hyperdriveSync(allHyperdrive, resources, _tenant, env, state, naming) {
2030
1319
  for (const config of resources) {
2031
- const derivedName = naming.hyperdriveName(config.logicalName, env);
1320
+ const derivedName = hyperdriveDeriveName(config, env, naming);
2032
1321
  const match = allHyperdrive.find((h) => h.name === derivedName);
2033
1322
  if (!match) continue;
2034
1323
  const key = `hyperdrive:${derivedName}`;
@@ -2061,7 +1350,7 @@ function hyperdriveDrift(allHyperdrive, resources, env, state, naming) {
2061
1350
  const cfByName = new Map(allHyperdrive.map((h) => [h.name, h.id]));
2062
1351
  const stateEntries = Object.values(state.getAll()).filter((e) => e.type === "hyperdrive");
2063
1352
  for (const config of resources) {
2064
- const derivedName = naming.hyperdriveName(config.logicalName, env);
1353
+ const derivedName = hyperdriveDeriveName(config, env, naming);
2065
1354
  const cfId = cfByName.get(derivedName);
2066
1355
  const stateEntry = stateEntries.find((e) => e.logicalName === config.logicalName);
2067
1356
  if (stateEntry && !cfId) drift.missingFromCloudflare.push({
@@ -2104,7 +1393,7 @@ async function hyperdriveDestroy(_env, state, api, config, baseDir, _force) {
2104
1393
  function hyperdriveGenerate(resources, env, state, naming) {
2105
1394
  const out = [];
2106
1395
  for (const config of resources) {
2107
- const derivedName = naming.hyperdriveName(config.logicalName, env);
1396
+ const derivedName = hyperdriveDeriveName(config, env, naming);
2108
1397
  const entry = state.get(`hyperdrive:${derivedName}`);
2109
1398
  if (!entry || entry.type !== "hyperdrive") throw new Error(`Hyperdrive "${config.logicalName}" not in state. Run 'tamer apply --env ${env}' first.`);
2110
1399
  out.push({
@@ -2121,7 +1410,7 @@ function hyperdriveGenerate(resources, env, state, naming) {
2121
1410
  function hyperdriveStatus(resources, env, state, naming) {
2122
1411
  const out = [];
2123
1412
  for (const config of resources) {
2124
- const derivedName = naming.hyperdriveName(config.logicalName, env);
1413
+ const derivedName = hyperdriveDeriveName(config, env, naming);
2125
1414
  const entry = state.get(`hyperdrive:${derivedName}`);
2126
1415
  out.push({
2127
1416
  binding: config.binding?.trim() || naming.hyperdriveBindingKey(config.logicalName),
@@ -2187,11 +1476,13 @@ const hyperdriveModule = {
2187
1476
  console.warn(`Rollback: failed to delete Hyperdrive ${entry.derivedName}:`, err);
2188
1477
  }
2189
1478
  },
2190
- async importOne({ options, env, api, state, naming, ts }) {
1479
+ async importOne({ options, env, api, state, naming, config, baseDir, ts }) {
2191
1480
  if (!options.cfId) throw new Error("import hyperdrive: --cf-id <config-id> is required");
1481
+ const resourceConfig = await findWorkerResourceByLogicalName(config, "hyperdrive", options.logical, baseDir);
1482
+ if (!resourceConfig) throw new Error(`import hyperdrive: no resources.hyperdrive entry with logicalName "${options.logical}" in the Tamer project config`);
2192
1483
  const hit = (await api.hyperdriveListAll()).find((h) => h.id === options.cfId);
2193
1484
  if (!hit) throw new Error(`import hyperdrive: config id "${options.cfId}" not found in account`);
2194
- const derivedName = naming.hyperdriveName(options.logical, env);
1485
+ const derivedName = hyperdriveDeriveName(resourceConfig, env, naming);
2195
1486
  if (hit.name !== derivedName) throw new Error(`import hyperdrive: cf name "${hit.name}" does not match derived "${derivedName}"`);
2196
1487
  const bindingKey = naming.hyperdriveBindingKey(options.logical);
2197
1488
  const key = `hyperdrive:${derivedName}`;
@@ -2213,6 +1504,12 @@ const hyperdriveModule = {
2213
1504
  }
2214
1505
  };
2215
1506
 
1507
+ //#endregion
1508
+ //#region src/features/vectorize/vectorize.naming.ts
1509
+ function vectorizeDeriveName(config, env, naming) {
1510
+ return resolveVectorizeCloudflareName(config, env, naming);
1511
+ }
1512
+
2216
1513
  //#endregion
2217
1514
  //#region src/features/vectorize/vectorize.apply.ts
2218
1515
  const STATE_KEY_PREFIX$4 = "vectorize:";
@@ -2221,7 +1518,7 @@ function stateKey$4(derivedName) {
2221
1518
  }
2222
1519
  async function vectorizeApply(resources, _tenant, env, api, state, naming) {
2223
1520
  for (const config of resources) {
2224
- const derivedName = naming.vectorizeName(config.logicalName, env);
1521
+ const derivedName = vectorizeDeriveName(config, env, naming);
2225
1522
  const key = stateKey$4(derivedName);
2226
1523
  const existing = state.get(key);
2227
1524
  if (existing) {
@@ -2257,7 +1554,7 @@ async function vectorizeApply(resources, _tenant, env, api, state, naming) {
2257
1554
  //#region src/features/vectorize/vectorize.sync.ts
2258
1555
  function vectorizeSync(allIndexes, resources, _tenant, env, state, naming) {
2259
1556
  for (const config of resources) {
2260
- const derivedName = naming.vectorizeName(config.logicalName, env);
1557
+ const derivedName = vectorizeDeriveName(config, env, naming);
2261
1558
  const match = allIndexes.find((i) => i.name === derivedName);
2262
1559
  if (!match) continue;
2263
1560
  const key = `vectorize:${derivedName}`;
@@ -2289,7 +1586,7 @@ function vectorizeDrift(allIndexes, resources, env, state, naming) {
2289
1586
  const cfByName = new Map(allIndexes.map((i) => [i.name, i.id ?? i.name]));
2290
1587
  const stateEntries = Object.values(state.getAll()).filter((e) => e.type === "vectorize");
2291
1588
  for (const config of resources) {
2292
- const derivedName = naming.vectorizeName(config.logicalName, env);
1589
+ const derivedName = vectorizeDeriveName(config, env, naming);
2293
1590
  const cfId = cfByName.get(derivedName);
2294
1591
  const stateEntry = stateEntries.find((e) => e.logicalName === config.logicalName);
2295
1592
  if (stateEntry && !cfId) drift.missingFromCloudflare.push({
@@ -2337,7 +1634,7 @@ async function vectorizeDestroy(_env, state, api, config, baseDir, _force) {
2337
1634
  function vectorizeGenerate(resources, env, state, naming) {
2338
1635
  const out = [];
2339
1636
  for (const config of resources) {
2340
- const derivedName = naming.vectorizeName(config.logicalName, env);
1637
+ const derivedName = vectorizeDeriveName(config, env, naming);
2341
1638
  const entry = state.get(`vectorize:${derivedName}`);
2342
1639
  if (!entry || entry.type !== "vectorize") throw new Error(`Vectorize index "${config.logicalName}" not in state. Run 'tamer apply --env ${env}' first.`);
2343
1640
  out.push({
@@ -2353,7 +1650,7 @@ function vectorizeGenerate(resources, env, state, naming) {
2353
1650
  function vectorizeStatus(resources, env, state, naming) {
2354
1651
  const out = [];
2355
1652
  for (const config of resources) {
2356
- const derivedName = naming.vectorizeName(config.logicalName, env);
1653
+ const derivedName = vectorizeDeriveName(config, env, naming);
2357
1654
  const entry = state.get(`vectorize:${derivedName}`);
2358
1655
  out.push({
2359
1656
  binding: config.binding?.trim() || naming.vectorizeBindingKey(config.logicalName),
@@ -2370,7 +1667,7 @@ function vectorizeDiffPlanItems(args) {
2370
1667
  const { resources, env, state, naming } = args;
2371
1668
  const items = [];
2372
1669
  for (const config of resources) {
2373
- const derivedName = naming.vectorizeName(config.logicalName, env);
1670
+ const derivedName = vectorizeDeriveName(config, env, naming);
2374
1671
  const key = `vectorize:${derivedName}`;
2375
1672
  const entry = state.get(key);
2376
1673
  if (!entry || entry.type !== "vectorize") continue;
@@ -2456,12 +1753,14 @@ const vectorizeModule = {
2456
1753
  console.warn(`Rollback: failed to delete Vectorize ${entry.derivedName}:`, err);
2457
1754
  }
2458
1755
  },
2459
- async importOne({ options, env, api, state, naming, ts }) {
1756
+ async importOne({ options, env, api, state, naming, config, baseDir, ts }) {
2460
1757
  const indexName = options.cfId;
2461
1758
  if (!indexName) throw new Error("import vectorize: --cf-id <index-name> is required");
1759
+ const resourceConfig = await findWorkerResourceByLogicalName(config, "vectorize", options.logical, baseDir);
1760
+ if (!resourceConfig) throw new Error(`import vectorize: no resources.vectorize entry with logicalName "${options.logical}" in the Tamer project config`);
2462
1761
  const hit = (await api.vectorizeListAll()).find((v) => v.name === indexName);
2463
1762
  if (!hit) throw new Error(`import vectorize: index "${indexName}" not found in account`);
2464
- const derivedName = naming.vectorizeName(options.logical, env);
1763
+ const derivedName = vectorizeDeriveName(resourceConfig, env, naming);
2465
1764
  if (hit.name !== derivedName) throw new Error(`import vectorize: cf name "${hit.name}" does not match derived "${derivedName}"`);
2466
1765
  if (!hit.config) throw new Error(`import vectorize: cf index "${hit.name}" returned no config (dimensions/metric)`);
2467
1766
  const metric = hit.config.metric;
@@ -2511,13 +1810,19 @@ function resolveAIGatewayConfig(config) {
2511
1810
  };
2512
1811
  }
2513
1812
 
1813
+ //#endregion
1814
+ //#region src/features/ai-gateway/ai-gateway.naming.ts
1815
+ function aiGatewayDeriveName(config, env, naming) {
1816
+ return resolveAIGatewayCloudflareName(config, env, naming);
1817
+ }
1818
+
2514
1819
  //#endregion
2515
1820
  //#region src/features/ai-gateway/ai-gateway.diff.ts
2516
1821
  function aiGatewayDiffPlanItems(args) {
2517
1822
  const { resources, env, state, naming } = args;
2518
1823
  const items = [];
2519
1824
  for (const config of resources) {
2520
- const derivedName = naming.aiGatewayId(config.logicalName, env);
1825
+ const derivedName = aiGatewayDeriveName(config, env, naming);
2521
1826
  const entry = state.get(`ai_gateway:${derivedName}`);
2522
1827
  if (!entry || entry.type !== "ai_gateway") continue;
2523
1828
  const changes = computeChanges(entry, config);
@@ -2601,7 +1906,7 @@ function stateKey$3(derivedName) {
2601
1906
  }
2602
1907
  async function aiGatewayApply(resources, _tenant, env, api, state, naming) {
2603
1908
  for (const config of resources) {
2604
- const derivedName = naming.aiGatewayId(config.logicalName, env);
1909
+ const derivedName = aiGatewayDeriveName(config, env, naming);
2605
1910
  const key = stateKey$3(derivedName);
2606
1911
  const existing = state.get(key);
2607
1912
  const resolved = resolveAIGatewayConfig(config);
@@ -2677,7 +1982,7 @@ async function aiGatewayApply(resources, _tenant, env, api, state, naming) {
2677
1982
  //#region src/features/ai-gateway/ai-gateway.sync.ts
2678
1983
  function aiGatewaySync(allGateways, resources, _tenant, env, state, naming) {
2679
1984
  for (const config of resources) {
2680
- const derivedName = naming.aiGatewayId(config.logicalName, env);
1985
+ const derivedName = aiGatewayDeriveName(config, env, naming);
2681
1986
  const match = allGateways.find((g) => g.id === derivedName);
2682
1987
  if (!match) continue;
2683
1988
  const key = `ai_gateway:${derivedName}`;
@@ -2715,7 +2020,7 @@ function aiGatewayDrift(allGateways, resources, env, state, naming) {
2715
2020
  const cfIds = new Set(allGateways.map((g) => g.id));
2716
2021
  const stateEntries = Object.values(state.getAll()).filter((e) => e.type === "ai_gateway");
2717
2022
  for (const config of resources) {
2718
- const derivedName = naming.aiGatewayId(config.logicalName, env);
2023
+ const derivedName = aiGatewayDeriveName(config, env, naming);
2719
2024
  const inCloudflare = cfIds.has(derivedName);
2720
2025
  const stateEntry = stateEntries.find((e) => e.logicalName === config.logicalName);
2721
2026
  if (stateEntry && !inCloudflare) drift.missingFromCloudflare.push({
@@ -2758,7 +2063,7 @@ async function aiGatewayDestroy(_env, state, api, config, baseDir, _force) {
2758
2063
  function aiGatewayStatus(resources, env, state, naming) {
2759
2064
  const out = [];
2760
2065
  for (const config of resources) {
2761
- const derivedName = naming.aiGatewayId(config.logicalName, env);
2066
+ const derivedName = aiGatewayDeriveName(config, env, naming);
2762
2067
  const entry = state.get(`ai_gateway:${derivedName}`);
2763
2068
  out.push({
2764
2069
  binding: naming.aiGatewayBindingKey(config.logicalName),
@@ -2817,12 +2122,14 @@ const aiGatewayModule = {
2817
2122
  console.warn(`Rollback: failed to delete AI Gateway ${entry.derivedName}:`, err);
2818
2123
  }
2819
2124
  },
2820
- async importOne({ options, env, api, state, naming, ts }) {
2125
+ async importOne({ options, env, api, state, naming, config, baseDir, ts }) {
2821
2126
  const gatewayId = options.cfId;
2822
2127
  if (!gatewayId) throw new Error("import ai_gateway: --cf-id <gateway-id> is required");
2128
+ const resourceConfig = await findWorkerResourceByLogicalName(config, "aiGateway", options.logical, baseDir);
2129
+ if (!resourceConfig) throw new Error(`import ai_gateway: no resources.aiGateway entry with logicalName "${options.logical}" in the Tamer project config`);
2823
2130
  const hit = (await api.aiGatewayListAll()).find((g) => g.id === gatewayId);
2824
2131
  if (!hit) throw new Error(`import ai_gateway: gateway "${gatewayId}" not found in account`);
2825
- const derivedName = naming.aiGatewayId(options.logical, env);
2132
+ const derivedName = aiGatewayDeriveName(resourceConfig, env, naming);
2826
2133
  if (hit.id !== derivedName) throw new Error(`import ai_gateway: cf id "${hit.id}" does not match derived "${derivedName}"`);
2827
2134
  const key = `ai_gateway:${derivedName}`;
2828
2135
  const existing = state.get(key);
@@ -2847,6 +2154,12 @@ const aiGatewayModule = {
2847
2154
  }
2848
2155
  };
2849
2156
 
2157
+ //#endregion
2158
+ //#region src/features/pipelines/pipelines.naming.ts
2159
+ function pipelineDeriveName(config, env, naming) {
2160
+ return resolvePipelineCloudflareName(config, env, naming);
2161
+ }
2162
+
2850
2163
  //#endregion
2851
2164
  //#region src/features/pipelines/pipelines.apply.ts
2852
2165
  const STATE_KEY_PREFIX$2 = "pipeline:";
@@ -2861,7 +2174,7 @@ function stateKey$2(derivedName) {
2861
2174
  */
2862
2175
  async function pipelinesApply(resources, _tenant, env, api, state, naming) {
2863
2176
  for (const config of resources) {
2864
- const derivedName = naming.pipelineName(config.logicalName, env);
2177
+ const derivedName = pipelineDeriveName(config, env, naming);
2865
2178
  const key = stateKey$2(derivedName);
2866
2179
  if (state.get(key)) continue;
2867
2180
  const ts = (/* @__PURE__ */ new Date()).toISOString();
@@ -2887,7 +2200,7 @@ async function pipelinesApply(resources, _tenant, env, api, state, naming) {
2887
2200
  //#region src/features/pipelines/pipelines.sync.ts
2888
2201
  function pipelinesSync(allPipelines, resources, _tenant, env, state, naming) {
2889
2202
  for (const config of resources) {
2890
- const derivedName = naming.pipelineName(config.logicalName, env);
2203
+ const derivedName = pipelineDeriveName(config, env, naming);
2891
2204
  const match = allPipelines.find((p) => p.name === derivedName);
2892
2205
  if (!match) continue;
2893
2206
  const key = `pipeline:${derivedName}`;
@@ -2919,7 +2232,7 @@ function pipelinesDrift(allPipelines, resources, env, state, naming) {
2919
2232
  const cfByName = new Map(allPipelines.map((p) => [p.name, p]));
2920
2233
  const stateEntries = Object.values(state.getAll()).filter((e) => e.type === "pipeline");
2921
2234
  for (const config of resources) {
2922
- const derivedName = naming.pipelineName(config.logicalName, env);
2235
+ const derivedName = pipelineDeriveName(config, env, naming);
2923
2236
  const inCloudflare = cfByName.has(derivedName);
2924
2237
  const stateEntry = stateEntries.find((e) => e.logicalName === config.logicalName);
2925
2238
  if (stateEntry && !inCloudflare) drift.missingFromCloudflare.push({
@@ -2972,7 +2285,7 @@ async function pipelinesDestroy(_env, state, api, config, baseDir, _force) {
2972
2285
  function pipelinesGenerate(resources, env, state, naming) {
2973
2286
  const out = [];
2974
2287
  for (const config of resources) {
2975
- const derivedName = naming.pipelineName(config.logicalName, env);
2288
+ const derivedName = pipelineDeriveName(config, env, naming);
2976
2289
  const entry = state.get(`pipeline:${derivedName}`);
2977
2290
  if (!entry || entry.type !== "pipeline") throw new Error(`Pipeline "${config.logicalName}" not in state. Run 'tamer apply --env ${env}' first.`);
2978
2291
  out.push({
@@ -2988,7 +2301,7 @@ function pipelinesGenerate(resources, env, state, naming) {
2988
2301
  function pipelinesStatus(resources, env, state, naming) {
2989
2302
  const out = [];
2990
2303
  for (const config of resources) {
2991
- const derivedName = naming.pipelineName(config.logicalName, env);
2304
+ const derivedName = pipelineDeriveName(config, env, naming);
2992
2305
  const entry = state.get(`pipeline:${derivedName}`);
2993
2306
  out.push({
2994
2307
  binding: config.binding?.trim() || naming.pipelineBindingKey(config.logicalName),
@@ -3005,7 +2318,7 @@ function pipelinesDiffPlanItems(args) {
3005
2318
  const { resources, env, state, naming } = args;
3006
2319
  const items = [];
3007
2320
  for (const config of resources) {
3008
- const derivedName = naming.pipelineName(config.logicalName, env);
2321
+ const derivedName = pipelineDeriveName(config, env, naming);
3009
2322
  const key = `pipeline:${derivedName}`;
3010
2323
  const entry = state.get(key);
3011
2324
  if (!entry || entry.type !== "pipeline") continue;
@@ -3097,12 +2410,14 @@ const pipelinesModule = {
3097
2410
  console.warn(`Rollback: failed to delete Pipeline ${entry.derivedName}:`, err);
3098
2411
  }
3099
2412
  },
3100
- async importOne({ options, env, api, state, naming, ts }) {
2413
+ async importOne({ options, env, api, state, naming, config, baseDir, ts }) {
3101
2414
  const pipelineId = options.cfId;
3102
2415
  if (!pipelineId) throw new Error("import pipeline: --cf-id <pipeline-id> is required");
2416
+ const resourceConfig = await findWorkerResourceByLogicalName(config, "pipelines", options.logical, baseDir);
2417
+ if (!resourceConfig) throw new Error(`import pipeline: no resources.pipelines entry with logicalName "${options.logical}" in the Tamer project config`);
3103
2418
  const hit = (await api.pipelineListAll()).find((p) => p.id === pipelineId);
3104
2419
  if (!hit) throw new Error(`import pipeline: pipeline "${pipelineId}" not found in account`);
3105
- const derivedName = naming.pipelineName(options.logical, env);
2420
+ const derivedName = pipelineDeriveName(resourceConfig, env, naming);
3106
2421
  if (hit.name !== derivedName) throw new Error(`import pipeline: cf name "${hit.name}" does not match derived "${derivedName}"`);
3107
2422
  const key = `pipeline:${derivedName}`;
3108
2423
  const existing = state.get(key);
@@ -3121,13 +2436,23 @@ const pipelinesModule = {
3121
2436
  }
3122
2437
  };
3123
2438
 
2439
+ //#endregion
2440
+ //#region src/features/workflows/workflows.naming.ts
2441
+ function workflowDeriveName(config, env, naming) {
2442
+ return resolveWorkflowCloudflareName(config, env, naming);
2443
+ }
2444
+ function workflowMatchPattern(config, env, naming) {
2445
+ const expected = resolveWorkflowCloudflareName(config, env, naming);
2446
+ return (name) => name === expected;
2447
+ }
2448
+
3124
2449
  //#endregion
3125
2450
  //#region src/features/workflows/workflows.diff.ts
3126
2451
  function workflowsDiffPlanItems(args) {
3127
2452
  const { resources, env, state, naming, worker } = args;
3128
2453
  const items = [];
3129
2454
  for (const config of resources) {
3130
- const derivedName = naming.workflowName(config.logicalName, env);
2455
+ const derivedName = workflowDeriveName(config, env, naming);
3131
2456
  const key = `workflow:${derivedName}`;
3132
2457
  const entry = state.get(key);
3133
2458
  if (!entry || entry.type !== "workflow") continue;
@@ -3214,7 +2539,7 @@ function limitsEqual(a, b) {
3214
2539
  */
3215
2540
  async function workflowsApply(resources, _tenant, env, api, state, naming, worker) {
3216
2541
  for (const config of resources) {
3217
- const derivedName = naming.workflowName(config.logicalName, env);
2542
+ const derivedName = workflowDeriveName(config, env, naming);
3218
2543
  const scriptName = resolveScriptName(config, worker);
3219
2544
  const key = stateKey$1(derivedName);
3220
2545
  const existing = state.get(key);
@@ -3267,8 +2592,8 @@ async function workflowsApply(resources, _tenant, env, api, state, naming, worke
3267
2592
  */
3268
2593
  function workflowsSync(allWorkflows, resources, _tenant, env, state, naming) {
3269
2594
  for (const config of resources) {
3270
- const derivedName = naming.workflowName(config.logicalName, env);
3271
- const pattern = naming.workflowMatchPattern(config.logicalName, env);
2595
+ const derivedName = workflowDeriveName(config, env, naming);
2596
+ const pattern = workflowMatchPattern(config, env, naming);
3272
2597
  const match = allWorkflows.find((w) => pattern(w.name));
3273
2598
  if (!match) continue;
3274
2599
  const key = `workflow:${derivedName}`;
@@ -3302,7 +2627,7 @@ function workflowsDrift(allWorkflows, resources, env, state, naming) {
3302
2627
  const cfByName = new Map(allWorkflows.map((w) => [w.name, w]));
3303
2628
  const stateEntries = Object.values(state.getAll()).filter((e) => e.type === "workflow");
3304
2629
  for (const config of resources) {
3305
- const derivedName = naming.workflowName(config.logicalName, env);
2630
+ const derivedName = workflowDeriveName(config, env, naming);
3306
2631
  const inCloudflare = cfByName.has(derivedName);
3307
2632
  const stateEntry = stateEntries.find((e) => e.logicalName === config.logicalName);
3308
2633
  if (stateEntry && !inCloudflare) drift.missingFromCloudflare.push({
@@ -3356,7 +2681,7 @@ async function workflowsDestroy(_env, state, api, config, baseDir, _force) {
3356
2681
  function workflowsGenerate(resources, env, state, naming, worker) {
3357
2682
  const out = [];
3358
2683
  for (const config of resources) {
3359
- const derivedName = naming.workflowName(config.logicalName, env);
2684
+ const derivedName = workflowDeriveName(config, env, naming);
3360
2685
  const entry = state.get(`workflow:${derivedName}`);
3361
2686
  if (!entry || entry.type !== "workflow") throw new Error(`Workflow "${config.logicalName}" not in state. Run 'tamer apply --env ${env}' first.`);
3362
2687
  const explicitScript = config.scriptName?.trim();
@@ -3378,7 +2703,7 @@ function workflowsGenerate(resources, env, state, naming, worker) {
3378
2703
  function workflowsStatus(resources, env, state, naming) {
3379
2704
  const out = [];
3380
2705
  for (const config of resources) {
3381
- const derivedName = naming.workflowName(config.logicalName, env);
2706
+ const derivedName = workflowDeriveName(config, env, naming);
3382
2707
  const entry = state.get(`workflow:${derivedName}`);
3383
2708
  out.push({
3384
2709
  binding: config.binding?.trim() || naming.workflowBindingKey(config.logicalName),
@@ -3446,10 +2771,11 @@ const workflowsModule = {
3446
2771
  console.warn(`Rollback: failed to delete Workflow ${entry.derivedName}:`, err);
3447
2772
  }
3448
2773
  },
3449
- async importOne({ options, env, api, state, naming, ts }) {
3450
- const all = await api.workflowListAll();
3451
- const derivedName = naming.workflowName(options.logical, env);
3452
- const hit = all.find((w) => w.name === derivedName);
2774
+ async importOne({ options, env, api, state, naming, config, baseDir, ts }) {
2775
+ const resourceConfig = await findWorkerResourceByLogicalName(config, "workflows", options.logical, baseDir);
2776
+ if (!resourceConfig) throw new Error(`import workflow: no resources.workflows entry with logicalName "${options.logical}" in the Tamer project config`);
2777
+ const derivedName = workflowDeriveName(resourceConfig, env, naming);
2778
+ const hit = (await api.workflowListAll()).find((w) => w.name === derivedName);
3453
2779
  if (!hit) throw new Error(`import workflow: no workflow named "${derivedName}" found in account`);
3454
2780
  if (options.cfId && hit.id !== options.cfId) throw new Error(`import workflow: cf id "${hit.id}" does not match --cf-id "${options.cfId}"`);
3455
2781
  const key = `workflow:${derivedName}`;
@@ -3470,6 +2796,12 @@ const workflowsModule = {
3470
2796
  }
3471
2797
  };
3472
2798
 
2799
+ //#endregion
2800
+ //#region src/features/secrets-store/secrets-store.naming.ts
2801
+ function secretsStoreDeriveName(config, env, naming) {
2802
+ return resolveSecretsStoreCloudflareName(config, env, naming);
2803
+ }
2804
+
3473
2805
  //#endregion
3474
2806
  //#region src/features/secrets-store/secrets-store.apply.ts
3475
2807
  const STATE_KEY_PREFIX = "secrets_store:";
@@ -3488,7 +2820,7 @@ async function secretsStoreApply(resources, _tenant, env, api, state, naming) {
3488
2820
  if (resources.length === 0) return;
3489
2821
  let allStores = null;
3490
2822
  for (const config of resources) {
3491
- const derivedName = naming.secretsStoreName(config.logicalName, env);
2823
+ const derivedName = secretsStoreDeriveName(config, env, naming);
3492
2824
  const key = stateKey(derivedName);
3493
2825
  const existing = state.get(key);
3494
2826
  const wantsBindingKey = naming.secretsStoreBindingKey(config.logicalName);
@@ -3522,7 +2854,7 @@ async function secretsStoreApply(resources, _tenant, env, api, state, naming) {
3522
2854
  */
3523
2855
  function secretsStoreSync(allStores, resources, _tenant, env, state, naming) {
3524
2856
  for (const config of resources) {
3525
- const derivedName = naming.secretsStoreName(config.logicalName, env);
2857
+ const derivedName = secretsStoreDeriveName(config, env, naming);
3526
2858
  const match = allStores.find((s) => s.name === derivedName);
3527
2859
  if (!match) continue;
3528
2860
  const key = `secrets_store:${derivedName}`;
@@ -3553,7 +2885,7 @@ function secretsStoreDrift(allStores, resources, env, state, naming) {
3553
2885
  const cfByName = new Map(allStores.map((s) => [s.name, s]));
3554
2886
  const stateEntries = Object.values(state.getAll()).filter((e) => e.type === "secrets_store");
3555
2887
  for (const config of resources) {
3556
- const derivedName = naming.secretsStoreName(config.logicalName, env);
2888
+ const derivedName = secretsStoreDeriveName(config, env, naming);
3557
2889
  const inCloudflare = cfByName.has(derivedName);
3558
2890
  const stateEntry = stateEntries.find((e) => e.logicalName === config.logicalName);
3559
2891
  if (stateEntry && !inCloudflare) drift.missingFromCloudflare.push({
@@ -3598,7 +2930,7 @@ async function secretsStoreDestroy(_env, state, api, config, baseDir, _force) {
3598
2930
  function secretsStoreStatus(resources, env, state, naming) {
3599
2931
  const out = [];
3600
2932
  for (const config of resources) {
3601
- const derivedName = naming.secretsStoreName(config.logicalName, env);
2933
+ const derivedName = secretsStoreDeriveName(config, env, naming);
3602
2934
  const entry = state.get(`secrets_store:${derivedName}`);
3603
2935
  out.push({
3604
2936
  binding: naming.secretsStoreBindingKey(config.logicalName),
@@ -3653,9 +2985,11 @@ const secretsStoreModule = {
3653
2985
  console.warn(`Rollback: failed to delete Secrets Store ${entry.derivedName}:`, err);
3654
2986
  }
3655
2987
  },
3656
- async importOne({ options, env, api, state, naming, ts }) {
2988
+ async importOne({ options, env, api, state, naming, config, baseDir, ts }) {
2989
+ const resourceConfig = await findWorkerResourceByLogicalName(config, "secretsStores", options.logical, baseDir);
2990
+ if (!resourceConfig) throw new Error(`import secret_store: no resources.secretsStores entry with logicalName "${options.logical}" in the Tamer project config`);
3657
2991
  const all = await api.secretsStoreListAll();
3658
- const derivedName = naming.secretsStoreName(options.logical, env);
2992
+ const derivedName = secretsStoreDeriveName(resourceConfig, env, naming);
3659
2993
  const hit = all.find((s) => s.name === derivedName);
3660
2994
  if (!hit) throw new Error(`import secret_store: no store named "${derivedName}" found in account`);
3661
2995
  if (options.cfId && hit.id !== options.cfId) throw new Error(`import secret_store: cf id "${hit.id}" does not match --cf-id "${options.cfId}"`);
@@ -3695,132 +3029,5 @@ function getResourceModule(kind) {
3695
3029
  }
3696
3030
 
3697
3031
  //#endregion
3698
- //#region src/core/imports/fetchStackImports.ts
3699
- const IMPORT_RE = /\$\{tamer:import:([a-zA-Z0-9_-]+)\.([a-zA-Z0-9_-]+)\}/g;
3700
- /**
3701
- * Walk the merged `CfiConfig` and collect every `${tamer:import:…}` ref
3702
- * site along with where it was found. Used both to drive the pre-fetch
3703
- * (which sibling stacks to load) and by `tamer status` to render an
3704
- * "inbound imports" panel even before any `apply` has run.
3705
- *
3706
- * Self-imports (current stack importing from its own name) are filtered
3707
- * out — they are almost always a config typo and would otherwise
3708
- * silently resolve via the same row this command is about to write.
3709
- */
3710
- function scanConfigForImports(config) {
3711
- const selfStack = stackNameForConfig(config);
3712
- const refs = [];
3713
- const seen = /* @__PURE__ */ new Set();
3714
- const push = (raw, fieldPath) => {
3715
- if (!raw) return;
3716
- IMPORT_RE.lastIndex = 0;
3717
- let m;
3718
- while ((m = IMPORT_RE.exec(raw)) !== null) {
3719
- const stack = m[1];
3720
- const output = m[2];
3721
- if (stack === selfStack) continue;
3722
- const key = `${fieldPath}::${stack}.${output}`;
3723
- if (seen.has(key)) continue;
3724
- seen.add(key);
3725
- refs.push({
3726
- stack,
3727
- output,
3728
- fieldPath
3729
- });
3730
- }
3731
- };
3732
- const walkVars = (vars, pathPrefix) => {
3733
- if (!vars) return;
3734
- for (const [k, v] of Object.entries(vars)) push(materializeTamerResolvable(v), `${pathPrefix}.${k}`);
3735
- };
3736
- const walkR2BucketNames = (w, pathPrefix) => {
3737
- if (!w.r2_buckets) return;
3738
- w.r2_buckets.forEach((b, i) => {
3739
- if (b.bucket_name === void 0) return;
3740
- push(materializeTamerResolvable(b.bucket_name), `${pathPrefix}.r2_buckets[${i}].bucket_name`);
3741
- });
3742
- };
3743
- const walkD1DatabaseNames = (w, pathPrefix) => {
3744
- const d1 = w.resources?.d1;
3745
- if (!d1) return;
3746
- d1.forEach((d, i) => {
3747
- if (d.databaseName === void 0) return;
3748
- push(materializeTamerResolvable(d.databaseName), `${pathPrefix}.resources.d1[${i}].databaseName`);
3749
- });
3750
- };
3751
- /** Service bindings / WfP namespace strings may carry `${tamer:import:…}`. */
3752
- const walkBindingsWithRefs = (w, pathPrefix) => {
3753
- w.services?.forEach((s, i) => {
3754
- if (s.service === void 0) return;
3755
- push(materializeTamerResolvable(s.service), `${pathPrefix}.services[${i}].service`);
3756
- });
3757
- w.dispatch_namespaces?.forEach((d, i) => {
3758
- if (d.namespace === void 0) return;
3759
- push(materializeTamerResolvable(d.namespace), `${pathPrefix}.dispatch_namespaces[${i}].namespace`);
3760
- });
3761
- };
3762
- if (config.worker) {
3763
- walkVars(config.worker.vars, "worker.vars");
3764
- walkR2BucketNames(config.worker, "worker");
3765
- walkD1DatabaseNames(config.worker, "worker");
3766
- walkBindingsWithRefs(config.worker, "worker");
3767
- if (config.worker.tamerRoutes) config.worker.tamerRoutes.forEach((r, i) => {
3768
- push(r.host, `worker.tamerRoutes[${i}].host`);
3769
- push(r.zone, `worker.tamerRoutes[${i}].zone`);
3770
- });
3771
- }
3772
- if (config.workers) for (const [key, w] of Object.entries(config.workers)) {
3773
- walkVars(w.vars, `worker[${key}].vars`);
3774
- walkR2BucketNames(w, `worker[${key}]`);
3775
- walkD1DatabaseNames(w, `worker[${key}]`);
3776
- walkBindingsWithRefs(w, `worker[${key}]`);
3777
- if (w.tamerRoutes) w.tamerRoutes.forEach((r, i) => {
3778
- push(r.host, `worker[${key}].tamerRoutes[${i}].host`);
3779
- push(r.zone, `worker[${key}].tamerRoutes[${i}].zone`);
3780
- });
3781
- }
3782
- if (config.outputs) for (const [name, source] of Object.entries(config.outputs)) push(materializeTamerResolvable(source), `outputs.${name}`);
3783
- return refs;
3784
- }
3785
- /** Distinct sibling stack names referenced anywhere in `config`. */
3786
- function importedStackNames(config) {
3787
- const refs = scanConfigForImports(config);
3788
- return [...new Set(refs.map((r) => r.stack))].sort();
3789
- }
3790
- /**
3791
- * Hydrate every imported sibling stack's persisted outputs and return
3792
- * them shaped for {@link ReferenceContext.imports}.
3793
- *
3794
- * - `local` env: returns `{}` immediately. Local mode never persists
3795
- * state, so cross-stack imports are inherently unresolvable. Callers
3796
- * running in tolerant mode (`plan`, `status`) will see the placeholder
3797
- * verbatim; strict callers (`apply`, `deploy`) will fail at resolution
3798
- * with a clear "no imported stack" message.
3799
- * - Missing sibling state row: recorded as an empty outputs map, so
3800
- * `lookupImport` can produce a "no published outputs" diagnostic
3801
- * (vs. the generic "stack not pre-fetched" error).
3802
- *
3803
- * The {@link CFApiClient} is shared with the caller for socket reuse.
3804
- */
3805
- async function fetchStackImports(api, config, env) {
3806
- const stacks = importedStackNames(config);
3807
- if (stacks.length === 0 || env === "local") return {};
3808
- const out = {};
3809
- for (const stack of stacks) {
3810
- const sibling = new StateManager(config.tenant.id, env, stack);
3811
- try {
3812
- await sibling.hydrate(api);
3813
- } catch (err) {
3814
- throw new Error(`Failed to hydrate imported stack "${stack}" from env "${env}": ${err instanceof Error ? err.message : String(err)}`);
3815
- }
3816
- const persisted = sibling.getStackOutputs();
3817
- const flat = {};
3818
- for (const [name, v] of Object.entries(persisted)) flat[name] = v.value;
3819
- out[stack] = flat;
3820
- }
3821
- return out;
3822
- }
3823
-
3824
- //#endregion
3825
- export { namingFromConfig as _, resourceModules as a, d1SkipsProvisionAndMigrate as c, mergedWorkerConfigForEnv as d, resolveDeployedWorkerName as f, wranglerConfigCliArgs as g, resolveReferencesInString as h, getResourceModule as i, buildIntraStackScriptNameMap as l, rewriteIntraStackServiceTargets as m, importedStackNames as n, logicalNamesForResourceKind as o, resolveWorkerConfig as p, scanConfigForImports as r, d1CloudflareDatabaseName as s, fetchStackImports as t, mergeWorkerConfigForResourcePick as u };
3826
- //# sourceMappingURL=fetchStackImports-C-1THPYL.mjs.map
3032
+ export { d1CloudflareDatabaseName as a, logicalNamesForResourceKind as i, resourceModules as n, d1SkipsProvisionAndMigrate as o, secretsStoreDeriveName as r, getResourceModule as t };
3033
+ //# sourceMappingURL=registry-EWWdkLf7.mjs.map