void 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/README.md +3 -1
  2. package/dist/{account-cmd-l-FM7Ioq.mjs → account-cmd-Ci00cncT.mjs} +5 -5
  3. package/dist/{agents-B_pX_HmQ.mjs → agents-CuNtT0D_.mjs} +5 -2
  4. package/dist/{application-analysis-DKy02UY0.mjs → application-analysis-D72ZQfMZ.mjs} +118 -135
  5. package/dist/{application-routing-DQyUh_5S.mjs → application-routing-Dy589Vgn.mjs} +1 -2
  6. package/dist/atomic-write-Dq6R0BPN.mjs +18 -0
  7. package/dist/{auth-Dn2vw-SG.mjs → auth-B6iOCjKI.mjs} +23 -56
  8. package/dist/{auth-link-vz9Z2kmG.mjs → auth-link-DWr6Afao.mjs} +10 -10
  9. package/dist/{auth-migrations-BwHgeEsD.mjs → auth-migrations-Cgs0k6lS.mjs} +28 -5
  10. package/dist/{auth-router-DvsCUVw4.mjs → auth-router-DP14wVkZ.mjs} +4 -4
  11. package/dist/auth-wn6F8dB8.mjs +2 -0
  12. package/dist/base64-DVrOndmI.mjs +16 -0
  13. package/dist/{better-auth-shared-CPvWD3nG.d.mts → better-auth-shared-B74NJIus.d.mts} +8 -13
  14. package/dist/{better-auth-shared-DPpj8zxc.mjs → better-auth-shared-CMXlZG7W.mjs} +56 -68
  15. package/dist/{build-cmd-D6we0VjO.mjs → build-cmd-Cr3FJxv0.mjs} +5 -5
  16. package/dist/{cache-CZRdzKx1.mjs → cache-D0Tt28cn.mjs} +5 -5
  17. package/dist/{cancel-deploy-CQ3NnMvf.mjs → cancel-deploy-CJKvk7AN.mjs} +4 -4
  18. package/dist/{cf-access-TWNzXltp.mjs → cf-access-BM9G0lhO.mjs} +4 -3
  19. package/dist/{cf-access-BcIBSKqG.mjs → cf-access-CWP4avfP.mjs} +3 -7
  20. package/dist/cf-build-output-2u583yJK.mjs +2 -0
  21. package/dist/{cf-build-output-DjvB_872.mjs → cf-build-output-Bc8i3dzE.mjs} +2 -2
  22. package/dist/cf-user-agent-ChjQp2MU.mjs +33 -0
  23. package/dist/cli/cli.mjs +198 -311
  24. package/dist/cli/cloudflare-operation-process.mjs +41 -15
  25. package/dist/cli/env-schema-probe.d.mts +5 -43
  26. package/dist/cli/env-schema-probe.mjs +14 -80
  27. package/dist/client-C1BjRn3g.mjs +2 -0
  28. package/dist/{client-DlDJuY0s.mjs → client-DM9Kcf4e.mjs} +161 -415
  29. package/dist/{cloudflare-auth-CuxfF6OA.mjs → cloudflare-auth-CqFBDo52.mjs} +12 -39
  30. package/dist/{cloudflare-cmd-lHqNlJGW.mjs → cloudflare-cmd-CTrn-lXJ.mjs} +6 -5
  31. package/dist/{cloudflare-config-BmhBv3HV.mjs → cloudflare-config-DV60XFFK.mjs} +16 -28
  32. package/dist/{cloudflare-connect-2G3rL2rP.mjs → cloudflare-connect-BosmCNlq.mjs} +3 -3
  33. package/dist/{cloudflare-operations-CwI1bChl.mjs → cloudflare-operations-BKdSfNBN.mjs} +26 -34
  34. package/dist/{cloudflare-operations-BlYLlowZ.mjs → cloudflare-operations-Ds-lX3Ts.mjs} +1 -1
  35. package/dist/{cloudflare-process-2-TfIEzB.mjs → cloudflare-process-CeDWJRhj.mjs} +12 -7
  36. package/dist/collect-NUlJMpLY.mjs +2 -0
  37. package/dist/{collect-DiTn9yr6.mjs → collect-xjffdCdk.mjs} +1 -1
  38. package/dist/{config-CSa15FvD.d.mts → config-7qoq2p9v.d.mts} +2 -2
  39. package/dist/{config-CLYAosnQ.mjs → config-BEm9vRvS.mjs} +11 -5
  40. package/dist/{config-DiowPT80.mjs → config-Bx_1SpnO.mjs} +87 -177
  41. package/dist/config-CNnrSMYm.mjs +2 -0
  42. package/dist/{config-DPByhVck.mjs → config-D0GY5ItR.mjs} +1 -1
  43. package/dist/config-entry.d.mts +1 -1
  44. package/dist/{connect-BfPBHHm-.mjs → connect-nukQSoEO.mjs} +8 -8
  45. package/dist/{create-project-BdXEFKal.mjs → create-project-D4APeBwX.mjs} +7 -7
  46. package/dist/{create-project-qFDC45zg.mjs → create-project-DL7YXpjj.mjs} +1 -1
  47. package/dist/{db-Xs80hcaA.mjs → db-27RztQLy.mjs} +173 -263
  48. package/dist/{delete-d2vuou3j.mjs → delete-BbsZFZIw.mjs} +5 -5
  49. package/dist/deploy-B06EQq4t.mjs +6009 -0
  50. package/dist/deploy-Db2ALnQP.mjs +3 -0
  51. package/dist/deploy-managed-static-CGswbcay.mjs +2277 -0
  52. package/dist/deploy-transport-BiicfoQW.mjs +180 -0
  53. package/dist/deploy.d.mts +10 -0
  54. package/dist/deploy.mjs +82 -0
  55. package/dist/dev-inbox-Rd6j_8vM.mjs +217 -0
  56. package/dist/discover-CTUiSsfG.mjs +2 -0
  57. package/dist/{discover-CkCYv9T_.mjs → discover-D2PGT63u.mjs} +2 -2
  58. package/dist/{dist-BVqXeR_h.mjs → dist-ipQi0Q8y.mjs} +2 -3
  59. package/dist/{domain-BsDUBAvt.mjs → domain-Bfq9n03H.mjs} +7 -22
  60. package/dist/{dotenv-BfU6eqFt.mjs → dotenv-CNazY3-w.mjs} +4 -16
  61. package/dist/{email-d_Aux1vM.mjs → email-BcjSyAL0.mjs} +4 -20
  62. package/dist/{email-_lGAHOhp.mjs → email-DIwaQU4P.mjs} +99 -191
  63. package/dist/email-cloudflare-CH053RxK.mjs +1096 -0
  64. package/dist/email-protocol-D9nTvhCp.mjs +82 -0
  65. package/dist/{entry-CMAkqBmU.mjs → entry-ehmBvs5w.mjs} +2 -2
  66. package/dist/{env-BxocywBB.mjs → env-BJjULvL0.mjs} +2 -2
  67. package/dist/{env-DMA3cXZt.mjs → env-BhdWMrNy.mjs} +2 -13
  68. package/dist/{env-C74QepDE.mjs → env-C6ipBLp3.mjs} +8 -8
  69. package/dist/{env-public-DR7ZM6d-.d.mts → env-public-CCdykygU.d.mts} +6 -23
  70. package/dist/{env-raw-jZpP5n47.mjs → env-raw-Cklzcde3.mjs} +3 -20
  71. package/dist/{env-types-CwXgeMgL.mjs → env-types-DS2_y4X8.mjs} +2 -2
  72. package/dist/{env-validation-CrVNjsPm.mjs → env-validation-CTn-HhG1.mjs} +1 -1
  73. package/dist/env-validation-cE0zcmzO.mjs +486 -0
  74. package/dist/{gen-DtkQhvQg.mjs → gen-CnN1Xidx.mjs} +131 -253
  75. package/dist/gen-F8pSZnhc.mjs +2 -0
  76. package/dist/{generate-GDbL7sUr.mjs → generate-Dat0UTry.mjs} +38 -4
  77. package/dist/generate-Rii9klHB.mjs +2 -0
  78. package/dist/generated-wrangler-config-DeWj5F9Y.mjs +18 -0
  79. package/dist/{github-cmd-DaDdBbSS.mjs → github-cmd-BdkU4Nhe.mjs} +27 -71
  80. package/dist/{handler-BHAn2fZJ.mjs → handler-BZ1t7-Rv.mjs} +2 -2
  81. package/dist/{handler-CNAwjRcW.d.mts → handler-_PqY82xe.d.mts} +1 -1
  82. package/dist/{headers-DlfR78Nu.mjs → headers-Di1FsD3e.mjs} +26 -81
  83. package/dist/{help-0bTe_lID.mjs → help-Bug7pyK_.mjs} +18 -10
  84. package/dist/help-s9q7LTcu.mjs +2 -0
  85. package/dist/{inbound-PfQDLXc5.mjs → inbound-DmkTQeWp.mjs} +71 -222
  86. package/dist/{inbound-CH5Mksyy.d.mts → inbound-brj2-TM5.d.mts} +19 -58
  87. package/dist/index.d.mts +2 -18
  88. package/dist/index.mjs +200 -496
  89. package/dist/{info-PYWwkWyt.mjs → info-CujPwtMe.mjs} +5 -5
  90. package/dist/{init-DaBGmaXC.mjs → init-ZWOJvc-Z.mjs} +179 -388
  91. package/dist/isr-config-DPjXM8J2.mjs +194 -0
  92. package/dist/{link-C6fjafep.mjs → link-UEc7bnF4.mjs} +8 -8
  93. package/dist/{list-BTFBlqKl.mjs → list-CuWeOnzk.mjs} +6 -17
  94. package/dist/{live-CgQuTpqD.mjs → live-BxLX-JqJ.mjs} +19 -17
  95. package/dist/{live-Du8jXwOW.d.mts → live-DJONVlQK.d.mts} +1 -1
  96. package/dist/load-user-env-DD5qveNU.mjs +49 -0
  97. package/dist/{local-d1-ga5O_idV.mjs → local-d1-BM3p74mm.mjs} +6 -6
  98. package/dist/{login-GKcNUmtI.mjs → login-CZ2Cqa-D.mjs} +11 -11
  99. package/dist/login-DhK7o1oJ.mjs +2 -0
  100. package/dist/{logs-BiMSULmc.mjs → logs-TihRcLTk.mjs} +5 -5
  101. package/dist/migrate-BgT-hmu8.mjs +2 -0
  102. package/dist/{migrate-NLsjBbuM.mjs → migrate-uFwojusJ.mjs} +69 -21
  103. package/dist/migration-handler-Cg0Y4EPu.mjs +470 -0
  104. package/dist/{migration-handler-DM4clYj5.d.mts → migration-handler-CwlEQUoo.d.mts} +17 -26
  105. package/dist/{mime-DxCznlJq.mjs → mime-srOklVVv.mjs} +92 -395
  106. package/dist/{node-DJicPvPj.mjs → node-DoKbo1SZ.mjs} +8 -24
  107. package/dist/{operator-args-DOBhIaIg.mjs → operator-args-UnE8Y2eK.mjs} +27 -26
  108. package/dist/{operator-auth-BEZ_u0Cz.mjs → operator-auth-Cr2zCc-J.mjs} +2 -2
  109. package/dist/{operator-client-DbDv4vtE.mjs → operator-client-C-ROjk1I.mjs} +4 -4
  110. package/dist/{operator-cmd-BT4hgavL.mjs → operator-cmd-C5lCctnc.mjs} +8 -8
  111. package/dist/operator-cmd-Cjk5DiRx.mjs +2 -0
  112. package/dist/{output-C50ag2r3.mjs → output-FNHKw5Ac.mjs} +36 -5
  113. package/dist/{package-json-DXfiT1jV.mjs → package-json-BjYqR-So.mjs} +1 -1
  114. package/dist/pages/client.d.mts +1 -1
  115. package/dist/pages/client.mjs +91 -5
  116. package/dist/pages/index.d.mts +1 -2
  117. package/dist/pages/index.mjs +6 -6
  118. package/dist/pages/islands-plugin.mjs +5 -83
  119. package/dist/pages/protocol.d.mts +2 -2
  120. package/dist/pages/protocol.mjs +1 -1
  121. package/dist/pages/serialize.mjs +1 -1
  122. package/dist/{platform-args-DUeXY9Om.mjs → platform-args-C6Mb_I3a.mjs} +34 -58
  123. package/dist/platform-args-Cm7x-fot.mjs +2 -0
  124. package/dist/{platform-auth-config-CkSx3usH.mjs → platform-auth-config-CJmNkFT2.mjs} +10 -11
  125. package/dist/{platform-auth-protection-BJimB_p9.mjs → platform-auth-protection-D5wvsI-Y.mjs} +36 -26
  126. package/dist/{platform-auth-recovery-BU6izFAU.mjs → platform-auth-recovery-D_0I3n-1.mjs} +8 -9
  127. package/dist/{platform-cmd-BbmJiq5O.mjs → platform-cmd-Cuj4oUVo.mjs} +1 -1
  128. package/dist/{platform-cmd-BbY1dWiM.mjs → platform-cmd-DxxZO6e5.mjs} +15 -15
  129. package/dist/{platform-discovery-DIYz8V63.mjs → platform-discovery-CHhNs8Nn.mjs} +1 -1
  130. package/dist/{platform-domain-CHVS6cV0.mjs → platform-domain-zLXnW1G_.mjs} +5 -5
  131. package/dist/{platform-lifecycle-DzCwqhFq.mjs → platform-lifecycle-DOW-wLfx.mjs} +1398 -2043
  132. package/dist/{platform-lifecycle-ByAlpkhV.mjs → platform-lifecycle-_gfnjUBr.mjs} +1 -1
  133. package/dist/{platform-management-CBOT4BSM.mjs → platform-management-CYrLvTGH.mjs} +1 -1
  134. package/dist/{platform-management-CuuVDhyt.mjs → platform-management-t7HKy4-U.mjs} +632 -124
  135. package/dist/{platform-plans-config-CN-heS4q.mjs → platform-plans-config-CNH6zbPX.mjs} +15 -11
  136. package/dist/{platform-recovery-CskSJgLh.mjs → platform-recovery-DeucI7A9.mjs} +6 -9
  137. package/dist/{platform-registry-Cjv2Qf0r.mjs → platform-registry-B9mWX9LO.mjs} +13 -18
  138. package/dist/{platform-setup-BBxRxmFC.mjs → platform-setup-CTf6MMT9.mjs} +19 -26
  139. package/dist/{plugin-inference-BlQbOL0P.mjs → plugin-inference-DsARdQKE.mjs} +18 -33
  140. package/dist/{prepare-Dq9hTIbo.mjs → prepare-C4zfwks4.mjs} +3 -3
  141. package/dist/{prepare-Do96654b.mjs → prepare-CSH9dKTI.mjs} +11 -13
  142. package/dist/prepare-dr9uxQSV.mjs +2 -0
  143. package/dist/{prerender-render-Ct20jftc.mjs → prerender-render-Bfsumdkv.mjs} +8 -2
  144. package/dist/prerender-render.d.mts +2 -0
  145. package/dist/prerender-render.mjs +2 -2
  146. package/dist/project-DiiOBZPF.mjs +2 -0
  147. package/dist/{project-cmd-DaoRrn-8.mjs → project-cmd-Dq75AXzy.mjs} +19 -19
  148. package/dist/{project-paths-GgcMozYz.mjs → project-paths-DMvEeSau.mjs} +9 -14
  149. package/dist/{project-BAm2aB6Q.mjs → project-rqDnVsJN.mjs} +8 -4
  150. package/dist/{project-team-Q_lCA7Io.mjs → project-team-B3_QcStG.mjs} +6 -6
  151. package/dist/{project-token-BArgK9o1.mjs → project-token-CvsRvv2I.mjs} +5 -5
  152. package/dist/{project-tsconfig-CVJhNMxs.mjs → project-tsconfig-bveqhlYA.mjs} +3 -5
  153. package/dist/{project-zero-trust-KO9Hu2Pq.mjs → project-zero-trust-D1ICiwN_.mjs} +5 -5
  154. package/dist/{protocol-BPZaNqBo.d.mts → protocol-4H7V_3Os.d.mts} +1 -1
  155. package/dist/{protocol-CfaUwNs8.mjs → protocol-RNP0u7UY.mjs} +9 -3
  156. package/dist/{provision-BfaLiWbj.mjs → provision-DDh7ITVS.mjs} +118 -865
  157. package/dist/{requests-C7Oeoh5u.mjs → requests-3CL3BuZh.mjs} +4 -4
  158. package/dist/resolve-project-B9Hr0D3n.mjs +2 -0
  159. package/dist/resolve-project-C_Cu7E8a.mjs +48 -0
  160. package/dist/{rollback-DVAtrLAl.mjs → rollback-Ce1d_0J9.mjs} +7 -17
  161. package/dist/{route-types-CbtsIeFn.mjs → route-types-IrBuwJ7u.mjs} +35 -70
  162. package/dist/routing-assets-VkrKIbxE.mjs +139 -0
  163. package/dist/{runner-9wjsSZx-.mjs → runner-B5huK2eC.mjs} +1 -1
  164. package/dist/{runner-DMBKSrRk.mjs → runner-DcVDrzuR.mjs} +7 -28
  165. package/dist/{runner-mysql-CEzKtmFb.mjs → runner-mysql-CCtyI0p6.mjs} +4 -3
  166. package/dist/runner-mysql-CaJq-hd6.mjs +2 -0
  167. package/dist/runner-pg-BJhFZZG4.mjs +2 -0
  168. package/dist/{runner-pg-DV8p_zjA.mjs → runner-pg-CPd-CB_F.mjs} +1 -1
  169. package/dist/runtime/ai.mjs +9 -22
  170. package/dist/runtime/better-auth-mysql.d.mts +2 -5
  171. package/dist/runtime/better-auth-mysql.mjs +6 -31
  172. package/dist/runtime/better-auth-pg.d.mts +2 -5
  173. package/dist/runtime/better-auth-pg.mjs +6 -32
  174. package/dist/runtime/better-auth.d.mts +2 -4
  175. package/dist/runtime/better-auth.mjs +9 -19
  176. package/dist/runtime/db.mjs +1 -1
  177. package/dist/runtime/durable.d.mts +16 -0
  178. package/dist/runtime/durable.mjs +26 -2
  179. package/dist/runtime/email/testing.d.mts +1 -1
  180. package/dist/runtime/email/testing.mjs +9 -23
  181. package/dist/runtime/email-protocol.d.mts +12 -0
  182. package/dist/runtime/email-protocol.mjs +2 -70
  183. package/dist/runtime/email.d.mts +1 -1
  184. package/dist/runtime/email.mjs +79 -221
  185. package/dist/runtime/env-public.d.mts +1 -1
  186. package/dist/runtime/env-public.mjs +12 -38
  187. package/dist/runtime/env.d.mts +1 -12
  188. package/dist/runtime/env.mjs +1 -1
  189. package/dist/runtime/handler.d.mts +1 -1
  190. package/dist/runtime/handler.mjs +1 -1
  191. package/dist/runtime/isr.mjs +1 -1
  192. package/dist/runtime/kv.mjs +1 -1
  193. package/dist/runtime/live-client.d.mts +1 -1
  194. package/dist/runtime/live-server.mjs +1 -16
  195. package/dist/runtime/live.d.mts +1 -1
  196. package/dist/runtime/live.mjs +1 -1
  197. package/dist/runtime/migration-handler-mysql.d.mts +2 -2
  198. package/dist/runtime/migration-handler-mysql.mjs +3 -2
  199. package/dist/runtime/migration-handler-pg.d.mts +2 -2
  200. package/dist/runtime/migration-handler-pg.mjs +1 -1
  201. package/dist/runtime/migration-handler.d.mts +2 -2
  202. package/dist/runtime/migration-handler.mjs +2 -470
  203. package/dist/runtime/queues.mjs +1 -1
  204. package/dist/runtime/remote/binding-handler.mjs +62 -62
  205. package/dist/runtime/remote/index.mjs +16 -77
  206. package/dist/runtime/routing.d.mts +1 -4
  207. package/dist/runtime/routing.mjs +82 -218
  208. package/dist/runtime/sandbox-container.d.mts +2 -2
  209. package/dist/runtime/sandbox-container.mjs +2 -2
  210. package/dist/runtime/sandbox.d.mts +2 -2
  211. package/dist/runtime/sandbox.mjs +13 -6
  212. package/dist/runtime/storage.mjs +1 -1
  213. package/dist/runtime/validator.d.mts +1 -1
  214. package/dist/runtime/ws-server.d.mts +2 -3
  215. package/dist/runtime/ws-server.mjs +6 -28
  216. package/dist/runtime/ws.d.mts +1 -1
  217. package/dist/{sandbox-container-Bo0eiFKz.d.mts → sandbox-container-ChQRum-j.d.mts} +3 -1
  218. package/dist/{sandbox-container-C6ItmVuN.mjs → sandbox-container-DBKIqDEK.mjs} +12 -1
  219. package/dist/{sandbox-C5LFoJMf.d.mts → sandbox-q3waMc2T.d.mts} +1 -1
  220. package/dist/{scan-C3uDzz6J.mjs → scan-C0BMdmEd.mjs} +84 -7
  221. package/dist/{secret-BvtB7IjY.mjs → secret-B5J8bBsI.mjs} +62 -80
  222. package/dist/{serialize-BPvnNQuA.mjs → serialize-BtQyaYoC.mjs} +10 -4
  223. package/dist/{skills-BgVMvQdy.mjs → skills-BJsan98C.mjs} +2 -2
  224. package/dist/{subcommand-prompt-BSlnD1fI.mjs → subcommand-prompt-gQ-NDA-u.mjs} +38 -43
  225. package/dist/sveltekit.mjs +1 -1
  226. package/dist/validate-C9xtFOYR.mjs +2 -0
  227. package/dist/{validate-C9qJArv7.mjs → validate-CheZGRE7.mjs} +4 -8
  228. package/dist/version-metadata-DIrqEHQo.mjs +73 -0
  229. package/dist/{wrangler-D9KTuqnv.mjs → wrangler-BYs07Rxy.mjs} +119 -378
  230. package/dist/{ws-CChrrAU-.d.mts → ws-aKVYB-fA.d.mts} +1 -1
  231. package/dist/yarn-pnp-DLbEFMT0.mjs +92 -0
  232. package/docs/guide/auth.md +2 -0
  233. package/docs/guide/database/postgresql.md +2 -0
  234. package/docs/guide/database.md +2 -0
  235. package/docs/guide/durable-state.md +24 -0
  236. package/docs/guide/platform/administration/access.md +4 -0
  237. package/docs/guide/platform/administration/connected-apps.md +55 -0
  238. package/docs/guide/platform/installation/credentials.md +3 -1
  239. package/docs/guide/quickstart.md +2 -0
  240. package/docs/guide/sandboxes.md +2 -0
  241. package/docs/reference/api/deploy.md +23 -0
  242. package/docs/reference/api/pages.md +2 -0
  243. package/docs/reference/api.md +2 -1
  244. package/docs/reference/cli/database.md +9 -3
  245. package/docs/reference/cli/platform-installation.md +1 -1
  246. package/docs/reference/cli/setup.md +2 -0
  247. package/package.json +13 -16
  248. package/skills/void/SKILL.md +1 -0
  249. package/dist/auth-LMJcNESe.mjs +0 -2
  250. package/dist/cf-build-output-H9a97vME.mjs +0 -2
  251. package/dist/cf-user-agent-lKblH3zU.mjs +0 -17
  252. package/dist/client-tso2OfcG.mjs +0 -2
  253. package/dist/collect-DLyFDiKW.mjs +0 -2
  254. package/dist/config-5r-YpMC-.mjs +0 -2
  255. package/dist/config-B_ggY-IO.mjs +0 -89
  256. package/dist/config-BtSFvXZx.mjs +0 -2
  257. package/dist/config-write-AHGesphx.mjs +0 -61
  258. package/dist/deploy-Bqe1PYBw.mjs +0 -10458
  259. package/dist/deploy-VsWsVQkw.mjs +0 -2
  260. package/dist/dev-inbox-CK-UuPob.mjs +0 -297
  261. package/dist/discover-EDUf6JJw.mjs +0 -2
  262. package/dist/dist-_UUlL6bg.mjs +0 -2
  263. package/dist/env-validation-Dxdx_5wo.mjs +0 -951
  264. package/dist/gen-dA9hW7AV.mjs +0 -2
  265. package/dist/head-client-DzmJGN4C.mjs +0 -90
  266. package/dist/help-DfQYVfGY.mjs +0 -2
  267. package/dist/login-mx_ydhmp.mjs +0 -2
  268. package/dist/migrate-BHp07yJE.mjs +0 -2
  269. package/dist/operator-cmd-CwBB-1yb.mjs +0 -2
  270. package/dist/pages/head-client.d.mts +0 -13
  271. package/dist/pages/head-client.mjs +0 -2
  272. package/dist/platform-args-D4E1PjVw.mjs +0 -2
  273. package/dist/prepare-DRUV-g3X.mjs +0 -2
  274. package/dist/project-DedqCp59.mjs +0 -2
  275. package/dist/provision-Wu9ZBk9L.mjs +0 -2
  276. package/dist/resolve-project-BIeYs9Cw.mjs +0 -2
  277. package/dist/resolve-project-CP8rZs_p.mjs +0 -28
  278. package/dist/runner-mysql-CkFqZ6CE.mjs +0 -2
  279. package/dist/runner-pg-BGYRFdRp.mjs +0 -2
  280. package/dist/runtime/env-helpers.d.mts +0 -2
  281. package/dist/runtime/env-helpers.mjs +0 -2
  282. package/dist/validate-BJr9LfXy.mjs +0 -2
  283. package/dist/yarn-pnp-CUX_iTPA.mjs +0 -188
