@void/deploy-cloudflare 1.2.0 → 1.3.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 CHANGED
@@ -87,6 +87,7 @@ type CloudflareOperation = ({
87
87
  percentage: number;
88
88
  }>;
89
89
  message?: string;
90
+ bypassDeploymentChecks?: boolean;
90
91
  } & WorkerTarget) | ({
91
92
  type: "versions.upload" | "worker.deploy";
92
93
  message?: string;
@@ -345,6 +346,12 @@ type CloudflareVersionActivation = {
345
346
  versionId?: string;
346
347
  previousVersionId?: string | null;
347
348
  rollback?: "not-needed" | "succeeded" | "failed" | "unavailable" | "unsafe";
349
+ /**
350
+ * Cloudflare refused to restore the previous version because a secret
351
+ * changed with this deploy, so Void forced it. The previous version runs
352
+ * with its earlier secret values.
353
+ */
354
+ restoredOlderSecrets?: true;
348
355
  /** Version that owned production after a concurrent operation superseded this command. */
349
356
  activeVersionId?: string | null;
350
357
  /** Whether Void restored the active version's immutable trigger snapshot. */
@@ -474,6 +481,7 @@ export declare function deployCloudflareVersionTraffic(options: {
474
481
  workerName: string;
475
482
  percentages: Array<string>;
476
483
  message: string;
484
+ bypassDeploymentChecks?: boolean;
477
485
  }): Promise<CloudflareCommandResult>;
478
486
  /** Normalize an account workers.dev subdomain supplied by config or the environment. */
479
487
  export declare function normalizeWorkersDevSubdomain(value: string | undefined): string | undefined;
package/dist/index.mjs CHANGED
@@ -799,6 +799,7 @@ function cloudflareCommandDiagnostic(result) {
799
799
  //#endregion
800
800
  //#region src/version.ts
801
801
  const DURABLE_MIGRATION_VERSION_ERROR = 10211;
802
+ const CLOUDFLARE_SECRET_CHANGED_ERROR = 10220;
802
803
  /** Encode migration state into Cloudflare's version annotation for safe rollback diagnostics. */
803
804
  function encodeCloudflareVersionMessage(migrations, triggerConfig, contentHash) {
804
805
  const metadata = triggerConfig ? {
@@ -1526,14 +1527,14 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1526
1527
  reason: ready === "access-denied" ? "readiness-access-denied" : "readiness-failed",
1527
1528
  versionId,
1528
1529
  previousVersionId: previous.versionId,
1529
- rollback: stagedVersionOverride ? await restorePreviousVersion(options, previous.versionId, "readiness failed", [stagedVersionPercentages(previous.versionId, versionId)]) : "not-needed"
1530
+ ...stagedVersionOverride ? await restorePreviousVersion(options, previous.versionId, "readiness failed", [stagedVersionPercentages(previous.versionId, versionId)]) : { rollback: "not-needed" }
1530
1531
  };
1531
1532
  if (!options.verifyUploader()) return {
1532
1533
  ok: false,
1533
1534
  reason: "uploader-changed",
1534
1535
  versionId,
1535
1536
  previousVersionId: previous.versionId,
1536
- rollback: stagedVersionOverride ? await restorePreviousVersion(options, previous.versionId, "uploader verification failed", [stagedVersionPercentages(previous.versionId, versionId)]) : "not-needed"
1537
+ ...stagedVersionOverride ? await restorePreviousVersion(options, previous.versionId, "uploader verification failed", [stagedVersionPercentages(previous.versionId, versionId)]) : { rollback: "not-needed" }
1537
1538
  };
1538
1539
  const ownerBeforeActivation = await readCurrentProductionVersion(options);
1539
1540
  if (ownerBeforeActivation.kind === "failed") return {
@@ -1570,10 +1571,10 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1570
1571
  status: activate.status,
1571
1572
  versionId,
1572
1573
  previousVersionId: previous.versionId,
1573
- rollback: stagedVersionOverride ? await restorePreviousVersion(options, previous.versionId, "version activation failed", [stagedVersionPercentages(previous.versionId, versionId), [{
1574
+ ...stagedVersionOverride ? await restorePreviousVersion(options, previous.versionId, "version activation failed", [stagedVersionPercentages(previous.versionId, versionId), [{
1574
1575
  versionId,
1575
1576
  percentage: 100
1576
- }]]) : "not-needed"
1577
+ }]]) : { rollback: "not-needed" }
1577
1578
  };
1578
1579
  if (!options.verifyUploader()) return {
1579
1580
  ok: false,
@@ -1666,14 +1667,14 @@ async function activateCloudflareVersionWithSecretsFile(options) {
1666
1667
  triggerRepair: triggerRepairOutcome(repair)
1667
1668
  };
1668
1669
  }
1669
- const rollback = await restorePreviousVersionAndTriggers(options, previous.versionId, "trigger activation failed", desiredTriggerConfig, versionId, versionedPreviousTriggerConfigWithTraffic);
1670
+ const restore = await restorePreviousVersionAndTriggers(options, previous.versionId, "trigger activation failed", desiredTriggerConfig, versionId, versionedPreviousTriggerConfigWithTraffic);
1670
1671
  return {
1671
1672
  ok: false,
1672
1673
  reason: "triggers-failed",
1673
1674
  status: triggers.status,
1674
1675
  versionId,
1675
1676
  previousVersionId: previous.versionId,
1676
- rollback
1677
+ ...restore
1677
1678
  };
1678
1679
  }
1679
1680
  if (!triggers.targetOwnsTraffic) return {
@@ -1704,16 +1705,28 @@ async function restorePreviousVersionAndTriggers(options, previousVersionId, cau
1704
1705
  versionId: failedVersionId,
1705
1706
  percentage: 100
1706
1707
  }]]);
1707
- if (traffic !== "succeeded" || !previousVersionId) return traffic;
1708
- if (!options.verifyUploader()) return "unsafe";
1708
+ if (traffic.rollback !== "succeeded" || !previousVersionId) return traffic;
1709
+ if (!options.verifyUploader()) return {
1710
+ ...traffic,
1711
+ rollback: "unsafe"
1712
+ };
1709
1713
  let targetTriggerConfig = capturedTriggerConfig;
1710
1714
  if (!targetTriggerConfig) {
1711
1715
  const metadata = await readCloudflareVersionMetadata(options, previousVersionId);
1712
- if (metadata?.schema !== 2) return "unavailable";
1716
+ if (metadata?.schema !== 2) return {
1717
+ ...traffic,
1718
+ rollback: "unavailable"
1719
+ };
1713
1720
  targetTriggerConfig = metadata.triggerConfig;
1714
1721
  }
1715
- if (targetTriggerConfig.preserve) return "unavailable";
1716
- if (!options.verifyUploader()) return "unsafe";
1722
+ if (targetTriggerConfig.preserve) return {
1723
+ ...traffic,
1724
+ rollback: "unavailable"
1725
+ };
1726
+ if (!options.verifyUploader()) return {
1727
+ ...traffic,
1728
+ rollback: "unsafe"
1729
+ };
1717
1730
  const triggers = await stabilizeCloudflareVersionTriggers({
1718
1731
  runWrangler: options.runWrangler,
1719
1732
  workerName: options.workerName,
@@ -1725,7 +1738,10 @@ async function restorePreviousVersionAndTriggers(options, previousVersionId, cau
1725
1738
  publishEmptyCustomDomains: options.publishEmptyCustomDomains,
1726
1739
  publishEmptyCrons: options.publishEmptyCrons
1727
1740
  });
1728
- return triggers.ok && triggers.targetOwnsTraffic ? "succeeded" : "failed";
1741
+ return {
1742
+ ...traffic,
1743
+ rollback: triggers.ok && triggers.targetOwnsTraffic ? "succeeded" : "failed"
1744
+ };
1729
1745
  }
1730
1746
  async function readCloudflareVersionMetadata(options, versionId) {
1731
1747
  return (await readCloudflareVersionInspection(options, versionId))?.metadata ?? null;
@@ -2236,7 +2252,8 @@ async function deployVersionPercentages(options, percentages, message) {
2236
2252
  versions: versionPercentages(percentages),
2237
2253
  configPath: options.configPath,
2238
2254
  workerName: options.workerName,
2239
- message
2255
+ message,
2256
+ ...options.bypassDeploymentChecks ? { bypassDeploymentChecks: true } : {}
2240
2257
  }, { capture: false });
2241
2258
  }
2242
2259
  /** Change version traffic without synchronizing Worker settings from local config. */
@@ -2251,7 +2268,8 @@ async function deployCloudflareVersionTraffic(options) {
2251
2268
  versions: versionPercentages(options.percentages),
2252
2269
  configPath: path,
2253
2270
  workerName: options.workerName,
2254
- message: options.message
2271
+ message: options.message,
2272
+ ...options.bypassDeploymentChecks ? { bypassDeploymentChecks: true } : {}
2255
2273
  }, { capture: false });
