devflare 1.0.0-next.21 → 1.0.0-next.23
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/LLM.md +144 -5
- package/dist/account-j8nfggg4.js +475 -0
- package/dist/account-qhe8vtds.js +475 -0
- package/dist/bridge/gateway-runtime.d.ts +1 -1
- package/dist/bridge/gateway-runtime.d.ts.map +1 -1
- package/dist/bridge/miniflare.d.ts +1 -1
- package/dist/bridge/miniflare.d.ts.map +1 -1
- package/dist/bridge/proxy.d.ts +2 -0
- package/dist/bridge/proxy.d.ts.map +1 -1
- package/dist/bridge/server.d.ts.map +1 -1
- package/dist/browser.d.ts +13 -13
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +5 -3
- package/dist/build-qsgnme4z.js +54 -0
- package/dist/build-vy95gy3f.js +54 -0
- package/dist/build-yzx0gsaj.js +54 -0
- package/dist/cli/commands/build-artifacts.d.ts.map +1 -1
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/type-generation/generator.d.ts +4 -2
- package/dist/cli/commands/type-generation/generator.d.ts.map +1 -1
- package/dist/cli/commands/types.d.ts.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/config/compiler/types.d.ts +1 -1
- package/dist/config/compiler/types.d.ts.map +1 -1
- package/dist/config/define.d.ts +7 -4
- package/dist/config/define.d.ts.map +1 -1
- package/dist/config/env-vars.d.ts +309 -0
- package/dist/config/env-vars.d.ts.map +1 -0
- package/dist/config/index.d.ts +2 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/local-dev-vars.d.ts +2 -2
- package/dist/config/local-dev-vars.d.ts.map +1 -1
- package/dist/config/schema-env.d.ts +6 -6
- package/dist/config/schema-types-bindings-platform.d.ts +378 -0
- package/dist/config/schema-types-bindings-platform.d.ts.map +1 -0
- package/dist/config/schema-types-bindings-resources.d.ts +551 -0
- package/dist/config/schema-types-bindings-resources.d.ts.map +1 -0
- package/dist/config/schema-types-bindings.d.ts +254 -0
- package/dist/config/schema-types-bindings.d.ts.map +1 -0
- package/dist/config/schema-types-build.d.ts +86 -0
- package/dist/config/schema-types-build.d.ts.map +1 -0
- package/dist/config/schema-types-runtime.d.ts +882 -0
- package/dist/config/schema-types-runtime.d.ts.map +1 -0
- package/dist/config/schema-types.d.ts +377 -0
- package/dist/config/schema-types.d.ts.map +1 -0
- package/dist/config/schema.d.ts +14 -15
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config-entry.d.ts +2 -0
- package/dist/config-entry.d.ts.map +1 -1
- package/dist/config-entry.js +3 -1
- package/dist/config-gq5jh4cx.js +105 -0
- package/dist/config-vec13050.js +105 -0
- package/dist/deploy-01j0ep5n.js +1055 -0
- package/dist/deploy-nh5tbv45.js +1055 -0
- package/dist/deploy-tjypkhg7.js +1055 -0
- package/dist/dev-bh581ew3.js +2597 -0
- package/dist/dev-cme5de75.js +2551 -0
- package/dist/dev-gn5y93z9.js +2597 -0
- package/dist/dev-server/server.d.ts.map +1 -1
- package/dist/doctor-h5q28qt1.js +259 -0
- package/dist/doctor-khk550tw.js +259 -0
- package/dist/env.d.ts +10 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/index-0bv2qjs1.js +1555 -0
- package/dist/index-35bmgpfw.js +573 -0
- package/dist/index-3tkzn06q.js +413 -0
- package/dist/index-4se6krdj.js +574 -0
- package/dist/index-8fyz6gcm.js +699 -0
- package/dist/index-97z629zr.js +109 -0
- package/dist/index-b28c4yr4.js +1205 -0
- package/dist/index-c1cj9085.js +2250 -0
- package/dist/index-c8p4njqy.js +479 -0
- package/dist/index-cr06zrgw.js +1033 -0
- package/dist/index-cwjjdtgn.js +74 -0
- package/dist/index-dref9ecb.js +476 -0
- package/dist/index-e151t4ge.js +895 -0
- package/dist/index-e7kakw0j.js +1033 -0
- package/dist/index-f1g5jdm8.js +1426 -0
- package/dist/index-f46984zs.js +1554 -0
- package/dist/index-grk8pzhr.js +185 -0
- package/dist/index-hbxkmb1q.js +1426 -0
- package/dist/index-hzmpecq9.js +52 -0
- package/dist/index-j1csb7gb.js +581 -0
- package/dist/index-j7x7f72h.js +185 -0
- package/dist/index-jkqbjwt2.js +476 -0
- package/dist/index-jwd3fanx.js +412 -0
- package/dist/index-mh5renra.js +895 -0
- package/dist/index-p9xq83p7.js +147 -0
- package/dist/index-q15nj71j.js +52 -0
- package/dist/index-qqp65pyv.js +699 -0
- package/dist/index-s0fmwxbk.js +74 -0
- package/dist/index-s9q605sq.js +1033 -0
- package/dist/index-stzx8nc4.js +111 -0
- package/dist/index-th4vrnbk.js +1205 -0
- package/dist/index-vtcmsgaf.js +581 -0
- package/dist/index-w36q6819.js +895 -0
- package/dist/index-x2k3awjs.js +147 -0
- package/dist/index-x8x547tz.js +1426 -0
- package/dist/index-xp0qkkxf.js +68 -0
- package/dist/index-xxxd0mvw.js +109 -0
- package/dist/index-zawn5tte.js +109 -0
- package/dist/index-zpy9caxn.js +1193 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -7
- package/dist/login-280p2cm9.js +77 -0
- package/dist/login-4n266whq.js +77 -0
- package/dist/previews-3m3ffpaw.js +1337 -0
- package/dist/previews-tr8sm03d.js +1337 -0
- package/dist/productions-62y489ff.js +505 -0
- package/dist/productions-cgn3fz7d.js +505 -0
- package/dist/runtime/exports.d.ts +23 -0
- package/dist/runtime/exports.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +6 -4
- package/dist/secrets-4050kqf5.js +91 -0
- package/dist/secrets-p112cajt.js +91 -0
- package/dist/sveltekit/index.js +8 -7
- package/dist/sveltekit/local-bindings.d.ts.map +1 -1
- package/dist/test/index.js +24 -12
- package/dist/test/resolve-service-bindings.d.ts +1 -1
- package/dist/test/resolve-service-bindings.d.ts.map +1 -1
- package/dist/test/simple-context-lifecycle.d.ts.map +1 -1
- package/dist/types-apmt10yj.js +705 -0
- package/dist/types-ttrrgdfj.js +705 -0
- package/dist/vite/index.js +5 -5
- package/dist/vite/plugin-context.d.ts.map +1 -1
- package/dist/vite/plugin-programmatic.d.ts.map +1 -1
- package/dist/worker-2k1jyr6p.js +513 -0
- package/dist/worker-jqgn6jyj.js +513 -0
- package/package.json +1 -1
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveConfigForEnvironment
|
|
3
|
+
} from "./index-f46984zs.js";
|
|
4
|
+
|
|
5
|
+
// src/cli/commands/previews-support/family.ts
|
|
6
|
+
function compareConfiguredWorkerFamilies(left, right) {
|
|
7
|
+
if (left.role === "primary" && right.role !== "primary") {
|
|
8
|
+
return -1;
|
|
9
|
+
}
|
|
10
|
+
if (left.role !== "primary" && right.role === "primary") {
|
|
11
|
+
return 1;
|
|
12
|
+
}
|
|
13
|
+
return left.baseName.localeCompare(right.baseName);
|
|
14
|
+
}
|
|
15
|
+
function comparePreviewScopeRows(left, right) {
|
|
16
|
+
const leftTime = left.updatedAt?.getTime() ?? 0;
|
|
17
|
+
const rightTime = right.updatedAt?.getTime() ?? 0;
|
|
18
|
+
if (rightTime !== leftTime) {
|
|
19
|
+
return rightTime - leftTime;
|
|
20
|
+
}
|
|
21
|
+
return left.scope.localeCompare(right.scope);
|
|
22
|
+
}
|
|
23
|
+
function collectConfiguredWorkerFamilies(config, environment) {
|
|
24
|
+
const resolvedConfig = resolveConfigForEnvironment(config, environment);
|
|
25
|
+
const families = new Map;
|
|
26
|
+
families.set(resolvedConfig.name, {
|
|
27
|
+
baseName: resolvedConfig.name,
|
|
28
|
+
roleLabel: "primary",
|
|
29
|
+
role: "primary"
|
|
30
|
+
});
|
|
31
|
+
for (const [bindingName, binding] of Object.entries(resolvedConfig.bindings?.services ?? {})) {
|
|
32
|
+
const existing = families.get(binding.service);
|
|
33
|
+
if (existing) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
families.set(binding.service, {
|
|
37
|
+
baseName: binding.service,
|
|
38
|
+
roleLabel: bindingName,
|
|
39
|
+
role: "service"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return Array.from(families.values()).sort(compareConfiguredWorkerFamilies);
|
|
43
|
+
}
|
|
44
|
+
function getWorkerUrl(workerName, workersSubdomain) {
|
|
45
|
+
if (!workersSubdomain) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
return `https://${workerName}.${workersSubdomain}.workers.dev`;
|
|
49
|
+
}
|
|
50
|
+
function getWorkerScopeSuffix(workerName, baseName) {
|
|
51
|
+
if (!workerName.startsWith(`${baseName}-`)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const suffix = workerName.slice(baseName.length + 1).trim();
|
|
55
|
+
return suffix || undefined;
|
|
56
|
+
}
|
|
57
|
+
function buildStableWorkerRowsFromLiveWorkers(families, workers, workersSubdomain) {
|
|
58
|
+
const workersByName = new Map(workers.map((worker) => [worker.name, worker]));
|
|
59
|
+
return families.map((family) => {
|
|
60
|
+
const worker = workersByName.get(family.baseName);
|
|
61
|
+
const status = worker ? "active" : "missing";
|
|
62
|
+
return {
|
|
63
|
+
workerName: family.baseName,
|
|
64
|
+
role: family.roleLabel,
|
|
65
|
+
status,
|
|
66
|
+
updatedAt: worker?.modifiedOn,
|
|
67
|
+
url: worker ? getWorkerUrl(family.baseName, workersSubdomain) : undefined
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function getDedicatedPreviewFamilyNamesFromWorkers(families, workers) {
|
|
72
|
+
const familyNames = new Set;
|
|
73
|
+
const workerNames = workers.map((worker) => worker.name);
|
|
74
|
+
for (const family of families) {
|
|
75
|
+
if (family.role === "primary") {
|
|
76
|
+
familyNames.add(family.baseName);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (workerNames.some((workerName) => Boolean(getWorkerScopeSuffix(workerName, family.baseName)))) {
|
|
80
|
+
familyNames.add(family.baseName);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return familyNames;
|
|
84
|
+
}
|
|
85
|
+
function buildPreviewScopeRowsFromLiveWorkers(families, workers, workersSubdomain) {
|
|
86
|
+
const workersByName = new Map(workers.map((worker) => [worker.name, worker]));
|
|
87
|
+
const previewFamilyNames = getDedicatedPreviewFamilyNamesFromWorkers(families, workers);
|
|
88
|
+
const expectedFamilies = families.filter((family) => previewFamilyNames.has(family.baseName));
|
|
89
|
+
const workerCandidatesByScope = buildPreviewWorkerCandidatesByScope(families, workers);
|
|
90
|
+
return Array.from(workerCandidatesByScope.keys()).map((scope) => {
|
|
91
|
+
const resolvedFamilies = expectedFamilies.map((family) => ({
|
|
92
|
+
family,
|
|
93
|
+
worker: workersByName.get(`${family.baseName}-${scope}`)
|
|
94
|
+
}));
|
|
95
|
+
const presentFamilies = resolvedFamilies.filter((entry) => entry.worker);
|
|
96
|
+
const updatedAt = presentFamilies.reduce((latest, entry) => {
|
|
97
|
+
const currentDate = entry.worker?.modifiedOn;
|
|
98
|
+
if (!currentDate) {
|
|
99
|
+
return latest;
|
|
100
|
+
}
|
|
101
|
+
if (!latest || currentDate.getTime() > latest.getTime()) {
|
|
102
|
+
return currentDate;
|
|
103
|
+
}
|
|
104
|
+
return latest;
|
|
105
|
+
}, undefined);
|
|
106
|
+
const primaryEntry = resolvedFamilies.find((entry) => entry.family.role === "primary");
|
|
107
|
+
const entryWorker = primaryEntry?.worker ?? presentFamilies[0]?.worker;
|
|
108
|
+
const missingLabels = resolvedFamilies.filter((entry) => !entry.worker).map((entry) => entry.family.role === "primary" ? "primary" : entry.family.roleLabel);
|
|
109
|
+
const notes = [];
|
|
110
|
+
if (missingLabels.length > 0) {
|
|
111
|
+
notes.push(`missing ${missingLabels.join(", ")}`);
|
|
112
|
+
}
|
|
113
|
+
const strategy = "dedicated workers";
|
|
114
|
+
const status = presentFamilies.length === resolvedFamilies.length ? "ready" : "partial";
|
|
115
|
+
return {
|
|
116
|
+
scope,
|
|
117
|
+
strategy,
|
|
118
|
+
workersLabel: `${presentFamilies.length}/${resolvedFamilies.length}`,
|
|
119
|
+
status,
|
|
120
|
+
updatedAt,
|
|
121
|
+
notes: notes.length > 0 ? notes.join(" · ") : undefined,
|
|
122
|
+
entryUrl: entryWorker ? getWorkerUrl(entryWorker.name, workersSubdomain) : undefined
|
|
123
|
+
};
|
|
124
|
+
}).sort(comparePreviewScopeRows);
|
|
125
|
+
}
|
|
126
|
+
function buildPreviewWorkerCandidatesByScope(families, workers) {
|
|
127
|
+
const candidates = new Map;
|
|
128
|
+
for (const worker of workers) {
|
|
129
|
+
for (const family of families) {
|
|
130
|
+
const scope = getWorkerScopeSuffix(worker.name, family.baseName);
|
|
131
|
+
if (!scope) {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const names = candidates.get(scope) ?? new Set;
|
|
135
|
+
names.add(worker.name);
|
|
136
|
+
candidates.set(scope, names);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return new Map(Array.from(candidates.entries()).map(([scope, workerNames]) => {
|
|
140
|
+
return [scope, Array.from(workerNames).sort((left, right) => left.localeCompare(right))];
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
function orderPreviewWorkerNamesForDeletion(workerNames, scope, families) {
|
|
144
|
+
const familyPriority = new Map;
|
|
145
|
+
for (const family of families) {
|
|
146
|
+
familyPriority.set(family.baseName, {
|
|
147
|
+
priority: family.role === "primary" ? 0 : 1,
|
|
148
|
+
roleLabel: family.roleLabel
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
const resolveFamilyForWorker = (workerName) => {
|
|
152
|
+
for (const family of families) {
|
|
153
|
+
if (getWorkerScopeSuffix(workerName, family.baseName) === scope) {
|
|
154
|
+
const resolved = familyPriority.get(family.baseName);
|
|
155
|
+
if (resolved) {
|
|
156
|
+
return {
|
|
157
|
+
priority: resolved.priority,
|
|
158
|
+
roleLabel: resolved.roleLabel,
|
|
159
|
+
baseName: family.baseName
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
priority: 2,
|
|
166
|
+
roleLabel: workerName
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
return [...workerNames].sort((left, right) => {
|
|
170
|
+
const leftFamily = resolveFamilyForWorker(left);
|
|
171
|
+
const rightFamily = resolveFamilyForWorker(right);
|
|
172
|
+
if (leftFamily.priority !== rightFamily.priority) {
|
|
173
|
+
return leftFamily.priority - rightFamily.priority;
|
|
174
|
+
}
|
|
175
|
+
if (leftFamily.roleLabel !== rightFamily.roleLabel) {
|
|
176
|
+
return leftFamily.roleLabel.localeCompare(rightFamily.roleLabel);
|
|
177
|
+
}
|
|
178
|
+
if (leftFamily.baseName && rightFamily.baseName && leftFamily.baseName !== rightFamily.baseName) {
|
|
179
|
+
return leftFamily.baseName.localeCompare(rightFamily.baseName);
|
|
180
|
+
}
|
|
181
|
+
return left.localeCompare(right);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export { collectConfiguredWorkerFamilies, buildStableWorkerRowsFromLiveWorkers, buildPreviewScopeRowsFromLiveWorkers, buildPreviewWorkerCandidatesByScope, orderPreviewWorkerNamesForDeletion };
|
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import {
|
|
2
|
+
mergeConfigForEnvironment
|
|
3
|
+
} from "./index-f46984zs.js";
|
|
4
|
+
import {
|
|
5
|
+
createD1Database,
|
|
6
|
+
createKVNamespace,
|
|
7
|
+
createQueue,
|
|
8
|
+
createR2Bucket,
|
|
9
|
+
createVectorizeIndex,
|
|
10
|
+
deleteD1Database,
|
|
11
|
+
deleteHyperdrive,
|
|
12
|
+
deleteKVNamespace,
|
|
13
|
+
deleteQueue,
|
|
14
|
+
deleteR2Bucket,
|
|
15
|
+
deleteVectorizeIndex,
|
|
16
|
+
getEffectiveAccountId,
|
|
17
|
+
getPrimaryAccount,
|
|
18
|
+
listD1Databases,
|
|
19
|
+
listHyperdrives,
|
|
20
|
+
listKVNamespaces,
|
|
21
|
+
listQueues,
|
|
22
|
+
listR2Buckets,
|
|
23
|
+
listVectorizeIndexes
|
|
24
|
+
} from "./index-1d4jg11n.js";
|
|
25
|
+
import {
|
|
26
|
+
isPreviewScopedName,
|
|
27
|
+
materializePreviewScopedConfig,
|
|
28
|
+
materializePreviewScopedString
|
|
29
|
+
} from "./index-c8p4njqy.js";
|
|
30
|
+
|
|
31
|
+
// src/config/preview-resources.ts
|
|
32
|
+
var defaultPreviewScopedResourceLifecycleApi = {
|
|
33
|
+
getPrimaryAccount,
|
|
34
|
+
getEffectiveAccountId,
|
|
35
|
+
listKVNamespaces,
|
|
36
|
+
createKVNamespace,
|
|
37
|
+
deleteKVNamespace,
|
|
38
|
+
listD1Databases,
|
|
39
|
+
createD1Database,
|
|
40
|
+
deleteD1Database,
|
|
41
|
+
listR2Buckets,
|
|
42
|
+
createR2Bucket,
|
|
43
|
+
deleteR2Bucket,
|
|
44
|
+
listQueues,
|
|
45
|
+
createQueue,
|
|
46
|
+
deleteQueue,
|
|
47
|
+
listVectorizeIndexes,
|
|
48
|
+
createVectorizeIndex,
|
|
49
|
+
deleteVectorizeIndex,
|
|
50
|
+
listHyperdrives,
|
|
51
|
+
deleteHyperdrive
|
|
52
|
+
};
|
|
53
|
+
function resolvePreviewScopedResourceLifecycleApi(overrides) {
|
|
54
|
+
return {
|
|
55
|
+
...defaultPreviewScopedResourceLifecycleApi,
|
|
56
|
+
...overrides ?? {}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function createEmptyPreviewScopedResourceNames() {
|
|
60
|
+
return {
|
|
61
|
+
kv: [],
|
|
62
|
+
d1: [],
|
|
63
|
+
r2: [],
|
|
64
|
+
queues: [],
|
|
65
|
+
vectorize: [],
|
|
66
|
+
hyperdrive: [],
|
|
67
|
+
analyticsEngine: [],
|
|
68
|
+
browser: []
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function createEmptyPreviewScopedResourcePlan() {
|
|
72
|
+
return {
|
|
73
|
+
kv: [],
|
|
74
|
+
d1: [],
|
|
75
|
+
r2: [],
|
|
76
|
+
queues: [],
|
|
77
|
+
vectorize: [],
|
|
78
|
+
hyperdrive: [],
|
|
79
|
+
analyticsEngine: [],
|
|
80
|
+
browser: []
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function createPreviewScopedResourceRef(value, bindingName, options) {
|
|
84
|
+
if (!isPreviewScopedName(value)) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const baseName = materializePreviewScopedString(value, {
|
|
88
|
+
env: {}
|
|
89
|
+
});
|
|
90
|
+
const previewName = materializePreviewScopedString(value, options);
|
|
91
|
+
if (!baseName || !previewName || baseName === previewName) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
...bindingName ? { bindingName } : {},
|
|
96
|
+
baseName,
|
|
97
|
+
previewName
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function upsertPreviewScopedQueueRef(queueRefs, value, options) {
|
|
101
|
+
const ref = createPreviewScopedResourceRef(value, undefined, options);
|
|
102
|
+
if (!ref) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (!queueRefs.has(ref.previewName)) {
|
|
106
|
+
queueRefs.set(ref.previewName, ref);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function applyHyperdriveBindingFallbacks(config, hyperdriveBindingFallbacks) {
|
|
110
|
+
if (!config.bindings?.hyperdrive || Object.keys(hyperdriveBindingFallbacks).length === 0) {
|
|
111
|
+
return config;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
...config,
|
|
115
|
+
bindings: {
|
|
116
|
+
...config.bindings,
|
|
117
|
+
hyperdrive: Object.fromEntries(Object.entries(config.bindings.hyperdrive).map(([bindingName, bindingConfig]) => {
|
|
118
|
+
const fallbackName = hyperdriveBindingFallbacks[bindingName];
|
|
119
|
+
if (!fallbackName) {
|
|
120
|
+
return [bindingName, bindingConfig];
|
|
121
|
+
}
|
|
122
|
+
return [bindingName, fallbackName];
|
|
123
|
+
}))
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function resolvePreviewScopedResourceLifecycleWarnings(plan) {
|
|
128
|
+
const warnings = [];
|
|
129
|
+
if (plan.analyticsEngine.length > 0) {
|
|
130
|
+
warnings.push("Workers Analytics Engine datasets are created automatically on first write, so Devflare does not provision or delete preview-scoped analytics datasets.");
|
|
131
|
+
}
|
|
132
|
+
if (plan.browser.length > 0) {
|
|
133
|
+
warnings.push("Browser Rendering bindings do not own account-scoped resources, so Devflare does not provision or delete preview-scoped browser bindings.");
|
|
134
|
+
}
|
|
135
|
+
return warnings;
|
|
136
|
+
}
|
|
137
|
+
function hasPreviewScopedLifecycleResources(plan) {
|
|
138
|
+
return plan.kv.length > 0 || plan.d1.length > 0 || plan.r2.length > 0 || plan.queues.length > 0 || plan.vectorize.length > 0 || plan.hyperdrive.length > 0;
|
|
139
|
+
}
|
|
140
|
+
async function resolveLifecycleAccountId(config, options, cloudflareApi) {
|
|
141
|
+
if (options.accountId?.trim()) {
|
|
142
|
+
return options.accountId.trim();
|
|
143
|
+
}
|
|
144
|
+
if (config.accountId?.trim()) {
|
|
145
|
+
return config.accountId.trim();
|
|
146
|
+
}
|
|
147
|
+
const primaryAccount = await cloudflareApi.getPrimaryAccount();
|
|
148
|
+
if (!primaryAccount) {
|
|
149
|
+
throw new Error("Could not resolve a Cloudflare account for preview-scoped resource lifecycle management. Set accountId in devflare.config.ts, pass --account, or authenticate with Wrangler.");
|
|
150
|
+
}
|
|
151
|
+
const effective = await cloudflareApi.getEffectiveAccountId(primaryAccount.id);
|
|
152
|
+
return effective.accountId;
|
|
153
|
+
}
|
|
154
|
+
async function loadPreviewScopedResourceLifecycleState(accountId, plan, cloudflareApi) {
|
|
155
|
+
const [namespaces, databases, buckets, queues, vectorizeIndexes, hyperdrives] = await Promise.all([
|
|
156
|
+
plan.kv.length > 0 ? cloudflareApi.listKVNamespaces(accountId) : Promise.resolve([]),
|
|
157
|
+
plan.d1.length > 0 ? cloudflareApi.listD1Databases(accountId) : Promise.resolve([]),
|
|
158
|
+
plan.r2.length > 0 ? cloudflareApi.listR2Buckets(accountId) : Promise.resolve([]),
|
|
159
|
+
plan.queues.length > 0 ? cloudflareApi.listQueues(accountId) : Promise.resolve([]),
|
|
160
|
+
plan.vectorize.length > 0 ? cloudflareApi.listVectorizeIndexes(accountId) : Promise.resolve([]),
|
|
161
|
+
plan.hyperdrive.length > 0 ? cloudflareApi.listHyperdrives(accountId) : Promise.resolve([])
|
|
162
|
+
]);
|
|
163
|
+
return {
|
|
164
|
+
namespaces,
|
|
165
|
+
databases,
|
|
166
|
+
buckets,
|
|
167
|
+
queues,
|
|
168
|
+
vectorizeIndexes,
|
|
169
|
+
hyperdrives
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function createPreviewScopedResourceResolutionCloudflareApi(state) {
|
|
173
|
+
return {
|
|
174
|
+
listKVNamespaces: async () => state.namespaces,
|
|
175
|
+
listD1Databases: async () => state.databases,
|
|
176
|
+
listHyperdrives: async () => state.hyperdrives
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function findVectorizeIndexByName(indexes, name) {
|
|
180
|
+
return indexes.find((index) => index.name === name);
|
|
181
|
+
}
|
|
182
|
+
function findKVNamespaceByName(namespaces, name) {
|
|
183
|
+
return namespaces.find((namespace) => namespace.name === name);
|
|
184
|
+
}
|
|
185
|
+
function findD1DatabaseByName(databases, name) {
|
|
186
|
+
return databases.find((database) => database.name === name);
|
|
187
|
+
}
|
|
188
|
+
function findR2BucketByName(buckets, name) {
|
|
189
|
+
return buckets.find((bucket) => bucket.name === name);
|
|
190
|
+
}
|
|
191
|
+
function findQueueByName(queues, name) {
|
|
192
|
+
return queues.find((queue) => queue.name === name);
|
|
193
|
+
}
|
|
194
|
+
function findHyperdriveByName(hyperdrives, name) {
|
|
195
|
+
return hyperdrives.find((hyperdrive) => hyperdrive.name === name);
|
|
196
|
+
}
|
|
197
|
+
function collectPreviewScopedResourcePlan(config, options = {}) {
|
|
198
|
+
const mergedConfig = mergeConfigForEnvironment(config, options.environment);
|
|
199
|
+
const plan = createEmptyPreviewScopedResourcePlan();
|
|
200
|
+
const bindings = mergedConfig.bindings;
|
|
201
|
+
if (!bindings) {
|
|
202
|
+
return plan;
|
|
203
|
+
}
|
|
204
|
+
if (bindings.kv) {
|
|
205
|
+
plan.kv = Object.entries(bindings.kv).map(([bindingName, bindingConfig]) => {
|
|
206
|
+
return typeof bindingConfig === "string" ? createPreviewScopedResourceRef(bindingConfig, bindingName, options) : null;
|
|
207
|
+
}).filter((ref) => ref !== null);
|
|
208
|
+
}
|
|
209
|
+
if (bindings.d1) {
|
|
210
|
+
plan.d1 = Object.entries(bindings.d1).map(([bindingName, bindingConfig]) => {
|
|
211
|
+
return typeof bindingConfig === "string" ? createPreviewScopedResourceRef(bindingConfig, bindingName, options) : null;
|
|
212
|
+
}).filter((ref) => ref !== null);
|
|
213
|
+
}
|
|
214
|
+
if (bindings.r2) {
|
|
215
|
+
plan.r2 = Object.entries(bindings.r2).map(([bindingName, bindingConfig]) => {
|
|
216
|
+
return createPreviewScopedResourceRef(bindingConfig, bindingName, options);
|
|
217
|
+
}).filter((ref) => ref !== null);
|
|
218
|
+
}
|
|
219
|
+
if (bindings.queues) {
|
|
220
|
+
const queueRefs = new Map;
|
|
221
|
+
for (const queueName of Object.values(bindings.queues.producers ?? {})) {
|
|
222
|
+
upsertPreviewScopedQueueRef(queueRefs, queueName, options);
|
|
223
|
+
}
|
|
224
|
+
for (const consumer of bindings.queues.consumers ?? []) {
|
|
225
|
+
upsertPreviewScopedQueueRef(queueRefs, consumer.queue, options);
|
|
226
|
+
if (consumer.deadLetterQueue) {
|
|
227
|
+
upsertPreviewScopedQueueRef(queueRefs, consumer.deadLetterQueue, options);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
plan.queues = Array.from(queueRefs.values());
|
|
231
|
+
}
|
|
232
|
+
if (bindings.vectorize) {
|
|
233
|
+
plan.vectorize = Object.entries(bindings.vectorize).map(([bindingName, bindingConfig]) => {
|
|
234
|
+
return createPreviewScopedResourceRef(bindingConfig.indexName, bindingName, options);
|
|
235
|
+
}).filter((ref) => ref !== null);
|
|
236
|
+
}
|
|
237
|
+
if (bindings.hyperdrive) {
|
|
238
|
+
plan.hyperdrive = Object.entries(bindings.hyperdrive).map(([bindingName, bindingConfig]) => {
|
|
239
|
+
if (typeof bindingConfig === "string") {
|
|
240
|
+
return createPreviewScopedResourceRef(bindingConfig, bindingName, options);
|
|
241
|
+
}
|
|
242
|
+
if (bindingConfig && typeof bindingConfig === "object" && "name" in bindingConfig && typeof bindingConfig.name === "string") {
|
|
243
|
+
if ("previewId" in bindingConfig && typeof bindingConfig.previewId === "string" && bindingConfig.previewId.trim()) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
const ref = createPreviewScopedResourceRef(bindingConfig.name, bindingName, options);
|
|
247
|
+
if (ref && bindingConfig.previewFallback === "base") {
|
|
248
|
+
ref.allowBaseFallback = true;
|
|
249
|
+
}
|
|
250
|
+
return ref;
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
}).filter((ref) => ref !== null);
|
|
254
|
+
}
|
|
255
|
+
if (bindings.analyticsEngine) {
|
|
256
|
+
plan.analyticsEngine = Object.entries(bindings.analyticsEngine).map(([bindingName, bindingConfig]) => {
|
|
257
|
+
return createPreviewScopedResourceRef(bindingConfig.dataset, bindingName, options);
|
|
258
|
+
}).filter((ref) => ref !== null);
|
|
259
|
+
}
|
|
260
|
+
if (bindings.browser) {
|
|
261
|
+
plan.browser = Object.entries(bindings.browser).map(([bindingName, bindingConfig]) => {
|
|
262
|
+
if (typeof bindingConfig !== "string") {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
return createPreviewScopedResourceRef(bindingConfig, bindingName, options);
|
|
266
|
+
}).filter((ref) => ref !== null);
|
|
267
|
+
}
|
|
268
|
+
return plan;
|
|
269
|
+
}
|
|
270
|
+
async function preparePreviewScopedResourcesForDeploy(config, options = {}) {
|
|
271
|
+
const mergedConfig = mergeConfigForEnvironment(config, options.environment);
|
|
272
|
+
const plan = collectPreviewScopedResourcePlan(config, options);
|
|
273
|
+
const created = createEmptyPreviewScopedResourceNames();
|
|
274
|
+
const existing = createEmptyPreviewScopedResourceNames();
|
|
275
|
+
const warnings = resolvePreviewScopedResourceLifecycleWarnings(plan);
|
|
276
|
+
if (!hasPreviewScopedLifecycleResources(plan)) {
|
|
277
|
+
return {
|
|
278
|
+
config: materializePreviewScopedConfig(mergedConfig, options),
|
|
279
|
+
plan,
|
|
280
|
+
created,
|
|
281
|
+
existing,
|
|
282
|
+
warnings
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
const cloudflareApi = resolvePreviewScopedResourceLifecycleApi(options.cloudflare);
|
|
286
|
+
const accountId = await resolveLifecycleAccountId(config, options, cloudflareApi);
|
|
287
|
+
const {
|
|
288
|
+
namespaces,
|
|
289
|
+
databases,
|
|
290
|
+
buckets,
|
|
291
|
+
queues,
|
|
292
|
+
vectorizeIndexes,
|
|
293
|
+
hyperdrives
|
|
294
|
+
} = await loadPreviewScopedResourceLifecycleState(accountId, plan, cloudflareApi);
|
|
295
|
+
for (const ref of plan.kv) {
|
|
296
|
+
if (findKVNamespaceByName(namespaces, ref.previewName)) {
|
|
297
|
+
existing.kv.push(ref.previewName);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
const namespace = await cloudflareApi.createKVNamespace(accountId, ref.previewName);
|
|
301
|
+
created.kv.push(ref.previewName);
|
|
302
|
+
namespaces.push(namespace);
|
|
303
|
+
}
|
|
304
|
+
for (const ref of plan.d1) {
|
|
305
|
+
if (findD1DatabaseByName(databases, ref.previewName)) {
|
|
306
|
+
existing.d1.push(ref.previewName);
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
const database = await cloudflareApi.createD1Database(accountId, ref.previewName);
|
|
310
|
+
created.d1.push(ref.previewName);
|
|
311
|
+
databases.push(database);
|
|
312
|
+
}
|
|
313
|
+
for (const ref of plan.r2) {
|
|
314
|
+
if (findR2BucketByName(buckets, ref.previewName)) {
|
|
315
|
+
existing.r2.push(ref.previewName);
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
const bucket = await cloudflareApi.createR2Bucket(accountId, ref.previewName);
|
|
319
|
+
created.r2.push(ref.previewName);
|
|
320
|
+
buckets.push(bucket);
|
|
321
|
+
}
|
|
322
|
+
for (const ref of plan.queues) {
|
|
323
|
+
if (findQueueByName(queues, ref.previewName)) {
|
|
324
|
+
existing.queues.push(ref.previewName);
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
const queue = await cloudflareApi.createQueue(accountId, ref.previewName);
|
|
328
|
+
created.queues.push(ref.previewName);
|
|
329
|
+
queues.push(queue);
|
|
330
|
+
}
|
|
331
|
+
for (const ref of plan.vectorize) {
|
|
332
|
+
if (findVectorizeIndexByName(vectorizeIndexes, ref.previewName)) {
|
|
333
|
+
existing.vectorize.push(ref.previewName);
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
const baseIndex = findVectorizeIndexByName(vectorizeIndexes, ref.baseName);
|
|
337
|
+
if (!baseIndex) {
|
|
338
|
+
throw new Error(`Could not provision preview Vectorize index "${ref.previewName}" because the base index "${ref.baseName}" was not found.`);
|
|
339
|
+
}
|
|
340
|
+
const createdIndex = await cloudflareApi.createVectorizeIndex(accountId, {
|
|
341
|
+
name: ref.previewName,
|
|
342
|
+
dimensions: baseIndex.dimensions,
|
|
343
|
+
metric: baseIndex.metric,
|
|
344
|
+
description: baseIndex.description
|
|
345
|
+
});
|
|
346
|
+
created.vectorize.push(ref.previewName);
|
|
347
|
+
vectorizeIndexes.push(createdIndex);
|
|
348
|
+
}
|
|
349
|
+
const hyperdriveBindingFallbacks = {};
|
|
350
|
+
for (const ref of plan.hyperdrive) {
|
|
351
|
+
if (findHyperdriveByName(hyperdrives, ref.previewName)) {
|
|
352
|
+
existing.hyperdrive.push(ref.previewName);
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (!findHyperdriveByName(hyperdrives, ref.baseName)) {
|
|
356
|
+
throw new Error(`Could not resolve preview Hyperdrive "${ref.previewName}" because neither the preview config nor the base config "${ref.baseName}" exists in this account.`);
|
|
357
|
+
}
|
|
358
|
+
if (!ref.allowBaseFallback) {
|
|
359
|
+
const bindingLabel = ref.bindingName ? `"${ref.bindingName}"` : `for preview name "${ref.previewName}"`;
|
|
360
|
+
throw new Error(`Preview Hyperdrive binding ${bindingLabel} has no dedicated preview Hyperdrive configuration "${ref.previewName}" in this account. ` + "Either provision a dedicated preview Hyperdrive (or set `previewId` on the binding), " + "or opt in to reusing the base Hyperdrive by setting `previewFallback: 'base'` on the binding.");
|
|
361
|
+
}
|
|
362
|
+
if (ref.bindingName) {
|
|
363
|
+
hyperdriveBindingFallbacks[ref.bindingName] = ref.baseName;
|
|
364
|
+
}
|
|
365
|
+
warnings.push(`Preview Hyperdrive "${ref.previewName}" is not auto-provisioned because Cloudflare does not expose stored Hyperdrive credentials for cloning. Devflare will reuse the base Hyperdrive "${ref.baseName}" for binding ${ref.bindingName ?? ref.previewName}.`);
|
|
366
|
+
}
|
|
367
|
+
const preparedConfig = applyHyperdriveBindingFallbacks(mergedConfig, hyperdriveBindingFallbacks);
|
|
368
|
+
return {
|
|
369
|
+
accountId,
|
|
370
|
+
config: materializePreviewScopedConfig(preparedConfig, options),
|
|
371
|
+
resourceResolutionCloudflare: createPreviewScopedResourceResolutionCloudflareApi({
|
|
372
|
+
namespaces,
|
|
373
|
+
databases,
|
|
374
|
+
hyperdrives
|
|
375
|
+
}),
|
|
376
|
+
plan,
|
|
377
|
+
created,
|
|
378
|
+
existing,
|
|
379
|
+
warnings
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
async function cleanupPreviewScopedResources(config, options = {}) {
|
|
383
|
+
const plan = collectPreviewScopedResourcePlan(config, options);
|
|
384
|
+
const candidates = createEmptyPreviewScopedResourceNames();
|
|
385
|
+
const deleted = createEmptyPreviewScopedResourceNames();
|
|
386
|
+
const warnings = resolvePreviewScopedResourceLifecycleWarnings(plan);
|
|
387
|
+
if (!hasPreviewScopedLifecycleResources(plan)) {
|
|
388
|
+
return {
|
|
389
|
+
plan,
|
|
390
|
+
candidates,
|
|
391
|
+
deleted,
|
|
392
|
+
warnings
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
const cloudflareApi = resolvePreviewScopedResourceLifecycleApi(options.cloudflare);
|
|
396
|
+
const accountId = await resolveLifecycleAccountId(config, options, cloudflareApi);
|
|
397
|
+
const apply = options.apply === true;
|
|
398
|
+
const {
|
|
399
|
+
namespaces,
|
|
400
|
+
databases,
|
|
401
|
+
buckets,
|
|
402
|
+
queues,
|
|
403
|
+
vectorizeIndexes,
|
|
404
|
+
hyperdrives
|
|
405
|
+
} = await loadPreviewScopedResourceLifecycleState(accountId, plan, cloudflareApi);
|
|
406
|
+
const kvCandidates = plan.kv.map((ref) => findKVNamespaceByName(namespaces, ref.previewName)).filter((namespace) => namespace !== undefined);
|
|
407
|
+
for (const namespace of kvCandidates) {
|
|
408
|
+
candidates.kv.push(namespace.name);
|
|
409
|
+
if (!apply) {
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
await cloudflareApi.deleteKVNamespace(accountId, namespace.id);
|
|
413
|
+
deleted.kv.push(namespace.name);
|
|
414
|
+
}
|
|
415
|
+
const d1Candidates = plan.d1.map((ref) => findD1DatabaseByName(databases, ref.previewName)).filter((database) => database !== undefined);
|
|
416
|
+
for (const database of d1Candidates) {
|
|
417
|
+
candidates.d1.push(database.name);
|
|
418
|
+
if (!apply) {
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
await cloudflareApi.deleteD1Database(accountId, database.id);
|
|
422
|
+
deleted.d1.push(database.name);
|
|
423
|
+
}
|
|
424
|
+
const r2Candidates = plan.r2.map((ref) => findR2BucketByName(buckets, ref.previewName)).filter((bucket) => bucket !== undefined);
|
|
425
|
+
for (const bucket of r2Candidates) {
|
|
426
|
+
candidates.r2.push(bucket.name);
|
|
427
|
+
if (!apply) {
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
await cloudflareApi.deleteR2Bucket(accountId, bucket.name);
|
|
431
|
+
deleted.r2.push(bucket.name);
|
|
432
|
+
}
|
|
433
|
+
const queueCandidates = plan.queues.map((ref) => findQueueByName(queues, ref.previewName)).filter((queue) => queue !== undefined);
|
|
434
|
+
for (const queue of queueCandidates) {
|
|
435
|
+
candidates.queues.push(queue.name);
|
|
436
|
+
if (!apply) {
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
if (!queue.id) {
|
|
440
|
+
warnings.push(`Skipping queue deletion for "${queue.name}" because Cloudflare did not return a queue id.`);
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
await cloudflareApi.deleteQueue(accountId, queue.id);
|
|
444
|
+
deleted.queues.push(queue.name);
|
|
445
|
+
}
|
|
446
|
+
const vectorizeCandidates = plan.vectorize.map((ref) => findVectorizeIndexByName(vectorizeIndexes, ref.previewName)).filter((index) => index !== undefined);
|
|
447
|
+
for (const index of vectorizeCandidates) {
|
|
448
|
+
candidates.vectorize.push(index.name);
|
|
449
|
+
if (!apply) {
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
await cloudflareApi.deleteVectorizeIndex(accountId, index.name);
|
|
453
|
+
deleted.vectorize.push(index.name);
|
|
454
|
+
}
|
|
455
|
+
const hyperdriveCandidates = plan.hyperdrive.map((ref) => findHyperdriveByName(hyperdrives, ref.previewName)).filter((hyperdrive) => hyperdrive !== undefined);
|
|
456
|
+
for (const hyperdrive of hyperdriveCandidates) {
|
|
457
|
+
candidates.hyperdrive.push(hyperdrive.name);
|
|
458
|
+
if (!apply) {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
await cloudflareApi.deleteHyperdrive(accountId, hyperdrive.id);
|
|
462
|
+
deleted.hyperdrive.push(hyperdrive.name);
|
|
463
|
+
}
|
|
464
|
+
if (plan.hyperdrive.length > 0) {
|
|
465
|
+
warnings.push("Preview-scoped Hyperdrive cleanup only deletes preview configs that already exist. Devflare does not auto-provision preview Hyperdrives because Cloudflare does not expose stored Hyperdrive credentials for cloning.");
|
|
466
|
+
}
|
|
467
|
+
return {
|
|
468
|
+
accountId,
|
|
469
|
+
plan,
|
|
470
|
+
candidates,
|
|
471
|
+
deleted,
|
|
472
|
+
warnings
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
export { preparePreviewScopedResourcesForDeploy, cleanupPreviewScopedResources };
|