@void/deploy-cloudflare 0.22.0 → 0.24.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/dist/index.d.mts +120 -3
- package/dist/index.mjs +526 -286
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -99,6 +99,43 @@ function isWranglerSecretOnlyDraft(entry) {
|
|
|
99
99
|
const runtimeKeys = Object.keys(scriptRuntime);
|
|
100
100
|
return scriptRuntime.usage_model === "standard" && (scriptRuntime.limits === void 0 || isRecord$1(scriptRuntime.limits) && Object.keys(scriptRuntime.limits).length === 0) && runtimeKeys.every((key) => key === "usage_model" || key === "limits");
|
|
101
101
|
}
|
|
102
|
+
const VOID_SECRET_DRAFT_SOURCE = "export default { fetch() { return new Response(\"\"); } };\n";
|
|
103
|
+
/** Prove a cf-created placeholder from the exact immutable version's source. */
|
|
104
|
+
function isVoidSecretOnlyDraft(entry) {
|
|
105
|
+
const metadataFields = /* @__PURE__ */ new Set([
|
|
106
|
+
"id",
|
|
107
|
+
"number",
|
|
108
|
+
"startup_time_ms",
|
|
109
|
+
"created_on",
|
|
110
|
+
"source",
|
|
111
|
+
"author_id",
|
|
112
|
+
"author_email",
|
|
113
|
+
"urls",
|
|
114
|
+
"annotations",
|
|
115
|
+
"compatibility_date",
|
|
116
|
+
"usage_model",
|
|
117
|
+
"main_module",
|
|
118
|
+
"modules",
|
|
119
|
+
"bindings",
|
|
120
|
+
"env",
|
|
121
|
+
"resources"
|
|
122
|
+
]);
|
|
123
|
+
if (Object.keys(entry).some((key) => !metadataFields.has(key)) || entry.source !== "cf_cli" || !isRecord$1(entry.annotations) || Object.keys(entry.annotations).length !== 1 || entry.annotations["workers/triggered_by"] !== "secret" || entry.main_module !== "index.js" || !Array.isArray(entry.urls) || entry.urls.length !== 0 || !Array.isArray(entry.modules) || entry.modules.length !== 1 || !Array.isArray(entry.bindings) || entry.bindings.length === 0) return false;
|
|
124
|
+
const module = entry.modules[0];
|
|
125
|
+
if (!isRecord$1(module) || Object.keys(module).length !== 3 || module.name !== "index.js" || module.content_type !== "application/javascript+module" || module.content_base64 !== Buffer.from("export default { fetch() { return new Response(\"\"); } };\n").toString("base64")) return false;
|
|
126
|
+
const names = /* @__PURE__ */ new Set();
|
|
127
|
+
for (const binding of entry.bindings) {
|
|
128
|
+
if (!isRecord$1(binding) || Object.keys(binding).length !== 2 || typeof binding.name !== "string" || binding.name.length === 0 || names.has(binding.name) || binding.type !== "secret_text") return false;
|
|
129
|
+
names.add(binding.name);
|
|
130
|
+
}
|
|
131
|
+
if (entry.env !== void 0 && (!isRecord$1(entry.env) || Object.keys(entry.env).length !== names.size || Object.entries(entry.env).some(([name, binding]) => !names.has(name) || !isRecord$1(binding) || Object.keys(binding).length !== 1 || binding.type !== "secret_text"))) return false;
|
|
132
|
+
if (entry.resources !== void 0) {
|
|
133
|
+
if (!isRecord$1(entry.resources) || Object.keys(entry.resources).length !== 1) return false;
|
|
134
|
+
const bindings = entry.resources.bindings;
|
|
135
|
+
if (!Array.isArray(bindings) || !isDeepStrictEqual(bindings, entry.bindings)) return false;
|
|
136
|
+
}
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
102
139
|
function isRecord$1(value) {
|
|
103
140
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
104
141
|
}
|
|
@@ -114,26 +151,19 @@ async function readExistingCloudflareWorker(options) {
|
|
|
114
151
|
if (!worker) throw new Error(`Cloudflare Worker "${options.workerName}" does not have an active version.`);
|
|
115
152
|
return worker.snapshot;
|
|
116
153
|
}
|
|
117
|
-
async function readCloudflareWorker(options, allowMissing) {
|
|
118
|
-
const target =
|
|
119
|
-
|
|
120
|
-
options.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
options.
|
|
124
|
-
];
|
|
125
|
-
const read = async (args, missingIsNull = false) => {
|
|
126
|
-
const result = await options.runWrangler([
|
|
127
|
-
...args,
|
|
128
|
-
...target,
|
|
129
|
-
"--json"
|
|
130
|
-
], { capture: true });
|
|
154
|
+
async function readCloudflareWorker(options, allowMissing, proveSecretDraft = false) {
|
|
155
|
+
const target = {
|
|
156
|
+
configPath: options.configPath,
|
|
157
|
+
workerName: options.workerName
|
|
158
|
+
};
|
|
159
|
+
const read = async (operation, missingIsNull = false) => {
|
|
160
|
+
const result = await options.runWrangler(operation, { capture: true });
|
|
131
161
|
if (result.status !== 0 || result.signal || result.error) {
|
|
132
|
-
if (missingIsNull &&
|
|
162
|
+
if (missingIsNull && Number.isSafeInteger(result.status) && result.status >= 0 && result.signal == null && (result.error == null || result.error === "") && (result.failure === "not-found" || result.errorCode === 10007)) return null;
|
|
133
163
|
throw new CloudflareWorkerInspectionError(`Could not verify existing Cloudflare Worker "${options.workerName}". Check the account, Worker name, and Cloudflare permissions before retrying.`);
|
|
134
164
|
}
|
|
135
165
|
try {
|
|
136
|
-
const value =
|
|
166
|
+
const value = result.data;
|
|
137
167
|
if (record$1(value)) return value;
|
|
138
168
|
} catch {}
|
|
139
169
|
throw new Error("Cloudflare returned an invalid existing Worker response.");
|
|
@@ -141,21 +171,37 @@ async function readCloudflareWorker(options, allowMissing) {
|
|
|
141
171
|
const deployment = options.versionId ? { versions: [{
|
|
142
172
|
version_id: options.versionId,
|
|
143
173
|
percentage: 100
|
|
144
|
-
}] } : await read(
|
|
174
|
+
}] } : await read({
|
|
175
|
+
type: "deployments.status",
|
|
176
|
+
...target
|
|
177
|
+
}, allowMissing);
|
|
145
178
|
if (deployment === null) return null;
|
|
146
179
|
const versions = deployment.versions;
|
|
147
180
|
if (allowMissing && Array.isArray(versions) && versions.length === 0) return null;
|
|
148
181
|
if (!Array.isArray(versions) || versions.length !== 1 || !record$1(versions[0]) || versions[0].percentage !== 100 || typeof versions[0].version_id !== "string") throw new Error("The existing Worker must have one deployed version receiving all traffic. Finish any gradual rollout before linking.");
|
|
149
182
|
const versionId = versions[0].version_id;
|
|
150
|
-
const version = await read(
|
|
151
|
-
"versions",
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
183
|
+
const version = await read({
|
|
184
|
+
type: "versions.view",
|
|
185
|
+
versionId,
|
|
186
|
+
...target
|
|
187
|
+
});
|
|
155
188
|
if (version === null) throw new Error("Cloudflare did not return the existing Worker configuration.");
|
|
156
189
|
const resources = version.resources;
|
|
157
190
|
if (version.id !== versionId || !record$1(resources) || !Array.isArray(resources.bindings) || !resources.bindings.every(record$1) || !record$1(resources.script_runtime) || !record$1(resources.script)) throw new Error("Cloudflare did not return the existing Worker configuration.");
|
|
158
|
-
|
|
191
|
+
let isSecretOnlyDraft = isWranglerSecretOnlyDraft(version);
|
|
192
|
+
if (proveSecretDraft && !isSecretOnlyDraft && record$1(version.annotations) && Object.keys(version.annotations).length === 1 && version.annotations["workers/triggered_by"] === "secret") {
|
|
193
|
+
const source = await read({
|
|
194
|
+
type: "versions.view",
|
|
195
|
+
versionId,
|
|
196
|
+
includeSource: true,
|
|
197
|
+
...target
|
|
198
|
+
});
|
|
199
|
+
if (source?.id === versionId) isSecretOnlyDraft = isVoidSecretOnlyDraft(source);
|
|
200
|
+
}
|
|
201
|
+
const after = options.versionId ? deployment : await read({
|
|
202
|
+
type: "deployments.status",
|
|
203
|
+
...target
|
|
204
|
+
});
|
|
159
205
|
if (after === null || !isDeepStrictEqual(deployment.versions, after.versions)) throw new Error("Cloudflare production changed while linking. Retry from the current deployment.");
|
|
160
206
|
return {
|
|
161
207
|
snapshot: {
|
|
@@ -164,7 +210,7 @@ async function readCloudflareWorker(options, allowMissing) {
|
|
|
164
210
|
runtime: resources.script_runtime,
|
|
165
211
|
script: resources.script
|
|
166
212
|
},
|
|
167
|
-
isSecretOnlyDraft
|
|
213
|
+
isSecretOnlyDraft
|
|
168
214
|
};
|
|
169
215
|
}
|
|
170
216
|
/** Parse legacy version-detail shapes; this is not authoritative Worker migration state. */
|
|
@@ -207,15 +253,11 @@ async function readCloudflareWorkerMigrationTag(options) {
|
|
|
207
253
|
return worker.migration_tag;
|
|
208
254
|
}
|
|
209
255
|
async function readCloudflareApiAuthentication(runWrangler) {
|
|
210
|
-
const result = await runWrangler(
|
|
211
|
-
"auth",
|
|
212
|
-
"token",
|
|
213
|
-
"--json"
|
|
214
|
-
], { capture: true });
|
|
256
|
+
const result = await runWrangler({ type: "auth.token" }, { capture: true });
|
|
215
257
|
if (result.status !== 0 || result.signal || result.error) throw new Error("Could not read the authenticated Cloudflare session.");
|
|
216
258
|
let value;
|
|
217
259
|
try {
|
|
218
|
-
value =
|
|
260
|
+
value = result.data;
|
|
219
261
|
} catch {
|
|
220
262
|
throw new Error("Cloudflare returned an invalid authentication response.");
|
|
221
263
|
}
|
|
@@ -236,7 +278,7 @@ async function readCloudflareApiAuthentication(runWrangler) {
|
|
|
236
278
|
async function assertCloudflareDurableObjectLifecycleSupported(options) {
|
|
237
279
|
const migrations = parseDurableObjectMigrations(parseRootWranglerConfig(options.configPath).migrations);
|
|
238
280
|
if (!migrations.some((migration) => migration.changesClasses)) return;
|
|
239
|
-
const existing = await readCloudflareWorker(options, true);
|
|
281
|
+
const existing = await readCloudflareWorker(options, true, true);
|
|
240
282
|
if (!existing) return;
|
|
241
283
|
const readMigrationTag = options.readMigrationTag ?? readCloudflareWorkerMigrationTag;
|
|
242
284
|
const migrationOptions = {
|
|
@@ -246,7 +288,7 @@ async function assertCloudflareDurableObjectLifecycleSupported(options) {
|
|
|
246
288
|
workerName: options.workerName
|
|
247
289
|
};
|
|
248
290
|
const activeTag = await readMigrationTag(migrationOptions);
|
|
249
|
-
const after = await readCloudflareWorker(options, false);
|
|
291
|
+
const after = await readCloudflareWorker(options, false, true);
|
|
250
292
|
const afterTag = await readMigrationTag(migrationOptions);
|
|
251
293
|
if (!after || after.snapshot.versionId !== existing.snapshot.versionId || afterTag !== activeTag) throw new Error("Cloudflare production or Durable Object migration state changed during verification. Retry from the current deployment.");
|
|
252
294
|
if (activeTag === null && existing.isSecretOnlyDraft && after.isSecretOnlyDraft) return;
|
|
@@ -309,9 +351,6 @@ function declarativeClassesMatch(migrations, actualValue) {
|
|
|
309
351
|
return record$1(current) && current.type === "durable-object" && current.storage === storage;
|
|
310
352
|
});
|
|
311
353
|
}
|
|
312
|
-
function isMissingWorkerOutput$1(output) {
|
|
313
|
-
return /\[code:\s*10007\]/i.test(output) || /no deployments|\bworker\b.*\b(?:does not exist|not found)\b/i.test(output);
|
|
314
|
-
}
|
|
315
354
|
function assertCloudflareBindingsPreserved(before, after, approvedKv = [], options = {}) {
|
|
316
355
|
const staticAssetsBinding = isAssetsOnlyWorker(before) ? options.staticAssetsBinding : void 0;
|
|
317
356
|
const addsAssetsBinding = staticAssetsBinding !== void 0 && !before.bindings.some((binding) => binding.name === staticAssetsBinding);
|
|
@@ -381,6 +420,9 @@ function assertExistingCloudflareConfig(existing, config, built = false, approve
|
|
|
381
420
|
if ((built || config[field] !== void 0) && !equal) throw new Error(`Keep the existing Worker's ${field} when linking. Update it in a later deployment.`);
|
|
382
421
|
}
|
|
383
422
|
const vars = record$1(config.vars) ? config.vars : {};
|
|
423
|
+
const metadataBindings = existing.bindings.filter((binding) => binding.type === "version_metadata");
|
|
424
|
+
const metadata = record$1(config.version_metadata) ? config.version_metadata : void 0;
|
|
425
|
+
if (metadataBindings.length > 1 || metadataBindings.length === 1 && metadata?.binding !== metadataBindings[0].name || metadataBindings.length === 0 && config.version_metadata !== void 0) throw new Error("Keep the existing Worker version_metadata binding when linking; linking cannot add or replace it.");
|
|
384
426
|
const remote = new Map(existing.bindings.map((binding) => [binding.name, binding]));
|
|
385
427
|
for (const [name, value] of Object.entries(vars)) {
|
|
386
428
|
const binding = remote.get(name);
|
|
@@ -423,6 +465,7 @@ function assertExistingCloudflareConfig(existing, config, built = false, approve
|
|
|
423
465
|
"secret_text",
|
|
424
466
|
"secret_key"
|
|
425
467
|
].includes(String(binding.type))) continue;
|
|
468
|
+
if (binding.type === "version_metadata") continue;
|
|
426
469
|
if (binding.type === "assets") {
|
|
427
470
|
if (built && (!record$1(config.assets) || config.assets.binding !== binding.name)) throw new Error(`Keep the existing assets binding ${binding.name} when linking.`);
|
|
428
471
|
continue;
|
|
@@ -478,14 +521,10 @@ async function executeCloudflareDeploy(options) {
|
|
|
478
521
|
ok: false,
|
|
479
522
|
reason: "uploader-changed"
|
|
480
523
|
};
|
|
481
|
-
const result = await Promise.resolve(options.runWrangler(
|
|
482
|
-
"deploy",
|
|
483
|
-
...options.configPath ?
|
|
484
|
-
|
|
485
|
-
"--experimental-provision=false",
|
|
486
|
-
"--experimental-auto-create=false",
|
|
487
|
-
"--autoconfig=false"
|
|
488
|
-
], { capture: false }));
|
|
524
|
+
const result = await Promise.resolve(options.runWrangler({
|
|
525
|
+
type: "worker.deploy",
|
|
526
|
+
...options.configPath ? { configPath: options.configPath } : {}
|
|
527
|
+
}, { capture: false }));
|
|
489
528
|
if (!isCleanCommandExit$1(result)) return {
|
|
490
529
|
ok: false,
|
|
491
530
|
reason: "deploy-failed",
|
|
@@ -558,6 +597,7 @@ function writeCloudflareFrameworkDeployConfig(options) {
|
|
|
558
597
|
upsert(["account_id"], options.accountId);
|
|
559
598
|
upsert(["main"], options.main);
|
|
560
599
|
upsert(["compatibility_date"], options.compatibilityDate);
|
|
600
|
+
if (options.versionMetadataBinding && parse(content).version_metadata === void 0) upsert(["version_metadata"], { binding: options.versionMetadataBinding });
|
|
561
601
|
if (options.compatibilityFlags && options.compatibilityFlags.length > 0) {
|
|
562
602
|
const config = parse(content);
|
|
563
603
|
const current = Array.isArray(config.compatibility_flags) ? config.compatibility_flags.filter((flag) => typeof flag === "string") : [];
|
|
@@ -615,7 +655,8 @@ function renderCloudflareStaticEntry(options) {
|
|
|
615
655
|
const config = JSON.stringify({
|
|
616
656
|
...options.headerRules?.length ? { headerRules: options.headerRules } : {},
|
|
617
657
|
...options.redirectRules?.length ? { redirectRules: options.redirectRules } : {},
|
|
618
|
-
...options.fallbackRules?.length ? { fallbackRules: options.fallbackRules } : {}
|
|
658
|
+
...options.fallbackRules?.length ? { fallbackRules: options.fallbackRules } : {},
|
|
659
|
+
...options.versionMetadataBinding ? { versionMetadataBinding: options.versionMetadataBinding } : {}
|
|
619
660
|
});
|
|
620
661
|
return [
|
|
621
662
|
`import { createStaticEdgeHandler } from ${JSON.stringify(options.runtimeImport ?? "@void/edge")};`,
|
|
@@ -762,10 +803,6 @@ function cloudflareCommandDiagnostic(result) {
|
|
|
762
803
|
}
|
|
763
804
|
//#endregion
|
|
764
805
|
//#region src/version.ts
|
|
765
|
-
const VERSION_ID_RE = /(?:Worker|Current) Version ID:\s*([0-9a-f]{8}-[0-9a-f-]{27})/i;
|
|
766
|
-
const PREVIEW_URL_RE = /Version Preview(?: Alias)? URL:\s*(https:\/\/\S+)/i;
|
|
767
|
-
const WORKERS_DEV_URL_RE = /(https:\/\/[a-z0-9.-]+\.workers\.dev(?:\/[^\s]*)?)/i;
|
|
768
|
-
const CLOUDFLARE_ERROR_CODE_RE = /\[code:\s*(\d+)\]/i;
|
|
769
806
|
const DURABLE_MIGRATION_VERSION_ERROR = 10211;
|
|
770
807
|
/** Encode migration state into Cloudflare's version annotation for safe rollback diagnostics. */
|
|
771
808
|
function encodeCloudflareVersionMessage(migrations, triggerConfig, contentHash) {
|
|
@@ -830,31 +867,23 @@ async function deployCloudflareVersionTriggers(options) {
|
|
|
830
867
|
const configPath = join(directory, "wrangler.json");
|
|
831
868
|
try {
|
|
832
869
|
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, { mode: 384 });
|
|
833
|
-
const deployed = await options.runWrangler(
|
|
834
|
-
"triggers",
|
|
835
|
-
"deploy",
|
|
836
|
-
"-c",
|
|
870
|
+
const deployed = await options.runWrangler({
|
|
871
|
+
type: "triggers.deploy",
|
|
837
872
|
configPath,
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
options.workerName
|
|
841
|
-
], { capture: false });
|
|
873
|
+
workerName: options.workerName
|
|
874
|
+
}, { capture: false });
|
|
842
875
|
if (!isCleanCommandExit(deployed)) return deployed;
|
|
843
876
|
if (options.triggerConfig.crons.length === 0 && options.publishEmptyCrons) {
|
|
844
877
|
const published = await options.publishEmptyCrons();
|
|
845
878
|
if (!isCleanCommandExit(published)) return published;
|
|
846
879
|
}
|
|
847
880
|
for (const queue of removedQueueConsumers(options.triggerConfig, options.previousTriggerConfig)) {
|
|
848
|
-
const removed = await options.runWrangler(
|
|
849
|
-
"queues",
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
"-c",
|
|
855
|
-
configPath,
|
|
856
|
-
"--env="
|
|
857
|
-
], { capture: false });
|
|
881
|
+
const removed = await options.runWrangler({
|
|
882
|
+
type: "queues.consumer.remove",
|
|
883
|
+
queueName: queue,
|
|
884
|
+
workerName: options.workerName,
|
|
885
|
+
configPath
|
|
886
|
+
}, { capture: false });
|
|
858
887
|
if (!isCleanCommandExit(removed)) return removed;
|
|
859
888
|
}
|
|
860
889
|
if (options.manageRoutes !== false && !options.triggerConfig.preserveRoutes && hasCustomDomains(options.previousTriggerConfig?.routes) && !hasCustomDomains(options.triggerConfig.routes)) {
|
|
@@ -894,11 +923,11 @@ function pickWranglerTriggerContext(source) {
|
|
|
894
923
|
* schema-2 snapshot. The bounded loop fails closed if traffic never stabilizes.
|
|
895
924
|
*/
|
|
896
925
|
async function stabilizeCloudflareVersionTriggers(options) {
|
|
897
|
-
const
|
|
926
|
+
const configPath = options.configPath;
|
|
898
927
|
let cleanupBaseline = mergeTriggerCleanupBaselines(options.previousTriggerConfig, options.targetTriggerConfig);
|
|
899
928
|
const attempts = Math.max(1, options.attempts ?? 4);
|
|
900
929
|
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
901
|
-
const owner = await readCurrentProductionVersion(options,
|
|
930
|
+
const owner = await readCurrentProductionVersion(options, configPath);
|
|
902
931
|
if (owner.kind === "failed") return {
|
|
903
932
|
ok: false,
|
|
904
933
|
reason: "status-failed",
|
|
@@ -916,7 +945,7 @@ async function stabilizeCloudflareVersionTriggers(options) {
|
|
|
916
945
|
const activeVersionId = owner.versionId;
|
|
917
946
|
let activeTriggerConfig = activeVersionId === options.targetVersionId ? options.targetTriggerConfig : options.knownTriggerConfigs?.[activeVersionId];
|
|
918
947
|
if (!activeTriggerConfig && activeVersionId !== options.targetVersionId) {
|
|
919
|
-
const metadata = await readCloudflareVersionMetadata(options,
|
|
948
|
+
const metadata = await readCloudflareVersionMetadata(options, configPath, activeVersionId);
|
|
920
949
|
activeTriggerConfig = metadata?.schema === 2 ? metadata.triggerConfig : void 0;
|
|
921
950
|
}
|
|
922
951
|
if (!activeTriggerConfig) return {
|
|
@@ -941,7 +970,7 @@ async function stabilizeCloudflareVersionTriggers(options) {
|
|
|
941
970
|
activeVersionId
|
|
942
971
|
};
|
|
943
972
|
cleanupBaseline = mergeTriggerCleanupBaselines(cleanupBaseline, activeTriggerConfig);
|
|
944
|
-
const after = await readCurrentProductionVersion(options,
|
|
973
|
+
const after = await readCurrentProductionVersion(options, configPath);
|
|
945
974
|
if (after.kind === "failed") return {
|
|
946
975
|
ok: false,
|
|
947
976
|
reason: "status-failed",
|
|
@@ -1139,6 +1168,15 @@ function resolvePreservedTraffic(desired, previous, workerExists) {
|
|
|
1139
1168
|
function isRecord(value) {
|
|
1140
1169
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1141
1170
|
}
|
|
1171
|
+
function isCandidatePreviewUrl(value, workerName, versionId, alias) {
|
|
1172
|
+
try {
|
|
1173
|
+
const url = new URL(value);
|
|
1174
|
+
const label = url.hostname.split(".")[0];
|
|
1175
|
+
return url.protocol === "https:" && !url.username && !url.password && extractWorkersDevSubdomain(value) !== void 0 && (label === `${versionId.slice(0, 8)}-${workerName}` || label === `${alias}-${workerName}`);
|
|
1176
|
+
} catch {
|
|
1177
|
+
return false;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1142
1180
|
/** Upload, probe, and atomically activate a verified Worker Version. */
|
|
1143
1181
|
async function activateCloudflareVersion(options) {
|
|
1144
1182
|
const candidateSecrets = Object.entries(options.candidateSecrets ?? {});
|
|
@@ -1159,13 +1197,13 @@ async function activateCloudflareVersion(options) {
|
|
|
1159
1197
|
}
|
|
1160
1198
|
}
|
|
1161
1199
|
async function activateCloudflareVersionWithSecretsFile(options) {
|
|
1162
|
-
const
|
|
1200
|
+
const configPath = options.configPath;
|
|
1163
1201
|
if (!options.verifyUploader()) return {
|
|
1164
1202
|
ok: false,
|
|
1165
1203
|
reason: "uploader-changed"
|
|
1166
1204
|
};
|
|
1167
1205
|
options.onProgress?.("Checking the current Worker deployment...");
|
|
1168
|
-
const previous = await readCurrentProductionVersion(options,
|
|
1206
|
+
const previous = await readCurrentProductionVersion(options, configPath);
|
|
1169
1207
|
if (previous.kind === "failed") return {
|
|
1170
1208
|
ok: false,
|
|
1171
1209
|
reason: "status-failed",
|
|
@@ -1186,12 +1224,20 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1186
1224
|
reason: "uploader-changed"
|
|
1187
1225
|
};
|
|
1188
1226
|
const previousVersionId = previous.versionId;
|
|
1227
|
+
if (options.atomic && options.requirePreviewForReadiness) return {
|
|
1228
|
+
ok: false,
|
|
1229
|
+
reason: "preview-unavailable",
|
|
1230
|
+
previousVersionId,
|
|
1231
|
+
rollback: "not-needed",
|
|
1232
|
+
diagnostic: "This binding-preserving handoff requires a candidate preview before activation. Configure version metadata on the existing Worker or retry without atomic publication; production traffic is unchanged."
|
|
1233
|
+
};
|
|
1189
1234
|
const trustedInheritanceVersionIds = previousVersionId && options.trustedInheritanceVersionIds?.at(-1) === previousVersionId ? [] : options.trustedInheritanceVersionIds;
|
|
1190
1235
|
let inheritanceBaseline;
|
|
1191
1236
|
let trustedCandidateChain = false;
|
|
1192
1237
|
let activeSecretsPinned = false;
|
|
1238
|
+
let pinnedActiveSecrets;
|
|
1193
1239
|
if (options.expectedPreviousVersionId !== void 0 || options.verifyInheritedSecrets === true) {
|
|
1194
|
-
const recent = await readRecentCloudflareVersionIds(options,
|
|
1240
|
+
const recent = await readRecentCloudflareVersionIds(options, configPath);
|
|
1195
1241
|
if (recent === null) return {
|
|
1196
1242
|
ok: false,
|
|
1197
1243
|
reason: "inheritance-source-unavailable"
|
|
@@ -1210,13 +1256,13 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1210
1256
|
};
|
|
1211
1257
|
}
|
|
1212
1258
|
if (options.verifyInheritedSecrets === true && previous.versionId !== latestVersionId && !trustedCandidateChain) {
|
|
1213
|
-
const replacesAllRemoteSecrets = await candidateReplacesAllRemoteSecrets(options,
|
|
1259
|
+
const replacesAllRemoteSecrets = await candidateReplacesAllRemoteSecrets(options, configPath, previous.versionId, latestVersionId);
|
|
1214
1260
|
if (replacesAllRemoteSecrets === null) return {
|
|
1215
1261
|
ok: false,
|
|
1216
1262
|
reason: "inheritance-source-unavailable"
|
|
1217
1263
|
};
|
|
1218
1264
|
if (!replacesAllRemoteSecrets) {
|
|
1219
|
-
const activeSecrets = previous.versionId ? await readCloudflareVersionSecretBindings(options,
|
|
1265
|
+
const activeSecrets = previous.versionId ? await readCloudflareVersionSecretBindings(options, configPath, previous.versionId) : null;
|
|
1220
1266
|
if (!activeSecrets || !options.pinActiveSecrets || !await options.pinActiveSecrets(previous.versionId, activeSecrets)) return {
|
|
1221
1267
|
ok: false,
|
|
1222
1268
|
reason: "inheritance-source-changed",
|
|
@@ -1224,16 +1270,17 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1224
1270
|
rollback: "not-needed"
|
|
1225
1271
|
};
|
|
1226
1272
|
activeSecretsPinned = true;
|
|
1273
|
+
pinnedActiveSecrets = activeSecrets;
|
|
1227
1274
|
}
|
|
1228
1275
|
}
|
|
1229
1276
|
inheritanceBaseline = recent;
|
|
1230
1277
|
}
|
|
1231
1278
|
const desiredMetadata = parseCloudflareVersionMessage(options.message);
|
|
1232
1279
|
let desiredTriggerConfig = desiredMetadata?.schema === 2 ? desiredMetadata.triggerConfig : options.configPath ? readCloudflareTriggerConfig(options.configPath) : triggerConfigFromWrangler({});
|
|
1233
|
-
let previousVersion = previousVersionId && desiredMetadata?.schema === 2 ? await readCloudflareVersionInspection(options,
|
|
1280
|
+
let previousVersion = previousVersionId && desiredMetadata?.schema === 2 ? await readCloudflareVersionInspection(options, configPath, previousVersionId, inheritanceBaseline?.map((version) => version.inspection)) : null;
|
|
1234
1281
|
async function previousIsSecretOnlyDraft() {
|
|
1235
1282
|
if (!previousVersionId) return false;
|
|
1236
|
-
previousVersion ??= await readCloudflareVersionInspection(options,
|
|
1283
|
+
previousVersion ??= await readCloudflareVersionInspection(options, configPath, previousVersionId, inheritanceBaseline?.map((version) => version.inspection));
|
|
1237
1284
|
return previousVersion?.isSecretOnlyDraft === true;
|
|
1238
1285
|
}
|
|
1239
1286
|
const previousMetadata = desiredMetadata?.schema === 2 ? previousVersion?.metadata : null;
|
|
@@ -1265,59 +1312,142 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1265
1312
|
} : versionedPreviousTriggerConfig;
|
|
1266
1313
|
const previousTriggerConfig = triggerConfigWithQueueConsumerCleanup(versionedPreviousTriggerConfigWithTraffic, options.queueConsumerCleanup);
|
|
1267
1314
|
const alias = `void-ready-${Date.now().toString(36)}`;
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1315
|
+
const bootstrapVoidDraft = !options.preserveTriggers && !options.requirePreviewForReadiness && previousVersion?.isVoidSecretOnlyDraft === true;
|
|
1316
|
+
if (previous.versionId !== null && (options.atomic || bootstrapVoidDraft)) {
|
|
1317
|
+
if (bootstrapVoidDraft && !activeSecretsPinned && !options.pinActiveSecrets) return {
|
|
1318
|
+
ok: false,
|
|
1319
|
+
reason: "inheritance-source-unavailable"
|
|
1320
|
+
};
|
|
1321
|
+
if (bootstrapVoidDraft || !activeSecretsPinned && options.pinActiveSecrets) {
|
|
1322
|
+
let activeSecrets;
|
|
1323
|
+
try {
|
|
1324
|
+
activeSecrets = await readCloudflareVersionSecretBindings(options, configPath, previous.versionId);
|
|
1325
|
+
} catch {
|
|
1326
|
+
return {
|
|
1327
|
+
ok: false,
|
|
1328
|
+
reason: "inheritance-source-unavailable"
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
if (activeSecrets === null) return {
|
|
1332
|
+
ok: false,
|
|
1333
|
+
reason: "inheritance-source-unavailable"
|
|
1334
|
+
};
|
|
1335
|
+
if (bootstrapVoidDraft && (activeSecrets.length === 0 || activeSecrets.some((secret) => secret.type !== "secret_text") || !arraysEqual(activeSecrets.map((secret) => secret.name).sort(), [...previousVersion.voidDraftSecretNames].sort()) || activeSecretsPinned && !isDeepStrictEqual([...activeSecrets].sort((a, b) => a.name.localeCompare(b.name)), [...pinnedActiveSecrets].sort((a, b) => a.name.localeCompare(b.name))))) return {
|
|
1336
|
+
ok: false,
|
|
1337
|
+
reason: "inheritance-source-changed"
|
|
1338
|
+
};
|
|
1339
|
+
if (!activeSecretsPinned && activeSecrets.length) {
|
|
1340
|
+
let pinned;
|
|
1341
|
+
try {
|
|
1342
|
+
pinned = await options.pinActiveSecrets(previous.versionId, activeSecrets);
|
|
1343
|
+
} catch {
|
|
1344
|
+
return {
|
|
1345
|
+
ok: false,
|
|
1346
|
+
reason: "inheritance-source-unavailable"
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
if (!pinned) return {
|
|
1350
|
+
ok: false,
|
|
1351
|
+
reason: "inheritance-source-changed"
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1272
1354
|
}
|
|
1273
1355
|
return bootstrapFirstDeployment({
|
|
1274
1356
|
...options,
|
|
1275
1357
|
message
|
|
1276
|
-
},
|
|
1358
|
+
}, configPath, previous.versionId, options.atomic === true, previousTriggerConfig);
|
|
1359
|
+
}
|
|
1360
|
+
if (previous.versionId !== null && !activeSecretsPinned && options.pinActiveSecrets && options.candidateSecretsFilePath === void 0) {
|
|
1361
|
+
let activeSecrets;
|
|
1362
|
+
try {
|
|
1363
|
+
activeSecrets = await readCloudflareVersionSecretBindings(options, configPath, previous.versionId);
|
|
1364
|
+
} catch {
|
|
1365
|
+
return {
|
|
1366
|
+
ok: false,
|
|
1367
|
+
reason: "inheritance-source-unavailable"
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
if (activeSecrets === null) return {
|
|
1371
|
+
ok: false,
|
|
1372
|
+
reason: "inheritance-source-unavailable"
|
|
1373
|
+
};
|
|
1374
|
+
if (activeSecrets.some((secret) => !secret.name.trim() || secret.name.trim() !== secret.name) || new Set(activeSecrets.map((secret) => secret.name)).size !== activeSecrets.length) return {
|
|
1375
|
+
ok: false,
|
|
1376
|
+
reason: "inheritance-source-changed"
|
|
1377
|
+
};
|
|
1378
|
+
if (activeSecrets.length) {
|
|
1379
|
+
let pinned;
|
|
1380
|
+
try {
|
|
1381
|
+
pinned = await options.pinActiveSecrets(previous.versionId, activeSecrets);
|
|
1382
|
+
} catch {
|
|
1383
|
+
return {
|
|
1384
|
+
ok: false,
|
|
1385
|
+
reason: "inheritance-source-unavailable"
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
if (!pinned) return {
|
|
1389
|
+
ok: false,
|
|
1390
|
+
reason: "inheritance-source-changed"
|
|
1391
|
+
};
|
|
1392
|
+
activeSecretsPinned = true;
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
if (activeSecretsPinned) {
|
|
1396
|
+
if (!options.verifyUploader()) return {
|
|
1397
|
+
ok: false,
|
|
1398
|
+
reason: "uploader-changed"
|
|
1399
|
+
};
|
|
1400
|
+
const owner = await readCurrentProductionVersion(options, configPath);
|
|
1401
|
+
if (owner.kind === "failed") return {
|
|
1402
|
+
ok: false,
|
|
1403
|
+
reason: "status-failed",
|
|
1404
|
+
status: owner.status
|
|
1405
|
+
};
|
|
1406
|
+
if (owner.kind !== "ok" || owner.versionId !== previous.versionId || !productionVersionPercentagesEqual(owner.versions, [{
|
|
1407
|
+
versionId: previous.versionId,
|
|
1408
|
+
percentage: 100
|
|
1409
|
+
}])) return {
|
|
1410
|
+
ok: false,
|
|
1411
|
+
reason: "deployment-changed",
|
|
1412
|
+
activeVersionId: owner.kind === "ok" ? owner.versionId : null,
|
|
1413
|
+
rollback: "not-needed"
|
|
1414
|
+
};
|
|
1277
1415
|
}
|
|
1278
1416
|
options.onProgress?.("Uploading the Worker and assets...");
|
|
1279
|
-
const upload = await Promise.resolve(options.runWrangler(
|
|
1280
|
-
"versions",
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
"--name",
|
|
1284
|
-
options.workerName,
|
|
1285
|
-
"--message",
|
|
1417
|
+
const upload = await Promise.resolve(options.runWrangler({
|
|
1418
|
+
type: "versions.upload",
|
|
1419
|
+
configPath,
|
|
1420
|
+
workerName: options.workerName,
|
|
1286
1421
|
message,
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
"--strict",
|
|
1292
|
-
"--experimental-provision=false",
|
|
1293
|
-
"--experimental-auto-create=false"
|
|
1294
|
-
], { capture: true }));
|
|
1422
|
+
secretsFilePath: options.candidateSecretsFilePath,
|
|
1423
|
+
assetsDirectory: options.assetsDirectoryOverride,
|
|
1424
|
+
previewAlias: alias
|
|
1425
|
+
}, { capture: true }));
|
|
1295
1426
|
if (!isCleanCommandExit(upload)) {
|
|
1296
|
-
const
|
|
1297
|
-
const
|
|
1298
|
-
const isBootstrapError = cloudflareErrorCode === DURABLE_MIGRATION_VERSION_ERROR || /This\s+Worker\s+has\s+a\s+pending\s+Durable\s+Object\s+migration,\s+which\s+cannot\s+be\s+applied\s+by\s+`wrangler\s+versions\s+upload`/i.test(output) || /cannot upload a new version of a worker that does not yet exist/i.test(output);
|
|
1427
|
+
const cloudflareErrorCode = upload.errorCode;
|
|
1428
|
+
const isBootstrapError = isCompletedCommand(upload) && (upload.failure === "durable-migration" || upload.failure === "not-found" || cloudflareErrorCode === DURABLE_MIGRATION_VERSION_ERROR || cloudflareErrorCode === 10007);
|
|
1299
1429
|
if (!options.preserveTriggers && isBootstrapError && (previous.versionId === null || options.allowFirstDeploymentBootstrap === true || await previousIsSecretOnlyDraft())) return bootstrapFirstDeployment({
|
|
1300
1430
|
...options,
|
|
1301
1431
|
message
|
|
1302
|
-
},
|
|
1432
|
+
}, configPath, previous.versionId, false, previousTriggerConfig);
|
|
1303
1433
|
return {
|
|
1304
1434
|
ok: false,
|
|
1305
1435
|
reason: "upload-failed",
|
|
1306
1436
|
status: upload.status,
|
|
1307
1437
|
...commandDiagnosticFields(upload),
|
|
1308
1438
|
...cloudflareErrorCode === void 0 ? {} : { cloudflareErrorCode },
|
|
1309
|
-
...isContainersUnavailable(
|
|
1439
|
+
...isContainersUnavailable(upload) ? { containersUnavailable: true } : {}
|
|
1310
1440
|
};
|
|
1311
1441
|
}
|
|
1312
|
-
const
|
|
1313
|
-
const versionId =
|
|
1442
|
+
const uploaded = readUploadResult(upload);
|
|
1443
|
+
const versionId = uploaded?.versionId;
|
|
1314
1444
|
if (!versionId) return {
|
|
1315
1445
|
ok: false,
|
|
1316
1446
|
reason: "upload-output-invalid"
|
|
1317
1447
|
};
|
|
1318
1448
|
options.onProgress?.("Verifying the uploaded Worker...");
|
|
1319
1449
|
if (inheritanceBaseline) {
|
|
1320
|
-
const recent = await readRecentCloudflareVersionIds(options,
|
|
1450
|
+
const recent = await readRecentCloudflareVersionIds(options, configPath);
|
|
1321
1451
|
const previousLatest = inheritanceBaseline.at(-1);
|
|
1322
1452
|
const expected = [...inheritanceBaseline.map((version) => version.id), versionId].slice(-10);
|
|
1323
1453
|
if (recent === null) return {
|
|
@@ -1342,7 +1472,15 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1342
1472
|
if (!options.validateUploadedVersion && !inheritanceBaseline) throw new Error("A Worker candidate cannot be recorded without validating its upload and version sequence.");
|
|
1343
1473
|
await options.recordVerifiedCandidate(versionId, previous.versionId);
|
|
1344
1474
|
}
|
|
1345
|
-
const reportedPreviewUrl =
|
|
1475
|
+
const reportedPreviewUrl = desiredTriggerConfig.preview_urls || desiredTriggerConfig.preservePreviewUrls || desiredTriggerConfig.preserve ? uploaded?.previewUrl : void 0;
|
|
1476
|
+
if (options.requirePreviewForReadiness && (!reportedPreviewUrl || !isCandidatePreviewUrl(reportedPreviewUrl, options.workerName, versionId, alias))) return {
|
|
1477
|
+
ok: false,
|
|
1478
|
+
reason: "preview-unavailable",
|
|
1479
|
+
versionId,
|
|
1480
|
+
previousVersionId,
|
|
1481
|
+
rollback: "not-needed",
|
|
1482
|
+
diagnostic: "This existing Worker has no version metadata binding and no genuine candidate preview URL. Keep its bindings unchanged; configure version metadata on the existing Worker or use an admitted version preview, then retry the handoff. Production traffic is unchanged."
|
|
1483
|
+
};
|
|
1346
1484
|
let authenticatedWorkersDevSubdomain = reportedPreviewUrl ? extractWorkersDevSubdomain(reportedPreviewUrl) : void 0;
|
|
1347
1485
|
let readinessUrl = reportedPreviewUrl;
|
|
1348
1486
|
let readinessUsesCustomRoute = false;
|
|
@@ -1351,7 +1489,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1351
1489
|
if (!options.preserveTriggers && (previous.versionId === null || options.allowFirstDeploymentBootstrap === true || await previousIsSecretOnlyDraft())) return bootstrapFirstDeployment({
|
|
1352
1490
|
...options,
|
|
1353
1491
|
message
|
|
1354
|
-
},
|
|
1492
|
+
}, configPath, previous.versionId, false, previousTriggerConfig);
|
|
1355
1493
|
readinessUrl = desiredTriggerConfig.workers_dev ? workersDevReadinessUrl(options.workerName, options.workersDevSubdomain) : customRouteReadinessUrl(desiredTriggerConfig.routes);
|
|
1356
1494
|
readinessUsesCustomRoute = !desiredTriggerConfig.workers_dev && readinessUrl !== void 0;
|
|
1357
1495
|
if (!readinessUrl) return {
|
|
@@ -1369,11 +1507,11 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1369
1507
|
previousVersionId: previous.versionId,
|
|
1370
1508
|
rollback: "not-needed"
|
|
1371
1509
|
};
|
|
1372
|
-
const stagingOwnerFailure = await verifyReadinessStagingOwner(options,
|
|
1510
|
+
const stagingOwnerFailure = await verifyReadinessStagingOwner(options, configPath, previous.versionId, versionId);
|
|
1373
1511
|
if (stagingOwnerFailure) return stagingOwnerFailure;
|
|
1374
|
-
const staged = await deployVersionPercentages(options,
|
|
1512
|
+
const staged = await deployVersionPercentages(options, configPath, [`${previous.versionId}@100`, `${versionId}@0`], message);
|
|
1375
1513
|
if (!isCleanCommandExit(staged)) {
|
|
1376
|
-
const cloudflareErrorCode =
|
|
1514
|
+
const cloudflareErrorCode = staged.errorCode;
|
|
1377
1515
|
return {
|
|
1378
1516
|
ok: false,
|
|
1379
1517
|
reason: "readiness-staging-failed",
|
|
@@ -1388,8 +1526,8 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1388
1526
|
stagedVersionOverride = true;
|
|
1389
1527
|
}
|
|
1390
1528
|
options.onProgress?.("Waiting for the Worker to become ready...");
|
|
1391
|
-
let ready = await probeReadiness(`${readinessUrl.replace(/\/$/, "")}/__void/ready`, options.workerName, readinessUsesCustomRoute ? void 0 : options.readinessHeaders, authenticatedWorkersDevSubdomain, stagedVersionOverride ? versionId : void 0, options.fetch ?? globalThis.fetch, options.sleep ?? defaultSleep, options.readinessAttempts ?? 6);
|
|
1392
|
-
if (ready === "access-denied" && !stagedVersionOverride && previous.versionId !== null) {
|
|
1529
|
+
let ready = await probeReadiness(`${readinessUrl.replace(/\/$/, "")}/__void/ready`, options.workerName, readinessUsesCustomRoute ? void 0 : options.readinessHeaders, authenticatedWorkersDevSubdomain, stagedVersionOverride ? versionId : void 0, options.fetch ?? globalThis.fetch, options.sleep ?? defaultSleep, options.readinessAttempts ?? 6, Number.POSITIVE_INFINITY, options.requireVersionMetadata ? versionId : void 0);
|
|
1530
|
+
if (ready === "access-denied" && !stagedVersionOverride && previous.versionId !== null && !options.requirePreviewForReadiness) {
|
|
1393
1531
|
const stableReadinessUrl = desiredTriggerConfig.workers_dev ? workersDevReadinessUrl(options.workerName, extractWorkersDevSubdomain(readinessUrl) ?? options.workersDevSubdomain) : customRouteReadinessUrl(desiredTriggerConfig.routes);
|
|
1394
1532
|
if (stableReadinessUrl && stableReadinessUrl !== readinessUrl) {
|
|
1395
1533
|
if (!options.verifyUploader()) return {
|
|
@@ -1399,11 +1537,11 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1399
1537
|
previousVersionId: previous.versionId,
|
|
1400
1538
|
rollback: "not-needed"
|
|
1401
1539
|
};
|
|
1402
|
-
const stagingOwnerFailure = await verifyReadinessStagingOwner(options,
|
|
1540
|
+
const stagingOwnerFailure = await verifyReadinessStagingOwner(options, configPath, previous.versionId, versionId);
|
|
1403
1541
|
if (stagingOwnerFailure) return stagingOwnerFailure;
|
|
1404
|
-
const staged = await deployVersionPercentages(options,
|
|
1542
|
+
const staged = await deployVersionPercentages(options, configPath, [`${previous.versionId}@100`, `${versionId}@0`], message);
|
|
1405
1543
|
if (!isCleanCommandExit(staged)) {
|
|
1406
|
-
const cloudflareErrorCode =
|
|
1544
|
+
const cloudflareErrorCode = staged.errorCode;
|
|
1407
1545
|
return {
|
|
1408
1546
|
ok: false,
|
|
1409
1547
|
reason: "readiness-staging-failed",
|
|
@@ -1419,7 +1557,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1419
1557
|
authenticatedWorkersDevSubdomain = extractWorkersDevSubdomain(stableReadinessUrl);
|
|
1420
1558
|
readinessUsesCustomRoute = !desiredTriggerConfig.workers_dev;
|
|
1421
1559
|
stagedVersionOverride = true;
|
|
1422
|
-
ready = await probeReadiness(`${readinessUrl.replace(/\/$/, "")}/__void/ready`, options.workerName, readinessUsesCustomRoute ? void 0 : options.readinessHeaders, authenticatedWorkersDevSubdomain, versionId, options.fetch ?? globalThis.fetch, options.sleep ?? defaultSleep, options.readinessAttempts ?? 6);
|
|
1560
|
+
ready = await probeReadiness(`${readinessUrl.replace(/\/$/, "")}/__void/ready`, options.workerName, readinessUsesCustomRoute ? void 0 : options.readinessHeaders, authenticatedWorkersDevSubdomain, versionId, options.fetch ?? globalThis.fetch, options.sleep ?? defaultSleep, options.readinessAttempts ?? 6, Number.POSITIVE_INFINITY, options.requireVersionMetadata ? versionId : void 0);
|
|
1423
1561
|
}
|
|
1424
1562
|
}
|
|
1425
1563
|
if (ready !== "ready") return {
|
|
@@ -1427,16 +1565,16 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1427
1565
|
reason: ready === "access-denied" ? "readiness-access-denied" : "readiness-failed",
|
|
1428
1566
|
versionId,
|
|
1429
1567
|
previousVersionId: previous.versionId,
|
|
1430
|
-
rollback: stagedVersionOverride ? await restorePreviousVersion(options,
|
|
1568
|
+
rollback: stagedVersionOverride ? await restorePreviousVersion(options, configPath, previous.versionId, "readiness failed", [stagedVersionPercentages(previous.versionId, versionId)]) : "not-needed"
|
|
1431
1569
|
};
|
|
1432
1570
|
if (!options.verifyUploader()) return {
|
|
1433
1571
|
ok: false,
|
|
1434
1572
|
reason: "uploader-changed",
|
|
1435
1573
|
versionId,
|
|
1436
1574
|
previousVersionId: previous.versionId,
|
|
1437
|
-
rollback: stagedVersionOverride ? await restorePreviousVersion(options,
|
|
1575
|
+
rollback: stagedVersionOverride ? await restorePreviousVersion(options, configPath, previous.versionId, "uploader verification failed", [stagedVersionPercentages(previous.versionId, versionId)]) : "not-needed"
|
|
1438
1576
|
};
|
|
1439
|
-
const ownerBeforeActivation = await readCurrentProductionVersion(options,
|
|
1577
|
+
const ownerBeforeActivation = await readCurrentProductionVersion(options, configPath);
|
|
1440
1578
|
if (ownerBeforeActivation.kind === "failed") return {
|
|
1441
1579
|
ok: false,
|
|
1442
1580
|
reason: "status-failed",
|
|
@@ -1464,14 +1602,14 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1464
1602
|
triggerRepair: "succeeded"
|
|
1465
1603
|
};
|
|
1466
1604
|
options.onProgress?.("Activating the Worker...");
|
|
1467
|
-
const activate = await deployVersionPercentages(options,
|
|
1605
|
+
const activate = await deployVersionPercentages(options, configPath, [`${versionId}@100`], message);
|
|
1468
1606
|
if (!isCleanCommandExit(activate)) return {
|
|
1469
1607
|
ok: false,
|
|
1470
1608
|
reason: "activation-failed",
|
|
1471
1609
|
status: activate.status,
|
|
1472
1610
|
versionId,
|
|
1473
1611
|
previousVersionId: previous.versionId,
|
|
1474
|
-
rollback: stagedVersionOverride ? await restorePreviousVersion(options,
|
|
1612
|
+
rollback: stagedVersionOverride ? await restorePreviousVersion(options, configPath, previous.versionId, "version activation failed", [stagedVersionPercentages(previous.versionId, versionId), [{
|
|
1475
1613
|
versionId,
|
|
1476
1614
|
percentage: 100
|
|
1477
1615
|
}]]) : "not-needed"
|
|
@@ -1484,7 +1622,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1484
1622
|
rollback: previous.versionId ? "unsafe" : "unavailable"
|
|
1485
1623
|
};
|
|
1486
1624
|
if (options.preserveTriggers) {
|
|
1487
|
-
const owner = await readCurrentProductionVersion(options,
|
|
1625
|
+
const owner = await readCurrentProductionVersion(options, configPath);
|
|
1488
1626
|
if (owner.kind !== "ok" || owner.versionId !== versionId) return {
|
|
1489
1627
|
ok: false,
|
|
1490
1628
|
reason: "deployment-changed",
|
|
@@ -1535,7 +1673,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1535
1673
|
previousVersionId: previous.versionId,
|
|
1536
1674
|
rollback: "unsafe"
|
|
1537
1675
|
};
|
|
1538
|
-
const ownerBeforeCompensation = await readCurrentProductionVersion(options,
|
|
1676
|
+
const ownerBeforeCompensation = await readCurrentProductionVersion(options, configPath);
|
|
1539
1677
|
if (ownerBeforeCompensation.kind !== "ok" || ownerBeforeCompensation.versionId === null) return {
|
|
1540
1678
|
ok: false,
|
|
1541
1679
|
reason: "triggers-failed",
|
|
@@ -1567,7 +1705,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1567
1705
|
triggerRepair: repair.ok ? "succeeded" : repair.reason === "metadata-unavailable" ? "unavailable" : "failed"
|
|
1568
1706
|
};
|
|
1569
1707
|
}
|
|
1570
|
-
const rollback = await restorePreviousVersionAndTriggers(options,
|
|
1708
|
+
const rollback = await restorePreviousVersionAndTriggers(options, configPath, previous.versionId, "trigger activation failed", desiredTriggerConfig, versionId, versionedPreviousTriggerConfigWithTraffic);
|
|
1571
1709
|
return {
|
|
1572
1710
|
ok: false,
|
|
1573
1711
|
reason: "triggers-failed",
|
|
@@ -1600,8 +1738,8 @@ async function activateCloudflareVersionWithSecretsFile(options) {
|
|
|
1600
1738
|
...workersDevSubdomainResult(readinessUrl)
|
|
1601
1739
|
};
|
|
1602
1740
|
}
|
|
1603
|
-
async function restorePreviousVersionAndTriggers(options,
|
|
1604
|
-
const traffic = await restorePreviousVersion(options,
|
|
1741
|
+
async function restorePreviousVersionAndTriggers(options, configPath, previousVersionId, cause, failedTriggerConfig, failedVersionId, capturedTriggerConfig) {
|
|
1742
|
+
const traffic = await restorePreviousVersion(options, configPath, previousVersionId, cause, [[{
|
|
1605
1743
|
versionId: failedVersionId,
|
|
1606
1744
|
percentage: 100
|
|
1607
1745
|
}]]);
|
|
@@ -1609,7 +1747,7 @@ async function restorePreviousVersionAndTriggers(options, commonArgs, previousVe
|
|
|
1609
1747
|
if (!options.verifyUploader()) return "unsafe";
|
|
1610
1748
|
let targetTriggerConfig = capturedTriggerConfig;
|
|
1611
1749
|
if (!targetTriggerConfig) {
|
|
1612
|
-
const metadata = await readCloudflareVersionMetadata(options,
|
|
1750
|
+
const metadata = await readCloudflareVersionMetadata(options, configPath, previousVersionId);
|
|
1613
1751
|
if (metadata?.schema !== 2) return "unavailable";
|
|
1614
1752
|
targetTriggerConfig = metadata.triggerConfig;
|
|
1615
1753
|
}
|
|
@@ -1628,23 +1766,20 @@ async function restorePreviousVersionAndTriggers(options, commonArgs, previousVe
|
|
|
1628
1766
|
});
|
|
1629
1767
|
return triggers.ok && triggers.targetOwnsTraffic ? "succeeded" : "failed";
|
|
1630
1768
|
}
|
|
1631
|
-
async function readCloudflareVersionMetadata(options,
|
|
1632
|
-
return (await readCloudflareVersionInspection(options,
|
|
1769
|
+
async function readCloudflareVersionMetadata(options, configPath, versionId) {
|
|
1770
|
+
return (await readCloudflareVersionInspection(options, configPath, versionId))?.metadata ?? null;
|
|
1633
1771
|
}
|
|
1634
|
-
async function readCloudflareVersionInspection(options,
|
|
1772
|
+
async function readCloudflareVersionInspection(options, configPath, versionId, knownVersions) {
|
|
1635
1773
|
try {
|
|
1636
1774
|
let versions = knownVersions;
|
|
1637
1775
|
if (versions === void 0) {
|
|
1638
|
-
const result = await options.runWrangler(
|
|
1639
|
-
"versions",
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
options.workerName,
|
|
1644
|
-
"--json"
|
|
1645
|
-
], { capture: true });
|
|
1776
|
+
const result = await options.runWrangler({
|
|
1777
|
+
type: "versions.list",
|
|
1778
|
+
configPath,
|
|
1779
|
+
workerName: options.workerName
|
|
1780
|
+
}, { capture: true });
|
|
1646
1781
|
if (!isCleanCommandExit(result)) return null;
|
|
1647
|
-
versions =
|
|
1782
|
+
versions = result.data;
|
|
1648
1783
|
}
|
|
1649
1784
|
if (!Array.isArray(versions)) return null;
|
|
1650
1785
|
for (const entry of versions) {
|
|
@@ -1652,24 +1787,25 @@ async function readCloudflareVersionInspection(options, commonArgs, versionId, k
|
|
|
1652
1787
|
const annotations = isRecord(entry.annotations) ? entry.annotations : void 0;
|
|
1653
1788
|
const message = annotations?.["workers/message"];
|
|
1654
1789
|
let draft = entry;
|
|
1655
|
-
if (annotations?.["workers/triggered_by"] === "secret" && Object.keys(annotations).length === 1 && !
|
|
1656
|
-
const inspection = await Promise.resolve(options.runWrangler(
|
|
1657
|
-
"versions",
|
|
1658
|
-
"view",
|
|
1790
|
+
if (annotations?.["workers/triggered_by"] === "secret" && Object.keys(annotations).length === 1 && !isWranglerSecretOnlyDraft(entry)) {
|
|
1791
|
+
const inspection = await Promise.resolve(options.runWrangler({
|
|
1792
|
+
type: "versions.view",
|
|
1659
1793
|
versionId,
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
], { capture: true }));
|
|
1794
|
+
configPath,
|
|
1795
|
+
workerName: options.workerName,
|
|
1796
|
+
includeSource: true
|
|
1797
|
+
}, { capture: true }));
|
|
1665
1798
|
if (isCleanCommandExit(inspection)) {
|
|
1666
|
-
const inspected =
|
|
1799
|
+
const inspected = inspection.data;
|
|
1667
1800
|
if (isRecord(inspected) && inspected.id === versionId) draft = inspected;
|
|
1668
1801
|
}
|
|
1669
1802
|
}
|
|
1803
|
+
const isVoidDraft = isVoidSecretOnlyDraft(draft);
|
|
1670
1804
|
return {
|
|
1671
1805
|
metadata: typeof message === "string" ? parseCloudflareVersionMessage(message) : null,
|
|
1672
|
-
isSecretOnlyDraft: isWranglerSecretOnlyDraft(draft)
|
|
1806
|
+
isSecretOnlyDraft: isWranglerSecretOnlyDraft(draft) || isVoidSecretOnlyDraft(draft),
|
|
1807
|
+
isVoidSecretOnlyDraft: isVoidDraft,
|
|
1808
|
+
voidDraftSecretNames: isVoidDraft ? draft.bindings.map((binding) => binding.name) : null
|
|
1673
1809
|
};
|
|
1674
1810
|
}
|
|
1675
1811
|
} catch {
|
|
@@ -1677,21 +1813,18 @@ async function readCloudflareVersionInspection(options, commonArgs, versionId, k
|
|
|
1677
1813
|
}
|
|
1678
1814
|
return null;
|
|
1679
1815
|
}
|
|
1680
|
-
async function readRecentCloudflareVersionIds(options,
|
|
1681
|
-
const result = await Promise.resolve(options.runWrangler(
|
|
1682
|
-
"versions",
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
options.workerName,
|
|
1687
|
-
"--json"
|
|
1688
|
-
], { capture: true }));
|
|
1816
|
+
async function readRecentCloudflareVersionIds(options, configPath) {
|
|
1817
|
+
const result = await Promise.resolve(options.runWrangler({
|
|
1818
|
+
type: "versions.list",
|
|
1819
|
+
configPath,
|
|
1820
|
+
workerName: options.workerName
|
|
1821
|
+
}, { capture: true }));
|
|
1689
1822
|
if (!isCleanCommandExit(result)) {
|
|
1690
|
-
if (
|
|
1823
|
+
if (isCompletedCommand(result) && (result.failure === "not-found" || result.errorCode === 10007)) return [];
|
|
1691
1824
|
return null;
|
|
1692
1825
|
}
|
|
1693
1826
|
try {
|
|
1694
|
-
const versions =
|
|
1827
|
+
const versions = result.data;
|
|
1695
1828
|
if (!Array.isArray(versions) || !versions.every((version) => isRecord(version) && typeof version.id === "string" && typeof version.number === "number" && Number.isSafeInteger(version.number))) return null;
|
|
1696
1829
|
return versions.map((version) => ({
|
|
1697
1830
|
id: version.id,
|
|
@@ -1705,29 +1838,26 @@ async function readRecentCloudflareVersionIds(options, commonArgs) {
|
|
|
1705
1838
|
function arraysEqual(left, right) {
|
|
1706
1839
|
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
1707
1840
|
}
|
|
1708
|
-
async function candidateReplacesAllRemoteSecrets(options,
|
|
1841
|
+
async function candidateReplacesAllRemoteSecrets(options, configPath, activeVersionId, latestVersionId) {
|
|
1709
1842
|
const versionIds = [...new Set([activeVersionId, latestVersionId].filter(Boolean))];
|
|
1710
1843
|
const secretBindings = [];
|
|
1711
1844
|
for (const versionId of versionIds) {
|
|
1712
|
-
const bindings = await readCloudflareVersionSecretBindings(options,
|
|
1845
|
+
const bindings = await readCloudflareVersionSecretBindings(options, configPath, versionId);
|
|
1713
1846
|
if (bindings === null) return null;
|
|
1714
1847
|
secretBindings.push(bindings);
|
|
1715
1848
|
}
|
|
1716
1849
|
return secretBindings.every((bindings) => bindings.every((binding) => binding.type === "secret_text" && Object.hasOwn(options.candidateSecrets ?? {}, binding.name)));
|
|
1717
1850
|
}
|
|
1718
|
-
async function readCloudflareVersionSecretBindings(options,
|
|
1719
|
-
const result = await Promise.resolve(options.runWrangler(
|
|
1720
|
-
"versions",
|
|
1721
|
-
"view",
|
|
1851
|
+
async function readCloudflareVersionSecretBindings(options, configPath, versionId) {
|
|
1852
|
+
const result = await Promise.resolve(options.runWrangler({
|
|
1853
|
+
type: "versions.view",
|
|
1722
1854
|
versionId,
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
"--json"
|
|
1727
|
-
], { capture: true }));
|
|
1855
|
+
configPath,
|
|
1856
|
+
workerName: options.workerName
|
|
1857
|
+
}, { capture: true }));
|
|
1728
1858
|
if (!isCleanCommandExit(result)) return null;
|
|
1729
1859
|
try {
|
|
1730
|
-
const version =
|
|
1860
|
+
const version = result.data;
|
|
1731
1861
|
if (!isRecord(version) || version.id !== versionId || !isRecord(version.resources)) return null;
|
|
1732
1862
|
const bindings = version.resources.bindings;
|
|
1733
1863
|
if (!Array.isArray(bindings) || !bindings.every(isRecord)) return null;
|
|
@@ -1751,19 +1881,22 @@ async function readCloudflareVersionSecretBindings(options, commonArgs, versionI
|
|
|
1751
1881
|
* brand-new Worker can therefore need one ordinary deploy before later releases use preview-first
|
|
1752
1882
|
* version activation. This fallback requires prior proof that no application had been deployed.
|
|
1753
1883
|
*/
|
|
1754
|
-
async function bootstrapFirstDeployment(options,
|
|
1884
|
+
async function bootstrapFirstDeployment(options, configPath, previousVersionId, atomic = false, previousTriggerConfig) {
|
|
1755
1885
|
if (!options.verifyUploader()) return {
|
|
1756
1886
|
ok: false,
|
|
1757
1887
|
reason: "uploader-changed"
|
|
1758
1888
|
};
|
|
1759
|
-
|
|
1760
|
-
const current = await readCurrentProductionVersion(options,
|
|
1889
|
+
{
|
|
1890
|
+
const current = await readCurrentProductionVersion(options, configPath);
|
|
1761
1891
|
if (current.kind === "failed") return {
|
|
1762
1892
|
ok: false,
|
|
1763
1893
|
reason: "status-failed",
|
|
1764
1894
|
status: current.status
|
|
1765
1895
|
};
|
|
1766
|
-
if (current.kind !== "ok" || current.versionId !== previousVersionId
|
|
1896
|
+
if (current.kind !== "ok" || current.versionId !== previousVersionId || !productionVersionPercentagesEqual(current.versions, previousVersionId ? [{
|
|
1897
|
+
versionId: previousVersionId,
|
|
1898
|
+
percentage: 100
|
|
1899
|
+
}] : [])) return {
|
|
1767
1900
|
ok: false,
|
|
1768
1901
|
reason: "deployment-changed",
|
|
1769
1902
|
activeVersionId: current.kind === "ok" ? current.versionId : null,
|
|
@@ -1771,53 +1904,172 @@ async function bootstrapFirstDeployment(options, commonArgs, previousVersionId,
|
|
|
1771
1904
|
};
|
|
1772
1905
|
}
|
|
1773
1906
|
options.onProgress?.(atomic ? "Publishing the Worker atomically..." : "Publishing the first Worker deployment...");
|
|
1774
|
-
const bootstrap = await Promise.resolve(options.runWrangler(
|
|
1775
|
-
"deploy",
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
options.
|
|
1779
|
-
|
|
1780
|
-
options.
|
|
1781
|
-
|
|
1782
|
-
...options.assetsDirectoryOverride ? ["--assets", options.assetsDirectoryOverride] : [],
|
|
1783
|
-
"--strict",
|
|
1784
|
-
"--experimental-provision=false",
|
|
1785
|
-
"--experimental-auto-create=false",
|
|
1786
|
-
"--autoconfig=false"
|
|
1787
|
-
], { capture: true }));
|
|
1788
|
-
const output = `${bootstrap.stdout}\n${bootstrap.stderr}`;
|
|
1907
|
+
const bootstrap = await Promise.resolve(options.runWrangler({
|
|
1908
|
+
type: "worker.deploy",
|
|
1909
|
+
configPath,
|
|
1910
|
+
workerName: options.workerName,
|
|
1911
|
+
message: options.message,
|
|
1912
|
+
secretsFilePath: options.candidateSecretsFilePath,
|
|
1913
|
+
assetsDirectory: options.assetsDirectoryOverride
|
|
1914
|
+
}, { capture: true }));
|
|
1789
1915
|
if (!isCleanCommandExit(bootstrap)) {
|
|
1790
|
-
const cloudflareErrorCode =
|
|
1916
|
+
const cloudflareErrorCode = bootstrap.errorCode;
|
|
1791
1917
|
return {
|
|
1792
1918
|
ok: false,
|
|
1793
1919
|
reason: atomic ? "atomic-failed" : "bootstrap-failed",
|
|
1794
1920
|
status: bootstrap.status,
|
|
1795
1921
|
...commandDiagnosticFields(bootstrap),
|
|
1796
1922
|
...cloudflareErrorCode === void 0 ? {} : { cloudflareErrorCode },
|
|
1797
|
-
...isContainersUnavailable(
|
|
1923
|
+
...isContainersUnavailable(bootstrap) ? { containersUnavailable: true } : {}
|
|
1798
1924
|
};
|
|
1799
1925
|
}
|
|
1800
|
-
const
|
|
1926
|
+
const published = readUploadResult(bootstrap);
|
|
1927
|
+
const versionId = published?.versionId;
|
|
1801
1928
|
const desiredMetadata = parseCloudflareVersionMessage(options.message);
|
|
1802
1929
|
const desiredTriggerConfig = desiredMetadata?.schema === 2 ? desiredMetadata.triggerConfig : options.configPath ? readCloudflareTriggerConfig(options.configPath) : triggerConfigFromWrangler({});
|
|
1803
|
-
const
|
|
1804
|
-
const reportedOrConfiguredUrl = reportedUrl ?? (desiredTriggerConfig.workers_dev ? workersDevReadinessUrl(options.workerName, options.workersDevSubdomain) : customRouteReadinessUrl(desiredTriggerConfig.routes));
|
|
1930
|
+
const reportedOrConfiguredUrl = published?.previewUrl ?? published?.workersDevUrl ?? (desiredTriggerConfig.workers_dev ? workersDevReadinessUrl(options.workerName, options.workersDevSubdomain) : customRouteReadinessUrl(desiredTriggerConfig.routes));
|
|
1805
1931
|
if (!versionId || !reportedOrConfiguredUrl) return {
|
|
1806
1932
|
ok: false,
|
|
1807
1933
|
reason: atomic ? "atomic-output-invalid" : "bootstrap-output-invalid",
|
|
1808
1934
|
previousVersionId,
|
|
1809
1935
|
...versionId ? { versionId } : {}
|
|
1810
1936
|
};
|
|
1937
|
+
if (!options.verifyUploader()) return {
|
|
1938
|
+
ok: false,
|
|
1939
|
+
reason: "uploader-changed",
|
|
1940
|
+
versionId,
|
|
1941
|
+
previousVersionId,
|
|
1942
|
+
rollback: "unsafe"
|
|
1943
|
+
};
|
|
1944
|
+
const triggerOptions = {
|
|
1945
|
+
runWrangler: options.runWrangler,
|
|
1946
|
+
workerName: options.workerName,
|
|
1947
|
+
configPath: options.configPath,
|
|
1948
|
+
targetVersionId: versionId,
|
|
1949
|
+
targetTriggerConfig: options.preserveTriggers ? {
|
|
1950
|
+
...desiredTriggerConfig,
|
|
1951
|
+
preserve: true
|
|
1952
|
+
} : desiredTriggerConfig,
|
|
1953
|
+
previousTriggerConfig,
|
|
1954
|
+
...previousVersionId && previousTriggerConfig ? { knownTriggerConfigs: { [previousVersionId]: previousTriggerConfig } } : {},
|
|
1955
|
+
publishEmptyCustomDomains: options.publishEmptyCustomDomains,
|
|
1956
|
+
publishEmptyCrons: options.publishEmptyCrons
|
|
1957
|
+
};
|
|
1958
|
+
const verifyPublishedOwner = async () => {
|
|
1959
|
+
const owner = await readCurrentProductionVersion(options, configPath);
|
|
1960
|
+
if (owner.kind === "failed") return {
|
|
1961
|
+
ok: false,
|
|
1962
|
+
reason: "status-failed",
|
|
1963
|
+
status: owner.status,
|
|
1964
|
+
versionId,
|
|
1965
|
+
previousVersionId,
|
|
1966
|
+
rollback: "unsafe"
|
|
1967
|
+
};
|
|
1968
|
+
if (owner.kind !== "ok" || owner.versionId !== versionId || !productionVersionPercentagesEqual(owner.versions, [{
|
|
1969
|
+
versionId,
|
|
1970
|
+
percentage: 100
|
|
1971
|
+
}])) {
|
|
1972
|
+
const repair = owner.kind === "ok" && owner.versionId && owner.versionId !== versionId && options.verifyUploader() ? await stabilizeCloudflareVersionTriggers({
|
|
1973
|
+
...triggerOptions,
|
|
1974
|
+
targetTriggerConfig: {
|
|
1975
|
+
...desiredTriggerConfig,
|
|
1976
|
+
preserve: true
|
|
1977
|
+
}
|
|
1978
|
+
}) : null;
|
|
1979
|
+
return {
|
|
1980
|
+
ok: false,
|
|
1981
|
+
reason: "deployment-changed",
|
|
1982
|
+
versionId,
|
|
1983
|
+
previousVersionId,
|
|
1984
|
+
activeVersionId: repair?.activeVersionId ?? (owner.kind === "ok" ? owner.versionId : null),
|
|
1985
|
+
rollback: "not-needed",
|
|
1986
|
+
...repair ? { triggerRepair: repair.ok && !repair.targetOwnsTraffic ? "succeeded" : !repair.ok && repair.reason !== "metadata-unavailable" ? "failed" : "unavailable" } : {}
|
|
1987
|
+
};
|
|
1988
|
+
}
|
|
1989
|
+
return null;
|
|
1990
|
+
};
|
|
1991
|
+
const publishedOwnerFailure = await verifyPublishedOwner();
|
|
1992
|
+
if (publishedOwnerFailure) return publishedOwnerFailure;
|
|
1993
|
+
if (options.validateUploadedVersion || options.recordVerifiedCandidate) {
|
|
1994
|
+
options.onProgress?.("Verifying the uploaded Worker...");
|
|
1995
|
+
try {
|
|
1996
|
+
await options.validateUploadedVersion?.(versionId);
|
|
1997
|
+
const validatedOwnerFailure = await verifyPublishedOwner();
|
|
1998
|
+
if (validatedOwnerFailure) return validatedOwnerFailure;
|
|
1999
|
+
if (options.recordVerifiedCandidate) {
|
|
2000
|
+
if (!options.validateUploadedVersion && !options.verifyInheritedSecrets && options.expectedPreviousVersionId === void 0) throw new Error("The bootstrap upload has no verified candidate checkpoint.");
|
|
2001
|
+
await options.recordVerifiedCandidate(versionId, previousVersionId);
|
|
2002
|
+
}
|
|
2003
|
+
} catch {
|
|
2004
|
+
return {
|
|
2005
|
+
ok: false,
|
|
2006
|
+
reason: atomic ? "atomic-failed" : "bootstrap-failed",
|
|
2007
|
+
versionId,
|
|
2008
|
+
previousVersionId,
|
|
2009
|
+
rollback: "unavailable",
|
|
2010
|
+
diagnostic: `Worker version ${versionId} was published, but its upload validation or candidate checkpoint failed. Inspect the current Worker deployment before retrying.`
|
|
2011
|
+
};
|
|
2012
|
+
}
|
|
2013
|
+
const checkpointOwnerFailure = await verifyPublishedOwner();
|
|
2014
|
+
if (checkpointOwnerFailure) return checkpointOwnerFailure;
|
|
2015
|
+
}
|
|
2016
|
+
options.onProgress?.("Updating routes and triggers...");
|
|
2017
|
+
const triggers = await stabilizeCloudflareVersionTriggers(triggerOptions);
|
|
2018
|
+
if (!triggers.ok || !triggers.targetOwnsTraffic) {
|
|
2019
|
+
const superseded = triggers.activeVersionId !== void 0 && triggers.activeVersionId !== null && triggers.activeVersionId !== versionId;
|
|
2020
|
+
return {
|
|
2021
|
+
ok: false,
|
|
2022
|
+
reason: superseded ? "deployment-changed" : "triggers-failed",
|
|
2023
|
+
...!triggers.ok ? { status: triggers.status } : {},
|
|
2024
|
+
versionId,
|
|
2025
|
+
previousVersionId,
|
|
2026
|
+
activeVersionId: triggers.activeVersionId,
|
|
2027
|
+
rollback: superseded ? "not-needed" : triggers.activeVersionId ? "unavailable" : "unsafe",
|
|
2028
|
+
...superseded ? { triggerRepair: triggers.ok ? "succeeded" : triggers.reason === "metadata-unavailable" ? "unavailable" : "failed" } : {}
|
|
2029
|
+
};
|
|
2030
|
+
}
|
|
1811
2031
|
const previewUrl = publishedCloudflareUrl(options.workerName, desiredTriggerConfig, reportedOrConfiguredUrl);
|
|
2032
|
+
const usesCustomDomain = !desiredTriggerConfig.workers_dev && desiredTriggerConfig.routes.some((route) => isRecord(route) && route.custom_domain === true);
|
|
2033
|
+
const customDomainBootstrap = !atomic && usesCustomDomain;
|
|
2034
|
+
const readinessTimeoutMs = customDomainBootstrap ? 3e5 : 6e4;
|
|
1812
2035
|
options.onProgress?.("Waiting for the Worker to become ready...");
|
|
1813
|
-
const ready = await probeReadiness(`${previewUrl.replace(/\/$/, "")}/__void/ready`, options.workerName,
|
|
2036
|
+
const ready = await probeReadiness(`${previewUrl.replace(/\/$/, "")}/__void/ready`, options.workerName, extractWorkersDevSubdomain(previewUrl) ? options.readinessHeaders : void 0, extractWorkersDevSubdomain(previewUrl), void 0, options.fetch ?? globalThis.fetch, options.sleep ?? defaultSleep, options.readinessAttempts ?? (customDomainBootstrap ? 150 : 30), readinessTimeoutMs, options.requireVersionMetadata ? versionId : void 0);
|
|
1814
2037
|
if (ready !== "ready") return {
|
|
1815
2038
|
ok: false,
|
|
1816
2039
|
reason: ready === "access-denied" ? atomic ? "atomic-readiness-access-denied" : "bootstrap-readiness-access-denied" : atomic ? "atomic-readiness-failed" : "bootstrap-readiness-failed",
|
|
1817
2040
|
versionId,
|
|
1818
2041
|
previousVersionId,
|
|
1819
|
-
rollback: "unavailable"
|
|
2042
|
+
rollback: "unavailable",
|
|
2043
|
+
...ready === "failed" && usesCustomDomain ? { diagnostic: "The Custom Domain may still be propagating DNS or its TLS certificate. Check the configured domain in Cloudflare, then retry `void deploy --platform cloudflare` once its /__void/ready endpoint is reachable." } : {}
|
|
2044
|
+
};
|
|
2045
|
+
if (!options.verifyUploader()) return {
|
|
2046
|
+
ok: false,
|
|
2047
|
+
reason: "uploader-changed",
|
|
2048
|
+
versionId,
|
|
2049
|
+
previousVersionId,
|
|
2050
|
+
rollback: "unsafe"
|
|
1820
2051
|
};
|
|
2052
|
+
const ownerAfterReadiness = await readCurrentProductionVersion(options, configPath);
|
|
2053
|
+
if (ownerAfterReadiness.kind === "failed") return {
|
|
2054
|
+
ok: false,
|
|
2055
|
+
reason: "status-failed",
|
|
2056
|
+
status: ownerAfterReadiness.status,
|
|
2057
|
+
versionId,
|
|
2058
|
+
previousVersionId,
|
|
2059
|
+
rollback: "unsafe"
|
|
2060
|
+
};
|
|
2061
|
+
if (ownerAfterReadiness.kind !== "ok" || ownerAfterReadiness.versionId !== versionId) {
|
|
2062
|
+
const repair = await stabilizeCloudflareVersionTriggers(triggerOptions);
|
|
2063
|
+
return {
|
|
2064
|
+
ok: false,
|
|
2065
|
+
reason: "deployment-changed",
|
|
2066
|
+
versionId,
|
|
2067
|
+
previousVersionId,
|
|
2068
|
+
activeVersionId: repair.activeVersionId,
|
|
2069
|
+
rollback: "not-needed",
|
|
2070
|
+
triggerRepair: repair.ok ? "succeeded" : repair.reason === "metadata-unavailable" ? "unavailable" : "failed"
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
1821
2073
|
return {
|
|
1822
2074
|
ok: true,
|
|
1823
2075
|
versionId,
|
|
@@ -1831,32 +2083,36 @@ async function bootstrapFirstDeployment(options, commonArgs, previousVersionId,
|
|
|
1831
2083
|
...workersDevSubdomainResult(previewUrl)
|
|
1832
2084
|
};
|
|
1833
2085
|
}
|
|
1834
|
-
function
|
|
1835
|
-
const
|
|
1836
|
-
|
|
2086
|
+
function readUploadResult(result) {
|
|
2087
|
+
const data = result.data;
|
|
2088
|
+
if (!isRecord(data) || typeof data.versionId !== "string" || !/^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(data.versionId)) return null;
|
|
2089
|
+
if (data.previewUrl !== void 0 && typeof data.previewUrl !== "string" || data.workersDevUrl !== void 0 && typeof data.workersDevUrl !== "string") return null;
|
|
2090
|
+
return data;
|
|
2091
|
+
}
|
|
2092
|
+
function versionPercentages(values) {
|
|
2093
|
+
return values.map((value) => {
|
|
2094
|
+
const [versionId, percentage] = value.split("@");
|
|
2095
|
+
return {
|
|
2096
|
+
versionId,
|
|
2097
|
+
percentage: Number(percentage)
|
|
2098
|
+
};
|
|
2099
|
+
});
|
|
1837
2100
|
}
|
|
1838
2101
|
function commandDiagnosticFields(result) {
|
|
1839
2102
|
const diagnostic = cloudflareCommandDiagnostic(result);
|
|
1840
2103
|
return diagnostic ? { diagnostic } : {};
|
|
1841
2104
|
}
|
|
1842
|
-
function
|
|
1843
|
-
return
|
|
1844
|
-
}
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
"deployments",
|
|
1852
|
-
"status",
|
|
1853
|
-
...commonArgs,
|
|
1854
|
-
"--name",
|
|
1855
|
-
options.workerName,
|
|
1856
|
-
"--json"
|
|
1857
|
-
], { capture: true }));
|
|
2105
|
+
function isContainersUnavailable(result) {
|
|
2106
|
+
return result.failure === "containers-unavailable" || (result.errors?.some(({ message }) => /Cloudflare Containers[^\n]*(?:Workers Paid|not (?:enabled|available)|subscription)/i.test(message) || /\/containers\/me(?:\b|\?)/i.test(message) && /\b403\b/.test(message)) ?? false);
|
|
2107
|
+
}
|
|
2108
|
+
async function readCurrentProductionVersion(options, configPath) {
|
|
2109
|
+
const result = await Promise.resolve(options.runWrangler({
|
|
2110
|
+
type: "deployments.status",
|
|
2111
|
+
configPath,
|
|
2112
|
+
workerName: options.workerName
|
|
2113
|
+
}, { capture: true }));
|
|
1858
2114
|
if (!isCleanCommandExit(result)) {
|
|
1859
|
-
if (
|
|
2115
|
+
if (isCompletedCommand(result) && (result.failure === "not-found" || result.errorCode === 10007)) return {
|
|
1860
2116
|
kind: "ok",
|
|
1861
2117
|
versionId: null,
|
|
1862
2118
|
versions: []
|
|
@@ -1867,7 +2123,7 @@ async function readCurrentProductionVersion(options, commonArgs) {
|
|
|
1867
2123
|
};
|
|
1868
2124
|
}
|
|
1869
2125
|
try {
|
|
1870
|
-
const versions = (
|
|
2126
|
+
const versions = (result.data.versions ?? []).map((version) => ({
|
|
1871
2127
|
versionId: typeof version.version_id === "string" ? version.version_id : "",
|
|
1872
2128
|
percentage: Number(version.percentage)
|
|
1873
2129
|
}));
|
|
@@ -1901,8 +2157,8 @@ function stagedVersionPercentages(previousVersionId, versionId) {
|
|
|
1901
2157
|
percentage: 0
|
|
1902
2158
|
}] : [];
|
|
1903
2159
|
}
|
|
1904
|
-
async function verifyReadinessStagingOwner(options,
|
|
1905
|
-
const owner = await readCurrentProductionVersion(options,
|
|
2160
|
+
async function verifyReadinessStagingOwner(options, configPath, previousVersionId, versionId) {
|
|
2161
|
+
const owner = await readCurrentProductionVersion(options, configPath);
|
|
1906
2162
|
if (owner.kind === "failed") return {
|
|
1907
2163
|
ok: false,
|
|
1908
2164
|
reason: "status-failed",
|
|
@@ -1932,7 +2188,7 @@ async function verifyReadinessStagingOwner(options, commonArgs, previousVersionI
|
|
|
1932
2188
|
};
|
|
1933
2189
|
return null;
|
|
1934
2190
|
}
|
|
1935
|
-
async function probeReadiness(url, workerName, readinessHeaders, authenticatedWorkersDevSubdomain, versionOverride, fetcher, sleep, attempts, timeoutMs = Number.POSITIVE_INFINITY) {
|
|
2191
|
+
async function probeReadiness(url, workerName, readinessHeaders, authenticatedWorkersDevSubdomain, versionOverride, fetcher, sleep, attempts, timeoutMs = Number.POSITIVE_INFINITY, expectedVersionId) {
|
|
1936
2192
|
const headers = guardedReadinessHeaders(url, workerName, readinessHeaders, authenticatedWorkersDevSubdomain);
|
|
1937
2193
|
if (headers === null) return "failed";
|
|
1938
2194
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -1951,7 +2207,8 @@ async function probeReadiness(url, workerName, readinessHeaders, authenticatedWo
|
|
|
1951
2207
|
signal: AbortSignal.timeout(Math.max(1, Math.min(1e4, remaining)))
|
|
1952
2208
|
});
|
|
1953
2209
|
if (response.ok) {
|
|
1954
|
-
|
|
2210
|
+
const body = await response.json();
|
|
2211
|
+
if (body.ready === true && (expectedVersionId === void 0 || body.versionId === expectedVersionId)) return "ready";
|
|
1955
2212
|
} else if (await isCloudflareAccessDenial(response)) return "access-denied";
|
|
1956
2213
|
} catch {} finally {
|
|
1957
2214
|
if (response && !response.bodyUsed) await response.body?.cancel().catch(() => {});
|
|
@@ -1987,7 +2244,7 @@ async function isCloudflareAccessDenial(response) {
|
|
|
1987
2244
|
return false;
|
|
1988
2245
|
}
|
|
1989
2246
|
}
|
|
1990
|
-
async function deployVersionPercentages(options,
|
|
2247
|
+
async function deployVersionPercentages(options, configPath, percentages, message) {
|
|
1991
2248
|
const metadata = parseCloudflareVersionMessage(message);
|
|
1992
2249
|
if ((options.preserveTriggers || metadata?.schema === 2 && metadata.triggerConfig.preserve) && options.configPath) return deployCloudflareVersionTraffic({
|
|
1993
2250
|
...options,
|
|
@@ -1995,17 +2252,13 @@ async function deployVersionPercentages(options, commonArgs, percentages, messag
|
|
|
1995
2252
|
percentages,
|
|
1996
2253
|
message
|
|
1997
2254
|
});
|
|
1998
|
-
return options.runWrangler(
|
|
1999
|
-
"versions",
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
"--message",
|
|
2006
|
-
message,
|
|
2007
|
-
"--yes"
|
|
2008
|
-
], { capture: false });
|
|
2255
|
+
return options.runWrangler({
|
|
2256
|
+
type: "versions.deploy",
|
|
2257
|
+
versions: versionPercentages(percentages),
|
|
2258
|
+
configPath,
|
|
2259
|
+
workerName: options.workerName,
|
|
2260
|
+
message
|
|
2261
|
+
}, { capture: false });
|
|
2009
2262
|
}
|
|
2010
2263
|
/** Change version traffic without synchronizing Worker settings from local config. */
|
|
2011
2264
|
async function deployCloudflareVersionTraffic(options) {
|
|
@@ -2014,19 +2267,13 @@ async function deployCloudflareVersionTraffic(options) {
|
|
|
2014
2267
|
const path = join(directory, "wrangler.json");
|
|
2015
2268
|
try {
|
|
2016
2269
|
writeFileSync(path, JSON.stringify(config), { mode: 384 });
|
|
2017
|
-
return await options.runWrangler(
|
|
2018
|
-
"versions",
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
"--name",
|
|
2025
|
-
options.workerName,
|
|
2026
|
-
"--message",
|
|
2027
|
-
options.message,
|
|
2028
|
-
"--yes"
|
|
2029
|
-
], { capture: false });
|
|
2270
|
+
return await options.runWrangler({
|
|
2271
|
+
type: "versions.deploy",
|
|
2272
|
+
versions: versionPercentages(options.percentages),
|
|
2273
|
+
configPath: path,
|
|
2274
|
+
workerName: options.workerName,
|
|
2275
|
+
message: options.message
|
|
2276
|
+
}, { capture: false });
|
|
2030
2277
|
} finally {
|
|
2031
2278
|
rmSync(directory, {
|
|
2032
2279
|
recursive: true,
|
|
@@ -2034,12 +2281,12 @@ async function deployCloudflareVersionTraffic(options) {
|
|
|
2034
2281
|
});
|
|
2035
2282
|
}
|
|
2036
2283
|
}
|
|
2037
|
-
async function restorePreviousVersion(options,
|
|
2284
|
+
async function restorePreviousVersion(options, configPath, previousVersionId, cause, expectedOwnedTraffic) {
|
|
2038
2285
|
if (!previousVersionId) return "unavailable";
|
|
2039
2286
|
if (!options.verifyUploader()) return "unsafe";
|
|
2040
|
-
const owner = await readCurrentProductionVersion(options,
|
|
2287
|
+
const owner = await readCurrentProductionVersion(options, configPath);
|
|
2041
2288
|
if (owner.kind !== "ok" || !expectedOwnedTraffic.some((expected) => productionVersionPercentagesEqual(owner.versions, expected))) return "unsafe";
|
|
2042
|
-
return isCleanCommandExit(await deployVersionPercentages(options,
|
|
2289
|
+
return isCleanCommandExit(await deployVersionPercentages(options, configPath, [`${previousVersionId}@100`], `Void automatic rollback after ${cause}.`)) ? "succeeded" : "failed";
|
|
2043
2290
|
}
|
|
2044
2291
|
function workersDevReadinessUrl(workerName, value) {
|
|
2045
2292
|
const subdomain = normalizeWorkersDevSubdomain(value);
|
|
@@ -2073,8 +2320,11 @@ function workersDevSubdomainResult(url) {
|
|
|
2073
2320
|
const workersDevSubdomain = extractWorkersDevSubdomain(url);
|
|
2074
2321
|
return workersDevSubdomain ? { workersDevSubdomain } : {};
|
|
2075
2322
|
}
|
|
2323
|
+
function isCompletedCommand(result) {
|
|
2324
|
+
return Number.isSafeInteger(result.status) && result.status >= 0 && result.signal == null && (result.error == null || result.error === "");
|
|
2325
|
+
}
|
|
2076
2326
|
function isCleanCommandExit(result) {
|
|
2077
|
-
return result.status === 0 &&
|
|
2327
|
+
return result.status === 0 && isCompletedCommand(result);
|
|
2078
2328
|
}
|
|
2079
2329
|
function defaultSleep(milliseconds) {
|
|
2080
2330
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
@@ -2088,13 +2338,6 @@ function defaultSleep(milliseconds) {
|
|
|
2088
2338
|
*/
|
|
2089
2339
|
function createCloudflareMetadataRunner(options) {
|
|
2090
2340
|
let tokenPromise;
|
|
2091
|
-
const common = [
|
|
2092
|
-
...options.configPath ? ["-c", options.configPath] : [],
|
|
2093
|
-
"--env=",
|
|
2094
|
-
"--name",
|
|
2095
|
-
options.workerName,
|
|
2096
|
-
"--json"
|
|
2097
|
-
];
|
|
2098
2341
|
const prefix = `${options.apiBaseUrl.replace(/\/$/, "")}/accounts/${encodeURIComponent(options.accountId)}/workers/scripts/${encodeURIComponent(options.workerName)}`;
|
|
2099
2342
|
const fetcher = options.fetch ?? globalThis.fetch;
|
|
2100
2343
|
const proxyEnv = options.env ?? process.env;
|
|
@@ -2105,26 +2348,22 @@ function createCloudflareMetadataRunner(options) {
|
|
|
2105
2348
|
stderr: "Cloudflare uploader integrity check failed.",
|
|
2106
2349
|
error: "uploader-changed"
|
|
2107
2350
|
};
|
|
2108
|
-
const fallback = (
|
|
2109
|
-
return async (
|
|
2351
|
+
const fallback = (operation, runOptions) => options.verifyUploader() ? options.runWrangler(operation, runOptions) : refused;
|
|
2352
|
+
return async (operation, runOptions) => {
|
|
2110
2353
|
let kind;
|
|
2111
2354
|
let resource;
|
|
2112
|
-
|
|
2113
|
-
if (args[0] === "deployments" && args[1] === "status") {
|
|
2355
|
+
if (operation.type === "deployments.status") {
|
|
2114
2356
|
kind = "deployment";
|
|
2115
2357
|
resource = "/deployments";
|
|
2116
|
-
|
|
2117
|
-
} else if (args[0] === "versions" && args[1] === "list") {
|
|
2358
|
+
} else if (operation.type === "versions.list") {
|
|
2118
2359
|
kind = "versions";
|
|
2119
2360
|
resource = "/versions?deployable=true";
|
|
2120
|
-
|
|
2121
|
-
} else if (args[0] === "versions" && args[1] === "view" && /^[0-9a-f-]{36}$/i.test(args[2] ?? "")) {
|
|
2361
|
+
} else if (operation.type === "versions.view" && !operation.includeSource && /^[0-9a-f-]{36}$/i.test(operation.versionId)) {
|
|
2122
2362
|
kind = "version";
|
|
2123
|
-
resource =
|
|
2124
|
-
rest = args.slice(3);
|
|
2363
|
+
resource = "/versions/" + encodeURIComponent(operation.versionId);
|
|
2125
2364
|
}
|
|
2126
|
-
if (!kind || !runOptions.capture ||
|
|
2127
|
-
if (requiresProxyTransport) return fallback(
|
|
2365
|
+
if (!kind || !runOptions.capture || !("workerName" in operation) || operation.workerName !== options.workerName || operation.configPath !== options.configPath) return fallback(operation, runOptions);
|
|
2366
|
+
if (requiresProxyTransport) return fallback(operation, runOptions);
|
|
2128
2367
|
let response;
|
|
2129
2368
|
try {
|
|
2130
2369
|
if (!tokenPromise && !options.verifyUploader()) return refused;
|
|
@@ -2145,29 +2384,30 @@ function createCloudflareMetadataRunner(options) {
|
|
|
2145
2384
|
if (result.deployments.length === 0) return {
|
|
2146
2385
|
status: 1,
|
|
2147
2386
|
stdout: "",
|
|
2148
|
-
stderr: `The Worker ${options.workerName} has no deployments
|
|
2387
|
+
stderr: `The Worker ${options.workerName} has no deployments.`,
|
|
2388
|
+
errorCode: 10007
|
|
2149
2389
|
};
|
|
2150
2390
|
if (record(latest) && Array.isArray(latest.versions)) return {
|
|
2151
2391
|
status: 0,
|
|
2152
|
-
stdout:
|
|
2392
|
+
stdout: "",
|
|
2393
|
+
data: latest,
|
|
2153
2394
|
stderr: ""
|
|
2154
2395
|
};
|
|
2155
2396
|
}
|
|
2156
|
-
if (
|
|
2397
|
+
if (operation.type === "versions.view" && result.id === operation.versionId) return {
|
|
2157
2398
|
status: 0,
|
|
2158
|
-
stdout:
|
|
2399
|
+
stdout: "",
|
|
2400
|
+
data: result,
|
|
2159
2401
|
stderr: ""
|
|
2160
2402
|
};
|
|
2161
2403
|
if (kind === "versions" && Array.isArray(result.items)) {
|
|
2162
2404
|
const items = result.items;
|
|
2163
|
-
if (items.every((item) => record(item) && record(item.metadata) && typeof item.metadata.created_on === "string")) {
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
};
|
|
2170
|
-
}
|
|
2405
|
+
if (items.every((item) => record(item) && record(item.metadata) && typeof item.metadata.created_on === "string")) return {
|
|
2406
|
+
status: 0,
|
|
2407
|
+
stdout: "",
|
|
2408
|
+
data: items.sort((a, b) => a.metadata.created_on.localeCompare(b.metadata.created_on)).slice(-10),
|
|
2409
|
+
stderr: ""
|
|
2410
|
+
};
|
|
2171
2411
|
}
|
|
2172
2412
|
}
|
|
2173
2413
|
}
|
|
@@ -2177,11 +2417,11 @@ function createCloudflareMetadataRunner(options) {
|
|
|
2177
2417
|
} finally {
|
|
2178
2418
|
if (response && !response.bodyUsed) await response.body?.cancel().catch(() => {});
|
|
2179
2419
|
}
|
|
2180
|
-
return fallback(
|
|
2420
|
+
return fallback(operation, runOptions);
|
|
2181
2421
|
};
|
|
2182
2422
|
}
|
|
2183
2423
|
function record(value) {
|
|
2184
2424
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2185
2425
|
}
|
|
2186
2426
|
//#endregion
|
|
2187
|
-
export { CloudflareWorkerInspectionError, activateCloudflareVersion, assertCloudflareBindingsPreserved, assertCloudflareDurableObjectLifecycleSupported, assertExistingCloudflareConfig, createCloudflareMetadataRunner, deployCloudflareVersionTraffic, deployCloudflareVersionTriggers, encodeCloudflareVersionMessage, executeCloudflareDeploy, extractWorkersDevSubdomain, normalizeWorkersDevSubdomain, parseCloudflareVersionMessage, parseRootWranglerConfig, readBindingFieldPresence, readCloudflareTriggerConfig, readCloudflareVersionMigrationTag, readCloudflareWorkerMigrationTag, readConfigEntryString, readExistingCloudflareWorker, readStoredResourceName, readWranglerTopLevelString, renderCloudflareStaticEntry, resolveD1MigrateTarget, stabilizeCloudflareVersionTriggers, stageCloudflareStaticAssets, writeCloudflareFrameworkDeployConfig, writeCloudflareStaticDeployConfig };
|
|
2427
|
+
export { CloudflareWorkerInspectionError, VOID_SECRET_DRAFT_SOURCE, activateCloudflareVersion, assertCloudflareBindingsPreserved, assertCloudflareDurableObjectLifecycleSupported, assertExistingCloudflareConfig, createCloudflareMetadataRunner, deployCloudflareVersionTraffic, deployCloudflareVersionTriggers, encodeCloudflareVersionMessage, executeCloudflareDeploy, extractWorkersDevSubdomain, normalizeWorkersDevSubdomain, parseCloudflareVersionMessage, parseRootWranglerConfig, readBindingFieldPresence, readCloudflareTriggerConfig, readCloudflareVersionMigrationTag, readCloudflareWorkerMigrationTag, readConfigEntryString, readExistingCloudflareWorker, readStoredResourceName, readWranglerTopLevelString, renderCloudflareStaticEntry, resolveD1MigrateTarget, stabilizeCloudflareVersionTriggers, stageCloudflareStaticAssets, writeCloudflareFrameworkDeployConfig, writeCloudflareStaticDeployConfig };
|