@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.
- package/README.md +2 -1
- package/dist/{apply-BOABC3UB.mjs → apply-BjrYbyHn.mjs} +14 -16
- package/dist/{apply-BOABC3UB.mjs.map → apply-BjrYbyHn.mjs.map} +1 -1
- package/dist/{applyTarget-GWDEOXeY.mjs → applyTarget-Ce_mtRQX.mjs} +3 -3
- package/dist/{applyTarget-GWDEOXeY.mjs.map → applyTarget-Ce_mtRQX.mjs.map} +1 -1
- package/dist/{bootstrap-BxwxC_2Z.mjs → bootstrap-D__dHw1w.mjs} +6 -6
- package/dist/bootstrap-D__dHw1w.mjs.map +1 -0
- package/dist/{buildDispatchUploadForm-BoUB93b3.mjs → buildDispatchUploadForm-CVnPmHg4.mjs} +1 -1
- package/dist/{buildDispatchUploadForm-BoUB93b3.mjs.map → buildDispatchUploadForm-CVnPmHg4.mjs.map} +1 -1
- package/dist/{cloudflareSnapshot-DzPuCRTh.mjs → cloudflareSnapshot-C6cF8GG8.mjs} +5 -7
- package/dist/{cloudflareSnapshot-DzPuCRTh.mjs.map → cloudflareSnapshot-C6cF8GG8.mjs.map} +1 -1
- package/dist/{deploy-C0edCpn9.mjs → deploy-C6fX9td0.mjs} +23 -11
- package/dist/deploy-C6fX9td0.mjs.map +1 -0
- package/dist/{destroy-tenant-U0t7BeJ0.mjs → destroy-tenant-T_94ed9x.mjs} +2 -4
- package/dist/{destroy-tenant-U0t7BeJ0.mjs.map → destroy-tenant-T_94ed9x.mjs.map} +1 -1
- package/dist/{destroy-DzgA4lCA.mjs → destroy-vfk2Zbfj.mjs} +11 -13
- package/dist/{destroy-DzgA4lCA.mjs.map → destroy-vfk2Zbfj.mjs.map} +1 -1
- package/dist/{dev-CZbKfdFw.mjs → dev-BLthyLml.mjs} +8 -10
- package/dist/{dev-CZbKfdFw.mjs.map → dev-BLthyLml.mjs.map} +1 -1
- package/dist/{dns-records.resolve-C2T0m4NG.mjs → dns-records.resolve-8a_eHfVI.mjs} +1 -1
- package/dist/{dns-records.resolve-DwBR_1WI.mjs → dns-records.resolve-BB2agPAb.mjs} +1 -1
- package/dist/{dns-records.resolve-DwBR_1WI.mjs.map → dns-records.resolve-BB2agPAb.mjs.map} +1 -1
- package/dist/{dns-records.sync-Bpzz9H0s.mjs → dns-records.sync-DqYROe07.mjs} +3 -3
- package/dist/{dns-records.sync-Bpzz9H0s.mjs.map → dns-records.sync-DqYROe07.mjs.map} +1 -1
- package/dist/{doctor-C_hs7k2D.mjs → doctor-32YLAXXl.mjs} +2 -2
- package/dist/{doctor-C_hs7k2D.mjs.map → doctor-32YLAXXl.mjs.map} +1 -1
- package/dist/drift-BCxWdYHG.mjs +8 -0
- package/dist/{drift-B5bpkI0i.mjs → drift-CeemyFqL.mjs} +37 -9
- package/dist/drift-CeemyFqL.mjs.map +1 -0
- package/dist/{events-BIznt8Sj.mjs → events-otk0l3aJ.mjs} +2 -4
- package/dist/{events-BIznt8Sj.mjs.map → events-otk0l3aJ.mjs.map} +1 -1
- package/dist/{generator-Ba-vqyBG.mjs → generator-gvCy7ouY.mjs} +6 -5
- package/dist/generator-gvCy7ouY.mjs.map +1 -0
- package/dist/{import-B0dlwKoQ.mjs → import-OvohE-H2.mjs} +8 -8
- package/dist/import-OvohE-H2.mjs.map +1 -0
- package/dist/index.d.mts +314 -38
- package/dist/index.d.mts.map +1 -1
- package/dist/{logpush-job-DsRkOORJ.mjs → logpush-job-DJPlpnRu.mjs} +2 -2
- package/dist/{logpush-job-DsRkOORJ.mjs.map → logpush-job-DJPlpnRu.mjs.map} +1 -1
- package/dist/{migrate-BpW6JkIg.mjs → migrate-CroDjbJz.mjs} +6 -8
- package/dist/{migrate-BpW6JkIg.mjs.map → migrate-CroDjbJz.mjs.map} +1 -1
- package/dist/normalize-DVSTRZhO.mjs.map +1 -1
- package/dist/{plan-Do5rE-c5.mjs → plan-C2urqJOz.mjs} +39 -14
- package/dist/plan-C2urqJOz.mjs.map +1 -0
- package/dist/{planFormat-CJw8Kq2s.mjs → planFormat-5XMJK879.mjs} +1 -1
- package/dist/{planFormat-CJw8Kq2s.mjs.map → planFormat-5XMJK879.mjs.map} +1 -1
- package/dist/{provision-tenant-Wfck-2Oa.mjs → provision-tenant-BJ1KugON.mjs} +6 -8
- package/dist/{provision-tenant-Wfck-2Oa.mjs.map → provision-tenant-BJ1KugON.mjs.map} +1 -1
- package/dist/{r2S3EmptyBucket-DD81ZWQ7.mjs → r2S3EmptyBucket-B9_pHfvB.mjs} +1 -1
- package/dist/{r2S3EmptyBucket-DD81ZWQ7.mjs.map → r2S3EmptyBucket-B9_pHfvB.mjs.map} +1 -1
- package/dist/{fetchStackImports-C-1THPYL.mjs → registry-EWWdkLf7.mjs} +272 -1065
- package/dist/registry-EWWdkLf7.mjs.map +1 -0
- package/dist/secrets-CnzjvndT.mjs +3 -0
- package/dist/{stackOutputs-CQQHtdPA.mjs → stackOutputs-Cltzl2g0.mjs} +2 -2
- package/dist/{stackOutputs-CQQHtdPA.mjs.map → stackOutputs-Cltzl2g0.mjs.map} +1 -1
- package/dist/{status-D5GLpWyn.mjs → status-DkkS5lc9.mjs} +7 -9
- package/dist/{status-D5GLpWyn.mjs.map → status-DkkS5lc9.mjs.map} +1 -1
- package/dist/{sync-B_pyPi7Z.mjs → sync-CpfxqlOx.mjs} +7 -9
- package/dist/{sync-B_pyPi7Z.mjs.map → sync-CpfxqlOx.mjs.map} +1 -1
- package/dist/tamer.mjs +4428 -213
- package/dist/tamer.mjs.map +1 -1
- package/dist/{tamerArtifactsR2-Ccgplu2Q.mjs → tamerArtifactsR2-DnUJmxnO.mjs} +2 -2
- package/dist/{tamerArtifactsR2-Ccgplu2Q.mjs.map → tamerArtifactsR2-DnUJmxnO.mjs.map} +1 -1
- package/dist/{types-JrdlG7Dy.mjs → types-BzzHwIdw.mjs} +6 -8
- package/dist/{types-JrdlG7Dy.mjs.map → types-BzzHwIdw.mjs.map} +1 -1
- package/dist/{verifyPlanFile-ah_4tvTu.mjs → verifyPlanFile-BmEadIqm.mjs} +2 -2
- package/dist/{verifyPlanFile-ah_4tvTu.mjs.map → verifyPlanFile-BmEadIqm.mjs.map} +1 -1
- package/dist/{wfp-delete-BhuUrBUA.mjs → wfp-delete-CDBFqmrM.mjs} +2 -3
- package/dist/{wfp-delete-BhuUrBUA.mjs.map → wfp-delete-CDBFqmrM.mjs.map} +1 -1
- package/dist/{wfp-put-DL0mJNNz.mjs → wfp-put-BrwICc9i.mjs} +3 -4
- package/dist/{wfp-put-DL0mJNNz.mjs.map → wfp-put-BrwICc9i.mjs.map} +1 -1
- package/dist/{worker-route-CMbtozNa.mjs → worker-route-x8q3K4-z.mjs} +3 -4
- package/dist/{worker-route-CMbtozNa.mjs.map → worker-route-x8q3K4-z.mjs.map} +1 -1
- package/dist/{workers-C-oeZhdD.mjs → workers-D3Ekf3mF.mjs} +3 -4
- package/dist/{workers-C-oeZhdD.mjs.map → workers-D3Ekf3mF.mjs.map} +1 -1
- package/dist/{wranglerSpawn-DmEz0ldT.mjs → wranglerSpawn-CUlo2qOJ.mjs} +1 -1
- package/dist/{wranglerSpawn-DmEz0ldT.mjs.map → wranglerSpawn-CUlo2qOJ.mjs.map} +1 -1
- package/dist/{zoneResolver-VoxLHM4N.mjs → zoneResolver-DNNNmO_w.mjs} +1 -1
- package/dist/{zoneResolver-VoxLHM4N.mjs.map → zoneResolver-DNNNmO_w.mjs.map} +1 -1
- package/package.json +1 -1
- package/dist/CFApiClient-DhbyyV71.mjs +0 -868
- package/dist/CFApiClient-DhbyyV71.mjs.map +0 -1
- package/dist/StateManager-DTqtLLVX.mjs +0 -760
- package/dist/StateManager-DTqtLLVX.mjs.map +0 -1
- package/dist/bootstrap-BxwxC_2Z.mjs.map +0 -1
- package/dist/deploy-C0edCpn9.mjs.map +0 -1
- package/dist/drift-B5bpkI0i.mjs.map +0 -1
- package/dist/drift-BNa92AK5.mjs +0 -10
- package/dist/fetchStackImports-C-1THPYL.mjs.map +0 -1
- package/dist/generator-Ba-vqyBG.mjs.map +0 -1
- package/dist/import-B0dlwKoQ.mjs.map +0 -1
- package/dist/loader-DAvCKLTT.mjs +0 -518
- package/dist/loader-DAvCKLTT.mjs.map +0 -1
- package/dist/plan-Do5rE-c5.mjs.map +0 -1
|
@@ -1,846 +1,69 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
d1ShardName(logicalName, shardDate, env)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 ?
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 ??
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
3271
|
-
const pattern =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
3451
|
-
|
|
3452
|
-
const
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
3699
|
-
|
|
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
|