@@ -1,36 +1,21 @@
1
- import { a as join, n as dirname, o as normalize, t as basename, u as resolve$2 } from "./dist-BVqXeR_h.mjs";
1
+ import { a as join, c as resolve$2, n as dirname, o as normalize, t as basename } from "./dist-ipQi0Q8y.mjs";
2
2
  import { i as voidWarn, r as voidLog } from "./log-vqY3pqwI.mjs";
3
- import { _ as persistMaterializedWranglerConfig, j as writeProvisionedWranglerConfig, s as assertNoDuplicateMembers, y as readProvisionedBindingEntry } from "./wrangler-D9KTuqnv.mjs";
4
- import { n as scanWranglerDotenvKeys } from "./dotenv-BfU6eqFt.mjs";
5
- import { l as resolveCloudflareOperationArgv, n as decodeCloudflareOperationResult, r as encodeCloudflareOperation } from "./cloudflare-process-2-TfIEzB.mjs";
3
+ import { _ as persistMaterializedWranglerConfig, j as writeProvisionedWranglerConfig, s as assertNoDuplicateMembers, y as readProvisionedBindingEntry } from "./wrangler-BYs07Rxy.mjs";
4
+ import { n as scanWranglerDotenvKeys } from "./dotenv-CNazY3-w.mjs";
5
+ import { l as resolveCloudflareOperationArgv, n as decodeCloudflareOperationResult, r as encodeCloudflareOperation } from "./cloudflare-process-CeDWJRhj.mjs";
6
6
  import { createRequire } from "node:module";
7
7
  import { closeSync, existsSync, fsyncSync, lstatSync, openSync, readFileSync, readlinkSync, realpathSync, renameSync, unlinkSync, writeSync } from "node:fs";
8
8
  import { isRecord } from "@void/deploy-core";
9
9
  import { randomUUID } from "node:crypto";
10
10
  import { parse } from "jsonc-parser";
11
- import { types } from "node:util";
12
11
  import { spawn } from "node:child_process";
13
12
  import { resolve } from "node:path/posix";
14
13
  import { resolve as resolve$1 } from "node:path/win32";
15
14
  import lockfile from "proper-lockfile";
16
15
  //#region src/cli/provision.ts
17
16
  /**
18
- * Diff the DESIRED id-bearing resources against the ACTUAL bindings in the root
19
- * wrangler config, WITHOUT any remote/wrangler call. A resource counts as
20
- * provisioned ONLY when its binding entry exists with a REAL (non-placeholder)
21
- * identifier — the SAME predicate the provisioner's read-first uses:
22
- * - D1 `database_id` is a real UUID ({@link isRealD1Id}, not `'local'`);
23
- * - KV `id` is a real 32-hex ({@link isRealKvId}, not `'local'`);
24
- * - R2 `bucket_name` names a real bucket ({@link isRealStoredR2BucketName});
25
- * - Hyperdrive `id` is a real 32-hex ({@link isRealHyperdriveId}).
26
- *
27
- * Queues are NAME-bearing (no id in the config), so they are NOT part of this
28
- * id-drift check. A missing config file yields every desired resource as missing.
29
- *
30
- * Used by the deploy orchestrator to decide whether automatic provisioning is needed
31
- * and to verify that every id-bearing resource was satisfied afterward.
32
- * A malformed/duplicate-binding config makes {@link readProvisionedBindingEntry}
33
- * throw — fail closed, exactly as the provisioner would.
17
+ * Desired id-bearing resources whose binding has no real id in the root config, using the
18
+ * same rule as read-first. Reads only the local config; queues have no id and are skipped.
34
19
  */
