void 0.21.2 → 0.21.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.
Files changed (184) hide show
  1. package/dist/{account-cmd-D8OC-U7y.mjs → account-cmd-DGt9cpRe.mjs} +4 -4
  2. package/dist/{agents-gni4eqBu.mjs → agents-B_pX_HmQ.mjs} +1 -1
  3. package/dist/ast-CPGPjb0V.mjs +18 -0
  4. package/dist/{auth-CAw7zHqj.mjs → auth-CZuiVsFh.mjs} +1 -1
  5. package/dist/{auth-B9_D6ygs.mjs → auth-DLNN0D3Z.mjs} +4 -4
  6. package/dist/{auth-link-BYFeMJAp.mjs → auth-link-Cl9vOuf7.mjs} +4 -4
  7. package/dist/{auth-router-OHZNmrb_.mjs → auth-router-D4ZcMUSf.mjs} +6 -6
  8. package/dist/{better-auth-shared-BoVwA5Vm.d.mts → better-auth-shared-BVkjZ3vM.d.mts} +1 -0
  9. package/dist/{better-auth-shared-syGYYmnY.mjs → better-auth-shared-rsBGBvWJ.mjs} +3 -6
  10. package/dist/{build-cmd-Bft7EY51.mjs → build-cmd-Dpt0jd-x.mjs} +4 -4
  11. package/dist/{cache-CKV1Gz2w.mjs → cache-7_UeZdTk.mjs} +4 -4
  12. package/dist/{cancel-deploy-BAKmkX4f.mjs → cancel-deploy-D23R1RXT.mjs} +3 -3
  13. package/dist/{cf-access-rAZxzMkL.mjs → cf-access-P0iZnu0q.mjs} +1 -1
  14. package/dist/{cf-build-output-CTdlo6Rt.mjs → cf-build-output-CGT03qCD.mjs} +2 -2
  15. package/dist/cli/cf-compat.mjs +2 -2
  16. package/dist/cli/cli.mjs +47 -43
  17. package/dist/cli/env-schema-probe.mjs +3 -3
  18. package/dist/client-4cDVv7BO.mjs +2 -0
  19. package/dist/{client-PdAJ-F0t.mjs → client-QTl6ko_D.mjs} +28 -5
  20. package/dist/{cloudflare-auth-BCmTc1X_.mjs → cloudflare-auth-B9jPCkV2.mjs} +1 -1
  21. package/dist/{cloudflare-cmd-D6PrKn7o.mjs → cloudflare-cmd-BjNxR1XF.mjs} +3 -3
  22. package/dist/{cloudflare-connect-DloREDlc.mjs → cloudflare-connect-CCUozPOe.mjs} +3 -3
  23. package/dist/{cloudflare-operations-BHNJVDbN.mjs → cloudflare-operations-BipGMJ5O.mjs} +1 -1
  24. package/dist/{cloudflare-operations-CPEdHYhM.mjs → cloudflare-operations-sMZXpk_S.mjs} +4 -4
  25. package/dist/collect-DLyFDiKW.mjs +2 -0
  26. package/dist/{collect-DXHNWHcT.mjs → collect-DiTn9yr6.mjs} +1 -1
  27. package/dist/config-0acf1oys.mjs +2 -0
  28. package/dist/{config-DywxBLQC.d.mts → config-CF69HgXc.d.mts} +7 -0
  29. package/dist/{config-Dxr6cTXn.mjs → config-CafTW6Cz.mjs} +12 -1
  30. package/dist/{config-BSe70f4T.mjs → config-D8MOgiQV.mjs} +3 -3
  31. package/dist/config-DPByhVck.mjs +32 -0
  32. package/dist/config-entry.d.mts +1 -1
  33. package/dist/{config--T87TD8T.mjs → config-s7Xj7tPb.mjs} +1 -1
  34. package/dist/{config-write-y3CBI_ux.mjs → config-write-BSduPMY8.mjs} +3 -3
  35. package/dist/{connect-DLx1pRYk.mjs → connect-4Ph5Y0QE.mjs} +7 -7
  36. package/dist/{create-project-JV9-6ICF.mjs → create-project-BniEV0OW.mjs} +1 -1
  37. package/dist/{create-project-BZBl_gQ0.mjs → create-project-DBfFSZKY.mjs} +4 -4
  38. package/dist/{db-B98_UV4H.mjs → db-DzJRn-qz.mjs} +123 -55
  39. package/dist/{delete-BEEyqlwd.mjs → delete-D6dZ9B6B.mjs} +4 -4
  40. package/dist/deploy-BH0grP4y.mjs +2 -0
  41. package/dist/{deploy-Bsymb0_c.mjs → deploy-CsMJrPfM.mjs} +520 -260
  42. package/dist/discover-AMCBXivQ.mjs +2 -0
  43. package/dist/{discover-C4O6YxVS.mjs → discover-BcPPiF1o.mjs} +2 -2
  44. package/dist/{dist-4WkAWhWx.mjs → dist-BVqXeR_h.mjs} +9 -1
  45. package/dist/dist-_UUlL6bg.mjs +2 -0
  46. package/dist/{domain-Av2AkLQP.mjs → domain-Dmhvb2oU.mjs} +4 -4
  47. package/dist/{email-C5kaZXzJ.mjs → email--tEtMoj_.mjs} +1 -1
  48. package/dist/{email-CUqa6TtH.mjs → email-BRKOG2RG.mjs} +9 -9
  49. package/dist/{entry-DdRFGK0y.mjs → entry-CF5wvH4w.mjs} +4 -21
  50. package/dist/{env-D4RIGEzz.mjs → env-Csi-tMbT.mjs} +7 -7
  51. package/dist/{env-Yz4HcvHs.mjs → env-D5liuQYR.mjs} +5 -2
  52. package/dist/{env-DX_v-Q-v.mjs → env-_v349JBd.mjs} +1 -1
  53. package/dist/{env-types-CWDtqHgw.mjs → env-types-C2_bIk_b.mjs} +2 -2
  54. package/dist/{env-validation-BsFEXps5.mjs → env-validation-BB4GkLxn.mjs} +4 -4
  55. package/dist/{env-validation-DIDGM7h4.mjs → env-validation-BXge7uyK.mjs} +1 -1
  56. package/dist/{gen-pg-Ojg8Y.mjs → gen-Dz3X1Qab.mjs} +8 -8
  57. package/dist/gen-Vnv2f65C.mjs +2 -0
  58. package/dist/{generate-C0VY6RVf.mjs → generate-GDbL7sUr.mjs} +2 -2
  59. package/dist/{github-cmd-BEK4VprE.mjs → github-cmd-BED3_9JD.mjs} +4 -4
  60. package/dist/{headers-B_HBMgi0.mjs → headers-BOg_velo.mjs} +2 -2
  61. package/dist/{help-iQOt7WHk.mjs → help-DC7gdz7L.mjs} +7 -3
  62. package/dist/help-DQMfeKMz.mjs +2 -0
  63. package/dist/index.mjs +132 -158
  64. package/dist/{init-D5niUPAz.mjs → init-CRGDXzVC.mjs} +105 -289
  65. package/dist/{link-3lGrfXzd.mjs → link-CsHOinF7.mjs} +5 -5
  66. package/dist/{list-CVjGr_C6.mjs → list-CDb-4bZ1.mjs} +5 -5
  67. package/dist/{local-d1-DzykTWY8.mjs → local-d1-CC8sKFGu.mjs} +3 -3
  68. package/dist/{login-BgQJzxAl.mjs → login-BQyISZuW.mjs} +3 -3
  69. package/dist/login-r2gL8l7B.mjs +2 -0
  70. package/dist/{logs-DbzD-QDf.mjs → logs-BdfiOezj.mjs} +4 -4
  71. package/dist/{migrate-BV8qHiCb.mjs → migrate-B8KuoYsO.mjs} +69 -44
  72. package/dist/migrate-TsHGBnDA.mjs +2 -0
  73. package/dist/{node-Cupyf7-s.mjs → node-BM43oz4G.mjs} +5 -5
  74. package/dist/{operator-auth-BkVgJqv-.mjs → operator-auth-8KnOVXVd.mjs} +2 -2
  75. package/dist/{operator-client-A0iex2yi.mjs → operator-client-DUwumHpQ.mjs} +2 -2
  76. package/dist/{operator-cmd-CR6Lxzt0.mjs → operator-cmd-Co-PeaeD.mjs} +6 -6
  77. package/dist/{package-json-iCbMg5XF.mjs → package-json-DXfiT1jV.mjs} +1 -1
  78. package/dist/pages/index.d.mts +1 -1
  79. package/dist/pages/index.mjs +11 -6
  80. package/dist/pages/islands-plugin.d.mts +271 -1
  81. package/dist/pages/islands-plugin.mjs +95 -18
  82. package/dist/parse-filename-DioPHiR9.mjs +77 -0
  83. package/dist/{platform-auth-config-De7BqRJm.mjs → platform-auth-config-TSw8edHw.mjs} +5 -5
  84. package/dist/{platform-auth-protection-Dcat-6zu.mjs → platform-auth-protection-Ba1XqGhn.mjs} +6 -6
  85. package/dist/{platform-auth-recovery-C9gsM640.mjs → platform-auth-recovery-BkT3EsF2.mjs} +5 -5
  86. package/dist/{platform-cmd-Cl9Uhzru.mjs → platform-cmd-C8OqhqPt.mjs} +1 -1
  87. package/dist/{platform-cmd-CudokNIg.mjs → platform-cmd-CRSKfu8k.mjs} +5 -5
  88. package/dist/{platform-domain-Ckpd2kXw.mjs → platform-domain-j9YCXRm6.mjs} +3 -3
  89. package/dist/{platform-lifecycle-DVzM2T4j.mjs → platform-lifecycle-78H0XQUA.mjs} +277 -229
  90. package/dist/{platform-lifecycle-DlpiGcjr.mjs → platform-lifecycle-DDc9zCeJ.mjs} +1 -1
  91. package/dist/{platform-management-ibuS1as0.mjs → platform-management-6w8-DUjC.mjs} +2 -2
  92. package/dist/{platform-management-44Bxd3YC.mjs → platform-management-DzKNsMlt.mjs} +1 -1
  93. package/dist/{platform-recovery-D_KmvdSk.mjs → platform-recovery-Do8VOyDE.mjs} +3 -3
  94. package/dist/{platform-registry-BJbgZLS1.mjs → platform-registry-QBa4DK32.mjs} +1 -1
  95. package/dist/{plugin-inference-DsvtJLll.mjs → plugin-inference-BMfKRSqE.mjs} +188 -85
  96. package/dist/prepare-BZXkjdNe.mjs +2 -0
  97. package/dist/{prepare-pcWcxSCh.mjs → prepare-C3kt3Rst.mjs} +11 -11
  98. package/dist/{prepare-_T-Haxrr.mjs → prepare-DyZ-Yok5.mjs} +1 -1
  99. package/dist/{prerender-render-Cf_WDE9W.mjs → prerender-render-D9qbLs2f.mjs} +1 -1
  100. package/dist/prerender-render.mjs +1 -1
  101. package/dist/{preset-Dowh9tTt.mjs → preset-UHj9ARyP.mjs} +4 -4
  102. package/dist/{project-BEBFDFLz.mjs → project-BuUwfj6f.mjs} +1 -1
  103. package/dist/{project-CWNIPoXc.mjs → project-C0Fqu05O.mjs} +2 -2
  104. package/dist/{project-cmd-BuF9doku.mjs → project-cmd-B44I8J_W.mjs} +15 -15
  105. package/dist/{project-paths-CKQ-Q5JS.mjs → project-paths-GgcMozYz.mjs} +1 -1
  106. package/dist/{project-team-B1Tia8vd.mjs → project-team-BkbYIsXN.mjs} +4 -4
  107. package/dist/{project-token-Bwxjf4y6.mjs → project-token-C8xEEQnB.mjs} +4 -4
  108. package/dist/{project-tsconfig-CwfqUnVp.mjs → project-tsconfig-B8GeM0RM.mjs} +2 -2
  109. package/dist/{provision-Cck2m3jJ.mjs → provision-BhreDAOS.mjs} +141 -78
  110. package/dist/provision-DNtrtaVD.mjs +3 -0
  111. package/dist/{requests-CphRF98D.mjs → requests-DFyhBMaf.mjs} +3 -3
  112. package/dist/{resolve-project-Xvis70DG.mjs → resolve-project-BG5ORGID.mjs} +1 -1
  113. package/dist/resolve-project-DtbidV4y.mjs +2 -0
  114. package/dist/{rollback-BYHJV2yD.mjs → rollback-DHHxXZiS.mjs} +4 -4
  115. package/dist/{route-types-Id82-veQ.mjs → route-types-Clm4WD0B.mjs} +39 -16
  116. package/dist/{runner-CQs_cDSG.mjs → runner-B8wXwWlo.mjs} +1 -1
  117. package/dist/{runner-mysql-1o47achK.mjs → runner-mysql-CEG5JozK.mjs} +1 -1
  118. package/dist/{runner-mysql-BhwMk2Bm.mjs → runner-mysql-DmWchSWJ.mjs} +1 -1
  119. package/dist/{runner-BGVsGgkb.mjs → runner-p-dMs2UN.mjs} +3 -3
  120. package/dist/{runner-pg-D7z01mQS.mjs → runner-pg-Bh4AgZdj.mjs} +1 -1
  121. package/dist/{runner-pg-CJ_JeGF6.mjs → runner-pg-D4OPlil-.mjs} +1 -1
  122. package/dist/runtime/better-auth-mysql.d.mts +1 -1
  123. package/dist/runtime/better-auth-mysql.mjs +1 -1
  124. package/dist/runtime/better-auth-pg.d.mts +1 -1
  125. package/dist/runtime/better-auth-pg.mjs +1 -1
  126. package/dist/runtime/better-auth.d.mts +1 -1
  127. package/dist/runtime/better-auth.mjs +2 -2
  128. package/dist/runtime/db.mjs +8 -5
  129. package/dist/runtime/durable.mjs +1 -1
  130. package/dist/runtime/email/testing.mjs +1 -1
  131. package/dist/runtime/env-public.mjs +1 -1
  132. package/dist/runtime/env.d.mts +1 -1
  133. package/dist/runtime/env.mjs +1 -1
  134. package/dist/runtime/kv.mjs +1 -1
  135. package/dist/runtime/live-server.mjs +38 -23
  136. package/dist/runtime/queues.mjs +1 -1
  137. package/dist/runtime/sandbox.mjs +1 -1
  138. package/dist/runtime/storage.mjs +1 -1
  139. package/dist/runtime/ws-server.d.mts +1 -1
  140. package/dist/runtime/ws-server.mjs +1 -1
  141. package/dist/{scan-DJbooZm2.mjs → scan-4tfN-PSn.mjs} +113 -99
  142. package/dist/{scan-DdDvRCU1.mjs → scan-ClYmX3sa.mjs} +35 -137
  143. package/dist/{secret-Rt9c4Ttw.mjs → secret-DN9sSNiV.mjs} +6 -6
  144. package/dist/{skills-B-690E7h.mjs → skills-O6FUaizK.mjs} +2 -2
  145. package/dist/sveltekit.mjs +1 -1
  146. package/dist/{validate-qNhV00PD.mjs → validate-CIUwFpjB.mjs} +2 -2
  147. package/dist/validate-EKmJWxmy.mjs +2 -0
  148. package/dist/{wrangler-D01qs6VB.mjs → wrangler-BymcxrRa.mjs} +3 -3
  149. package/dist/{yarn-pnp-CVEc3gE7.mjs → yarn-pnp-BV4AzNul.mjs} +1 -1
  150. package/package.json +7 -7
  151. package/schema.json +18 -0
  152. package/skills/void/docs/guide/app-types.md +1 -1
  153. package/skills/void/docs/guide/auth.md +2 -2
  154. package/skills/void/docs/guide/database/d1.md +6 -0
  155. package/skills/void/docs/guide/durable-state.md +1 -1
  156. package/skills/void/docs/guide/edge/rewrites.md +2 -3
  157. package/skills/void/docs/guide/env-migration.md +1 -1
  158. package/skills/void/docs/guide/pages-routing/markdown.md +1 -1
  159. package/skills/void/docs/guide/platform/development/local.md +1 -1
  160. package/skills/void/docs/guide/platform/installation/prerequisites.md +2 -2
  161. package/skills/void/docs/guide/platform/installation/setup.md +1 -1
  162. package/skills/void/docs/guide/server-routing.md +2 -3
  163. package/skills/void/docs/guide/ssr.md +4 -10
  164. package/skills/void/docs/guide/websockets.md +1 -1
  165. package/skills/void/docs/integrations/cloudflare.md +2 -0
  166. package/skills/void/docs/reference/api.md +1 -1
  167. package/skills/void/docs/reference/cli.md +9 -3
  168. package/skills/void/docs/reference/config.md +11 -0
  169. package/skills/void/docs/reference/resource-inference.md +1 -1
  170. package/dist/client-DAAivdid.mjs +0 -2
  171. package/dist/collect-DAUItMDS.mjs +0 -2
  172. package/dist/config-DDIFxQYx.mjs +0 -2
  173. package/dist/config-uP7ZDtVZ.mjs +0 -21
  174. package/dist/deploy-CsjbRNyv.mjs +0 -2
  175. package/dist/discover-BBzDZe_o.mjs +0 -2
  176. package/dist/dist-D7-nEOXi.mjs +0 -2
  177. package/dist/gen-B87rlalt.mjs +0 -2
  178. package/dist/help-r_vrpH_d.mjs +0 -2
  179. package/dist/login-Bz0zEPoy.mjs +0 -2
  180. package/dist/migrate-BXY3B3m7.mjs +0 -2
  181. package/dist/prepare-D4CkM3_v.mjs +0 -2
  182. package/dist/provision-CNgEBkVA.mjs +0 -3
  183. package/dist/resolve-project-BTotl8Nn.mjs +0 -2
  184. package/dist/validate-DqJ33oHj.mjs +0 -2
