void 0.21.1 → 0.21.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/README.md +3 -2
  2. package/dist/{auth-cmd-g_ymMkUe.mjs → account-cmd-DGt9cpRe.mjs} +10 -10
  3. package/dist/{agents-gni4eqBu.mjs → agents-B_pX_HmQ.mjs} +1 -1
  4. package/dist/ast-CPGPjb0V.mjs +18 -0
  5. package/dist/{auth-CAw7zHqj.mjs → auth-CZuiVsFh.mjs} +1 -1
  6. package/dist/{auth-B9_D6ygs.mjs → auth-DLNN0D3Z.mjs} +4 -4
  7. package/dist/{auth-link-DFvxIyZi.mjs → auth-link-Cl9vOuf7.mjs} +5 -5
  8. package/dist/auth-router-D4ZcMUSf.mjs +74 -0
  9. package/dist/{better-auth-shared-BoVwA5Vm.d.mts → better-auth-shared-BVkjZ3vM.d.mts} +1 -0
  10. package/dist/{better-auth-shared-syGYYmnY.mjs → better-auth-shared-rsBGBvWJ.mjs} +3 -6
  11. package/dist/{build-cmd-wJAv808h.mjs → build-cmd-Dpt0jd-x.mjs} +5 -5
  12. package/dist/{cache-Be0Fu5Ka.mjs → cache-7_UeZdTk.mjs} +5 -5
  13. package/dist/{cancel-deploy-BgmyOwhe.mjs → cancel-deploy-D23R1RXT.mjs} +4 -4
  14. package/dist/{cf-access-rAZxzMkL.mjs → cf-access-P0iZnu0q.mjs} +1 -1
  15. package/dist/{cf-build-output-CTdlo6Rt.mjs → cf-build-output-CGT03qCD.mjs} +2 -2
  16. package/dist/cli/cf-compat.mjs +2 -2
  17. package/dist/cli/cli.mjs +122 -66
  18. package/dist/cli/env-schema-probe.mjs +3 -3
  19. package/dist/client-4cDVv7BO.mjs +2 -0
  20. package/dist/{client-PdAJ-F0t.mjs → client-QTl6ko_D.mjs} +28 -5
  21. package/dist/{cloudflare-auth-BCmTc1X_.mjs → cloudflare-auth-B9jPCkV2.mjs} +1 -1
  22. package/dist/{cloudflare-cmd-D6PrKn7o.mjs → cloudflare-cmd-BjNxR1XF.mjs} +3 -3
  23. package/dist/{cloudflare-connect-DloREDlc.mjs → cloudflare-connect-CCUozPOe.mjs} +3 -3
  24. package/dist/{cloudflare-operations-BHNJVDbN.mjs → cloudflare-operations-BipGMJ5O.mjs} +1 -1
  25. package/dist/{cloudflare-operations-CPEdHYhM.mjs → cloudflare-operations-sMZXpk_S.mjs} +4 -4
  26. package/dist/collect-DLyFDiKW.mjs +2 -0
  27. package/dist/{collect-DXHNWHcT.mjs → collect-DiTn9yr6.mjs} +1 -1
  28. package/dist/config-0acf1oys.mjs +2 -0
  29. package/dist/{config-DywxBLQC.d.mts → config-CF69HgXc.d.mts} +7 -0
  30. package/dist/{config-Dxr6cTXn.mjs → config-CafTW6Cz.mjs} +12 -1
  31. package/dist/{config-BSe70f4T.mjs → config-D8MOgiQV.mjs} +3 -3
  32. package/dist/config-DPByhVck.mjs +32 -0
  33. package/dist/config-entry.d.mts +1 -1
  34. package/dist/{config--T87TD8T.mjs → config-s7Xj7tPb.mjs} +1 -1
  35. package/dist/{config-write-y3CBI_ux.mjs → config-write-BSduPMY8.mjs} +3 -3
  36. package/dist/{connect-LnvW4HKx.mjs → connect-4Ph5Y0QE.mjs} +8 -8
  37. package/dist/{create-project-JV9-6ICF.mjs → create-project-BniEV0OW.mjs} +1 -1
  38. package/dist/{create-project-BZBl_gQ0.mjs → create-project-DBfFSZKY.mjs} +4 -4
  39. package/dist/{db-Mzv88E1C.mjs → db-DzJRn-qz.mjs} +128 -60
  40. package/dist/{delete-Ri6JemSU.mjs → delete-D6dZ9B6B.mjs} +5 -5
  41. package/dist/deploy-BH0grP4y.mjs +2 -0
  42. package/dist/{deploy-DEsMVrCY.mjs → deploy-CsMJrPfM.mjs} +522 -262
  43. package/dist/discover-AMCBXivQ.mjs +2 -0
  44. package/dist/{discover-C4O6YxVS.mjs → discover-BcPPiF1o.mjs} +2 -2
  45. package/dist/{dist-4WkAWhWx.mjs → dist-BVqXeR_h.mjs} +9 -1
  46. package/dist/dist-_UUlL6bg.mjs +2 -0
  47. package/dist/{domain-BA37Ye7T.mjs → domain-Dmhvb2oU.mjs} +5 -5
  48. package/dist/{email-C5kaZXzJ.mjs → email--tEtMoj_.mjs} +1 -1
  49. package/dist/{email-C5NsxrQG.mjs → email-BRKOG2RG.mjs} +10 -10
  50. package/dist/{entry-DdRFGK0y.mjs → entry-CF5wvH4w.mjs} +4 -21
  51. package/dist/{env-U_ohASB0.mjs → env-Csi-tMbT.mjs} +8 -8
  52. package/dist/{env-Yz4HcvHs.mjs → env-D5liuQYR.mjs} +5 -2
  53. package/dist/{env-DX_v-Q-v.mjs → env-_v349JBd.mjs} +1 -1
  54. package/dist/{env-types-CWDtqHgw.mjs → env-types-C2_bIk_b.mjs} +2 -2
  55. package/dist/{env-validation-BsFEXps5.mjs → env-validation-BB4GkLxn.mjs} +4 -4
  56. package/dist/{env-validation-DIDGM7h4.mjs → env-validation-BXge7uyK.mjs} +1 -1
  57. package/dist/{gen-pg-Ojg8Y.mjs → gen-Dz3X1Qab.mjs} +8 -8
  58. package/dist/gen-Vnv2f65C.mjs +2 -0
  59. package/dist/{generate-C0VY6RVf.mjs → generate-GDbL7sUr.mjs} +2 -2
  60. package/dist/{github-cmd-DsrkweIl.mjs → github-cmd-BED3_9JD.mjs} +7 -7
  61. package/dist/{headers-B_HBMgi0.mjs → headers-BOg_velo.mjs} +2 -2
  62. package/dist/{help-sBhFH6pi.mjs → help-DC7gdz7L.mjs} +46 -11
  63. package/dist/help-DQMfeKMz.mjs +2 -0
  64. package/dist/index.mjs +134 -160
  65. package/dist/{init-C--Yyj1b.mjs → init-CRGDXzVC.mjs} +105 -289
  66. package/dist/{link-BC-mNG9-.mjs → link-CsHOinF7.mjs} +6 -6
  67. package/dist/{list-DHU1Wj6c.mjs → list-CDb-4bZ1.mjs} +6 -6
  68. package/dist/{local-d1-DzykTWY8.mjs → local-d1-CC8sKFGu.mjs} +3 -3
  69. package/dist/{login-jKe_0QZL.mjs → login-BQyISZuW.mjs} +4 -4
  70. package/dist/login-r2gL8l7B.mjs +2 -0
  71. package/dist/{logs-BG11f5PR.mjs → logs-BdfiOezj.mjs} +5 -5
  72. package/dist/{migrate-BV8qHiCb.mjs → migrate-B8KuoYsO.mjs} +69 -44
  73. package/dist/migrate-TsHGBnDA.mjs +2 -0
  74. package/dist/{node-Cupyf7-s.mjs → node-BM43oz4G.mjs} +5 -5
  75. package/dist/{operator-auth-BkVgJqv-.mjs → operator-auth-8KnOVXVd.mjs} +2 -2
  76. package/dist/{operator-client-A0iex2yi.mjs → operator-client-DUwumHpQ.mjs} +2 -2
  77. package/dist/{operator-cmd-BwAS2XZt.mjs → operator-cmd-Co-PeaeD.mjs} +6 -6
  78. package/dist/{package-json-iCbMg5XF.mjs → package-json-DXfiT1jV.mjs} +1 -1
  79. package/dist/pages/index.d.mts +1 -1
  80. package/dist/pages/index.mjs +11 -6
  81. package/dist/pages/islands-plugin.d.mts +271 -1
  82. package/dist/pages/islands-plugin.mjs +95 -18
  83. package/dist/parse-filename-DioPHiR9.mjs +77 -0
  84. package/dist/{platform-auth-config-C-hv-_Ok.mjs → platform-auth-config-TSw8edHw.mjs} +5 -5
  85. package/dist/{platform-auth-protection-DjTE5Hj-.mjs → platform-auth-protection-Ba1XqGhn.mjs} +6 -6
  86. package/dist/{platform-auth-recovery-Cr0r8TEb.mjs → platform-auth-recovery-BkT3EsF2.mjs} +5 -5
  87. package/dist/{platform-cmd-DE6dw45v.mjs → platform-cmd-C8OqhqPt.mjs} +1 -1
  88. package/dist/{platform-cmd-0tEh2ZtA.mjs → platform-cmd-CRSKfu8k.mjs} +5 -5
  89. package/dist/{platform-domain-B_7x6Iqx.mjs → platform-domain-j9YCXRm6.mjs} +3 -3
  90. package/dist/{platform-lifecycle-Di0LbhPM.mjs → platform-lifecycle-78H0XQUA.mjs} +278 -230
  91. package/dist/{platform-lifecycle-Dhx9Pnub.mjs → platform-lifecycle-DDc9zCeJ.mjs} +1 -1
  92. package/dist/{platform-management-eaiaU3uM.mjs → platform-management-6w8-DUjC.mjs} +2 -2
  93. package/dist/{platform-management-B9LUtMt9.mjs → platform-management-DzKNsMlt.mjs} +1 -1
  94. package/dist/{platform-recovery-BxfA8E5C.mjs → platform-recovery-Do8VOyDE.mjs} +3 -3
  95. package/dist/{platform-registry-BJbgZLS1.mjs → platform-registry-QBa4DK32.mjs} +1 -1
  96. package/dist/{plugin-inference-DsvtJLll.mjs → plugin-inference-BMfKRSqE.mjs} +188 -85
  97. package/dist/prepare-BZXkjdNe.mjs +2 -0
  98. package/dist/{prepare-pcWcxSCh.mjs → prepare-C3kt3Rst.mjs} +11 -11
  99. package/dist/{prepare-_T-Haxrr.mjs → prepare-DyZ-Yok5.mjs} +1 -1
  100. package/dist/{prerender-render-Cf_WDE9W.mjs → prerender-render-D9qbLs2f.mjs} +1 -1
  101. package/dist/prerender-render.mjs +1 -1
  102. package/dist/{preset-Dowh9tTt.mjs → preset-UHj9ARyP.mjs} +4 -4
  103. package/dist/{project-BEBFDFLz.mjs → project-BuUwfj6f.mjs} +1 -1
  104. package/dist/{project-CWNIPoXc.mjs → project-C0Fqu05O.mjs} +2 -2
  105. package/dist/{project-cmd-DrnRJdep.mjs → project-cmd-B44I8J_W.mjs} +16 -16
  106. package/dist/{project-paths-CKQ-Q5JS.mjs → project-paths-GgcMozYz.mjs} +1 -1
  107. package/dist/{project-team-CzRbO_kA.mjs → project-team-BkbYIsXN.mjs} +6 -6
  108. package/dist/{project-token-Bwxjf4y6.mjs → project-token-C8xEEQnB.mjs} +4 -4
  109. package/dist/{project-tsconfig-CwfqUnVp.mjs → project-tsconfig-B8GeM0RM.mjs} +2 -2
  110. package/dist/{provision-Cck2m3jJ.mjs → provision-BhreDAOS.mjs} +141 -78
  111. package/dist/provision-DNtrtaVD.mjs +3 -0
  112. package/dist/{requests-DwrqUQZ8.mjs → requests-DFyhBMaf.mjs} +4 -4
  113. package/dist/{resolve-project-Xvis70DG.mjs → resolve-project-BG5ORGID.mjs} +1 -1
  114. package/dist/resolve-project-DtbidV4y.mjs +2 -0
  115. package/dist/{rollback-B4tFWmkN.mjs → rollback-DHHxXZiS.mjs} +5 -5
  116. package/dist/{route-types-Id82-veQ.mjs → route-types-Clm4WD0B.mjs} +39 -16
  117. package/dist/{runner-CQs_cDSG.mjs → runner-B8wXwWlo.mjs} +1 -1
  118. package/dist/{runner-mysql-1o47achK.mjs → runner-mysql-CEG5JozK.mjs} +1 -1
  119. package/dist/{runner-mysql-BhwMk2Bm.mjs → runner-mysql-DmWchSWJ.mjs} +1 -1
  120. package/dist/{runner-BGVsGgkb.mjs → runner-p-dMs2UN.mjs} +3 -3
  121. package/dist/{runner-pg-D7z01mQS.mjs → runner-pg-Bh4AgZdj.mjs} +1 -1
  122. package/dist/{runner-pg-CJ_JeGF6.mjs → runner-pg-D4OPlil-.mjs} +1 -1
  123. package/dist/runtime/better-auth-mysql.d.mts +1 -1
  124. package/dist/runtime/better-auth-mysql.mjs +1 -1
  125. package/dist/runtime/better-auth-pg.d.mts +1 -1
  126. package/dist/runtime/better-auth-pg.mjs +1 -1
  127. package/dist/runtime/better-auth.d.mts +1 -1
  128. package/dist/runtime/better-auth.mjs +2 -2
  129. package/dist/runtime/db.mjs +8 -5
  130. package/dist/runtime/durable.mjs +1 -1
  131. package/dist/runtime/email/testing.mjs +1 -1
  132. package/dist/runtime/env-public.mjs +1 -1
  133. package/dist/runtime/env.d.mts +1 -1
  134. package/dist/runtime/env.mjs +1 -1
  135. package/dist/runtime/kv.mjs +1 -1
  136. package/dist/runtime/live-server.mjs +38 -23
  137. package/dist/runtime/queues.mjs +1 -1
  138. package/dist/runtime/sandbox.mjs +1 -1
  139. package/dist/runtime/storage.mjs +1 -1
  140. package/dist/runtime/ws-server.d.mts +1 -1
  141. package/dist/runtime/ws-server.mjs +1 -1
  142. package/dist/{scan-DJbooZm2.mjs → scan-4tfN-PSn.mjs} +113 -99
  143. package/dist/{scan-DdDvRCU1.mjs → scan-ClYmX3sa.mjs} +35 -137
  144. package/dist/{secret-UtrRjhEO.mjs → secret-DN9sSNiV.mjs} +7 -7
  145. package/dist/{skills-B-690E7h.mjs → skills-O6FUaizK.mjs} +2 -2
  146. package/dist/sveltekit.mjs +1 -1
  147. package/dist/{validate-qNhV00PD.mjs → validate-CIUwFpjB.mjs} +2 -2
  148. package/dist/validate-EKmJWxmy.mjs +2 -0
  149. package/dist/{wrangler-D01qs6VB.mjs → wrangler-BymcxrRa.mjs} +3 -3
  150. package/dist/{yarn-pnp-CVEc3gE7.mjs → yarn-pnp-BV4AzNul.mjs} +1 -1
  151. package/package.json +7 -7
  152. package/schema.json +18 -0
  153. package/skills/migrate-vite-cloudflare-to-void/SKILL.md +1 -1
  154. package/skills/void/SKILL.md +4 -2
  155. package/skills/void/docs/guide/app-types.md +1 -1
  156. package/skills/void/docs/guide/auth.md +2 -2
  157. package/skills/void/docs/guide/database/d1.md +6 -0
  158. package/skills/void/docs/guide/durable-state.md +1 -1
  159. package/skills/void/docs/guide/edge/rewrites.md +2 -3
  160. package/skills/void/docs/guide/env-migration.md +1 -1
  161. package/skills/void/docs/guide/pages-routing/markdown.md +1 -1
  162. package/skills/void/docs/guide/platform/administration/access.md +1 -1
  163. package/skills/void/docs/guide/platform/development/local.md +1 -1
  164. package/skills/void/docs/guide/platform/installation/prerequisites.md +2 -2
  165. package/skills/void/docs/guide/platform/installation/setup.md +1 -1
  166. package/skills/void/docs/guide/project-collaboration.md +1 -1
  167. package/skills/void/docs/guide/server-routing.md +2 -3
  168. package/skills/void/docs/guide/ssr.md +4 -10
  169. package/skills/void/docs/guide/websockets.md +1 -1
  170. package/skills/void/docs/integrations/cloudflare.md +2 -0
  171. package/skills/void/docs/reference/api.md +1 -1
  172. package/skills/void/docs/reference/cli.md +34 -13
  173. package/skills/void/docs/reference/config.md +12 -1
  174. package/skills/void/docs/reference/resource-inference.md +1 -1
  175. package/dist/client-DAAivdid.mjs +0 -2
  176. package/dist/collect-DAUItMDS.mjs +0 -2
  177. package/dist/config-DDIFxQYx.mjs +0 -2
  178. package/dist/config-uP7ZDtVZ.mjs +0 -21
  179. package/dist/deploy-DAH2-m_-.mjs +0 -2
  180. package/dist/discover-BBzDZe_o.mjs +0 -2
  181. package/dist/dist-D7-nEOXi.mjs +0 -2
  182. package/dist/gen-B87rlalt.mjs +0 -2
  183. package/dist/help-B403BLBB.mjs +0 -2
  184. package/dist/login-BwiopVdg.mjs +0 -2
  185. package/dist/migrate-BXY3B3m7.mjs +0 -2
  186. package/dist/prepare-D4CkM3_v.mjs +0 -2
  187. package/dist/provision-CNgEBkVA.mjs +0 -3
  188. package/dist/resolve-project-BTotl8Nn.mjs +0 -2
  189. 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-jKe_0QZL.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";
