@void/deploy-cloudflare 0.27.0 → 1.0.3

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 CHANGED
@@ -479,6 +479,10 @@ export declare function createCloudflareMetadataRunner(options: {
479
479
  env?: Readonly<Record<string, string | undefined>>;
480
480
  }): CloudflareCommandRunner;
481
481
  //#endregion
482
+ //#region src/diagnostics.d.ts
483
+ /** Keep the uploader's error, excluding stdout binding tables and redacting common credential formats. */
484
+ export declare function cloudflareCommandDiagnostic(result: CloudflareCommandResult): string | undefined;
485
+ //#endregion
482
486
  //#region src/secret-draft.d.ts
483
487
  export declare const VOID_SECRET_DRAFT_SOURCE = "export default { fetch() { return new Response(\"\"); } };\n";
484
488
  //#endregion
package/dist/index.mjs CHANGED
@@ -1,10 +1,11 @@
1
1
  import { isDeepStrictEqual, stripVTControlCharacters } from "node:util";
2
- import { isRecord } from "@void/deploy-core";
2
+ import { canonicalJson, isRecord } from "@void/deploy-core";
3
3
  import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { SyntaxKind, applyEdits, createScanner, modify, parse, parseTree } from "jsonc-parser";
5
5
  import nodePath from "node:path";
6
6
  import { createHash } from "node:crypto";
7
7
  import { tmpdir } from "node:os";
8
+ import { setTimeout } from "node:timers/promises";
8
9
  //#region src/config.ts
9
10
  /** Parse a root Wrangler JSON/JSONC config without accepting a partial parse. */