@@ -1,14 +1,14 @@
1
1
  import { n as __toESM } from "./rolldown-runtime-DXIUcv95.mjs";
2
- import { a as join } from "./dist-4WkAWhWx.mjs";
2
+ import { a as join } from "./dist-BVqXeR_h.mjs";
3
3
  import { c as import_picocolors$1, d as require_picocolors, i as createSpinner, n as cliCommandName, r as cliTitle } from "./output-CCH48AMM.mjs";
4
4
  import { t as cfAccessHeaders } from "./cf-access-DRsQRe6k.mjs";
5
- import { d as openBrowser } from "./auth-B9_D6ygs.mjs";
6
- import { a as listInstallationManifests, d as readInstallationRecoverySecrets, f as readPendingInstallationSecrets, g as savePlatformConnection, h as resolveInstallationManifest, i as latestPlatformWorkerCutoverGeneration, l as platformWorkerSecretUpdateIntentState, n as assertPlatformInstallationSlugAvailable, s as normalizePlatformApiUrl, t as acquirePlatformLifecycleLock, u as promoteInstallationSecrets, v as writeInstallationManifest, y as writePendingInstallationSecrets } from "./platform-registry-BJbgZLS1.mjs";
7
- import { n as ensurePlatformAccessToken } from "./cf-access-rAZxzMkL.mjs";
5
+ import { d as openBrowser } from "./auth-DLNN0D3Z.mjs";
6
+ import { a as listInstallationManifests, d as readInstallationRecoverySecrets, f as readPendingInstallationSecrets, g as savePlatformConnection, h as resolveInstallationManifest, i as latestPlatformWorkerCutoverGeneration, l as platformWorkerSecretUpdateIntentState, n as assertPlatformInstallationSlugAvailable, s as normalizePlatformApiUrl, t as acquirePlatformLifecycleLock, u as promoteInstallationSecrets, v as writeInstallationManifest, y as writePendingInstallationSecrets } from "./platform-registry-QBa4DK32.mjs";
7
+ import { n as ensurePlatformAccessToken } from "./cf-access-P0iZnu0q.mjs";
8
8
  import { B as text$1, E as confirm, F as password, G as settings, I as select, K as u$1, M as multiselect, N as note, O as intro, P as outro, R as symbol, U as CANCEL_SYMBOL, W as isCancel, g as S_PASSWORD_MASK, i as S_BAR_END, j as log, r as S_BAR } from "./dist-Dn6nn2IU.mjs";