@@ -2275,6 +2277,48 @@ function createCfVersionRunner(options) {
2275
2277
  };
2276
2278
  }
2277
2279
  //#endregion
2280
+ //#region src/cli/cloudflare-candidate.ts
2281
+ const CANDIDATE_FILE = ".void/cloudflare-candidate.json";
2282
+ /** A failed normal deploy keeps its locally verified upload chain across retries. */
2283
+ function readCloudflareCandidate(root) {
2284
+ const path = join(root, CANDIDATE_FILE);
2285
+ if (!existsSync(path)) return null;
2286
+ let value;
2287
+ try {
2288
+ value = JSON.parse(readFileSync(path, "utf8"));
2289
+ } catch {
2290
+ throw new Error("The saved Cloudflare candidate receipt is invalid. Restore or remove .void/cloudflare-candidate.json before retrying.");
2291
+ }
2292
+ 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.");
2293
+ return value;
2294
+ }
2295
+ function assertCloudflareCandidateUnchanged(root, expected) {
2296
+ 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.");
2297
+ }
2298
+ function recordCloudflareCandidateUpload(root, expected, accountId, workerName, parentVersionId, versionId) {
2299
+ assertCloudflareCandidateUnchanged(root, expected);
2300
+ 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.");
2301
+ const versionIds = [...expected?.versionIds ?? [], versionId];
2302
+ mkdirSync(join(root, ".void"), { recursive: true });
2303
+ const path = join(root, CANDIDATE_FILE);
2304
+ const temp = `${path}.${process.pid}.tmp`;
2305
+ try {
2306
+ writeFileSync(temp, `${JSON.stringify({
2307
+ accountId,
2308
+ workerName,
2309
+ parentVersionId,
2310
+ versionIds
2311
+ })}\n`, { mode: 384 });
2312
+ renameSync(temp, path);
2313
+ } finally {
2314
+ if (existsSync(temp)) unlinkSync(temp);
2315
+ }
2316
+ }
2317
+ function clearCloudflareCandidate(root) {
2318
+ const path = join(root, CANDIDATE_FILE);
2319
+ if (existsSync(path)) unlinkSync(path);
2320
+ }
2321
+ //#endregion
2278
2322
  //#region src/cli/cloudflare-deploy/classify.ts