10
11
  function parseRootWranglerConfig(configPath) {
@@ -21,6 +22,14 @@ function parseRootWranglerConfig(configPath) {
21
22
  if (errors.length > 0 || typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
22
23
  return parsed;
23
24
  }
25
+ /** Set one value in JSONC text, keeping comments and formatting elsewhere. */
26
+ function setJsoncValue(text, path, value) {
27
+ return applyEdits(text, modify(text, path, value, { formattingOptions: {
28
+ insertSpaces: true,
29
+ tabSize: 2,
30
+ eol: "\n"
31
+ } }));
32
+ }
24
33
  function readWranglerTopLevelString(config, field) {
25
34
  return readConfigEntryString(config, field);
26
35
  }
@@ -574,11 +583,7 @@ function writeCloudflareFrameworkDeployConfig(options) {
574
583
  const initial = existsSync(options.configPath) ? readFileSync(options.configPath, "utf-8") : "{}\n";
575
584
  let content = initial;
576
585
  const upsert = (path, value) => {
577
- content = applyEdits(content, modify(content, path, value, { formattingOptions: {
578
- insertSpaces: true,
579
- tabSize: 2,
580
- eol: "\n"
581
- } }));
586
+ content = setJsoncValue(content, path, value);
582
587
  };
583
588
  upsert(["name"], options.name);
584
589
  upsert(["account_id"], options.accountId);
@@ -692,12 +697,7 @@ function writeCloudflareStaticDeployConfig(options) {
692
697
  const originalComments = extractCommentTokens(source);
693
698
  let content = source;
694
699
  const upsert = (path, value) => {
695
- const edits = modify(content, path, value, { formattingOptions: {
696
- insertSpaces: true,
697
- tabSize: 2,
698
- eol: "\n"
699
- } });
700
- content = applyEdits(content, edits);
700
+ content = setJsoncValue(content, path, value);
701
701
  };
702
702
  upsert(["name"], options.name);
703
703
  upsert(["account_id"], options.accountId);
@@ -781,6 +781,14 @@ function cloudflareCommandDiagnostic(result) {
781
781
  if (message === stderr && !/(?:^|\n)[ \t]*(?:[✘×X][ \t]+)?\[ERROR\]/i.test(stderr)) {
782
782
  const box = /(?:^|\n)[ \t]*┌[ \t]*(?:APIError|Error)\b[^\n]*\n(?:[ \t]*│[^\n]*\n)*[ \t]*└[^\n]*/i.exec(stdout);
783
783
  if (box) message = box[0].trim();
784
+ else {
785
+ const lines = stdout.split("\n");
786
+ const abort = lines.find((line) => line.startsWith("■ Aborting the upload operation because of conflicts."));
787
+ if (abort) {
788
+ const reason = "You are about to upload a Worker that was last updated via the script API.";
789
+ message = [lines.includes(`▲ ${reason}`) ? reason : "", abort.slice(3)].filter(Boolean).join("\n");
790
+ }
791
+ }
784
792
  }
785
793
  message = stripVTControlCharacters(message).split(/\n\s*(?:🪵|Logs (?:were )?written|If you think this is a bug)/)[0].trim();
786
794
  if (!message) return;
@@ -910,11 +918,10 @@ function pickWranglerTriggerContext(source) {
910
918
  * schema-2 snapshot. The bounded loop fails closed if traffic never stabilizes.
911
919
  */
912
920
  async function stabilizeCloudflareVersionTriggers(options) {
913
- const configPath = options.configPath;
914
921
  let cleanupBaseline = mergeTriggerCleanupBaselines(options.previousTriggerConfig, options.targetTriggerConfig);
915
922
  const attempts = Math.max(1, options.attempts ?? 4);
916
923
  for (let attempt = 0; attempt < attempts; attempt++) {
917
- const owner = await readCurrentProductionVersion(options, configPath);
924
+ const owner = await readCurrentProductionVersion(options);
918
925
  if (owner.kind === "failed") return {
919
926
  ok: false,
920
927
  reason: "status-failed",
@@ -932,7 +939,7 @@ async function stabilizeCloudflareVersionTriggers(options) {
932
939
  const activeVersionId = owner.versionId;
933
940
  let activeTriggerConfig = activeVersionId === options.targetVersionId ? options.targetTriggerConfig : options.knownTriggerConfigs?.[activeVersionId];
934
941
  if (!activeTriggerConfig && activeVersionId !== options.targetVersionId) {
935
- const metadata = await readCloudflareVersionMetadata(options, configPath, activeVersionId);
942
+ const metadata = await readCloudflareVersionMetadata(options, activeVersionId);
936
943
  activeTriggerConfig = metadata?.schema === 2 ? metadata.triggerConfig : void 0;
937
944
  }
938
945
  if (!activeTriggerConfig) return {
@@ -957,7 +964,7 @@ async function stabilizeCloudflareVersionTriggers(options) {
957
964
  activeVersionId
958
965
  };
959
966
  cleanupBaseline = mergeTriggerCleanupBaselines(cleanupBaseline, activeTriggerConfig);
960
- const after = await readCurrentProductionVersion(options, configPath);
967
+ const after = await readCurrentProductionVersion(options);
961
968
  if (after.kind === "failed") return {
962
969
  ok: false,
963
970
  reason: "status-failed",
@@ -1097,12 +1104,7 @@ function nonVersionedSettingsHash(config) {
1097
1104
  "tail_consumers",
1098
1105
  "streaming_tail_consumers"
1099
1106
  ].filter((key) => config[key] !== void 0).map((key) => [key, config[key]]));
1100
- return createHash("sha256").update(stableJson(settings)).digest("hex");
1101
- }
1102
- function stableJson(value) {
1103
- if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`;
1104
- if (isRecord(value)) return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
1105
- return JSON.stringify(value);
1107
+ return createHash("sha256").update(canonicalJson(settings)).digest("hex");
1106
1108
  }
1107
1109
  function parseTriggerConfig(value) {
1108
1110
  if (!isRecord(value)) return null;
@@ -1190,13 +1192,12 @@ async function activateCloudflareVersion(options) {
1190
1192
  }
1191
1193
  }
1192
1194
  async function activateCloudflareVersionWithSecretsFile(options) {
1193
- const configPath = options.configPath;
1194
1195
  if (!options.verifyUploader()) return {
1195
1196
  ok: false,
1196
1197
  reason: "uploader-changed"
1197
1198
  };
1198
1199
  options.onProgress?.("Checking the current Worker deployment...");
1199
- const previous = await readCurrentProductionVersion(options, configPath);
1200
+ const previous = await readCurrentProductionVersion(options);
1200
1201
  if (previous.kind === "failed") return {
1201
1202
  ok: false,
1202
1203
  reason: "status-failed",
@@ -1230,7 +1231,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1230
1231
  let activeSecretsPinned = false;
1231
1232
  let pinnedActiveSecrets;
1232
1233
  if (options.expectedPreviousVersionId !== void 0 || options.verifyInheritedSecrets === true) {
1233
- const recent = await readRecentCloudflareVersionIds(options, configPath);
1234
+ const recent = await readRecentCloudflareVersionIds(options);
1234
1235
  if (recent === null) return {
1235
1236
  ok: false,
1236
1237
  reason: "inheritance-source-unavailable"
@@ -1249,13 +1250,13 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1249
1250
  };
1250
1251
  }
1251
1252
  if (options.verifyInheritedSecrets === true && previous.versionId !== latestVersionId && !trustedCandidateChain) {
1252
- const replacesAllRemoteSecrets = await candidateReplacesAllRemoteSecrets(options, configPath, previous.versionId, latestVersionId);
1253
+ const replacesAllRemoteSecrets = await candidateReplacesAllRemoteSecrets(options, previous.versionId, latestVersionId);
1253
1254
  if (replacesAllRemoteSecrets === null) return {
1254
1255
  ok: false,
1255
1256
  reason: "inheritance-source-unavailable"
1256
1257
  };
1257
1258
  if (!replacesAllRemoteSecrets) {
1258
- const activeSecrets = previous.versionId ? await readCloudflareVersionSecretBindings(options, configPath, previous.versionId) : null;
1259
+ const activeSecrets = previous.versionId ? await readCloudflareVersionSecretBindings(options, previous.versionId) : null;
1259
1260
  if (!activeSecrets || !options.pinActiveSecrets || !await options.pinActiveSecrets(previous.versionId, activeSecrets)) return {
1260
1261
  ok: false,
1261
1262
  reason: "inheritance-source-changed",
@@ -1270,10 +1271,10 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1270
1271
  }
1271
1272
  const desiredMetadata = parseCloudflareVersionMessage(options.message);
1272
1273
  let desiredTriggerConfig = desiredTriggerConfigFor(desiredMetadata, options.configPath);
1273
- let previousVersion = previousVersionId && desiredMetadata?.schema === 2 ? await readCloudflareVersionInspection(options, configPath, previousVersionId, inheritanceBaseline?.map((version) => version.inspection)) : null;
1274
+ let previousVersion = previousVersionId && desiredMetadata?.schema === 2 ? await readCloudflareVersionInspection(options, previousVersionId, inheritanceBaseline?.map((version) => version.inspection)) : null;
1274
1275
  async function previousIsSecretOnlyDraft() {
1275
1276
  if (!previousVersionId) return false;
1276
- previousVersion ??= await readCloudflareVersionInspection(options, configPath, previousVersionId, inheritanceBaseline?.map((version) => version.inspection));
1277
+ previousVersion ??= await readCloudflareVersionInspection(options, previousVersionId, inheritanceBaseline?.map((version) => version.inspection));
1277
1278
  return previousVersion?.isSecretOnlyDraft === true;
1278
1279
  }
1279
1280
  const previousMetadata = desiredMetadata?.schema === 2 ? previousVersion?.metadata : null;
@@ -1314,7 +1315,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1314
1315
  if (bootstrapVoidDraft || !activeSecretsPinned && options.pinActiveSecrets) {
1315
1316
  let activeSecrets;
1316
1317
  try {
1317
- activeSecrets = await readCloudflareVersionSecretBindings(options, configPath, previous.versionId);
1318
+ activeSecrets = await readCloudflareVersionSecretBindings(options, previous.versionId);
1318
1319
  } catch {
1319
1320
  return {
1320
1321
  ok: false,
@@ -1348,12 +1349,12 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1348
1349
  return bootstrapFirstDeployment({
1349
1350
  ...options,
1350
1351
  message
1351
- }, configPath, previous.versionId, options.atomic === true, previousTriggerConfig);
1352
+ }, previous.versionId, options.atomic === true, previousTriggerConfig);
1352
1353
  }
1353
1354
  if (previous.versionId !== null && !activeSecretsPinned && options.pinActiveSecrets && options.candidateSecretsFilePath === void 0) {
1354
1355
  let activeSecrets;
1355
1356
  try {
1356
- activeSecrets = await readCloudflareVersionSecretBindings(options, configPath, previous.versionId);
1357
+ activeSecrets = await readCloudflareVersionSecretBindings(options, previous.versionId);
1357
1358
  } catch {
1358
1359
  return {
1359
1360
  ok: false,
@@ -1390,7 +1391,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1390
1391
  ok: false,
1391
1392
  reason: "uploader-changed"
1392
1393
  };
1393
- const owner = await readCurrentProductionVersion(options, configPath);
1394
+ const owner = await readCurrentProductionVersion(options);
1394
1395
  if (owner.kind === "failed") return {
1395
1396
  ok: false,
1396
1397
  reason: "status-failed",
@@ -1409,7 +1410,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1409
1410
  options.onProgress?.("Uploading the Worker and assets...");
1410
1411
  const upload = await options.runWrangler({
1411
1412
  type: "versions.upload",
1412
- configPath,
1413
+ configPath: options.configPath,
1413
1414
  workerName: options.workerName,
1414
1415
  message,
1415
1416
  secretsFilePath: options.candidateSecretsFilePath,
@@ -1422,7 +1423,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1422
1423
  if (!options.preserveTriggers && isBootstrapError && (previous.versionId === null || options.allowFirstDeploymentBootstrap === true || await previousIsSecretOnlyDraft())) return bootstrapFirstDeployment({
1423
1424
  ...options,
1424
1425
  message
1425
- }, configPath, previous.versionId, false, previousTriggerConfig);
1426
+ }, previous.versionId, false, previousTriggerConfig);
1426
1427
  return {
1427
1428
  ok: false,
1428
1429
  reason: "upload-failed",
@@ -1440,7 +1441,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1440
1441
  };
1441
1442
  options.onProgress?.("Verifying the uploaded Worker...");
1442
1443
  if (inheritanceBaseline) {
1443
- const recent = await readRecentCloudflareVersionIds(options, configPath);
1444
+ const recent = await readRecentCloudflareVersionIds(options);
1444
1445
  const previousLatest = inheritanceBaseline.at(-1);
1445
1446
  const expected = [...inheritanceBaseline.map((version) => version.id), versionId].slice(-10);
1446
1447
  if (recent === null) return {
@@ -1482,7 +1483,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1482
1483
  if (!options.preserveTriggers && (previous.versionId === null || options.allowFirstDeploymentBootstrap === true || await previousIsSecretOnlyDraft())) return bootstrapFirstDeployment({
1483
1484
  ...options,
1484
1485
  message
1485
- }, configPath, previous.versionId, false, previousTriggerConfig);
1486
+ }, previous.versionId, false, previousTriggerConfig);
1486
1487
  readinessUrl = desiredTriggerConfig.workers_dev ? workersDevReadinessUrl(options.workerName, options.workersDevSubdomain) : customRouteReadinessUrl(desiredTriggerConfig.routes);
1487
1488
  readinessUsesCustomRoute = !desiredTriggerConfig.workers_dev && readinessUrl !== void 0;
1488
1489
  if (!readinessUrl) return {
@@ -1493,17 +1494,17 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1493
1494
  };
1494
1495
  const fallbackSubdomain = extractWorkersDevSubdomain(readinessUrl);
1495
1496
  if (fallbackSubdomain && fallbackSubdomain === options.readinessHeadersWorkersDevSubdomain) authenticatedWorkersDevSubdomain = fallbackSubdomain;
1496
- const stagingFailure = await stageCandidateForReadiness(options, configPath, previous.versionId, versionId, message);
1497
+ const stagingFailure = await stageCandidateForReadiness(options, previous.versionId, versionId, message);
1497
1498
  if (stagingFailure) return stagingFailure;
1498
1499
  stagedVersionOverride = true;
1499
1500
  }
1500
- const probe = (url) => probeReadiness(`${url.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);
1501
+ const probe = (url) => probeReadiness(`${url.replace(/\/$/, "")}/__void/ready`, options.workerName, readinessUsesCustomRoute ? void 0 : options.readinessHeaders, authenticatedWorkersDevSubdomain, stagedVersionOverride ? versionId : void 0, options.fetch ?? globalThis.fetch, options.sleep ?? setTimeout, options.readinessAttempts ?? 6, Number.POSITIVE_INFINITY, options.requireVersionMetadata ? versionId : void 0);
1501
1502
  options.onProgress?.("Waiting for the Worker to become ready...");
1502
1503
  let ready = await probe(readinessUrl);
1503
1504
  if (ready === "access-denied" && !stagedVersionOverride && previous.versionId !== null && !options.requirePreviewForReadiness) {
1504
1505
  const stableReadinessUrl = desiredTriggerConfig.workers_dev ? workersDevReadinessUrl(options.workerName, extractWorkersDevSubdomain(readinessUrl) ?? options.workersDevSubdomain) : customRouteReadinessUrl(desiredTriggerConfig.routes);
1505
1506
  if (stableReadinessUrl && stableReadinessUrl !== readinessUrl) {
1506
- const stagingFailure = await stageCandidateForReadiness(options, configPath, previous.versionId, versionId, message);
1507
+ const stagingFailure = await stageCandidateForReadiness(options, previous.versionId, versionId, message);
1507
1508
  if (stagingFailure) return stagingFailure;
1508
1509
  readinessUrl = stableReadinessUrl;
1509
1510
  authenticatedWorkersDevSubdomain = extractWorkersDevSubdomain(stableReadinessUrl);
@@ -1517,16 +1518,16 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1517
1518
  reason: ready === "access-denied" ? "readiness-access-denied" : "readiness-failed",
1518
1519
  versionId,
1519
1520
  previousVersionId: previous.versionId,
1520
- rollback: stagedVersionOverride ? await restorePreviousVersion(options, configPath, previous.versionId, "readiness failed", [stagedVersionPercentages(previous.versionId, versionId)]) : "not-needed"
1521
+ rollback: stagedVersionOverride ? await restorePreviousVersion(options, previous.versionId, "readiness failed", [stagedVersionPercentages(previous.versionId, versionId)]) : "not-needed"
1521
1522
  };
1522
1523
  if (!options.verifyUploader()) return {
1523
1524
  ok: false,
1524
1525
  reason: "uploader-changed",
1525
1526
  versionId,
1526
1527
  previousVersionId: previous.versionId,
1527
- rollback: stagedVersionOverride ? await restorePreviousVersion(options, configPath, previous.versionId, "uploader verification failed", [stagedVersionPercentages(previous.versionId, versionId)]) : "not-needed"
1528
+ rollback: stagedVersionOverride ? await restorePreviousVersion(options, previous.versionId, "uploader verification failed", [stagedVersionPercentages(previous.versionId, versionId)]) : "not-needed"
1528
1529
  };
1529
- const ownerBeforeActivation = await readCurrentProductionVersion(options, configPath);
1530
+ const ownerBeforeActivation = await readCurrentProductionVersion(options);
1530
1531
  if (ownerBeforeActivation.kind === "failed") return {
1531
1532
  ok: false,
1532
1533
  reason: "status-failed",
@@ -1554,14 +1555,14 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1554
1555
  triggerRepair: "succeeded"
1555
1556
  };
1556
1557
  options.onProgress?.("Activating the Worker...");
1557
- const activate = await deployVersionPercentages(options, configPath, [`${versionId}@100`], message);
1558
+ const activate = await deployVersionPercentages(options, [`${versionId}@100`], message);
1558
1559
  if (!isCleanCommandExit(activate)) return {
1559
1560
  ok: false,
1560
1561
  reason: "activation-failed",
1561
1562
  status: activate.status,
1562
1563
  versionId,
1563
1564
  previousVersionId: previous.versionId,
1564
- rollback: stagedVersionOverride ? await restorePreviousVersion(options, configPath, previous.versionId, "version activation failed", [stagedVersionPercentages(previous.versionId, versionId), [{
1565
+ rollback: stagedVersionOverride ? await restorePreviousVersion(options, previous.versionId, "version activation failed", [stagedVersionPercentages(previous.versionId, versionId), [{
1565
1566
  versionId,
1566
1567
  percentage: 100
1567
1568
  }]]) : "not-needed"
@@ -1574,7 +1575,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1574
1575
  rollback: previous.versionId ? "unsafe" : "unavailable"
1575
1576
  };
1576
1577
  if (options.preserveTriggers) {
1577
- const owner = await readCurrentProductionVersion(options, configPath);
1578
+ const owner = await readCurrentProductionVersion(options);
1578
1579
  if (owner.kind !== "ok" || owner.versionId !== versionId) return {
1579
1580
  ok: false,
1580
1581
  reason: "deployment-changed",
@@ -1625,7 +1626,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1625
1626
  previousVersionId: previous.versionId,
1626
1627
  rollback: "unsafe"
1627
1628
  };
1628
- const ownerBeforeCompensation = await readCurrentProductionVersion(options, configPath);
1629
+ const ownerBeforeCompensation = await readCurrentProductionVersion(options);
1629
1630
  if (ownerBeforeCompensation.kind !== "ok" || ownerBeforeCompensation.versionId === null) return {
1630
1631
  ok: false,
1631
1632
  reason: "triggers-failed",
@@ -1657,7 +1658,7 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1657
1658
  triggerRepair: triggerRepairOutcome(repair)
1658
1659
  };
1659
1660
  }
1660
- const rollback = await restorePreviousVersionAndTriggers(options, configPath, previous.versionId, "trigger activation failed", desiredTriggerConfig, versionId, versionedPreviousTriggerConfigWithTraffic);
1661
+ const rollback = await restorePreviousVersionAndTriggers(options, previous.versionId, "trigger activation failed", desiredTriggerConfig, versionId, versionedPreviousTriggerConfigWithTraffic);
1661
1662
  return {
1662
1663
  ok: false,
1663
1664
  reason: "triggers-failed",
@@ -1690,8 +1691,8 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1690
1691
  ...workersDevSubdomainResult(readinessUrl)
1691
1692
  };
1692
1693
  }
1693
- async function restorePreviousVersionAndTriggers(options, configPath, previousVersionId, cause, failedTriggerConfig, failedVersionId, capturedTriggerConfig) {
1694
- const traffic = await restorePreviousVersion(options, configPath, previousVersionId, cause, [[{
1694
+ async function restorePreviousVersionAndTriggers(options, previousVersionId, cause, failedTriggerConfig, failedVersionId, capturedTriggerConfig) {
1695
+ const traffic = await restorePreviousVersion(options, previousVersionId, cause, [[{
1695
1696
  versionId: failedVersionId,
1696
1697
  percentage: 100
1697
1698
  }]]);
@@ -1699,7 +1700,7 @@ async function restorePreviousVersionAndTriggers(options, configPath, previousVe
1699
1700
  if (!options.verifyUploader()) return "unsafe";
1700
1701
  let targetTriggerConfig = capturedTriggerConfig;
1701
1702
  if (!targetTriggerConfig) {
1702
- const metadata = await readCloudflareVersionMetadata(options, configPath, previousVersionId);
1703
+ const metadata = await readCloudflareVersionMetadata(options, previousVersionId);
1703
1704
  if (metadata?.schema !== 2) return "unavailable";
1704
1705
  targetTriggerConfig = metadata.triggerConfig;
1705
1706
  }
@@ -1718,16 +1719,16 @@ async function restorePreviousVersionAndTriggers(options, configPath, previousVe
1718
1719
  });
1719
1720
  return triggers.ok && triggers.targetOwnsTraffic ? "succeeded" : "failed";
1720
1721
  }
1721
- async function readCloudflareVersionMetadata(options, configPath, versionId) {
1722
- return (await readCloudflareVersionInspection(options, configPath, versionId))?.metadata ?? null;
1722
+ async function readCloudflareVersionMetadata(options, versionId) {
1723
+ return (await readCloudflareVersionInspection(options, versionId))?.metadata ?? null;
1723
1724
  }
1724
- async function readCloudflareVersionInspection(options, configPath, versionId, knownVersions) {
1725
+ async function readCloudflareVersionInspection(options, versionId, knownVersions) {
1725
1726
  try {
1726
1727
  let versions = knownVersions;
1727
1728
  if (versions === void 0) {
1728
1729
  const result = await options.runWrangler({
1729
1730
  type: "versions.list",
1730
- configPath,
1731
+ configPath: options.configPath,
1731
1732
  workerName: options.workerName
1732
1733
  }, { capture: true });
1733
1734
  if (!isCleanCommandExit(result)) return null;
@@ -1743,7 +1744,7 @@ async function readCloudflareVersionInspection(options, configPath, versionId, k
1743
1744
  const inspection = await options.runWrangler({
1744
1745
  type: "versions.view",
1745
1746
  versionId,
1746
- configPath,
1747
+ configPath: options.configPath,
1747
1748
  workerName: options.workerName,
1748
1749
  includeSource: true
1749
1750
  }, { capture: true });
@@ -1765,10 +1766,10 @@ async function readCloudflareVersionInspection(options, configPath, versionId, k
1765
1766
  }
1766
1767
  return null;
1767
1768
  }
1768
- async function readRecentCloudflareVersionIds(options, configPath) {
1769
+ async function readRecentCloudflareVersionIds(options) {
1769
1770
  const result = await options.runWrangler({
1770
1771
  type: "versions.list",
1771
- configPath,
1772
+ configPath: options.configPath,
1772
1773
  workerName: options.workerName
1773
1774
  }, { capture: true });
1774
1775
  if (!isCleanCommandExit(result)) {
@@ -1786,21 +1787,21 @@ async function readRecentCloudflareVersionIds(options, configPath) {
1786
1787
  function arraysEqual(left, right) {
1787
1788
  return left.length === right.length && left.every((value, index) => value === right[index]);
1788
1789
  }
1789
- async function candidateReplacesAllRemoteSecrets(options, configPath, activeVersionId, latestVersionId) {
1790
+ async function candidateReplacesAllRemoteSecrets(options, activeVersionId, latestVersionId) {
1790
1791
  const versionIds = [...new Set([activeVersionId, latestVersionId].filter(Boolean))];
1791
1792
  const secretBindings = [];
1792
1793
  for (const versionId of versionIds) {
1793
- const bindings = await readCloudflareVersionSecretBindings(options, configPath, versionId);
1794
+ const bindings = await readCloudflareVersionSecretBindings(options, versionId);
1794
1795
  if (bindings === null) return null;
1795
1796
  secretBindings.push(bindings);
1796
1797
  }
1797
1798
  return secretBindings.every((bindings) => bindings.every((binding) => binding.type === "secret_text" && Object.hasOwn(options.candidateSecrets ?? {}, binding.name)));
1798
1799
  }
1799
- async function readCloudflareVersionSecretBindings(options, configPath, versionId) {
1800
+ async function readCloudflareVersionSecretBindings(options, versionId) {
1800
1801
  const result = await options.runWrangler({
1801
1802
  type: "versions.view",
1802
1803
  versionId,
1803
- configPath,
1804
+ configPath: options.configPath,
1804
1805
  workerName: options.workerName
1805
1806
  }, { capture: true });
1806
1807
  if (!isCleanCommandExit(result)) return null;
@@ -1825,13 +1826,13 @@ async function readCloudflareVersionSecretBindings(options, configPath, versionI
1825
1826
  * brand-new Worker can therefore need one ordinary deploy before later releases use preview-first
1826
1827
  * version activation. This fallback requires prior proof that no application had been deployed.
1827
1828
  */
1828
- async function bootstrapFirstDeployment(options, configPath, previousVersionId, atomic = false, previousTriggerConfig) {
1829
+ async function bootstrapFirstDeployment(options, previousVersionId, atomic = false, previousTriggerConfig) {
1829
1830
  if (!options.verifyUploader()) return {
1830
1831
  ok: false,
1831
1832
  reason: "uploader-changed"
1832
1833
  };
1833
1834
  {
1834
- const current = await readCurrentProductionVersion(options, configPath);
1835
+ const current = await readCurrentProductionVersion(options);
1835
1836
  if (current.kind === "failed") return {
1836
1837
  ok: false,
1837
1838
  reason: "status-failed",
@@ -1850,7 +1851,7 @@ async function bootstrapFirstDeployment(options, configPath, previousVersionId,
1850
1851
  options.onProgress?.(atomic ? "Publishing the Worker atomically..." : "Publishing the first Worker deployment...");
1851
1852
  const bootstrap = await options.runWrangler({
1852
1853
  type: "worker.deploy",
1853
- configPath,
1854
+ configPath: options.configPath,
1854
1855
  workerName: options.workerName,
1855
1856
  message: options.message,
1856
1857
  secretsFilePath: options.candidateSecretsFilePath,
@@ -1899,7 +1900,7 @@ async function bootstrapFirstDeployment(options, configPath, previousVersionId,
1899
1900
  publishEmptyCrons: options.publishEmptyCrons
1900
1901
  };
1901
1902
  const verifyPublishedOwner = async () => {
1902
- const owner = await readCurrentProductionVersion(options, configPath);
1903
+ const owner = await readCurrentProductionVersion(options);
1903
1904
  if (owner.kind === "failed") return {
1904
1905
  ok: false,
1905
1906
  reason: "status-failed",
@@ -1976,7 +1977,7 @@ async function bootstrapFirstDeployment(options, configPath, previousVersionId,
1976
1977
  const customDomainBootstrap = !atomic && usesCustomDomain;
1977
1978
  const readinessTimeoutMs = customDomainBootstrap ? 3e5 : 6e4;
1978
1979
  options.onProgress?.("Waiting for the Worker to become ready...");
1979
- 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);
1980
+ 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 ?? setTimeout, options.readinessAttempts ?? (customDomainBootstrap ? 150 : 30), readinessTimeoutMs, options.requireVersionMetadata ? versionId : void 0);
1980
1981
  if (ready !== "ready") return {
1981
1982
  ok: false,
1982
1983
  reason: ready === "access-denied" ? atomic ? "atomic-readiness-access-denied" : "bootstrap-readiness-access-denied" : atomic ? "atomic-readiness-failed" : "bootstrap-readiness-failed",
@@ -1992,7 +1993,7 @@ async function bootstrapFirstDeployment(options, configPath, previousVersionId,
1992
1993
  previousVersionId,
1993
1994
  rollback: "unsafe"
1994
1995
  };
1995
- const ownerAfterReadiness = await readCurrentProductionVersion(options, configPath);
1996
+ const ownerAfterReadiness = await readCurrentProductionVersion(options);
1996
1997
  if (ownerAfterReadiness.kind === "failed") return {
1997
1998
  ok: false,
1998
1999
  reason: "status-failed",
@@ -2048,10 +2049,10 @@ function commandDiagnosticFields(result) {
2048
2049
  function isContainersUnavailable(result) {
2049
2050
  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);
2050
2051
  }
2051
- async function readCurrentProductionVersion(options, configPath) {
2052
+ async function readCurrentProductionVersion(options) {
2052
2053
  const result = await options.runWrangler({
2053
2054
  type: "deployments.status",
2054
- configPath,
2055
+ configPath: options.configPath,
2055
2056
  workerName: options.workerName
2056
2057
  }, { capture: true });
2057
2058
  if (!isCleanCommandExit(result)) {
@@ -2101,7 +2102,7 @@ function stagedVersionPercentages(previousVersionId, versionId) {
2101
2102
  }] : [];
2102
2103
  }
2103
2104
  /** Stage the candidate at 0% beside the unchanged previous version so readiness can select it. */
2104
- async function stageCandidateForReadiness(options, configPath, previousVersionId, versionId, message) {
2105
+ async function stageCandidateForReadiness(options, previousVersionId, versionId, message) {
2105
2106
  if (!options.verifyUploader()) return {
2106
2107
  ok: false,
2107
2108
  reason: "uploader-changed",
@@ -2109,9 +2110,9 @@ async function stageCandidateForReadiness(options, configPath, previousVersionId
2109
2110
  previousVersionId,
2110
2111
  rollback: "not-needed"
2111
2112
  };
2112
- const ownerFailure = await verifyReadinessStagingOwner(options, configPath, previousVersionId, versionId);
2113
+ const ownerFailure = await verifyReadinessStagingOwner(options, previousVersionId, versionId);
2113
2114
  if (ownerFailure) return ownerFailure;
2114
- const staged = await deployVersionPercentages(options, configPath, [`${previousVersionId}@100`, `${versionId}@0`], message);
2115
+ const staged = await deployVersionPercentages(options, [`${previousVersionId}@100`, `${versionId}@0`], message);
2115
2116
  if (!isCleanCommandExit(staged)) {
2116
2117
  const cloudflareErrorCode = staged.errorCode;
2117
2118
  return {
@@ -2127,8 +2128,8 @@ async function stageCandidateForReadiness(options, configPath, previousVersionId
2127
2128
  }
2128
2129
  return null;
2129
2130
  }
2130
- async function verifyReadinessStagingOwner(options, configPath, previousVersionId, versionId) {
2131
- const owner = await readCurrentProductionVersion(options, configPath);
2131
+ async function verifyReadinessStagingOwner(options, previousVersionId, versionId) {
2132
+ const owner = await readCurrentProductionVersion(options);
2132
2133
  if (owner.kind === "failed") return {
2133
2134
  ok: false,
2134
2135
  reason: "status-failed",
@@ -2184,8 +2185,8 @@ async function probeReadiness(url, workerName, readinessHeaders, authenticatedWo
2184
2185
  if (response && !response.bodyUsed) await response.body?.cancel().catch(() => {});
2185
2186
  }
2186
2187
  if (attempt + 1 < attempts) {
2187
- const delay = Math.min(250 * 2 ** attempt, 2e3, deadline - Date.now());
2188
- if (delay > 0) await sleep(delay);
2188
+ const waitMs = Math.min(250 * 2 ** attempt, 2e3, deadline - Date.now());
2189
+ if (waitMs > 0) await sleep(waitMs);
2189
2190
  }
2190
2191
  }
2191
2192
  return "failed";
@@ -2214,7 +2215,7 @@ async function isCloudflareAccessDenial(response) {
2214
2215
  return false;
2215
2216
  }
2216
2217
  }
2217
- async function deployVersionPercentages(options, configPath, percentages, message) {
2218
+ async function deployVersionPercentages(options, percentages, message) {
2218
2219
  const metadata = parseCloudflareVersionMessage(message);
2219
2220
  if ((options.preserveTriggers || metadata?.schema === 2 && metadata.triggerConfig.preserve) && options.configPath) return deployCloudflareVersionTraffic({
2220
2221
  ...options,
@@ -2225,7 +2226,7 @@ async function deployVersionPercentages(options, configPath, percentages, messag
2225
2226
  return options.runWrangler({
2226
2227
  type: "versions.deploy",
2227
2228
  versions: versionPercentages(percentages),
2228
- configPath,
2229
+ configPath: options.configPath,
2229
2230
  workerName: options.workerName,
2230
2231
  message
2231
2232
  }, { capture: false });
@@ -2251,12 +2252,12 @@ async function deployCloudflareVersionTraffic(options) {
2251
2252
  });
2252
2253
  }
2253
2254
  }
2254
- async function restorePreviousVersion(options, configPath, previousVersionId, cause, expectedOwnedTraffic) {
2255
+ async function restorePreviousVersion(options, previousVersionId, cause, expectedOwnedTraffic) {
2255
2256
  if (!previousVersionId) return "unavailable";
2256
2257
  if (!options.verifyUploader()) return "unsafe";
2257
- const owner = await readCurrentProductionVersion(options, configPath);
2258
+ const owner = await readCurrentProductionVersion(options);
2258
2259
  if (owner.kind !== "ok" || !expectedOwnedTraffic.some((expected) => productionVersionPercentagesEqual(owner.versions, expected))) return "unsafe";
2259
- return isCleanCommandExit(await deployVersionPercentages(options, configPath, [`${previousVersionId}@100`], `Void automatic rollback after ${cause}.`)) ? "succeeded" : "failed";
2260
+ return isCleanCommandExit(await deployVersionPercentages(options, [`${previousVersionId}@100`], `Void automatic rollback after ${cause}.`)) ? "succeeded" : "failed";
2260
2261
  }
2261
2262
  function workersDevReadinessUrl(workerName, value) {
2262
2263
  const subdomain = normalizeWorkersDevSubdomain(value);
@@ -2290,9 +2291,6 @@ function workersDevSubdomainResult(url) {
2290
2291
  const workersDevSubdomain = extractWorkersDevSubdomain(url);
2291
2292
  return workersDevSubdomain ? { workersDevSubdomain } : {};
2292
2293
  }
2293
- function defaultSleep(milliseconds) {
2294
- return new Promise((resolve) => setTimeout(resolve, milliseconds));
2295
- }
2296
2294
  //#endregion
2297
2295
  //#region src/metadata.ts
2298
2296
  /**
@@ -2385,4 +2383,4 @@ function createCloudflareMetadataRunner(options) {
2385
2383
  };
2386
2384
  }
2387
2385
  //#endregion
2388
- 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 };
2386
+ export { CloudflareWorkerInspectionError, VOID_SECRET_DRAFT_SOURCE, activateCloudflareVersion, assertCloudflareBindingsPreserved, assertCloudflareDurableObjectLifecycleSupported, assertExistingCloudflareConfig, cloudflareCommandDiagnostic, createCloudflareMetadataRunner, deployCloudflareVersionTraffic, deployCloudflareVersionTriggers, encodeCloudflareVersionMessage, executeCloudflareDeploy, extractWorkersDevSubdomain, normalizeWorkersDevSubdomain, parseCloudflareVersionMessage, parseRootWranglerConfig, readBindingFieldPresence, readCloudflareTriggerConfig, readCloudflareVersionMigrationTag, readCloudflareWorkerMigrationTag, readConfigEntryString, readExistingCloudflareWorker, readStoredResourceName, readWranglerTopLevelString, renderCloudflareStaticEntry, resolveD1MigrateTarget, stabilizeCloudflareVersionTriggers, stageCloudflareStaticAssets, writeCloudflareFrameworkDeployConfig, writeCloudflareStaticDeployConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@void/deploy-cloudflare",
3
- "version": "0.27.0",
3
+ "version": "1.0.3",
4
4
  "description": "Cloudflare deployment primitives for Void runtimes and deployment adapters.",
5
5
  "homepage": "https://void.cloud",
6
6
  "bugs": {
@@ -26,15 +26,15 @@
26
26
  "access": "public"
27
27
  },
28
28
  "dependencies": {
29
- "@void/deploy-core": "0.27.0",
29
+ "@void/deploy-core": "1.0.3",
30
30
  "jsonc-parser": "^3.3.1"
31
31
  },
32
32
  "devDependencies": {
33
- "@cloudflare/workers-types": "^5.20261009.1",
34
- "@types/node": "^26.6.4",
33
+ "@cloudflare/workers-types": "^5.20261014.1",
34
+ "@types/node": "^26.6.5",
35
35
  "pathslash": "^0.1.0",
36
36
  "typescript": "7.0.2",
37
- "vite-plus": "1.1.0"
37
+ "vite-plus": "1.2.0"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "vp pack",