35
20
  function checkCloudflareProvisionDrift(configPath, desired) {
36
21
  const config = readRootConfig(configPath);
@@ -76,22 +61,13 @@ const KV_ID_PLACEHOLDER = "local";
76
61
  const R2_BUCKET_NAME_PLACEHOLDER = "default";
77
62
  const D1_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
78
63
  const HEX32_ID_RE = /^[0-9a-f]{32}$/i;
79
- /** R2 bucket names ARE the identity: wrangler 4.131's `isValidR2BucketName`. */
64
+ /** R2 bucket-name grammar (wrangler's `isValidR2BucketName`). */
80
65
  const R2_BUCKET_NAME_RE = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
81
- /**
82
- * A D1 `database_id` that is a real (non-placeholder) hyphenated UUID. Exported so
83
- * the deploy orchestrator applies the SAME placeholder rule when deciding whether a
84
- * stored `database_name` names a real DB (a synced `database_id: "local"` must not
85
- * let its paired name become the production database identity).
86
- */
66
+ /** A real (non-placeholder) D1 `database_id`. */
87
67
  function isRealD1Id(value) {
88
68
  return typeof value === "string" && value !== D1_ID_PLACEHOLDER && D1_ID_RE.test(value);
89
69
  }
90
- /**
91
- * A KV namespace `id` that is a real (non-placeholder) 32-hex string. Exported so the
92
- * deploy orchestrator applies the SAME placeholder rule when checking whether two KV
93
- * bindings already share one provisioned namespace.
94
- */
70
+ /** A real (non-placeholder) KV namespace `id`. */
95
71
  function isRealKvId(value) {
96
72
  return typeof value === "string" && value !== KV_ID_PLACEHOLDER && HEX32_ID_RE.test(value);
97
73
  }
@@ -104,11 +80,8 @@ function isValidR2BucketNameFormat(value) {
104
80
  return typeof value === "string" && R2_BUCKET_NAME_RE.test(value);
105
81
  }
106
82
  /**
107
- * A STORED R2 `bucket_name` that names a REAL bucket, i.e. any non-empty string
108
- * other than the placeholder (`default`), unless `default` itself is desired.
109
- * `local` IS a real name here. Grammar is
110
- * deliberately not required: a grammar-invalid stored name that contradicts the desired
111
- * bucket must still fail closed as a contradiction, never be silently rewritten.
83
+ * A stored R2 `bucket_name` naming a real bucket: any non-empty string except the `default`
84
+ * placeholder (unless desired). Grammar is not checked, so a contradicting name still fails.
112
85
  */
113
86
  function isRealStoredR2BucketName(value, desiredName) {
114
87
  return typeof value === "string" && value.length > 0 && (value !== R2_BUCKET_NAME_PLACEHOLDER || value === desiredName);
@@ -118,16 +91,8 @@ const defaultLogger = {
118
91
  warn: (msg) => voidWarn(msg)
119
92
  };
120
93
  /**
121
- * The transport-redirecting env vars wrangler 4.131 honors. Each can point
122
- * wrangler's authenticated API transport at a DIFFERENT endpoint (or select a
123
- * different env-block/account) than the ONE this provision pinned:
124
- * - `CLOUDFLARE_API_BASE_URL` / `CF_API_BASE_URL` — override the API base URL directly
125
- * (`getCloudflareApiBaseUrlFromEnv`).
126
- * - `WRANGLER_API_ENVIRONMENT=staging` — routes to `api.staging.cloudflare.com`.
127
- * - `CLOUDFLARE_COMPLIANCE_REGION=fedramp_high` — routes to `api.fed.cloudflare.com`.
128
- * - `CLOUDFLARE_ENV` — selects a named `env.*` config block (different account/bindings).
129
- * We pin ONE resolved base explicitly (see {@link provisionEnv}) and fail closed when a
130
- * project dotenv would reselect one (see {@link assertNoTransportRedirectInProjectDotenv}).
94
+ * Env vars that move wrangler's API transport to another endpoint or select another config
95
+ * env. Provisioning pins one base ({@link provisionEnv}) and rejects them in project dotenv.
131
96
  */
132
97
  const TRANSPORT_REDIRECT_ENV_VARS = [
133
98
  "CLOUDFLARE_API_BASE_URL",
@@ -137,53 +102,17 @@ const TRANSPORT_REDIRECT_ENV_VARS = [
137
102
  "CLOUDFLARE_ENV"
138
103
  ];
139
104
  /**
140
- * Wrangler 4.131's diagnostic-output sinks that would PERSIST the raw provisioning
141
- * argv (including a Hyperdrive connection string, password and all) to disk:
142
- * - `WRANGLER_OUTPUT_FILE_PATH` / `WRANGLER_OUTPUT_FILE_DIRECTORY` — when either is set
143
- * (`getOutputFilePathFromEnv`/`getOutputFileDirectoryFromEnv`), wrangler's startup
144
- * middleware appends a `wrangler-session` entry with the VERBATIM
145
- * `command_line_args: argv` to that file (`writeOutput` in wrangler-dist/cli.js) — so
146
- * `hyperdrive create --connection-string=postgres://user:PASSWORD@…` lands on disk.
147
- * They are scrubbed from every provisioner child env ({@link provisionEnv}) and fenced in
148
- * the project dotenv ({@link assertNoTransportRedirectInProjectDotenv}) — wrangler reloads
149
- * dotenv into `process.env` BEFORE writing the session entry, so a dotenv-declared sink
150
- * would resurrect the leak. `WRANGLER_LOG_SANITIZE` (`getSanitizeLogs`, default true) is
151
- * PINNED to `true` instead: a truthy ambient value survives wrangler's dotenv reload
152
- * (dotenv-expand keeps an already-set truthy `process.env` value), so the pin cannot be
153
- * overridden into unsanitized logging of the secret-bearing API request.
105
+ * Wrangler session-output sinks. When set, wrangler writes the raw argv to disk, which can
106
+ * include a Hyperdrive password. They are scrubbed from the child env and rejected in project
107
+ * dotenv, which wrangler reloads before writing.
154
108
  */
155
109
  const OUTPUT_FILE_ENV_VARS = ["WRANGLER_OUTPUT_FILE_PATH", "WRANGLER_OUTPUT_FILE_DIRECTORY"];
156
110
  /**
157
- * Resolve the ONE Cloudflare API base URL this provision is pinned to, mirroring
158
- * wrangler 4.131's `getCloudflareApiBaseUrl` EXACTLY (wrangler-dist/cli.js) so the
159
- * Hyperdrive REST lister and the spawned wrangler agree on the endpoint:
160
- *
161
- * getCloudflareApiBaseUrl = (complianceConfig) =>
162
- * getCloudflareApiBaseUrlFromEnv() ??
163
- * `https://api${getComplianceRegionSubdomain(complianceConfig)}${getStagingSubdomain()}.cloudflare.com/client/v4`
164
- *
165
- * Order + semantics mirrored exactly:
166
- * 1. The DIRECT base override is evaluated FIRST, by PRESENCE (wrangler's env factory
167
- * checks `variableName in process.env`), with `CLOUDFLARE_API_BASE_URL` taking
168
- * precedence over the deprecated `CF_API_BASE_URL`. A present-but-EMPTY override is
169
- * returned AS-IS: `"" ?? derived` keeps the empty string (NULLISH, not falsy,
170
- * coalescing), so wrangler pins the empty base (its API calls then fail on the
171
- * unparsable URL) — we mirror that instead of silently substituting an endpoint.
172
- * 2. Only on the DERIVED branch are the staging/compliance selectors read — wrangler's
173
- * `??` short-circuits past `getComplianceRegionSubdomain`/`getStagingSubdomain` when a
174
- * direct base is present, so a direct base + conflicting compliance settings resolves
175
- * to the direct base in wrangler (NO conflict error) and must not be rejected here.
176
- * 3. On the derived branch both env selectors are choice-VALIDATED (wrangler's
177
- * `getProcessEnv` → `assertOneOf` throws on any present value outside the choices,
178
- * e.g. `WRANGLER_API_ENVIRONMENT=stagng` or an empty string), so an invalid selector
179
- * FAILS CLOSED instead of silently pinning public production.
180
- * 4. The config's own `compliance_region` VALUE is validated UNCONDITIONALLY — wrangler's
181
- * config validation (`isOneOf("public", "fedramp_high")` on the `compliance_region`
182
- * field) rejects an invalid config value for every command regardless of which branch
183
- * resolves the base.
184
- * Read ONCE from the REAL ambient `process.env` (which does NOT include the project `.env`
185
- * — Node never auto-loads it), so an ambient/CI pin is honored while a project dotenv
186
- * redirect is rejected up front by {@link assertNoTransportRedirectInProjectDotenv}.
111
+ * The one API base URL this provision uses, resolved like wrangler's `getCloudflareApiBaseUrl`
112
+ * so the Hyperdrive REST lister and wrangler agree:
113
+ * 1. a present `CLOUDFLARE_API_BASE_URL` (then `CF_API_BASE_URL`) is used as-is, even empty;
114
+ * 2. otherwise the staging and compliance selectors derive it, and invalid values fail;
115
+ * 3. the config's `compliance_region` is always validated.
187
116
  */
188
117
  function resolvePinnedApiBaseUrl(env = process.env, configComplianceRegion) {
189
118
  const configRegion = configComplianceRegion !== void 0 ? assertComplianceChoice(configComplianceRegion, "the wrangler config \"compliance_region\"") : void 0;
@@ -191,51 +120,27 @@ function resolvePinnedApiBaseUrl(env = process.env, configComplianceRegion) {
191
120
  if (direct !== void 0) return direct;
192
121
  return `https://api${resolveComplianceRegion(env, configRegion) === "fedramp_high" ? ".fed" : ""}${resolveApiEnvironment(env) === "staging" ? ".staging" : ""}.cloudflare.com/client/v4`;
193
122
  }
194
- /**
195
- * Mirror wrangler 4.131's `getCloudflareApiEnvironmentFromEnv` (env factory with
196
- * `choices: ["production", "staging"]`, default `"production"`): an ABSENT variable
197
- * defaults to production; a PRESENT value outside the choices — `"stagng"`, an empty
198
- * string — makes wrangler's `assertOneOf` throw, so we fail closed identically instead of
199
- * silently pinning public production where wrangler stops.
200
- */
123
+ /** `WRANGLER_API_ENVIRONMENT` like wrangler: absent means production; other values fail. */
201
124
  function resolveApiEnvironment(env) {
202
125
  const raw = env.WRANGLER_API_ENVIRONMENT;
203
126
  if (raw === void 0) return "production";
204
127
  if (raw !== "production" && raw !== "staging") throw new Error(`provision: the WRANGLER_API_ENVIRONMENT environment variable must be one of "production" or "staging", got ${JSON.stringify(raw)}. wrangler rejects this value, so provisioning refuses to guess an endpoint; fix or unset it and retry.`);
205
128
  return raw;
206
129
  }
207
- /** The compliance-region choices wrangler 4.131 accepts (`getCloudflareComplianceRegionFromEnv`). */
130
+ /** Compliance-region values wrangler accepts. */
208
131
  const COMPLIANCE_REGIONS = ["public", "fedramp_high"];
209
132
  function assertComplianceChoice(value, source) {
210
133
  if (value !== "public" && value !== "fedramp_high") throw new Error(`provision: ${source} must be one of ${COMPLIANCE_REGIONS.map((c) => JSON.stringify(c)).join(" or ")}, got ${JSON.stringify(value)}.`);
211
134
  return value;
212
135
  }
213
- /**
214
- * Reconcile the effective Cloudflare compliance region, mirroring wrangler 4.131's
215
- * `getCloudflareComplianceRegion(complianceConfig)` EXACTLY (evaluated only on the
216
- * DERIVED-base branch — with a direct base override wrangler never calls it):
217
- * - reads `CLOUDFLARE_COMPLIANCE_REGION` by PRESENCE and validates it against the
218
- * `public`/`fedramp_high` choices (wrangler's `getProcessEnv` → `assertOneOf`, which
219
- * throws on ANY present out-of-choices value — an empty string included);
220
- * - when BOTH the env var AND the (already-validated) config region are set to
221
- * DIFFERENT values, THROWS (fail closed) — wrangler raises a `UserError` for exactly
222
- * this conflict, so we must not paper over it by pinning one endpoint while the config
223
- * declares the other region;
224
- * - otherwise returns `env || config || "public"` (both values are validated choices by
225
- * now, so wrangler's falsy-coalescing is equivalent to nullish here).
226
- */
136
+ /** Effective compliance region like wrangler: values are validated and a conflict fails. */
227
137
  function resolveComplianceRegion(env, configRegion) {
228
138
  const rawEnv = env.CLOUDFLARE_COMPLIANCE_REGION;
229
139
  const envRegion = rawEnv !== void 0 ? assertComplianceChoice(rawEnv, "the CLOUDFLARE_COMPLIANCE_REGION environment variable") : void 0;
230
140
  if (envRegion !== void 0 && configRegion !== void 0 && envRegion !== configRegion) throw new Error(`provision: the Cloudflare compliance region is set to conflicting values — the CLOUDFLARE_COMPLIANCE_REGION environment variable is ${JSON.stringify(envRegion)} but the wrangler config "compliance_region" is ${JSON.stringify(configRegion)}. wrangler refuses to run with a mismatched compliance region; reconcile them (remove one, or set them equal) and retry.`);
231
141
  return envRegion ?? configRegion ?? "public";
232
142
  }
233
- /**
234
- * Mirror wrangler 4.131's `getDefaultEnvFiles(env)`: base `.env`/`.env.local`, then —
235
- * when the environment argument is DEFINED (we always pass `--env=`, so wrangler sees
236
- * `args.env === ""`, which is `!== undefined`) — the per-env pair `.env.${env}`/`.env.${env}.local`.
237
- * With the empty environment those are the empty-env filenames `.env.` and `.env..local`.
238
- */
143
+ /** Dotenv files wrangler loads for `--env=<env>`; provisioning always passes an empty env. */
239
144
  function defaultWranglerEnvFiles(env) {
240
145
  return [
241
146
  ".env",
@@ -245,20 +150,9 @@ function defaultWranglerEnvFiles(env) {
245
150
  ];
246
151
  }
247
152
  /**
248
- * FAIL CLOSED when the project's dotenv files declare a transport-redirecting
249
- * variable. wrangler 4.131 reloads `.env`/`.env.local` (and the dev-vars files) from the
250
- * project root into `process.env` on EVERY command with `override: true`, so a repo `.env`
251
- * setting `CLOUDFLARE_API_BASE_URL` / `WRANGLER_API_ENVIRONMENT` /
252
- * `CLOUDFLARE_COMPLIANCE_REGION` / `CLOUDFLARE_ENV` would redirect wrangler's authenticated
253
- * transport (and credentials) to a staging / FedRAMP / arbitrary endpoint AFTER we resolved
254
- * the pinned base — while the Hyperdrive existence check runs against the pinned base.
255
- * Single-account/single-endpoint provisioning cannot reason about a transport redirected
256
- * out from under it, so we refuse. The fix is to export the variable in the shell/CI
257
- * environment (which we DO honor, pinning both wrangler and the lister to it) instead of
258
- * the project dotenv.
259
- *
260
- * Exported for direct unit testing of the file-set and the Windows case rule; production
261
- * always calls it with the real `process.platform`.
153
+ * Fail when a project dotenv file sets a transport-redirect or session-output variable.
154
+ * Wrangler reloads these files on every command, which would move its authenticated transport
155
+ * away from the pinned base. Values exported in the shell are honored instead.
262
156
  */
263
157
  function assertNoTransportRedirectInProjectDotenv(root, platform = process.platform) {
264
158
  const dotenvCaseInsensitive = platform === "win32";
@@ -281,14 +175,8 @@ function assertNoTransportRedirectInProjectDotenv(root, platform = process.platf
281
175
  }
282
176
  }
283
177
  /**
284
- * Delete `name` from `env` IN PLACE, honoring the platform's env-key case rule.
285
- * Windows environment keys are CASE-INSENSITIVE: a spawned child's `process.env`
286
- * resolves `WRANGLER_OUTPUT_FILE_PATH` from an ambient `Wrangler_Output_File_Path`
287
- * too, so an exact-case `delete` leaves a mixed-case spelling live. On win32 every
288
- * case-insensitive spelling is removed; elsewhere POSIX env vars are case-sensitive,
289
- * so only the exact key is a match. Exported so the deploy orchestrator scrubs its
290
- * OWN extra deploy-time keys (worker-name override, build-config-path) through the
291
- * SAME rule the provisioner uses, instead of re-deriving it.
178
+ * Delete `name` from `env` in place. Windows env keys are case-insensitive, so every spelling
179
+ * is removed there; elsewhere only the exact key.
292
180
  */
293
181
  function deleteEnvVarCaseAware(env, name, platform = process.platform) {
294
182
  if (platform !== "win32") {
@@ -299,19 +187,8 @@ function deleteEnvVarCaseAware(env, name, platform = process.platform) {
299
187
  for (const key of Object.keys(env)) if (key.toLowerCase() === lower) delete env[key];
300
188
  }
301
189
  /**
302
- * Child-process env with every CF Access credential scrubbed. Mirrors `buildEnv`
303
- * in `deploy.ts`: Access credentials are needed only by this CLI's own guarded
304
- * HTTP requests and must never leak into the spawned wrangler process (which may
305
- * in turn run user hooks). This includes the short-lived cloudflared
306
- * `CF_ACCESS_TOKEN` JWT used by local readiness probes.
307
- *
308
- * Pins ONE transport context: scrubs every {@link TRANSPORT_REDIRECT_ENV_VARS}
309
- * from the child env, then re-sets `CLOUDFLARE_API_BASE_URL` to the SINGLE resolved
310
- * `apiBaseUrl` so the spawned wrangler and the Hyperdrive REST lister hit the exact same
311
- * endpoint. Scrubbing the compliance/staging/env selectors makes the explicit base
312
- * authoritative (they can no longer re-derive a different base). Combined with
313
- * {@link assertNoTransportRedirectInProjectDotenv} (which blocks a project dotenv from
314
- * repopulating any of them via wrangler's per-command reload), the pin cannot be moved.
190
+ * Child env for a Cloudflare operation. CF Access credentials, transport selectors and output
191
+ * sinks are scrubbed; the account, API base and sanitized logging are pinned.
315
192
  */
316
193
  function provisionEnv(ctx) {
317
194
  const env = { ...process.env };
@@ -344,53 +221,24 @@ function provisionEnv(ctx) {
344
221
  }
345
222
  return env;
346
223
  }
347
- /**
348
- * Hard per-command timeout for a single wrangler invocation. A hung wrangler must
349
- * NEVER hang the whole provision, so the default runner SIGKILLs a child that runs
350
- * past this and reports a HARD failure (a non-null signal — see
351
- * {@link normalizeRunWranglerResult}). With the ASYNC runner this bound is
352
- * INDEPENDENT of {@link LOCK_STALE_MS}: awaiting the child keeps the event loop free,
353
- * so `proper-lockfile`'s heartbeat refreshes the mutex throughout — the timeout only
354
- * bounds a hang, it is not load-bearing for lock safety.
355
- */
224
+ /** Per-command timeout; the default runner SIGKILLs a child that runs longer. */
356
225
  const COMMAND_TIMEOUT_MS = 12e4;
357
226
  /**
358
- * After a timeout SIGKILL, how long to keep confirming the child is ACTUALLY gone —
359
- * BOTH its `close` event AND whole-group disappearance (`kill(-pid, 0)` → ESRCH) — before
360
- * giving up. SIGKILL is uncatchable, so a healthy kernel reaps the group within
361
- * milliseconds; this generous bound only guards a pathological uninterruptible-sleep child.
362
- * The runner NEVER settles a timeout as "done" until both facts are confirmed; an expiry
363
- * (or a failed kill) REJECTS with a {@link WranglerQuarantineError} instead, so the
364
- * whole-provision lock — released only after a CONFIRMED settle — is intentionally
365
- * retained while the real wrangler CLI may still be creating resources.
227
+ * After a SIGKILL, how long to wait for both `close` and the whole process group to be gone.
228
+ * If that cannot be confirmed, the runner rejects with {@link WranglerQuarantineError}.
366
229
  */
367
230
  const CONFIRM_KILL_GRACE_MS = 5e3;
368
231
  /** The pid-poll interval while confirming post-SIGKILL termination. */
369
232
  const CONFIRM_KILL_POLL_MS = 20;
370
- /**
371
- * The margin the coordinator-WIDE teardown deadline adds on top of a
372
- * runner's own confirmation grace window: a signal teardown is bounded at
373
- * `confirmGraceMs + this` even if the runner's bounded confirmation never calls back.
374
- */
233
+ /** Extra time a signal teardown allows beyond a runner's confirmation window. */
375
234
  const SIGNAL_TEARDOWN_DEADLINE_MARGIN_MS = 5e3;
376
- /**
377
- * Classify a process-group kill error. `ESRCH` means the group ALREADY exited (there was
378
- * nothing left to kill) → success. ANY other code (`EPERM`, …) is a REAL kill failure: the
379
- * child may still be running, so it must be surfaced, never swallowed. Exported for direct
380
- * unit testing of the classification the timeout/cancel paths rely on.
381
- */
235
+ /** ESRCH means the group already exited; any other kill error is a real failure. */
382
236
  function isAlreadyGoneKillError(error) {
383
237
  return error?.code === "ESRCH";
384
238
  }
385
239
  /**
386
- * A QUARANTINE failure: the runner could NOT confirm that a spawned
387
- * wrangler child (and its whole process group) is dead — the group kill failed for a
388
- * non-ESRCH reason (EPERM, …), or the post-SIGKILL confirmation window expired with the
389
- * group still (possibly) alive. The child may STILL be creating resources / writing
390
- * config, so the whole-provision mutex must be INTENTIONALLY RETAINED — never released —
391
- * and this error surfaces with manual-recovery guidance naming the surviving pid.
392
- * {@link provisionCloudflareResources} detects it via {@link isQuarantineError} and calls
393
- * `lock.quarantine()` instead of `lock.release()`.
240
+ * The runner could not confirm that a spawned child and its process group are dead. The child
241
+ * may still be creating resources, so the provision lock is kept instead of released.
394
242
  */
395
243
  var WranglerQuarantineError = class extends Error {
396
244
  quarantine = true;
@@ -413,17 +261,8 @@ function acquireProcessProvisionSlot() {
413
261
  };
414
262
  }
415
263
  /**
416
- * The ONE active provision's lock-quarantine hook, 1:1 with the
417
- * provision slot above. When the parent process is about to DIE re-raising a forwarded
418
- * SIGINT/SIGTERM while a spawned wrangler child's teardown could NOT be confirmed,
419
- * proper-lockfile's signal-exit sweep would remove the still-TRACKED provision mutex —
420
- * releasing the lock under a possibly-live child. {@link provisionCloudflareResources}
421
- * sets this for the duration of the provision; a registering wrangler child CAPTURES it
422
- * at registration (see {@link registerRunner}) so an unresolved teardown quarantines
423
- * exactly ITS OWNING provision lock with ITS OWN pid metadata — never a broadcast
424
- * through every lock (the previous Set this replaces stamped the FIRST unresolved
425
- * registrant's pid into every lock's sidecar, so a foreign group's death could clear a
426
- * quarantine whose real child was alive).
264
+ * The active provision's lock-quarantine hook. A child captures it at registration, so a
265
+ * failed teardown quarantines only its own provision lock with its own pid.
427
266
  */
428
267
  let activeProvisionQuarantineHook;
429
268
  /** True when `error` is a quarantine failure whose provision lock must stay retained. */
@@ -493,8 +332,7 @@ function coordinatorHandleSignal(signal) {
493
332
  teardown.dispatching = false;
494
333
  maybeFinishCoordinatorTeardown(teardown);
495
334
  }
496
- /** Finish only after the initial dispatch fully completed AND every
497
- * snapshot registrant resolved (confirmed or quarantined). */
335
+ /** Finish after dispatch completes and every registrant is resolved. */
498
336
  function maybeFinishCoordinatorTeardown(teardown) {
499
337
  if (!teardown.dispatching && teardown.pending === 0) finishCoordinatorTeardown(teardown);
500
338
  }
@@ -554,12 +392,7 @@ function finishCoordinatorTeardown(teardown) {
554
392
  const RETENTION_RETRY_MIN_MS = 250;
555
393
  const RETENTION_RETRY_MAX_MS = 5e3;
556
394
  let retentionWatchdog;
557
- /**
558
- * Quarantine `lock`, and on a PERSISTENCE failure arm the retention
559
- * watchdog BEFORE rethrowing. THE single quarantine entry point for provision-level
560
- * code (the body-error path and the signal coordinator's hook both route through it),
561
- * so no persistence failure can leave the process free to drain unprotected.
562
- */
395
+ /** Quarantine `lock`; if persisting fails, arm the retention watchdog before rethrowing. */
563
396
  function retainQuarantinedLock(lock, info) {
564
397
  try {
565
398
  lock.quarantine(info);
@@ -610,20 +443,11 @@ function armRetentionWatchdog(lock, info) {
610
443
  };
611
444
  }
612
445
  /**
613
- * Default provider runner: launches the isolated typed operation entry through
614
- * {@link resolveCloudflareOperationArgv} with `shell: false`. Public request fields
615
- * travel as literal JSON argv; secrets travel through stdin. Captured stdout carries
616
- * the structured result envelope, while stderr carries provider diagnostics.
617
- *
618
- * ASYNC (returns a Promise). `spawn` + `await` (vs. the old blocking
619
- * `spawnSync`) keeps the Node event loop free while wrangler runs, so
620
- * `proper-lockfile`'s update timer keeps refreshing the mutex mtime for the WHOLE
621
- * provision — no wrangler call, however slow, can freeze the loop long enough for
622
- * another process to see the lock stale and steal it while we still hold it. A
623
- * {@link COMMAND_TIMEOUT_MS} SIGKILL guards against a hung child.
446
+ * Default runner: spawns the typed operation entry ({@link resolveCloudflareOperationArgv})
447
+ * without a shell; secrets go through stdin. It is async so the lock heartbeat keeps running.
624
448
  */
625
449
  function createDefaultRunWrangler(root, options) {
626
- const launcher = options?.launcher ?? resolveCloudflareOperationArgv(root);
450
+ const launcher = options?.launcher ?? resolveCloudflareOperationArgv();
627
451
  const timeoutMs = options?.timeoutMs ?? COMMAND_TIMEOUT_MS;
628
452
  const confirmGraceMs = options?.confirmKillGraceMs ?? CONFIRM_KILL_GRACE_MS;
629
453
  const killProcessGroup = options?.killProcessGroup ?? ((target, signal) => process.kill(target, signal));
@@ -867,14 +691,8 @@ function createDefaultRunWrangler(root, options) {
867
691
  });
868
692
  }
869
693
  /**
870
- * Normalize a `spawnSync` result into a {@link RunWranglerResult}, treating a
871
- * signal-killed child or a spawn error as a FAILURE — never success.
872
- *
873
- * The naive `status ?? (error ? 1 : 0)` collapses a SIGTERM'd child (which
874
- * returns `status: null`, a non-null `signal`, and NO `error`) to `0`, so a
875
- * killed `create` would be recorded as `created` though nothing happened. So we
876
- * fail on ANY non-numeric `status`, a non-null `signal`, or a present `error`,
877
- * and surface the signal/spawn-error text in `stderr` for diagnostics.
694
+ * Normalize a finished child into a {@link RunWranglerResult}. A signal, a spawn error or a
695
+ * non-numeric status is a non-zero failure, never success.
878
696
  */
879
697
  function normalizeRunWranglerResult(result) {
880
698
  const stdout = result.stdout ?? "";
@@ -891,12 +709,7 @@ function normalizeRunWranglerResult(result) {
891
709
  error: result.error != null ? result.error.message : null
892
710
  };
893
711
  }
894
- /**
895
- * THE single provenance rule. A result is a HARD failure when the child was
896
- * signal-killed or could not be spawned: it did not run to completion, so its
897
- * buffered status/stdout/stderr is unreliable and must NEVER be read as "absent"
898
- * or "success". Every success/absence/adopt classifier below defers to this.
899
- */
712
+ /** A signal-killed or unspawned child: its output is never read as success or absence. */
900
713
  function isHardFailure(result) {
901
714
  return result.signal != null || result.error != null;
902
715
  }
@@ -904,27 +717,13 @@ function isHardFailure(result) {
904
717
  function isCleanSuccess(result) {
905
718
  return !isHardFailure(result) && result.status === 0;
906
719
  }
907
- /**
908
- * The child ran to completion and reported a FAILURE status (a numeric non-zero
909
- * exit, no signal, no spawn error) — the ONLY case whose stdout/stderr may be
910
- * classified for a resource-specific not-found signal.
911
- */
720
+ /** A completed child with a non-zero exit: the only result that may mean "not found". */
912
721
  function isCleanFailure(result) {
913
722
  return !isHardFailure(result) && Number.isSafeInteger(result.status) && result.status > 0;
914
723
  }
915
- /**
916
- * The OVERALL deadline for the Hyperdrive existence lister (across ALL its paginated
917
- * requests). A stalled body or a never-settling injected seam must never hold the
918
- * whole-provision lock (whose heartbeat keeps refreshing while the loop is free) forever, so
919
- * the caller fails closed at this bound.
920
- */
724
+ /** Overall deadline for the Hyperdrive lister, so a stalled list cannot hold the lock forever. */
921
725
  const HYPERDRIVE_LIST_TIMEOUT_MS = 6e4;
922
- /**
923
- * Run a lister call under an OVERALL deadline. Builds one `AbortController`, hands its
924
- * signal to `start` (threaded into every paginated `fetch`), and races the returned promise
925
- * against a timer that ABORTS the signal AND rejects — so even a seam that ignores the signal
926
- * (never settling) can NOT hold the caller (and thus the provision lock) past `ms`.
927
- */
726
+ /** Run `start` under an overall deadline: abort and reject at `ms`, even if it ignores the signal. */
928
727
  function withListerDeadline(start, ms) {
929
728
  return new Promise((resolve, reject) => {
930
729
  const controller = new AbortController();
@@ -942,21 +741,16 @@ function withListerDeadline(start, ms) {
942
741
  });
943
742
  }
944
743
  /**
945
- * The Cloudflare API token the default Hyperdrive existence check authenticates with:
946
- * the caller-supplied one, else the ambient `CLOUDFLARE_API_TOKEN`. An empty value is
947
- * treated as absent. This is the ONE resolver — the up-front Hyperdrive fence and the
948
- * default lister below both use it, so the fence can never promise a check the lister
949
- * then declines to make.
744
+ * API token for the Hyperdrive REST check: the caller's, else `CLOUDFLARE_API_TOKEN`. Shared by
745
+ * the up-front fence and the default lister so they always agree.
950
746
  */
951
747
  function resolveHyperdriveApiToken(apiToken) {
952
748
  const token = apiToken ?? process.env.CLOUDFLARE_API_TOKEN;
953
749
  return typeof token === "string" && token.length > 0 ? token : void 0;
954
750
  }
955
751
  /**
956
- * Default Hyperdrive existence check: `GET /accounts/{id}/hyperdrive/configs`
957
- * with the CF API token, matched by name in the caller. Returns `undefined` when
958
- * it cannot be built (no account id / no token) — the caller then fails closed
959
- * before any blind create. Never called in unit tests — those inject a stub.
752
+ * Default Hyperdrive lister over the REST API. Returns `undefined` without a token, so the
753
+ * caller fails closed before a blind create.
960
754
  */
961
755
  function createDefaultListHyperdriveConfigs(apiToken) {
962
756
  const token = resolveHyperdriveApiToken(apiToken);
@@ -995,16 +789,8 @@ function createDefaultListHyperdriveConfigs(apiToken) {
995
789
  };
996
790
  }
997
791
  /**
998
- * The ONE strict Hyperdrive-list validator, applied at the CALLER after EITHER
999
- * lister returns (the default fetch OR an injected seam), so validation can never live
1000
- * only inside the default fetch. Validates EVERY member up front — BEFORE any name
1001
- * filtering: rejects any non-object member, empty/non-string `name`, and duplicate `id`,
1002
- * AND requires every member's `id` to be a REAL 32-hex Hyperdrive id (not merely
1003
- * non-empty). A malformed id on ANY member means the list is untrustworthy, so we fail
1004
- * closed rather than skip that member and mistake the target for absent. Then requires
1005
- * EXACTLY 0 or 1 exact-name match (>1 is ambiguous — Hyperdrive names are NOT
1006
- * account-unique — and fails closed) BEFORE any match/write. Returns the single
1007
- * exact-name match, or `undefined` when none matches.
792
+ * Validate a Hyperdrive list from any lister and return the config named `name`, if any. A
793
+ * malformed member, a bad or duplicate id, or more than one match fails closed.
1008
794
  */
1009
795
  function selectHyperdriveMatch(configs, name, configPath) {
1010
796
  const seenIds = /* @__PURE__ */ new Set();
@@ -1028,18 +814,8 @@ function quarantineSidecarPath(lockTarget) {
1028
814
  return `${lockTarget}.quarantine.json`;
1029
815
  }
1030
816
  /**
1031
- * Atomically persist the quarantine owner metadata: write a temp file,
1032
- * then `rename` over the final path, so a concurrent acquisition gate can never read
1033
- * partial JSON. On POSIX the spawned wrangler child is `detached` (its own process-group
1034
- * leader), so the recorded `pgid` IS its pid; Windows has no process groups (the gate
1035
- * probes the pid directly there).
1036
- *
1037
- * DURABLE: the temp file is fsync'd before the rename, the directory is
1038
- * fsync'd after it (see the classification below), and the final sidecar is READ
1039
- * BACK and verified. Any failure THROWS — callers treat persistence as a PRECONDITION
1040
- * for detaching the lock from proper-lockfile's tracking (see
1041
- * {@link ProvisionLock.quarantine}); a sidecar that merely "probably" landed is not a
1042
- * durable marker the acquisition gate can rely on.
817
+ * Persist quarantine metadata durably (temp file, fsync, rename, directory fsync), then read it
818
+ * back. Throws on any failure.
1043
819
  */
1044
820
  function writeQuarantineSidecar(sidecarPath, info, dirDurability) {
1045
821
  const payload = JSON.stringify({
@@ -1098,33 +874,11 @@ function readPositiveInt(value) {
1098
874
  return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : void 0;
1099
875
  }
1100
876
  /**
1101
- * The quarantine acquisition GATE. Every provision acquires its mutex
1102
- * through {@link acquireProvisionLock} (the single choke point — grep-proven: no other
1103
- * code calls `lockfile.lock`), and this gate runs BEFORE proper-lockfile is even
1104
- * consulted, so a QUARANTINED mutex can never be stolen by the mtime-stale path while
1105
- * the recorded wrangler process group may still be alive:
1106
- * - no sidecar → nothing quarantined → proceed to normal acquisition;
1107
- * - sidecar present → probe the recorded group (`kill(-pgid, 0)`; the plain pid where
1108
- * no group exists): ESRCH (confirmed dead) → clear the sidecar and proceed; still
1109
- * alive OR the probe fails (EPERM, no recorded pid, unreadable sidecar) → FAIL
1110
- * CLOSED with the recorded metadata + manual-recovery guidance. PID reuse can make
1111
- * a dead group probe "alive" — that keeps failing closed (the safe direction; the
1112
- * guidance covers manual clearance).
1113
- * Clearing touches ONLY the sidecar (unlink, ENOENT-tolerant — concurrent clearers are
1114
- * fine). The retained mutex DIRECTORY is deliberately NOT removed by hand: its
1115
- * heartbeat stopped at quarantine, so proper-lockfile's own stale lifecycle reclaims it
1116
- * during the acquisition below — a manual rmdir here could race a concurrent acquirer's
1117
- * fresh mutex (remove-then-acquire is not atomic across processes) and let two
1118
- * provisions hold the lock at once.
1119
- *
1120
- * This gate now ALWAYS runs under the RECOVERY mutex (see
1121
- * {@link acquireProvisionLock}), so its read IS the re-read-under-the-mutex every
1122
- * recoverer must base its decision on, and a clear may only remove the exact sidecar
1123
- * GENERATION it just inspected: the sidecar is re-read immediately before the unlink
1124
- * and the decision fails closed if the generation changed (a newer quarantine was
1125
- * persisted by the current main-mutex holder — whose quarantine writes are the one
1126
- * interleaving the recovery mutex cannot serialize — while this decision was pending).
1127
- * `onBeforeClear` is a test seam injecting exactly that interleaving deterministically.
877
+ * Quarantine gate, run under the recovery mutex before each lock attempt. With a sidecar
878
+ * present, the recorded group is probed: confirmed dead clears the sidecar, alive or unknown
879
+ * fails closed. Only the sidecar generation that was inspected is cleared; the mutex directory
880
+ * is left for proper-lockfile's stale handling, since removing it by hand could race another
881
+ * acquirer.
1128
882
  */
1129
883
  function assertQuarantineClearedOrClear(lockTarget, onBeforeClear) {
1130
884
  const sidecarPath = quarantineSidecarPath(lockTarget);
@@ -1176,28 +930,13 @@ function loadProperLockfileInternals() {
1176
930
  return;
1177
931
  }
1178
932
  }
1179
- /**
1180
- * `realpathSync` is `node:fs`, so it returns a NATIVE path — backslashes on Windows —
1181
- * while every other path in this module comes from `pathslash` and is POSIX-normalized,
1182
- * including the not-yet-created branch below (whose `join()` already normalizes). Without
1183
- * this, `canonicalizeConfigPath` hands back TWO different spellings of the same file
1184
- * depending only on whether it happens to exist yet, defeating the "ONE identity" contract
1185
- * the function exists to provide — and splitting the lock identity, the wrangler `-c` argv,
1186
- * and the paths printed in error messages. No-op off Windows, where `\` is a legal filename
1187
- * character that must survive byte-for-byte.
1188
- */
933
+ /** `realpathSync` returns backslashes on Windows; normalize so one file has one spelling. */
1189
934
  function toPosixConfigPath(nativePath) {
1190
935
  return process.platform === "win32" ? normalize(nativePath) : nativePath;
1191
936
  }
1192
937
  /**
1193
- * Canonicalize an already-absolute config path via `realpath` so the lock identity
1194
- * and every read/write/`-c` key on the REAL file, not a lexical symlink alias. When the
1195
- * config file EXISTS, its own realpath is returned (a symlink resolves to its target).
1196
- * When it does NOT yet exist, `realpath` would throw (ENOENT), so we canonicalize the
1197
- * PARENT directory (which normally exists — the project root) and rejoin the basename, so
1198
- * two aliases to the same not-yet-created config still resolve to one identity. If neither
1199
- * the file nor its parent can be canonicalized, the lexical path is returned unchanged (no
1200
- * worse than before, and the common case — an existing project dir — is always canonical).
938
+ * Canonical config path, so symlink aliases share one lock identity. A dangling symlink is
939
+ * followed; a missing file canonicalizes its parent directory instead.
1201
940
  */
1202
941
  function canonicalizeConfigPath(absoluteConfigPath, depth = 0) {
1203
942
  try {
@@ -1225,49 +964,22 @@ function canonicalizeConfigPath(absoluteConfigPath, depth = 0) {
1225
964
  }
1226
965
  }
1227
966
  /**
1228
- * A lock whose owner has not refreshed it within this window is treated as abandoned
1229
- * (crashed) and may be compromised/stolen, so a crashed provision cannot wedge every
1230
- * future one. A LIVE owner refreshes the mutex mtime every {@link LOCK_UPDATE_MS}
1231
- * (strictly less than this), so it never expires by age. Generous vs. a real
1232
- * provision's duration.
1233
- *
1234
- * CORRECTNESS — this heartbeat is a `setTimeout` on the Node event loop, so it only
1235
- * fires while the loop is FREE. The default runner is ASYNC (`spawn`, awaited), so no
1236
- * wrangler call blocks the loop; between/`during` every `await` the pending update timer
1237
- * runs and refreshes the mtime. Fast synchronous bookkeeping (JSON parse, small config
1238
- * reads) is « `LOCK_UPDATE_MS`, so the mtime is continuously refreshed and NO other
1239
- * process ever sees this lock stale → it can never be stolen while we hold it. (The old
1240
- * blocking `spawnSync` could freeze the loop past `LOCK_STALE_MS`, starving the
1241
- * heartbeat AND `onCompromised`, which is exactly the race this closes.)
967
+ * A lock not refreshed for this long counts as abandoned. A live owner refreshes it every
968
+ * {@link LOCK_UPDATE_MS}; this needs a free event loop, which is why the runner is async.
1242
969
  */
1243
970
  const LOCK_STALE_MS = 12e4;
1244
971
  /** Refresh interval keeping a live owner's lock fresh (must be < {@link LOCK_STALE_MS}). */
1245
972
  const LOCK_UPDATE_MS = 2e4;
1246
- /**
1247
- * Backoff budget while waiting for a held (non-stale) lock. Polls with jittered backoff
1248
- * for roughly a minute before giving up, so a concurrent provision blocks (not spins)
1249
- * until the holder releases, then proceeds.
1250
- */
973
+ /** Backoff while waiting for a held lock (about a minute). */
1251
974
  const LOCK_RETRIES = {
1252
975
  retries: 100,
1253
976
  factor: 1.5,
1254
977
  minTimeout: 200,
1255
978
  maxTimeout: 2e3
1256
979
  };
1257
- /**
1258
- * The stale window of the RECOVERY mutex (the small proper-lockfile
1259
- * lock serializing every gate→probe→clear→acquire→revalidate decision — see
1260
- * {@link acquireProvisionLock}). Deliberately SHORT: its critical section is a few
1261
- * synchronous fs reads plus one mkdir, so a crashed recoverer frees it within seconds
1262
- * (proper-lockfile's own heartbeat keeps a live recoverer's window fresh).
1263
- */
980
+ /** Stale window of the short-lived recovery mutex. */
1264
981
  const RECOVERY_LOCK_STALE_MS = 6e3;
1265
- /**
1266
- * Normalize the `retries` knob into the ONE backoff schedule OUR
1267
- * acquisition loop runs (proper-lockfile's internal retrying is disabled with
1268
- * `retries: 0` so the quarantine gate runs on EVERY attempt — see
1269
- * {@link acquireProvisionLock}). A bare number keeps {@link LOCK_RETRIES}' backoff shape.
1270
- */
982
+ /** Backoff schedule for our own retry loop (proper-lockfile runs with `retries: 0`). */
1271
983
  function normalizeLockRetries(retries) {
1272
984
  if (typeof retries === "number") return {
1273
985
  ...LOCK_RETRIES,
@@ -1280,52 +992,18 @@ function normalizeLockRetries(retries) {
1280
992
  maxTimeout: retries?.maxTimeout ?? LOCK_RETRIES.maxTimeout
1281
993
  };
1282
994
  }
1283
- /**
1284
- * Match the key spelling `proper-lockfile` stores when `realpath: false`.
1285
- *
1286
- * The library uses the host's native `node:path.resolve`, including backslashes on
1287
- * Windows. Most Void paths intentionally use `pathslash`, but its forward-slash output
1288
- * cannot address `proper-lockfile`'s internal registry on Windows.
1289
- */
995
+ /** The registry key proper-lockfile uses with `realpath: false` (native separators). */
1290
996
  function resolveProperLockfileKey(file, platform = process.platform) {
1291
997
  return platform === "win32" ? resolve$1(file) : resolve(file);
1292
998
  }
1293
999
  /**
1294
- * Acquire the cross-process provision lock over the resolved config path via
1295
- * `proper-lockfile` (an atomic `mkdir`-based mutex at `<configPath>.void-provision.lock.lock`).
1296
- * The library normally realpaths the pathname being locked, which requires it to exist.
1297
- * Both lock identities here are deliberately SYNTHETIC adjacent paths, so acquisition
1298
- * passes `realpath: false`: proper-lockfile resolves the identity lexically and creates
1299
- * only its temporary mutex directory — never an empty marker file in the user's project.
1300
- * This is safe because the config path was already canonicalized (including missing-file
1301
- * and symlink cases) before reaching this function. It also preserves the writer's
1302
- * missing-vs-empty config semantics. Returns a handle whose `release()` drops the mutex;
1303
- * ALWAYS call it in a `finally` so an interruption never leaks the lock.
1304
- *
1305
- * `onCompromised` FAILS CLOSED (re-throws): if the lock is ever detected stolen (its
1306
- * mtime changed, or the mutex vanished under a live owner), provisioning must NEVER
1307
- * continue — a compromised lock means another process may be racing the same config.
1000
+ * Acquire the provision lock (`<configPath>.void-provision.lock.lock`). The lock targets are
1001
+ * synthetic paths, so `realpath: false` avoids creating marker files; the config path is
1002
+ * already canonical. A compromised lock throws.
1308
1003
  *
1309
- * Acquisition is ONE atomic recovery protocol, applied on EVERY
1310
- * attempt: quarantine GATE → single non-retrying proper-lockfile acquisition →
1311
- * REVALIDATE the gate under ownership → clear-or-abort. Retrying is owned by THIS
1312
- * function (proper-lockfile runs with `retries: 0`), so a waiter that entered while the
1313
- * holder was healthy re-runs the gate on every backoff attempt and can never stale-take
1314
- * a mutex whose holder QUARANTINED mid-wait; the post-acquire revalidation catches a
1315
- * sidecar that appeared between the last gate and the acquisition itself (the fresh
1316
- * lock is released and the acquisition fails closed).
1317
- *
1318
- * The ENTIRE per-attempt protocol runs under a second small
1319
- * proper-lockfile RECOVERY mutex (`<lockTarget>.recovery`, `retries: 0`, short stale):
1320
- * without it, two recoverers could interleave ACROSS processes — B reads a dead sidecar
1321
- * S0, gets descheduled; A clears S0, acquires the main mutex, quarantines again writing
1322
- * a LIVE sidecar S1; B resumes and unlinks the PATHNAME (now S1) on its stale decision,
1323
- * then stale-reclaims A's retained mutex (the revalidation sees no sidecar). Under the
1324
- * recovery mutex every decision re-reads the sidecar after acquiring it, and the clear
1325
- * is additionally GENERATION-verified (see {@link assertQuarantineClearedOrClear}) for
1326
- * the one interleaving the recovery mutex cannot serialize (the current MAIN-mutex
1327
- * holder quarantining mid-decision). The recovery mutex deliberately does NOT take the
1328
- * caller's `fs` seam — that seam simulates main-mutex failures.
1004
+ * Each attempt runs under a short recovery mutex: quarantine gate, one non-retrying
1005
+ * acquisition, then the gate again under ownership. This loop owns retries, so the gate runs
1006
+ * on every attempt and a quarantined lock is never taken over by age.
1329
1007
  */
1330
1008
  async function acquireProvisionLock(configPath, lockOptions) {
1331
1009
  const lockTarget = `${configPath}.void-provision.lock`;
@@ -1427,39 +1105,13 @@ async function acquireProvisionLock(configPath, lockOptions) {
1427
1105
  }
1428
1106
  };
1429
1107
  }
1430
- /**
1431
- * Parse a wrangler `--json` stdout into an array, distinguishing a VALID JSON
1432
- * array (returns it, possibly empty) from unparseable/non-array output (returns
1433
- * `undefined`). Members are returned UNFILTERED — a malformed member (e.g. a
1434
- * `null`) is preserved, NOT silently dropped, so {@link validateResourceList}
1435
- * can fail closed on it (a dropped malformed member could BE the target and look
1436
- * like "absent", minting a duplicate). Used everywhere an empty list must mean
1437
- * "authoritatively absent" and garbage must NOT be coerced to "absent".
1438
- */
1439
- function parseJsonArrayStrict(value) {
1440
- return Array.isArray(value) ? value : void 0;
1441
- }
1442
- function parseJsonObject(value) {
1443
- return isRecord(value) ? value : void 0;
1444
- }
1445
- /**
1446
- * Read the single provisioned binding entry for `field`/`binding` from the resolved
1447
- * config, delegating to the STRICT canonical reader in `wrangler.ts`
1448
- * ({@link readProvisionedBindingEntry}). Unlike the old loose first-match `.find()`, this
1449
- * validates the target field's outer shape, fails closed on a DUPLICATE binding, and runs
1450
- * the worker-wide CROSS-TYPE collision check — so a
1451
- * duplicate/collision config can never be reported `reused` or pass a create postcondition.
1452
- */
1108
+ /** One binding entry, via the strict reader that fails on duplicate or colliding bindings. */
1453
1109
  function readBindingEntry(configPath, field, binding) {
1454
1110
  return readProvisionedBindingEntry(readRootConfig(configPath), field, binding, configPath);
1455
1111
  }
1456
1112
  /**
1457
- * Read + parse the root wrangler config (fresh each call — wrangler mutates it).
1458
- * BOM-aware (wrangler + `writeProvisionedWranglerConfig` strip a leading BOM before
1459
- * parsing, so we must too, else a BOM-prefixed config would look unparseable). FAILS CLOSED
1460
- * on a genuine parse error or a non-object root: never silently treat a real
1461
- * config as `{}`, which would miss existing ids (re-provision/orphan) and mask a
1462
- * corrupt file. A missing file is fine (nothing to read-first → `{}`).
1113
+ * Read the root config fresh (wrangler edits it), without a BOM. A parse error or a non-object
1114
+ * fails; a missing file reads as `{}`.
1463
1115
  */
1464
1116
  function readRootConfig(configPath) {
1465
1117
  if (!existsSync(configPath)) return {};
@@ -1471,27 +1123,13 @@ function readRootConfig(configPath) {
1471
1123
  if (!isRecord(parsed)) throw new Error(`provision: "${configPath}" must be a JSON object.`);
1472
1124
  return parsed;
1473
1125
  }
1474
- /**
1475
- * FAIL-CLOSED gate over a discovery/list/info result. Throws (no create) unless
1476
- * the child exited cleanly — a NUMERIC `status === 0`. Because
1477
- * {@link normalizeRunWranglerResult} already folds a signal-killed child or a
1478
- * spawn error into a non-zero status, a single numeric check here rejects ALL of
1479
- * nonzero-exit / SIGTERM / spawn-error / non-numeric status. MUST be called
1480
- * BEFORE reading provider data, so failed discovery never implies absence.
1481
- */
1126
+ /** Throw unless a discovery call exited cleanly, so a failed list never means "absent". */
1482
1127
  function assertDiscoverySucceeded(result, label) {
1483
1128
  if (!isCleanSuccess(result)) throw new Error(`provision: "${label}" failed (exit ${String(result.status)}): ${result.stderr || result.stdout || "no output"}. Cannot verify existing resources; refusing to create a possible duplicate.`);
1484
1129
  }
1485
1130
  /**
1486
- * STRICT list validator shared by KV + D1. Rejects the ENTIRE list (throws) if ANY
1487
- * member is not a well-formed object carrying a non-empty name AND a
1488
- * FORMAT-VALID id (per {@link ResourceListSpec.hasValidId}). A member is NEVER
1489
- * silently filtered, and a member with a malformed id is NEVER accepted, because
1490
- * either could BE the requested target (or signal a corrupt list) and treating it as
1491
- * "absent" would mint a duplicate. Validates EVERY member up front — BEFORE any
1492
- * name-filtering by the caller — so a nonmatching member with a bogus id can no longer
1493
- * pass the gate as authoritative absence. Returns the validated members (every one
1494
- * guaranteed to have a real id + name) on success.
1131
+ * Reject the whole list if any member lacks a non-empty name or a valid id. A malformed member
1132
+ * could be the target, so it is never filtered out as "absent".
1495
1133
  */
1496
1134
  function validateResourceList(list, spec) {
1497
1135
  const validated = [];
@@ -1521,25 +1159,9 @@ function reconcileD1IdAliases(entry) {
1521
1159
  };
1522
1160
  }
1523
1161
  /**
1524
- * THE single strict D1 identity normalizer, shared by `d1 list --json` and
1525
- * `d1 info <name> --json`. It reconciles the TWO name aliases (`name`,
1526
- * `database_name`) and TWO id aliases (`database_id`, `uuid`) — an EMPTY STRING is
1527
- * treated as ABSENT for each — and returns a usable id ONLY when the entry
1528
- * unambiguously IS the requested database:
1529
- * - `{ kind: 'other' }` — no non-empty name alias equals `requestedName`, so this
1530
- * entry is a different database (the caller skips it, never mistakes it for the
1531
- * target, and never adopts it under a normalization of a DIFFERENT name);
1532
- * - `{ kind: 'claimed-but-invalid' }` — a name alias DOES equal `requestedName`
1533
- * but the entry is ambiguous: CONFLICTING non-empty name aliases (e.g.
1534
- * `name:"wanted"` + `database_name:"other"`), OR not EXACTLY ONE distinct
1535
- * non-empty id (0 → no id; >1 → conflicting/blank uuid vs database_id). The
1536
- * caller fails closed (never adopt, never create a duplicate);
1537
- * - `{ kind: 'match', id }` — exactly one requested-name alias and exactly one
1538
- * unambiguous non-empty id.
1539
- * The old two-helper split (`normalizeD1Identity` preferring `database_name`,
1540
- * `d1EntryName` preferring `name`) let a `{name,database_name}` mismatch be
1541
- * SELECTED under one alias yet KEYED under the other. This collapses both into one
1542
- * exact-match rule so no sibling gap remains.
1162
+ * Strict D1 identity check shared by `d1 list` and `d1 info`. `other` when no name alias
1163
+ * (`name`, `database_name`) equals `requestedName`; `claimed-but-invalid` when one does but the
1164
+ * name or id aliases conflict; otherwise `match`.
1543
1165
  */
1544
1166
  function normalizeD1(entry, requestedName) {
1545
1167
  if (entry === void 0) return { kind: "other" };
@@ -1553,73 +1175,32 @@ function normalizeD1(entry, requestedName) {
1553
1175
  id: reconciled.id
1554
1176
  };
1555
1177
  }
1556
- /**
1557
- * `wrangler kv namespace list` → the `{ id }` of every namespace whose title
1558
- * matches. The list has ALREADY been through {@link validateResourceList} (every
1559
- * member has a non-empty string `id` + `title`), so this only filters + collects.
1560
- *
1561
- * A title-matching namespace whose `id` is NOT a real KV id (32-hex) is ambiguous:
1562
- * we can neither adopt it nor treat it as absent (which would mint a duplicate title), so
1563
- * we FAIL CLOSED. Real wrangler always returns 32-hex ids; this guards a malformed seam.
1564
- */
1565
- function extractKvMatches(list, title) {
1566
- const matches = [];
1567
- for (const ns of list) {
1568
- if (ns.title !== title) continue;
1569
- if (!isRealKvId(ns.id)) throw new Error(`provision: "wrangler kv namespace list" returned a namespace titled ${JSON.stringify(title)} with a malformed id ${JSON.stringify(ns.id)} (expected a 32-character hex namespace id). Cannot verify whether it already exists; refusing to create a possible duplicate.`);
1570
- matches.push({ id: ns.id });
1571
- }
1572
- return matches;
1573
- }
1574
1178
  /** True when a `d1 create` failure means the name is already taken (code 7502). */
1575
1179
  function isAlreadyExistsError(result) {
1576
1180
  return result.errorCode === 7502;
1577
1181
  }
1578
1182
  /**
1579
- * Not-found classifier shared by R2 + queues. Given an `<res> info`-by-name probe,
1580
- * returns `true` (confirmed absent → safe to create) ONLY on a clean non-zero exit
1581
- * with the provider's typed not-found result (R2 error code 10006; the queue
1582
- * operation's `not-found` failure). Everything else returns `false` so the caller
1583
- * fails closed — a signal/spawn failure, an auth/network/metrics error, or a
1584
- * GENERIC "not found" (e.g. `Account not found`) is NEVER treated as absence,
1585
- * which would mint a duplicate resource.
1183
+ * True only for a completed non-zero probe with the provider's typed not-found result (R2
1184
+ * code 10006, or the queue operation's `not-found`). Nothing else counts as absence.
1586
1185
  */
1587
1186
  function isConfirmedAbsent(result, kind) {
1588
1187
  return isCleanFailure(result) && (kind === "r2" ? result.errorCode === 10006 : result.failure === "not-found");
1589
1188
  }
1590
1189
  /** Only a completed, typed not-found response confirms queue absence. */
1591
- function isQueueConfirmedAbsent(result, _name) {
1190
+ function isQueueConfirmedAbsent(result) {
1592
1191
  return isConfirmedAbsent(result, "queue");
1593
1192
  }
1594
1193
  /** Reuse and post-create verification require clean success and the exact returned name. */
1595
1194
  function queueInfoConfirmsExists(result, name) {
1596
1195
  return isCleanSuccess(result) && isRecord(result.data) && result.data.name === name;
1597
1196
  }
1598
- /**
1599
- * Throw when the writer could not attach `migrations_dir` because no matching
1600
- * `d1_databases[]` entry exists. The provisioner only writes `migrations_dir`
1601
- * AFTER establishing the D1 entry (create/adopt/reuse), so a skip here means the
1602
- * D1 resource is unexpectedly absent from the config — never silently succeed
1603
- * with the gap unfilled.
1604
- */
1197
+ /** Throw when the writer found no D1 entry to attach `migrations_dir` to. */
1605
1198
  function assertD1MigrationsDirApplied(result, binding, configPath) {
1606
1199
  if (result.d1MigrationsDirSkipped) throw new Error(`provision: could not set migrations_dir for D1 binding ${JSON.stringify(binding)} — no matching d1_databases entry exists in "${configPath}" after provisioning it. The D1 resource was not written to the config as expected; inspect the file and retry.`);
1607
1200
  }
1608
1201
  /**
1609
- * Backstop — verify a create's POSTCONDITION, RESOURCE-SPECIFICALLY + identity
1610
- * checked. wrangler 4.131's `bin.wrangler` is a WRAPPER that spawns
1611
- * `wrangler-dist/cli.js` and maps a signal-killed child (`code === null`) to
1612
- * `process.exit(0)`, so `spawnSync` can see a `create` report "success" though the
1613
- * real CLI was killed and `--update-config` wrote NO id. After every config-writing
1614
- * create (d1/kv/r2/hyperdrive) reports success we RE-READ the resolved config and
1615
- * CONFIRM the target binding now holds a REAL id AND — where the resource's name is
1616
- * its identity (R2 `bucket_name`, D1 `database_name`) — that the recorded name EXACTLY
1617
- * matches the requested one; otherwise we FAIL CLOSED. A bare "some non-placeholder
1618
- * value" check is NOT enough: for R2, `bucket_name` IS the identity, so
1619
- * `{ bucket_name: 'other' }` would otherwise pass and bind the WRONG bucket. This also
1620
- * catches any partial/silent create failure, not only kills. (Queue creates write NO
1621
- * config, so they cannot be verified this way — a killed queue-create self-heals on
1622
- * the next read-first/probe run, which re-detects absence and re-creates.)
1202
+ * After a create reports success, re-read the config and require a real id, plus the exact
1203
+ * name where the name is the identity. A killed child can still report exit 0.
1623
1204
  */
1624
1205
  function assertCreateWroteRealId(configPath, spec, binding, name) {
1625
1206
  const entry = readBindingEntry(configPath, spec.field, binding);
@@ -1639,19 +1220,7 @@ function hasControlChar(value) {
1639
1220
  function assertNoOptionInjection(kind, name) {
1640
1221
  if (typeof name !== "string" || name.length === 0 || name.startsWith("-") || hasControlChar(name)) throw new Error(`provision: refusing to pass an unsafe ${kind} name ${JSON.stringify(name)} to wrangler. A name may not be empty, begin with "-" (it would be parsed as a CLI flag), or contain control characters. Rename the resource and retry.`);
1641
1222
  }
1642
- /**
1643
- * Per-resource Cloudflare naming GRAMMAR, verified 2026-07 against wrangler 4.107
1644
- * and live account resources:
1645
- * - `r2` — wrangler's own `isValidR2BucketName`: 3–63 chars, lowercase letters /
1646
- * digits / `-`, begin+end alphanumeric (DNS-like). This IS the identity.
1647
- * - `kvTitle` — the KV namespace positional is forwarded verbatim as the account TITLE;
1648
- * Cloudflare allows a broad charset INCLUDING SPACES (≤512 chars). We only
1649
- * forbid control chars (already covered by the injection guard) — spaces
1650
- * and mixed case are legal, so "My Own Namespace" is accepted.
1651
- * - `d1` / `hyperdrive` / `queue` — 1–63 chars, begin with a letter/digit, then
1652
- * letters / digits / `-` / `_` (matches every live D1 `name`, Hyperdrive
1653
- * config `name`, and Void's `QUEUE_<NAME>`-derived queue names).
1654
- */
1223
+ /** Per-resource Cloudflare naming grammar. KV titles may contain spaces and mixed case. */
1655
1224
  const RESOURCE_NAME_GRAMMARS = {
1656
1225
  r2: {
1657
1226
  re: R2_BUCKET_NAME_RE,
@@ -1679,34 +1248,13 @@ const RESOURCE_NAME_GRAMMARS = {
1679
1248
  rule: "be 1–63 characters, contain only letters, digits and \"-\", and begin and end with a letter or digit"
1680
1249
  }
1681
1250
  };
1682
- /**
1683
- * Validate a name destined for a wrangler ARGV positional: FIRST the universal
1684
- * option-injection guard, THEN the resource's own Cloudflare grammar. Fail closed on any
1685
- * violation, before the account gate or any wrangler/REST call.
1686
- *
1687
- * Exported — like {@link isQueueConfirmedAbsent} — so the deploy orchestrator's
1688
- * pre-provision queue probe (`cli/deploy.ts`) gates names on the SAME rules this
1689
- * provisioner enforces. Queue names
1690
- * are taken verbatim from filenames with no sanitization, so without this gate a name
1691
- * beginning with `-` reaches wrangler as a FLAG rather than a positional.
1692
- */
1251
+ /** Validate an argv positional: the option-injection guard, then the resource grammar. */
1693
1252
  function assertValidResourceName(kind, name) {
1694
1253
  assertNoOptionInjection(RESOURCE_NAME_GRAMMARS[kind].label, name);
1695
1254
  const grammar = RESOURCE_NAME_GRAMMARS[kind];
1696
1255
  if (!grammar.re.test(name)) throw new Error(`provision: refusing to pass an invalid ${grammar.label} name ${JSON.stringify(name)} to wrangler. A ${grammar.label} name must ${grammar.rule}. Rename the resource and retry.`);
1697
1256
  }
1698
- /**
1699
- * Build a redactor that strips connection-string secrets from every string the
1700
- * provisioner PROPAGATES (buffered wrangler stdout/stderr, error strings, logged
1701
- * warnings). Two layers:
1702
- * 1. the EXACT desired connection string (when this provision carries one) is replaced
1703
- * whole, so no derived message can echo it verbatim;
1704
- * 2. any URL userinfo password (`scheme://user:secret@…`) is masked generically, so a
1705
- * wrangler error that re-renders a connection string in ANY spelling still never
1706
- * leaks the password (the scheme + user survive for diagnostics).
1707
- * Applied at the single runWrangler choke point (every call site reads pre-redacted
1708
- * results) and to the Hyperdrive lister's propagated failure message.
1709
- */
1257
+ /** Redactor that replaces the exact connection string and masks any URL userinfo password. */
1710
1258
  function createSecretRedactor(connectionString) {
1711
1259
  return (text) => {
1712
1260
  let out = text;
@@ -1715,304 +1263,16 @@ function createSecretRedactor(connectionString) {
1715
1263
  return out;
1716
1264
  };
1717
1265
  }
1718
- /**
1719
- * The engine's own lazy `Error#stack` accessor pair, captured ONCE at
1720
- * module init. V8 defines `stack` as an own get/set accessor on every Error instance,
1721
- * sharing ONE getter/setter function across all of them — so FUNCTION IDENTITY proves
1722
- * "this is the engine's deterministic lazy-stack slot" (user code cannot forge these
1723
- * function identities). It is the ONLY accessor the in-place sanitizer may handle;
1724
- * every other accessor forces the inert fallback carrier.
1725
- */
1726
- const engineStackDescriptor = Object.getOwnPropertyDescriptor(/* @__PURE__ */ new Error(), "stack");
1727
- const ENGINE_STACK_GET = engineStackDescriptor?.get;
1728
- const ENGINE_STACK_SET = engineStackDescriptor?.set;
1729
- /**
1730
- * The ONLY prototypes a rebuilt carrier may have restored. Restoring an
1731
- * ARBITRARY prototype would reintroduce hostile behavior on the otherwise-inert carrier
1732
- * (a prototype getter or `toString` the carrier's readers would still hit), so an
1733
- * unknown prototype degrades to the base Error/Object/Array prototype the fresh carrier
1734
- * was built with. `WranglerQuarantineError` is included so a rebuilt quarantine carrier
1735
- * keeps its `instanceof` classification.
1736
- */
1737
- const KNOWN_SAFE_PROTOTYPES = /* @__PURE__ */ new Set([
1738
- Error.prototype,
1739
- TypeError.prototype,
1740
- RangeError.prototype,
1741
- ReferenceError.prototype,
1742
- SyntaxError.prototype,
1743
- EvalError.prototype,
1744
- URIError.prototype,
1745
- AggregateError.prototype,
1746
- WranglerQuarantineError.prototype,
1747
- Object.prototype,
1748
- Array.prototype
1749
- ]);
1750
- function tryRedactValue(value, redactText) {
1751
- try {
1752
- if (typeof value === "string") return {
1753
- ok: true,
1754
- value: redactText(value)
1755
- };
1756
- if (typeof value !== "object" || value === null) return {
1757
- ok: true,
1758
- value
1759
- };
1760
- if (!types.isProxy(value) && sanitizeInPlace(value, redactText)) return {
1761
- ok: true,
1762
- value
1763
- };
1764
- return {
1765
- ok: true,
1766
- value: deepSanitizedCopy(value, redactText)
1767
- };
1768
- } catch {
1769
- return { ok: false };
1770
- }
1771
- }
1772
- /**
1773
- * Attempt to redact `root` fully IN PLACE. Returns `true` only when EVERY string
1774
- * that needed redaction was verifiably rewritten (assignment read back); any immutable
1775
- * or unverifiable slot holding a secret returns `false` so the caller switches to the
1776
- * fallback-carrier copy. Partial rewrites applied before a `false` are harmless — they
1777
- * only ever REMOVE secret text, and the caller then discards the original anyway.
1778
- */
1779
- function sanitizeInPlace(root, redactText) {
1780
- const seen = /* @__PURE__ */ new WeakSet();
1781
- let ok = true;
1782
- const visitChild = (child) => {
1783
- if (typeof child === "object" && child !== null) visit(child);
1784
- };
1785
- const visit = (v) => {
1786
- if (!ok || seen.has(v)) return;
1787
- seen.add(v);
1788
- if (types.isProxy(v)) {
1789
- ok = false;
1790
- return;
1791
- }
1792
- if (v instanceof Map) {
1793
- for (const [key, val] of Array.from(v.entries())) {
1794
- const newKey = typeof key === "string" ? redactText(key) : key;
1795
- const newVal = typeof val === "string" ? redactText(val) : val;
1796
- visitChild(key);
1797
- visitChild(val);
1798
- if (newKey !== key) v.delete(key);
1799
- if (newKey !== key || newVal !== val) v.set(newKey, newVal);
1800
- if (!ok) return;
1801
- }
1802
- return;
1803
- }
1804
- if (v instanceof Set) {
1805
- for (const member of Array.from(v.values())) {
1806
- if (typeof member === "string") {
1807
- const red = redactText(member);
1808
- if (red !== member) {
1809
- v.delete(member);
1810
- v.add(red);
1811
- }
1812
- } else visitChild(member);
1813
- if (!ok) return;
1814
- }
1815
- return;
1816
- }
1817
- for (const key of Reflect.ownKeys(v)) {
1818
- const desc = Object.getOwnPropertyDescriptor(v, key);
1819
- if (!desc) continue;
1820
- if (desc.get !== void 0 || desc.set !== void 0) {
1821
- if (!(key === "stack" && ENGINE_STACK_GET !== void 0 && desc.get === ENGINE_STACK_GET && desc.set === ENGINE_STACK_SET)) {
1822
- ok = false;
1823
- return;
1824
- }
1825
- let current;
1826
- try {
1827
- current = desc.get !== void 0 ? desc.get.call(v) : void 0;
1828
- } catch {
1829
- ok = false;
1830
- return;
1831
- }
1832
- if (typeof current === "string") {
1833
- const red = redactText(current);
1834
- if (red !== current) {
1835
- if (desc.set === void 0) {
1836
- ok = false;
1837
- return;
1838
- }
1839
- try {
1840
- desc.set.call(v, red);
1841
- } catch {
1842
- ok = false;
1843
- return;
1844
- }
1845
- let after;
1846
- try {
1847
- const afterDesc = Object.getOwnPropertyDescriptor(v, key);
1848
- after = afterDesc?.get !== void 0 ? afterDesc.get.call(v) : afterDesc?.value;
1849
- } catch {
1850
- ok = false;
1851
- return;
1852
- }
1853
- if (after !== red) {
1854
- ok = false;
1855
- return;
1856
- }
1857
- }
1858
- } else visitChild(current);
1859
- if (!ok) return;
1860
- continue;
1861
- }
1862
- const val = desc.value;
1863
- if (typeof val === "string") {
1864
- const red = redactText(val);
1865
- if (red === val) continue;
1866
- if (desc.writable !== true) {
1867
- ok = false;
1868
- return;
1869
- }
1870
- try {
1871
- v[key] = red;
1872
- } catch {
1873
- ok = false;
1874
- return;
1875
- }
1876
- if (Object.getOwnPropertyDescriptor(v, key)?.value !== red) {
1877
- ok = false;
1878
- return;
1879
- }
1880
- } else {
1881
- visitChild(val);
1882
- if (!ok) return;
1883
- }
1884
- }
1885
- };
1886
- visit(root);
1887
- return ok;
1888
- }
1889
- /**
1890
- * The fallback CARRIER: a fully sanitized deep copy of `root`, built when in-place
1891
- * redaction is impossible. Fresh objects/arrays/Errors/Maps/Sets (all mutable), every
1892
- * string redacted, every own property — enumerable or not, string or symbol key —
1893
- * carried over as a plain data property, accessors snapshotted (an unreadable getter
1894
- * becomes `'[unredactable]'`), the original PROTOTYPE restored so `instanceof`
1895
- * classification (e.g. {@link WranglerQuarantineError}) survives the rebuild. Cycle-safe
1896
- * (a cycle in the original maps to the same cycle among the copies).
1897
- */
1898
- function deepSanitizedCopy(root, redactText) {
1899
- const copies = /* @__PURE__ */ new WeakMap();
1900
- const copy = (v) => {
1901
- if (typeof v === "string") return redactText(v);
1902
- if (typeof v !== "object" || v === null) return v;
1903
- if (copies.has(v)) return copies.get(v);
1904
- if (v instanceof Map) {
1905
- const out = /* @__PURE__ */ new Map();
1906
- copies.set(v, out);
1907
- for (const [key, val] of v.entries()) out.set(copy(key), copy(val));
1908
- return out;
1909
- }
1910
- if (v instanceof Set) {
1911
- const out = /* @__PURE__ */ new Set();
1912
- copies.set(v, out);
1913
- for (const member of v.values()) out.add(copy(member));
1914
- return out;
1915
- }
1916
- const out = Array.isArray(v) ? [] : v instanceof Error ? /* @__PURE__ */ new Error() : {};
1917
- const proto = Object.getPrototypeOf(v);
1918
- if (typeof proto === "object" && proto !== null && KNOWN_SAFE_PROTOTYPES.has(proto)) try {
1919
- Object.setPrototypeOf(out, proto);
1920
- } catch {}
1921
- copies.set(v, out);
1922
- for (const key of Reflect.ownKeys(v)) {
1923
- const desc = Object.getOwnPropertyDescriptor(v, key);
1924
- if (!desc) continue;
1925
- let val;
1926
- if (desc.get !== void 0 || desc.set !== void 0) try {
1927
- val = desc.get !== void 0 ? desc.get.call(v) : void 0;
1928
- } catch {
1929
- val = "[unredactable]";
1930
- }
1931
- else val = desc.value;
1932
- try {
1933
- Object.defineProperty(out, key, {
1934
- value: copy(val),
1935
- writable: true,
1936
- enumerable: desc.enumerable === true,
1937
- configurable: true
1938
- });
1939
- } catch {}
1940
- }
1941
- return out;
1942
- };
1943
- return copy(root);
1944
- }
1945
- /**
1946
- * Extract a SAFELY-READ, redacted one-line message from an unknown
1947
- * value, for logging. Never coerces an object (`String()`/template literals invoke an
1948
- * arbitrary — possibly hostile — `toString`): only primitives are stringified, and for
1949
- * objects only a plain string `message` field is read (inside the no-throw boundary; a
1950
- * throwing trap/getter degrades to the generic placeholder). THE one helper every
1951
- * logging path uses for unknown rejection values (grep-proven: the Hyperdrive lister
1952
- * warning and the rebuilt-carrier message below).
1953
- */
1954
- function safeRedactedErrorMessage(value, redactText) {
1955
- try {
1956
- if (typeof value === "string") return redactText(value);
1957
- if (value === null || value === void 0 || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
1958
- const message = value.message;
1959
- if (typeof message === "string") return redactText(message);
1960
- } catch {}
1961
- return "the rejection could not be rendered safely; its content was withheld";
1962
- }
1963
- /** The conservative carrier for a rejection that resists inspection. */
1964
- function unsafeInspectionQuarantineCarrier() {
1965
- const carrier = /* @__PURE__ */ new Error("provision: a propagated rejection could not be safely inspected (a property or prototype trap threw during redaction); its content was withheld. Treating it conservatively as an unconfirmed-wrangler-child (quarantine) failure: the whole-provision lock is retained, not released.");
1966
- Object.assign(carrier, {
1967
- quarantine: true,
1968
- pid: void 0
1969
- });
1970
- return carrier;
1971
- }
1972
- /**
1973
- * Redact a seam REJECTION with EVERYTHING — the quarantine
1974
- * classification included — inside the ONE no-throw boundary, GUARANTEEING:
1975
- * 1. this function NEVER throws (pre-fix, `isQuarantineError`'s `instanceof` ran on
1976
- * the ORIGINAL value before any boundary — a Proxy with throwing
1977
- * `getPrototypeOf`/property traps made the redactor itself throw a
1978
- * secret-bearing, classification-free replacement error, and the outer path then
1979
- * RELEASED the mutex under a possibly-live child);
1980
- * 2. if inspection is unsafe ANYWHERE (classification, redaction, message reads), it
1981
- * FAILS CLOSED AS QUARANTINE: a fresh INERT sanitized carrier marked
1982
- * `{ quarantine: true }` propagates, so the mutex is retained (conservative — the
1983
- * hostile value could have been hiding a real quarantine) and no trap error or
1984
- * secret ever escapes;
1985
- * 3. a quarantined rejection can never degrade into an ordinary failure: the
1986
- * classification + pid are captured inside the boundary and restored structurally
1987
- * on the carrier when a rebuild lost them.
1988
- */
1266
+ /** Redact a runner rejection, keeping the same Error object so quarantine fields survive. */
1989
1267
  function redactRejection(error, redactText) {
1990
- try {
1991
- const wasQuarantine = isQuarantineError(error);
1992
- const quarantinePid = wasQuarantine && typeof error.pid === "number" ? error.pid : void 0;
1993
- const attempt = tryRedactValue(error, redactText);
1994
- if (!attempt.ok) return unsafeInspectionQuarantineCarrier();
1995
- const redacted = attempt.value;
1996
- if (!wasQuarantine || isQuarantineError(redacted)) return redacted;
1997
- const carrier = redacted instanceof Error ? redacted : new Error(safeRedactedErrorMessage(redacted, redactText));
1998
- Object.assign(carrier, {
1999
- quarantine: true,
2000
- pid: quarantinePid
2001
- });
2002
- return carrier;
2003
- } catch {
2004
- return unsafeInspectionQuarantineCarrier();
2005
- }
1268
+ if (!(error instanceof Error)) return new Error(redactText(String(error)));
1269
+ error.message = redactText(error.message);
1270
+ if (typeof error.stack === "string") error.stack = redactText(error.stack);
1271
+ return error;
2006
1272
  }
2007
1273
  /**
2008
- * Ensure every resource in `desired` exists in the user's own Cloudflare account,
2009
- * creating the missing ones by shelling out to `wrangler` and letting
2010
- * `wrangler <res> create --update-config` write real ids into the root config.
2011
- * For resources that already exist (adopt path) — where `create` cannot run —
2012
- * the real id is captured from `wrangler <res> list/info` (or, for Hyperdrive,
2013
- * the account-list existence seam) and written through `writeProvisionedWranglerConfig`'s
2014
- * adopt fields. Pure provisioning: NO build, deploy, or drift-check. Idempotent +
2015
- * read-first: a binding already pointing at a real id is left untouched.
1274
+ * Ensure every desired resource exists in the user's Cloudflare account and record its id in
1275
+ * the root config, creating or adopting as needed. A binding with a real id is left as is.
2016
1276
  */
2017
1277
  async function provisionCloudflareResources(root, rootWranglerPath, desired, opts) {
2018
1278
  const releaseProvisionSlot = acquireProcessProvisionSlot();
@@ -2024,7 +1284,6 @@ async function provisionCloudflareResources(root, rootWranglerPath, desired, opt
2024
1284
  }
2025
1285
  /** The provision body, run while holding this process's single provision slot. */
2026
1286
  async function provisionWithProcessSlot(root, rootWranglerPath, desired, opts) {
2027
- await Promise.resolve();
2028
1287
  const configPath = canonicalizeConfigPath(resolve$2(root, rootWranglerPath));
2029
1288
  const lock = await acquireProvisionLock(configPath, opts?.lockOptions);
2030
1289
  const quarantineHook = (info) => retainQuarantinedLock(lock, info);
@@ -2101,8 +1360,8 @@ async function reconcileD1(desired, configPath, runWrangler, write, persistCreat
2101
1360
  configPath
2102
1361
  }, {});
2103
1362
  assertDiscoverySucceeded(listResult, "wrangler d1 list");
2104
- const rawList = parseJsonArrayStrict(listResult.data);
2105
- if (!rawList) throw new Error(`provision: "wrangler d1 list --json" did not return a JSON array; cannot verify whether D1 database ${JSON.stringify(name)} exists. Refusing to create a possible duplicate.`);
1363
+ const rawList = listResult.data;
1364
+ if (!Array.isArray(rawList)) throw new Error(`provision: "wrangler d1 list --json" did not return a JSON array; cannot verify whether D1 database ${JSON.stringify(name)} exists. Refusing to create a possible duplicate.`);
2106
1365
  const claimants = validateResourceList(rawList, {
2107
1366
  resource: "D1 database",
2108
1367
  command: "wrangler d1 list",
@@ -2168,7 +1427,7 @@ async function reconcileD1(desired, configPath, runWrangler, write, persistCreat
2168
1427
  configPath
2169
1428
  }, {});
2170
1429
  assertDiscoverySucceeded(infoResult, `wrangler d1 info ${name}`);
2171
- const info = normalizeD1(parseJsonObject(infoResult.data), name);
1430
+ const info = normalizeD1(isRecord(infoResult.data) ? infoResult.data : void 0, name);
2172
1431
  if (info.kind !== "match") throw new Error(`provision: "wrangler d1 create ${name}" reported the database already exists, but "wrangler d1 info ${name} --json" did not return a database with a matching name and an unambiguous id. Refusing to adopt an unverified database.`);
2173
1432
  log.info(`adopted existing D1 database ${name} (${info.id})`);
2174
1433
  assertD1MigrationsDirApplied(write({
@@ -2233,16 +1492,16 @@ async function reconcileKv(desired, configPath, runWrangler, write, persistCreat
2233
1492
  configPath
2234
1493
  }, {});
2235
1494
  assertDiscoverySucceeded(listResult, "wrangler kv namespace list");
2236
- const rawList = parseJsonArrayStrict(listResult.data);
2237
- if (!rawList) throw new Error(`provision: "wrangler kv namespace list" did not return a JSON array; cannot verify whether KV namespace ${JSON.stringify(title)} exists. Refusing to create a possible duplicate.`);
2238
- const matches = extractKvMatches(validateResourceList(rawList, {
1495
+ const rawList = listResult.data;
1496
+ if (!Array.isArray(rawList)) throw new Error(`provision: "wrangler kv namespace list" did not return a JSON array; cannot verify whether KV namespace ${JSON.stringify(title)} exists. Refusing to create a possible duplicate.`);
1497
+ const matches = validateResourceList(rawList, {
2239
1498
  resource: "KV namespace",
2240
1499
  command: "wrangler kv namespace list",
2241
1500
  hasValidId: (member) => isRealKvId(member.id),
2242
1501
  idRule: "its id is missing or not a well-formed 32-hex namespace id",
2243
1502
  nameField: "title",
2244
1503
  nameLabel: "titled"
2245
- }), title);
1504
+ }).filter((ns) => ns.title === title).map((ns) => ({ id: ns.id }));
2246
1505
  if (matches.length > 0) {
2247
1506
  const chosen = matches.reduce((min, ns) => ns.id < min.id ? ns : min);
2248
1507
  if (matches.length > 1) log.warn(`multiple KV namespaces titled "${title}" (${matches.map((m) => m.id).join(", ")}); adopting the lexicographically-smallest id ${chosen.id}`);
@@ -2303,8 +1562,8 @@ async function reconcileR2(desired, configPath, runWrangler, write, persistCreat
2303
1562
  configPath
2304
1563
  }, {});
2305
1564
  if (isCleanSuccess(info)) {
2306
- const payload = parseJsonObject(info.data);
2307
- if (!payload || payload.name !== bucketName) throw new Error(`provision: "wrangler r2 bucket info ${bucketName} --json" exited 0 but did not identify the requested bucket (expected name ${JSON.stringify(bucketName)}). Refusing to adopt an unverified bucket. Output: ${info.stdout || info.stderr}`);
1565
+ const payload = info.data;
1566
+ if (!isRecord(payload) || payload.name !== bucketName) throw new Error(`provision: "wrangler r2 bucket info ${bucketName} --json" exited 0 but did not identify the requested bucket (expected name ${JSON.stringify(bucketName)}). Refusing to adopt an unverified bucket. Output: ${info.stdout || info.stderr}`);
2308
1567
  log.info(`adopted existing R2 bucket ${bucketName}`);
2309
1568
  write({ r2: {
2310
1569
  binding,
@@ -2338,8 +1597,7 @@ async function reconcileR2(desired, configPath, runWrangler, write, persistCreat
2338
1597
  name: bucketName,
2339
1598
  configPath
2340
1599
  }, {});
2341
- const payload = isCleanSuccess(verify) ? parseJsonObject(verify.data) : void 0;
2342
- if (!payload || payload.name !== bucketName) throw new Error(`provision: "wrangler r2 bucket create ${bucketName}" reported success but a follow-up "wrangler r2 bucket info ${bucketName}" did not confirm the bucket exists. The create may have been interrupted — wrangler's launcher can mask a signal-killed child as exit 0, and the config entry is indistinguishable from the local-dev placeholder for this name. Refusing to record an unprovisioned bucket; inspect the account and retry.`);
1600
+ if (!isCleanSuccess(verify) || !isRecord(verify.data) || verify.data.name !== bucketName) throw new Error(`provision: "wrangler r2 bucket create ${bucketName}" reported success but a follow-up "wrangler r2 bucket info ${bucketName}" did not confirm the bucket exists. The create may have been interrupted — wrangler's launcher can mask a signal-killed child as exit 0, and the config entry is indistinguishable from the local-dev placeholder for this name. Refusing to record an unprovisioned bucket; inspect the account and retry.`);
2343
1601
  }
2344
1602
  persistCreatedConfig();
2345
1603
  resources.push({
@@ -2377,7 +1635,7 @@ async function reconcileHyperdrive(desired, configPath, runWrangler, write, pers
2377
1635
  validatedConfigs = result;
2378
1636
  existenceUnknown = false;
2379
1637
  } catch (error) {
2380
- log.warn(`Hyperdrive existence check for ${name} failed: ` + safeRedactedErrorMessage(error, redactSecrets));
1638
+ log.warn(`Hyperdrive existence check for ${name} failed: ` + redactSecrets(error instanceof Error ? error.message : String(error)));
2381
1639
  existenceUnknown = true;
2382
1640
  validatedConfigs = void 0;
2383
1641
  }
@@ -2466,12 +1724,7 @@ async function reconcileQueues(desired, configPath, runWrangler, resources) {
2466
1724
  });
2467
1725
  }
2468
1726
  }
2469
- /**
2470
- * The provision body, run entirely UNDER the whole-provision lock (see
2471
- * {@link provisionCloudflareResources}). `configPath` is the ONE resolved absolute
2472
- * config path the lock is keyed on — threaded through read-first, wrangler `-c`, and
2473
- * the writer so reads/writes can never hit different files.
2474
- */
1727
+ /** The provision body, run under the lock with the canonical config path. */
2475
1728
  async function provisionCloudflareResourcesLocked(root, configPath, desired, opts) {
2476
1729
  if (existsSync(configPath)) {
2477
1730
  const raw = readFileSync(configPath, "utf-8");
@@ -2541,4 +1794,4 @@ async function provisionCloudflareResourcesLocked(root, configPath, desired, opt
2541
1794
  };
2542
1795
  }
2543
1796
  //#endregion
2544
- export { resolvePinnedApiBaseUrl as _, checkCloudflareProvisionDrift as a, enableD1ReadReplicationViaApi as c, isQueueConfirmedAbsent as d, isRealD1Id as f, provisionEnv as g, provisionCloudflareResources as h, assertValidResourceName as i, isAlreadyGoneKillError as l, normalizeRunWranglerResult as m, acquireProvisionLock as n, createDefaultRunWrangler as o, isRealKvId as p, assertNoTransportRedirectInProjectDotenv as r, deleteEnvVarCaseAware as s, WranglerQuarantineError as t, isQuarantineError as u, resolveProperLockfileKey as v };
1797
+ export { deleteEnvVarCaseAware as a, isRealKvId as c, resolvePinnedApiBaseUrl as d, createDefaultRunWrangler as i, provisionCloudflareResources as l, assertValidResourceName as n, isQueueConfirmedAbsent as o, checkCloudflareProvisionDrift as r, isRealD1Id as s, assertNoTransportRedirectInProjectDotenv as t, provisionEnv as u };