2279
2323
  /**
2280
2324
  * Narrow native Cloudflare deploys to app shapes whose emitted Worker artifact
@@ -3837,6 +3881,69 @@ function __resolveQueueIndex(queueName) {
3837
3881
  }`;
3838
3882
  }
3839
3883
  //#endregion
3884
+ //#region src/cli/pg-bundle-transform.ts
3885
+ function nodes(root) {
3886
+ const found = [];
3887
+ const pending = [root];
3888
+ while (pending.length > 0) {
3889
+ const node = pending.pop();
3890
+ found.push(node);
3891
+ for (const value of Object.values(node)) if (Array.isArray(value)) {
3892
+ for (const child of value) if (child && typeof child === "object" && typeof child.type === "string") pending.push(child);
3893
+ } else if (value && typeof value === "object" && typeof value.type === "string") pending.push(value);
3894
+ }
3895
+ return found;
3896
+ }
3897
+ /** Rewrite the two CommonJS constructs emitted by the PG migration bundle. */
3898
+ function transformPgWorkerBundle(code, filename, requireShim) {
3899
+ if (!code.includes("createRequire") && !code.includes("pgpass")) return code;
3900
+ const program = parseSync(filename, code).program;
3901
+ const edits = [];
3902
+ let hasRequireBinding = false;
3903
+ let pgpassCalls = 0;
3904
+ for (const statement of program.body ?? []) {
3905
+ if (statement.type === "ImportDeclaration" && statement.source?.value === "node:module") {
3906
+ const specifiers = statement.specifiers;
3907
+ 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}.`);
3908
+ edits.push({
3909
+ start: statement.start,
3910
+ end: statement.end,
3911
+ replacement: ""
3912
+ });
3913
+ }
3914
+ if (statement.type === "VariableDeclaration") {
3915
+ const declarations = statement.declarations;
3916
+ if (declarations?.some((declaration) => isIdentifier(declaration.id) && declaration.id.name === "__require")) {
3917
+ if (declarations.length !== 1 || hasRequireBinding) throw new Error(`deploy: Unsupported require binding in PostgreSQL bundle ${filename}.`);
3918
+ hasRequireBinding = true;
3919
+ edits.push({
3920
+ start: statement.start,
3921
+ end: statement.end,
3922
+ replacement: requireShim
3923
+ });
3924
+ }
3925
+ }
3926
+ }
3927
+ for (const node of nodes(program)) {
3928
+ if (node.type !== "CallExpression" || !isIdentifier(node.callee) || node.callee.name !== "__require") continue;
3929
+ const args = node.arguments;
3930
+ if (args?.length !== 1 || !isLiteral(args[0]) || args[0].value !== "pgpass") continue;
3931
+ pgpassCalls++;
3932
+ edits.push({
3933
+ start: node.start,
3934
+ end: node.end,
3935
+ replacement: "__voidPgpassNoop"
3936
+ });
3937
+ }
3938
+ if (code.includes("createRequire") && !hasRequireBinding) throw new Error(`deploy: Could not locate the generated require binding in PostgreSQL bundle ${filename}.`);
3939
+ if (code.includes("pgpass") && pgpassCalls === 0 && code.includes("__require")) throw new Error(`deploy: Could not locate the pgpass require in PostgreSQL bundle ${filename}.`);
3940
+ const ms = new MagicString(code);
3941
+ for (const edit of edits.sort((a, b) => b.start - a.start)) ms.overwrite(edit.start, edit.end, edit.replacement);
3942
+ const transformed = ms.toString();
3943
+ if (transformed.includes("createRequire") || transformed.includes("__require(\"pgpass\")")) throw new Error(`deploy: PostgreSQL bundle ${filename} still contains an unsupported require.`);
3944
+ return pgpassCalls > 0 ? `const __voidPgpassNoop = Object.assign(function pgpass(_connectionInfo, callback) { callback(undefined); }, { warnTo() {} });\n${transformed}` : transformed;
3945
+ }
3946
+ //#endregion
3840
3947
  //#region src/cli/wrapper.ts
3841
3948
  const BUNDLED_ENTRY_RE = /^index\.(?:m?js|cjs)$/;
3842
3949
  const WRAPPER_MARKER = "// Generated by Void: deployment wrapper.";
@@ -3904,7 +4011,7 @@ async function generateWrapper(workerDir, workerMain, root, features) {
3904
4011
  let migrations;
3905
4012
  let migrationPlanBundle;
3906
4013
  if (features.hasMigrations) {
3907
- const { collectMigrations } = await import("./collect-DAUItMDS.mjs");
4014
+ const { collectMigrations } = await import("./collect-DLyFDiKW.mjs");
3908
4015
  const { buildMigrationPlanBundle } = await import("./plan-DpuOr14e.mjs");
3909
4016
  const migrationsDir = readProjectPaths(root).migrationsDir;
3910
4017
  migrations = collectMigrations(migrationsDir);
@@ -4017,11 +4124,9 @@ function patchPgWorkerBundle(outDir) {
4017
4124
  for (const file of readdirSync(outDir)) {
4018
4125
  if (!file.endsWith(".mjs") && !file.endsWith(".js")) continue;
4019
4126
  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);
4127
+ const code = readFileSync(path, "utf-8");
4128
+ const transformed = transformPgWorkerBundle(code, file, pgWorkerRequireShim());
4129
+ if (transformed !== code) writeFileSync(path, transformed);
4025
4130
  }
4026
4131
  }
4027
4132
  function createPgPackageRequire(fromPath) {
@@ -4318,7 +4423,7 @@ let loadedProvisionModule;
4318
4423
  * so a managed deploy never imports it — and thus never loads `proper-lockfile`.
4319
4424
  */
4320
4425
  async function loadProvisionModule() {
4321
- loadedProvisionModule ??= await import("./provision-CNgEBkVA.mjs");
4426
+ loadedProvisionModule ??= await import("./provision-DNtrtaVD.mjs");
4322
4427
  return loadedProvisionModule;
4323
4428
  }
4324
4429
  /**
@@ -4884,6 +4989,47 @@ function reconstructExpectedContainers(config, root, rootConfig, needsSandbox) {
4884
4989
  }
4885
4990
  return expected;
4886
4991
  }
4992
+ /** Reconstruct the Durable Object state emitted after the pre-build root config is synced. */
4993
+ function reconstructExpectedDurableObjectState(config, root, rootConfig, options) {
4994
+ const bindings = bindingEntriesForField("durable_objects", rootConfig.durable_objects).map(({ entry }) => entry);
4995
+ const migrations = Array.isArray(rootConfig.migrations) ? [...rootConfig.migrations] : [];
4996
+ const sandbox = options.needsSandbox ? resolveSandboxConfig(config, root) : void 0;
4997
+ if (sandbox) {
4998
+ if (!bindings.some((binding) => binding.name === sandbox.binding)) bindings.push({
4999
+ name: sandbox.binding,
5000
+ class_name: sandbox.className
5001
+ });
5002
+ if (!migrations.some((migration) => migration.tag === "void-sandbox-v1" || Array.isArray(migration.new_sqlite_classes) && migration.new_sqlite_classes.includes(sandbox.className))) migrations.push({
5003
+ tag: SANDBOX_MIGRATION_TAG,
5004
+ new_sqlite_classes: [sandbox.className]
5005
+ });
5006
+ }
5007
+ const paths = resolveProjectPaths(root, config);
5008
+ const websocketRoutes = scanWebSocketRoutesSync(root, paths);
5009
+ const durableObjects = scanDurableObjectModules(root);
5010
+ const live = options.needsLive ? resolveLiveBindingConfig(root, {
5011
+ reservedBindings: [...websocketRoutes.map((route) => route.bindingName), ...durableObjects.map((module) => module.bindingName)],
5012
+ reservedClasses: [
5013
+ ...websocketRoutes.map((route) => route.className),
5014
+ ...durableObjects.map((module) => module.className),
5015
+ sandbox?.className
5016
+ ]
5017
+ }) : readExistingLiveBindingConfig(root);
5018
+ if (live) {
5019
+ if (!bindings.some((binding) => binding.name === live.bindingName)) bindings.push({
5020
+ name: live.bindingName,
5021
+ class_name: live.className
5022
+ });
5023
+ if (!hasDurableObjectSqliteMigration(migrations, live.className)) migrations.push({
5024
+ tag: nextDurableObjectMigrationTag(migrations, LIVE_MIGRATION_TAG),
5025
+ new_sqlite_classes: [live.className]
5026
+ });
5027
+ }
5028
+ return {
5029
+ bindings,
5030
+ migrations
5031
+ };
5032
+ }
4887
5033
  /**
4888
5034
  * Deterministic sha256 over the wrangler uploader BUNDLE the credentialed deploy executes — the
4889
5035
  * resolved `wrangler-dist/cli.js` PLUS every sibling file in its directory. `cli.js` loads sibling
@@ -4941,17 +5087,39 @@ function hashCfUploader() {
4941
5087
  function hashDirectoryContents(dir) {
4942
5088
  try {
4943
5089
  const hash = createHash("sha256");
5090
+ const visiting = /* @__PURE__ */ new Set();
4944
5091
  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 {
5092
+ const real = realpathSync(join(dir, rel));
5093
+ if (visiting.has(real)) throw new Error(`Cyclic symlink in uploader: ${rel}`);
5094
+ visiting.add(real);
5095
+ try {
5096
+ const entries = readdirSync(join(dir, rel), { withFileTypes: true }).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
5097
+ for (const entry of entries) {
5098
+ const childRel = rel ? `${rel}/${entry.name}` : entry.name;
5099
+ const childPath = join(dir, childRel);
5100
+ if (entry.isDirectory()) {
5101
+ walk(childRel);
5102
+ continue;
5103
+ }
4950
5104
  hash.update(childRel);
4951
5105
  hash.update("\0");
4952
- hash.update(readFileSync(join(dir, childRel)));
5106
+ if (entry.isSymbolicLink()) {
5107
+ hash.update(readlinkSync(childPath));
5108
+ hash.update("\0");
5109
+ try {
5110
+ const target = statSync(childPath);
5111
+ if (target.isDirectory()) walk(childRel);
5112
+ else if (target.isFile()) hash.update(readFileSync(childPath));
5113
+ else throw new Error(`Unsupported uploader symlink target: ${childRel}`);
5114
+ } catch (error) {
5115
+ if (error.code !== "ENOENT") throw error;
5116
+ hash.update("missing");
5117
+ }
5118
+ } else hash.update(readFileSync(childPath));
4953
5119
  hash.update("\0");
4954
5120
  }
5121
+ } finally {
5122
+ visiting.delete(real);
4955
5123
  }
4956
5124
  };
4957
5125
  walk("");
@@ -5452,6 +5620,32 @@ function verifyGeneratedDeployConfig(root, expected) {
5452
5620
  const destructiveMigration = verifyNoInjectedDestructiveMigration(generated.migrations, raw.get("migrations"));
5453
5621
  if (!destructiveMigration.ok) return destructiveMigration;
5454
5622
  }
5623
+ if (expected.expectedDurableObjectBindings) {
5624
+ let emittedBindings;
5625
+ try {
5626
+ emittedBindings = bindingEntriesForField("durable_objects", generated.durable_objects).map(({ entry }) => entry);
5627
+ } catch {
5628
+ return {
5629
+ ok: false,
5630
+ reason: "generated config durable_objects bindings could not be verified."
5631
+ };
5632
+ }
5633
+ const byName = (left, right) => String(left.name).localeCompare(String(right.name));
5634
+ if (!deepEqual([...emittedBindings].sort(byName), [...expected.expectedDurableObjectBindings].sort(byName))) return {
5635
+ ok: false,
5636
+ reason: "generated config durable_objects bindings differ from the pre-build binding set — refusing to deploy a binding the build added, removed, or retargeted."
5637
+ };
5638
+ }
5639
+ if (expected.expectedMigrations) {
5640
+ if (generated.migrations !== void 0 && !Array.isArray(generated.migrations)) return {
5641
+ ok: false,
5642
+ reason: "generated config migrations could not be verified."
5643
+ };
5644
+ if (!deepEqual(Array.isArray(generated.migrations) ? generated.migrations : [], expected.expectedMigrations)) return {
5645
+ ok: false,
5646
+ reason: "generated config migrations differ from the pre-build migration sequence — refusing to deploy a migration the build added, removed, or retargeted."
5647
+ };
5648
+ }
5455
5649
  if (expected.expectedContainers) {
5456
5650
  const emittedContainers = Array.isArray(generated.containers) ? generated.containers : [];
5457
5651
  const expectedContainers = expected.expectedContainers;
@@ -5695,7 +5889,8 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
5695
5889
  const inferenceOptions = voidConfig.inference?.bindings ? { bindings: voidConfig.inference.bindings } : void 0;
5696
5890
  const bindings = inferProjectBindings(root, {
5697
5891
  ...inferenceOptions,
5698
- paths
5892
+ paths,
5893
+ environment: "prod"
5699
5894
  }, scanDirs);
5700
5895
  const authEnabled = bindings.needsAuth || findVoidAuthConfig(root, paths) !== null || voidConfig.auth !== void 0;
5701
5896
  const dialect = getDatabaseDialect(voidConfig);
@@ -5714,9 +5909,10 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
5714
5909
  const binding = bindingNames?.d1 ?? "DB";
5715
5910
  const storedName = readStoredResourceName(config, "d1_databases", binding, "database_name");
5716
5911
  const storedId = readStoredResourceName(config, "d1_databases", binding, "database_id");
5912
+ const authoredName = voidConfig.cloudflare?.d1_databases?.find((entry) => entry.binding === binding)?.database_name;
5717
5913
  desired.d1 = {
5718
5914
  binding,
5719
- name: storedName != null && isRealD1Id(storedId) ? storedName : suffixedResourceName(workerName, "db"),
5915
+ name: storedName != null && isRealD1Id(storedId) ? storedName : authoredName?.trim() || (basename(configPath) !== ".void-wrangler.jsonc" && storedName !== "default" ? storedName : void 0) || suffixedResourceName(workerName, "db"),
5720
5916
  migrationsDir: migrationsDirRelative
5721
5917
  };
5722
5918
  reasons.set(binding, databaseReason);
@@ -5732,9 +5928,10 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
5732
5928
  if (bindings.needsR2) {
5733
5929
  const binding = bindingNames?.r2 ?? "STORAGE";
5734
5930
  const storedName = readStoredResourceName(config, "r2_buckets", binding, "bucket_name");
5931
+ const generatedDefault = storedName === "default" && basename(configPath) === ".void-wrangler.jsonc" && !voidConfig.cloudflare?.r2_buckets?.some((entry) => entry.binding === binding && entry.bucket_name === "default");
5735
5932
  desired.r2 = {
5736
5933
  binding,
5737
- bucketName: storedName && storedName !== "default" ? storedName : suffixedResourceName(workerName, "storage")
5934
+ bucketName: storedName && !generatedDefault ? storedName : suffixedResourceName(workerName, "storage")
5738
5935
  };
5739
5936
  reasons.set(binding, "app uses env.STORAGE (R2)");
5740
5937
  }
@@ -5774,7 +5971,8 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
5774
5971
  expectedCrons,
5775
5972
  needsEmail: bindings.needsEmail === true || hasEmailHandlers(emailHandlers),
5776
5973
  emailHandlers,
5777
- needsSandbox: isSandboxEnabled(voidConfig) || bindings.needsSandbox
5974
+ needsSandbox: isSandboxEnabled(voidConfig) || bindings.needsSandbox,
5975
+ needsLive: bindings.needsLive === true
5778
5976
  };
5779
5977
  }
5780
5978
  /**
@@ -6481,56 +6679,8 @@ async function ensureCloudflareAuthSecret(options) {
6481
6679
  ...workerWasMissing ? { workerWasMissing: true } : {}
6482
6680
  };
6483
6681
  }
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);
6682
+ /** Validate source-level native deploy inputs before account operations or project code. */
6683
+ async function prepareCloudflareDeploySource(root, options, voidConfig) {
6534
6684
  if (options.skipBuild) {
6535
6685
  log.error([
6536
6686
  "deploy: --skip-build is not supported with --platform cloudflare.",
@@ -6540,15 +6690,16 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6540
6690
  "are about to upload. Drop --skip-build, or deploy with `void deploy` (the managed",
6541
6691
  "platform), which supports it."
6542
6692
  ].join("\n"));
6543
- return exit(1);
6693
+ return null;
6544
6694
  }
6545
6695
  const classification = classifyCloudflareDeployApp(root, voidConfig, options);
6546
6696
  if (!classification.supported) {
6547
6697
  log.error(classification.reason);
6548
- return exit(1);
6698
+ return null;
6549
6699
  }
6550
6700
  const configPath = discoverRootWranglerConfig(root);
6551
- const { desired, reasons, authEnabled, dialect, migrationsDir, migrations: preBuildMigrations, needsAI, aiBindingName, needsSandbox, expectedCrons, needsEmail, emailHandlers } = await computeDesiredCloudflareResources(root, voidConfig, configPath);
6701
+ const facts = await computeDesiredCloudflareResources(root, voidConfig, configPath);
6702
+ const { desired, dialect, migrations: preBuildMigrations, migrationsDir } = facts;
6552
6703
  if (dialect !== "sqlite" && preBuildMigrations.length > 0 && !process.env.DATABASE_URL) {
6553
6704
  log.error([
6554
6705
  `deploy: ${dialect === "mysql" ? "MySQL" : "PostgreSQL"} migrations require DATABASE_URL for --platform cloudflare.`,
@@ -6556,15 +6707,204 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6556
6707
  "provision Hyperdrive and apply checked-in migrations before uploading the Worker; it is",
6557
6708
  "never written to wrangler.jsonc or the generated Worker config."
6558
6709
  ].join("\n"));
6559
- return exit(1);
6710
+ return null;
6560
6711
  }
6561
6712
  if (desired.d1) {
6562
6713
  const migrationsPattern = resolveWranglerMigrationPattern(parseRootWranglerConfig(configPath), desired.d1.binding, desired.d1.migrationsDir ?? relative(dirname(configPath), migrationsDir));
6563
6714
  if (!migrationsPattern.ok) {
6564
6715
  log.error(migrationsPattern.reason);
6716
+ return null;
6717
+ }
6718
+ }
6719
+ return {
6720
+ configPath,
6721
+ ...facts
6722
+ };
6723
+ }
6724
+ /** Apply remote D1 changes and prove no migrations remain pending. */
6725
+ async function applyAndVerifyRemoteD1Migrations(d1MigrateToken, configPath, runWrangler, assertUploaderStillPinned) {
6726
+ if (d1MigrateToken) {
6727
+ log.step("Applying D1 migrations...");
6728
+ if (!assertUploaderStillPinned()) return false;
6729
+ const migrate = await Promise.resolve(runWrangler([
6730
+ "d1",
6731
+ "migrations",
6732
+ "apply",
6733
+ d1MigrateToken,
6734
+ "--remote",
6735
+ "-c",
6736
+ configPath,
6737
+ "--env="
6738
+ ], { capture: false }));
6739
+ if (!isCleanWranglerExit(migrate)) {
6740
+ 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.`);
6741
+ return false;
6742
+ }
6743
+ if (!assertUploaderStillPinned()) return false;
6744
+ const migrateList = await Promise.resolve(runWrangler([
6745
+ "d1",
6746
+ "migrations",
6747
+ "list",
6748
+ d1MigrateToken,
6749
+ "--remote",
6750
+ "-c",
6751
+ configPath,
6752
+ "--env="
6753
+ ], { capture: true }));
6754
+ if (!isCleanWranglerExit(migrateList)) {
6755
+ 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.`);
6756
+ return false;
6757
+ }
6758
+ if (migrateList.stdout.includes("Migrations to be applied:")) {
6759
+ log.error([
6760
+ `deploy: remote D1 still has UNAPPLIED migrations for "${d1MigrateToken}" after apply.`,
6761
+ "`wrangler d1 migrations apply` exits 0 even when its confirmation is declined, so",
6762
+ "the schema may be un-migrated while the code that needs it is about to deploy.",
6763
+ "Re-run and confirm the migration (or apply it non-interactively), then rerun."
6764
+ ].join("\n"));
6765
+ return false;
6766
+ }
6767
+ if (!migrateList.stdout.includes("No migrations to apply!")) {
6768
+ log.error([
6769
+ `deploy: could not confirm the remote migration state for "${d1MigrateToken}".`,
6770
+ "`wrangler d1 migrations list` printed neither the \"no migrations to apply\" nor the",
6771
+ "\"migrations to be applied\" marker (WRANGLER_LOG is pinned so they are never",
6772
+ "suppressed) — refusing to deploy against an unverified schema. Rerun once wrangler",
6773
+ "can reach your account."
6774
+ ].join("\n"));
6775
+ return false;
6776
+ }
6777
+ }
6778
+ return true;
6779
+ }
6780
+ /** Check the built Worker against the pinned deployment target before upload. */
6781
+ function verifyCloudflareDeployArtifact(root, deps, options) {
6782
+ const verification = (deps.verifyDeployConfig ?? verifyGeneratedDeployConfig)(root, options);
6783
+ if (!verification.ok) {
6784
+ log.error([
6785
+ "deploy: the generated deploy config does not match the pinned target — refusing to deploy.",
6786
+ verification.reason,
6787
+ "This typically means CLOUDFLARE_ENV / CLOUDFLARE_VITE_WRANGLER_CONFIG_PATH (in the",
6788
+ "environment or a production `.env`) selected a different named environment or config",
6789
+ "at build time. This backend always deploys the canonical top-level config — remove",
6790
+ "them and rebuild."
6791
+ ].filter(Boolean).join("\n"));
6792
+ return false;
6793
+ }
6794
+ return true;
6795
+ }
6796
+ /** Validate emitted Worker vars and required secrets against post-build ground truth. */
6797
+ async function validateCloudflarePostBuildEnv(root, configPath, accountId, apiBaseUrl, workerName, schemaFacts, authEnabled, existingWorker, approvedHandoffKv, deps, assertUploaderStillPinned) {
6798
+ const emitted = (deps.readEmittedWorkerVars ?? readEmittedWorkerVarsDefault)(root);
6799
+ if (existingWorker) {
6800
+ const generated = readGeneratedDeployConfig(root);
6801
+ assertExistingCloudflareConfig(existingWorker, generated.config, true, approvedHandoffKv);
6802
+ }
6803
+ if (!emitted.ok) {
6804
+ log.error([
6805
+ "deploy: could not read the worker vars the build emitted — refusing to validate secrets.",
6806
+ ` ${emitted.reason}`,
6807
+ "The build must emit dist/ssr/wrangler.json for this backend. Rerun the build, or deploy",
6808
+ "this app with `void deploy` (the managed platform)."
6809
+ ].join("\n"));
6810
+ return false;
6811
+ }
6812
+ const emittedVars = emitted.vars;
6813
+ if (authEnabled && Object.prototype.hasOwnProperty.call(emittedVars, BETTER_AUTH_SECRET_NAME)) {
6814
+ log.error([
6815
+ `deploy: ${BETTER_AUTH_SECRET_NAME} must be stored as a Cloudflare Worker secret, not a plaintext worker var.`,
6816
+ "Remove it from Worker vars and rerun. This deploy command preserves an",
6817
+ "existing remote value or creates a persistent one automatically when it is missing."
6818
+ ].join("\n"));
6819
+ return false;
6820
+ }
6821
+ const plaintextServerKeys = schemaFacts.serverKeys.filter((key) => key in emittedVars);
6822
+ if (plaintextServerKeys.length > 0) {
6823
+ log.error([
6824
+ "deploy: server env keys cannot ship as plaintext Worker vars:",
6825
+ ...plaintextServerKeys.map((key) => ` • ${key}`),
6826
+ "Remove them from Worker vars and set them with `void secret put <NAME>`."
6827
+ ].join("\n"));
6828
+ return false;
6829
+ }
6830
+ const envContext = deriveSelfHostEnvContextFromVars(emittedVars, schemaFacts);
6831
+ if (schemaFacts.hasSchema) {
6832
+ let validateResult;
6833
+ try {
6834
+ validateResult = await (deps.validateEmittedVars ?? validateEmittedVarsDefault)({ root }, buildSchemaProbeEnv(accountId, apiBaseUrl));
6835
+ } catch (err) {
6836
+ log.error(`deploy: could not validate the emitted worker vars against the env schema — ${getErrorMessage(err)}`);
6837
+ return false;
6838
+ }
6839
+ if (validateResult.kind === "schema-error") {
6840
+ log.error(`deploy: ${selfHostSchemaFailureMessage(validateResult.reason)}`);
6841
+ return false;
6842
+ }
6843
+ envContext.invalidKeys = validateResult.invalidKeys;
6844
+ }
6845
+ if (authEnabled) {
6846
+ envContext.absentRequired = envContext.absentRequired.filter((key) => key !== BETTER_AUTH_SECRET_NAME);
6847
+ envContext.invalidKeys = envContext.invalidKeys.filter((key) => key !== BETTER_AUTH_SECRET_NAME);
6848
+ }
6849
+ if (!assertUploaderStillPinned()) return false;
6850
+ try {
6851
+ await (deps.dischargeSelfHostEnv ?? dischargeSelfHostEnvContext)(envContext, {
6852
+ root,
6853
+ configPath,
6854
+ accountId,
6855
+ workerName
6856
+ });
6857
+ } catch (err) {
6858
+ if (err instanceof SelfHostFirstDeployError || err instanceof SelfHostSecretListError || err instanceof SelfHostEnvValidationError || err instanceof SelfHostSchemaError) {
6859
+ log.error(err.message);
6860
+ return false;
6861
+ }
6862
+ throw err;
6863
+ }
6864
+ return true;
6865
+ }
6866
+ /** Deploy to the user's own Cloudflare account through the guarded native Worker flow. */
6867
+ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6868
+ const initialCloudflareLink = readCloudflareLink(root);
6869
+ const initialCloudflareCandidate = readCloudflareCandidate(root);
6870
+ const exit = deps.exit ?? ((code) => process.exit(code));
6871
+ const voidConfig = readConfig(root);
6872
+ const atomic = options.atomic === true || voidConfig.deploy?.cloudflare?.mode === "atomic";
6873
+ if (atomic && (options.reuseExistingWorker || initialCloudflareLink)) {
6874
+ log.error("deploy: atomic deployment is unavailable during the existing Worker handoff. Complete the handoff first.");
6875
+ return exit(1);
6876
+ }
6877
+ const detectedFramework = detectFramework(root);
6878
+ const frameworkPreset = detectedFramework ? FRAMEWORK_PRESETS[detectedFramework.name] : void 0;
6879
+ cliLog.info("cloudflare_deploy_start", { provision: options.provision === true ? true : void 0 });
6880
+ if (isNodeTarget(voidConfig.target)) {
6881
+ log.error([
6882
+ `deploy: --platform cloudflare is not supported for the "${voidConfig.target}" target.`,
6883
+ "This backend deploys Cloudflare Workers only. Deploy a node/bun/deno build with its",
6884
+ "own host/runtime, or use the default Cloudflare target for --platform cloudflare."
6885
+ ].join("\n"));
6886
+ return exit(1);
6887
+ }
6888
+ if (detectedFramework?.class === "a" && hasConfiguredVoidWorkerRoutingRules(voidConfig.routing)) {
6889
+ log.error([
6890
+ `deploy: native Cloudflare deployment cannot apply Void routing redirects, rewrites, fallbacks, or headers to ${detectedFramework.name}.`,
6891
+ "This framework owns its Worker request handler, so these rules would otherwise be ignored.",
6892
+ "Move the rules into the framework or its Cloudflare Worker, then retry."
6893
+ ].join("\n"));
6894
+ return exit(1);
6895
+ }
6896
+ const provisionModule = await loadProvisionModule();
6897
+ const staticPreset = resolveCloudflareStaticPreset(root, voidConfig, options) ?? await resolveCloudflareVoidStaticPreset(root, voidConfig);
6898
+ if (staticPreset) {
6899
+ if (atomic) {
6900
+ log.error("deploy: atomic deployment is only for Workers with Durable Objects.");
6565
6901
  return exit(1);
6566
6902
  }
6903
+ return runCloudflareStaticDeploy(root, options, voidConfig, staticPreset, cliLog, deps, initialCloudflareLink, initialCloudflareCandidate);
6567
6904
  }
6905
+ const source = await prepareCloudflareDeploySource(root, options, voidConfig);
6906
+ if (!source) return exit(1);
6907
+ const { configPath, desired, reasons, authEnabled, dialect, migrationsDir, migrations: preBuildMigrations, needsAI, aiBindingName, needsSandbox, needsLive, expectedCrons, needsEmail, emailHandlers } = source;
6568
6908
  let rootConfig = parseRootWranglerConfig(configPath);
6569
6909
  let apiBaseUrl;
6570
6910
  try {
@@ -6862,6 +7202,10 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6862
7202
  const passthroughIdentitySnapshot = snapshotPassthroughIdentities(preBuildRootConfig);
6863
7203
  const passthroughRawFields = snapshotPassthroughRawFields(preBuildRootConfig);
6864
7204
  const expectedContainers = reconstructExpectedContainers(voidConfig, root, preBuildRootConfig, needsSandbox);
7205
+ const expectedDurableObjectState = reconstructExpectedDurableObjectState(voidConfig, root, preBuildRootConfig, {
7206
+ needsSandbox,
7207
+ needsLive
7208
+ });
6865
7209
  removeDeployPointer(root);
6866
7210
  const buildChildEnv = scrubManagedDeployBuildMarkers(scrubWranglerAuthCredentials(deployChildEnv(accountId, apiBaseUrl)));
6867
7211
  requireProvisionModule().deleteEnvVarCaseAware(buildChildEnv, CLOUDFLARE_DEPLOY_BUILD_ENV);
@@ -6897,6 +7241,10 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6897
7241
  return exit(1);
6898
7242
  }
6899
7243
  const lifecycleConfigPath = (deps.resolveGeneratedConfigPath ?? ((projectRoot) => readGeneratedDeployConfig(projectRoot).path))(root);
7244
+ if (atomic && !Array.isArray(parseRootWranglerConfig(lifecycleConfigPath).migrations)) {
7245
+ log.error("deploy: atomic deployment is only for Workers with Durable Object migration history.");
7246
+ return exit(1);
7247
+ }
6900
7248
  try {
6901
7249
  deduplicateGeneratedCompatibilityFlags(lifecycleConfigPath, configPath);
6902
7250
  const lifecycleOptions = {
@@ -6906,77 +7254,15 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
6906
7254
  accountId,
6907
7255
  apiBaseUrl
6908
7256
  };
6909
- await (deps.assertDurableObjectLifecycle ?? assertCloudflareDurableObjectLifecycleSupported)(lifecycleOptions);
7257
+ await (deps.assertDurableObjectLifecycle ?? assertCloudflareDurableObjectLifecycleSupported)({
7258
+ ...lifecycleOptions,
7259
+ allowPendingAtomicMigration: atomic
7260
+ });
6910
7261
  } catch (error) {
6911
7262
  log.error(getErrorMessage(error));
6912
7263
  return exit(1);
6913
7264
  }
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
- }
7265
+ if (!await validateCloudflarePostBuildEnv(root, configPath, accountId, apiBaseUrl, workerName, schemaFacts, authEnabled, existingWorker, approvedHandoffKv, deps, assertUploaderStillPinned)) return exit(1);
6980
7266
  if (authEnabled && dialect === "sqlite") try {
6981
7267
  await (deps.validateAuthMigrations ?? validateAuthMigrationSchema)(root, migrations);
6982
7268
  } catch (err) {
@@ -7071,6 +7357,8 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7071
7357
  aiBindingName,
7072
7358
  authEnabled,
7073
7359
  expectedContainers,
7360
+ expectedDurableObjectBindings: expectedDurableObjectState.bindings,
7361
+ expectedMigrations: expectedDurableObjectState.migrations,
7074
7362
  expectedCrons
7075
7363
  });
7076
7364
  if (!inheritance.ok) {
@@ -7128,59 +7416,8 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7128
7416
  return exit(1);
7129
7417
  }
7130
7418
  }
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, {
7419
+ if (!await applyAndVerifyRemoteD1Migrations(d1MigrateToken, configPath, runWrangler, assertUploaderStillPinned)) return exit(1);
7420
+ if (!verifyCloudflareDeployArtifact(root, deps, {
7184
7421
  accountId,
7185
7422
  workerName,
7186
7423
  desired,
@@ -7192,21 +7429,14 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7192
7429
  authEnabled,
7193
7430
  requiredSecretNames: schemaFacts.requiredKeys,
7194
7431
  expectedContainers,
7432
+ expectedDurableObjectBindings: expectedDurableObjectState.bindings,
7433
+ expectedMigrations: expectedDurableObjectState.migrations,
7195
7434
  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
- }
7435
+ })) return exit(1);
7208
7436
  const queueConsumerCleanup = readWranglerManagedQueueCleanupCandidates(configPath);
7209
7437
  if (existingWorker) assertCloudflareLinkUnchanged(root, pinnedHandoffLink);
7438
+ assertCloudflareCandidateUnchanged(root, initialCloudflareCandidate);
7439
+ 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
7440
  const candidateReceipt = pinnedHandoffLink?.candidateReceipt;
7211
7441
  if (!deps.activateVersion && !deps.runWrangler && !cfUploaderIsPinned()) return exit(1);
7212
7442
  const cfOutput = deps.activateVersion || deps.runWrangler ? null : await prepareBuildOutput();
@@ -7238,7 +7468,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7238
7468
  configPath: generatedConfigPath,
7239
7469
  preserveTriggers: existingWorker !== null,
7240
7470
  expectedPreviousVersionId: existingWorker?.versionId,
7241
- trustedInheritanceVersionIds: existingWorker && candidateReceipt?.parentVersionId === existingWorker.versionId ? candidateReceipt.versionIds : void 0,
7471
+ trustedInheritanceVersionIds: existingWorker ? candidateReceipt?.parentVersionId === existingWorker.versionId ? candidateReceipt.versionIds : void 0 : initialCloudflareCandidate?.versionIds,
7242
7472
  validateUploadedVersion: existingWorker ? async (versionId) => {
7243
7473
  if (!assertUploaderStillPinned()) throw new Error("The deployment uploader changed.");
7244
7474
  const uploaded = await (deps.readExistingWorker ?? readExistingCloudflareWorker)({
@@ -7249,7 +7479,9 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7249
7479
  });
7250
7480
  assertCloudflareBindingsPreserved(existingWorker, uploaded, approvedHandoffKv);
7251
7481
  } : void 0,
7252
- recordVerifiedCandidate: existingWorker ? (versionId) => recordCloudflareCandidate(root, pinnedHandoffLink, existingWorker.versionId, versionId) : void 0,
7482
+ recordVerifiedCandidate: existingWorker ? (versionId) => recordCloudflareCandidate(root, pinnedHandoffLink, existingWorker.versionId, versionId) : (versionId, parentVersionId) => {
7483
+ if (parentVersionId) recordCloudflareCandidateUpload(root, initialCloudflareCandidate, accountId, workerName, parentVersionId, versionId);
7484
+ },
7253
7485
  message: encodeCloudflareVersionMessage(migrations.map((migration) => migration.name), {
7254
7486
  ...readCloudflareTriggerConfig(generatedConfigPath, configPath),
7255
7487
  ...existingWorker ? { preserve: true } : {}
@@ -7275,12 +7507,15 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
7275
7507
  previousTrafficConfig: readWranglerPublishedTrafficSnapshot(configPath),
7276
7508
  queueConsumerCleanup,
7277
7509
  verifyInheritedSecrets: true,
7510
+ atomic,
7278
7511
  ...initialAuthSecret ? { candidateSecrets: { [BETTER_AUTH_SECRET_NAME]: initialAuthSecret } } : {}
7279
7512
  }).finally(() => cfOutput?.dispose());
7280
7513
  if (!execution.ok) {
7514
+ if (execution.reason === "atomic-readiness-failed" || execution.reason === "atomic-readiness-access-denied") clearCloudflareCandidate(root);
7281
7515
  await reportCloudflareActivationFailure(cliLog, needsSandbox && execution.containersUnavailable ? formatCloudflareSandboxUnavailable() : formatCloudflareActivationError(execution));
7282
7516
  return exit(1);
7283
7517
  }
7518
+ clearCloudflareCandidate(root);
7284
7519
  if (existingWorker) completeCloudflareLink(root);
7285
7520
  acknowledgeWranglerManagedQueueRemovals(configPath, queueConsumerCleanup);
7286
7521
  rememberCloudflareWorkersDevSubdomain(root, accountId, execution.previewUrl);
@@ -7319,12 +7554,16 @@ async function activateCloudflareVersionWithProgress(activate, options) {
7319
7554
  const progress = createSpinner();
7320
7555
  progress.start("Checking the current Worker deployment...");
7321
7556
  try {
7322
- return await activate({
7557
+ const result = await activate({
7323
7558
  ...options,
7324
7559
  onProgress: (message) => progress.message(message)
7325
7560
  });
7326
- } finally {
7327
- progress.stop();
7561
+ if (result.ok) progress.stop("Worker version is ready.");
7562
+ else progress.error("Worker deployment stopped.");
7563
+ return result;
7564
+ } catch (error) {
7565
+ progress.error("Worker deployment stopped.");
7566
+ throw error;
7328
7567
  }
7329
7568
  }
7330
7569
  function formatCloudflareActivationError(result) {
@@ -7360,7 +7599,11 @@ function formatCloudflareActivationError(result) {
7360
7599
  "Set CLOUDFLARE_WORKERS_SUBDOMAIN to your account subdomain (for example \"my-team\")",
7361
7600
  "and retry. Void caches it after a successful workers.dev deployment; production traffic is unchanged."
7362
7601
  ].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.`;
7602
+ 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." : ""}`;
7603
+ case "atomic-failed": return `deploy: Cloudflare could not publish the Worker atomically${status}; inspect production status before retrying.${cloudflareCode}${diagnostic}`;
7604
+ case "atomic-output-invalid": return "deploy: Cloudflare published atomically but did not report a version id or URL. Inspect `void project status` immediately.";
7605
+ case "atomic-readiness-failed":
7606
+ 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
7607
  case "readiness-failed": return ["deploy: the uploaded Worker Version did not pass /__void/ready.", formatCloudflareReadinessRestoration(result)].join("\n");
7365
7608
  case "readiness-access-denied": return [
7366
7609
  "deploy: Cloudflare Access blocked the uploaded Worker Version readiness probe.",
@@ -7491,7 +7734,10 @@ async function resolveCloudflareVoidStaticPreset(root, voidConfig) {
7491
7734
  paths
7492
7735
  });
7493
7736
  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 });
