void 0.21.2 → 0.21.4

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-CTXIWD42.mjs} +123 -55
  39. package/dist/{delete-BEEyqlwd.mjs → delete-D6dZ9B6B.mjs} +4 -4
  40. package/dist/deploy-BVwow28d.mjs +2 -0
  41. package/dist/{deploy-Bsymb0_c.mjs → deploy-F1exK5F4.mjs} +567 -263
  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-BxHabktK.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 +3 -0
  166. package/skills/void/docs/reference/api.md +1 -1
  167. package/skills/void/docs/reference/cli.md +10 -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,58 +1,60 @@
1
1
  import { n as __toESM, t as __commonJSMin } from "./rolldown-runtime-DXIUcv95.mjs";
2
- import { a as join, l as relative, n as dirname, o as normalize, r as extname, t as basename, u as resolve } from "./dist-4WkAWhWx.mjs";
2
+ import { a as join, l as relative, n as dirname, o as normalize, r as extname, t as basename, u as resolve } from "./dist-BVqXeR_h.mjs";
3
3
  import { c as import_picocolors$1, d as require_picocolors, i as createSpinner, r as cliTitle } from "./output-CCH48AMM.mjs";
4
- import { i as resolveProjectPaths, n as readProjectPaths, t as assertNoRootSourceConventionConflicts } from "./project-paths-CKQ-Q5JS.mjs";
5
- import { t as findVoidAuthConfig } from "./config-uP7ZDtVZ.mjs";
4
+ import { i as resolveProjectPaths, n as readProjectPaths, t as assertNoRootSourceConventionConflicts } from "./project-paths-GgcMozYz.mjs";
5
+ import { t as findVoidAuthConfig } from "./config-DPByhVck.mjs";
6
6
  import { i as trustedCloudflareWorkerAccessHeaders, r as scopedAccessCredentials, t as cfAccessHeaders } from "./cf-access-DRsQRe6k.mjs";
7
- import { a as getApiUrl, c as getToken, l as getTokenSource, o as getProxyUrl, u as isStagingMode } from "./auth-B9_D6ygs.mjs";
8
- import { r as ensurePlatformProxyAccess, t as ensureCloudflaredToken } from "./cf-access-rAZxzMkL.mjs";
9
- import { d as writeProjectConfig, i as readDeploymentPlatform, l as writeDeploymentPlatform, o as readProjectConfig, t as attachSelectedPlatform } from "./project-CWNIPoXc.mjs";
10
- import { d as isNodeTarget, h as resolveBindingNames, m as readConfig, u as getDatabaseDialect } from "./config-Dxr6cTXn.mjs";
11
- import { A as writeWranglerPublishedTrafficSnapshot, D as syncWranglerWebSockets, E as syncWranglerDurableObjects, L as materializeCloudflareConfig, M as isSandboxEnabled, N as requiresSandboxPlatformImage, P as resolveSandboxConfig, R as persistCloudflareConfig, S as readWranglerPublishedTrafficSnapshot, T as syncWranglerBindings, V as stashCloudflareDeployPointer, a as LIVE_MIGRATION_TAG, c as bindingEntriesForField, f as findBindingNameOwner, g as readExistingLiveBindingConfig, h as normalizeWranglerCompatibilityFlags, k as writeProvisionedWranglerConfig, l as ensureWranglerCompat, o as acknowledgeWranglerManagedQueueRemovals, r as FRIENDLY_BINDING_NAMES, w as resolveLiveBindingConfig, x as readWranglerManagedQueueCleanupCandidates } from "./wrangler-D01qs6VB.mjs";
7
+ import { a as getApiUrl, c as getToken, l as getTokenSource, o as getProxyUrl, u as isStagingMode } from "./auth-DLNN0D3Z.mjs";
8
+ import { r as ensurePlatformProxyAccess, t as ensureCloudflaredToken } from "./cf-access-P0iZnu0q.mjs";
9
+ import { d as writeProjectConfig, i as readDeploymentPlatform, l as writeDeploymentPlatform, o as readProjectConfig, t as attachSelectedPlatform } from "./project-C0Fqu05O.mjs";
10
+ import { d as isNodeTarget, h as resolveBindingNames, m as readConfig, u as getDatabaseDialect } from "./config-CafTW6Cz.mjs";
11
+ import { A as writeWranglerPublishedTrafficSnapshot, D as syncWranglerWebSockets, E as syncWranglerDurableObjects, L as materializeCloudflareConfig, M as isSandboxEnabled, N as requiresSandboxPlatformImage, P as resolveSandboxConfig, R as persistCloudflareConfig, S as readWranglerPublishedTrafficSnapshot, T as syncWranglerBindings, V as stashCloudflareDeployPointer, a as LIVE_MIGRATION_TAG, c as bindingEntriesForField, f as findBindingNameOwner, g as readExistingLiveBindingConfig, h as normalizeWranglerCompatibilityFlags, j as SANDBOX_MIGRATION_TAG, k as writeProvisionedWranglerConfig, l as ensureWranglerCompat, m as nextDurableObjectMigrationTag, o as acknowledgeWranglerManagedQueueRemovals, p as hasDurableObjectSqliteMigration, r as FRIENDLY_BINDING_NAMES, w as resolveLiveBindingConfig, x as readWranglerManagedQueueCleanupCandidates } from "./wrangler-BymcxrRa.mjs";
12
12
  import { i as voidWarn, r as voidLog } from "./log-ChfPKsVd.mjs";
13
- import { n as lintDuplicateSources, r as mergeRoutingRules, t as lintDestinationSplats } from "./headers-B_HBMgi0.mjs";
14
- import { a as scanQueuesSync, i as scanWebSocketRoutesSync, o as scanJobsSync, r as scanRoutes } from "./scan-DdDvRCU1.mjs";
15
- import { i as inferProjectBindings, n as FRAMEWORK_SCAN_DIRS, r as detectFramework } from "./plugin-inference-DsvtJLll.mjs";
16
- import { o as validateSsrEntry } from "./entry-DdRFGK0y.mjs";
17
- import { t as collectMigrations } from "./collect-DXHNWHcT.mjs";
13
+ import { n as lintDuplicateSources, r as mergeRoutingRules, t as lintDestinationSplats } from "./headers-BOg_velo.mjs";
14
+ import { n as isIdentifier, r as isLiteral } from "./ast-CPGPjb0V.mjs";
15
+ import { t as scanPages } from "./scan-4tfN-PSn.mjs";
16
+ import { a as scanJobsSync, i as scanQueuesSync, r as scanRoutes } from "./scan-ClYmX3sa.mjs";
17
+ import { i as inferProjectBindings, n as FRAMEWORK_SCAN_DIRS, r as detectFramework, s as scanWebSocketRoutesSync } from "./plugin-inference-BMfKRSqE.mjs";
18
+ import { t as collectMigrations } from "./collect-DiTn9yr6.mjs";
18
19
  import { r as buildMigrationPlanBundle } from "./plan-BEZ8VJW0.mjs";
19
20
  import { r as scanWranglerDotenvKeys } from "./dotenv-VQxupEUv.mjs";
20
- import { t as discoverSchema } from "./discover-C4O6YxVS.mjs";
21
- import { t as findEnvFile } from "./env-types-CWDtqHgw.mjs";
22
- import { d as formatEnvReport, f as listSelfHostSecretNames, g as validateProdEnv, h as selfHostSchemaFailureMessage, i as SelfHostSecretListError, l as dischargeSelfHostEnvContext, n as SelfHostFirstDeployError, p as readEmittedWorkerVars, r as SelfHostSchemaError, s as deriveSelfHostEnvContextFromVars, t as SelfHostEnvValidationError, u as fetchRemoteSecretNames, v as readGeneratedWranglerConfigFile } from "./env-validation-BsFEXps5.mjs";
23
- import { n as CLOUDFLARE_DEPLOY_BUILD_ENV, o as resolveRemoteMode, s as stripInternalEnvKeys } from "./env-DX_v-Q-v.mjs";
21
+ import { t as discoverSchema } from "./discover-BcPPiF1o.mjs";
22
+ import { t as MagicString } from "./dist-BR1quN_w.mjs";
23
+ import { t as findEnvFile } from "./env-types-C2_bIk_b.mjs";
24
+ import { d as formatEnvReport, f as listSelfHostSecretNames, g as validateProdEnv, h as selfHostSchemaFailureMessage, i as SelfHostSecretListError, l as dischargeSelfHostEnvContext, n as SelfHostFirstDeployError, p as readEmittedWorkerVars, r as SelfHostSchemaError, s as deriveSelfHostEnvContextFromVars, t as SelfHostEnvValidationError, u as fetchRemoteSecretNames, v as readGeneratedWranglerConfigFile } from "./env-validation-BB4GkLxn.mjs";
25
+ import { n as CLOUDFLARE_DEPLOY_BUILD_ENV, o as resolveRemoteMode, s as stripInternalEnvKeys } from "./env-_v349JBd.mjs";
26
+ import { o as validateSsrEntry } from "./entry-CF5wvH4w.mjs";
24
27
  import { E as confirm, I as select, N as note, O as intro, P as outro, W as isCancel, j as log$1 } from "./dist-Dn6nn2IU.mjs";
25
- import { t as writeDrizzleConfig } from "./config-BSe70f4T.mjs";
26
- import { i as runMySqlMigrations } from "./runner-mysql-BhwMk2Bm.mjs";
27
- import { i as runPgMigrations } from "./runner-pg-CJ_JeGF6.mjs";
28
+ import { t as writeDrizzleConfig } from "./config-D8MOgiQV.mjs";
29
+ import { i as runMySqlMigrations } from "./runner-mysql-DmWchSWJ.mjs";
30
+ import { i as runPgMigrations } from "./runner-pg-D4OPlil-.mjs";
28
31
  import { n as openMigrationValidationDatabase, t as SqliteMigrationError } from "./sqlite-validation-BzKMWnO4.mjs";