9
- import { o as resolveWranglerArgv } from "./preset-Dowh9tTt.mjs";
10
- import { c as runCloudflareAuthCommand, n as announceCloudflareLogin } from "./cloudflare-auth-BCmTc1X_.mjs";
11
- import { g as resolvePinnedApiBaseUrl, o as createDefaultRunWrangler } from "./provision-Cck2m3jJ.mjs";
9
+ import { o as resolveWranglerArgv } from "./preset-UHj9ARyP.mjs";
10
+ import { c as runCloudflareAuthCommand, n as announceCloudflareLogin } from "./cloudflare-auth-B9jPCkV2.mjs";
11
+ import { _ as resolvePinnedApiBaseUrl, o as createDefaultRunWrangler } from "./provision-BhreDAOS.mjs";
12
12
  import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
13
13
  import { createHash, createHmac, randomBytes, randomUUID } from "node:crypto";
14
14
  import { tmpdir } from "node:os";
@@ -1499,7 +1499,7 @@ async function verifyInstalledPlatformAccessProtection(input) {
1499
1499
  }
1500
1500
  const existingWorkers = input.plan.actions.filter((action) => action.kind === "worker" && action.action === "update").map((action) => action.name);
1501
1501
  if (existingWorkers.length) {
1502
- const { verifyProtectionWorkerOrigins } = await import("./platform-auth-protection-Dcat-6zu.mjs");
1502
+ const { verifyProtectionWorkerOrigins } = await import("./platform-auth-protection-Ba1XqGhn.mjs");
1503
1503
  await verifyProtectionWorkerOrigins({
1504
1504
  request: input.client.request.bind(input.client),
1505
1505
  listWorkerDomains: input.client.listWorkerDomains.bind(input.client),
@@ -1570,8 +1570,8 @@ function verifyExternalPlatformHyperdrive(input) {
1570
1570
  const { config, expected } = input;
1571
1571
  const database = platformDatabaseNameFromOwnerUrl(input.databaseUrl);
1572
1572
  const hash = hyperdriveOriginConfigHash(config.origin);
1573
- if (config.id !== expected.id || config.name !== expected.name || config.origin.host !== expected.host.toLowerCase() || config.origin.user !== expected.user || config.origin.database !== database || input.recordedHash && input.recordedHash !== hash) throw new Error("platform: The Terraform-managed Hyperdrive does not match the expected database origin.");
1574
- if (config.cachingDisabled !== true) throw new Error("platform: Disable SQL result caching on the Terraform-managed Hyperdrive before installing.");
1573
+ if (config.id !== expected.id || config.name !== expected.name || config.origin.host !== expected.host.toLowerCase() || config.origin.user !== expected.user || config.origin.database !== database || input.recordedHash && input.recordedHash !== hash) throw new Error("platform: The externally managed Hyperdrive does not match the expected database origin.");
1574
+ if (config.cachingDisabled !== true) throw new Error("platform: Disable SQL result caching on the externally managed Hyperdrive before installing.");
1575
1575
  return hash;
1576
1576
  }
1577
1577
  /** Authentication requires fresh reads; mutate only the installation-owned configuration. */
@@ -1782,16 +1782,18 @@ async function createPlatformInstallPlan(client, input, existing, options) {
1782
1782
  const recordedHyperdrive = existing?.resources.find((resource) => resource.key === "hyperdrive");
1783
1783
  const externalHyperdriveId = input.externalHyperdrive?.id || (recordedHyperdrive?.ownership === "adopted" ? recordedHyperdrive.id : "");
1784
1784
  if (externalHyperdriveId) {
1785
- if (recordedHyperdrive && (recordedHyperdrive.ownership !== "adopted" || recordedHyperdrive.id !== externalHyperdriveId)) throw new Error("platform: The Terraform-managed Hyperdrive differs from this installation.");
1785
+ if (recordedHyperdrive && (recordedHyperdrive.ownership !== "adopted" || recordedHyperdrive.id !== externalHyperdriveId)) throw new Error("platform: The externally managed Hyperdrive differs from this installation.");
1786
1786
  const remote = hyperdrives.find((resource) => resource.id === externalHyperdriveId);
1787
- if (!remote || remote.name !== names.hyperdrive) throw new Error(`platform: Terraform-managed Hyperdrive ${JSON.stringify(externalHyperdriveId)} must exist with the name ${JSON.stringify(names.hyperdrive)}.`);
1787
+ const selectedName = input.externalHyperdrive?.name;
1788
+ const recordedName = recordedHyperdrive?.name;
1789
+ if (!remote || selectedName && remote.name !== selectedName || recordedName && remote.name !== recordedName) throw new Error(`platform: Externally managed Hyperdrive ${JSON.stringify(externalHyperdriveId)} must exist with its selected name.`);
1788
1790
  actions.push({
1789
1791
  action: recordedHyperdrive ? "reuse" : "adopt",
1790
1792
  id: remote.id,
1791
1793
  key: "hyperdrive",
1792
1794
  kind: "hyperdrive",
1793
1795
  name: remote.name,
1794
- reason: recordedHyperdrive ? "Reuse the recorded Terraform-managed Hyperdrive." : "Use the Terraform-managed Hyperdrive without taking ownership."
1796
+ reason: recordedHyperdrive ? "Reuse the recorded externally managed Hyperdrive." : "Use the externally managed Hyperdrive without taking ownership."
1795
1797
  });
1796
1798
  } else addNamedPlan(actions, existing, "hyperdrive", "hyperdrive", names.hyperdrive, hyperdrives.filter((resource) => resource.name === names.hyperdrive), "reuse", options, remoteOwnership);
1797
1799
  for (const [key, name] of [
@@ -2427,6 +2429,204 @@ function parseWorkerSecretUpdateIntent(value) {
2427
2429
  function sanitizeWorkerSecretUpdates(updates) {
2428
2430
  return Object.fromEntries(Object.entries(updates ?? {}).filter(([name, value]) => PLATFORM_WORKER_SECRET_UPDATE_NAMES.includes(name) && typeof value === "string" && value !== ""));
2429
2431
  }
2432
+ async function reconcilePlatformInstallationResources(manifest, plan, secrets, zoneId, externalHyperdriveOriginHash, dependencies, now, writeRemoteInstallationCheckpoint, onManifestChange) {
2433
+ for (const action of plan.actions.filter((entry) => entry.key !== "routing-kv" && entry.kind !== "zone" && entry.kind !== "worker")) {
2434
+ const retainedManifest = retainReplacedInstallationResource(manifest, action, now());
2435
+ if (retainedManifest !== manifest) {
2436
+ manifest = retainedManifest;
2437
+ onManifestChange(manifest);
2438
+ writeInstallationManifest(manifest);
2439
+ await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2440
+ }
2441
+ if (action.action === "adopt") {
2442
+ if (!action.id) throw new Error(`platform: Adopted ${action.kind} ${action.name} has no id.`);
2443
+ manifest = recordAdoptionIntent(manifest, action, action.id, now());
2444
+ onManifestChange(manifest);
2445
+ writeInstallationManifest(manifest);
2446
+ await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2447
+ manifest = recordResource(manifest, action, action.id, "adopted", now(), secrets.databaseUrl, action.kind === "hyperdrive" ? externalHyperdriveOriginHash : void 0);
2448
+ onManifestChange(manifest);
2449
+ writeInstallationManifest(manifest);
2450
+ await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2451
+ continue;
2452
+ }
2453
+ if (action.action === "reuse") {
2454
+ if (action.id && (action.kind === "hyperdrive" || !manifest.resources.some((resource) => resource.key === action.key))) {
2455
+ manifest = recordResource(manifest, action, action.id, void 0, now(), secrets.databaseUrl, action.kind === "hyperdrive" ? externalHyperdriveOriginHash : void 0);
2456
+ onManifestChange(manifest);
2457
+ writeInstallationManifest(manifest);
2458
+ await writeR2OwnershipMarkerIfNeeded(dependencies.client, plan, manifest, action);
2459
+ await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2460
+ }
2461
+ continue;
2462
+ }
2463
+ manifest = recordProvisionIntent(manifest, action, now());
2464
+ onManifestChange(manifest);
2465
+ writeInstallationManifest(manifest);
2466
+ await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2467
+ const resource = await createResource(dependencies.client, plan, action, secrets.databaseUrl, zoneId);
2468
+ manifest = recordResource(manifest, action, resource.id, "created", now(), secrets.databaseUrl, action.kind === "hyperdrive" ? externalHyperdriveOriginHash : resource.fingerprint);
2469
+ onManifestChange(manifest);
2470
+ writeInstallationManifest(manifest);
2471
+ await writeR2OwnershipMarkerIfNeeded(dependencies.client, plan, manifest, action);
2472
+ await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2473
+ }
2474
+ return manifest;
2475
+ }
2476
+ async function preparePlatformDatabaseSchema(manifest, runtime, runtimeDirectory, sourcePlatformVersion, hadPriorWorkers, plan, secrets, dependencies, releaseDatabaseLock, now, writeRemoteInstallationCheckpoint, onManifestChange) {
2477
+ dependencies.onProgress?.("Checking the platform database schema");
2478
+ const rollbackDatabase = dependencies.databaseRollbackSource;
2479
+ const migrationStep = `database-schema:${runtime.database.schemaDigest}`;
2480
+ if (rollbackDatabase) {
2481
+ const verifyDatabase = releaseDatabaseLock.verifyDatabase;
2482
+ if (!verifyDatabase) throw new Error("platform: The PostgreSQL lifecycle lock cannot verify the forward-only rollback schema.");
2483
+ await verifyDatabase(rollbackDatabase.directory, rollbackDatabase.manifest.database);
2484
+ manifest = {
2485
+ ...manifest,
2486
+ databaseSchemaDigest: rollbackDatabase.manifest.database.schemaDigest,
2487
+ updatedAt: now()
2488
+ };
2489
+ onManifestChange(manifest);
2490
+ writeInstallationManifest(manifest);
2491
+ await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2492
+ } else if (!manifest.steps.some((step) => step.key === migrationStep)) {
2493
+ dependencies.onProgress?.("Applying platform database migrations");
2494
+ const legacyMigrationStep = `database-migrations:${runtime.database.journalSha256}`;
2495
+ if (dependencies.migrateDatabase) {
2496
+ if (!manifest.steps.some((step) => step.key === legacyMigrationStep)) await dependencies.migrateDatabase(secrets.databaseUrl, join(runtimeDirectory, "drizzle"));
2497
+ } else {
2498
+ const prepareDatabase = dependencies.prepareDatabase ?? releaseDatabaseLock.prepareDatabase;
2499
+ if (!prepareDatabase) throw new Error("platform: The PostgreSQL lifecycle lock cannot verify or migrate this database.");
2500
+ await prepareDatabase(runtimeDirectory, runtime.database, sourcePlatformVersion, hadPriorWorkers);
2501
+ }
2502
+ manifest = recordInstallationStep(manifest, {
2503
+ completedAt: now(),
2504
+ key: migrationStep,
2505
+ resultHash: runtime.database.schemaDigest
2506
+ }, now());
2507
+ manifest = {
2508
+ ...manifest,
2509
+ databaseSchemaDigest: runtime.database.schemaDigest,
2510
+ updatedAt: now()
2511
+ };
2512
+ onManifestChange(manifest);
2513
+ writeInstallationManifest(manifest);
2514
+ await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2515
+ } else if (releaseDatabaseLock.verifyDatabase) {
2516
+ await releaseDatabaseLock.verifyDatabase(runtimeDirectory, runtime.database);
2517
+ if (manifest.databaseSchemaDigest !== runtime.database.schemaDigest) {
2518
+ manifest = {
2519
+ ...manifest,
2520
+ databaseSchemaDigest: runtime.database.schemaDigest,
2521
+ updatedAt: now()
2522
+ };
2523
+ onManifestChange(manifest);
2524
+ writeInstallationManifest(manifest);
2525
+ await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2526
+ }
2527
+ }
2528
+ return manifest;
2529
+ }
2530
+ async function recoverInterruptedPlatformWorkerCutover(manifest, interruptedCutover, workerActions, configs, previousConfigs, plan, dependencies, ids, zoneId, previousPublicEndpoints, hasEmailGatewayArtifact, runPinnedPlatformWrangler, now, writeRemoteInstallationCheckpoint, onManifestChange) {
2531
+ if (interruptedCutover) {
2532
+ for (const key of [...interruptedCutover.staged.keys()].reverse()) {
2533
+ const snapshot = interruptedCutover.staged.get(key);
2534
+ const preservedRoutes = dependencies.recoverWorkerCutover ? [] : await inventoryUnmanagedPlatformWorkerTraffic(dependencies.client, plan, snapshot.workerName);
2535
+ const recoveryConfig = mergePlatformWorkerTrafficConfig({
2536
+ ...configs[key],
2537
+ name: snapshot.workerName
2538
+ }, preservedRoutes);
2539
+ const previousRecoveryConfig = mergePlatformWorkerTrafficConfig({
2540
+ ...previousConfigs[key],
2541
+ name: snapshot.workerName
2542
+ }, preservedRoutes);
2543
+ if (dependencies.recoverWorkerCutover) await dependencies.recoverWorkerCutover({
2544
+ key,
2545
+ preserveCustomDomains: interruptedCutover.unsafeTraffic.has(key),
2546
+ previousVersionId: snapshot.previousVersionId,
2547
+ stagedVersionId: snapshot.stagedVersionId,
2548
+ workerName: snapshot.workerName
2549
+ });
2550
+ else {
2551
+ const recoveryTraffic = isolatePlatformWorkerCustomDomains(recoveryConfig);
2552
+ const previousRecoveryTraffic = isolatePlatformWorkerCustomDomains(previousRecoveryConfig);
2553
+ await rollbackPlatformWorker({
2554
+ accountId: plan.account.id,
2555
+ activatedDeploymentId: null,
2556
+ activatedVersionId: snapshot.stagedVersionId,
2557
+ config: recoveryConfig,
2558
+ nextTriggers: readTriggerConfigFromObject(recoveryTraffic.wranglerConfig),
2559
+ previousConfig: previousRecoveryConfig,
2560
+ previousCustomDomains: previousRecoveryTraffic.customDomains,
2561
+ previousDeployment: null,
2562
+ previousTriggers: mergePreservedTriggerRoutes(withoutPlatformCustomDomainTriggers(snapshot.previousTriggers), preservedRoutes),
2563
+ previousVersionId: snapshot.previousVersionId,
2564
+ preserveCustomDomains: interruptedCutover.unsafeTraffic.has(key),
2565
+ inspectNewWorker: () => inspectNewPlatformWorker(dependencies.client, plan.account.id, manifest, key === "emailGateway" ? "email-gateway-worker" : `${key}-worker`, snapshot.workerName),
2566
+ removeCustomDomains: async () => {
2567
+ if (!dependencies.client.removeRoutes) throw new Error("platform: Cloudflare route removal is unavailable.");
2568
+ await dependencies.client.removeRoutes(plan.account.id, zoneId, trackedPlatformWorkerTraffic(manifest, /* @__PURE__ */ new Set([snapshot.workerName])));
2569
+ },
2570
+ publishCustomDomains: (workerName, origins) => publishPlatformWorkerCustomDomains(dependencies.client, plan.account.id, workerName, origins),
2571
+ retainNewWorker: async () => {
2572
+ await dependencies.client.putKvValue(plan.account.id, requireId(ids, "routing-kv"), PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE);
2573
+ },
2574
+ runner: runPinnedPlatformWrangler,
2575
+ workerExisted: snapshot.previousVersionId !== null,
2576
+ workerName: snapshot.workerName
2577
+ });
2578
+ }
2579
+ }
2580
+ manifest = recordWorkerCutoverResolution(manifest, interruptedCutover.generation, "restored", now());
2581
+ manifest = recordWorkerTrafficState(manifest, interruptedCutover.generation, previousPublicEndpoints && interruptedCutover.unsafeTraffic.size === 0, now());
2582
+ let retainedNewWorker = false;
2583
+ for (const [, snapshot] of interruptedCutover.staged) {
2584
+ if (snapshot.previousVersionId !== null) continue;
2585
+ retainedNewWorker = true;
2586
+ }
2587
+ onManifestChange(manifest);
2588
+ writeInstallationManifest(manifest);
2589
+ await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2590
+ if (retainedNewWorker) {
2591
+ if (!dependencies.replanWorkers) throw new Error("platform: Recovering retained Workers requires a fresh Cloudflare installation plan.");
2592
+ workerActions = validateReplannedWorkerActions(plan, manifest, await dependencies.replanWorkers(manifest)).filter((action) => hasEmailGatewayArtifact || action.key !== "email-gateway-worker");
2593
+ }
2594
+ }
2595
+ return {
2596
+ manifest,
2597
+ workerActions
2598
+ };
2599
+ }
2600
+ async function recoverFailedPlatformInstallation(error, manifest, plan, dependencies, workerTrafficGuarded, workerDeploymentCommitted, workerRollbacks, authenticationEnforcementActive, authenticationProtocolTransition, workerCutoverGeneration, previousPublicEndpoints, now, writeRemoteInstallationCheckpoint) {
2601
+ let failure = error;
2602
+ const currentWorkerRecoveryIncomplete = error instanceof PlatformWorkerRecoveryIncompleteError;
2603
+ if (workerTrafficGuarded) try {
2604
+ await dependencies.client.putKvValue(plan.account.id, requireId(Object.fromEntries(manifest.resources.map((resource) => [resource.key, resource.id])), "routing-kv"), PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE);
2605
+ } catch (guardError) {
2606
+ failure = new Error(`platform: ${errorMessage(error)} The installation also failed to retain its routing safety gate: ${errorMessage(guardError)}`, { cause: error });
2607
+ }
2608
+ if (!workerDeploymentCommitted && workerRollbacks.length > 0 && !(authenticationEnforcementActive && authenticationProtocolTransition)) {
2609
+ const rollbackFailures = [];
2610
+ for (const rollback of workerRollbacks.reverse()) try {
2611
+ await rollback();
2612
+ } catch (rollbackError) {
2613
+ rollbackFailures.push(errorMessage(rollbackError));
2614
+ }
2615
+ workerRollbacks = [];
2616
+ if (rollbackFailures.length > 0 || currentWorkerRecoveryIncomplete) failure = new Error(rollbackFailures.length > 0 ? `platform: ${errorMessage(error)} Automatic Worker rollback was incomplete: ${rollbackFailures.join("; ")} Inspect the installation before retrying.` : `platform: ${errorMessage(error)} The current Worker rollback was incomplete. The cutover remains unresolved and will be recovered on retry.`, { cause: error });
2617
+ else if (workerCutoverGeneration > 0) {
2618
+ manifest = recordWorkerCutoverResolution(manifest, workerCutoverGeneration, "restored", now());
2619
+ manifest = recordWorkerTrafficState(manifest, workerCutoverGeneration, previousPublicEndpoints, now());
2620
+ writeInstallationManifest(manifest);
2621
+ }
2622
+ } else if (authenticationEnforcementActive && authenticationProtocolTransition) workerRollbacks = [];
2623
+ if (manifest.status !== "failed" && manifest.status !== "uninstalled") try {
2624
+ manifest = transitionInstallation(manifest, "failed", now());
2625
+ writeInstallationManifest(manifest);
2626
+ await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2627
+ } catch {}
2628
+ return failure;
2629
+ }
2430
2630
  async function installPlatform(plan, secrets, existing, dependencies) {
2431
2631
  if (plan.actions.some((action) => action.action === "inspect")) throw new Error("platform: AI Gateway access must be verified before provisioning. Provide AI Gateway: Edit on the runtime token, then retry.");
2432
2632
  const now = dependencies.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
@@ -2457,8 +2657,8 @@ async function installPlatform(plan, secrets, existing, dependencies) {
2457
2657
  const recordedHyperdrive = existing?.resources.find((resource) => resource.key === "hyperdrive");
2458
2658
  let externalHyperdriveOriginHash;
2459
2659
  if (hyperdriveAction && (hyperdriveAction.action === "adopt" || recordedHyperdrive?.ownership === "adopted")) {
2460
- if (!hyperdriveAction.id) throw new Error("platform: The Terraform-managed Hyperdrive has no ID.");
2461
- if (!plan.externalHyperdrive && !recordedHyperdrive) throw new Error("platform: The Terraform-managed Hyperdrive origin must be specified.");
2660
+ if (!hyperdriveAction.id) throw new Error("platform: The externally managed Hyperdrive has no ID.");
2661
+ if (!plan.externalHyperdrive && !recordedHyperdrive) throw new Error("platform: The externally managed Hyperdrive origin must be specified.");
2462
2662
  const live = await dependencies.client.getHyperdriveConfig(plan.account.id, hyperdriveAction.id);
2463
2663
  externalHyperdriveOriginHash = verifyExternalPlatformHyperdrive({
2464
2664
  config: live,
@@ -2747,93 +2947,16 @@ async function installPlatform(plan, secrets, existing, dependencies) {
2747
2947
  }
2748
2948
  }
2749
2949
  const zoneId = zone?.id ?? "";
2750
- for (const action of plan.actions.filter((entry) => entry.key !== "routing-kv" && entry.kind !== "zone" && entry.kind !== "worker")) {
2751
- const retainedManifest = retainReplacedInstallationResource(manifest, action, now());
2752
- if (retainedManifest !== manifest) {
2753
- manifest = retainedManifest;
2754
- writeInstallationManifest(manifest);
2755
- await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2756
- }
2757
- if (action.action === "adopt") {
2758
- if (!action.id) throw new Error(`platform: Adopted ${action.kind} ${action.name} has no id.`);
2759
- manifest = recordAdoptionIntent(manifest, action, action.id, now());
2760
- writeInstallationManifest(manifest);
2761
- await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2762
- manifest = recordResource(manifest, action, action.id, "adopted", now(), secrets.databaseUrl, action.kind === "hyperdrive" ? externalHyperdriveOriginHash : void 0);
2763
- writeInstallationManifest(manifest);
2764
- await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2765
- continue;
2766
- }
2767
- if (action.action === "reuse") {
2768
- if (action.id && (action.kind === "hyperdrive" || !manifest.resources.some((resource) => resource.key === action.key))) {
2769
- manifest = recordResource(manifest, action, action.id, void 0, now(), secrets.databaseUrl, action.kind === "hyperdrive" ? externalHyperdriveOriginHash : void 0);
2770
- writeInstallationManifest(manifest);
2771
- await writeR2OwnershipMarkerIfNeeded(dependencies.client, plan, manifest, action);
2772
- await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2773
- }
2774
- continue;
2775
- }
2776
- manifest = recordProvisionIntent(manifest, action, now());
2777
- writeInstallationManifest(manifest);
2778
- await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2779
- const resource = await createResource(dependencies.client, plan, action, secrets.databaseUrl, zoneId);
2780
- manifest = recordResource(manifest, action, resource.id, "created", now(), secrets.databaseUrl, action.kind === "hyperdrive" ? externalHyperdriveOriginHash : resource.fingerprint);
2781
- writeInstallationManifest(manifest);
2782
- await writeR2OwnershipMarkerIfNeeded(dependencies.client, plan, manifest, action);
2783
- await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2784
- }
2950
+ manifest = await reconcilePlatformInstallationResources(manifest, plan, secrets, zoneId, externalHyperdriveOriginHash, dependencies, now, writeRemoteInstallationCheckpoint, (next) => {
2951
+ manifest = next;
2952
+ });
2785
2953
  dependencies.onProgress?.("Verifying uncached authentication database reads");
2786
2954
  const authenticationDatabase = manifest.resources.find((resource) => resource.key === "hyperdrive");
2787
2955
  if (!authenticationDatabase) throw new Error("platform: The authentication database resource is missing.");
2788
2956
  await verifyPlatformAuthenticationDatabase(dependencies.client, plan.account.id, authenticationDatabase, secrets.databaseUrl);
2789
- dependencies.onProgress?.("Checking the platform database schema");
2790
- const rollbackDatabase = dependencies.databaseRollbackSource;
2791
- const migrationStep = `database-schema:${runtime.database.schemaDigest}`;
2792
- if (rollbackDatabase) {
2793
- const verifyDatabase = releaseDatabaseLock.verifyDatabase;
2794
- if (!verifyDatabase) throw new Error("platform: The PostgreSQL lifecycle lock cannot verify the forward-only rollback schema.");
2795
- await verifyDatabase(rollbackDatabase.directory, rollbackDatabase.manifest.database);
2796
- manifest = {
2797
- ...manifest,
2798
- databaseSchemaDigest: rollbackDatabase.manifest.database.schemaDigest,
2799
- updatedAt: now()
2800
- };
2801
- writeInstallationManifest(manifest);
2802
- await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2803
- } else if (!manifest.steps.some((step) => step.key === migrationStep)) {
2804
- dependencies.onProgress?.("Applying platform database migrations");
2805
- const legacyMigrationStep = `database-migrations:${runtime.database.journalSha256}`;
2806
- if (dependencies.migrateDatabase) {
2807
- if (!manifest.steps.some((step) => step.key === legacyMigrationStep)) await dependencies.migrateDatabase(secrets.databaseUrl, join(runtimeDirectory, "drizzle"));
2808
- } else {
2809
- const prepareDatabase = dependencies.prepareDatabase ?? releaseDatabaseLock.prepareDatabase;
2810
- if (!prepareDatabase) throw new Error("platform: The PostgreSQL lifecycle lock cannot verify or migrate this database.");
2811
- await prepareDatabase(runtimeDirectory, runtime.database, sourcePlatformVersion, hadPriorWorkers);
2812
- }
2813
- manifest = recordInstallationStep(manifest, {
2814
- completedAt: now(),
2815
- key: migrationStep,
2816
- resultHash: runtime.database.schemaDigest
2817
- }, now());
2818
- manifest = {
2819
- ...manifest,
2820
- databaseSchemaDigest: runtime.database.schemaDigest,
2821
- updatedAt: now()
2822
- };
2823
- writeInstallationManifest(manifest);
2824
- await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2825
- } else if (releaseDatabaseLock.verifyDatabase) {
2826
- await releaseDatabaseLock.verifyDatabase(runtimeDirectory, runtime.database);
2827
- if (manifest.databaseSchemaDigest !== runtime.database.schemaDigest) {
2828
- manifest = {
2829
- ...manifest,
2830
- databaseSchemaDigest: runtime.database.schemaDigest,
2831
- updatedAt: now()
2832
- };
2833
- writeInstallationManifest(manifest);
2834
- await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2835
- }
2836
- }
2957
+ manifest = await preparePlatformDatabaseSchema(manifest, runtime, runtimeDirectory, sourcePlatformVersion, hadPriorWorkers, plan, secrets, dependencies, releaseDatabaseLock, now, writeRemoteInstallationCheckpoint, (next) => {
2958
+ manifest = next;
2959
+ });
2837
2960
  dependencies.onProgress?.("Checking platform safety");
2838
2961
  const targetSandboxDrainProtocol = runtime.safetyProtocols?.sandboxDrain ?? 0;
2839
2962
  const prepareSandboxDrain = dependencies.prepareSandboxDrain ?? releaseDatabaseLock.prepareSandboxDrain;
@@ -2937,69 +3060,9 @@ async function installPlatform(plan, secrets, existing, dependencies) {
2937
3060
  });
2938
3061
  const managedRoutes = platformManagedWorkerTraffic(plan.deployment).routes;
2939
3062
  let workerActions = plan.actions.filter((action) => action.kind === "worker" && (hasEmailGatewayArtifact || action.key !== "email-gateway-worker"));
2940
- if (interruptedCutover) {
2941
- for (const key of [...interruptedCutover.staged.keys()].reverse()) {
2942
- const snapshot = interruptedCutover.staged.get(key);
2943
- const preservedRoutes = dependencies.recoverWorkerCutover ? [] : await inventoryUnmanagedPlatformWorkerTraffic(dependencies.client, plan, snapshot.workerName);
2944
- const recoveryConfig = mergePlatformWorkerTrafficConfig({
2945
- ...configs[key],
2946
- name: snapshot.workerName
2947
- }, preservedRoutes);
2948
- const previousRecoveryConfig = mergePlatformWorkerTrafficConfig({
2949
- ...previousConfigs[key],
2950
- name: snapshot.workerName
2951
- }, preservedRoutes);
2952
- if (dependencies.recoverWorkerCutover) await dependencies.recoverWorkerCutover({
2953
- key,
2954
- preserveCustomDomains: interruptedCutover.unsafeTraffic.has(key),
2955
- previousVersionId: snapshot.previousVersionId,
2956
- stagedVersionId: snapshot.stagedVersionId,
2957
- workerName: snapshot.workerName
2958
- });
2959
- else {
2960
- const recoveryTraffic = isolatePlatformWorkerCustomDomains(recoveryConfig);
2961
- const previousRecoveryTraffic = isolatePlatformWorkerCustomDomains(previousRecoveryConfig);
2962
- await rollbackPlatformWorker({
2963
- accountId: plan.account.id,
2964
- activatedDeploymentId: null,
2965
- activatedVersionId: snapshot.stagedVersionId,
2966
- config: recoveryConfig,
2967
- nextTriggers: readTriggerConfigFromObject(recoveryTraffic.wranglerConfig),
2968
- previousConfig: previousRecoveryConfig,
2969
- previousCustomDomains: previousRecoveryTraffic.customDomains,
2970
- previousDeployment: null,
2971
- previousTriggers: mergePreservedTriggerRoutes(withoutPlatformCustomDomainTriggers(snapshot.previousTriggers), preservedRoutes),
2972
- previousVersionId: snapshot.previousVersionId,
2973
- preserveCustomDomains: interruptedCutover.unsafeTraffic.has(key),
2974
- inspectNewWorker: () => inspectNewPlatformWorker(dependencies.client, plan.account.id, manifest, key === "emailGateway" ? "email-gateway-worker" : `${key}-worker`, snapshot.workerName),
2975
- removeCustomDomains: async () => {
2976
- if (!dependencies.client.removeRoutes) throw new Error("platform: Cloudflare route removal is unavailable.");
2977
- await dependencies.client.removeRoutes(plan.account.id, zoneId, trackedPlatformWorkerTraffic(manifest, /* @__PURE__ */ new Set([snapshot.workerName])));
2978
- },
2979
- publishCustomDomains: (workerName, origins) => publishPlatformWorkerCustomDomains(dependencies.client, plan.account.id, workerName, origins),
2980
- retainNewWorker: async () => {
2981
- await dependencies.client.putKvValue(plan.account.id, requireId(ids, "routing-kv"), PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE);
2982
- },
2983
- runner: runPinnedPlatformWrangler,
2984
- workerExisted: snapshot.previousVersionId !== null,
2985
- workerName: snapshot.workerName
2986
- });
2987
- }
2988
- }
2989
- manifest = recordWorkerCutoverResolution(manifest, interruptedCutover.generation, "restored", now());
2990
- manifest = recordWorkerTrafficState(manifest, interruptedCutover.generation, previousPublicEndpoints && interruptedCutover.unsafeTraffic.size === 0, now());
2991
- let retainedNewWorker = false;
2992
- for (const [, snapshot] of interruptedCutover.staged) {
2993
- if (snapshot.previousVersionId !== null) continue;
2994
- retainedNewWorker = true;
2995
- }
2996
- writeInstallationManifest(manifest);
2997
- await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
2998
- if (retainedNewWorker) {
2999
- if (!dependencies.replanWorkers) throw new Error("platform: Recovering retained Workers requires a fresh Cloudflare installation plan.");
3000
- workerActions = validateReplannedWorkerActions(plan, manifest, await dependencies.replanWorkers(manifest)).filter((action) => hasEmailGatewayArtifact || action.key !== "email-gateway-worker");
3001
- }
3002
- }
3063
+ ({manifest, workerActions} = await recoverInterruptedPlatformWorkerCutover(manifest, interruptedCutover, workerActions, configs, previousConfigs, plan, dependencies, ids, zoneId, previousPublicEndpoints, hasEmailGatewayArtifact, runPinnedPlatformWrangler, now, writeRemoteInstallationCheckpoint, (next) => {
3064
+ manifest = next;
3065
+ }));
3003
3066
  workerCutoverGeneration = nextWorkerCutoverGeneration(manifest);
3004
3067
  if (workerSecretUpdateIntent) {
3005
3068
  manifest = recordWorkerSecretUpdateState(manifest, workerCutoverGeneration, "pending", workerSecretUpdateIntent.id, now());
@@ -3310,34 +3373,7 @@ async function installPlatform(plan, secrets, existing, dependencies) {
3310
3373
  zoneNameServers: zone?.nameServers ?? []
3311
3374
  };
3312
3375
  } catch (error) {
3313
- let failure = error;
3314
- const currentWorkerRecoveryIncomplete = error instanceof PlatformWorkerRecoveryIncompleteError;
3315
- if (workerTrafficGuarded) try {
3316
- await dependencies.client.putKvValue(plan.account.id, requireId(Object.fromEntries(manifest.resources.map((resource) => [resource.key, resource.id])), "routing-kv"), PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE);
3317
- } catch (guardError) {
3318
- failure = new Error(`platform: ${errorMessage(error)} The installation also failed to retain its routing safety gate: ${errorMessage(guardError)}`, { cause: error });
3319
- }
3320
- if (!workerDeploymentCommitted && workerRollbacks.length > 0 && !(authenticationEnforcementActive && authenticationProtocolTransition)) {
3321
- const rollbackFailures = [];
3322
- for (const rollback of workerRollbacks.reverse()) try {
3323
- await rollback();
3324
- } catch (rollbackError) {
3325
- rollbackFailures.push(errorMessage(rollbackError));
3326
- }
3327
- workerRollbacks = [];
3328
- if (rollbackFailures.length > 0 || currentWorkerRecoveryIncomplete) failure = new Error(rollbackFailures.length > 0 ? `platform: ${errorMessage(error)} Automatic Worker rollback was incomplete: ${rollbackFailures.join("; ")} Inspect the installation before retrying.` : `platform: ${errorMessage(error)} The current Worker rollback was incomplete. The cutover remains unresolved and will be recovered on retry.`, { cause: error });
3329
- else if (workerCutoverGeneration > 0) {
3330
- manifest = recordWorkerCutoverResolution(manifest, workerCutoverGeneration, "restored", now());
3331
- manifest = recordWorkerTrafficState(manifest, workerCutoverGeneration, previousPublicEndpoints, now());
3332
- writeInstallationManifest(manifest);
3333
- }
3334
- } else if (authenticationEnforcementActive && authenticationProtocolTransition) workerRollbacks = [];
3335
- if (manifest.status !== "failed" && manifest.status !== "uninstalled") try {
3336
- manifest = transitionInstallation(manifest, "failed", now());
3337
- writeInstallationManifest(manifest);
3338
- await writeRemoteInstallationCheckpoint(dependencies.client, plan, manifest);
3339
- } catch {}
3340
- throw failure;
3376
+ throw await recoverFailedPlatformInstallation(error, manifest, plan, dependencies, workerTrafficGuarded, workerDeploymentCommitted, workerRollbacks, authenticationEnforcementActive, authenticationProtocolTransition, workerCutoverGeneration, previousPublicEndpoints, now, writeRemoteInstallationCheckpoint);
3341
3377
  } finally {
3342
3378
  await releaseDatabaseLock();
3343
3379
  }
@@ -5532,14 +5568,14 @@ function resolvePlatformInstallDatabaseUrl(checkpoint, manifest = null) {
5532
5568
  }
5533
5569
  async function runPlatformLifecycleCommand(args) {
5534
5570
  if (args.subcommand === "domain") {
5535
- const { runPlatformDomainCommand } = await import("./platform-domain-Ckpd2kXw.mjs");
5571
+ const { runPlatformDomainCommand } = await import("./platform-domain-j9YCXRm6.mjs");
5536
5572
  await runPlatformDomainCommand(args);
5537
5573
  return;
5538
5574
  }
5539
5575
  if (args.subcommand === "discover") {
5540
5576
  const client = new PlatformCloudflareClient((await resolvePlatformCloudflareCredential()).token);
5541
5577
  const accountId = await selectAccount(await readAccounts(client), args.account);
5542
- const { recoverPlatformInstallations } = await import("./platform-recovery-D_KmvdSk.mjs");
5578
+ const { recoverPlatformInstallations } = await import("./platform-recovery-Do8VOyDE.mjs");
5543
5579
  const recovered = await recoverPlatformInstallations(client, accountId, void 0, args.selector);
5544
5580
  if (recovered.length === 0) {
5545
5581
  log.info(`No recoverable Void platform installations were found in ${accountId}.`);
@@ -5549,7 +5585,7 @@ async function runPlatformLifecycleCommand(args) {
5549
5585
  return;
5550
5586
  }
5551
5587
  if (args.subcommand !== "install") {
5552
- const { runInstalledPlatformCommand } = await import("./platform-management-44Bxd3YC.mjs");
5588
+ const { runInstalledPlatformCommand } = await import("./platform-management-DzKNsMlt.mjs");
5553
5589
  await runInstalledPlatformCommand(args);
5554
5590
  return;
5555
5591
  }
@@ -5709,48 +5745,60 @@ async function runPlatformLifecycleCommand(args) {
5709
5745
  user: externalHyperdriveUser
5710
5746
  } : void 0;
5711
5747
  if (!externalHyperdrive && process.stdin.isTTY && (!existing || isPlatformSetupDraft(existing)) && !existing?.resources.some((resource) => resource.key === "hyperdrive")) {
5712
- const expectedName = existing?.deployment.resources.hyperdrive ?? createPlatformResourceNames(installationSlug).hyperdrive;
5713
- const matches = (await client.listHyperdriveConfigs(accountId)).filter((resource) => resource.name === expectedName);
5714
- if (matches.length > 1) throw new Error(`platform: More than one Hyperdrive named ${expectedName} exists.`);
5715
- const live = matches[0] ? await client.getHyperdriveConfig(accountId, matches[0].id) : null;
5716
- if (live) {
5717
- if (live.id !== matches[0].id || live.name !== expectedName || !live.origin.user) throw new Error(`platform: Could not verify the database user for existing Hyperdrive ${expectedName}.`);
5718
- note(`Database: ${live.origin.database}\nHost: ${live.origin.host}\nPort: ${live.origin.port}\nUser: ${live.origin.user}\nSQL result caching: ${live.cachingDisabled ? "disabled" : "enabled"}`, `Existing Hyperdrive ${expectedName}`);
5719
- const choice = await select({
5720
- message: "How should Void set up Hyperdrive?",
5721
- options: [{
5748
+ const suggestedName = existing?.deployment.resources.hyperdrive ?? createPlatformResourceNames(installationSlug).hyperdrive;
5749
+ const configurations = await client.listHyperdriveConfigs(accountId);
5750
+ const suggestedNameAvailable = !configurations.some((resource) => resource.name === suggestedName);
5751
+ const choice = await select({
5752
+ message: "How should Void set up Hyperdrive?",
5753
+ options: [
5754
+ ...configurations.length > 0 ? [{
5722
5755
  value: "existing",
5723
- label: `Use existing Hyperdrive ${expectedName}`
5724
- }, {
5725
- value: "cancel",
5726
- label: "Cancel installation"
5727
- }]
5756
+ label: "Use an existing Hyperdrive"
5757
+ }] : [],
5758
+ ...suggestedNameAvailable ? [{
5759
+ value: "create",
5760
+ label: "Let Void create Hyperdrive",
5761
+ hint: "recommended"
5762
+ }] : [],
5763
+ {
5764
+ value: "setup",
5765
+ label: "Set up a separately managed Hyperdrive"
5766
+ }
5767
+ ]
5768
+ });
5769
+ if (isCancel(choice)) throw new Error("platform: Cancelled.");
5770
+ if (choice === "setup") {
5771
+ note(`Create a Hyperdrive in account ${accountId} with any unused name${suggestedNameAvailable ? ` (for example ${suggestedName})` : ""}. Point it at the same dedicated PostgreSQL database you will give Void, use a runtime database user, and disable SQL result caching. If your organization manages Hyperdrive, ask its administrator to create it. Then rerun this command and select it from the list.\nSetup: https://developers.cloudflare.com/hyperdrive/get-started/`, "Set up Hyperdrive first");
5772
+ outro("No Cloudflare or local installation state was changed.");
5773
+ return;
5774
+ }
5775
+ if (choice === "existing") {
5776
+ const selectedId = await select({
5777
+ message: "Which Hyperdrive should Void use?",
5778
+ options: [...configurations].sort((a, b) => Number(b.name === suggestedName) - Number(a.name === suggestedName) || a.name.localeCompare(b.name) || a.id.localeCompare(b.id)).map((resource) => ({
5779
+ value: resource.id,
5780
+ label: resource.name,
5781
+ hint: resource.name === suggestedName ? `suggested · ${resource.id}` : resource.id
5782
+ }))
5728
5783
  });
5729
- if (isCancel(choice) || choice === "cancel") throw new Error("platform: Cancelled.");
5730
- if (!live.cachingDisabled) throw new Error(`platform: Disable SQL result caching on existing Hyperdrive ${expectedName} before installing.`);
5784
+ if (isCancel(selectedId)) throw new Error("platform: Cancelled.");
5785
+ const selected = configurations.find((resource) => resource.id === selectedId);
5786
+ if (!selected) throw new Error("platform: The selected Hyperdrive is no longer available.");
5787
+ const live = await client.getHyperdriveConfig(accountId, selected.id);
5788
+ if (live.id !== selected.id || live.name !== selected.name || !live.origin.user) throw new Error(`platform: Could not verify the database user for existing Hyperdrive ${selected.name}.`);
5789
+ note(`Database: ${live.origin.database}\nHost: ${live.origin.host}\nPort: ${live.origin.port}\nUser: ${live.origin.user}\nSQL result caching: ${live.cachingDisabled ? "disabled" : "enabled"}`, `Existing Hyperdrive ${live.name}`);
5790
+ if (!live.cachingDisabled) throw new Error(`platform: Disable SQL result caching on existing Hyperdrive ${live.name} before installing.`);
5791
+ const confirmed = await confirm({
5792
+ message: `Use ${live.name} for this platform?`,
5793
+ initialValue: true
5794
+ });
5795
+ if (isCancel(confirmed) || !confirmed) throw new Error("platform: Cancelled.");
5731
5796
  externalHyperdrive = {
5732
5797
  id: live.id,
5798
+ name: live.name,
5733
5799
  host: live.origin.host,
5734
5800
  user: live.origin.user
5735
5801
  };
5736
- } else {
5737
- const choice = await select({
5738
- message: "How should Void set up Hyperdrive?",
5739
- options: [{
5740
- value: "create",
5741
- label: "Let Void create Hyperdrive",
5742
- hint: "recommended"
5743
- }, {
5744
- value: "existing",
5745
- label: "Use a separately managed Hyperdrive"
5746
- }]
5747
- });
5748
- if (isCancel(choice)) throw new Error("platform: Cancelled.");
5749
- if (choice === "existing") {
5750
- note(`Create a Hyperdrive in account ${accountId} named ${expectedName}. Point it at the same dedicated PostgreSQL database you will give Void, use a runtime database user, and disable SQL result caching. If your organization manages Hyperdrive, ask its administrator to create it. Then rerun this command.\nSetup: https://developers.cloudflare.com/hyperdrive/get-started/`, "Set up Hyperdrive first");
5751
- outro("No Cloudflare or local installation state was changed.");
5752
- return;
5753
- }
5754
5802
  }
5755
5803
  }
5756
5804
  let authoritativeProvisionIntents = false;
@@ -5761,7 +5809,7 @@ async function runPlatformLifecycleCommand(args) {
5761
5809
  progress?.stop("Read the saved installation.");
5762
5810
  progress = void 0;
5763
5811
  if (authoritative) {
5764
- const { selectAuthoritativePlatformManifest } = await import("./platform-management-44Bxd3YC.mjs");
5812
+ const { selectAuthoritativePlatformManifest } = await import("./platform-management-DzKNsMlt.mjs");
5765
5813
  const selected = selectAuthoritativePlatformManifest(existing, authoritative);
5766
5814
  authoritativeProvisionIntents = true;
5767
5815
  if (!args.plan && JSON.stringify(selected) !== JSON.stringify(existing)) writeInstallationManifest(selected);
@@ -5990,7 +6038,7 @@ async function runPlatformLifecycleCommand(args) {
5990
6038
  })).actions.filter((action) => action.kind === "worker"),
5991
6039
  revalidateBeforeWorkerDeploy: (manifest, action) => revalidatePlatformInstallAction(client, plan, manifest, action),
5992
6040
  verifyExistingOwnership: async (manifest, databaseCheckpointExists) => {
5993
- const { verifyPlatformInstallationOwnership } = await import("./platform-management-44Bxd3YC.mjs");
6041
+ const { verifyPlatformInstallationOwnership } = await import("./platform-management-DzKNsMlt.mjs");
5994
6042
  const retainedReplacementKeys = new Set(plan.actions.filter((action) => {
5995
6043
  const previous = manifest.resources.find((resource) => resource.key === action.key);
5996
6044
  return action.action === "create" && previous && previous.name !== action.name;
@@ -1,2 +1,2 @@
1
- import { r as runPlatformLifecycleCommand } from "./platform-lifecycle-DVzM2T4j.mjs";
1
+ import { r as runPlatformLifecycleCommand } from "./platform-lifecycle-78H0XQUA.mjs";
2
2
  export { runPlatformLifecycleCommand };