7737
+ const bindings = inferProjectBindings(root, {
7738
+ paths,
7739
+ environment: "prod"
7740
+ });
7495
7741
  const authEnabled = bindings.needsAuth || findVoidAuthConfig(root, paths) !== null || voidConfig.auth !== void 0;
7496
7742
  if (hasNonPageBackend({
7497
7743
  hasRoutes: routeScan.routes.length > 0,
@@ -7507,7 +7753,7 @@ async function resolveCloudflareVoidStaticPreset(root, voidConfig) {
7507
7753
  appType: "static"
7508
7754
  };
7509
7755
  }
7510
- async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliLog, deps, initialCloudflareLink) {
7756
+ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliLog, deps, initialCloudflareLink, initialCloudflareCandidate) {
7511
7757
  const exit = deps.exit ?? ((code) => process.exit(code));
7512
7758
  const configPath = discoverRootWranglerConfig(root);
7513
7759
  let rootConfig = parseRootWranglerConfig(configPath);
@@ -7657,6 +7903,8 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7657
7903
  });
7658
7904
  const queueConsumerCleanup = readWranglerManagedQueueCleanupCandidates(configPath);
7659
7905
  if (existingWorker) assertCloudflareLinkUnchanged(root, pinnedHandoffLink);
7906
+ assertCloudflareCandidateUnchanged(root, initialCloudflareCandidate);
7907
+ 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
7908
  const candidateReceipt = pinnedHandoffLink?.candidateReceipt;