29
- import { i as validateMigrations, t as assertJournalCoherence } from "./validate-qNhV00PD.mjs";
30
- import { t as scanPages } from "./scan-DJbooZm2.mjs";
31
- import { t as renderPrerenderPaths } from "./prerender-render-Cf_WDE9W.mjs";
32
- import { a as scanEmailHandlersSync, r as hasEmailHandlers } from "./email-C5kaZXzJ.mjs";
33
- import { i as migrateBuiltWranglerConfig, n as prepareCfFrameworkBuildOutput, r as prepareCfStaticBuildOutput, t as prepareCfBuildOutput } from "./cf-build-output-CTdlo6Rt.mjs";
34
- import { n as getPackageDir } from "./agents-gni4eqBu.mjs";
35
- import { i as isExpiredTokenError, n as PlatformClient, o as parsePlatformErrorBody, r as isCliOutdatedError, s as platformErrorMessage, t as PlatformApiError } from "./client-PdAJ-F0t.mjs";
36
- import { a as resolveProjectCommand, i as hasBackendFiles, n as detectPreset, o as resolveWranglerArgv, r as formatProjectCommand, t as FRAMEWORK_PRESETS } from "./preset-Dowh9tTt.mjs";
37
- import { o as ensureCloudflareAuthentication, r as cloudflareAuthNeedsTerminal, t as CloudflareAuthenticationError } from "./cloudflare-auth-BCmTc1X_.mjs";
38
- import { n as writeVoidProjectConfig } from "./config-write-y3CBI_ux.mjs";
39
- import { r as discoverFrameworkWranglerFiles, t as migrateLegacyVoidConfig } from "./migrate-BV8qHiCb.mjs";
40
- import { a as createCloudflareEmptyDomainPublisher, i as createCloudflareEmptyCronPublisher } from "./cloudflare-operations-CPEdHYhM.mjs";
32
+ import { i as validateMigrations, t as assertJournalCoherence } from "./validate-CIUwFpjB.mjs";
33
+ import { t as renderPrerenderPaths } from "./prerender-render-D9qbLs2f.mjs";
34
+ import { a as scanEmailHandlersSync, r as hasEmailHandlers } from "./email--tEtMoj_.mjs";
35
+ import { i as migrateBuiltWranglerConfig, n as prepareCfFrameworkBuildOutput, r as prepareCfStaticBuildOutput, t as prepareCfBuildOutput } from "./cf-build-output-CGT03qCD.mjs";
36
+ import { n as getPackageDir } from "./agents-B_pX_HmQ.mjs";
37
+ import { i as isExpiredTokenError, n as PlatformClient, o as parsePlatformErrorBody, r as isCliOutdatedError, s as platformErrorMessage, t as PlatformApiError } from "./client-QTl6ko_D.mjs";
38
+ import { a as resolveProjectCommand, i as hasBackendFiles, n as detectPreset, o as resolveWranglerArgv, r as formatProjectCommand, t as FRAMEWORK_PRESETS } from "./preset-UHj9ARyP.mjs";
39
+ import { o as ensureCloudflareAuthentication, r as cloudflareAuthNeedsTerminal, t as CloudflareAuthenticationError } from "./cloudflare-auth-B9jPCkV2.mjs";
40
+ import { n as writeVoidProjectConfig } from "./config-write-BSduPMY8.mjs";
41
+ import { r as discoverFrameworkWranglerFiles, t as migrateLegacyVoidConfig } from "./migrate-B8KuoYsO.mjs";
42
+ import { a as createCloudflareEmptyDomainPublisher, i as createCloudflareEmptyCronPublisher } from "./cloudflare-operations-sMZXpk_S.mjs";
41
43
  import { t as formatCloudflareUserMessage } from "./cloudflare-user-output-Q-k0QoNQ.mjs";
42
- import { a as promptProjectSetupAction, i as promptProjectSelection, r as promptAndCreateProject } from "./create-project-BZBl_gQ0.mjs";
43
- import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-Xvis70DG.mjs";
44
+ import { a as promptProjectSetupAction, i as promptProjectSelection, r as promptAndCreateProject } from "./create-project-DBfFSZKY.mjs";
45
+ import { t as getRequestedProjectSlug } from "./resolve-project-BG5ORGID.mjs";
44
46
  import { t as collectGitDeployMetadata } from "./git-metadata-D-gurjzG.mjs";
45
- import { t as promptForLoginToken } from "./login-BgQJzxAl.mjs";
47
+ import { t as promptForLoginToken } from "./login-BQyISZuW.mjs";
46
48
  import { createRequire } from "node:module";
47
- import { copyFileSync, cpSync, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
49
+ import { copyFileSync, cpSync, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
48
50
  import { fileURLToPath } from "node:url";
49
51
  import { createDeployArtifact, createDeployUploadPayload } from "@void/deploy-core";
52
+ import { build, parseSync } from "vite";
50
53
  import { createHash, randomBytes } from "node:crypto";
51
54
  import { homedir, tmpdir } from "node:os";
52
55
  import { execFile, execSync, spawn, spawnSync } from "node:child_process";
53
56
  import { applyEdits, modify, parse } from "jsonc-parser";
54
57
  import { isDeepStrictEqual } from "node:util";
55
- import { build } from "vite";
56
58
  import { Minimatch } from "minimatch";
57
59
  import { activateCloudflareVersion, assertCloudflareBindingsPreserved, assertCloudflareDurableObjectLifecycleSupported, assertExistingCloudflareConfig, encodeCloudflareVersionMessage, extractWorkersDevSubdomain, normalizeWorkersDevSubdomain, parseRootWranglerConfig, parseRootWranglerConfig as parseRootWranglerConfig$1, readBindingFieldPresence, readCloudflareTriggerConfig, readConfigEntryString, readExistingCloudflareWorker, readStoredResourceName, readWranglerTopLevelString, renderCloudflareStaticEntry, resolveD1MigrateTarget, stageCloudflareStaticAssets, writeCloudflareFrameworkDeployConfig, writeCloudflareStaticDeployConfig } from "@void/deploy-cloudflare";
58
60
  import { getWorkerConfigPath, readBuildOutput } from "@cloudflare/build-output-utils";
@@ -1883,6 +1885,44 @@ function safePositional(value) {
1883
1885
  return code < 32 || code === 127;
1884
1886
  });
1885
1887
  }
1888
+ /** Pin opaque secrets to the live version in the private, disposable Build Output. */
1889
+ async function pinActiveWorkerSecrets(options) {
1890
+ const { activeVersionId, bindings, requiredNames, explicitNames = [] } = options;
1891
+ if (!/^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(activeVersionId)) return false;
1892
+ const secretNames = new Set(bindings.map((binding) => binding.name));
1893
+ const explicit = new Set(explicitNames);
1894
+ if (bindings.some((binding) => !safePositional(binding.name)) || secretNames.size !== bindings.length) return false;
1895
+ if (requiredNames.some((name) => !secretNames.has(name) && !explicit.has(name))) return false;
1896
+ const path = getWorkerConfigPath(options.output.directory);
1897
+ const worker = parseJson(readFileSync(path, "utf8"));
1898
+ if (!record(worker) || worker.env !== void 0 && !record(worker.env)) return false;
1899
+ const env = { ...worker.env ?? {} };
1900
+ for (const name of explicit) delete env[name];
1901
+ for (const [name, value] of Object.entries(env)) if (record(value) && (value.type === "secret" || value.type === "inherit" || value.type === "unsafe:inherit") && !secretNames.has(name) && !explicit.has(name)) return false;
1902
+ for (const { name } of bindings) {
1903
+ if (explicit.has(name)) continue;
1904
+ const current = env[name];
1905
+ if (current !== void 0 && (!record(current) || current.type !== "secret" && current.type !== "inherit" && current.type !== "unsafe:inherit")) return false;
1906
+ env[name] = {
1907
+ type: "unsafe:inherit",
1908
+ version_id: activeVersionId
1909
+ };
1910
+ }
1911
+ const unsafe = record(worker.unsafe) ? { ...worker.unsafe } : {};
1912
+ const metadata = record(unsafe.metadata) ? { ...unsafe.metadata } : {};
1913
+ if (metadata.bindings !== void 0) return false;
1914
+ if (metadata.keep_bindings !== void 0 && (!Array.isArray(metadata.keep_bindings) || !metadata.keep_bindings.every((type) => typeof type === "string"))) return false;
1915
+ metadata.keep_bindings = (metadata.keep_bindings ?? []).filter((type) => type !== "secret_text" && type !== "secret_key");
1916
+ unsafe.metadata = metadata;
1917
+ const next = {
1918
+ ...worker,
1919
+ env,
1920
+ unsafe
1921
+ };
1922
+ writeFileSync(path, JSON.stringify(next), { mode: 384 });
1923
+ await readBuildOutput(options.output.directory);
1924
+ return true;
1925
+ }
1886
1926
  /** Prevent cf's prebuilt uploader from creating a resource as a side effect. */