2256
2274
  } finally {
2257
2275
  rmSync(directory, {
@@ -2261,11 +2279,26 @@ async function deployCloudflareVersionTraffic(options) {
2261
2279
  }
2262
2280
  }
2263
2281
  async function restorePreviousVersion(options, previousVersionId, cause, expectedOwnedTraffic) {
2264
- if (!previousVersionId) return "unavailable";
2265
- if (!options.verifyUploader()) return "unsafe";
2266
- const owner = await readCurrentProductionVersion(options);
2267
- if (owner.kind !== "ok" || !expectedOwnedTraffic.some((expected) => productionVersionPercentagesEqual(owner.versions, expected))) return "unsafe";
2268
- return isCleanCommandExit(await deployVersionPercentages(options, [`${previousVersionId}@100`], `Void automatic rollback after ${cause}.`)) ? "succeeded" : "failed";
2282
+ if (!previousVersionId) return { rollback: "unavailable" };
2283
+ if (!options.verifyUploader()) return { rollback: "unsafe" };
2284
+ const ownsExpectedTraffic = async () => {
2285
+ const owner = await readCurrentProductionVersion(options);
2286
+ return owner.kind === "ok" && expectedOwnedTraffic.some((expected) => productionVersionPercentagesEqual(owner.versions, expected));
2287
+ };
2288
+ if (!await ownsExpectedTraffic()) return { rollback: "unsafe" };
2289
+ const restore = (bypassDeploymentChecks) => deployVersionPercentages({
2290
+ ...options,
2291
+ bypassDeploymentChecks
2292
+ }, [`${previousVersionId}@100`], `Void automatic rollback after ${cause}.`);
2293
+ const result = await restore(false);
2294
+ if (result.errorCode === CLOUDFLARE_SECRET_CHANGED_ERROR) {
2295
+ if (!await ownsExpectedTraffic()) return { rollback: "unsafe" };
2296
+ return isCleanCommandExit(await restore(true)) ? {
2297
+ rollback: "succeeded",
2298
+ restoredOlderSecrets: true
2299
+ } : { rollback: "failed" };
2300
+ }
2301
+ return { rollback: isCleanCommandExit(result) ? "succeeded" : "failed" };
2269
2302
  }
2270
2303
  function workersDevReadinessUrl(workerName, value) {
2271
2304
  const subdomain = normalizeWorkersDevSubdomain(value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@void/deploy-cloudflare",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Cloudflare deployment primitives for Void runtimes and deployment adapters.",
5
5
  "homepage": "https://void.cloud",
6
6
  "bugs": {
@@ -26,7 +26,7 @@
26
26
  "access": "public"
27
27
  },
28
28
  "dependencies": {
29
- "@void/deploy-core": "1.2.0",
29
+ "@void/deploy-core": "1.3.0",
30
30
  "jsonc-parser": "^3.3.1"
31
31
  },
32
32
  "devDependencies": {