7661
7909
  if (!deps.activateVersion && !deps.runWrangler && !cfUploaderIsPinned()) return exit(1);
7662
7910
  const cfOutput = deps.activateVersion || deps.runWrangler ? null : await prepareCfStaticBuildOutput({
@@ -7692,7 +7940,7 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7692
7940
  configPath: staticConfigPath,
7693
7941
  preserveTriggers: existingWorker !== null,
7694
7942
  expectedPreviousVersionId: existingWorker?.versionId,
7695
- trustedInheritanceVersionIds: existingWorker && candidateReceipt?.parentVersionId === existingWorker.versionId ? candidateReceipt.versionIds : void 0,
7943
+ trustedInheritanceVersionIds: existingWorker ? candidateReceipt?.parentVersionId === existingWorker.versionId ? candidateReceipt.versionIds : void 0 : initialCloudflareCandidate?.versionIds,
7696
7944
  validateUploadedVersion: existingWorker ? async (versionId) => {
7697
7945
  if (!uploaderIsPinned()) throw new Error("The deployment uploader changed.");
7698
7946
  const uploaded = await (deps.readExistingWorker ?? readExistingCloudflareWorker)({
@@ -7703,7 +7951,9 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7703
7951
  });
7704
7952
  assertCloudflareBindingsPreserved(existingWorker, uploaded, [], { staticAssetsBinding: "ASSETS" });
7705
7953
  } : void 0,
7706
- recordVerifiedCandidate: existingWorker ? (versionId) => recordCloudflareCandidate(root, pinnedHandoffLink, existingWorker.versionId, versionId) : void 0,
7954
+ recordVerifiedCandidate: existingWorker ? (versionId) => recordCloudflareCandidate(root, pinnedHandoffLink, existingWorker.versionId, versionId) : (versionId, parentVersionId) => {
7955
+ if (parentVersionId) recordCloudflareCandidateUpload(root, initialCloudflareCandidate, accountId, workerName, parentVersionId, versionId);
7956
+ },
7707
7957
  workerName,
7708
7958
  message: encodeCloudflareVersionMessage([], {
7709
7959
  ...readCloudflareTriggerConfig(staticConfigPath, configPath),
@@ -7734,6 +7984,7 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
7734
7984
  await reportCloudflareActivationFailure(cliLog, formatCloudflareActivationError(execution));
7735
7985
  return exit(1);
7736
7986
  }
7987
+ clearCloudflareCandidate(root);
7737
7988
  if (existingWorker) completeCloudflareLink(root);
7738
7989
  acknowledgeWranglerManagedQueueRemovals(configPath, queueConsumerCleanup);
7739
7990
  rememberCloudflareWorkersDevSubdomain(root, accountId, execution.previewUrl);
@@ -7828,6 +8079,7 @@ async function runDeployInner(root, options, cliLog) {
7828
8079
  reuseExistingWorker: true
7829
8080
  };
7830
8081
  const platform = resolveDeploymentPlatform(root, options);
8082
+ if (options?.atomic && platform !== "cloudflare") throw new Error("deploy: --atomic is available only for Cloudflare Workers.");
7831
8083
  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
8084
  const targetLabel = platform === "cloudflare" ? "Cloudflare" : "Void";
7833
8085
  log.info(`Deployment target: ${targetLabel}`);
@@ -7855,7 +8107,7 @@ async function runManagedDeploy(root, options, cliLog) {
7855
8107
  }
7856
8108
  token ??= getToken(root);
7857
8109
  if (!token) {
7858
- log.error("No auth token found. Run `void auth login` first.");
8110
+ log.error("No auth token found. Run `void account login` first.");
7859
8111
  process.exit(1);
7860
8112
  }
7861
8113
  const client = new PlatformClient(token, {
@@ -7863,11 +8115,16 @@ async function runManagedDeploy(root, options, cliLog) {
7863
8115
  cliLog
7864
8116
  });
7865
8117
  const requestedProjectSlug = getRequestedProjectSlug(options);
8118
+ const linkedProject = readProjectConfig(root);
7866
8119
  let config = null;
7867
8120
  if (requestedProjectSlug) {
7868
- const projects = await client.listProjects();
7869
- assertProjectDeployAccess(projects.find((project) => project.slug === requestedProjectSlug));
7870
- config = resolveProjectBySlug(projects, requestedProjectSlug);
8121
+ const linked = linkedProject?.slug === requestedProjectSlug ? await client.getProject(linkedProject.projectId) : null;
8122
+ const project = linked?.slug === requestedProjectSlug ? linked : await client.findProjectBySlug(requestedProjectSlug);
8123
+ assertProjectDeployAccess(project ?? void 0);
8124
+ config = project ? {
8125
+ projectId: project.id,
8126
+ slug: project.slug
8127
+ } : null;
7871
8128
  if (!config) {
7872
8129
  if (!process.stdin.isTTY) config = await createProjectFromSlug(root, client, requestedProjectSlug, cliLog);
7873
8130
  else {
@@ -7880,11 +8137,10 @@ async function runManagedDeploy(root, options, cliLog) {
7880
8137
  }
7881
8138
  }
7882
8139
  } else {
7883
- config = readProjectConfig(root);
8140
+ config = linkedProject;
7884
8141
  if (config) {
7885
- const projects = await client.listProjects();
7886
8142
  const { projectId, slug } = config;
7887
- const project = projects.find((project) => project.id === projectId);
8143
+ const project = await client.getProject(projectId);
7888
8144
  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
8145
  assertProjectDeployAccess(project);
7890
8146
  }
@@ -7942,7 +8198,7 @@ async function runManagedDeploy(root, options, cliLog) {
7942
8198
  } catch (error) {
7943
8199
  if (isExpiredTokenError(error)) {
7944
8200
  if (getTokenSource() === "ci") throw new Error("`VOID_TOKEN` is invalid or expired. Generate a new token and try again.");
7945
- if (!process.stdin.isTTY || reauthenticated) throw new Error("Auth token expired. Run `void auth login` and try again.");
8201
+ if (!process.stdin.isTTY || reauthenticated) throw new Error("Auth token expired. Run `void account login` and try again.");
7946
8202
  log.warn("Auth token expired. Re-authenticating...");
7947
8203
  await promptForLoginToken(root);
7948
8204
  log.success("Re-authenticated. Retrying deploy...");
@@ -7956,7 +8212,7 @@ function assertProjectDeployAccess(project) {
7956
8212
  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
8213
  }
7958
8214
  async function promptDeployProjectConfig(root, client, cliLog) {
7959
- const projects = await client.listProjects();
8215
+ const projects = await client.listProjectChoices();
7960
8216
  const deployableProjects = projects.filter((project) => project.role !== "reader");
7961
8217
  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
8218
  if (await promptProjectSetupAction("Set up a Void project for deploy:", { includeLink: deployableProjects.length > 0 }) === "create") return promptAndCreateProject(root, client);
@@ -8475,7 +8731,8 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
8475
8731
  const scanDirs = voidConfig.inference?.scanDirs ?? FRAMEWORK_SCAN_DIRS;
8476
8732
  const bindings = inferProjectBindings(root, {
8477
8733
  ...inferenceOptions,
8478
- paths
8734
+ paths,
8735
+ environment: "prod"
8479
8736
  }, scanDirs);
8480
8737
  if (bindings.needsAuth || findVoidAuthConfig(root, paths) !== null || voidConfig.auth !== void 0) {
8481
8738
  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 +8953,10 @@ async function runFullDeploy(root, config, client, voidConfig, fwPreset, skipBui
8696
8953
  const paths = resolveProjectPaths(root, deployConfig);
8697
8954
  const dialect = getDatabaseDialect(deployConfig);
8698
8955
  const deployScanDirs = deployConfig.inference?.scanDirs ?? (isFrameworkMode ? FRAMEWORK_SCAN_DIRS : void 0);
8699
- const bindings = inferProjectBindings(root, { paths }, deployScanDirs);
8956
+ const bindings = inferProjectBindings(root, {
8957
+ paths,
8958
+ environment: "prod"
8959
+ }, deployScanDirs);
8700
8960
  if (isSandboxEnabled(deployConfig)) bindings.needsSandbox = true;
8701
8961
  const authEnabled = bindings.needsAuth || findVoidAuthConfig(root, paths) !== null || deployConfig.auth !== void 0;
8702
8962
  const effectiveBindings = authEnabled ? {
@@ -9202,4 +9462,4 @@ function resolveWorkerDirName(distDir, fwPreset, buildCommand) {
9202
9462
  throw new Error("deploy: Worker output not found. Expected dist/ssr/ or dist/rsc/.");
9203
9463
  }
9204
9464
  //#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 };
9465
+ 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 };