1887
1927
  function createCfResourceVerifier(options) {
1888
1928
  return async (directory) => {
@@ -2275,6 +2315,48 @@ function createCfVersionRunner(options) {
2275
2315
  };
2276
2316
  }
2277
2317
  //#endregion
2318
+ //#region src/cli/cloudflare-candidate.ts
2319
+ const CANDIDATE_FILE = ".void/cloudflare-candidate.json";
2320
+ /** A failed normal deploy keeps its locally verified upload chain across retries. */
2321
+ function readCloudflareCandidate(root) {
2322
+ const path = join(root, CANDIDATE_FILE);
2323
+ if (!existsSync(path)) return null;
2324
+ let value;
2325
+ try {
2326
+ value = JSON.parse(readFileSync(path, "utf8"));
2327
+ } catch {
2328
+ throw new Error("The saved Cloudflare candidate receipt is invalid. Restore or remove .void/cloudflare-candidate.json before retrying.");
2329
+ }
2330
+ if (typeof value !== "object" || value === null || Array.isArray(value) || !("accountId" in value) || typeof value.accountId !== "string" || !value.accountId || !("workerName" in value) || typeof value.workerName !== "string" || !value.workerName || !("parentVersionId" in value) || typeof value.parentVersionId !== "string" || !value.parentVersionId || !("versionIds" in value) || !Array.isArray(value.versionIds) || !value.versionIds.length || !value.versionIds.every((id) => typeof id === "string" && id.length > 0) || new Set(value.versionIds).size !== value.versionIds.length) throw new Error("The saved Cloudflare candidate receipt is invalid. Restore or remove .void/cloudflare-candidate.json before retrying.");
2331
+ return value;
2332
+ }
2333
+ function assertCloudflareCandidateUnchanged(root, expected) {
2334
+ if (JSON.stringify(readCloudflareCandidate(root)) !== JSON.stringify(expected)) throw new Error("The Cloudflare candidate receipt changed while project code was running. Retry from a trusted checkout.");
2335
+ }
2336
+ function recordCloudflareCandidateUpload(root, expected, accountId, workerName, parentVersionId, versionId) {
2337
+ assertCloudflareCandidateUnchanged(root, expected);
2338
+ if (expected && (expected.accountId !== accountId || expected.workerName !== workerName || expected.parentVersionId !== parentVersionId)) throw new Error("The saved Cloudflare candidate belongs to a different Worker or live version. Inspect the deployment before retrying.");
2339
+ const versionIds = [...expected?.versionIds ?? [], versionId];
2340
+ mkdirSync(join(root, ".void"), { recursive: true });
2341
+ const path = join(root, CANDIDATE_FILE);
2342
+ const temp = `${path}.${process.pid}.tmp`;
2343
+ try {
2344
+ writeFileSync(temp, `${JSON.stringify({
2345
+ accountId,
2346
+ workerName,
2347
+ parentVersionId,
2348
+ versionIds
2349
+ })}\n`, { mode: 384 });
2350
+ renameSync(temp, path);
2351
+ } finally {
2352
+ if (existsSync(temp)) unlinkSync(temp);
2353
+ }
2354
+ }
2355
+ function clearCloudflareCandidate(root) {
2356
+ const path = join(root, CANDIDATE_FILE);
2357
+ if (existsSync(path)) unlinkSync(path);
2358
+ }
2359
+ //#endregion
2278
2360
  //#region src/cli/cloudflare-deploy/classify.ts
2279
2361
  /**
2280
2362
  * Narrow native Cloudflare deploys to app shapes whose emitted Worker artifact
@@ -3837,6 +3919,69 @@ function __resolveQueueIndex(queueName) {
3837
3919
  }`;
3838
3920
  }
3839
3921
  //#endregion
3922
+ //#region src/cli/pg-bundle-transform.ts
3923
+ function nodes(root) {
3924
+ const found = [];
3925
+ const pending = [root];
3926
+ while (pending.length > 0) {
3927
+ const node = pending.pop();
3928
+ found.push(node);
3929
+ for (const value of Object.values(node)) if (Array.isArray(value)) {
3930
+ for (const child of value) if (child && typeof child === "object" && typeof child.type === "string") pending.push(child);
3931
+ } else if (value && typeof value === "object" && typeof value.type === "string") pending.push(value);
3932
+ }
3933
+ return found;
3934
+ }
3935
+ /** Rewrite the two CommonJS constructs emitted by the PG migration bundle. */
3936
+ function transformPgWorkerBundle(code, filename, requireShim) {
3937
+ if (!code.includes("createRequire") && !code.includes("pgpass")) return code;
3938
+ const program = parseSync(filename, code).program;
3939
+ const edits = [];
3940
+ let hasRequireBinding = false;
3941
+ let pgpassCalls = 0;
3942
+ for (const statement of program.body ?? []) {
3943
+ if (statement.type === "ImportDeclaration" && statement.source?.value === "node:module") {
3944
+ const specifiers = statement.specifiers;
3945
+ if (specifiers?.length !== 1 || !isIdentifier(specifiers[0]?.imported) || specifiers[0].imported.name !== "createRequire") throw new Error(`deploy: Unsupported node:module import in PostgreSQL bundle ${filename}.`);
3946
+ edits.push({
3947
+ start: statement.start,
3948
+ end: statement.end,
3949
+ replacement: ""
3950
+ });
3951
+ }
3952
+ if (statement.type === "VariableDeclaration") {
3953
+ const declarations = statement.declarations;
3954
+ if (declarations?.some((declaration) => isIdentifier(declaration.id) && declaration.id.name === "__require")) {
3955
+ if (declarations.length !== 1 || hasRequireBinding) throw new Error(`deploy: Unsupported require binding in PostgreSQL bundle ${filename}.`);
3956
+ hasRequireBinding = true;
3957
+ edits.push({
3958
+ start: statement.start,
3959
+ end: statement.end,
3960
+ replacement: requireShim
3961
+ });
3962
+ }
3963
+ }
3964
+ }
3965
+ for (const node of nodes(program)) {
3966
+ if (node.type !== "CallExpression" || !isIdentifier(node.callee) || node.callee.name !== "__require") continue;
3967
+ const args = node.arguments;
3968
+ if (args?.length !== 1 || !isLiteral(args[0]) || args[0].value !== "pgpass") continue;
3969
+ pgpassCalls++;
3970
+ edits.push({
3971
+ start: node.start,
3972
+ end: node.end,
3973
+ replacement: "__voidPgpassNoop"
3974
+ });
3975
+ }
3976
+ if (code.includes("createRequire") && !hasRequireBinding) throw new Error(`deploy: Could not locate the generated require binding in PostgreSQL bundle ${filename}.`);
3977
+ if (code.includes("pgpass") && pgpassCalls === 0 && code.includes("__require")) throw new Error(`deploy: Could not locate the pgpass require in PostgreSQL bundle ${filename}.`);
3978
+ const ms = new MagicString(code);
3979
+ for (const edit of edits.sort((a, b) => b.start - a.start)) ms.overwrite(edit.start, edit.end, edit.replacement);
3980
+ const transformed = ms.toString();
3981
+ if (transformed.includes("createRequire") || transformed.includes("__require(\"pgpass\")")) throw new Error(`deploy: PostgreSQL bundle ${filename} still contains an unsupported require.`);
3982
+ return pgpassCalls > 0 ? `const __voidPgpassNoop = Object.assign(function pgpass(_connectionInfo, callback) { callback(undefined); }, { warnTo() {} });\n${transformed}` : transformed;
3983
+ }
3984
+ //#endregion
3840
3985
  //#region src/cli/wrapper.ts
3841
3986
  const BUNDLED_ENTRY_RE = /^index\.(?:m?js|cjs)$/;
3842
3987
  const WRAPPER_MARKER = "// Generated by Void: deployment wrapper.";
@@ -3904,7 +4049,7 @@ async function generateWrapper(workerDir, workerMain, root, features) {
3904
4049
  let migrations;
3905
4050
  let migrationPlanBundle;
3906
4051
  if (features.hasMigrations) {
3907
- const { collectMigrations } = await import("./collect-DAUItMDS.mjs");
4052
+ const { collectMigrations } = await import("./collect-DLyFDiKW.mjs");
3908
4053
  const { buildMigrationPlanBundle } = await import("./plan-DpuOr14e.mjs");
3909
4054
  const migrationsDir = readProjectPaths(root).migrationsDir;
3910
4055
  migrations = collectMigrations(migrationsDir);
@@ -4017,11 +4162,9 @@ function patchPgWorkerBundle(outDir) {
4017
4162
  for (const file of readdirSync(outDir)) {
4018
4163
  if (!file.endsWith(".mjs") && !file.endsWith(".js")) continue;
4019
4164
  const path = join(outDir, file);
4020
- let code = readFileSync(path, "utf-8");
4021
- if (!code.includes("__require(\"pgpass\")") && !code.includes("createRequire(import.meta.url)")) continue;
4022
- code = code.replaceAll("__require(\"pgpass\")", "__voidPgpassNoop").replace("import { createRequire } from \"node:module\";", "").replace("var __require = /* @__PURE__ */ createRequire(import.meta.url);", pgWorkerRequireShim()).replace("var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();", pgWorkerRequireShim());
4023
- code = `const __voidPgpassNoop = Object.assign(function pgpass(_connectionInfo, callback) { callback(undefined); }, { warnTo() {} });\n` + code;
4024
- writeFileSync(path, code);
4165
+ const code = readFileSync(path, "utf-8");
4166
+ const transformed = transformPgWorkerBundle(code, file, pgWorkerRequireShim());
4167
+ if (transformed !== code) writeFileSync(path, transformed);
4025
4168
  }
4026
4169
  }
4027
4170
  function createPgPackageRequire(fromPath) {
@@ -4318,7 +4461,7 @@ let loadedProvisionModule;
4318
4461
  * so a managed deploy never imports it — and thus never loads `proper-lockfile`.
4319
4462
  */
4320
4463
  async function loadProvisionModule() {
4321
- loadedProvisionModule ??= await import("./provision-CNgEBkVA.mjs");
4464
+ loadedProvisionModule ??= await import("./provision-DNtrtaVD.mjs");
4322
4465
  return loadedProvisionModule;
4323
4466
  }
4324
4467
  /**
@@ -4884,6 +5027,47 @@ function reconstructExpectedContainers(config, root, rootConfig, needsSandbox) {
4884
5027
  }
4885
5028
  return expected;
4886
5029
  }
5030
+ /** Reconstruct the Durable Object state emitted after the pre-build root config is synced. */
5031
+ function reconstructExpectedDurableObjectState(config, root, rootConfig, options) {
5032
+ const bindings = bindingEntriesForField("durable_objects", rootConfig.durable_objects).map(({ entry }) => entry);
5033
+ const migrations = Array.isArray(rootConfig.migrations) ? [...rootConfig.migrations] : [];
5034
+ const sandbox = options.needsSandbox ? resolveSandboxConfig(config, root) : void 0;
5035
+ if (sandbox) {
5036
+ if (!bindings.some((binding) => binding.name === sandbox.binding)) bindings.push({
5037
+ name: sandbox.binding,
5038
+ class_name: sandbox.className
5039
+ });
5040
+ if (!migrations.some((migration) => migration.tag === "void-sandbox-v1" || Array.isArray(migration.new_sqlite_classes) && migration.new_sqlite_classes.includes(sandbox.className))) migrations.push({
5041
+ tag: SANDBOX_MIGRATION_TAG,
5042
+ new_sqlite_classes: [sandbox.className]
5043
+ });
5044
+ }
5045
+ const paths = resolveProjectPaths(root, config);
5046
+ const websocketRoutes = scanWebSocketRoutesSync(root, paths);
5047
+ const durableObjects = scanDurableObjectModules(root);
5048
+ const live = options.needsLive ? resolveLiveBindingConfig(root, {
5049
+ reservedBindings: [...websocketRoutes.map((route) => route.bindingName), ...durableObjects.map((module) => module.bindingName)],
5050
+ reservedClasses: [
5051
+ ...websocketRoutes.map((route) => route.className),
5052
+ ...durableObjects.map((module) => module.className),
5053
+ sandbox?.className
5054
+ ]
5055
+ }) : readExistingLiveBindingConfig(root);
5056
+ if (live) {
5057
+ if (!bindings.some((binding) => binding.name === live.bindingName)) bindings.push({
5058
+ name: live.bindingName,
5059
+ class_name: live.className
5060
+ });
5061
+ if (!hasDurableObjectSqliteMigration(migrations, live.className)) migrations.push({
5062
+ tag: nextDurableObjectMigrationTag(migrations, LIVE_MIGRATION_TAG),
5063
+ new_sqlite_classes: [live.className]
5064
+ });
5065
+ }
5066
+ return {
5067
+ bindings,
5068
+ migrations
5069
+ };
5070
+ }
4887
5071
  /**
4888
5072
  * Deterministic sha256 over the wrangler uploader BUNDLE the credentialed deploy executes — the
4889
5073
  * resolved `wrangler-dist/cli.js` PLUS every sibling file in its directory. `cli.js` loads sibling
@@ -4941,17 +5125,39 @@ function hashCfUploader() {
4941
5125
  function hashDirectoryContents(dir) {
4942
5126
  try {
4943
5127
  const hash = createHash("sha256");
5128
+ const visiting = /* @__PURE__ */ new Set();
4944
5129
  const walk = (rel) => {
4945
- const entries = readdirSync(join(dir, rel), { withFileTypes: true }).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
4946
- for (const entry of entries) {
4947
- const childRel = rel ? `${rel}/${entry.name}` : entry.name;
4948
- if (entry.isDirectory()) walk(childRel);
4949
- else {
5130
+ const real = realpathSync(join(dir, rel));
5131
+ if (visiting.has(real)) throw new Error(`Cyclic symlink in uploader: ${rel}`);
5132
+ visiting.add(real);
5133
+ try {
5134
+ const entries = readdirSync(join(dir, rel), { withFileTypes: true }).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
5135
+ for (const entry of entries) {
5136
+ const childRel = rel ? `${rel}/${entry.name}` : entry.name;
5137
+ const childPath = join(dir, childRel);
5138
+ if (entry.isDirectory()) {
5139
+ walk(childRel);
5140
+ continue;
5141
+ }
4950
5142
  hash.update(childRel);
4951
5143
  hash.update("\0");
4952
- hash.update(readFileSync(join(dir, childRel)));
5144
+ if (entry.isSymbolicLink()) {
5145
+ hash.update(readlinkSync(childPath));
5146
+ hash.update("\0");
5147
+ try {
5148
+ const target = statSync(childPath);
5149
+ if (target.isDirectory()) walk(childRel);
5150
+ else if (target.isFile()) hash.update(readFileSync(childPath));
5151
+ else throw new Error(`Unsupported uploader symlink target: ${childRel}`);
5152
+ } catch (error) {
5153
+ if (error.code !== "ENOENT") throw error;
5154
+ hash.update("missing");
5155
+ }
5156
+ } else hash.update(readFileSync(childPath));
4953
5157
  hash.update("\0");
4954
5158
  }
5159
+ } finally {
5160
+ visiting.delete(real);
4955
5161
  }
4956
5162
  };
4957
5163
  walk("");
@@ -5452,6 +5658,32 @@ function verifyGeneratedDeployConfig(root, expected) {
5452
5658
  const destructiveMigration = verifyNoInjectedDestructiveMigration(generated.migrations, raw.get("migrations"));
5453
5659
  if (!destructiveMigration.ok) return destructiveMigration;
5454
5660
  }
5661
+ if (expected.expectedDurableObjectBindings) {
5662
+ let emittedBindings;
5663
+ try {
5664
+ emittedBindings = bindingEntriesForField("durable_objects", generated.durable_objects).map(({ entry }) => entry);
5665
+ } catch {
5666
+ return {
5667
+ ok: false,
5668
+ reason: "generated config durable_objects bindings could not be verified."
5669
+ };
5670
+ }
5671
+ const byName = (left, right) => String(left.name).localeCompare(String(right.name));
5672
+ if (!deepEqual([...emittedBindings].sort(byName), [...expected.expectedDurableObjectBindings].sort(byName))) return {
5673
+ ok: false,
5674
+ reason: "generated config durable_objects bindings differ from the pre-build binding set — refusing to deploy a binding the build added, removed, or retargeted."
5675
+ };
5676
+ }
5677
+ if (expected.expectedMigrations) {
5678
+ if (generated.migrations !== void 0 && !Array.isArray(generated.migrations)) return {
5679
+ ok: false,
5680
+ reason: "generated config migrations could not be verified."
5681
+ };
5682
+ if (!deepEqual(Array.isArray(generated.migrations) ? generated.migrations : [], expected.expectedMigrations)) return {
5683
+ ok: false,
5684
+ reason: "generated config migrations differ from the pre-build migration sequence — refusing to deploy a migration the build added, removed, or retargeted."
5685
+ };
5686
+ }
5455
5687
  if (expected.expectedContainers) {
5456
5688
  const emittedContainers = Array.isArray(generated.containers) ? generated.containers : [];
5457
5689
  const expectedContainers = expected.expectedContainers;
@@ -5695,7 +5927,8 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
5695
5927
  const inferenceOptions = voidConfig.inference?.bindings ? { bindings: voidConfig.inference.bindings } : void 0;
5696
5928
  const bindings = inferProjectBindings(root, {
5697
5929
  ...inferenceOptions,
5698
- paths
5930
+ paths,
5931
+ environment: "prod"
5699
5932
  }, scanDirs);
5700
5933
  const authEnabled = bindings.needsAuth || findVoidAuthConfig(root, paths) !== null || voidConfig.auth !== void 0;
5701
5934
  const dialect = getDatabaseDialect(voidConfig);
@@ -5714,9 +5947,10 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
5714
5947
  const binding = bindingNames?.d1 ?? "DB";
5715
5948
  const storedName = readStoredResourceName(config, "d1_databases", binding, "database_name");
5716
5949
  const storedId = readStoredResourceName(config, "d1_databases", binding, "database_id");
5950
+ const authoredName = voidConfig.cloudflare?.d1_databases?.find((entry) => entry.binding === binding)?.database_name;
5717
5951
  desired.d1 = {
5718
5952
  binding,
5719
- name: storedName != null && isRealD1Id(storedId) ? storedName : suffixedResourceName(workerName, "db"),
5953
+ name: storedName != null && isRealD1Id(storedId) ? storedName : authoredName?.trim() || (basename(configPath) !== ".void-wrangler.jsonc" && storedName !== "default" ? storedName : void 0) || suffixedResourceName(workerName, "db"),
5720
5954
  migrationsDir: migrationsDirRelative
5721
5955
  };
5722
5956
  reasons.set(binding, databaseReason);
@@ -5732,9 +5966,10 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
5732
5966
  if (bindings.needsR2) {
5733
5967
  const binding = bindingNames?.r2 ?? "STORAGE";
5734
5968
  const storedName = readStoredResourceName(config, "r2_buckets", binding, "bucket_name");
5969
+ const generatedDefault = storedName === "default" && basename(configPath) === ".void-wrangler.jsonc" && !voidConfig.cloudflare?.r2_buckets?.some((entry) => entry.binding === binding && entry.bucket_name === "default");
5735
5970
  desired.r2 = {
5736
5971
  binding,
5737
- bucketName: storedName && storedName !== "default" ? storedName : suffixedResourceName(workerName, "storage")
5972
+ bucketName: storedName && !generatedDefault ? storedName : suffixedResourceName(workerName, "storage")
5738
5973
  };
5739
5974
  reasons.set(binding, "app uses env.STORAGE (R2)");
5740
5975
  }
@@ -5774,7 +6009,8 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
5774
6009
  expectedCrons,
5775
6010
  needsEmail: bindings.needsEmail === true || hasEmailHandlers(emailHandlers),
5776
6011
  emailHandlers,
5777
- needsSandbox: isSandboxEnabled(voidConfig) || bindings.needsSandbox
6012
+ needsSandbox: isSandboxEnabled(voidConfig) || bindings.needsSandbox,
6013
+ needsLive: bindings.needsLive === true
5778
6014
  };
5779
6015
  }
5780
6016
  /**
@@ -6481,56 +6717,8 @@ async function ensureCloudflareAuthSecret(options) {
6481
6717
  ...workerWasMissing ? { workerWasMissing: true } : {}
6482
6718
  };
6483
6719
  }
6484
- /**
6485
- * Deploy to the user's OWN Cloudflare account (no Void platform).
6486
- *
6487
- * Orchestrates the existing units — it does NOT re-implement provisioning
6488
- * (`cli/provision.ts`), the config writer (`cli/wrangler.ts`), or the self-host
6489
- * secret preflight (`cli/env-validation.ts`). Flow:
6490
- *
6491
- * app-class guard → desired set (from source, pre-build) → preflight (auth +
6492
- * account pin) → automatically ensure resources → ensure worker name →
6493
- * remote D1 migrate → secrets (warn + gate) → clean-env build → wrangler deploy
6494
- *
6495
- * ORDERING DECISION (documented): the secrets GATE runs AFTER provision + remote
6496
- * migrations resolve but BEFORE build + deploy — the brief's recommended default.
6497
- * Provision and D1 migrations are idempotent (read-first / tracked in wrangler's
6498
- * `d1_migrations` table), so re-running them after a gate failure is safe, while
6499
- * build + `wrangler deploy` (the non-idempotent worker upload) is what the gate
6500
- * protects. The warning is emitted first (non-fatal); a first-deploy secret-list
6501
- * failure (worker not yet created) renders actionable `wrangler secret put`
6502
- * bootstrap guidance rather than dead-ending.
6503
- *
6504
- * Every wrangler / provisioner / secret-unit call is an injected seam
6505
- * ({@link CloudflareDeployDeps}) so the whole orchestration is unit-testable with
6506
- * no real wrangler, network, or Cloudflare account.
6507
- */
6508
- async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6509
- const initialCloudflareLink = readCloudflareLink(root);
6510
- const exit = deps.exit ?? ((code) => process.exit(code));
6511
- const voidConfig = readConfig(root);
6512
- const detectedFramework = detectFramework(root);
6513
- const frameworkPreset = detectedFramework ? FRAMEWORK_PRESETS[detectedFramework.name] : void 0;
6514
- cliLog.info("cloudflare_deploy_start", { provision: options.provision === true ? true : void 0 });
6515
- if (isNodeTarget(voidConfig.target)) {
6516
- log.error([
6517
- `deploy: --platform cloudflare is not supported for the "${voidConfig.target}" target.`,
6518
- "This backend deploys Cloudflare Workers only. Deploy a node/bun/deno build with its",
6519
- "own host/runtime, or use the default Cloudflare target for --platform cloudflare."
6520
- ].join("\n"));
6521
- return exit(1);
6522
- }
6523
- if (detectedFramework?.class === "a" && hasConfiguredVoidWorkerRoutingRules(voidConfig.routing)) {
6524
- log.error([
6525
- `deploy: native Cloudflare deployment cannot apply Void routing redirects, rewrites, fallbacks, or headers to ${detectedFramework.name}.`,
6526
- "This framework owns its Worker request handler, so these rules would otherwise be ignored.",
6527
- "Move the rules into the framework or its Cloudflare Worker, then retry."
6528
- ].join("\n"));
6529
- return exit(1);
6530
- }
6531
- const provisionModule = await loadProvisionModule();
6532
- const staticPreset = resolveCloudflareStaticPreset(root, voidConfig, options) ?? await resolveCloudflareVoidStaticPreset(root, voidConfig);
6533
- if (staticPreset) return runCloudflareStaticDeploy(root, options, voidConfig, staticPreset, cliLog, deps, initialCloudflareLink);
6720
+ /** Validate source-level native deploy inputs before account operations or project code. */
6721
+ async function prepareCloudflareDeploySource(root, options, voidConfig) {
6534
6722
  if (options.skipBuild) {
6535
6723
  log.error([
6536
6724
  "deploy: --skip-build is not supported with --platform cloudflare.",
@@ -6540,15 +6728,16 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6540
6728
  "are about to upload. Drop --skip-build, or deploy with `void deploy` (the managed",
6541
6729
  "platform), which supports it."
6542
6730
  ].join("\n"));
6543
- return exit(1);
6731
+ return null;
6544
6732
  }
6545
6733
  const classification = classifyCloudflareDeployApp(root, voidConfig, options);
6546
6734
  if (!classification.supported) {
6547
6735
  log.error(classification.reason);
6548
- return exit(1);
6736
+ return null;
6549
6737
  }
6550
6738
  const configPath = discoverRootWranglerConfig(root);
6551
- const { desired, reasons, authEnabled, dialect, migrationsDir, migrations: preBuildMigrations, needsAI, aiBindingName, needsSandbox, expectedCrons, needsEmail, emailHandlers } = await computeDesiredCloudflareResources(root, voidConfig, configPath);
6739
+ const facts = await computeDesiredCloudflareResources(root, voidConfig, configPath);
6740
+ const { desired, dialect, migrations: preBuildMigrations, migrationsDir } = facts;
6552
6741
  if (dialect !== "sqlite" && preBuildMigrations.length > 0 && !process.env.DATABASE_URL) {
6553
6742
  log.error([
6554
6743
  `deploy: ${dialect === "mysql" ? "MySQL" : "PostgreSQL"} migrations require DATABASE_URL for --platform cloudflare.`,
@@ -6556,15 +6745,204 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6556
6745
  "provision Hyperdrive and apply checked-in migrations before uploading the Worker; it is",
6557
6746
  "never written to wrangler.jsonc or the generated Worker config."
6558
6747
  ].join("\n"));
6559
- return exit(1);
6748
+ return null;
6560
6749
  }
6561
6750
  if (desired.d1) {
6562
6751
  const migrationsPattern = resolveWranglerMigrationPattern(parseRootWranglerConfig(configPath), desired.d1.binding, desired.d1.migrationsDir ?? relative(dirname(configPath), migrationsDir));
6563
6752
  if (!migrationsPattern.ok) {
6564
6753
  log.error(migrationsPattern.reason);
6754
+ return null;
6755
+ }
6756
+ }
6757
+ return {
6758
+ configPath,
6759
+ ...facts
6760
+ };
6761
+ }
6762
+ /** Apply remote D1 changes and prove no migrations remain pending. */
6763
+ async function applyAndVerifyRemoteD1Migrations(d1MigrateToken, configPath, runWrangler, assertUploaderStillPinned) {
6764
+ if (d1MigrateToken) {
6765
+ log.step("Applying D1 migrations...");
6766
+ if (!assertUploaderStillPinned()) return false;
6767
+ const migrate = await Promise.resolve(runWrangler([
6768
+ "d1",
6769
+ "migrations",
6770
+ "apply",
6771
+ d1MigrateToken,
6772
+ "--remote",
6773
+ "-c",
6774
+ configPath,
6775
+ "--env="
6776
+ ], { capture: false }));
6777
+ if (!isCleanWranglerExit(migrate)) {
6778
+ log.error(`deploy: remote D1 migrations failed for "${d1MigrateToken}" (exit ${String(migrate.status)}). Fix the migration and rerun. Note: D1 always enforces foreign_keys=ON — a Drizzle table-rebuild using PRAGMA foreign_keys=OFF must use PRAGMA defer_foreign_keys instead.`);
6779
+ return false;
6780
+ }
6781
+ if (!assertUploaderStillPinned()) return false;
6782
+ const migrateList = await Promise.resolve(runWrangler([
6783
+ "d1",
6784
+ "migrations",
6785
+ "list",
6786
+ d1MigrateToken,
6787
+ "--remote",
6788
+ "-c",
6789
+ configPath,
6790
+ "--env="
6791
+ ], { capture: true }));
6792
+ if (!isCleanWranglerExit(migrateList)) {
6793
+ log.error(`deploy: could not verify the remote migration state for "${d1MigrateToken}" (\`d1 migrations list\` exit ${String(migrateList.status)}). Refusing to deploy against an unverified schema — rerun once wrangler can reach your account.`);
6794
+ return false;
6795
+ }
6796
+ if (migrateList.stdout.includes("Migrations to be applied:")) {
6797
+ log.error([
6798
+ `deploy: remote D1 still has UNAPPLIED migrations for "${d1MigrateToken}" after apply.`,
6799
+ "`wrangler d1 migrations apply` exits 0 even when its confirmation is declined, so",
6800
+ "the schema may be un-migrated while the code that needs it is about to deploy.",
6801
+ "Re-run and confirm the migration (or apply it non-interactively), then rerun."
6802
+ ].join("\n"));
6803
+ return false;
6804
+ }
6805
+ if (!migrateList.stdout.includes("No migrations to apply!")) {
6806
+ log.error([
6807
+ `deploy: could not confirm the remote migration state for "${d1MigrateToken}".`,
6808
+ "`wrangler d1 migrations list` printed neither the \"no migrations to apply\" nor the",
6809
+ "\"migrations to be applied\" marker (WRANGLER_LOG is pinned so they are never",
6810
+ "suppressed) — refusing to deploy against an unverified schema. Rerun once wrangler",
6811
+ "can reach your account."
6812
+ ].join("\n"));
6813
+ return false;
6814
+ }
6815
+ }
6816
+ return true;
6817
+ }
6818
+ /** Check the built Worker against the pinned deployment target before upload. */
6819
+ function verifyCloudflareDeployArtifact(root, deps, options) {
6820
+ const verification = (deps.verifyDeployConfig ?? verifyGeneratedDeployConfig)(root, options);
6821
+ if (!verification.ok) {
6822
+ log.error([
6823
+ "deploy: the generated deploy config does not match the pinned target — refusing to deploy.",
6824
+ verification.reason,
6825
+ "This typically means CLOUDFLARE_ENV / CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH (in the",
6826
+ "environment or a production `.env`) selected a different named environment or config",
6827
+ "at build time. This backend always deploys the canonical top-level config — remove",
6828
+ "them and rebuild."
6829
+ ].filter(Boolean).join("\n"));
6830
+ return false;
6831
+ }
6832
+ return true;
6833
+ }
6834
+ /** Validate emitted Worker vars and required secrets against post-build ground truth. */
6835
+ async function validateCloudflarePostBuildEnv(root, configPath, accountId, apiBaseUrl, workerName, schemaFacts, authEnabled, existingWorker, approvedHandoffKv, deps, assertUploaderStillPinned) {
6836
+ const emitted = (deps.readEmittedWorkerVars ?? readEmittedWorkerVarsDefault)(root);
6837
+ if (existingWorker) {
6838
+ const generated = readGeneratedDeployConfig(root);
6839
+ assertExistingCloudflareConfig(existingWorker, generated.config, true, approvedHandoffKv);
6840
+ }
6841
+ if (!emitted.ok) {
6842
+ log.error([
6843
+ "deploy: could not read the worker vars the build emitted — refusing to validate secrets.",
6844
+ ` ${emitted.reason}`,
6845
+ "The build must emit dist/ssr/wrangler.json for this backend. Rerun the build, or deploy",
6846
+ "this app with `void deploy` (the managed platform)."
6847
+ ].join("\n"));
6848
+ return false;
6849
+ }
6850
+ const emittedVars = emitted.vars;
6851
+ if (authEnabled && Object.prototype.hasOwnProperty.call(emittedVars, BETTER_AUTH_SECRET_NAME)) {
6852
+ log.error([
6853
+ `deploy: ${BETTER_AUTH_SECRET_NAME} must be stored as a Cloudflare Worker secret, not a plaintext worker var.`,
6854
+ "Remove it from Worker vars and rerun. This deploy command preserves an",
6855
+ "existing remote value or creates a persistent one automatically when it is missing."
6856
+ ].join("\n"));
6857
+ return false;
6858
+ }
6859
+ const plaintextServerKeys = schemaFacts.serverKeys.filter((key) => key in emittedVars);
6860
+ if (plaintextServerKeys.length > 0) {
6861
+ log.error([
6862
+ "deploy: server env keys cannot ship as plaintext Worker vars:",
6863
+ ...plaintextServerKeys.map((key) => ` • ${key}`),
6864
+ "Remove them from Worker vars and set them with `void secret put <NAME>`."
6865
+ ].join("\n"));
6866
+ return false;
6867
+ }
6868
+ const envContext = deriveSelfHostEnvContextFromVars(emittedVars, schemaFacts);
6869
+ if (schemaFacts.hasSchema) {
6870
+ let validateResult;
6871
+ try {
6872
+ validateResult = await (deps.validateEmittedVars ?? validateEmittedVarsDefault)({ root }, buildSchemaProbeEnv(accountId, apiBaseUrl));
6873
+ } catch (err) {
6874
+ log.error(`deploy: could not validate the emitted worker vars against the env schema — ${getErrorMessage(err)}`);
6875
+ return false;
6876
+ }
6877
+ if (validateResult.kind === "schema-error") {
6878
+ log.error(`deploy: ${selfHostSchemaFailureMessage(validateResult.reason)}`);
6879
+ return false;
6880
+ }
6881
+ envContext.invalidKeys = validateResult.invalidKeys;
6882
+ }
6883
+ if (authEnabled) {
6884
+ envContext.absentRequired = envContext.absentRequired.filter((key) => key !== BETTER_AUTH_SECRET_NAME);
6885
+ envContext.invalidKeys = envContext.invalidKeys.filter((key) => key !== BETTER_AUTH_SECRET_NAME);
6886
+ }
6887
+ if (!assertUploaderStillPinned()) return false;
6888
+ try {
6889
+ await (deps.dischargeSelfHostEnv ?? dischargeSelfHostEnvContext)(envContext, {
6890
+ root,
6891
+ configPath,
6892
+ accountId,
6893
+ workerName
6894
+ });
6895
+ } catch (err) {
6896
+ if (err instanceof SelfHostFirstDeployError || err instanceof SelfHostSecretListError || err instanceof SelfHostEnvValidationError || err instanceof SelfHostSchemaError) {
6897
+ log.error(err.message);
6898
+ return false;
6899
+ }
6900
+ throw err;
6901
+ }
6902
+ return true;
6903
+ }
6904
+ /** Deploy to the user's own Cloudflare account through the guarded native Worker flow. */
6905
+ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6906
+ const initialCloudflareLink = readCloudflareLink(root);
6907
+ const initialCloudflareCandidate = readCloudflareCandidate(root);
6908
+ const exit = deps.exit ?? ((code) => process.exit(code));
6909
+ const voidConfig = readConfig(root);
6910
+ const atomic = options.atomic === true || voidConfig.deploy?.cloudflare?.mode === "atomic";
6911
+ if (atomic && (options.reuseExistingWorker || initialCloudflareLink)) {
6912
+ log.error("deploy: atomic deployment is unavailable during the existing Worker handoff. Complete the handoff first.");
6913
+ return exit(1);
6914
+ }
6915
+ const detectedFramework = detectFramework(root);
6916
+ const frameworkPreset = detectedFramework ? FRAMEWORK_PRESETS[detectedFramework.name] : void 0;
6917
+ cliLog.info("cloudflare_deploy_start", { provision: options.provision === true ? true : void 0 });
6918
+ if (isNodeTarget(voidConfig.target)) {
6919
+ log.error([
6920
+ `deploy: --platform cloudflare is not supported for the "${voidConfig.target}" target.`,
6921
+ "This backend deploys Cloudflare Workers only. Deploy a node/bun/deno build with its",
6922
+ "own host/runtime, or use the default Cloudflare target for --platform cloudflare."
6923
+ ].join("\n"));
6924
+ return exit(1);
6925
+ }
6926
+ if (detectedFramework?.class === "a" && hasConfiguredVoidWorkerRoutingRules(voidConfig.routing)) {
6927
+ log.error([
6928
+ `deploy: native Cloudflare deployment cannot apply Void routing redirects, rewrites, fallbacks, or headers to ${detectedFramework.name}.`,
6929
+ "This framework owns its Worker request handler, so these rules would otherwise be ignored.",
6930
+ "Move the rules into the framework or its Cloudflare Worker, then retry."
6931
+ ].join("\n"));
6932
+ return exit(1);
6933
+ }
6934
+ const provisionModule = await loadProvisionModule();
6935
+ const staticPreset = resolveCloudflareStaticPreset(root, voidConfig, options) ?? await resolveCloudflareVoidStaticPreset(root, voidConfig);
6936
+ if (staticPreset) {
6937
+ if (atomic) {
6938
+ log.error("deploy: atomic deployment is only for Workers with Durable Objects.");
6565
6939
  return exit(1);
6566
6940
  }
6941
+ return runCloudflareStaticDeploy(root, options, voidConfig, staticPreset, cliLog, deps, initialCloudflareLink, initialCloudflareCandidate);
6567
6942
  }
6943
+ const source = await prepareCloudflareDeploySource(root, options, voidConfig);
6944
+ if (!source) return exit(1);
6945
+ const { configPath, desired, reasons, authEnabled, dialect, migrationsDir, migrations: preBuildMigrations, needsAI, aiBindingName, needsSandbox, needsLive, expectedCrons, needsEmail, emailHandlers } = source;
6568
6946
  let rootConfig = parseRootWranglerConfig(configPath);
6569
6947
  let apiBaseUrl;
6570
6948
  try {
@@ -6862,6 +7240,10 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6862
7240
  const passthroughIdentitySnapshot = snapshotPassthroughIdentities(preBuildRootConfig);
6863
7241
  const passthroughRawFields = snapshotPassthroughRawFields(preBuildRootConfig);
6864
7242
  const expectedContainers = reconstructExpectedContainers(voidConfig, root, preBuildRootConfig, needsSandbox);
7243
+ const expectedDurableObjectState = reconstructExpectedDurableObjectState(voidConfig, root, preBuildRootConfig, {
7244
+ needsSandbox,
7245
+ needsLive
7246
+ });
6865
7247
  removeDeployPointer(root);
6866
7248
  const buildChildEnv = scrubManagedDeployBuildMarkers(scrubWranglerAuthCredentials(deployChildEnv(accountId, apiBaseUrl)));
6867
7249
  requireProvisionModule().deleteEnvVarCaseAware(buildChildEnv, CLOUDFLARE_DEPLOY_BUILD_ENV);
@@ -6897,6 +7279,10 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6897
7279
  return exit(1);
6898
7280
  }
6899
7281
  const lifecycleConfigPath = (deps.resolveGeneratedConfigPath ?? ((projectRoot) => readGeneratedDeployConfig(projectRoot).path))(root);
7282
+ if (atomic && !Array.isArray(parseRootWranglerConfig(lifecycleConfigPath).migrations)) {
7283
+ log.error("deploy: atomic deployment is only for Workers with Durable Object migration history.");
7284
+ return exit(1);
7285
+ }
6900
7286
  try {
6901
7287
  deduplicateGeneratedCompatibilityFlags(lifecycleConfigPath, configPath);
6902
7288
  const lifecycleOptions = {
@@ -6906,77 +7292,15 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6906
7292
  accountId,
6907
7293
  apiBaseUrl
6908
7294
  };
6909
- await (deps.assertDurableObjectLifecycle ?? assertCloudflareDurableObjectLifecycleSupported)(lifecycleOptions);
7295
+ await (deps.assertDurableObjectLifecycle ?? assertCloudflareDurableObjectLifecycleSupported)({
7296
+ ...lifecycleOptions,
7297
+ allowPendingAtomicMigration: atomic
7298
+ });
6910
7299
  } catch (error) {
6911
7300
  log.error(getErrorMessage(error));
6912
7301
  return exit(1);
6913
7302
  }
6914
- const emitted = (deps.readEmittedWorkerVars ?? readEmittedWorkerVarsDefault)(root);
6915
- if (existingWorker) {
6916
- const generated = readGeneratedDeployConfig(root);
6917
- assertExistingCloudflareConfig(existingWorker, generated.config, true, approvedHandoffKv);
6918
- }
6919
- if (!emitted.ok) {
6920
- log.error([
6921
- "deploy: could not read the worker vars the build emitted — refusing to validate secrets.",
6922
- ` ${emitted.reason}`,
6923
- "The build must emit dist/ssr/wrangler.json for this backend. Rerun the build, or deploy",
6924
- "this app with `void deploy` (the managed platform)."
6925
- ].join("\n"));
6926
- return exit(1);
6927
- }
6928
- const emittedVars = emitted.vars;
6929
- if (authEnabled && Object.prototype.hasOwnProperty.call(emittedVars, BETTER_AUTH_SECRET_NAME)) {
6930
- log.error([
6931
- `deploy: ${BETTER_AUTH_SECRET_NAME} must be stored as a Cloudflare Worker secret, not a plaintext worker var.`,
6932
- "Remove it from Worker vars and rerun. This deploy command preserves an",
6933
- "existing remote value or creates a persistent one automatically when it is missing."
6934
- ].join("\n"));
6935
- return exit(1);
6936
- }
6937
- const plaintextServerKeys = schemaFacts.serverKeys.filter((key) => key in emittedVars);
6938
- if (plaintextServerKeys.length > 0) {
6939
- log.error([
6940
- "deploy: server env keys cannot ship as plaintext Worker vars:",
6941
- ...plaintextServerKeys.map((key) => ` • ${key}`),
6942
- "Remove them from Worker vars and set them with `void secret put <NAME>`."
6943
- ].join("\n"));
6944
- return exit(1);
6945
- }
6946
- const envContext = deriveSelfHostEnvContextFromVars(emittedVars, schemaFacts);
6947
- if (schemaFacts.hasSchema) {
6948
- let validateResult;
6949
- try {
6950
- validateResult = await (deps.validateEmittedVars ?? validateEmittedVarsDefault)({ root }, buildSchemaProbeEnv(accountId, apiBaseUrl));
6951
- } catch (err) {
6952
- log.error(`deploy: could not validate the emitted worker vars against the env schema — ${getErrorMessage(err)}`);
6953
- return exit(1);
6954
- }
6955
- if (validateResult.kind === "schema-error") {
6956
- log.error(`deploy: ${selfHostSchemaFailureMessage(validateResult.reason)}`);
6957
- return exit(1);
6958
- }
6959
- envContext.invalidKeys = validateResult.invalidKeys;
6960
- }
6961
- if (authEnabled) {
6962
- envContext.absentRequired = envContext.absentRequired.filter((key) => key !== BETTER_AUTH_SECRET_NAME);
6963
- envContext.invalidKeys = envContext.invalidKeys.filter((key) => key !== BETTER_AUTH_SECRET_NAME);
6964
- }
6965
- if (!assertUploaderStillPinned()) return exit(1);
6966
- try {
6967
- await (deps.dischargeSelfHostEnv ?? dischargeSelfHostEnvContext)(envContext, {
6968
- root,
6969
- configPath,
6970
- accountId,
6971
- workerName
6972
- });
6973
- } catch (err) {
6974
- if (err instanceof SelfHostFirstDeployError || err instanceof SelfHostSecretListError || err instanceof SelfHostEnvValidationError || err instanceof SelfHostSchemaError) {
6975
- log.error(err.message);
6976
- return exit(1);
6977
- }
6978
- throw err;
6979
- }
7303
+ if (!await validateCloudflarePostBuildEnv(root, configPath, accountId, apiBaseUrl, workerName, schemaFacts, authEnabled, existingWorker, approvedHandoffKv, deps, assertUploaderStillPinned)) return exit(1);
6980
7304
  if (authEnabled && dialect === "sqlite") try {
6981
7305
  await (deps.validateAuthMigrations ?? validateAuthMigrationSchema)(root, migrations);
6982
7306
  } catch (err) {
@@ -7071,6 +7395,8 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7071
7395
  aiBindingName,
7072
7396
  authEnabled,
7073
7397
  expectedContainers,
7398
+ expectedDurableObjectBindings: expectedDurableObjectState.bindings,
7399
+ expectedMigrations: expectedDurableObjectState.migrations,
7074
7400
  expectedCrons
7075
7401
  });
7076
7402
  if (!inheritance.ok) {
@@ -7128,59 +7454,8 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7128
7454
  return exit(1);
7129
7455
  }
7130
7456
  }
7131
- if (d1MigrateToken) {
7132
- log.step("Applying D1 migrations...");
7133
- if (!assertUploaderStillPinned()) return exit(1);
7134
- const migrate = await Promise.resolve(runWrangler([
7135
- "d1",
7136
- "migrations",
7137
- "apply",
7138
- d1MigrateToken,
7139
- "--remote",
7140
- "-c",
7141
- configPath,
7142
- "--env="
7143
- ], { capture: false }));
7144
- if (!isCleanWranglerExit(migrate)) {
7145
- log.error(`deploy: remote D1 migrations failed for "${d1MigrateToken}" (exit ${String(migrate.status)}). Fix the migration and rerun. Note: D1 always enforces foreign_keys=ON — a Drizzle table-rebuild using PRAGMA foreign_keys=OFF must use PRAGMA defer_foreign_keys instead.`);
7146
- return exit(1);
7147
- }
7148
- if (!assertUploaderStillPinned()) return exit(1);
7149
- const migrateList = await Promise.resolve(runWrangler([
7150
- "d1",
7151
- "migrations",
7152
- "list",
7153
- d1MigrateToken,
7154
- "--remote",
7155
- "-c",
7156
- configPath,
7157
- "--env="
7158
- ], { capture: true }));
7159
- if (!isCleanWranglerExit(migrateList)) {
7160
- log.error(`deploy: could not verify the remote migration state for "${d1MigrateToken}" (\`d1 migrations list\` exit ${String(migrateList.status)}). Refusing to deploy against an unverified schema — rerun once wrangler can reach your account.`);
7161
- return exit(1);
7162
- }
7163
- if (migrateList.stdout.includes("Migrations to be applied:")) {
7164
- log.error([
7165
- `deploy: remote D1 still has UNAPPLIED migrations for "${d1MigrateToken}" after apply.`,
7166
- "`wrangler d1 migrations apply` exits 0 even when its confirmation is declined, so",
7167
- "the schema may be un-migrated while the code that needs it is about to deploy.",
7168
- "Re-run and confirm the migration (or apply it non-interactively), then rerun."
7169
- ].join("\n"));
7170
- return exit(1);
7171
- }
7172
- if (!migrateList.stdout.includes("No migrations to apply!")) {
7173
- log.error([
7174
- `deploy: could not confirm the remote migration state for "${d1MigrateToken}".`,
7175
- "`wrangler d1 migrations list` printed neither the \"no migrations to apply\" nor the",
7176
- "\"migrations to be applied\" marker (WRANGLER_LOG is pinned so they are never",
7177
- "suppressed) — refusing to deploy against an unverified schema. Rerun once wrangler",
7178
- "can reach your account."
7179
- ].join("\n"));
7180
- return exit(1);
7181
- }
7182
- }
7183
- const verification = (deps.verifyDeployConfig ?? verifyGeneratedDeployConfig)(root, {
7457
+ if (!await applyAndVerifyRemoteD1Migrations(d1MigrateToken, configPath, runWrangler, assertUploaderStillPinned)) return exit(1);
7458
+ if (!verifyCloudflareDeployArtifact(root, deps, {
7184
7459
  accountId,
7185
7460
  workerName,
7186
7461
  desired,
@@ -7192,21 +7467,14 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7192
7467
  authEnabled,
7193
7468
  requiredSecretNames: schemaFacts.requiredKeys,
7194
7469
  expectedContainers,
7470
+ expectedDurableObjectBindings: expectedDurableObjectState.bindings,
7471
+ expectedMigrations: expectedDurableObjectState.migrations,
7195
7472
  expectedCrons
7196
- });
7197
- if (!verification.ok) {
7198
- log.error([
7199
- "deploy: the generated deploy config does not match the pinned target — refusing to deploy.",
7200
- verification.reason,
7201
- "This typically means CLOUDFLARE_ENV / CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH (in the",
7202
- "environment or a production `.env`) selected a different named environment or config",
7203
- "at build time. This backend always deploys the canonical top-level config — remove",
7204
- "them and rebuild."
7205
- ].filter(Boolean).join("\n"));
7206
- return exit(1);
7207
- }
7473
+ })) return exit(1);
7208
7474
  const queueConsumerCleanup = readWranglerManagedQueueCleanupCandidates(configPath);
7209
7475
  if (existingWorker) assertCloudflareLinkUnchanged(root, pinnedHandoffLink);
7476
+ assertCloudflareCandidateUnchanged(root, initialCloudflareCandidate);
7477
+ if (initialCloudflareCandidate && (initialCloudflareCandidate.accountId !== accountId || initialCloudflareCandidate.workerName !== workerName)) throw new Error("The saved Cloudflare candidate belongs to a different account or Worker. Inspect its receipt before retrying.");
7210
7478
  const candidateReceipt = pinnedHandoffLink?.candidateReceipt;
7211
7479
  if (!deps.activateVersion && !deps.runWrangler && !cfUploaderIsPinned()) return exit(1);
7212
7480
  const cfOutput = deps.activateVersion || deps.runWrangler ? null : await prepareBuildOutput();
@@ -7238,7 +7506,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7238
7506
  configPath: generatedConfigPath,
7239
7507
  preserveTriggers: existingWorker !== null,
7240
7508
  expectedPreviousVersionId: existingWorker?.versionId,
7241
- trustedInheritanceVersionIds: existingWorker && candidateReceipt?.parentVersionId === existingWorker.versionId ? candidateReceipt.versionIds : void 0,
7509
+ trustedInheritanceVersionIds: existingWorker ? candidateReceipt?.parentVersionId === existingWorker.versionId ? candidateReceipt.versionIds : void 0 : initialCloudflareCandidate?.versionIds,
7242
7510
  validateUploadedVersion: existingWorker ? async (versionId) => {
7243
7511
  if (!assertUploaderStillPinned()) throw new Error("The deployment uploader changed.");
7244
7512
  const uploaded = await (deps.readExistingWorker ?? readExistingCloudflareWorker)({
@@ -7249,7 +7517,9 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7249
7517
  });
7250
7518
  assertCloudflareBindingsPreserved(existingWorker, uploaded, approvedHandoffKv);
7251
7519
  } : void 0,
7252
- recordVerifiedCandidate: existingWorker ? (versionId) => recordCloudflareCandidate(root, pinnedHandoffLink, existingWorker.versionId, versionId) : void 0,
7520
+ recordVerifiedCandidate: existingWorker ? (versionId) => recordCloudflareCandidate(root, pinnedHandoffLink, existingWorker.versionId, versionId) : (versionId, parentVersionId) => {
7521
+ if (parentVersionId) recordCloudflareCandidateUpload(root, initialCloudflareCandidate, accountId, workerName, parentVersionId, versionId);
7522
+ },
7253
7523
  message: encodeCloudflareVersionMessage(migrations.map((migration) => migration.name), {
7254
7524
  ...readCloudflareTriggerConfig(generatedConfigPath, configPath),
7255
7525
  ...existingWorker ? { preserve: true } : {}
@@ -7275,12 +7545,22 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7275
7545
  previousTrafficConfig: readWranglerPublishedTrafficSnapshot(configPath),
7276
7546
  queueConsumerCleanup,
7277
7547
  verifyInheritedSecrets: true,
7548
+ ...cfOutput && existingWorker && !pinnedHandoffLink ? { pinActiveSecrets: (activeVersionId, bindings) => pinActiveWorkerSecrets({
7549
+ output: cfOutput,
7550
+ activeVersionId,
7551
+ bindings,
7552
+ requiredNames: schemaFacts.requiredKeys,
7553
+ ...initialAuthSecret ? { explicitNames: [BETTER_AUTH_SECRET_NAME] } : {}
7554
+ }) } : {},
7555
+ atomic,
7278
7556
  ...initialAuthSecret ? { candidateSecrets: { [BETTER_AUTH_SECRET_NAME]: initialAuthSecret } } : {}
7279
7557
  }).finally(() => cfOutput?.dispose());
7280
7558
  if (!execution.ok) {
7559
+ if (execution.reason === "atomic-readiness-failed" || execution.reason === "atomic-readiness-access-denied") clearCloudflareCandidate(root);
7281
7560
  await reportCloudflareActivationFailure(cliLog, needsSandbox && execution.containersUnavailable ? formatCloudflareSandboxUnavailable() : formatCloudflareActivationError(execution));
7282
7561
  return exit(1);
7283
7562
  }
7563
+ clearCloudflareCandidate(root);
7284
7564
  if (existingWorker) completeCloudflareLink(root);
7285
7565
  acknowledgeWranglerManagedQueueRemovals(configPath, queueConsumerCleanup);
7286
7566
  rememberCloudflareWorkersDevSubdomain(root, accountId, execution.previewUrl);
@@ -7319,12 +7599,16 @@ async function activateCloudflareVersionWithProgress(activate, options) {
7319
7599
  const progress = createSpinner();
7320
7600
  progress.start("Checking the current Worker deployment...");
7321
7601
  try {
7322
- return await activate({
7602
+ const result = await activate({
7323
7603
  ...options,
7324
7604
  onProgress: (message) => progress.message(message)
7325
7605
  });
7326
- } finally {
7327
- progress.stop();
7606
+ if (result.ok) progress.stop("Worker version is ready.");
7607
+ else progress.error("Worker deployment stopped.");
7608
+ return result;
7609
+ } catch (error) {
7610
+ progress.error("Worker deployment stopped.");
7611
+ throw error;
7328
7612
  }
7329
7613
  }
7330
7614
  function formatCloudflareActivationError(result) {
@@ -7342,9 +7626,8 @@ function formatCloudflareActivationError(result) {
7342
7626
  case "deployment-changed": return result.triggerRepair === "succeeded" ? `deploy: another Cloudflare operation superseded this deployment. Void restored triggers for the active version ${result.activeVersionId ?? "(unknown)"}; retry from fresh deployment status.` : `deploy: another Cloudflare operation superseded this deployment, but its trigger state could not be verified. Inspect the active Worker version ${result.activeVersionId ?? "(unknown)"} immediately.`;
7343
7627
  case "inheritance-source-unavailable": return "deploy: could not verify which Worker Version would supply inherited secrets; production traffic is unchanged.";
7344
7628
  case "inheritance-source-changed": return [
7345
- "deploy: the active Worker Version is not the latest upload, so inherited secrets cannot be pinned safely.",
7346
- "Supply explicit local values for every schema-marked text secret and retry. If the Worker has",
7347
- "non-text secret bindings, inspect its active and latest versions in Cloudflare before proceeding.",
7629
+ "deploy: the active Worker Version is not the latest upload, and its secrets could not be pinned safely.",
7630
+ "Inspect the active and latest Worker versions in Cloudflare before retrying.",
7348
7631
  "No version was uploaded; production traffic is unchanged."
7349
7632
  ].join("\n");
7350
7633
  case "traffic-preservation-unavailable": return ["deploy: the existing Worker has dashboard-managed routes or visibility that Void cannot safely republish.", "Add its current routes, workers_dev, and preview_urls values to the root Wrangler config, then retry; no version was uploaded."].join("\n");
@@ -7360,7 +7643,11 @@ function formatCloudflareActivationError(result) {
7360
7643
  "Set CLOUDFLARE_WORKERS_SUBDOMAIN to your account subdomain (for example \"my-team\")",
7361
7644
  "and retry. Void caches it after a successful workers.dev deployment; production traffic is unchanged."
7362
7645
  ].join("\n");
7363
- case "readiness-staging-failed": return `deploy: Cloudflare could not stage the uploaded Worker Version at zero-percent traffic${status}; production traffic is unchanged.`;
7646
+ case "readiness-staging-failed": return `deploy: Cloudflare could not stage the uploaded Worker Version at zero-percent traffic${status}; production traffic is unchanged.${cloudflareCode}${diagnostic}${result.cloudflareErrorCode === 10210 && /Durable Object migration/i.test(result.diagnostic ?? "") ? "\n\nReview the Durable Object migration, then run `void deploy --platform cloudflare --atomic`. For future deploys, set deploy.cloudflare.mode to \"atomic\" in void.config.ts." : ""}`;
7647
+ case "atomic-failed": return `deploy: Cloudflare could not publish the Worker atomically${status}; inspect production status before retrying.${cloudflareCode}${diagnostic}`;
7648
+ case "atomic-output-invalid": return "deploy: Cloudflare published atomically but did not report a version id or URL. Inspect `void project status` immediately.";
7649
+ case "atomic-readiness-failed":
7650
+ case "atomic-readiness-access-denied": return "deploy: the atomic Worker deployment is live, but /__void/ready could not be verified. Inspect `void project status` and Worker logs immediately.";
7364
7651
  case "readiness-failed": return ["deploy: the uploaded Worker Version did not pass /__void/ready.", formatCloudflareReadinessRestoration(result)].join("\n");
7365
7652
  case "readiness-access-denied": return [
7366
7653
  "deploy: Cloudflare Access blocked the uploaded Worker Version readiness probe.",
@@ -7491,7 +7778,10 @@ async function resolveCloudflareVoidStaticPreset(root, voidConfig) {
7491
7778
  paths
7492
7779
  });
7493
7780
  if (pageScan.pages.length === 0 || !pageScan.pages.every((page) => page.shouldPrerender && (page.params.length === 0 && !page.catchAll || page.hasGetPrerenderPaths))) return null;
7494
- const bindings = inferProjectBindings(root, { paths });
7781
+ const bindings = inferProjectBindings(root, {
7782
+ paths,
7783
+ environment: "prod"
7784
+ });
7495
7785
  const authEnabled = bindings.needsAuth || findVoidAuthConfig(root, paths) !== null || voidConfig.auth !== void 0;
7496
7786
  if (hasNonPageBackend({
7497
7787
  hasRoutes: routeScan.routes.length > 0,
@@ -7507,7 +7797,7 @@ async function resolveCloudflareVoidStaticPreset(root, voidConfig) {
7507
7797
  appType: "static"
7508
7798
  };
7509
7799
  }
7510
- async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliLog, deps, initialCloudflareLink) {
7800
+ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliLog, deps, initialCloudflareLink, initialCloudflareCandidate) {
7511
7801
  const exit = deps.exit ?? ((code) => process.exit(code));
7512
7802
  const configPath = discoverRootWranglerConfig(root);
7513
7803
  let rootConfig = parseRootWranglerConfig(configPath);
@@ -7657,6 +7947,8 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7657
7947
  });
7658
7948
  const queueConsumerCleanup = readWranglerManagedQueueCleanupCandidates(configPath);
7659
7949
  if (existingWorker) assertCloudflareLinkUnchanged(root, pinnedHandoffLink);
7950
+ assertCloudflareCandidateUnchanged(root, initialCloudflareCandidate);
7951
+ if (initialCloudflareCandidate && (initialCloudflareCandidate.accountId !== accountId || initialCloudflareCandidate.workerName !== workerName)) throw new Error("The saved Cloudflare candidate belongs to a different account or Worker. Inspect its receipt before retrying.");
7660
7952
  const candidateReceipt = pinnedHandoffLink?.candidateReceipt;
7661
7953
  if (!deps.activateVersion && !deps.runWrangler && !cfUploaderIsPinned()) return exit(1);
7662
7954
  const cfOutput = deps.activateVersion || deps.runWrangler ? null : await prepareCfStaticBuildOutput({
@@ -7692,7 +7984,7 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7692
7984
  configPath: staticConfigPath,
7693
7985
  preserveTriggers: existingWorker !== null,
7694
7986
  expectedPreviousVersionId: existingWorker?.versionId,
7695
- trustedInheritanceVersionIds: existingWorker && candidateReceipt?.parentVersionId === existingWorker.versionId ? candidateReceipt.versionIds : void 0,
7987
+ trustedInheritanceVersionIds: existingWorker ? candidateReceipt?.parentVersionId === existingWorker.versionId ? candidateReceipt.versionIds : void 0 : initialCloudflareCandidate?.versionIds,
7696
7988
  validateUploadedVersion: existingWorker ? async (versionId) => {
7697
7989
  if (!uploaderIsPinned()) throw new Error("The deployment uploader changed.");
7698
7990
  const uploaded = await (deps.readExistingWorker ?? readExistingCloudflareWorker)({
@@ -7703,7 +7995,9 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7703
7995
  });
7704
7996
  assertCloudflareBindingsPreserved(existingWorker, uploaded, [], { staticAssetsBinding: "ASSETS" });
7705
7997
  } : void 0,
7706
- recordVerifiedCandidate: existingWorker ? (versionId) => recordCloudflareCandidate(root, pinnedHandoffLink, existingWorker.versionId, versionId) : void 0,
7998
+ recordVerifiedCandidate: existingWorker ? (versionId) => recordCloudflareCandidate(root, pinnedHandoffLink, existingWorker.versionId, versionId) : (versionId, parentVersionId) => {
7999
+ if (parentVersionId) recordCloudflareCandidateUpload(root, initialCloudflareCandidate, accountId, workerName, parentVersionId, versionId);
8000
+ },
7707
8001
  workerName,
7708
8002
  message: encodeCloudflareVersionMessage([], {
7709
8003
  ...readCloudflareTriggerConfig(staticConfigPath, configPath),
@@ -7734,6 +8028,7 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7734
8028
  await reportCloudflareActivationFailure(cliLog, formatCloudflareActivationError(execution));
7735
8029
  return exit(1);
7736
8030
  }
8031
+ clearCloudflareCandidate(root);
7737
8032
  if (existingWorker) completeCloudflareLink(root);
7738
8033
  acknowledgeWranglerManagedQueueRemovals(configPath, queueConsumerCleanup);
7739
8034
  rememberCloudflareWorkersDevSubdomain(root, accountId, execution.previewUrl);
@@ -7828,6 +8123,7 @@ async function runDeployInner(root, options, cliLog) {
7828
8123
  reuseExistingWorker: true
7829
8124
  };
7830
8125
  const platform = resolveDeploymentPlatform(root, options);
8126
+ if (options?.atomic && platform !== "cloudflare") throw new Error("deploy: --atomic is available only for Cloudflare Workers.");
7831
8127
  if (platform === "none") throw new Error("deploy: deployment setup was skipped during `void init`. Pass `--platform cloudflare` or `--platform void` to choose a destination.");
7832
8128
  const targetLabel = platform === "cloudflare" ? "Cloudflare" : "Void";
7833
8129
  log.info(`Deployment target: ${targetLabel}`);
@@ -7863,11 +8159,16 @@ async function runManagedDeploy(root, options, cliLog) {
7863
8159
  cliLog
7864
8160
  });
7865
8161
  const requestedProjectSlug = getRequestedProjectSlug(options);
8162
+ const linkedProject = readProjectConfig(root);
7866
8163
  let config = null;
7867
8164
  if (requestedProjectSlug) {
7868
- const projects = await client.listProjects();
7869
- assertProjectDeployAccess(projects.find((project) => project.slug === requestedProjectSlug));
7870
- config = resolveProjectBySlug(projects, requestedProjectSlug);
8165
+ const linked = linkedProject?.slug === requestedProjectSlug ? await client.getProject(linkedProject.projectId) : null;
8166
+ const project = linked?.slug === requestedProjectSlug ? linked : await client.findProjectBySlug(requestedProjectSlug);
8167
+ assertProjectDeployAccess(project ?? void 0);
8168
+ config = project ? {
8169
+ projectId: project.id,
8170
+ slug: project.slug
8171
+ } : null;
7871
8172
  if (!config) {
7872
8173
  if (!process.stdin.isTTY) config = await createProjectFromSlug(root, client, requestedProjectSlug, cliLog);
7873
8174
  else {
@@ -7880,11 +8181,10 @@ async function runManagedDeploy(root, options, cliLog) {
7880
8181
  }
7881
8182
  }
7882
8183
  } else {
7883
- config = readProjectConfig(root);
8184
+ config = linkedProject;
7884
8185
  if (config) {
7885
- const projects = await client.listProjects();
7886
8186
  const { projectId, slug } = config;
7887
- const project = projects.find((project) => project.id === projectId);
8187
+ const project = await client.getProject(projectId);
7888
8188
  if (!project) throw new Error(`deploy: The linked project "${slug}" is unavailable or you no longer have access. Ask a project admin or owner to restore access, or choose another project with \`--project <slug>\`.`);
7889
8189
  assertProjectDeployAccess(project);
7890
8190
  }
@@ -7956,7 +8256,7 @@ function assertProjectDeployAccess(project) {
7956
8256
  if (project?.role === "reader") throw new Error(`deploy: You have reader access to "${project.slug}" and cannot deploy. Ask a project admin or owner to grant collaborator access, or choose another project with \`--project <slug>\`.`);
7957
8257
  }
7958
8258
  async function promptDeployProjectConfig(root, client, cliLog) {
7959
- const projects = await client.listProjects();
8259
+ const projects = await client.listProjectChoices();
7960
8260
  const deployableProjects = projects.filter((project) => project.role !== "reader");
7961
8261
  if (deployableProjects.length !== projects.length) log.warn("Projects with reader access are hidden from deploy selection. Ask a project admin or owner to grant collaborator access to deploy to them.");
7962
8262
  if (await promptProjectSetupAction("Set up a Void project for deploy:", { includeLink: deployableProjects.length > 0 }) === "create") return promptAndCreateProject(root, client);
@@ -8475,7 +8775,8 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
8475
8775
  const scanDirs = voidConfig.inference?.scanDirs ?? FRAMEWORK_SCAN_DIRS;
8476
8776
  const bindings = inferProjectBindings(root, {
8477
8777
  ...inferenceOptions,
8478
- paths
8778
+ paths,
8779
+ environment: "prod"
8479
8780
  }, scanDirs);
8480
8781
  if (bindings.needsAuth || findVoidAuthConfig(root, paths) !== null || voidConfig.auth !== void 0) {
8481
8782
  log.error("deploy: Void-managed Better Auth is only supported in Void apps. Use Better Auth's official integration for this framework instead.");
@@ -8696,7 +8997,10 @@ async function runFullDeploy(root, config, client, voidConfig, fwPreset, skipBui
8696
8997
  const paths = resolveProjectPaths(root, deployConfig);
8697
8998
  const dialect = getDatabaseDialect(deployConfig);
8698
8999
  const deployScanDirs = deployConfig.inference?.scanDirs ?? (isFrameworkMode ? FRAMEWORK_SCAN_DIRS : void 0);
8699
- const bindings = inferProjectBindings(root, { paths }, deployScanDirs);
9000
+ const bindings = inferProjectBindings(root, {
9001
+ paths,
9002
+ environment: "prod"
9003
+ }, deployScanDirs);
8700
9004
  if (isSandboxEnabled(deployConfig)) bindings.needsSandbox = true;
8701
9005
  const authEnabled = bindings.needsAuth || findVoidAuthConfig(root, paths) !== null || deployConfig.auth !== void 0;
8702
9006
  const effectiveBindings = authEnabled ? {
@@ -9202,4 +9506,4 @@ function resolveWorkerDirName(distDir, fwPreset, buildCommand) {
9202
9506
  throw new Error("deploy: Worker output not found. Expected dist/ssr/ or dist/rsc/.");
9203
9507
  }
9204
9508
  //#endregion
9205
- export { streamDeployEvents as $, parseRootWranglerConfig$1 as A, resolveDistDir as B, generateDeployWrapperIfNeeded as C, resolveAssetRoutingPolicy as Ct, hashWranglerUploader as D, hasPrerenderSources as E, resolveDeployLiveBindingConfig as F, resolveWranglerMigrationPattern as G, resolveStaticBuildCommand as H, resolveDeployTransport as I, runStaticDeploy as J, runCloudflareDeploy as K, resolveDeployWorkerMain as L, promptDeployProjectConfig as M, reconstructExpectedContainers as N, isWranglerNonInteractiveOrCI as O, resolveCloudflareVoidStaticPreset as P, snapshotPassthroughRawFields as Q, resolveDeployWranglerCompat as R, formatCloudflareSandboxUnavailable as S, resolveAssetConfig as St, hasNonPageBackend as T, resolveStaticDeployPreset as U, resolveFullDeployBuildCommand as V, resolveWorkerDirName as W, snapshotBindingIdentities as X, runWranglerAuthToken as Y, snapshotPassthroughIdentities as Z, deriveWorkerName as _, preflightEmail as _t, applyDeployEvent as a, generateQueueResolverSource as at, ensurePreviouslyDeployedLiveBindingConfig as b, hasApiRoutes as bt, assertMigrationsProduceAuthSchema as c, buildEnv as ct, assertWranglerUploaderUnchanged as d, hasRevalidate as dt, validateAuthMigrationSchema as et, checkWranglerMigrationApplySet as f, scanDurableObjectModules as ft, deployChildEnv as g, findEmailConfigConflicts as gt, createDeployWranglerRunner as h, createNodeEmailDns as ht, DEPLOY_WHOLE_OBJECT_PINNED_FIELDS as i, warnUnpublishedRouting as it, prepareCloudflareFrameworkArtifact as j, loadProvisionModule as k, assertNoConfigOverrideInProjectDotenv as l, collectPages as lt, computeDesiredCloudflareResources as m, applyEmailSetup as mt, DEPLOY_PASSTHROUGH_ASSERT_FIELDS as n, warnIgnoredNotFoundForFramework as nt, assembleVoidManifest as o, prerenderPages as ot, compareWranglerMigrationPaths as p, SEND_EMAIL_BINDING as pt, runDeploy as q, DEPLOY_PASSTHROUGH_EXCLUDE_FIELDS as r, warnRedundantForceOn3xx as rt, assertManagedDurableStateSupported as s, prerenderPagesNode as st, CloudflareAuthSecretError as t, verifyGeneratedDeployConfig as tt, assertRemoteMigrationsDeployable as u, collectRevalidate as ut, discoverRootWranglerConfig as v, renderAddressMap as vt, hasDeploySchemaDrift as w, formatCloudflareActivationError as x, hasDocumentRoutes as xt, ensureCloudflareAuthSecret as y, renderEmailChecklist as yt, resolveDeploymentPlatform as z };
9509
+ export { snapshotPassthroughRawFields as $, parseRootWranglerConfig$1 as A, resolveDeploymentPlatform as B, generateDeployWrapperIfNeeded as C, resolveAssetConfig as Ct, hashWranglerUploader as D, hasPrerenderSources as E, resolveCloudflareVoidStaticPreset as F, resolveWorkerDirName as G, resolveFullDeployBuildCommand as H, resolveDeployLiveBindingConfig as I, runDeploy as J, resolveWranglerMigrationPattern as K, resolveDeployTransport as L, promptDeployProjectConfig as M, reconstructExpectedContainers as N, isWranglerNonInteractiveOrCI as O, reconstructExpectedDurableObjectState as P, snapshotPassthroughIdentities as Q, resolveDeployWorkerMain as R, formatCloudflareSandboxUnavailable as S, hasDocumentRoutes as St, hasNonPageBackend as T, resolveStaticBuildCommand as U, resolveDistDir as V, resolveStaticDeployPreset as W, runWranglerAuthToken as X, runStaticDeploy as Y, snapshotBindingIdentities as Z, deriveWorkerName as _, findEmailConfigConflicts as _t, applyDeployEvent as a, warnUnpublishedRouting as at, ensurePreviouslyDeployedLiveBindingConfig as b, renderEmailChecklist as bt, assertMigrationsProduceAuthSchema as c, prerenderPagesNode as ct, assertWranglerUploaderUnchanged as d, collectRevalidate as dt, streamDeployEvents as et, checkWranglerMigrationApplySet as f, hasRevalidate as ft, deployChildEnv as g, createNodeEmailDns as gt, createDeployWranglerRunner as h, applyEmailSetup as ht, DEPLOY_WHOLE_OBJECT_PINNED_FIELDS as i, warnRedundantForceOn3xx as it, prepareCloudflareFrameworkArtifact as j, loadProvisionModule as k, assertNoConfigOverrideInProjectDotenv as l, buildEnv as lt, computeDesiredCloudflareResources as m, SEND_EMAIL_BINDING as mt, DEPLOY_PASSTHROUGH_ASSERT_FIELDS as n, verifyGeneratedDeployConfig as nt, assembleVoidManifest as o, generateQueueResolverSource as ot, compareWranglerMigrationPaths as p, scanDurableObjectModules as pt, runCloudflareDeploy as q, DEPLOY_PASSTHROUGH_EXCLUDE_FIELDS as r, warnIgnoredNotFoundForFramework as rt, assertManagedDurableStateSupported as s, prerenderPages as st, CloudflareAuthSecretError as t, validateAuthMigrationSchema as tt, assertRemoteMigrationsDeployable as u, collectPages as ut, discoverRootWranglerConfig as v, preflightEmail as vt, hasDeploySchemaDrift as w, resolveAssetRoutingPolicy as wt, formatCloudflareActivationError as x, hasApiRoutes as xt, ensureCloudflareAuthSecret as y, renderAddressMap as yt, resolveDeployWranglerCompat as z };