void 0.20.3 → 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/agents-gni4eqBu.mjs +111 -0
- package/dist/auth-3sGB0zJ1.mjs +22 -0
- package/dist/{auth-DPl6kck4.mjs → auth-B9_D6ygs.mjs} +6 -241
- package/dist/auth-CAw7zHqj.mjs +2 -0
- package/dist/auth-client-BWBT8HLp.mjs +6 -0
- package/dist/auth-client-Bawdj38n.d.mts +7 -0
- package/dist/auth-client-react-7GFffu8R.d.mts +7 -0
- package/dist/auth-client-react-CMLwT2xI.mjs +6 -0
- package/dist/auth-client-solid-DyTFL4cq.d.mts +7 -0
- package/dist/auth-client-solid-UoreJWZG.mjs +6 -0
- package/dist/auth-client-svelte-Cv_WvrRk.mjs +6 -0
- package/dist/auth-client-svelte-zetW0KIH.d.mts +7 -0
- package/dist/auth-client-vue-CFk7Xbv3.mjs +6 -0
- package/dist/auth-client-vue-bChShbQP.d.mts +7 -0
- package/dist/{auth-cmd-CzwquNiP.mjs → auth-cmd-g_ymMkUe.mjs} +5 -5
- package/dist/{auth-link-ElDTgF7j.mjs → auth-link-DFvxIyZi.mjs} +5 -5
- package/dist/{better-auth-shared-DSCeohOK.d.mts → better-auth-shared-BoVwA5Vm.d.mts} +1 -6
- package/dist/{better-auth-shared-CYw1T3k4.mjs → better-auth-shared-syGYYmnY.mjs} +1 -1
- package/dist/{build-cmd-BpJe6boP.mjs → build-cmd-wJAv808h.mjs} +6 -4
- package/dist/{cache-D98YTqeE.mjs → cache-Be0Fu5Ka.mjs} +6 -4
- package/dist/{cancel-deploy-CPbEQLMG.mjs → cancel-deploy-BgmyOwhe.mjs} +5 -3
- package/dist/cf-access-rAZxzMkL.mjs +181 -0
- package/dist/cf-build-output-CTdlo6Rt.mjs +520 -0
- package/dist/cli/cf-compat.d.mts +1 -0
- package/dist/cli/cf-compat.mjs +944 -0
- package/dist/cli/cli.mjs +60 -38
- package/dist/cli/env-schema-probe.mjs +3 -3
- package/dist/client-DAAivdid.mjs +2 -0
- package/dist/{client-BQBrZoCX.mjs → client-PdAJ-F0t.mjs} +6 -12
- package/dist/{cloudflare-auth-6M5llVPC.mjs → cloudflare-auth-BCmTc1X_.mjs} +13 -44
- package/dist/{cloudflare-cmd-4RPGN3KB.mjs → cloudflare-cmd-D6PrKn7o.mjs} +4 -7
- package/dist/{cloudflare-connect-t1UU5svD.mjs → cloudflare-connect-DloREDlc.mjs} +6 -6
- package/dist/cloudflare-operations-BHNJVDbN.mjs +2 -0
- package/dist/{cloudflare-operations-BzWnlC1_.mjs → cloudflare-operations-CPEdHYhM.mjs} +37 -39
- package/dist/cloudflare-user-output-Q-k0QoNQ.mjs +20 -0
- package/dist/collect-DAUItMDS.mjs +2 -0
- package/dist/collect-DXHNWHcT.mjs +48 -0
- package/dist/config--T87TD8T.mjs +2 -0
- package/dist/{config-NOG_U1aK.mjs → config-BSe70f4T.mjs} +4 -6
- package/dist/config-DDIFxQYx.mjs +2 -0
- package/dist/{config-uNGuFsI2.mjs → config-Dxr6cTXn.mjs} +22 -37
- package/dist/config-DywxBLQC.d.mts +185 -0
- package/dist/config-entry.d.mts +6 -0
- package/dist/config-entry.mjs +7 -0
- package/dist/config-uP7ZDtVZ.mjs +21 -0
- package/dist/config-write-y3CBI_ux.mjs +60 -0
- package/dist/{connect-WCQZ_u3m.mjs → connect-LnvW4HKx.mjs} +8 -6
- package/dist/{create-project-D0oXA090.mjs → create-project-BZBl_gQ0.mjs} +8 -23
- package/dist/create-project-JV9-6ICF.mjs +2 -0
- package/dist/database-provider-Cx525bwX.mjs +6 -0
- package/dist/database-provider.mjs +1 -5
- package/dist/{db-DJ-9qs3S.mjs → db-Mzv88E1C.mjs} +48 -44
- package/dist/{delete-BZ4-WaGm.mjs → delete-Ri6JemSU.mjs} +6 -4
- package/dist/deploy-DAH2-m_-.mjs +2 -0
- package/dist/{deploy-BAhhcg5q.mjs → deploy-DEsMVrCY.mjs} +796 -198
- package/dist/discover-BBzDZe_o.mjs +2 -0
- package/dist/{discover-xvfrgJeo.mjs → discover-C4O6YxVS.mjs} +3 -8
- package/dist/{dist-BrsS7cai.mjs → dist-4WkAWhWx.mjs} +1 -15
- package/dist/{dist-m40_XgNh.mjs → dist-Bn8Kodjp.mjs} +1 -1
- package/dist/dist-C5fND3R0.mjs +2 -0
- package/dist/dist-D7-nEOXi.mjs +2 -0
- package/dist/{output-B0cfNSx5.mjs → dist-Dn6nn2IU.mjs} +3 -926
- package/dist/{domain-BxAyhxXN.mjs → domain-BA37Ye7T.mjs} +7 -5
- package/dist/{route-types-Da-DpyUp.mjs → drizzle-Beb2Am5S.mjs} +1 -280
- package/dist/{email-Bj7Cvdwp.mjs → email-C5NsxrQG.mjs} +14 -12
- package/dist/{email-Ce6SQq-i.mjs → email-C5kaZXzJ.mjs} +2 -2
- package/dist/{entry-DU3oDoQ3.mjs → entry-DdRFGK0y.mjs} +2 -2
- package/dist/{env-DBKmK4vc.mjs → env-DX_v-Q-v.mjs} +1 -1
- package/dist/{env-DP_EErve.mjs → env-U_ohASB0.mjs} +9 -7
- package/dist/env-Yz4HcvHs.mjs +78 -0
- package/dist/env-helpers--wFmQ_5Q.mjs +136 -0
- package/dist/{env-types-BNPhro-M.mjs → env-types-CWDtqHgw.mjs} +6 -2
- package/dist/{env-validation-CF6KvTRf.mjs → env-validation-BsFEXps5.mjs} +19 -28
- package/dist/env-validation-DIDGM7h4.mjs +2 -0
- package/dist/fetch-CXDChK7B.mjs +18 -0
- package/dist/fetch-_SeGZao9.d.mts +57 -0
- package/dist/fetch-stream-AOByI7Ki.mjs +81 -0
- package/dist/fetch-stream-Bjf0hoZb.d.mts +49 -0
- package/dist/gen-B87rlalt.mjs +2 -0
- package/dist/{gen-B_wPnVTK.mjs → gen-pg-Ojg8Y.mjs} +13 -11
- package/dist/{generate-RTK8_kK1.mjs → generate-C0VY6RVf.mjs} +2 -2
- package/dist/{github-cmd-C-z_xRrQ.mjs → github-cmd-DsrkweIl.mjs} +6 -4
- package/dist/{handler-D1hLsObx.d.mts → handler-BXJTXd02.d.mts} +6 -1
- package/dist/handler-DghKr6dU.mjs +150 -0
- package/dist/head-D_QRR5Yd.mjs +112 -0
- package/dist/head-client-DzmJGN4C.mjs +90 -0
- package/dist/{headers-BAHwgHdW.mjs → headers-B_HBMgi0.mjs} +2 -2
- package/dist/help-B403BLBB.mjs +2 -0
- package/dist/{help-CwOX-zmI.mjs → help-sBhFH6pi.mjs} +17 -12
- package/dist/index.d.mts +2 -20
- package/dist/index.mjs +116 -60
- package/dist/{init-BGktCXgA.mjs → init-C--Yyj1b.mjs} +49 -50
- package/dist/{link-D2kbqhWb.mjs → link-BC-mNG9-.mjs} +7 -5
- package/dist/{list-CvkK_G7k.mjs → list-DHU1Wj6c.mjs} +7 -5
- package/dist/live-CB1y5IuC.mjs +411 -0
- package/dist/live-CKiJilLr.d.mts +105 -0
- package/dist/local-d1-DzykTWY8.mjs +104 -0
- package/dist/login-BwiopVdg.mjs +2 -0
- package/dist/{login-WIjNc77c.mjs → login-jKe_0QZL.mjs} +6 -11
- package/dist/{logs-dLUFCapG.mjs → logs-BG11f5PR.mjs} +6 -4
- package/dist/migrate-BV8qHiCb.mjs +285 -0
- package/dist/migrate-BXY3B3m7.mjs +2 -0
- package/dist/migration-handler-DM4clYj5.d.mts +51 -0
- package/dist/{neon-DHwd2zvC.mjs → neon-n74ta1Pr.mjs} +1 -1
- package/dist/{node-Ez5KW5rn.mjs → node-Cupyf7-s.mjs} +6 -6
- package/dist/{operator-auth-B3e08unv.mjs → operator-auth-BkVgJqv-.mjs} +2 -2
- package/dist/{operator-client-LUZnlnYk.mjs → operator-client-A0iex2yi.mjs} +2 -1
- package/dist/{operator-cmd-CKJ7xIRs.mjs → operator-cmd-BwAS2XZt.mjs} +6 -6
- package/dist/output-CCH48AMM.mjs +146 -0
- package/dist/{package-json-CPoWX79C.mjs → package-json-iCbMg5XF.mjs} +1 -1
- package/dist/pages/client.d.mts +5 -2
- package/dist/pages/client.mjs +5 -3
- package/dist/pages/head-client.mjs +1 -89
- package/dist/pages/head.mjs +1 -111
- package/dist/pages/index.d.mts +2 -3
- package/dist/pages/index.mjs +7 -7
- package/dist/pages/islands-plugin.mjs +2 -2
- package/dist/pages/prefetch.d.mts +2 -30
- package/dist/pages/prefetch.mjs +1 -89
- package/dist/pages/protocol.d.mts +2 -2
- package/dist/pages/protocol.mjs +3 -3
- package/dist/pages/serialize.d.mts +2 -9
- package/dist/pages/serialize.mjs +1 -13
- package/dist/plan-BEZ8VJW0.mjs +256 -0
- package/dist/plan-DpuOr14e.mjs +2 -0
- package/dist/{platform-auth-config-CdVWRRJr.mjs → platform-auth-config-C-hv-_Ok.mjs} +6 -6
- package/dist/{platform-auth-protection-Drl0qhrn.mjs → platform-auth-protection-DjTE5Hj-.mjs} +7 -5
- package/dist/{platform-auth-recovery-CmKEWpDo.mjs → platform-auth-recovery-Cr0r8TEb.mjs} +6 -5
- package/dist/{platform-cmd-5q_k56xS.mjs → platform-cmd-0tEh2ZtA.mjs} +8 -5
- package/dist/platform-cmd-DE6dw45v.mjs +2 -0
- package/dist/{platform-domain-4GiDlcqx.mjs → platform-domain-B_7x6Iqx.mjs} +4 -3
- package/dist/platform-lifecycle-Dhx9Pnub.mjs +2 -0
- package/dist/{platform-lifecycle-R9xAxvtG.mjs → platform-lifecycle-Di0LbhPM.mjs} +208 -37
- package/dist/platform-management-B9LUtMt9.mjs +2 -0
- package/dist/{platform-management-BfWsXHEW.mjs → platform-management-eaiaU3uM.mjs} +8 -5
- package/dist/{platform-recovery-CbK-I1FB.mjs → platform-recovery-BxfA8E5C.mjs} +3 -3
- package/dist/platform-registry-BJbgZLS1.mjs +431 -0
- package/dist/{plugin-inference-BDRfZngg.mjs → plugin-inference-DsvtJLll.mjs} +4 -4
- package/dist/prefetch-Bsc_Pb6c.mjs +90 -0
- package/dist/prefetch-Ce6la4EI.d.mts +31 -0
- package/dist/prepare-D4CkM3_v.mjs +2 -0
- package/dist/{prepare-blNRQvQl.mjs → prepare-_T-Haxrr.mjs} +3 -2
- package/dist/{prepare-CtDJjoOj.mjs → prepare-pcWcxSCh.mjs} +13 -11
- package/dist/prerender-render-Cf_WDE9W.mjs +111 -0
- package/dist/prerender-render.mjs +1 -110
- package/dist/{preset-lAy0B0BQ.mjs → preset-Dowh9tTt.mjs} +16 -118
- package/dist/project-BEBFDFLz.mjs +2 -0
- package/dist/project-CWNIPoXc.mjs +209 -0
- package/dist/{project-cmd-CTdmnzvc.mjs → project-cmd-DrnRJdep.mjs} +18 -16
- package/dist/{project-paths-SK8nMHPp.mjs → project-paths-CKQ-Q5JS.mjs} +47 -14
- package/dist/project-slug-23TpquG4.mjs +8 -0
- package/dist/project-slug-DofjTFd-.mjs +2 -0
- package/dist/{project-team-CGxsQe3_.mjs → project-team-CzRbO_kA.mjs} +6 -4
- package/dist/{project-token-Cirx7uwZ.mjs → project-token-Bwxjf4y6.mjs} +6 -4
- package/dist/{project-tsconfig-Ql2XsSQp.mjs → project-tsconfig-CwfqUnVp.mjs} +2 -2
- package/dist/{protocol-C-pqYJjE.d.mts → protocol-ZH3jP4a7.d.mts} +1 -1
- package/dist/providers-BNKRacMr.d.mts +7 -0
- package/dist/provision-CNgEBkVA.mjs +3 -0
- package/dist/{provision-CSJOjjQk.mjs → provision-Cck2m3jJ.mjs} +11 -25
- package/dist/queues-BWKt1Xo4.d.mts +7 -0
- package/dist/{requests-4Nq59hOr.mjs → requests-DwrqUQZ8.mjs} +5 -3
- package/dist/resolve-project-BTotl8Nn.mjs +2 -0
- package/dist/{resolve-project--Vxawf7z.mjs → resolve-project-Xvis70DG.mjs} +2 -8
- package/dist/response-Tn7rU0MV.mjs +30 -0
- package/dist/{rollback-Dr7u0Ljx.mjs → rollback-B4tFWmkN.mjs} +6 -4
- package/dist/{rolldown-runtime-rQ84J-ij.mjs → rolldown-runtime-DXIUcv95.mjs} +1 -10
- package/dist/route-types-Id82-veQ.mjs +280 -0
- package/dist/{local-d1-D2I6Ox5F.mjs → runner-BGVsGgkb.mjs} +6 -114
- package/dist/runner-CQs_cDSG.mjs +2 -0
- package/dist/runner-mysql-1o47achK.mjs +2 -0
- package/dist/{runner-mysql-7BPUNGmL.mjs → runner-mysql-BhwMk2Bm.mjs} +2 -9
- package/dist/{runner-pg-BkEza-dX.mjs → runner-pg-CJ_JeGF6.mjs} +2 -9
- package/dist/runner-pg-D7z01mQS.mjs +2 -0
- package/dist/runtime/ai.mjs +1 -1
- package/dist/runtime/auth-client-react.d.mts +2 -6
- package/dist/runtime/auth-client-react.mjs +1 -5
- package/dist/runtime/auth-client-solid.d.mts +2 -6
- package/dist/runtime/auth-client-solid.mjs +1 -5
- package/dist/runtime/auth-client-svelte.d.mts +2 -6
- package/dist/runtime/auth-client-svelte.mjs +1 -5
- package/dist/runtime/auth-client-vue.d.mts +2 -6
- package/dist/runtime/auth-client-vue.mjs +1 -5
- package/dist/runtime/auth-client.d.mts +2 -6
- package/dist/runtime/auth-client.mjs +1 -5
- package/dist/runtime/auth.mjs +1 -21
- package/dist/runtime/better-auth-mysql.d.mts +1 -1
- package/dist/runtime/better-auth-mysql.mjs +1 -1
- package/dist/runtime/better-auth-pg.d.mts +1 -1
- package/dist/runtime/better-auth-pg.mjs +1 -1
- package/dist/runtime/better-auth.d.mts +1 -1
- package/dist/runtime/better-auth.mjs +1 -1
- package/dist/runtime/client-react.d.mts +3 -3
- package/dist/runtime/client-react.mjs +3 -3
- package/dist/runtime/client-solid.d.mts +3 -3
- package/dist/runtime/client-solid.mjs +3 -3
- package/dist/runtime/client-svelte.d.mts +3 -3
- package/dist/runtime/client-svelte.mjs +3 -3
- package/dist/runtime/client-vue.d.mts +3 -3
- package/dist/runtime/client-vue.mjs +3 -3
- package/dist/runtime/client.d.mts +3 -3
- package/dist/runtime/client.mjs +3 -3
- package/dist/runtime/db.mjs +1 -1
- package/dist/runtime/durable.mjs +1 -1
- package/dist/runtime/email/testing.mjs +1 -1
- package/dist/runtime/env-helpers.mjs +1 -135
- package/dist/runtime/env-public-client.mjs +1 -1
- package/dist/runtime/env-public.mjs +2 -2
- package/dist/runtime/env.mjs +1 -77
- package/dist/runtime/fetch-stream.d.mts +2 -49
- package/dist/runtime/fetch-stream.mjs +2 -80
- package/dist/runtime/fetch.d.mts +2 -57
- package/dist/runtime/fetch.mjs +2 -17
- package/dist/runtime/handler.d.mts +1 -1
- package/dist/runtime/handler.mjs +1 -149
- package/dist/runtime/kv.mjs +1 -1
- package/dist/runtime/live-client.d.mts +1 -1
- package/dist/runtime/live-server.mjs +2 -2
- package/dist/runtime/live.d.mts +2 -104
- package/dist/runtime/live.mjs +1 -410
- package/dist/runtime/migration-handler-mysql.d.mts +1 -1
- package/dist/runtime/migration-handler-pg.d.mts +1 -1
- package/dist/runtime/migration-handler.d.mts +2 -50
- package/dist/runtime/queues.d.mts +2 -6
- package/dist/runtime/queues.mjs +1 -1
- package/dist/runtime/response.mjs +1 -29
- package/dist/runtime/sandbox.mjs +1 -1
- package/dist/runtime/sse.mjs +1 -171
- package/dist/runtime/storage.mjs +1 -1
- package/dist/runtime/validator.d.mts +1 -1
- package/dist/runtime/validator.mjs +1 -71
- package/dist/runtime/ws-server.d.mts +2 -2
- package/dist/runtime/ws-server.mjs +2 -2
- package/dist/runtime/ws.d.mts +2 -121
- package/dist/{scan-CpK-57ug.mjs → scan-DJbooZm2.mjs} +3 -3
- package/dist/{scan-BMH4rzlv.mjs → scan-DdDvRCU1.mjs} +8 -26
- package/dist/{secret-AcPi-FoA.mjs → secret-UtrRjhEO.mjs} +8 -6
- package/dist/serialize-BPvnNQuA.mjs +14 -0
- package/dist/serialize-CfSwWfF2.d.mts +10 -0
- package/dist/{skills-C0RvGjeE.mjs → skills-B-690E7h.mjs} +3 -2
- package/dist/sse-BaC1jXko.mjs +172 -0
- package/dist/{subcommand-prompt-Bmyn5Rlc.mjs → subcommand-prompt-BuGYkAkC.mjs} +2 -1
- package/dist/sveltekit.d.mts +2 -1
- package/dist/sveltekit.mjs +3 -2
- package/dist/validate-DqJ33oHj.mjs +2 -0
- package/dist/validate-qNhV00PD.mjs +180 -0
- package/dist/validator-BTOu0fB0.mjs +72 -0
- package/dist/{wrangler--imS8n0d.mjs → wrangler-D01qs6VB.mjs} +259 -71
- package/dist/ws-BwcqizuH.d.mts +122 -0
- package/dist/{yarn-pnp-DxSInkzL.mjs → yarn-pnp-CVEc3gE7.mjs} +1 -1
- package/package.json +19 -8
- package/skills/void/SKILL.md +6 -4
- package/skills/void/docs/guide/ai.md +3 -3
- package/skills/void/docs/guide/app-types.md +12 -11
- package/skills/void/docs/guide/auth.md +2 -2
- package/skills/void/docs/guide/database/d1.md +1 -1
- package/skills/void/docs/guide/database/mysql.md +1 -1
- package/skills/void/docs/guide/database/postgresql.md +3 -3
- package/skills/void/docs/guide/deployment.md +8 -15
- package/skills/void/docs/guide/durable-state.md +2 -2
- package/skills/void/docs/guide/edge/headers.md +3 -3
- package/skills/void/docs/guide/edge/prerendering.md +1 -1
- package/skills/void/docs/guide/edge/redirects.md +4 -4
- package/skills/void/docs/guide/edge/revalidation.md +6 -6
- package/skills/void/docs/guide/edge/rewrites.md +28 -27
- package/skills/void/docs/guide/edge/static-assets.md +1 -1
- package/skills/void/docs/guide/email.md +60 -66
- package/skills/void/docs/guide/env-migration.md +1 -1
- package/skills/void/docs/guide/index.md +15 -41
- package/skills/void/docs/guide/pages-routing/head.md +1 -1
- package/skills/void/docs/guide/platform/administration/access.md +13 -5
- package/skills/void/docs/guide/platform/administration/projects.md +3 -1
- package/skills/void/docs/guide/platform/installation/ci.md +3 -0
- package/skills/void/docs/guide/platform/installation/credentials.md +15 -5
- package/skills/void/docs/guide/platform/installation/prerequisites.md +2 -0
- package/skills/void/docs/guide/platform/installation/setup.md +1 -1
- package/skills/void/docs/guide/quickstart.md +11 -78
- package/skills/void/docs/guide/remote-dev.md +2 -2
- package/skills/void/docs/guide/sandboxes.md +1 -1
- package/skills/void/docs/guide/ssg.md +1 -1
- package/skills/void/docs/guide/websockets.md +1 -1
- package/skills/void/docs/index.md +17 -17
- package/skills/void/docs/integrations/cloudflare.md +91 -96
- package/skills/void/docs/integrations/frameworks/analog.md +14 -9
- package/skills/void/docs/integrations/frameworks/astro.md +14 -10
- package/skills/void/docs/integrations/frameworks/nuxt.md +14 -9
- package/skills/void/docs/integrations/frameworks/overview.md +35 -29
- package/skills/void/docs/integrations/frameworks/react-router.md +1 -1
- package/skills/void/docs/integrations/frameworks/sveltekit.md +33 -30
- package/skills/void/docs/integrations/frameworks/tanstack-start.md +1 -1
- package/skills/void/docs/integrations/nodejs-bun-deno.md +5 -5
- package/skills/void/docs/reference/api.md +21 -4
- package/skills/void/docs/reference/cli.md +40 -25
- package/skills/void/docs/reference/config.md +58 -35
- package/skills/void/docs/reference/structure.md +2 -2
- package/dist/validate-tBBN_dXH.mjs +0 -505
|
@@ -1,51 +1,63 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { i as resolveProjectPaths, n as readProjectPaths, t as assertNoRootSourceConventionConflicts } from "./project-paths-
|
|
5
|
-
import {
|
|
1
|
+
import { n as __toESM, t as __commonJSMin } from "./rolldown-runtime-DXIUcv95.mjs";
|
|
2
|
+
import { a as join, l as relative, n as dirname, o as normalize, r as extname, t as basename, u as resolve } from "./dist-4WkAWhWx.mjs";
|
|
3
|
+
import { c as import_picocolors$1, d as require_picocolors, i as createSpinner, r as cliTitle } from "./output-CCH48AMM.mjs";
|
|
4
|
+
import { i as resolveProjectPaths, n as readProjectPaths, t as assertNoRootSourceConventionConflicts } from "./project-paths-CKQ-Q5JS.mjs";
|
|
5
|
+
import { t as findVoidAuthConfig } from "./config-uP7ZDtVZ.mjs";
|
|
6
6
|
import { i as trustedCloudflareWorkerAccessHeaders, r as scopedAccessCredentials, t as cfAccessHeaders } from "./cf-access-DRsQRe6k.mjs";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
7
|
+
import { a as getApiUrl, c as getToken, l as getTokenSource, o as getProxyUrl, u as isStagingMode } from "./auth-B9_D6ygs.mjs";
|
|
8
|
+
import { r as ensurePlatformProxyAccess, t as ensureCloudflaredToken } from "./cf-access-rAZxzMkL.mjs";
|
|
9
|
+
import { d as writeProjectConfig, i as readDeploymentPlatform, l as writeDeploymentPlatform, o as readProjectConfig, t as attachSelectedPlatform } from "./project-CWNIPoXc.mjs";
|
|
10
|
+
import { d as isNodeTarget, h as resolveBindingNames, m as readConfig, u as getDatabaseDialect } from "./config-Dxr6cTXn.mjs";
|
|
11
|
+
import { A as writeWranglerPublishedTrafficSnapshot, D as syncWranglerWebSockets, E as syncWranglerDurableObjects, L as materializeCloudflareConfig, M as isSandboxEnabled, N as requiresSandboxPlatformImage, P as resolveSandboxConfig, R as persistCloudflareConfig, S as readWranglerPublishedTrafficSnapshot, T as syncWranglerBindings, V as stashCloudflareDeployPointer, a as LIVE_MIGRATION_TAG, c as bindingEntriesForField, f as findBindingNameOwner, g as readExistingLiveBindingConfig, h as normalizeWranglerCompatibilityFlags, k as writeProvisionedWranglerConfig, l as ensureWranglerCompat, o as acknowledgeWranglerManagedQueueRemovals, r as FRIENDLY_BINDING_NAMES, w as resolveLiveBindingConfig, x as readWranglerManagedQueueCleanupCandidates } from "./wrangler-D01qs6VB.mjs";
|
|
10
12
|
import { i as voidWarn, r as voidLog } from "./log-ChfPKsVd.mjs";
|
|
11
|
-
import { n as lintDuplicateSources, r as mergeRoutingRules, t as lintDestinationSplats } from "./headers-
|
|
12
|
-
import { i as
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { n as lintDuplicateSources, r as mergeRoutingRules, t as lintDestinationSplats } from "./headers-B_HBMgi0.mjs";
|
|
14
|
+
import { a as scanQueuesSync, i as scanWebSocketRoutesSync, o as scanJobsSync, r as scanRoutes } from "./scan-DdDvRCU1.mjs";
|
|
15
|
+
import { i as inferProjectBindings, n as FRAMEWORK_SCAN_DIRS, r as detectFramework } from "./plugin-inference-DsvtJLll.mjs";
|
|
16
|
+
import { o as validateSsrEntry } from "./entry-DdRFGK0y.mjs";
|
|
17
|
+
import { t as collectMigrations } from "./collect-DXHNWHcT.mjs";
|
|
18
|
+
import { r as buildMigrationPlanBundle } from "./plan-BEZ8VJW0.mjs";
|
|
15
19
|
import { r as scanWranglerDotenvKeys } from "./dotenv-VQxupEUv.mjs";
|
|
16
|
-
import { t as discoverSchema } from "./discover-
|
|
17
|
-
import { t as findEnvFile } from "./env-types-
|
|
18
|
-
import {
|
|
19
|
-
import { n as CLOUDFLARE_DEPLOY_BUILD_ENV, o as resolveRemoteMode, s as stripInternalEnvKeys } from "./env-
|
|
20
|
-
import {
|
|
21
|
-
import { t as
|
|
22
|
-
import {
|
|
20
|
+
import { t as discoverSchema } from "./discover-C4O6YxVS.mjs";
|
|
21
|
+
import { t as findEnvFile } from "./env-types-CWDtqHgw.mjs";
|
|
22
|
+
import { d as formatEnvReport, f as listSelfHostSecretNames, g as validateProdEnv, h as selfHostSchemaFailureMessage, i as SelfHostSecretListError, l as dischargeSelfHostEnvContext, n as SelfHostFirstDeployError, p as readEmittedWorkerVars, r as SelfHostSchemaError, s as deriveSelfHostEnvContextFromVars, t as SelfHostEnvValidationError, u as fetchRemoteSecretNames, v as readGeneratedWranglerConfigFile } from "./env-validation-BsFEXps5.mjs";
|
|
23
|
+
import { n as CLOUDFLARE_DEPLOY_BUILD_ENV, o as resolveRemoteMode, s as stripInternalEnvKeys } from "./env-DX_v-Q-v.mjs";
|
|
24
|
+
import { E as confirm, I as select, N as note, O as intro, P as outro, W as isCancel, j as log$1 } from "./dist-Dn6nn2IU.mjs";
|
|
25
|
+
import { t as writeDrizzleConfig } from "./config-BSe70f4T.mjs";
|
|
26
|
+
import { i as runMySqlMigrations } from "./runner-mysql-BhwMk2Bm.mjs";
|
|
27
|
+
import { i as runPgMigrations } from "./runner-pg-CJ_JeGF6.mjs";
|
|
23
28
|
import { n as openMigrationValidationDatabase, t as SqliteMigrationError } from "./sqlite-validation-BzKMWnO4.mjs";
|
|
24
|
-
import { t as
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { a as
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import { n as
|
|
31
|
-
import { i as
|
|
32
|
-
import { r as
|
|
29
|
+
import { i as validateMigrations, t as assertJournalCoherence } from "./validate-qNhV00PD.mjs";
|
|
30
|
+
import { t as scanPages } from "./scan-DJbooZm2.mjs";
|
|
31
|
+
import { t as renderPrerenderPaths } from "./prerender-render-Cf_WDE9W.mjs";
|
|
32
|
+
import { a as scanEmailHandlersSync, r as hasEmailHandlers } from "./email-C5kaZXzJ.mjs";
|
|
33
|
+
import { i as migrateBuiltWranglerConfig, n as prepareCfFrameworkBuildOutput, r as prepareCfStaticBuildOutput, t as prepareCfBuildOutput } from "./cf-build-output-CTdlo6Rt.mjs";
|
|
34
|
+
import { n as getPackageDir } from "./agents-gni4eqBu.mjs";
|
|
35
|
+
import { i as isExpiredTokenError, n as PlatformClient, o as parsePlatformErrorBody, r as isCliOutdatedError, s as platformErrorMessage, t as PlatformApiError } from "./client-PdAJ-F0t.mjs";
|
|
36
|
+
import { a as resolveProjectCommand, i as hasBackendFiles, n as detectPreset, o as resolveWranglerArgv, r as formatProjectCommand, t as FRAMEWORK_PRESETS } from "./preset-Dowh9tTt.mjs";
|
|
37
|
+
import { o as ensureCloudflareAuthentication, r as cloudflareAuthNeedsTerminal, t as CloudflareAuthenticationError } from "./cloudflare-auth-BCmTc1X_.mjs";
|
|
38
|
+
import { n as writeVoidProjectConfig } from "./config-write-y3CBI_ux.mjs";
|
|
39
|
+
import { r as discoverFrameworkWranglerFiles, t as migrateLegacyVoidConfig } from "./migrate-BV8qHiCb.mjs";
|
|
40
|
+
import { a as createCloudflareEmptyDomainPublisher, i as createCloudflareEmptyCronPublisher } from "./cloudflare-operations-CPEdHYhM.mjs";
|
|
41
|
+
import { t as formatCloudflareUserMessage } from "./cloudflare-user-output-Q-k0QoNQ.mjs";
|
|
42
|
+
import { a as promptProjectSetupAction, i as promptProjectSelection, r as promptAndCreateProject } from "./create-project-BZBl_gQ0.mjs";
|
|
43
|
+
import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-Xvis70DG.mjs";
|
|
33
44
|
import { t as collectGitDeployMetadata } from "./git-metadata-D-gurjzG.mjs";
|
|
34
|
-
import {
|
|
45
|
+
import { t as promptForLoginToken } from "./login-jKe_0QZL.mjs";
|
|
35
46
|
import { createRequire } from "node:module";
|
|
36
|
-
import { copyFileSync, cpSync, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
37
|
-
import { fileURLToPath
|
|
47
|
+
import { copyFileSync, cpSync, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
48
|
+
import { fileURLToPath } from "node:url";
|
|
38
49
|
import { createDeployArtifact, createDeployUploadPayload } from "@void/deploy-core";
|
|
39
50
|
import { createHash, randomBytes } from "node:crypto";
|
|
40
|
-
import { homedir } from "node:os";
|
|
41
|
-
import { execFile, execSync, spawnSync } from "node:child_process";
|
|
51
|
+
import { homedir, tmpdir } from "node:os";
|
|
52
|
+
import { execFile, execSync, spawn, spawnSync } from "node:child_process";
|
|
42
53
|
import { applyEdits, modify, parse } from "jsonc-parser";
|
|
54
|
+
import { isDeepStrictEqual } from "node:util";
|
|
43
55
|
import { build } from "vite";
|
|
44
56
|
import { Minimatch } from "minimatch";
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
47
|
-
import { hash } from "blake3-jit";
|
|
57
|
+
import { activateCloudflareVersion, assertCloudflareBindingsPreserved, assertCloudflareDurableObjectLifecycleSupported, assertExistingCloudflareConfig, encodeCloudflareVersionMessage, extractWorkersDevSubdomain, normalizeWorkersDevSubdomain, parseRootWranglerConfig, parseRootWranglerConfig as parseRootWranglerConfig$1, readBindingFieldPresence, readCloudflareTriggerConfig, readConfigEntryString, readExistingCloudflareWorker, readStoredResourceName, readWranglerTopLevelString, renderCloudflareStaticEntry, resolveD1MigrateTarget, stageCloudflareStaticAssets, writeCloudflareFrameworkDeployConfig, writeCloudflareStaticDeployConfig } from "@void/deploy-cloudflare";
|
|
58
|
+
import { getWorkerConfigPath, readBuildOutput } from "@cloudflare/build-output-utils";
|
|
48
59
|
import ignore from "ignore";
|
|
60
|
+
import { hash } from "blake3-jit";
|
|
49
61
|
//#region src/asset-routing.ts
|
|
50
62
|
function isApiRoutePattern(pattern) {
|
|
51
63
|
return pattern === "/api" || pattern.startsWith("/api/");
|
|
@@ -96,7 +108,7 @@ function resolveAssetRoutingPolicy(inputs) {
|
|
|
96
108
|
//#region src/cli/email-cloudflare.ts
|
|
97
109
|
/** The `send_email` binding name Void provisions and the runtime reads. */
|
|
98
110
|
const SEND_EMAIL_BINDING = "SEND_EMAIL";
|
|
99
|
-
/** The root-config `vars` key carrying `void.
|
|
111
|
+
/** The root-config `vars` key carrying `void.config.ts` `email.from` into the worker. */
|
|
100
112
|
const EMAIL_FROM_VAR = "__VOID_EMAIL_FROM";
|
|
101
113
|
/** Cloudflare's public API base — the same one `wrangler` targets by default. */
|
|
102
114
|
const CLOUDFLARE_API_BASE_URL = "https://api.cloudflare.com/client/v4";
|
|
@@ -133,17 +145,17 @@ function findEmailConfigConflicts(config) {
|
|
|
133
145
|
try {
|
|
134
146
|
owner = findBindingNameOwner(config, field, name);
|
|
135
147
|
} catch (err) {
|
|
136
|
-
conflicts.add(`
|
|
148
|
+
conflicts.add(`Cloudflare config: ${err instanceof Error ? err.message : String(err)}`);
|
|
137
149
|
return;
|
|
138
150
|
}
|
|
139
|
-
if (owner !== void 0) conflicts.add(`
|
|
151
|
+
if (owner !== void 0) conflicts.add(`Cloudflare config already uses ${name} as a ${owner} binding; rename it in void.config.ts (Void writes ${name} into ${field})`);
|
|
140
152
|
};
|
|
141
153
|
check("send_email", SEND_EMAIL_BINDING);
|
|
142
154
|
check("vars", EMAIL_FROM_VAR);
|
|
143
155
|
return [...conflicts];
|
|
144
156
|
}
|
|
145
157
|
/**
|
|
146
|
-
* Host part of `email.from`, lowercased; `null` when it is not `local@host`. `void.
|
|
158
|
+
* Host part of `email.from`, lowercased; `null` when it is not `local@host`. `void.config.ts`
|
|
147
159
|
* also accepts the display-name form (`Acme <noreply@mail.acme.com>`, see `config.ts`),
|
|
148
160
|
* so the address inside `<…>` is read when present.
|
|
149
161
|
*
|
|
@@ -663,7 +675,7 @@ async function preflightEmail(inputs) {
|
|
|
663
675
|
state: "foreign",
|
|
664
676
|
foreignName: names[0]
|
|
665
677
|
};
|
|
666
|
-
block("all", `
|
|
678
|
+
block("all", `Cloudflare config already has a send_email binding named ${JSON.stringify(names[0])}; rename it to ${SEND_EMAIL_BINDING} in void.config.ts (a second binding would be silent)`);
|
|
667
679
|
}
|
|
668
680
|
if (inputs.existingAddresses !== void 0 && inputs.existingAddresses !== null) {
|
|
669
681
|
const existing = Array.isArray(inputs.existingAddresses) ? inputs.existingAddresses.map((a) => typeof a === "string" ? a.toLowerCase() : String(a)) : ["(not an array)"];
|
|
@@ -674,7 +686,7 @@ async function preflightEmail(inputs) {
|
|
|
674
686
|
state: "foreign",
|
|
675
687
|
foreign: unknown
|
|
676
688
|
};
|
|
677
|
-
block("all", `
|
|
689
|
+
block("all", `Cloudflare addresses holds entries Void did not derive (${unknown.join(", ")}); remove ${unknown.map((a) => JSON.stringify(a)).join(", ")} from cloudflare.addresses in void.config.ts, or manage addresses by hand and unset email.from — skipping email setup this deploy`);
|
|
678
690
|
} else {
|
|
679
691
|
pre.addressesOwnership = {
|
|
680
692
|
state: "mine",
|
|
@@ -710,7 +722,7 @@ function renderEmailChecklist(pre) {
|
|
|
710
722
|
const row = (label, value, note = "") => {
|
|
711
723
|
lines.push(` ${pad(label, 10)}${note ? `${pad(value, 23)}${note}` : value}`);
|
|
712
724
|
};
|
|
713
|
-
row("domain", pre.domain, "(void.
|
|
725
|
+
row("domain", pre.domain, "(void.config.ts email.from)");
|
|
714
726
|
const session = [pre.session.accountName ? `account ${pre.session.accountName} (${shortId(pre.accountId)})` : `account ${shortId(pre.accountId)}`, pre.session.authType && pre.session.authType !== "OAuth Token" ? `session ${pre.session.email ? `${pre.session.email} ` : ""}(${pre.session.authType})` : pre.session.email ? `session ${pre.session.email}` : null].filter(Boolean).join(" · ");
|
|
715
727
|
row("zone", pre.zone.state === "found" ? apex : `${apex} ${pre.zone.state}`, session);
|
|
716
728
|
if (pre.mode === "subdomain") row("apex MX", pre.apexMx.exchanges[0] ?? (pre.apexMx.state === "unknown" ? "unknown" : "none"), "left alone — mail lives on the subdomain");
|
|
@@ -745,7 +757,7 @@ function renderEmailChecklist(pre) {
|
|
|
745
757
|
if (pre.binding.state !== "present") parts.push(`send_email: [{ name: "${SEND_EMAIL_BINDING}" }]`);
|
|
746
758
|
if (pre.addressesStale) parts.push(pre.addresses.length > 0 ? `addresses: ${JSON.stringify(pre.addresses)}` : "addresses: (removed)");
|
|
747
759
|
if (pre.sender.state !== "ready") parts.push(`vars.${EMAIL_FROM_VAR}: ${JSON.stringify(pre.from)}`);
|
|
748
|
-
if (parts.length > 0) change("
|
|
760
|
+
if (parts.length > 0) change("Cloudflare config", parts.join(", "));
|
|
749
761
|
for (const address of pre.rules.absent) change("routing rule (created on deploy)", `${address} → ${pre.workerName}`);
|
|
750
762
|
for (const foreign of pre.rules.foreign) warn(foreign.address, `already routed to ${foreign.owner}; left alone, not in addresses`);
|
|
751
763
|
for (const refused of pre.derived.refused) warn(refused.handler, refused.reason);
|
|
@@ -930,7 +942,7 @@ async function applyEmailSetup(pre, inputs) {
|
|
|
930
942
|
result.patch.addresses = null;
|
|
931
943
|
if (result.addressesWithheld && pre.addresses.length > 0) lines.push(` ! config addresses withheld this run (${bearerFailed ? "session-bearer step failed" : "routing not ready"}); no routing rule is created for ${pre.addresses.join(", ")}`);
|
|
932
944
|
}
|
|
933
|
-
if (result.patch.sendEmail || result.patch.addresses !== void 0) lines.push(" ✔ config
|
|
945
|
+
if (result.patch.sendEmail || result.patch.addresses !== void 0) lines.push(" ✔ config void.lock.json updated");
|
|
934
946
|
result.inboundReady = result.routingReady && result.subaddressingReady && !result.addressesWithheld;
|
|
935
947
|
return result;
|
|
936
948
|
}
|
|
@@ -1643,9 +1655,7 @@ async function createCloudflarePrerenderRunner(options) {
|
|
|
1643
1655
|
voidStaging,
|
|
1644
1656
|
remoteMode
|
|
1645
1657
|
});
|
|
1646
|
-
const
|
|
1647
|
-
const miniflarePath = createRequire(wranglerUrl).resolve("miniflare");
|
|
1648
|
-
const { Miniflare, convertV4MiniflareOptions } = await import(pathToFileURL(miniflarePath).href);
|
|
1658
|
+
const { Miniflare, convertV4MiniflareOptions } = await import("miniflare");
|
|
1649
1659
|
const mfOptions = {
|
|
1650
1660
|
modules: collectPrerenderWorkerModules(workerDir, workerMain),
|
|
1651
1661
|
modulesRoot: workerDir,
|
|
@@ -1845,6 +1855,426 @@ async function prerenderPagesNode(options) {
|
|
|
1845
1855
|
return result;
|
|
1846
1856
|
}
|
|
1847
1857
|
//#endregion
|
|
1858
|
+
//#region src/cli/cf-version-runner.ts
|
|
1859
|
+
function failed(message) {
|
|
1860
|
+
return {
|
|
1861
|
+
status: 1,
|
|
1862
|
+
stdout: "",
|
|
1863
|
+
stderr: message
|
|
1864
|
+
};
|
|
1865
|
+
}
|
|
1866
|
+
function flag(args, name) {
|
|
1867
|
+
const index = args.indexOf(name);
|
|
1868
|
+
return index < 0 ? void 0 : args[index + 1];
|
|
1869
|
+
}
|
|
1870
|
+
function parseJson(value) {
|
|
1871
|
+
try {
|
|
1872
|
+
return JSON.parse(value);
|
|
1873
|
+
} catch {
|
|
1874
|
+
return null;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
function record(value) {
|
|
1878
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1879
|
+
}
|
|
1880
|
+
function safePositional(value) {
|
|
1881
|
+
return typeof value === "string" && value.length > 0 && !value.startsWith("-") && ![...value].some((character) => {
|
|
1882
|
+
const code = character.charCodeAt(0);
|
|
1883
|
+
return code < 32 || code === 127;
|
|
1884
|
+
});
|
|
1885
|
+
}
|
|
1886
|
+
/** Prevent cf's prebuilt uploader from creating a resource as a side effect. */
|
|
1887
|
+
function createCfResourceVerifier(options) {
|
|
1888
|
+
return async (directory) => {
|
|
1889
|
+
const worker = parseJson(readFileSync(getWorkerConfigPath(directory), "utf8"));
|
|
1890
|
+
if (!record(worker) || worker.env !== void 0 && !record(worker.env)) return failed("The Cloudflare Worker bindings were not readable.");
|
|
1891
|
+
for (const [bindingName, value] of Object.entries(worker.env ?? {})) {
|
|
1892
|
+
if (!record(value)) return failed(`Cloudflare binding ${bindingName} was not readable.`);
|
|
1893
|
+
const identifier = (field) => safePositional(value[field]) ? value[field] : null;
|
|
1894
|
+
if (value.type === "kv" || value.type === "d1" || value.type === "flagship") {
|
|
1895
|
+
if (!identifier("id")) return failed(`Cloudflare binding ${bindingName} has no ID; refusing automatic provisioning.`);
|
|
1896
|
+
continue;
|
|
1897
|
+
}
|
|
1898
|
+
if (value.type === "queue") {
|
|
1899
|
+
const name = identifier("name");
|
|
1900
|
+
if (!name) return failed(`Cloudflare Queue binding ${bindingName} has no name.`);
|
|
1901
|
+
if (!options.verifyCompatibilityRunner()) return failed("The Cloudflare resource verifier changed during deployment.");
|
|
1902
|
+
const found = await Promise.resolve(options.runWrangler([
|
|
1903
|
+
"queues",
|
|
1904
|
+
"info",
|
|
1905
|
+
name,
|
|
1906
|
+
"-c",
|
|
1907
|
+
options.configPath,
|
|
1908
|
+
"--env="
|
|
1909
|
+
], { capture: true }));
|
|
1910
|
+
if (found.status !== 0 || found.signal || found.error || found.stdout.trim() !== `Queue Name: ${name}`) return failed(`Cloudflare Queue ${name} is unavailable; refusing automatic provisioning.`);
|
|
1911
|
+
continue;
|
|
1912
|
+
}
|
|
1913
|
+
const resource = value.type === "r2" ? {
|
|
1914
|
+
kind: "R2 bucket",
|
|
1915
|
+
field: "name",
|
|
1916
|
+
command: [
|
|
1917
|
+
"r2",
|
|
1918
|
+
"buckets",
|
|
1919
|
+
"get"
|
|
1920
|
+
],
|
|
1921
|
+
response: "name"
|
|
1922
|
+
} : value.type === "dispatch-namespace" ? {
|
|
1923
|
+
kind: "dispatch namespace",
|
|
1924
|
+
field: "namespace",
|
|
1925
|
+
command: [
|
|
1926
|
+
"workers-for-platforms",
|
|
1927
|
+
"dispatch-namespaces",
|
|
1928
|
+
"get"
|
|
1929
|
+
],
|
|
1930
|
+
response: "namespace_name"
|
|
1931
|
+
} : value.type === "ai-search-namespace" ? {
|
|
1932
|
+
kind: "AI Search namespace",
|
|
1933
|
+
field: "namespace",
|
|
1934
|
+
command: [
|
|
1935
|
+
"ai-search",
|
|
1936
|
+
"namespace",
|
|
1937
|
+
"get"
|
|
1938
|
+
],
|
|
1939
|
+
response: "name"
|
|
1940
|
+
} : value.type === "agent-memory" ? {
|
|
1941
|
+
kind: "Agent Memory namespace",
|
|
1942
|
+
field: "namespace",
|
|
1943
|
+
command: ["agent-memory", "get-namespace"],
|
|
1944
|
+
response: "name"
|
|
1945
|
+
} : null;
|
|
1946
|
+
if (!resource) continue;
|
|
1947
|
+
const name = identifier(resource.field);
|
|
1948
|
+
if (!name) return failed(`Cloudflare ${resource.kind} binding ${bindingName} has no name.`);
|
|
1949
|
+
const jurisdiction = value.type === "r2" ? value.jurisdiction : void 0;
|
|
1950
|
+
if (jurisdiction !== void 0 && !safePositional(jurisdiction)) return failed(`Cloudflare R2 binding ${bindingName} has an invalid jurisdiction.`);
|
|
1951
|
+
const result = await options.runCf([
|
|
1952
|
+
...resource.command,
|
|
1953
|
+
name,
|
|
1954
|
+
...jurisdiction ? ["--cf-r2-jurisdiction", jurisdiction] : []
|
|
1955
|
+
], {
|
|
1956
|
+
cwd: directory,
|
|
1957
|
+
capture: true
|
|
1958
|
+
});
|
|
1959
|
+
const body = parseJson(result.stdout);
|
|
1960
|
+
if (result.status !== 0 || result.signal || result.error || !record(body) || body[resource.response] !== name) return failed(`Cloudflare ${resource.kind} ${name} is unavailable; refusing automatic provisioning.`);
|
|
1961
|
+
}
|
|
1962
|
+
return {
|
|
1963
|
+
status: 0,
|
|
1964
|
+
stdout: "",
|
|
1965
|
+
stderr: ""
|
|
1966
|
+
};
|
|
1967
|
+
};
|
|
1968
|
+
}
|
|
1969
|
+
/** Run the pinned package-local cf binary with Void's existing Cloudflare session. */
|
|
1970
|
+
function createCfCommand(options) {
|
|
1971
|
+
const cf = join(dirname(fileURLToPath(import.meta.resolve("cf/package.json"))), "bin", "cf");
|
|
1972
|
+
return async (args, run) => {
|
|
1973
|
+
if (!options.verifyUploader()) return failed("The Cloudflare uploader changed during deployment.");
|
|
1974
|
+
const env = {
|
|
1975
|
+
...options.env(options.accountId, options.apiBaseUrl),
|
|
1976
|
+
CF_DELEGATION: "1",
|
|
1977
|
+
CF_QUIET: "1",
|
|
1978
|
+
CF_NO_OSC_PROGRESS: "1",
|
|
1979
|
+
CF_SEND_TELEMETRY: "false"
|
|
1980
|
+
};
|
|
1981
|
+
if (env.HTTP_PROXY || env.HTTPS_PROXY || env.http_proxy || env.https_proxy) env.NODE_USE_ENV_PROXY = "1";
|
|
1982
|
+
if (options.token) env.CLOUDFLARE_API_TOKEN = options.token;
|
|
1983
|
+
return await new Promise((resolve) => {
|
|
1984
|
+
const child = spawn(process.execPath, [cf, ...args], {
|
|
1985
|
+
cwd: run.cwd,
|
|
1986
|
+
env,
|
|
1987
|
+
shell: false,
|
|
1988
|
+
windowsHide: true,
|
|
1989
|
+
stdio: [
|
|
1990
|
+
"ignore",
|
|
1991
|
+
"pipe",
|
|
1992
|
+
"pipe"
|
|
1993
|
+
]
|
|
1994
|
+
});
|
|
1995
|
+
const stdout = [];
|
|
1996
|
+
const stderr = [];
|
|
1997
|
+
let bytes = 0;
|
|
1998
|
+
let error = null;
|
|
1999
|
+
const collect = (chunks, chunk) => {
|
|
2000
|
+
bytes += chunk.length;
|
|
2001
|
+
if (bytes > 268435456) {
|
|
2002
|
+
error = "Cloudflare command output exceeded 256 MiB.";
|
|
2003
|
+
child.kill();
|
|
2004
|
+
} else chunks.push(chunk);
|
|
2005
|
+
};
|
|
2006
|
+
child.stdout.on("data", (chunk) => collect(stdout, chunk));
|
|
2007
|
+
child.stderr.on("data", (chunk) => collect(stderr, chunk));
|
|
2008
|
+
child.on("error", (cause) => {
|
|
2009
|
+
error = cause.message;
|
|
2010
|
+
});
|
|
2011
|
+
child.on("close", (status, signal) => {
|
|
2012
|
+
resolve({
|
|
2013
|
+
status: typeof status === "number" ? status : 1,
|
|
2014
|
+
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
2015
|
+
stderr: Buffer.concat(stderr).toString("utf8").replace(/\[(\d{4,})\]/g, "[code: $1]"),
|
|
2016
|
+
signal,
|
|
2017
|
+
error
|
|
2018
|
+
});
|
|
2019
|
+
});
|
|
2020
|
+
});
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
/**
|
|
2024
|
+
* Adapt the stable activation protocol to cf's prebuilt and API commands.
|
|
2025
|
+
* The protocol keeps the existing preview, inheritance, traffic and rollback checks.
|
|
2026
|
+
*/
|
|
2027
|
+
function createCfVersionRunner(options) {
|
|
2028
|
+
const { output, workerName, runCf } = options;
|
|
2029
|
+
const run = async (args, capture, cwd = output.directory) => await runCf(args, {
|
|
2030
|
+
cwd,
|
|
2031
|
+
capture
|
|
2032
|
+
});
|
|
2033
|
+
const verifyResources = async (directory) => {
|
|
2034
|
+
try {
|
|
2035
|
+
return await options.verifyResources(directory);
|
|
2036
|
+
} catch {
|
|
2037
|
+
return failed("Cloudflare resources could not be verified before upload.");
|
|
2038
|
+
}
|
|
2039
|
+
};
|
|
2040
|
+
return async (args, command) => {
|
|
2041
|
+
if (args[0] === "deployments" && args[1] === "status") {
|
|
2042
|
+
const result = await run([
|
|
2043
|
+
"workers",
|
|
2044
|
+
"deployments",
|
|
2045
|
+
"list",
|
|
2046
|
+
"--worker",
|
|
2047
|
+
workerName
|
|
2048
|
+
], true);
|
|
2049
|
+
if (result.status !== 0) return result;
|
|
2050
|
+
const body = parseJson(result.stdout);
|
|
2051
|
+
const deployments = record(body) ? body.deployments : void 0;
|
|
2052
|
+
if (Array.isArray(deployments) && deployments.length === 0) return failed("The Cloudflare Worker has no deployments.");
|
|
2053
|
+
if (!Array.isArray(deployments) || !record(deployments[0])) return failed("The Cloudflare Worker deployment was not readable.");
|
|
2054
|
+
return {
|
|
2055
|
+
...result,
|
|
2056
|
+
stdout: JSON.stringify(deployments[0])
|
|
2057
|
+
};
|
|
2058
|
+
}
|
|
2059
|
+
if (args[0] === "versions" && args[1] === "list") {
|
|
2060
|
+
const pageSize = 10;
|
|
2061
|
+
const readPage = async (page) => {
|
|
2062
|
+
const result = await run([
|
|
2063
|
+
"workers",
|
|
2064
|
+
"versions",
|
|
2065
|
+
"list",
|
|
2066
|
+
"--worker-id",
|
|
2067
|
+
workerName,
|
|
2068
|
+
"--per-page",
|
|
2069
|
+
String(pageSize),
|
|
2070
|
+
"--page",
|
|
2071
|
+
String(page)
|
|
2072
|
+
], true);
|
|
2073
|
+
const body = parseJson(result.stdout);
|
|
2074
|
+
return {
|
|
2075
|
+
result,
|
|
2076
|
+
versions: Array.isArray(body) && body.length <= pageSize && body.every((item) => record(item) && typeof item.id === "string" && Number.isSafeInteger(item.number)) && new Set(body.map((item) => item.number)).size === body.length ? body : null
|
|
2077
|
+
};
|
|
2078
|
+
};
|
|
2079
|
+
const first = await readPage(1);
|
|
2080
|
+
if (first.result.status !== 0) return first.result;
|
|
2081
|
+
if (!first.versions) return failed("The Cloudflare Worker version list was not readable.");
|
|
2082
|
+
const versions = [...first.versions];
|
|
2083
|
+
if (versions.length === pageSize) {
|
|
2084
|
+
const second = await readPage(2);
|
|
2085
|
+
if (second.result.status !== 0 || !second.versions) return failed("The Cloudflare Worker version history was not readable.");
|
|
2086
|
+
if (second.versions.length > 0) {
|
|
2087
|
+
const firstNumbers = versions.map((item) => item.number);
|
|
2088
|
+
const secondNumbers = second.versions.map((item) => item.number);
|
|
2089
|
+
if (Math.min(...secondNumbers) > Math.max(...firstNumbers)) {
|
|
2090
|
+
versions.push(...second.versions);
|
|
2091
|
+
let last = Math.max(...secondNumbers);
|
|
2092
|
+
for (let page = 3; page <= 1e3 && second.versions.length === pageSize; page++) {
|
|
2093
|
+
const next = await readPage(page);
|
|
2094
|
+
if (next.result.status !== 0 || !next.versions) return failed("The Cloudflare Worker version history was not readable.");
|
|
2095
|
+
if (next.versions.length === 0) break;
|
|
2096
|
+
const numbers = next.versions.map((item) => item.number);
|
|
2097
|
+
if (Math.min(...numbers) <= last) return failed("The Cloudflare Worker version history changed during inspection.");
|
|
2098
|
+
versions.push(...next.versions);
|
|
2099
|
+
last = Math.max(...numbers);
|
|
2100
|
+
if (next.versions.length < pageSize) break;
|
|
2101
|
+
if (page === 1e3) return failed("The Cloudflare Worker version history is too large to verify.");
|
|
2102
|
+
}
|
|
2103
|
+
} else if (Math.max(...secondNumbers) >= Math.min(...firstNumbers)) return failed("The Cloudflare Worker version history changed during inspection.");
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
return {
|
|
2107
|
+
...first.result,
|
|
2108
|
+
stdout: JSON.stringify(versions.sort((a, b) => a.number - b.number).slice(-10))
|
|
2109
|
+
};
|
|
2110
|
+
}
|
|
2111
|
+
if (args[0] === "versions" && args[1] === "view" && args[2]) {
|
|
2112
|
+
const result = await run([
|
|
2113
|
+
"workers",
|
|
2114
|
+
"versions",
|
|
2115
|
+
"get",
|
|
2116
|
+
args[2],
|
|
2117
|
+
"--worker-id",
|
|
2118
|
+
workerName
|
|
2119
|
+
], true);
|
|
2120
|
+
if (result.status !== 0) return result;
|
|
2121
|
+
const version = parseJson(result.stdout);
|
|
2122
|
+
if (!record(version) || version.id !== args[2] || !Array.isArray(version.bindings)) return failed("The Cloudflare Worker version was not readable.");
|
|
2123
|
+
return {
|
|
2124
|
+
...result,
|
|
2125
|
+
stdout: JSON.stringify({
|
|
2126
|
+
...version,
|
|
2127
|
+
resources: { bindings: version.bindings }
|
|
2128
|
+
})
|
|
2129
|
+
};
|
|
2130
|
+
}
|
|
2131
|
+
if (args[0] === "versions" && args[1] === "upload") {
|
|
2132
|
+
if (flag(args, "--name") !== workerName || args.includes("--assets") && flag(args, "--assets") !== output.assetsDirectory) return failed("The Cloudflare version upload target changed.");
|
|
2133
|
+
const verified = await verifyResources(output.directory);
|
|
2134
|
+
if (verified.status !== 0 || verified.signal || verified.error) return verified;
|
|
2135
|
+
return run([
|
|
2136
|
+
"workers",
|
|
2137
|
+
"versions",
|
|
2138
|
+
"create",
|
|
2139
|
+
"--prebuilt",
|
|
2140
|
+
...flag(args, "--message") ? ["--message", flag(args, "--message")] : [],
|
|
2141
|
+
...flag(args, "--secrets-file") ? ["--secrets-file", flag(args, "--secrets-file")] : [],
|
|
2142
|
+
...flag(args, "--preview-alias") ? ["--preview-alias", flag(args, "--preview-alias")] : []
|
|
2143
|
+
], command.capture);
|
|
2144
|
+
}
|
|
2145
|
+
if (args[0] === "versions" && args[1] === "deploy") {
|
|
2146
|
+
if (flag(args, "--name") !== workerName) return failed("The Cloudflare deployment target changed.");
|
|
2147
|
+
const flagsStart = args.findIndex((item, index) => index >= 2 && item.startsWith("-"));
|
|
2148
|
+
const versions = args.slice(2, flagsStart < 0 ? void 0 : flagsStart);
|
|
2149
|
+
if (!versions.every((item) => /^[0-9a-f-]{36}@\d+(?:\.\d+)?$/i.test(item))) return failed("The Cloudflare deployment versions were invalid.");
|
|
2150
|
+
const parsed = versions.map((item) => {
|
|
2151
|
+
const [version_id, percentage] = item.split("@");
|
|
2152
|
+
return {
|
|
2153
|
+
version_id,
|
|
2154
|
+
percentage: Number(percentage)
|
|
2155
|
+
};
|
|
2156
|
+
});
|
|
2157
|
+
if (parsed.length === 0 || new Set(parsed.map((item) => item.version_id)).size !== parsed.length || parsed.some((item) => item.percentage < 0 || item.percentage > 100) || Math.abs(parsed.reduce((sum, item) => sum + item.percentage, 0) - 100) > .001) return failed("The Cloudflare deployment percentages were invalid.");
|
|
2158
|
+
return run([
|
|
2159
|
+
"workers",
|
|
2160
|
+
"deployments",
|
|
2161
|
+
"create",
|
|
2162
|
+
"--worker",
|
|
2163
|
+
workerName,
|
|
2164
|
+
"--strategy",
|
|
2165
|
+
"percentage",
|
|
2166
|
+
"--versions",
|
|
2167
|
+
JSON.stringify(parsed),
|
|
2168
|
+
...flag(args, "--message") ? ["--body", JSON.stringify({
|
|
2169
|
+
strategy: "percentage",
|
|
2170
|
+
versions: parsed,
|
|
2171
|
+
annotations: { "workers/message": flag(args, "--message") }
|
|
2172
|
+
})] : []
|
|
2173
|
+
], command.capture);
|
|
2174
|
+
}
|
|
2175
|
+
if (args[0] === "deploy") {
|
|
2176
|
+
if (flag(args, "--name") !== workerName || args.includes("--assets") && flag(args, "--assets") !== output.assetsDirectory) return failed("The Cloudflare bootstrap target changed.");
|
|
2177
|
+
const verified = await verifyResources(output.directory);
|
|
2178
|
+
if (verified.status !== 0 || verified.signal || verified.error) return verified;
|
|
2179
|
+
return run([
|
|
2180
|
+
"deploy",
|
|
2181
|
+
"--prebuilt",
|
|
2182
|
+
...flag(args, "--message") ? ["--message", flag(args, "--message")] : [],
|
|
2183
|
+
...flag(args, "--secrets-file") ? ["--secrets-file", flag(args, "--secrets-file")] : []
|
|
2184
|
+
], command.capture);
|
|
2185
|
+
}
|
|
2186
|
+
if (args[0] === "triggers" && args[1] === "deploy") {
|
|
2187
|
+
const configPath = flag(args, "-c");
|
|
2188
|
+
if (!configPath || flag(args, "--name") !== workerName) return failed("The Cloudflare trigger target changed.");
|
|
2189
|
+
const raw = parseJson(readFileSync(configPath, "utf8"));
|
|
2190
|
+
if (!record(raw) || raw.name !== workerName) return failed("The Cloudflare trigger snapshot was not readable.");
|
|
2191
|
+
const directory = mkdtempSync(join(tmpdir(), "void-cf-triggers-"));
|
|
2192
|
+
try {
|
|
2193
|
+
cpSync(join(output.directory, ".cloudflare"), join(directory, ".cloudflare"), { recursive: true });
|
|
2194
|
+
const workerPath = getWorkerConfigPath(directory);
|
|
2195
|
+
const worker = parseJson(readFileSync(workerPath, "utf8"));
|
|
2196
|
+
if (!record(worker)) return failed("The private Cloudflare Worker config was not readable.");
|
|
2197
|
+
const migrated = migrateBuiltWranglerConfig({
|
|
2198
|
+
...raw,
|
|
2199
|
+
compatibility_date: worker.compatibilityDate
|
|
2200
|
+
}).worker;
|
|
2201
|
+
if (!migrated) return failed("The Cloudflare trigger snapshot was not convertible.");
|
|
2202
|
+
const next = migrated.triggers ?? [];
|
|
2203
|
+
const previous = Array.isArray(worker.triggers) ? worker.triggers : [];
|
|
2204
|
+
const preserveRoutes = raw.routes === void 0 && raw.route === void 0;
|
|
2205
|
+
const preserveEmail = raw.addresses === void 0;
|
|
2206
|
+
worker.triggers = [
|
|
2207
|
+
...next,
|
|
2208
|
+
...preserveRoutes ? previous.filter((trigger) => record(trigger) && trigger.type === "fetch") : [],
|
|
2209
|
+
...preserveEmail ? previous.filter((trigger) => record(trigger) && trigger.type === "email") : []
|
|
2210
|
+
];
|
|
2211
|
+
for (const field of ["env", "exports"]) {
|
|
2212
|
+
const previous = record(worker[field]) ? worker[field] : {};
|
|
2213
|
+
worker[field] = {
|
|
2214
|
+
...Object.fromEntries(Object.entries(previous).filter(([, value]) => !record(value) || value.type !== "workflow")),
|
|
2215
|
+
...migrated[field]
|
|
2216
|
+
};
|
|
2217
|
+
}
|
|
2218
|
+
if (!preserveRoutes) worker.domains = migrated.domains ?? [];
|
|
2219
|
+
if (typeof raw.workers_dev === "boolean") worker.workersDev = raw.workers_dev;
|
|
2220
|
+
if (typeof raw.preview_urls === "boolean") worker.previewUrls = raw.preview_urls;
|
|
2221
|
+
writeFileSync(workerPath, JSON.stringify(worker), { mode: 384 });
|
|
2222
|
+
await readBuildOutput(directory);
|
|
2223
|
+
const verified = await verifyResources(directory);
|
|
2224
|
+
if (verified.status !== 0 || verified.signal || verified.error) return verified;
|
|
2225
|
+
return await run([
|
|
2226
|
+
"workers",
|
|
2227
|
+
"triggers",
|
|
2228
|
+
"deploy",
|
|
2229
|
+
"--prebuilt"
|
|
2230
|
+
], command.capture, directory);
|
|
2231
|
+
} finally {
|
|
2232
|
+
rmSync(directory, {
|
|
2233
|
+
recursive: true,
|
|
2234
|
+
force: true
|
|
2235
|
+
});
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
if (args[0] === "queues" && args[1] === "consumer" && args[2] === "remove") {
|
|
2239
|
+
const queueName = args[3];
|
|
2240
|
+
if (!queueName || args[4] !== workerName) return failed("The Cloudflare Queue consumer target changed.");
|
|
2241
|
+
const queues = await run(["queues", "list"], true);
|
|
2242
|
+
if (queues.status !== 0) return queues;
|
|
2243
|
+
const allQueues = parseJson(queues.stdout);
|
|
2244
|
+
if (!Array.isArray(allQueues)) return failed("The Cloudflare Queue list was not readable.");
|
|
2245
|
+
const queue = allQueues.find((item) => record(item) && item.queue_name === queueName);
|
|
2246
|
+
if (!record(queue) || typeof queue.queue_id !== "string") return failed(`Cloudflare Queue ${queueName} was not found.`);
|
|
2247
|
+
const consumers = await run([
|
|
2248
|
+
"queues",
|
|
2249
|
+
"consumers",
|
|
2250
|
+
"list",
|
|
2251
|
+
"--queue-id",
|
|
2252
|
+
queue.queue_id
|
|
2253
|
+
], true);
|
|
2254
|
+
if (consumers.status !== 0) return consumers;
|
|
2255
|
+
const allConsumers = parseJson(consumers.stdout);
|
|
2256
|
+
if (!Array.isArray(allConsumers)) return failed("The Cloudflare Queue consumers were not readable.");
|
|
2257
|
+
const matching = allConsumers.filter((item) => record(item) && item.script === workerName);
|
|
2258
|
+
if (matching.length === 0) return {
|
|
2259
|
+
status: 0,
|
|
2260
|
+
stdout: "",
|
|
2261
|
+
stderr: ""
|
|
2262
|
+
};
|
|
2263
|
+
if (matching.length !== 1 || !record(matching[0]) || typeof matching[0].consumer_id !== "string") return failed("The Cloudflare Queue consumer identity was ambiguous.");
|
|
2264
|
+
return run([
|
|
2265
|
+
"queues",
|
|
2266
|
+
"consumers",
|
|
2267
|
+
"delete",
|
|
2268
|
+
matching[0].consumer_id,
|
|
2269
|
+
"--queue-id",
|
|
2270
|
+
queue.queue_id,
|
|
2271
|
+
"--force"
|
|
2272
|
+
], command.capture);
|
|
2273
|
+
}
|
|
2274
|
+
return failed(`Unsupported Cloudflare activation operation: ${args[0] ?? ""} ${args[1] ?? ""}`);
|
|
2275
|
+
};
|
|
2276
|
+
}
|
|
2277
|
+
//#endregion
|
|
1848
2278
|
//#region src/cli/cloudflare-deploy/classify.ts
|
|
1849
2279
|
/**
|
|
1850
2280
|
* Narrow native Cloudflare deploys to app shapes whose emitted Worker artifact
|
|
@@ -1860,14 +2290,14 @@ function classifyCloudflareDeployApp(root, voidConfig, options) {
|
|
|
1860
2290
|
if (framework) {
|
|
1861
2291
|
if (!FRAMEWORK_PRESETS[framework.name]) return unsupported(`deploy: --platform cloudflare has no deployment preset for framework ${framework.name}.`);
|
|
1862
2292
|
}
|
|
1863
|
-
const staticPreset = detectPreset(root, {
|
|
2293
|
+
const staticPreset = framework ? null : detectPreset(root, {
|
|
1864
2294
|
dir: options.dir,
|
|
1865
2295
|
spa: options.spa
|
|
1866
2296
|
});
|
|
1867
2297
|
const configuredStatic = voidConfig.inference?.appType === "static" || voidConfig.inference?.appType === "spa";
|
|
1868
2298
|
if (staticPreset || configuredStatic || options.dir || options.spa) return unsupported([
|
|
1869
2299
|
`deploy: --platform cloudflare could not resolve the ${staticPreset?.appType ?? (options.spa ? "spa" : "static")} output to deploy.`,
|
|
1870
|
-
"Set inference.outputDir in void.
|
|
2300
|
+
"Set inference.outputDir in void.config.ts, pass --dir with an existing build directory,",
|
|
1871
2301
|
"or add a supported build tool so Void can locate the generated static assets."
|
|
1872
2302
|
].join("\n"));
|
|
1873
2303
|
if (!framework && !hasBackendFiles(root)) return unsupported([
|
|
@@ -1910,7 +2340,7 @@ function approvedCloudflareIsrBinding(config, rootConfig) {
|
|
|
1910
2340
|
/** Persist the migration decision in source configuration, not a temporary link marker. */
|
|
1911
2341
|
async function chooseCloudflareIsr(root, config, options) {
|
|
1912
2342
|
if (config.routing?.isr !== void 0) return config.routing.isr;
|
|
1913
|
-
if (!options.interactive) throw new Error("This migration needs an ISR caching choice. Set routing.isr to true in void.
|
|
2343
|
+
if (!options.interactive) throw new Error("This migration needs an ISR caching choice. Set routing.isr to true in void.config.ts to provision the KV cache, or false to keep rendering on each request, then rerun `void deploy`.");
|
|
1914
2344
|
const enabled = await (options.confirm ?? (async (message) => {
|
|
1915
2345
|
const answer = await confirm({
|
|
1916
2346
|
message,
|
|
@@ -1918,18 +2348,27 @@ async function chooseCloudflareIsr(root, config, options) {
|
|
|
1918
2348
|
});
|
|
1919
2349
|
if (isCancel(answer)) throw new Error("ISR setup cancelled. Rerun `void deploy` to finish linking.");
|
|
1920
2350
|
return answer === true;
|
|
1921
|
-
}))("Enable ISR caching for this app? Yes provisions a Cloudflare KV cache; No keeps caching disabled until you change void.
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
2351
|
+
}))("Enable ISR caching for this app? Yes provisions a Cloudflare KV cache; No keeps caching disabled until you change void.config.ts.");
|
|
2352
|
+
if (existsSync(join(root, "void.config.ts"))) writeVoidProjectConfig(root, {
|
|
2353
|
+
...config,
|
|
2354
|
+
routing: {
|
|
2355
|
+
...config.routing,
|
|
2356
|
+
isr: enabled
|
|
2357
|
+
}
|
|
2358
|
+
});
|
|
2359
|
+
else {
|
|
2360
|
+
const path = join(root, "void.json");
|
|
2361
|
+
const source = existsSync(path) ? readFileSync(path, "utf8") : "{}\n";
|
|
2362
|
+
writeFileSync(path, applyEdits(source, modify(source, ["routing", "isr"], enabled, { formattingOptions: {
|
|
2363
|
+
insertSpaces: true,
|
|
2364
|
+
tabSize: 2
|
|
2365
|
+
} })));
|
|
2366
|
+
}
|
|
1928
2367
|
config.routing = {
|
|
1929
2368
|
...config.routing,
|
|
1930
2369
|
isr: enabled
|
|
1931
2370
|
};
|
|
1932
|
-
log$1.info(`Saved routing.isr: ${String(enabled)} in void.
|
|
2371
|
+
log$1.info(`Saved routing.isr: ${String(enabled)} in void.config.ts. ISR caching ${enabled ? "will be enabled in this deployment" : "stays disabled until you change this setting"}.`);
|
|
1933
2372
|
return enabled;
|
|
1934
2373
|
}
|
|
1935
2374
|
//#endregion
|
|
@@ -2014,22 +2453,25 @@ async function prepareExistingCloudflareDeploy(options) {
|
|
|
2014
2453
|
workerName: config.name
|
|
2015
2454
|
});
|
|
2016
2455
|
writeFileSync(options.configPath, updated);
|
|
2456
|
+
persistCloudflareConfig(options.root);
|
|
2017
2457
|
return existing;
|
|
2018
2458
|
}
|
|
2019
2459
|
/** Offer the existing destination before the legacy hosted-platform fallback. */
|
|
2020
2460
|
async function maybeLinkCloudflareDeploy(root, options = {}, deps = {}) {
|
|
2021
2461
|
if (options.platform || options.backend || options.projectSlug || process.env.VOID_PROJECT || readDeploymentPlatform(root) !== null) return null;
|
|
2022
|
-
const files = [
|
|
2462
|
+
const files = [.../* @__PURE__ */ new Set([...[
|
|
2023
2463
|
"wrangler.jsonc",
|
|
2024
2464
|
"wrangler.json",
|
|
2025
2465
|
"wrangler.toml"
|
|
2026
|
-
].filter((name) => existsSync(join(root, name)));
|
|
2027
|
-
if (!files.length) return null;
|
|
2466
|
+
].filter((name) => existsSync(join(root, name))), ...discoverFrameworkWranglerFiles(root)])];
|
|
2467
|
+
if (!files.length && !existsSync(join(root, "void.config.ts"))) return null;
|
|
2028
2468
|
if (files.length > 1) throw new Error("Multiple Wrangler config files were found. Keep one root configuration before linking to Cloudflare.");
|
|
2029
|
-
const name = files[0];
|
|
2469
|
+
const name = files[0] ?? ".void-wrangler.jsonc";
|
|
2030
2470
|
if (name.endsWith(".toml")) throw new Error("Found wrangler.toml. Direct Cloudflare deployment currently needs a root wrangler.jsonc or wrangler.json with the same settings. Convert the config before linking.");
|
|
2031
2471
|
const errors = [];
|
|
2032
|
-
const
|
|
2472
|
+
const configPath = files.length ? join(root, name) : materializeCloudflareConfig(root);
|
|
2473
|
+
const config = parse(readFileSync(configPath, "utf8"), errors, { allowTrailingComma: true });
|
|
2474
|
+
if (!files.length && (!config || typeof config.name !== "string" || !config.name.trim())) return null;
|
|
2033
2475
|
if (errors.length || !config || typeof config !== "object" || Array.isArray(config) || typeof config.name !== "string" || !config.name.trim()) throw new Error(`Set the existing Worker's name in a valid ${name} before linking to Cloudflare.`);
|
|
2034
2476
|
if (!(deps.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY))) throw new Error(`Found ${name} without a deployment destination. Run void deploy interactively to link the existing Worker, or use void deploy --platform cloudflare with Cloudflare credentials in CI.`);
|
|
2035
2477
|
log$1.info(`Found ${basename(name)} for Worker "${config.name}".`);
|
|
@@ -2084,6 +2526,44 @@ function readCloudflareLocalState(root) {
|
|
|
2084
2526
|
}
|
|
2085
2527
|
}
|
|
2086
2528
|
//#endregion
|
|
2529
|
+
//#region src/cli/installed-void.ts
|
|
2530
|
+
/** A global CLI still builds with the project's installed Vite plugin. */
|
|
2531
|
+
function assertInstalledVoidMatchesCli(root) {
|
|
2532
|
+
const projectManifest = join(root, "package.json");
|
|
2533
|
+
if (!existsSync(projectManifest)) return;
|
|
2534
|
+
const project = JSON.parse(readFileSync(projectManifest, "utf8"));
|
|
2535
|
+
if (![
|
|
2536
|
+
"dependencies",
|
|
2537
|
+
"devDependencies",
|
|
2538
|
+
"optionalDependencies"
|
|
2539
|
+
].some((key) => {
|
|
2540
|
+
const dependencies = project[key];
|
|
2541
|
+
return typeof dependencies === "object" && dependencies !== null && "void" in dependencies;
|
|
2542
|
+
})) return;
|
|
2543
|
+
const cliPackageDir = getPackageDir();
|
|
2544
|
+
const cli = JSON.parse(readFileSync(join(cliPackageDir, "package.json"), "utf8"));
|
|
2545
|
+
let installedVersion;
|
|
2546
|
+
let installedPackageDir;
|
|
2547
|
+
try {
|
|
2548
|
+
const entry = createRequire(projectManifest).resolve("void");
|
|
2549
|
+
let directory = dirname(entry);
|
|
2550
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
2551
|
+
const manifest = join(directory, "package.json");
|
|
2552
|
+
if (existsSync(manifest)) {
|
|
2553
|
+
const installed = JSON.parse(readFileSync(manifest, "utf8"));
|
|
2554
|
+
if (installed.name === "void") {
|
|
2555
|
+
installedVersion = installed.version;
|
|
2556
|
+
installedPackageDir = directory;
|
|
2557
|
+
break;
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
directory = dirname(directory);
|
|
2561
|
+
}
|
|
2562
|
+
} catch {}
|
|
2563
|
+
if (installedVersion !== cli.version) throw new Error(`deploy: this CLI is void@${cli.version}, but the project's installed Vite plugin is ${installedVersion ? `void@${installedVersion}` : "missing"}. Install the same Void version in the project (or link this development checkout) before deploying. The build imports the project package; mixing versions can rewrite legacy config and produce an unsafe Cloudflare deploy target.`);
|
|
2564
|
+
if (installedPackageDir && existsSync(join(cliPackageDir, "src", "index.ts")) && realpathSync(installedPackageDir) !== realpathSync(cliPackageDir)) throw new Error("deploy: this development CLI and the project Vite plugin come from different Void builds, even though their package versions match. Link the same development checkout into the project before deploying.");
|
|
2565
|
+
}
|
|
2566
|
+
//#endregion
|
|
2087
2567
|
//#region src/cli/deploy-errors.ts
|
|
2088
2568
|
const BODY_SNIPPET_MAX = 200;
|
|
2089
2569
|
function trimSnippet(body) {
|
|
@@ -3372,7 +3852,7 @@ function selectBundledEntryFilename(outFiles) {
|
|
|
3372
3852
|
* Determine whether a wrapper is needed based on the features.
|
|
3373
3853
|
*/
|
|
3374
3854
|
function needsWrapper(features) {
|
|
3375
|
-
return features.crons.length > 0 || features.queues.length > 0 || !!features.hasMigrations || !!features.readiness;
|
|
3855
|
+
return features.crons.length > 0 || features.queues.length > 0 || !!features.hasMigrations || !!features.readiness || !!features.isr;
|
|
3376
3856
|
}
|
|
3377
3857
|
/**
|
|
3378
3858
|
* Generate a wrapper entry in-place in the worker directory.
|
|
@@ -3424,8 +3904,8 @@ async function generateWrapper(workerDir, workerMain, root, features) {
|
|
|
3424
3904
|
let migrations;
|
|
3425
3905
|
let migrationPlanBundle;
|
|
3426
3906
|
if (features.hasMigrations) {
|
|
3427
|
-
const { collectMigrations } = await import("./
|
|
3428
|
-
const { buildMigrationPlanBundle } = await import("./
|
|
3907
|
+
const { collectMigrations } = await import("./collect-DAUItMDS.mjs");
|
|
3908
|
+
const { buildMigrationPlanBundle } = await import("./plan-DpuOr14e.mjs");
|
|
3429
3909
|
const migrationsDir = readProjectPaths(root).migrationsDir;
|
|
3430
3910
|
migrations = collectMigrations(migrationsDir);
|
|
3431
3911
|
migrationPlanBundle = features.migrationDialect === "sqlite" ? buildMigrationPlanBundle(migrations) : void 0;
|
|
@@ -3438,6 +3918,7 @@ async function generateWrapper(workerDir, workerMain, root, features) {
|
|
|
3438
3918
|
if (!existsSync(handlerPath)) throw new Error(`Migration handler not found: ${handlerFilename_}. Run "pnpm -C packages/void build" first.`);
|
|
3439
3919
|
await bundleMigrationHandler(root, workerDir, handlerPath, features.migrationDialect ?? "sqlite");
|
|
3440
3920
|
}
|
|
3921
|
+
if (features.isr) await bundleFrameworkIsr(root, workerDir);
|
|
3441
3922
|
const wrapperSource = generateWrapperSource(renamedName, handlerFilename, features, migrations, migrationPlanBundle);
|
|
3442
3923
|
const stagedPath = `${mainPath}.${crypto.randomUUID()}.tmp`;
|
|
3443
3924
|
try {
|
|
@@ -3448,6 +3929,33 @@ async function generateWrapper(workerDir, workerMain, root, features) {
|
|
|
3448
3929
|
rmSync(stagedPath, { force: true });
|
|
3449
3930
|
}
|
|
3450
3931
|
}
|
|
3932
|
+
async function bundleFrameworkIsr(root, workerDir) {
|
|
3933
|
+
const entry = fileURLToPath(import.meta.resolve("@void/isr/runtime"));
|
|
3934
|
+
const tmpDir = join(root, ".void", "isr");
|
|
3935
|
+
const outDir = join(tmpDir, "out");
|
|
3936
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
3937
|
+
await build({
|
|
3938
|
+
root: tmpDir,
|
|
3939
|
+
logLevel: "silent",
|
|
3940
|
+
ssr: { noExternal: true },
|
|
3941
|
+
build: {
|
|
3942
|
+
outDir,
|
|
3943
|
+
emptyOutDir: true,
|
|
3944
|
+
minify: false,
|
|
3945
|
+
ssr: entry,
|
|
3946
|
+
target: "esnext",
|
|
3947
|
+
rollupOptions: {
|
|
3948
|
+
input: entry,
|
|
3949
|
+
external: [/^cloudflare:/, /^node:/],
|
|
3950
|
+
output: {
|
|
3951
|
+
entryFileNames: "__void_isr.mjs",
|
|
3952
|
+
chunkFileNames: "__void_isr-[hash].mjs"
|
|
3953
|
+
}
|
|
3954
|
+
}
|
|
3955
|
+
}
|
|
3956
|
+
});
|
|
3957
|
+
for (const file of readdirSync(outDir)) copyFileSync(join(outDir, file), join(workerDir, file));
|
|
3958
|
+
}
|
|
3451
3959
|
async function bundleMigrationHandler(root, workerDir, handlerPath, dialect) {
|
|
3452
3960
|
const tmpDir = join(root, ".void", "migration-handler");
|
|
3453
3961
|
mkdirSync(tmpDir, { recursive: true });
|
|
@@ -3602,6 +4110,7 @@ function cleanupWrapper(root) {
|
|
|
3602
4110
|
for (const directory of [
|
|
3603
4111
|
"handlers",
|
|
3604
4112
|
"migration-handler",
|
|
4113
|
+
"isr",
|
|
3605
4114
|
"bundle"
|
|
3606
4115
|
]) rmSync(join(voidDir, directory), {
|
|
3607
4116
|
recursive: true,
|
|
@@ -3612,6 +4121,14 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
|
|
|
3612
4121
|
const lines = [];
|
|
3613
4122
|
lines.push(WRAPPER_MARKER);
|
|
3614
4123
|
lines.push(`import original from "./${renamedEntry}";`);
|
|
4124
|
+
if (features.isr) {
|
|
4125
|
+
lines.push("import { handleFrameworkIsr } from \"./__void_isr.mjs\";");
|
|
4126
|
+
lines.push(`const __voidIsrDeploymentId = ${JSON.stringify(crypto.randomUUID())};`);
|
|
4127
|
+
lines.push(`const __voidIsrPolicy = ${JSON.stringify({
|
|
4128
|
+
revalidate: features.isr.revalidate,
|
|
4129
|
+
queryAllowlist: features.isr.queryAllowlist
|
|
4130
|
+
})};`);
|
|
4131
|
+
}
|
|
3615
4132
|
if (features.crons.length > 0) lines.push(`import { handleScheduled } from "./${handlersModule}";`);
|
|
3616
4133
|
if (features.queues.length > 0) lines.push(`import { handleQueue, handleQueueRelay } from "./${handlersModule}";`);
|
|
3617
4134
|
if (migrations && migrations.length > 0) {
|
|
@@ -3621,10 +4138,14 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
|
|
|
3621
4138
|
lines.push(`const __migrationDialect = ${JSON.stringify(features.migrationDialect ?? "sqlite")};`);
|
|
3622
4139
|
}
|
|
3623
4140
|
lines.push("");
|
|
3624
|
-
const needsFetchWrap = features.readiness || features.crons.length > 0 || features.queues.length > 0 || migrations && migrations.length > 0;
|
|
4141
|
+
const needsFetchWrap = features.readiness || features.crons.length > 0 || features.queues.length > 0 || migrations && migrations.length > 0 || !!features.isr;
|
|
3625
4142
|
if (needsFetchWrap) {
|
|
3626
4143
|
lines.push("async function wrappedFetch(request, env, ctx) {");
|
|
3627
4144
|
lines.push(" const url = new URL(request.url);");
|
|
4145
|
+
if (features.isr) {
|
|
4146
|
+
lines.push(" env.__VOID_ISR_DEPLOYMENT_ID ??= __voidIsrDeploymentId;");
|
|
4147
|
+
lines.push(" env.__VOID_ISR_HOST = url.hostname;");
|
|
4148
|
+
}
|
|
3628
4149
|
if (features.readiness || features.crons.length > 0 || features.queues.length > 0 || features.hasMigrations) {
|
|
3629
4150
|
lines.push(" if (request.method === \"GET\" && url.pathname === \"/__void/ready\") {");
|
|
3630
4151
|
lines.push(" return Response.json({ ready: true });");
|
|
@@ -3686,6 +4207,12 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
|
|
|
3686
4207
|
lines.push(" }");
|
|
3687
4208
|
lines.push(" }");
|
|
3688
4209
|
}
|
|
4210
|
+
if (features.isr) {
|
|
4211
|
+
lines.push(" if (env.ISR_CACHE && request.headers.get(\"upgrade\")?.toLowerCase() !== \"websocket\") {");
|
|
4212
|
+
lines.push(" const cached = await handleFrameworkIsr(request, env, ctx, { ...__voidIsrPolicy, deploymentId: __voidIsrDeploymentId }, (req) => original.fetch(req, env, ctx));");
|
|
4213
|
+
lines.push(" if (cached) return cached;");
|
|
4214
|
+
lines.push(" }");
|
|
4215
|
+
}
|
|
3689
4216
|
lines.push(" return original.fetch(request, env, ctx);");
|
|
3690
4217
|
lines.push("}");
|
|
3691
4218
|
lines.push("");
|
|
@@ -3693,8 +4220,8 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
|
|
|
3693
4220
|
lines.push("export default {");
|
|
3694
4221
|
if (needsFetchWrap) lines.push(" fetch: wrappedFetch,");
|
|
3695
4222
|
else lines.push(" fetch: original.fetch,");
|
|
3696
|
-
if (features.crons.length > 0) lines.push(" scheduled: handleScheduled,");
|
|
3697
|
-
if (features.queues.length > 0) lines.push(" queue: handleQueue,");
|
|
4223
|
+
if (features.crons.length > 0) lines.push(features.isr ? " scheduled(controller, env, ctx) { env.__VOID_ISR_DEPLOYMENT_ID ??= __voidIsrDeploymentId; return handleScheduled(controller, env, ctx); }," : " scheduled: handleScheduled,");
|
|
4224
|
+
if (features.queues.length > 0) lines.push(features.isr ? " queue(batch, env, ctx) { env.__VOID_ISR_DEPLOYMENT_ID ??= __voidIsrDeploymentId; return handleQueue(batch, env, ctx); }," : " queue: handleQueue,");
|
|
3698
4225
|
lines.push("};");
|
|
3699
4226
|
return lines.join("\n");
|
|
3700
4227
|
}
|
|
@@ -3782,66 +4309,6 @@ export async function handleQueueRelay(payload, env, ctx) {
|
|
|
3782
4309
|
}
|
|
3783
4310
|
//#endregion
|
|
3784
4311
|
//#region src/cli/deploy.ts
|
|
3785
|
-
var deploy_exports = /* @__PURE__ */ __exportAll({
|
|
3786
|
-
CloudflareAuthSecretError: () => CloudflareAuthSecretError,
|
|
3787
|
-
DEPLOY_PASSTHROUGH_ASSERT_FIELDS: () => DEPLOY_PASSTHROUGH_ASSERT_FIELDS,
|
|
3788
|
-
DEPLOY_PASSTHROUGH_EXCLUDE_FIELDS: () => DEPLOY_PASSTHROUGH_EXCLUDE_FIELDS,
|
|
3789
|
-
DEPLOY_WHOLE_OBJECT_PINNED_FIELDS: () => DEPLOY_WHOLE_OBJECT_PINNED_FIELDS,
|
|
3790
|
-
applyDeployEvent: () => applyDeployEvent,
|
|
3791
|
-
assembleVoidManifest: () => assembleVoidManifest,
|
|
3792
|
-
assertManagedDurableStateSupported: () => assertManagedDurableStateSupported,
|
|
3793
|
-
assertMigrationsProduceAuthSchema: () => assertMigrationsProduceAuthSchema,
|
|
3794
|
-
assertNoConfigOverrideInProjectDotenv: () => assertNoConfigOverrideInProjectDotenv,
|
|
3795
|
-
assertRemoteMigrationsDeployable: () => assertRemoteMigrationsDeployable,
|
|
3796
|
-
assertWranglerUploaderUnchanged: () => assertWranglerUploaderUnchanged,
|
|
3797
|
-
checkWranglerMigrationApplySet: () => checkWranglerMigrationApplySet,
|
|
3798
|
-
compareWranglerMigrationPaths: () => compareWranglerMigrationPaths,
|
|
3799
|
-
computeDesiredCloudflareResources: () => computeDesiredCloudflareResources,
|
|
3800
|
-
createDeployWranglerRunner: () => createDeployWranglerRunner,
|
|
3801
|
-
deployChildEnv: () => deployChildEnv,
|
|
3802
|
-
deriveWorkerName: () => deriveWorkerName,
|
|
3803
|
-
discoverRootWranglerConfig: () => discoverRootWranglerConfig,
|
|
3804
|
-
ensureCloudflareAuthSecret: () => ensureCloudflareAuthSecret,
|
|
3805
|
-
ensurePreviouslyDeployedLiveBindingConfig: () => ensurePreviouslyDeployedLiveBindingConfig,
|
|
3806
|
-
formatCloudflareActivationError: () => formatCloudflareActivationError,
|
|
3807
|
-
formatCloudflareSandboxUnavailable: () => formatCloudflareSandboxUnavailable,
|
|
3808
|
-
generateDeployWrapperIfNeeded: () => generateDeployWrapperIfNeeded,
|
|
3809
|
-
hasDeploySchemaDrift: () => hasDeploySchemaDrift,
|
|
3810
|
-
hasNonPageBackend: () => hasNonPageBackend,
|
|
3811
|
-
hasPrerenderSources: () => hasPrerenderSources,
|
|
3812
|
-
hashWranglerUploader: () => hashWranglerUploader,
|
|
3813
|
-
isWranglerNonInteractiveOrCI: () => isWranglerNonInteractiveOrCI,
|
|
3814
|
-
loadProvisionModule: () => loadProvisionModule,
|
|
3815
|
-
parseRootWranglerConfig: () => parseRootWranglerConfig$1,
|
|
3816
|
-
prepareCloudflareFrameworkArtifact: () => prepareCloudflareFrameworkArtifact,
|
|
3817
|
-
promptDeployProjectConfig: () => promptDeployProjectConfig,
|
|
3818
|
-
reconstructExpectedContainers: () => reconstructExpectedContainers,
|
|
3819
|
-
resolveCloudflareVoidStaticPreset: () => resolveCloudflareVoidStaticPreset,
|
|
3820
|
-
resolveDeployLiveBindingConfig: () => resolveDeployLiveBindingConfig,
|
|
3821
|
-
resolveDeployTransport: () => resolveDeployTransport,
|
|
3822
|
-
resolveDeployWorkerMain: () => resolveDeployWorkerMain,
|
|
3823
|
-
resolveDeployWranglerCompat: () => resolveDeployWranglerCompat,
|
|
3824
|
-
resolveDeploymentPlatform: () => resolveDeploymentPlatform,
|
|
3825
|
-
resolveDistDir: () => resolveDistDir,
|
|
3826
|
-
resolveFullDeployBuildCommand: () => resolveFullDeployBuildCommand,
|
|
3827
|
-
resolveStaticBuildCommand: () => resolveStaticBuildCommand,
|
|
3828
|
-
resolveStaticDeployPreset: () => resolveStaticDeployPreset,
|
|
3829
|
-
resolveWorkerDirName: () => resolveWorkerDirName,
|
|
3830
|
-
resolveWranglerMigrationPattern: () => resolveWranglerMigrationPattern,
|
|
3831
|
-
runCloudflareDeploy: () => runCloudflareDeploy,
|
|
3832
|
-
runDeploy: () => runDeploy,
|
|
3833
|
-
runStaticDeploy: () => runStaticDeploy,
|
|
3834
|
-
runWranglerAuthToken: () => runWranglerAuthToken,
|
|
3835
|
-
snapshotBindingIdentities: () => snapshotBindingIdentities,
|
|
3836
|
-
snapshotPassthroughIdentities: () => snapshotPassthroughIdentities,
|
|
3837
|
-
snapshotPassthroughRawFields: () => snapshotPassthroughRawFields,
|
|
3838
|
-
streamDeployEvents: () => streamDeployEvents,
|
|
3839
|
-
validateAuthMigrationSchema: () => validateAuthMigrationSchema,
|
|
3840
|
-
verifyGeneratedDeployConfig: () => verifyGeneratedDeployConfig,
|
|
3841
|
-
warnIgnoredNotFoundForFramework: () => warnIgnoredNotFoundForFramework,
|
|
3842
|
-
warnRedundantForceOn3xx: () => warnRedundantForceOn3xx,
|
|
3843
|
-
warnUnpublishedRouting: () => warnUnpublishedRouting
|
|
3844
|
-
});
|
|
3845
4312
|
const drizzleKitBin = join(fileURLToPath(import.meta.resolve("drizzle-kit")), "..", "bin.cjs");
|
|
3846
4313
|
const deployDriftCheckDir = join(".void", "deploy-drift-check");
|
|
3847
4314
|
let loadedProvisionModule;
|
|
@@ -3851,7 +4318,7 @@ let loadedProvisionModule;
|
|
|
3851
4318
|
* so a managed deploy never imports it — and thus never loads `proper-lockfile`.
|
|
3852
4319
|
*/
|
|
3853
4320
|
async function loadProvisionModule() {
|
|
3854
|
-
loadedProvisionModule ??= await import("./provision-
|
|
4321
|
+
loadedProvisionModule ??= await import("./provision-CNgEBkVA.mjs");
|
|
3855
4322
|
return loadedProvisionModule;
|
|
3856
4323
|
}
|
|
3857
4324
|
/**
|
|
@@ -4438,6 +4905,34 @@ function hashWranglerUploader(root, resolveArgv = resolveWranglerArgv) {
|
|
|
4438
4905
|
if (typeof entry !== "string" || entry.length === 0 || !existsSync(entry)) return;
|
|
4439
4906
|
return hashDirectoryContents(dirname(entry));
|
|
4440
4907
|
}
|
|
4908
|
+
/** Pin the cf uploader and prebuilt-artifact builders before project code runs. */
|
|
4909
|
+
function hashCfUploader() {
|
|
4910
|
+
try {
|
|
4911
|
+
const hash = createHash("sha256");
|
|
4912
|
+
for (const name of [
|
|
4913
|
+
"cf",
|
|
4914
|
+
"@cloudflare/config",
|
|
4915
|
+
"@cloudflare/build-output-utils",
|
|
4916
|
+
"vite"
|
|
4917
|
+
]) {
|
|
4918
|
+
let path = dirname(fileURLToPath(import.meta.resolve(name)));
|
|
4919
|
+
while (!existsSync(join(path, "package.json"))) {
|
|
4920
|
+
const parent = dirname(path);
|
|
4921
|
+
if (parent === path) return;
|
|
4922
|
+
path = parent;
|
|
4923
|
+
}
|
|
4924
|
+
const contents = hashDirectoryContents(path);
|
|
4925
|
+
if (!contents) return;
|
|
4926
|
+
hash.update(name);
|
|
4927
|
+
hash.update("\0");
|
|
4928
|
+
hash.update(contents);
|
|
4929
|
+
hash.update("\0");
|
|
4930
|
+
}
|
|
4931
|
+
return hash.digest("hex");
|
|
4932
|
+
} catch {
|
|
4933
|
+
return;
|
|
4934
|
+
}
|
|
4935
|
+
}
|
|
4441
4936
|
/**
|
|
4442
4937
|
* sha256 over every file under `dir`, walked in a STABLE (name-sorted, depth-first) order with
|
|
4443
4938
|
* each file's relative path folded into the digest, so the hash depends only on the directory's
|
|
@@ -4475,11 +4970,11 @@ function hashDirectoryContents(dir) {
|
|
|
4475
4970
|
function assertWranglerUploaderUnchanged(before, after) {
|
|
4476
4971
|
if (before === void 0 || after === void 0) return {
|
|
4477
4972
|
ok: false,
|
|
4478
|
-
reason: `could not resolve or hash the
|
|
4973
|
+
reason: `could not resolve or hash the Cloudflare uploader to verify it across the build — refusing to run a deploy binary that cannot be verified.`
|
|
4479
4974
|
};
|
|
4480
4975
|
if (before !== after) return {
|
|
4481
4976
|
ok: false,
|
|
4482
|
-
reason: `the build modified the
|
|
4977
|
+
reason: `the build modified the Cloudflare uploader (its bundle hash changed across the build) — refusing to run it with your Cloudflare credentials.`
|
|
4483
4978
|
};
|
|
4484
4979
|
return { ok: true };
|
|
4485
4980
|
}
|
|
@@ -4732,14 +5227,12 @@ function resolveGeneratedDeployConfigPathDefault(root) {
|
|
|
4732
5227
|
function readGeneratedDeployConfig(root) {
|
|
4733
5228
|
const redirectedPath = resolveGeneratedDeployConfigPathDefault(root);
|
|
4734
5229
|
try {
|
|
4735
|
-
const config = JSON.parse(readFileSync(redirectedPath, "utf-8"));
|
|
4736
|
-
if (config === null || typeof config !== "object" || Array.isArray(config)) throw new Error("malformed config");
|
|
4737
5230
|
return {
|
|
4738
5231
|
path: redirectedPath,
|
|
4739
|
-
config
|
|
5232
|
+
config: readGeneratedWranglerConfigFile(redirectedPath)
|
|
4740
5233
|
};
|
|
4741
5234
|
} catch {
|
|
4742
|
-
throw new Error(`Generated Cloudflare deploy config ${redirectedPath} is missing or invalid JSON.`);
|
|
5235
|
+
throw new Error(`Generated Cloudflare deploy config ${redirectedPath} is missing or invalid JSON/JSONC.`);
|
|
4743
5236
|
}
|
|
4744
5237
|
}
|
|
4745
5238
|
/** Older project plugins can repeat root flags; normalize only the generated artifact. */
|
|
@@ -4827,11 +5320,11 @@ function verifyGeneratedDeployConfig(root, expected) {
|
|
|
4827
5320
|
};
|
|
4828
5321
|
let generated;
|
|
4829
5322
|
try {
|
|
4830
|
-
generated =
|
|
5323
|
+
generated = readGeneratedWranglerConfigFile(redirectedPath);
|
|
4831
5324
|
} catch {
|
|
4832
5325
|
return {
|
|
4833
5326
|
ok: false,
|
|
4834
|
-
reason: `generated wrangler config ${redirectedPath} is not valid JSON.`
|
|
5327
|
+
reason: `generated wrangler config ${redirectedPath} is not valid JSON/JSONC.`
|
|
4835
5328
|
};
|
|
4836
5329
|
}
|
|
4837
5330
|
if (generated.account_id !== expected.accountId) return {
|
|
@@ -5640,31 +6133,28 @@ async function checkWranglerMigrationApplySet(configPath, config, binding, migra
|
|
|
5640
6133
|
* child env (via {@link deployChildEnv} — reused provisioner scrub/pin: CF Access +
|
|
5641
6134
|
* every transport selector incl. `CLOUDFLARE_ENV` + the deploy config-override vars
|
|
5642
6135
|
* scrubbed, one account + API base pinned), so `whoami`/`migrate`/`deploy` can never
|
|
5643
|
-
* consult a different ambient account or endpoint.
|
|
5644
|
-
* `opts.env` layers one more pin
|
|
6136
|
+
* consult a different ambient account or endpoint. Noninteractive output is captured so Void
|
|
6137
|
+
* controls the terminal; browser login still inherits stdio. `opts.env` layers one more pin
|
|
6138
|
+
* over the child env for a single spawn (`auth token` gets
|
|
5645
6139
|
* `WRANGLER_WRITE_LOGS=false`, see {@link runWranglerAuthToken}).
|
|
5646
6140
|
*/
|
|
5647
6141
|
function createDeployWranglerRunner(root, accountId, apiBaseUrl) {
|
|
5648
6142
|
const [command, ...prefix] = resolveWranglerArgv(root);
|
|
5649
6143
|
return (args, opts) => {
|
|
5650
6144
|
const childEnv = deployChildEnv(accountId, apiBaseUrl);
|
|
5651
|
-
const
|
|
5652
|
-
if (!opts.capture ||
|
|
6145
|
+
const interactiveLogin = cloudflareAuthNeedsTerminal(args);
|
|
6146
|
+
if (!opts.capture || interactiveLogin) childEnv.WRANGLER_LOG = "none";
|
|
5653
6147
|
if (opts.env) Object.assign(childEnv, opts.env);
|
|
5654
6148
|
const result = spawnSync(command, [...prefix, ...args], {
|
|
5655
6149
|
cwd: root,
|
|
5656
|
-
stdio:
|
|
5657
|
-
"inherit",
|
|
5658
|
-
"inherit",
|
|
5659
|
-
"ignore"
|
|
5660
|
-
] : opts.input === void 0 ? opts.capture ? [
|
|
6150
|
+
stdio: interactiveLogin ? "inherit" : opts.input === void 0 ? [
|
|
5661
6151
|
"ignore",
|
|
5662
6152
|
"pipe",
|
|
5663
6153
|
"pipe"
|
|
5664
|
-
] :
|
|
6154
|
+
] : [
|
|
5665
6155
|
"pipe",
|
|
5666
|
-
|
|
5667
|
-
|
|
6156
|
+
"pipe",
|
|
6157
|
+
"pipe"
|
|
5668
6158
|
],
|
|
5669
6159
|
input: opts.input,
|
|
5670
6160
|
encoding: "utf-8",
|
|
@@ -5791,7 +6281,7 @@ async function runCloudflareEmailStep(input) {
|
|
|
5791
6281
|
};
|
|
5792
6282
|
const from = input.voidConfig.email?.from;
|
|
5793
6283
|
if (!from) {
|
|
5794
|
-
log.warn(["deploy: this app uses email, but void.
|
|
6284
|
+
log.warn(["deploy: this app uses email, but void.config.ts names no sender.", "Set email.from to \"you@mail.acme.com\" in void.config.ts — deploying without email."].join("\n"));
|
|
5795
6285
|
return without;
|
|
5796
6286
|
}
|
|
5797
6287
|
const { rootConfig } = input;
|
|
@@ -5900,7 +6390,7 @@ async function runCloudflareEmailStep(input) {
|
|
|
5900
6390
|
};
|
|
5901
6391
|
};
|
|
5902
6392
|
if (pre.blockers.some((b) => b.scope === "all")) return leaveAccount(`email on ${pre.domain} cannot be set up from here.`);
|
|
5903
|
-
if (input.nonInteractive) return leaveAccount([`email on ${pre.domain} is not ${shipsBinding ? "fully " : ""}set up, and this shell cannot ask.`, "Run `void email setup --platform cloudflare` once locally, commit
|
|
6393
|
+
if (input.nonInteractive) return leaveAccount([`email on ${pre.domain} is not ${shipsBinding ? "fully " : ""}set up, and this shell cannot ask.`, "Run `void email setup --platform cloudflare` once locally, commit void.lock.json, then redeploy."].join("\n"));
|
|
5904
6394
|
if (!await input.confirm(`Set up email on ${pre.domain}?`)) return leaveAccount("email setup skipped — run `void email setup --platform cloudflare` later.");
|
|
5905
6395
|
const out = await applyEmailSetup(pre, inputs);
|
|
5906
6396
|
if (out.lines.length > 0) log.message(out.lines.join("\n"));
|
|
@@ -5962,6 +6452,11 @@ async function ensureCloudflareAuthSecret(options) {
|
|
|
5962
6452
|
};
|
|
5963
6453
|
if ((await list(true)).includes(BETTER_AUTH_SECRET_NAME)) return { created: false };
|
|
5964
6454
|
const secret = randomBytes(32).toString("hex");
|
|
6455
|
+
if (workerWasMissing) return {
|
|
6456
|
+
created: true,
|
|
6457
|
+
workerWasMissing: true,
|
|
6458
|
+
candidateSecret: secret
|
|
6459
|
+
};
|
|
5965
6460
|
beforeRun();
|
|
5966
6461
|
let put;
|
|
5967
6462
|
try {
|
|
@@ -5979,8 +6474,8 @@ async function ensureCloudflareAuthSecret(options) {
|
|
|
5979
6474
|
} catch {
|
|
5980
6475
|
throw new CloudflareAuthSecretError(`deploy: could not create the remote ${BETTER_AUTH_SECRET_NAME}. No worker was uploaded. Run \`void secret put ${BETTER_AUTH_SECRET_NAME}\` and retry.`, "put-failed");
|
|
5981
6476
|
}
|
|
5982
|
-
if (!isCleanWranglerExit(put)) throw new CloudflareAuthSecretError(`deploy: could not create the remote ${BETTER_AUTH_SECRET_NAME} (
|
|
5983
|
-
if (!(await list(false)).includes(BETTER_AUTH_SECRET_NAME)) throw new CloudflareAuthSecretError(`deploy:
|
|
6477
|
+
if (!isCleanWranglerExit(put)) throw new CloudflareAuthSecretError(`deploy: could not create the remote ${BETTER_AUTH_SECRET_NAME} (Cloudflare command exit ${String(put.status)}). No worker was uploaded. Run \`void secret put ${BETTER_AUTH_SECRET_NAME}\` and retry.`, "put-failed");
|
|
6478
|
+
if (!(await list(false)).includes(BETTER_AUTH_SECRET_NAME)) throw new CloudflareAuthSecretError(`deploy: Cloudflare reported success but ${BETTER_AUTH_SECRET_NAME} was not present afterward. No worker was uploaded; retry once Cloudflare secret storage is available.`, "verification-failed");
|
|
5984
6479
|
return {
|
|
5985
6480
|
created: true,
|
|
5986
6481
|
...workerWasMissing ? { workerWasMissing: true } : {}
|
|
@@ -6080,10 +6575,16 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
6080
6575
|
}
|
|
6081
6576
|
const hashUploader = deps.hashWranglerUploader ?? hashWranglerUploader;
|
|
6082
6577
|
const wranglerUploaderHashBefore = hashUploader(root);
|
|
6578
|
+
const cfUploaderHashBefore = deps.activateVersion || deps.runWrangler ? void 0 : hashCfUploader();
|
|
6579
|
+
const cfUploaderIsPinned = () => {
|
|
6580
|
+
const matched = cfUploaderHashBefore !== void 0 && cfUploaderHashBefore === hashCfUploader();
|
|
6581
|
+
if (!matched) log.error("deploy: refusing to run a changed cf uploader with Cloudflare credentials.");
|
|
6582
|
+
return matched;
|
|
6583
|
+
};
|
|
6083
6584
|
const assertUploaderStillPinned = () => {
|
|
6084
6585
|
const check = assertWranglerUploaderUnchanged(wranglerUploaderHashBefore, hashUploader(root));
|
|
6085
6586
|
if (check.ok) return true;
|
|
6086
|
-
log.error(["deploy: refusing to run the
|
|
6587
|
+
log.error(["deploy: refusing to run the Cloudflare uploader with your Cloudflare credentials.", check.reason].filter(Boolean).join("\n"));
|
|
6087
6588
|
return false;
|
|
6088
6589
|
};
|
|
6089
6590
|
let accountId = readWranglerTopLevelString(rootConfig, "account_id") ?? (process.env.CLOUDFLARE_ACCOUNT_ID?.trim() || void 0);
|
|
@@ -6148,10 +6649,10 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
6148
6649
|
const staleAddresses = Array.isArray(rootConfig.addresses) ? rootConfig.addresses.filter((a) => typeof a === "string") : [];
|
|
6149
6650
|
const staleBinding = Array.isArray(rootConfig.send_email) && rootConfig.send_email.some((e) => e?.name === "SEND_EMAIL");
|
|
6150
6651
|
if (staleAddresses.length > 0 || staleBinding) log.warn([
|
|
6151
|
-
"deploy: this app no longer declares email handlers or imports void/email, but
|
|
6652
|
+
"deploy: this app no longer declares email handlers or imports void/email, but the Cloudflare config still carries the email setup Void wrote:",
|
|
6152
6653
|
...staleAddresses.map((a) => ` • ${a} — still routed to worker "${workerName}", which no longer exports email(); inbound mail there will fail.`),
|
|
6153
6654
|
...staleBinding ? [` • send_email ${SEND_EMAIL_BINDING} binding`] : [],
|
|
6154
|
-
"Deploying as-is. To detach: remove `addresses`, `send_email
|
|
6655
|
+
"Deploying as-is. To detach: remove `addresses`, `send_email`, and `vars.__VOID_EMAIL_FROM` from `resolved` in void.lock.json (and any authored overrides in void.config.ts), then delete the rules in the Cloudflare dashboard (Email → Email Routing → Routing rules)."
|
|
6155
6656
|
].join("\n"));
|
|
6156
6657
|
}
|
|
6157
6658
|
const schemaProbeEnv = buildSchemaProbeEnv(accountId, apiBaseUrl);
|
|
@@ -6255,7 +6756,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
6255
6756
|
const provisionAndVerify = async () => {
|
|
6256
6757
|
if (existingWorker) {
|
|
6257
6758
|
const { missing } = provisionModule.checkCloudflareProvisionDrift(configPath, desired);
|
|
6258
|
-
throw new Error(missing.length > 0 ? formatCloudflareDriftMessage(missing, reasons, "Linking cannot provision these inferred resources:", `Check the existing Worker's binding names and resource IDs in
|
|
6759
|
+
throw new Error(missing.length > 0 ? formatCloudflareDriftMessage(missing, reasons, "Linking cannot provision these inferred resources:", `Check the existing Worker's binding names and resource IDs in void.config.ts and inference.bindings there, then rerun \`void deploy\`. Keep new resources for a later deployment.`) : "Linking cannot provision resources. Remove --provision and rerun `void deploy` to reuse the existing Worker.");
|
|
6259
6760
|
}
|
|
6260
6761
|
if (!assertUploaderStillPinned()) return exit(1);
|
|
6261
6762
|
const provision = deps.provision ?? provisionModule.provisionCloudflareResources;
|
|
@@ -6381,8 +6882,9 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
6381
6882
|
log.error(`deploy: build failed — ${getErrorMessage(err)}`);
|
|
6382
6883
|
return exit(getExitCode(err));
|
|
6383
6884
|
}
|
|
6885
|
+
log.step("Preparing deployment...");
|
|
6384
6886
|
if (detectedFramework && frameworkPreset) try {
|
|
6385
|
-
await (deps.prepareFrameworkArtifact ?? prepareCloudflareFrameworkArtifact)(root, configPath, accountId, workerName, voidConfig, detectedFramework, frameworkPreset, schemaFacts.requiredKeys);
|
|
6887
|
+
await (deps.prepareFrameworkArtifact ?? prepareCloudflareFrameworkArtifact)(root, configPath, accountId, workerName, voidConfig, detectedFramework, frameworkPreset, schemaFacts.requiredKeys, needsAI ? { binding: aiBindingName } : void 0);
|
|
6386
6888
|
} catch (error) {
|
|
6387
6889
|
log.error(`deploy: could not prepare ${detectedFramework.name} for Cloudflare — ${getErrorMessage(error)}`);
|
|
6388
6890
|
return exit(1);
|
|
@@ -6541,7 +7043,22 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
6541
7043
|
d1MigrateToken = migrateTarget.token;
|
|
6542
7044
|
}
|
|
6543
7045
|
}
|
|
7046
|
+
const generatedConfigPath = (deps.resolveGeneratedConfigPath ?? resolveGeneratedDeployConfigPathDefault)(root);
|
|
7047
|
+
const prepareBuildOutput = () => frameworkPreset?.cloudflareArtifact === "worker-output" ? prepareCfFrameworkBuildOutput({
|
|
7048
|
+
projectRoot: root,
|
|
7049
|
+
configPath: generatedConfigPath,
|
|
7050
|
+
accountId
|
|
7051
|
+
}) : prepareCfBuildOutput(dirname(generatedConfigPath), accountId);
|
|
7052
|
+
if (!deps.activateVersion && !deps.runWrangler) {
|
|
7053
|
+
const preflight = await prepareBuildOutput();
|
|
7054
|
+
if (!preflight) {
|
|
7055
|
+
log.error("deploy: cf could not prepare the built Worker for deployment.");
|
|
7056
|
+
return exit(1);
|
|
7057
|
+
}
|
|
7058
|
+
preflight.dispose();
|
|
7059
|
+
}
|
|
6544
7060
|
let workerWasMissingBeforeSecretProvisioning = false;
|
|
7061
|
+
let initialAuthSecret;
|
|
6545
7062
|
if (authEnabled) {
|
|
6546
7063
|
const inheritance = (deps.verifyDeployConfig ?? verifyGeneratedDeployConfig)(root, {
|
|
6547
7064
|
accountId,
|
|
@@ -6570,6 +7087,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
6570
7087
|
beforeWranglerRun: assertUploaderStillPinned
|
|
6571
7088
|
});
|
|
6572
7089
|
workerWasMissingBeforeSecretProvisioning ||= authSecret.workerWasMissing === true;
|
|
7090
|
+
initialAuthSecret = authSecret.candidateSecret;
|
|
6573
7091
|
cliLog.info("cloudflare_auth_secret_ready", { created: authSecret.created });
|
|
6574
7092
|
} catch (error) {
|
|
6575
7093
|
if (error instanceof CloudflareAuthSecretError && error.reason === "uploader-changed") return exit(1);
|
|
@@ -6611,6 +7129,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
6611
7129
|
}
|
|
6612
7130
|
}
|
|
6613
7131
|
if (d1MigrateToken) {
|
|
7132
|
+
log.step("Applying D1 migrations...");
|
|
6614
7133
|
if (!assertUploaderStillPinned()) return exit(1);
|
|
6615
7134
|
const migrate = await Promise.resolve(runWrangler([
|
|
6616
7135
|
"d1",
|
|
@@ -6686,23 +7205,35 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
6686
7205
|
].filter(Boolean).join("\n"));
|
|
6687
7206
|
return exit(1);
|
|
6688
7207
|
}
|
|
6689
|
-
const generatedConfigPath = (deps.resolveGeneratedConfigPath ?? resolveGeneratedDeployConfigPathDefault)(root);
|
|
6690
7208
|
const queueConsumerCleanup = readWranglerManagedQueueCleanupCandidates(configPath);
|
|
6691
7209
|
if (existingWorker) assertCloudflareLinkUnchanged(root, pinnedHandoffLink);
|
|
6692
7210
|
const candidateReceipt = pinnedHandoffLink?.candidateReceipt;
|
|
6693
|
-
|
|
6694
|
-
|
|
7211
|
+
if (!deps.activateVersion && !deps.runWrangler && !cfUploaderIsPinned()) return exit(1);
|
|
7212
|
+
const cfOutput = deps.activateVersion || deps.runWrangler ? null : await prepareBuildOutput();
|
|
7213
|
+
if (!cfOutput && !deps.activateVersion && !deps.runWrangler) {
|
|
7214
|
+
log.error("deploy: cf could not prepare the built Worker for deployment.");
|
|
7215
|
+
return exit(1);
|
|
7216
|
+
}
|
|
7217
|
+
const cfCommand = cfOutput ? createCfCommand({
|
|
6695
7218
|
accountId,
|
|
6696
7219
|
apiBaseUrl,
|
|
7220
|
+
env: deployChildEnv,
|
|
7221
|
+
verifyUploader: cfUploaderIsPinned
|
|
7222
|
+
}) : null;
|
|
7223
|
+
const activationRunner = cfOutput && cfCommand ? createCfVersionRunner({
|
|
7224
|
+
output: cfOutput,
|
|
6697
7225
|
workerName,
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
7226
|
+
runCf: cfCommand,
|
|
7227
|
+
verifyResources: createCfResourceVerifier({
|
|
7228
|
+
configPath: generatedConfigPath,
|
|
7229
|
+
runCf: cfCommand,
|
|
7230
|
+
runWrangler,
|
|
7231
|
+
verifyCompatibilityRunner: assertUploaderStillPinned
|
|
7232
|
+
})
|
|
7233
|
+
}) : runWrangler;
|
|
7234
|
+
const execution = await activateCloudflareVersionWithProgress(deps.activateVersion ?? activateCloudflareVersion, {
|
|
6704
7235
|
runWrangler: activationRunner,
|
|
6705
|
-
verifyUploader: assertUploaderStillPinned,
|
|
7236
|
+
verifyUploader: cfOutput ? cfUploaderIsPinned : assertUploaderStillPinned,
|
|
6706
7237
|
workerName,
|
|
6707
7238
|
configPath: generatedConfigPath,
|
|
6708
7239
|
preserveTriggers: existingWorker !== null,
|
|
@@ -6734,10 +7265,18 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
6734
7265
|
workerName,
|
|
6735
7266
|
runWrangler
|
|
6736
7267
|
}),
|
|
7268
|
+
publishEmptyCrons: createCloudflareEmptyCronPublisher({
|
|
7269
|
+
accountId,
|
|
7270
|
+
apiBaseUrl,
|
|
7271
|
+
configPath: generatedConfigPath,
|
|
7272
|
+
workerName,
|
|
7273
|
+
runWrangler
|
|
7274
|
+
}),
|
|
6737
7275
|
previousTrafficConfig: readWranglerPublishedTrafficSnapshot(configPath),
|
|
6738
7276
|
queueConsumerCleanup,
|
|
6739
|
-
verifyInheritedSecrets: true
|
|
6740
|
-
|
|
7277
|
+
verifyInheritedSecrets: true,
|
|
7278
|
+
...initialAuthSecret ? { candidateSecrets: { [BETTER_AUTH_SECRET_NAME]: initialAuthSecret } } : {}
|
|
7279
|
+
}).finally(() => cfOutput?.dispose());
|
|
6741
7280
|
if (!execution.ok) {
|
|
6742
7281
|
await reportCloudflareActivationFailure(cliLog, needsSandbox && execution.containersUnavailable ? formatCloudflareSandboxUnavailable() : formatCloudflareActivationError(execution));
|
|
6743
7282
|
return exit(1);
|
|
@@ -6765,11 +7304,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
6765
7304
|
*/
|
|
6766
7305
|
function discoverRootWranglerConfig(root) {
|
|
6767
7306
|
if (existsSync(join(root, "wrangler.toml"))) throw new Error("Found wrangler.toml. Direct Cloudflare deployment needs one root wrangler.jsonc or wrangler.json with the same settings. Convert the config before deploying.");
|
|
6768
|
-
|
|
6769
|
-
const candidate = join(root, name);
|
|
6770
|
-
if (existsSync(candidate)) return candidate;
|
|
6771
|
-
}
|
|
6772
|
-
return join(root, "wrangler.jsonc");
|
|
7307
|
+
return materializeCloudflareConfig(root);
|
|
6773
7308
|
}
|
|
6774
7309
|
/** Avoid making Wrangler open a config path that Void has not created yet. */
|
|
6775
7310
|
function existingWranglerConfigArgs(configPath) {
|
|
@@ -6780,6 +7315,18 @@ async function reportCloudflareActivationFailure(cliLog, message) {
|
|
|
6780
7315
|
await cliLog.close().catch(() => {});
|
|
6781
7316
|
log.error(`${message}${cliLog.path ? `\n\nDetailed log: ${cliLog.path}` : ""}`);
|
|
6782
7317
|
}
|
|
7318
|
+
async function activateCloudflareVersionWithProgress(activate, options) {
|
|
7319
|
+
const progress = createSpinner();
|
|
7320
|
+
progress.start("Checking the current Worker deployment...");
|
|
7321
|
+
try {
|
|
7322
|
+
return await activate({
|
|
7323
|
+
...options,
|
|
7324
|
+
onProgress: (message) => progress.message(message)
|
|
7325
|
+
});
|
|
7326
|
+
} finally {
|
|
7327
|
+
progress.stop();
|
|
7328
|
+
}
|
|
7329
|
+
}
|
|
6783
7330
|
function formatCloudflareActivationError(result) {
|
|
6784
7331
|
const status = result.status === void 0 ? "" : ` (exit ${String(result.status)})`;
|
|
6785
7332
|
const cloudflareCode = result.cloudflareErrorCode === void 0 ? "" : ` Cloudflare error code: ${String(result.cloudflareErrorCode)}.`;
|
|
@@ -6819,6 +7366,7 @@ function formatCloudflareActivationError(result) {
|
|
|
6819
7366
|
"deploy: Cloudflare Access blocked the uploaded Worker Version readiness probe.",
|
|
6820
7367
|
"For CI, set CF_ACCESS_CLIENT_ID and CF_ACCESS_CLIENT_SECRET to an admitted service token.",
|
|
6821
7368
|
"For a local deploy, set CF_ACCESS_TOKEN to a short-lived user JWT from cloudflared.",
|
|
7369
|
+
"If the response is error 1050, create an Access application for this hostname; a token alone cannot bypass account default-deny.",
|
|
6822
7370
|
`Then retry. ${formatCloudflareReadinessRestoration(result)}`
|
|
6823
7371
|
].join("\n");
|
|
6824
7372
|
case "bootstrap-failed": return `deploy: Cloudflare could not bootstrap the first Worker deployment${status}.${cloudflareCode}${diagnostic}`;
|
|
@@ -6832,6 +7380,7 @@ function formatCloudflareActivationError(result) {
|
|
|
6832
7380
|
"deploy: Cloudflare Access blocked the first Worker deployment readiness probe.",
|
|
6833
7381
|
"For CI, set CF_ACCESS_CLIENT_ID and CF_ACCESS_CLIENT_SECRET to an admitted service token;",
|
|
6834
7382
|
"for a local deploy, set CF_ACCESS_TOKEN to a short-lived user JWT from cloudflared.",
|
|
7383
|
+
"If the response is error 1050, create an Access application for this hostname; a token alone cannot bypass account default-deny.",
|
|
6835
7384
|
"Then retry. Cloudflare requires the first deployment to be non-versioned, so the new",
|
|
6836
7385
|
"Worker is already active behind Access."
|
|
6837
7386
|
].join("\n");
|
|
@@ -6857,7 +7406,7 @@ function cloudflareWorkerReadinessHeaders() {
|
|
|
6857
7406
|
});
|
|
6858
7407
|
}
|
|
6859
7408
|
/** Build the trusted Wrangler pointer for a framework that emits Worker files directly. */
|
|
6860
|
-
async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, workerName, voidConfig, framework, preset, requiredSecretNames = []) {
|
|
7409
|
+
async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, workerName, voidConfig, framework, preset, requiredSecretNames = [], ai) {
|
|
6861
7410
|
const workerMain = join(root, preset.workerDir, preset.workerMain);
|
|
6862
7411
|
const assetsDirectory = join(root, preset.assetsDir);
|
|
6863
7412
|
if (!existsSync(workerMain)) throw new Error(`framework ${framework.name} did not emit its Worker entry at ${preset.workerDir}/${preset.workerMain}`);
|
|
@@ -6865,13 +7414,18 @@ async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, w
|
|
|
6865
7414
|
const paths = resolveProjectPaths(root, voidConfig);
|
|
6866
7415
|
const crons = scanJobsSync(root, paths.cronsDir);
|
|
6867
7416
|
const queues = scanQueuesSync(root, paths.queuesDir);
|
|
7417
|
+
const revalidate = collectRevalidate(voidConfig, null);
|
|
6868
7418
|
await generateDeployWrapperIfNeeded(root, join(root, preset.workerDir), preset.workerMain, {
|
|
6869
7419
|
auth: null,
|
|
6870
7420
|
crons,
|
|
6871
7421
|
queues,
|
|
6872
7422
|
hasMigrations: false,
|
|
6873
7423
|
migrationDialect: getDatabaseDialect(voidConfig),
|
|
6874
|
-
readiness: true
|
|
7424
|
+
readiness: true,
|
|
7425
|
+
...hasRevalidate(revalidate) && { isr: {
|
|
7426
|
+
revalidate,
|
|
7427
|
+
queryAllowlist: voidConfig.routing?.revalidateQueryAllowlist
|
|
7428
|
+
} }
|
|
6875
7429
|
});
|
|
6876
7430
|
if (preset.cloudflareArtifact === "vite-plugin") return;
|
|
6877
7431
|
const rootConfig = parseRootWranglerConfig(configPath);
|
|
@@ -6886,12 +7440,17 @@ async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, w
|
|
|
6886
7440
|
compatibilityFlags: preset.cloudflareCompatibilityFlags,
|
|
6887
7441
|
crons: [...new Set(crons.flatMap((job) => job.crons))],
|
|
6888
7442
|
requiredSecrets: requiredSecretNames,
|
|
7443
|
+
...ai ? { ai: {
|
|
7444
|
+
...ai,
|
|
7445
|
+
gateway: voidConfig.ai?.gateway
|
|
7446
|
+
} } : {},
|
|
6889
7447
|
...preset.workerDir === preset.assetsDir ? { assetsIgnore: [
|
|
6890
7448
|
preset.workerMain,
|
|
6891
7449
|
"_routes.json",
|
|
6892
7450
|
"__original.js",
|
|
6893
7451
|
"__original.mjs",
|
|
6894
7452
|
"__void_handlers.mjs",
|
|
7453
|
+
"__void_isr*.mjs",
|
|
6895
7454
|
"__void_migration_handler*.mjs"
|
|
6896
7455
|
] } : {}
|
|
6897
7456
|
});
|
|
@@ -6961,9 +7520,15 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
|
|
|
6961
7520
|
}
|
|
6962
7521
|
const hashUploader = deps.hashWranglerUploader ?? hashWranglerUploader;
|
|
6963
7522
|
const uploaderHash = hashUploader(root);
|
|
7523
|
+
const cfUploaderHashBefore = deps.activateVersion || deps.runWrangler ? void 0 : hashCfUploader();
|
|
7524
|
+
const cfUploaderIsPinned = () => {
|
|
7525
|
+
const matched = cfUploaderHashBefore !== void 0 && cfUploaderHashBefore === hashCfUploader();
|
|
7526
|
+
if (!matched) log.error("deploy: refusing to run a changed cf uploader with Cloudflare credentials.");
|
|
7527
|
+
return matched;
|
|
7528
|
+
};
|
|
6964
7529
|
const uploaderIsPinned = () => {
|
|
6965
7530
|
const result = assertWranglerUploaderUnchanged(uploaderHash, hashUploader(root));
|
|
6966
|
-
if (!result.ok) log.error(["deploy: refusing to run the
|
|
7531
|
+
if (!result.ok) log.error(["deploy: refusing to run the Cloudflare uploader with your Cloudflare credentials.", result.reason].filter(Boolean).join("\n"));
|
|
6967
7532
|
return result.ok;
|
|
6968
7533
|
};
|
|
6969
7534
|
let accountId = readWranglerTopLevelString(rootConfig, "account_id") ?? (process.env.CLOUDFLARE_ACCOUNT_ID?.trim() || void 0);
|
|
@@ -7036,6 +7601,7 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
|
|
|
7036
7601
|
return exit(getExitCode(error));
|
|
7037
7602
|
}
|
|
7038
7603
|
}
|
|
7604
|
+
log.step("Preparing deployment...");
|
|
7039
7605
|
if (!existsSync(preset.outputDir)) {
|
|
7040
7606
|
log.error(`deploy: Output directory '${preset.outputDir}' not found. Run the build first.`);
|
|
7041
7607
|
return exit(1);
|
|
@@ -7092,19 +7658,37 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
|
|
|
7092
7658
|
const queueConsumerCleanup = readWranglerManagedQueueCleanupCandidates(configPath);
|
|
7093
7659
|
if (existingWorker) assertCloudflareLinkUnchanged(root, pinnedHandoffLink);
|
|
7094
7660
|
const candidateReceipt = pinnedHandoffLink?.candidateReceipt;
|
|
7095
|
-
|
|
7096
|
-
|
|
7661
|
+
if (!deps.activateVersion && !deps.runWrangler && !cfUploaderIsPinned()) return exit(1);
|
|
7662
|
+
const cfOutput = deps.activateVersion || deps.runWrangler ? null : await prepareCfStaticBuildOutput({
|
|
7663
|
+
projectRoot: root,
|
|
7664
|
+
configPath: staticConfigPath,
|
|
7665
|
+
assetsDirectory: stagedAssetsDirectory,
|
|
7666
|
+
accountId
|
|
7667
|
+
});
|
|
7668
|
+
if (!cfOutput && !deps.activateVersion && !deps.runWrangler) {
|
|
7669
|
+
log.error("deploy: cf could not prepare the static Worker for deployment.");
|
|
7670
|
+
return exit(1);
|
|
7671
|
+
}
|
|
7672
|
+
const cfCommand = cfOutput ? createCfCommand({
|
|
7097
7673
|
accountId,
|
|
7098
7674
|
apiBaseUrl,
|
|
7675
|
+
env: deployChildEnv,
|
|
7676
|
+
verifyUploader: cfUploaderIsPinned
|
|
7677
|
+
}) : null;
|
|
7678
|
+
const activationRunner = cfOutput && cfCommand ? createCfVersionRunner({
|
|
7679
|
+
output: cfOutput,
|
|
7099
7680
|
workerName,
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7681
|
+
runCf: cfCommand,
|
|
7682
|
+
verifyResources: createCfResourceVerifier({
|
|
7683
|
+
configPath: staticConfigPath,
|
|
7684
|
+
runCf: cfCommand,
|
|
7685
|
+
runWrangler,
|
|
7686
|
+
verifyCompatibilityRunner: uploaderIsPinned
|
|
7687
|
+
})
|
|
7688
|
+
}) : runWrangler;
|
|
7689
|
+
const execution = await activateCloudflareVersionWithProgress(deps.activateVersion ?? activateCloudflareVersion, {
|
|
7106
7690
|
runWrangler: activationRunner,
|
|
7107
|
-
verifyUploader: uploaderIsPinned,
|
|
7691
|
+
verifyUploader: cfOutput ? cfUploaderIsPinned : uploaderIsPinned,
|
|
7108
7692
|
configPath: staticConfigPath,
|
|
7109
7693
|
preserveTriggers: existingWorker !== null,
|
|
7110
7694
|
expectedPreviousVersionId: existingWorker?.versionId,
|
|
@@ -7136,9 +7720,16 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
|
|
|
7136
7720
|
workerName,
|
|
7137
7721
|
runWrangler
|
|
7138
7722
|
}),
|
|
7723
|
+
publishEmptyCrons: createCloudflareEmptyCronPublisher({
|
|
7724
|
+
accountId,
|
|
7725
|
+
apiBaseUrl,
|
|
7726
|
+
configPath: staticConfigPath,
|
|
7727
|
+
workerName,
|
|
7728
|
+
runWrangler
|
|
7729
|
+
}),
|
|
7139
7730
|
previousTrafficConfig: readWranglerPublishedTrafficSnapshot(configPath),
|
|
7140
7731
|
queueConsumerCleanup
|
|
7141
|
-
});
|
|
7732
|
+
}).finally(() => cfOutput?.dispose());
|
|
7142
7733
|
if (!execution.ok) {
|
|
7143
7734
|
await reportCloudflareActivationFailure(cliLog, formatCloudflareActivationError(execution));
|
|
7144
7735
|
return exit(1);
|
|
@@ -7189,6 +7780,8 @@ const deployTargets = {
|
|
|
7189
7780
|
},
|
|
7190
7781
|
async deploy(root, options, cliLog) {
|
|
7191
7782
|
if (options.projectSlug !== void 0) throw new Error("deploy: --project is not supported with platform cloudflare — this platform deploys to your own Cloudflare account and no Void project is involved.");
|
|
7783
|
+
assertInstalledVoidMatchesCli(root);
|
|
7784
|
+
if (migrateLegacyVoidConfig(root)) log.success("Migrated project configuration to void.config.ts. Commit void.config.ts and void.lock.json.");
|
|
7192
7785
|
return runCloudflareDeploy(root, options, cliLog);
|
|
7193
7786
|
}
|
|
7194
7787
|
},
|
|
@@ -7239,7 +7832,11 @@ async function runDeployInner(root, options, cliLog) {
|
|
|
7239
7832
|
const targetLabel = platform === "cloudflare" ? "Cloudflare" : "Void";
|
|
7240
7833
|
log.info(`Deployment target: ${targetLabel}`);
|
|
7241
7834
|
cliLog.info("deploy_target", { target: platform });
|
|
7242
|
-
|
|
7835
|
+
try {
|
|
7836
|
+
return await deployTargets[platform].deploy(root, options ?? {}, cliLog);
|
|
7837
|
+
} finally {
|
|
7838
|
+
if (existsSync(join(root, "void.config.ts"))) stashCloudflareDeployPointer(root);
|
|
7839
|
+
}
|
|
7243
7840
|
}
|
|
7244
7841
|
async function runManagedDeploy(root, options, cliLog) {
|
|
7245
7842
|
let reauthenticated = false;
|
|
@@ -7301,6 +7898,7 @@ async function runManagedDeploy(root, options, cliLog) {
|
|
|
7301
7898
|
projectId: config.projectId,
|
|
7302
7899
|
slug: config.slug
|
|
7303
7900
|
});
|
|
7901
|
+
if (migrateLegacyVoidConfig(root)) log.success("Migrated project configuration to void.config.ts. Commit void.config.ts and void.lock.json.");
|
|
7304
7902
|
const voidConfig = readConfig(root);
|
|
7305
7903
|
cliLog.info("config_resolved", {
|
|
7306
7904
|
target: voidConfig.target,
|
|
@@ -7418,7 +8016,7 @@ function resolveFullDeployBuildCommand(root, buildOverride) {
|
|
|
7418
8016
|
* (`router/compile.ts`) emits a `paths.push(...)` for:
|
|
7419
8017
|
* 1. `scan.pages.pages` — static patterns + dynamic pages' `getPrerenderPaths()`
|
|
7420
8018
|
* 2. the custom SSR entry's top-level `getPrerenderPaths()` (`ssr` argument)
|
|
7421
|
-
* 3. `options.explicitPrerenderPaths` — void.
|
|
8019
|
+
* 3. `options.explicitPrerenderPaths` — void.config.ts `routing.prerender`
|
|
7422
8020
|
* With none of them present the collector is a generated function whose body
|
|
7423
8021
|
* returns `[...new Set([])]`, so skipping is result-identical.
|
|
7424
8022
|
*
|
|
@@ -7831,7 +8429,7 @@ function warnRedundantForceOn3xx(count) {
|
|
|
7831
8429
|
*/
|
|
7832
8430
|
function warnIgnoredNotFoundForFramework(notFound, frameworkName) {
|
|
7833
8431
|
if (notFound === void 0) return;
|
|
7834
|
-
log.warn(`"routing.notFound" in void.
|
|
8432
|
+
log.warn(`"routing.notFound" in void.config.ts is ignored for ${frameworkName} deploys (not_found_handling is pinned to "none" — the framework's own worker owns unmatched HTML).`);
|
|
7835
8433
|
}
|
|
7836
8434
|
/**
|
|
7837
8435
|
* Class B/C framework deploy: build with framework CLI, package with preset output paths.
|
|
@@ -7911,7 +8509,7 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
|
|
|
7911
8509
|
} catch {}
|
|
7912
8510
|
if (resources) {
|
|
7913
8511
|
if (!resources.some((resource) => resource.type === "hyperdrive")) {
|
|
7914
|
-
const { text: promptText, isCancel: isCancelPrompt } = await import("./
|
|
8512
|
+
const { text: promptText, isCancel: isCancelPrompt } = await import("./dist-C5fND3R0.mjs");
|
|
7915
8513
|
const connectionString = await promptText({
|
|
7916
8514
|
message: `Your project uses ${dialect === "mysql" ? "MySQL" : "PostgreSQL"}. Enter your connection string:`,
|
|
7917
8515
|
placeholder: dialect === "mysql" ? "mysql://user:pass@host:3306/dbname" : "postgresql://user:pass@host:5432/dbname",
|
|
@@ -7953,8 +8551,8 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
|
|
|
7953
8551
|
log.info("Wrapper generated");
|
|
7954
8552
|
}
|
|
7955
8553
|
const wranglerCompat = resolveDeployWranglerCompat(root, voidConfig, workerDir, { dialect });
|
|
7956
|
-
const revalidate = voidConfig
|
|
7957
|
-
const prerender = voidConfig.routing?.prerender;
|
|
8554
|
+
const revalidate = collectRevalidate(voidConfig, null);
|
|
8555
|
+
const prerender = voidConfig.routing?.isr === false ? void 0 : voidConfig.routing?.prerender;
|
|
7958
8556
|
const schedules = rawJobs.flatMap((job) => job.crons.map((cron) => ({
|
|
7959
8557
|
name: job.name,
|
|
7960
8558
|
cron
|
|
@@ -8157,7 +8755,7 @@ async function runFullDeploy(root, config, client, voidConfig, fwPreset, skipBui
|
|
|
8157
8755
|
} catch {}
|
|
8158
8756
|
if (resources) {
|
|
8159
8757
|
if (!resources.some((resource) => resource.type === "hyperdrive")) {
|
|
8160
|
-
const { text: promptText, isCancel: isCancelPrompt } = await import("./
|
|
8758
|
+
const { text: promptText, isCancel: isCancelPrompt } = await import("./dist-C5fND3R0.mjs");
|
|
8161
8759
|
const connectionString = await promptText({
|
|
8162
8760
|
message: `Your project uses ${dialect === "mysql" ? "MySQL" : "PostgreSQL"}. Enter your connection string:`,
|
|
8163
8761
|
placeholder: dialect === "mysql" ? "mysql://user:pass@host:3306/dbname" : "postgresql://user:pass@host:5432/dbname",
|
|
@@ -8604,4 +9202,4 @@ function resolveWorkerDirName(distDir, fwPreset, buildCommand) {
|
|
|
8604
9202
|
throw new Error("deploy: Worker output not found. Expected dist/ssr/ or dist/rsc/.");
|
|
8605
9203
|
}
|
|
8606
9204
|
//#endregion
|
|
8607
|
-
export {
|
|
9205
|
+
export { streamDeployEvents as $, parseRootWranglerConfig$1 as A, resolveDistDir as B, generateDeployWrapperIfNeeded as C, resolveAssetRoutingPolicy as Ct, hashWranglerUploader as D, hasPrerenderSources as E, resolveDeployLiveBindingConfig as F, resolveWranglerMigrationPattern as G, resolveStaticBuildCommand as H, resolveDeployTransport as I, runStaticDeploy as J, runCloudflareDeploy as K, resolveDeployWorkerMain as L, promptDeployProjectConfig as M, reconstructExpectedContainers as N, isWranglerNonInteractiveOrCI as O, resolveCloudflareVoidStaticPreset as P, snapshotPassthroughRawFields as Q, resolveDeployWranglerCompat as R, formatCloudflareSandboxUnavailable as S, resolveAssetConfig as St, hasNonPageBackend as T, resolveStaticDeployPreset as U, resolveFullDeployBuildCommand as V, resolveWorkerDirName as W, snapshotBindingIdentities as X, runWranglerAuthToken as Y, snapshotPassthroughIdentities as Z, deriveWorkerName as _, preflightEmail as _t, applyDeployEvent as a, generateQueueResolverSource as at, ensurePreviouslyDeployedLiveBindingConfig as b, hasApiRoutes as bt, assertMigrationsProduceAuthSchema as c, buildEnv as ct, assertWranglerUploaderUnchanged as d, hasRevalidate as dt, validateAuthMigrationSchema as et, checkWranglerMigrationApplySet as f, scanDurableObjectModules as ft, deployChildEnv as g, findEmailConfigConflicts as gt, createDeployWranglerRunner as h, createNodeEmailDns as ht, DEPLOY_WHOLE_OBJECT_PINNED_FIELDS as i, warnUnpublishedRouting as it, prepareCloudflareFrameworkArtifact as j, loadProvisionModule as k, assertNoConfigOverrideInProjectDotenv as l, collectPages as lt, computeDesiredCloudflareResources as m, applyEmailSetup as mt, DEPLOY_PASSTHROUGH_ASSERT_FIELDS as n, warnIgnoredNotFoundForFramework as nt, assembleVoidManifest as o, prerenderPages as ot, compareWranglerMigrationPaths as p, SEND_EMAIL_BINDING as pt, runDeploy as q, DEPLOY_PASSTHROUGH_EXCLUDE_FIELDS as r, warnRedundantForceOn3xx as rt, assertManagedDurableStateSupported as s, prerenderPagesNode as st, CloudflareAuthSecretError as t, verifyGeneratedDeployConfig as tt, assertRemoteMigrationsDeployable as u, collectRevalidate as ut, discoverRootWranglerConfig as v, renderAddressMap as vt, hasDeploySchemaDrift as w, formatCloudflareActivationError as x, hasDocumentRoutes as xt, ensureCloudflareAuthSecret as y, renderEmailChecklist as yt, resolveDeploymentPlatform as z };
|