void 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_TEMPLATE.md +1 -1
- package/README.md +5 -1
- package/dist/{account-cmd-CjyxcGkM.mjs → account-cmd-vJhh5lrb.mjs} +5 -5
- package/dist/{scan-ClYmX3sa.mjs → application-analysis-BVsVqc11.mjs} +135 -18
- package/dist/application-routing-B7QEjqSR.mjs +27 -0
- package/dist/{auth-DLNN0D3Z.mjs → auth-CQkSDS50.mjs} +26 -96
- package/dist/auth-DX3JURcX.mjs +2 -0
- package/dist/{auth-link-BLO4ptzo.mjs → auth-link-D75t9wO2.mjs} +5 -5
- package/dist/{auth-router-ZUg9MF_U.mjs → auth-router-ClfhL1J7.mjs} +7 -7
- package/dist/{better-auth-shared-rsBGBvWJ.mjs → better-auth-shared-hy6RPh9W.mjs} +13 -2
- package/dist/{build-cmd-BxR5FROK.mjs → build-cmd-zMi1iFnS.mjs} +21 -9
- package/dist/{cache-D0sWhgKI.mjs → cache-ZtQmyxVV.mjs} +5 -5
- package/dist/{cancel-deploy-D4NUqFbi.mjs → cancel-deploy-Box0kkEV.mjs} +5 -5
- package/dist/{cf-access-P0iZnu0q.mjs → cf-access-BGe5sWXF.mjs} +4 -48
- package/dist/{cf-access-DRsQRe6k.mjs → cf-access-TWNzXltp.mjs} +3 -11
- package/dist/{cf-build-output-BJ6yGEIS.mjs → cf-build-output-BPqOT964.mjs} +2 -1
- package/dist/cf-build-output-_0HNWysu.mjs +2 -0
- package/dist/cli/cli.mjs +89 -461
- package/dist/cli/{cf-compat.mjs → cloudflare-operation-process.mjs} +454 -424
- package/dist/cli/env-schema-probe.d.mts +2 -1
- package/dist/cli/env-schema-probe.mjs +4 -4
- package/dist/client-B9UBI03V.mjs +2 -0
- package/dist/{client-BTZ3XkrB.mjs → client-DKAsFA4X.mjs} +161 -24
- package/dist/{cloudflare-auth-DQkqoMYa.mjs → cloudflare-auth-Qdc7tw8F.mjs} +41 -38
- package/dist/{cloudflare-cmd-BKlfGHAy.mjs → cloudflare-cmd-CmY8dGkd.mjs} +6 -6
- package/dist/cloudflare-config-Bktvwtpf.mjs +182 -0
- package/dist/{cloudflare-connect-Ctmrw579.mjs → cloudflare-connect-IiR3ZieC.mjs} +4 -4
- package/dist/{cloudflare-operations-BT6OWFBk.mjs → cloudflare-operations-BCdXSsmo.mjs} +1 -1
- package/dist/{cloudflare-operations-B9tzgjmf.mjs → cloudflare-operations-DzH-A966.mjs} +116 -172
- package/dist/{preset-UHj9ARyP.mjs → cloudflare-process-B-wekeR6.mjs} +93 -6
- package/dist/{config-VavjpDnp.d.mts → config-BMHb8RCj.d.mts} +1 -0
- package/dist/config-C_XRIPx2.mjs +89 -0
- package/dist/config-entry.d.mts +1 -1
- package/dist/{connect-Dg-WkW-C.mjs → connect-B-usTnlF.mjs} +9 -9
- package/dist/{create-project-l9J7pbtm.mjs → create-project-CYOOAYcn.mjs} +12 -12
- package/dist/{create-project-DdoqwFLF.mjs → create-project-FWbf5Olo.mjs} +1 -1
- package/dist/{db-gp2sCXyN.mjs → db-Ck2eZ2iB.mjs} +26 -26
- package/dist/{delete-TTedbH6B.mjs → delete-sK56qtzZ.mjs} +5 -5
- package/dist/{deploy-CH-o2CaZ.mjs → deploy-gCVaiJbS.mjs} +984 -616
- package/dist/{deploy-B19L2Bra.mjs → deploy-irP5q0-x.mjs} +1 -1
- package/dist/{domain-JRF59P_r.mjs → domain-DFfQE8jg.mjs} +6 -6
- package/dist/{email-Bo6G9LOZ.mjs → email-CdnhUHvJ.mjs} +15 -30
- package/dist/{env-BYOrWQnv.mjs → env-DmGdHi5i.mjs} +8 -8
- package/dist/{env-public-BxU_0yTL.d.mts → env-public-BX_r8HR6.d.mts} +1 -1
- package/dist/{env-types-C2_bIk_b.mjs → env-types-D5kds_OZ.mjs} +1 -1
- package/dist/{env-validation-BB4GkLxn.mjs → env-validation-C_8tPdhs.mjs} +20 -73
- package/dist/{env-validation-BXge7uyK.mjs → env-validation-zZOCcQVZ.mjs} +1 -1
- package/dist/{fetch-CXDChK7B.mjs → fetch-BIZJh7vR.mjs} +2 -2
- package/dist/{fetch-stream-AOByI7Ki.mjs → fetch-stream-IvCYKyQL.mjs} +24 -4
- package/dist/{gen-sCtlCOdA.mjs → gen-CshAkukR.mjs} +4 -4
- package/dist/gen-DvQTWzDU.mjs +2 -0
- package/dist/{github-cmd-0-7PexDq.mjs → github-cmd-DftuEvIt.mjs} +13 -13
- package/dist/{handler-HEcZsaij.d.mts → handler-CZ4nAylQ.d.mts} +1 -1
- package/dist/{headers-DWi2IXWx.mjs → headers-2rKda9Y6.mjs} +1 -1
- package/dist/{help-GKtwl07I.mjs → help-Dotbf6iz.mjs} +236 -750
- package/dist/help-mabuIV98.mjs +2 -0
- package/dist/{inbound-aVHEUhKo.mjs → inbound-fRkqcXaC.mjs} +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +299 -1517
- package/dist/info-B97bTX9N.mjs +113 -0
- package/dist/{init-FZx3Elvz.mjs → init-BTQEZZGJ.mjs} +61 -27
- package/dist/limits-Bq5LG8Id.d.mts +27 -0
- package/dist/limits-Cjuk2VPm.mjs +68 -0
- package/dist/{link-BrQfb_CU.mjs → link-B46sYH0K.mjs} +6 -6
- package/dist/{list-D44jmIAM.mjs → list-BnPrIsU_.mjs} +6 -6
- package/dist/{live-CKJlvlNp.d.mts → live-Chw1eIMv.d.mts} +1 -1
- package/dist/{local-d1-Bg9OzEEO.mjs → local-d1-2CMnpuW_.mjs} +2 -2
- package/dist/log-vqY3pqwI.mjs +29 -0
- package/dist/{login-CAsAsQ-_.mjs → login-BuiMyUrx.mjs} +8 -8
- package/dist/login-DIy9Sb-U.mjs +2 -0
- package/dist/{logs-BjKvFnVM.mjs → logs-CZG9d-ic.mjs} +10 -11
- package/dist/migrate-BCiJ8w0f.mjs +2 -0
- package/dist/{migrate-BPITvDJN.mjs → migrate-q4_njtaW.mjs} +4 -3
- package/dist/{node-Dt7z256D.mjs → node-BkyRWRx8.mjs} +1 -1
- package/dist/operator-args-B3BTmSoi.mjs +697 -0
- package/dist/{operator-auth-8KnOVXVd.mjs → operator-auth-7erYc6Lt.mjs} +2 -2
- package/dist/{operator-client-DUwumHpQ.mjs → operator-client-CpHjTd0t.mjs} +3 -3
- package/dist/{operator-cmd-BK5CCiT9.mjs → operator-cmd-DGqPJUD3.mjs} +70 -24
- package/dist/{output-Dm_A4Tbv.mjs → output-CbM85T4k.mjs} +18 -10
- package/dist/pages/client.d.mts +34 -2
- package/dist/pages/client.mjs +59 -3
- package/dist/pages/index.d.mts +1 -1
- package/dist/pages/index.mjs +2 -2
- package/dist/pages/islands-plugin.mjs +1 -1
- package/dist/pages/protocol.d.mts +2 -2
- package/dist/pages/protocol.mjs +2 -308
- package/dist/{parse-filename-DioPHiR9.mjs → parse-filename-CUbj-1MP.mjs} +35 -1
- package/dist/plan-D1Q5rf-r.mjs +2 -0
- package/dist/plan-NPpwZ_kc.mjs +58 -0
- package/dist/platform-args-3k8X9-H_.mjs +514 -0
- package/dist/platform-args-DdnM6WIf.mjs +2 -0
- package/dist/{platform-auth-config-BlN8xTdD.mjs → platform-auth-config-DDrxUy4m.mjs} +6 -6
- package/dist/{platform-auth-protection-7d5aV2Jg.mjs → platform-auth-protection-BLadnnct.mjs} +8 -8
- package/dist/{platform-auth-recovery-Dxij8ZbR.mjs → platform-auth-recovery-CmCzX2Fl.mjs} +6 -6
- package/dist/{platform-cmd-B3hwKrFK.mjs → platform-cmd-DMDEc9uS.mjs} +29 -8
- package/dist/{platform-cmd-E0FuL212.mjs → platform-cmd-pMTRhvYs.mjs} +1 -1
- package/dist/{platform-domain-D6Xcy9ZX.mjs → platform-domain-Di6EYrQl.mjs} +5 -5
- package/dist/{platform-lifecycle-k0E0xoxx.mjs → platform-lifecycle-BBoNzojY.mjs} +1541 -572
- package/dist/{platform-lifecycle-DMh_qrry.mjs → platform-lifecycle-BFdSi9Qt.mjs} +1 -1
- package/dist/{platform-management-Brz_BDiT.mjs → platform-management-CWOQOWXm.mjs} +10 -7
- package/dist/{platform-management-DOtss0BN.mjs → platform-management-DG47jys8.mjs} +1 -1
- package/dist/platform-plans-config-Vl9BP3H4.mjs +359 -0
- package/dist/{platform-recovery-BvtcXON5.mjs → platform-recovery-BJnQJEtQ.mjs} +4 -4
- package/dist/{platform-registry-QBa4DK32.mjs → platform-registry-DkPPXfp_.mjs} +2 -2
- package/dist/{plugin-inference-BMfKRSqE.mjs → plugin-inference-CXWnn79A.mjs} +174 -64
- package/dist/{prepare-C-6YZyyg.mjs → prepare-CBLT3CHH.mjs} +3 -3
- package/dist/prepare-CnjcTV2s.mjs +2 -0
- package/dist/{prepare-CRhJbVrG.mjs → prepare-DnaKBi--.mjs} +5 -21
- package/dist/{project-C0Fqu05O.mjs → project-DKG5Ra8p.mjs} +15 -82
- package/dist/project-DsblYifa.mjs +2 -0
- package/dist/{project-cmd-BZLCqOqw.mjs → project-cmd-DxnXstAq.mjs} +19 -19
- package/dist/{project-team-BvgM0WoX.mjs → project-team-BmHcaALJ.mjs} +5 -5
- package/dist/{project-token-l5DqK6Az.mjs → project-token-GionZlBI.mjs} +5 -5
- package/dist/{project-zero-trust-v6Mvpp8y.mjs → project-zero-trust-JLCjVQA7.mjs} +5 -5
- package/dist/prompts-2TGE6oXx.mjs +2 -0
- package/dist/prompts-BNUoTiaf.mjs +2044 -0
- package/dist/{protocol-BBa6cstI.d.mts → protocol-CjF_iI9X.d.mts} +2 -2
- package/dist/protocol-U7bfjHmA.mjs +331 -0
- package/dist/{provision-Fr9pRqce.mjs → provision-CVku1JFU.mjs} +1 -1
- package/dist/{provision-C4IGqkBf.mjs → provision-CaoxO_U7.mjs} +90 -199
- package/dist/{requests-DN-BbNiM.mjs → requests-BOjIVAeF.mjs} +5 -5
- package/dist/resource-name-C7LVpcRm.mjs +11 -0
- package/dist/{rollback-D7rzSaZM.mjs → rollback-CwR3pLj3.mjs} +6 -6
- package/dist/route-url-CG7U-cRN.mjs +15 -0
- package/dist/{runner-B8wXwWlo.mjs → runner-CXA9Fh8h.mjs} +1 -1
- package/dist/{runner-p-dMs2UN.mjs → runner-Ol0TNjk6.mjs} +2 -2
- package/dist/runtime/ai.d.mts +12 -8
- package/dist/runtime/ai.mjs +87 -22
- package/dist/runtime/better-auth-mysql.mjs +1 -1
- package/dist/runtime/better-auth-pg.mjs +1 -1
- package/dist/runtime/better-auth.mjs +1 -1
- package/dist/runtime/client-react.mjs +2 -2
- package/dist/runtime/client-solid.mjs +2 -2
- package/dist/runtime/client-svelte.mjs +2 -2
- package/dist/runtime/client-vue.mjs +2 -2
- package/dist/runtime/client.mjs +2 -2
- package/dist/runtime/durable.d.mts +3 -1
- package/dist/runtime/durable.mjs +4 -1
- package/dist/runtime/email/testing.mjs +2 -2
- package/dist/runtime/email.mjs +1 -1
- package/dist/runtime/env-public.d.mts +1 -1
- package/dist/runtime/fetch-stream.mjs +1 -1
- package/dist/runtime/fetch.mjs +1 -1
- package/dist/runtime/handler.d.mts +1 -1
- package/dist/runtime/kv.mjs +0 -1
- package/dist/runtime/limits.d.mts +2 -0
- package/dist/runtime/limits.mjs +2 -0
- package/dist/runtime/live-client.d.mts +1 -1
- package/dist/runtime/live-server.mjs +25 -16
- package/dist/runtime/live.d.mts +1 -1
- package/dist/runtime/migration-handler.mjs +62 -42
- package/dist/runtime/remote/index.mjs +2 -2
- package/dist/runtime/route-url.d.mts +4 -0
- package/dist/runtime/route-url.mjs +2 -0
- package/dist/runtime/routing.d.mts +180 -0
- package/dist/runtime/routing.mjs +1082 -0
- package/dist/runtime/sandbox-container.d.mts +1 -1
- package/dist/runtime/sandbox-container.mjs +1 -1
- package/dist/runtime/sandbox.d.mts +3 -3
- package/dist/runtime/sandbox.mjs +75 -45
- package/dist/runtime/sse.mjs +1 -1
- package/dist/runtime/validator.d.mts +1 -1
- package/dist/runtime/ws-server.d.mts +4 -2
- package/dist/runtime/ws-server.mjs +27 -2
- package/dist/runtime/ws.d.mts +2 -2
- package/dist/runtime/ws.mjs +8 -6
- package/dist/{sandbox-qpNBT8a3.d.mts → sandbox-XZAqzFlG.d.mts} +11 -8
- package/dist/{sandbox-container-DdNEBfCc.d.mts → sandbox-container-Bo0eiFKz.d.mts} +2 -1
- package/dist/{sandbox-container-4fdqLnyb.mjs → sandbox-container-C6ItmVuN.mjs} +4 -2
- package/dist/{scan-4tfN-PSn.mjs → scan-C7okrLyM.mjs} +4 -35
- package/dist/{secret-BOtOl_cb.mjs → secret-ByWJWBUG.mjs} +7 -7
- package/dist/{skills-D1II1Juz.mjs → skills-C1PlclPt.mjs} +1 -1
- package/dist/{sse-BaC1jXko.mjs → sse-CQNaDFFV.mjs} +6 -3
- package/dist/{subcommand-prompt-CY1C4fvl.mjs → subcommand-prompt-klFCfcor.mjs} +40 -32
- package/dist/validate-Dq_L3s0S.mjs +2 -0
- package/dist/{validate-CIUwFpjB.mjs → validate-ctOrgiS3.mjs} +2 -1
- package/dist/{wrangler-DQF1vKyf.mjs → wrangler-7K-bW_DL.mjs} +8 -239
- package/dist/{ws-BoY7vQML.d.mts → ws-CL1w7GXU.d.mts} +13 -2
- package/package.json +16 -10
- package/skills/migrate-vite-cloudflare-to-void/SKILL.md +34 -157
- package/skills/void/SKILL.md +55 -135
- package/skills/void/docs/guide/ai.md +94 -84
- package/skills/void/docs/guide/app-types.md +3 -32
- package/skills/void/docs/guide/auth.md +12 -116
- package/skills/void/docs/guide/database/d1.md +9 -54
- package/skills/void/docs/guide/database/mysql.md +1 -1
- package/skills/void/docs/guide/database/postgresql.md +5 -26
- package/skills/void/docs/guide/database.md +23 -75
- package/skills/void/docs/guide/deployment.md +48 -112
- package/skills/void/docs/guide/durable-state.md +43 -18
- package/skills/void/docs/guide/edge/headers.md +4 -48
- package/skills/void/docs/guide/edge/prerendering.md +5 -20
- package/skills/void/docs/guide/edge/redirects.md +11 -64
- package/skills/void/docs/guide/edge/revalidation.md +5 -18
- package/skills/void/docs/guide/edge/rewrites.md +56 -284
- package/skills/void/docs/guide/edge/static-assets.md +22 -72
- package/skills/void/docs/guide/email/domains.md +116 -0
- package/skills/void/docs/guide/email/receiving.md +139 -0
- package/skills/void/docs/guide/email/sending.md +231 -0
- package/skills/void/docs/guide/email.md +13 -619
- package/skills/void/docs/guide/env-migration.md +11 -11
- package/skills/void/docs/guide/env-vars.md +9 -29
- package/skills/void/docs/guide/index.md +0 -15
- package/skills/void/docs/guide/jobs.md +3 -18
- package/skills/void/docs/guide/kv.md +5 -11
- package/skills/void/docs/guide/live.md +5 -56
- package/skills/void/docs/guide/pages-routing/actions-and-forms.md +78 -125
- package/skills/void/docs/guide/pages-routing/head.md +10 -10
- package/skills/void/docs/guide/pages-routing/islands.md +6 -36
- package/skills/void/docs/guide/pages-routing/layouts.md +6 -128
- package/skills/void/docs/guide/pages-routing/loaders.md +3 -19
- package/skills/void/docs/guide/pages-routing/markdown.md +13 -171
- package/skills/void/docs/guide/pages-routing/overview.md +7 -17
- package/skills/void/docs/guide/pages-routing/view-transitions.md +1 -1
- package/skills/void/docs/guide/platform/administration/access.md +1 -4
- package/skills/void/docs/guide/platform/administration/email.md +35 -8
- package/skills/void/docs/guide/platform/administration/operations.md +26 -4
- package/skills/void/docs/guide/platform/administration/plans.md +126 -0
- package/skills/void/docs/guide/platform/administration/projects.md +5 -2
- package/skills/void/docs/guide/platform/administration/zero-trust.md +49 -160
- package/skills/void/docs/guide/platform/development/runtime.md +3 -13
- package/skills/void/docs/guide/platform/development/schema-ci.md +0 -58
- package/skills/void/docs/guide/platform/installation/ci.md +1 -1
- package/skills/void/docs/guide/platform/installation/credentials.md +15 -6
- package/skills/void/docs/guide/platform/installation/domains.md +35 -2
- package/skills/void/docs/guide/platform/installation/first-deployment.md +4 -2
- package/skills/void/docs/guide/platform/installation/maintenance.md +15 -1
- package/skills/void/docs/guide/platform/installation/prerequisites.md +24 -18
- package/skills/void/docs/guide/platform/installation/setup.md +88 -14
- package/skills/void/docs/guide/platform-administration.md +1 -0
- package/skills/void/docs/guide/queues.md +7 -9
- package/skills/void/docs/guide/quickstart.md +38 -37
- package/skills/void/docs/guide/remote-dev.md +5 -10
- package/skills/void/docs/guide/sandboxes.md +29 -21
- package/skills/void/docs/guide/server-routing.md +9 -72
- package/skills/void/docs/guide/sse.md +4 -18
- package/skills/void/docs/guide/ssg.md +3 -15
- package/skills/void/docs/guide/ssr.md +14 -62
- package/skills/void/docs/guide/storage.md +9 -4
- package/skills/void/docs/guide/type-safety.md +3 -14
- package/skills/void/docs/guide/typed-fetch.md +3 -7
- package/skills/void/docs/guide/websockets.md +68 -40
- package/skills/void/docs/integrations/agents.md +3 -3
- package/skills/void/docs/integrations/cloudflare.md +85 -316
- package/skills/void/docs/integrations/frameworks/analog.md +5 -64
- package/skills/void/docs/integrations/frameworks/astro.md +4 -73
- package/skills/void/docs/integrations/frameworks/nuxt.md +5 -62
- package/skills/void/docs/integrations/frameworks/overview.md +11 -54
- package/skills/void/docs/integrations/frameworks/react-router.md +5 -60
- package/skills/void/docs/integrations/frameworks/sveltekit.md +6 -65
- package/skills/void/docs/integrations/frameworks/tanstack-start.md +4 -62
- package/skills/void/docs/integrations/nodejs-bun-deno.md +5 -69
- package/skills/void/docs/reference/api/auth.md +156 -0
- package/skills/void/docs/reference/api/client.md +87 -0
- package/skills/void/docs/reference/api/database.md +95 -0
- package/skills/void/docs/reference/api/durable.md +46 -0
- package/skills/void/docs/reference/api/env.md +50 -0
- package/skills/void/docs/reference/api/handlers.md +254 -0
- package/skills/void/docs/reference/api/pages.md +241 -0
- package/skills/void/docs/reference/api/plugin.md +39 -0
- package/skills/void/docs/reference/api/resources.md +109 -0
- package/skills/void/docs/reference/api/rewrites.md +76 -0
- package/skills/void/docs/reference/api/types.md +92 -0
- package/skills/void/docs/reference/api.md +56 -1218
- package/skills/void/docs/reference/cli/auth.md +89 -0
- package/skills/void/docs/reference/cli/database.md +128 -0
- package/skills/void/docs/reference/cli/deploy.md +105 -0
- package/skills/void/docs/reference/cli/domains.md +41 -0
- package/skills/void/docs/reference/cli/email.md +129 -0
- package/skills/void/docs/reference/cli/generate.md +116 -0
- package/skills/void/docs/reference/cli/github.md +189 -0
- package/skills/void/docs/reference/cli/platform-config.md +92 -0
- package/skills/void/docs/reference/cli/platform-email.md +81 -0
- package/skills/void/docs/reference/cli/platform-installation.md +142 -0
- package/skills/void/docs/reference/cli/platform-operations.md +90 -0
- package/skills/void/docs/reference/cli/platform-users.md +89 -0
- package/skills/void/docs/reference/cli/platform-zero-trust.md +59 -0
- package/skills/void/docs/reference/cli/platform.md +70 -0
- package/skills/void/docs/reference/cli/project.md +214 -0
- package/skills/void/docs/reference/cli/secrets.md +76 -0
- package/skills/void/docs/reference/cli/setup.md +70 -0
- package/skills/void/docs/reference/cli.md +32 -1682
- package/skills/void/docs/reference/config.md +12 -18
- package/skills/void/docs/reference/resource-inference.md +3 -58
- package/skills/void/docs/reference/structure.md +14 -41
- package/dist/auth-CZuiVsFh.mjs +0 -2
- package/dist/canonical-json-DuDiiUsQ.mjs +0 -13
- package/dist/client-Czz8o5jP.mjs +0 -2
- package/dist/dist-BuDuKZJv.mjs +0 -2
- package/dist/dist-CTBk70IR.mjs +0 -1310
- package/dist/gen-CNJ62MM7.mjs +0 -2
- package/dist/help-CmZzxUba.mjs +0 -2
- package/dist/log-ChfPKsVd.mjs +0 -26
- package/dist/login-CGcRKEoi.mjs +0 -2
- package/dist/migrate-CYfbKkXh.mjs +0 -2
- package/dist/plan-BEZ8VJW0.mjs +0 -256
- package/dist/plan-DpuOr14e.mjs +0 -2
- package/dist/prepare-Bm3iq-u4.mjs +0 -2
- package/dist/project-BuUwfj6f.mjs +0 -2
- package/dist/validate-EKmJWxmy.mjs +0 -2
- /package/dist/cli/{cf-compat.d.mts → cloudflare-operation-process.d.mts} +0 -0
|
@@ -1,51 +1,52 @@
|
|
|
1
1
|
import { n as __toESM, t as __commonJSMin } from "./rolldown-runtime-DXIUcv95.mjs";
|
|
2
2
|
import { a as join, l as relative, n as dirname, o as normalize, r as extname, t as basename, u as resolve } from "./dist-BVqXeR_h.mjs";
|
|
3
3
|
import { t as require_picocolors } from "./picocolors-BTps1_gs.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
6
|
-
import {
|
|
7
|
-
import { a as getApiUrl, c as getToken, l as getTokenSource, o as getProxyUrl, u as isStagingMode } from "./auth-DLNN0D3Z.mjs";
|
|
8
|
-
import { r as ensurePlatformProxyAccess, t as ensureCloudflaredToken } from "./cf-access-P0iZnu0q.mjs";
|
|
9
|
-
import { d as writeProjectConfig, i as readDeploymentPlatform, l as writeDeploymentPlatform, o as readProjectConfig, t as attachSelectedPlatform } from "./project-C0Fqu05O.mjs";
|
|
10
|
-
import { d as isNodeTarget, h as resolveBindingNames, m as readConfig, u as getDatabaseDialect } from "./config-Br_JZD6u.mjs";
|
|
11
|
-
import { A as writeWranglerPublishedTrafficSnapshot, B as materializeCloudflareConfig, D as syncWranglerWebSockets, E as syncWranglerDurableObjects, F as requiresSandboxPlatformImage, I as resolveSandboxConfig, L as sandboxContainerConfig, M as SANDBOX_MIGRATION_TAG, P as isSandboxEnabled, S as readWranglerPublishedTrafficSnapshot, T as syncWranglerBindings, V as persistCloudflareConfig, W 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, m as nextDurableObjectMigrationTag, o as acknowledgeWranglerManagedQueueRemovals, p as hasDurableObjectSqliteMigration, r as FRIENDLY_BINDING_NAMES, w as resolveLiveBindingConfig, x as readWranglerManagedQueueCleanupCandidates } from "./wrangler-DQF1vKyf.mjs";
|
|
12
|
-
import { i as voidWarn, r as voidLog } from "./log-ChfPKsVd.mjs";
|
|
13
|
-
import { n as lintDuplicateSources, r as mergeRoutingRules, t as lintDestinationSplats } from "./headers-DWi2IXWx.mjs";
|
|
4
|
+
import { m as needsApplicationDatabase, r as detectFramework } from "./plugin-inference-CXWnn79A.mjs";
|
|
5
|
+
import { n as readProjectPaths, t as assertNoRootSourceConventionConflicts } from "./project-paths-GgcMozYz.mjs";
|
|
6
|
+
import { d as isNodeTarget, h as resolveBindingNames, m as readConfig } from "./config-Br_JZD6u.mjs";
|
|
14
7
|
import { n as isIdentifier, r as isLiteral } from "./ast-CPGPjb0V.mjs";
|
|
15
|
-
import { t as
|
|
16
|
-
import { a as scanJobsSync, i as scanQueuesSync, r as scanRoutes } from "./scan-ClYmX3sa.mjs";
|
|
17
|
-
import { i as inferProjectBindings, n as FRAMEWORK_SCAN_DIRS, r as detectFramework, s as scanWebSocketRoutesSync } from "./plugin-inference-BMfKRSqE.mjs";
|
|
8
|
+
import { o as scanDurableObjectModules, t as analyzeApplicationSync } from "./application-analysis-BVsVqc11.mjs";
|
|
18
9
|
import { t as collectMigrations } from "./collect-DiTn9yr6.mjs";
|
|
19
|
-
import {
|
|
10
|
+
import { o as validateSsrEntry } from "./entry-CF5wvH4w.mjs";
|
|
11
|
+
import { r as hasEmailHandlers } from "./email--tEtMoj_.mjs";
|
|
12
|
+
import { a as hasSandboxSqliteMigration, c as resolveSandboxConfig, i as assertSandboxNamespaceConfig, l as sandboxContainerConfig, r as SANDBOX_MIGRATION_TAG, s as requiresSandboxPlatformImage } from "./config-C_XRIPx2.mjs";
|
|
13
|
+
import { n as scopedAccessCredentials, r as trustedCloudflareWorkerAccessHeaders, t as cfAccessHeaders } from "./cf-access-TWNzXltp.mjs";
|
|
14
|
+
import { r as ensurePlatformProxyAccess, t as ensureCloudflaredToken } from "./cf-access-BGe5sWXF.mjs";
|
|
15
|
+
import { l as writeProjectConfig, n as readDeploymentPlatform, o as shouldLinkDeployProject, r as readProjectConfig, s as writeDeploymentPlatform, t as attachSelectedPlatform } from "./project-DKG5Ra8p.mjs";
|
|
16
|
+
import { a as getApiUrl, c as getToken, l as getTokenSource, o as getProxyUrl } from "./auth-CQkSDS50.mjs";
|
|
17
|
+
import { i as persistCloudflareConfig, r as materializeCloudflareConfig, s as stashCloudflareDeployPointer } from "./cloudflare-config-Bktvwtpf.mjs";
|
|
18
|
+
import { A as writeProvisionedWranglerConfig, C as readWranglerPublishedTrafficSnapshot, D as syncWranglerDurableObjects, E as syncWranglerBindings, O as syncWranglerWebSockets, S as readWranglerManagedQueueCleanupCandidates, T as resolveLiveBindingConfig, _ as readExistingLiveBindingConfig, a as LIVE_MIGRATION_TAG, c as bindingEntriesForField, g as normalizeWranglerCompatibilityFlags, h as nextDurableObjectMigrationTag, j as writeWranglerPublishedTrafficSnapshot, l as bindingNamesForField, m as hasDurableObjectSqliteMigration, o as acknowledgeWranglerManagedQueueRemovals, p as findBindingNameOwner, r as FRIENDLY_BINDING_NAMES, u as ensureWranglerCompat } from "./wrangler-7K-bW_DL.mjs";
|
|
19
|
+
import { i as voidWarn, r as voidLog } from "./log-vqY3pqwI.mjs";
|
|
20
|
+
import { n as lintDuplicateSources, r as mergeRoutingRules, t as lintDestinationSplats } from "./headers-2rKda9Y6.mjs";
|
|
21
|
+
import { n as buildMigrationPlanBundle } from "./plan-NPpwZ_kc.mjs";
|
|
20
22
|
import { r as scanWranglerDotenvKeys } from "./dotenv-VQxupEUv.mjs";
|
|
21
23
|
import { t as discoverSchema } from "./discover-BcPPiF1o.mjs";
|
|
22
24
|
import { t as MagicString } from "./dist-AoCzRTJE.mjs";
|
|
23
|
-
import { t as findEnvFile } from "./env-types-
|
|
24
|
-
import { d as formatEnvReport, f as listSelfHostSecretNames, g as validateProdEnv, h as selfHostSchemaFailureMessage, i as SelfHostSecretListError, l as dischargeSelfHostEnvContext, n as SelfHostFirstDeployError, p as readEmittedWorkerVars, r as SelfHostSchemaError, s as deriveSelfHostEnvContextFromVars, t as SelfHostEnvValidationError, u as fetchRemoteSecretNames, v as readGeneratedWranglerConfigFile } from "./env-validation-
|
|
25
|
+
import { t as findEnvFile } from "./env-types-D5kds_OZ.mjs";
|
|
26
|
+
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-C_8tPdhs.mjs";
|
|
25
27
|
import { n as CLOUDFLARE_DEPLOY_BUILD_ENV, o as resolveRemoteMode, s as stripInternalEnvKeys } from "./env-_v349JBd.mjs";
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
+
import { A as confirm, B as note, H as outro, K as select, L as log$1, N as intro, tt as isCancel } from "./prompts-BNUoTiaf.mjs";
|
|
29
|
+
import { n as completeApplicationAnalysis, t as analyzeApplication } from "./application-routing-B7QEjqSR.mjs";
|
|
28
30
|
import { t as writeDrizzleConfig } from "./config-D8MOgiQV.mjs";
|
|
29
31
|
import { i as runMySqlMigrations } from "./runner-mysql-DmWchSWJ.mjs";
|
|
30
32
|
import { i as runPgMigrations } from "./runner-pg-D4OPlil-.mjs";
|
|
31
33
|
import { n as openMigrationValidationDatabase, t as SqliteMigrationError } from "./sqlite-validation-BzKMWnO4.mjs";
|
|
32
|
-
import { i as validateMigrations, t as assertJournalCoherence } from "./validate-
|
|
34
|
+
import { i as validateMigrations, t as assertJournalCoherence } from "./validate-ctOrgiS3.mjs";
|
|
33
35
|
import { t as renderPrerenderPaths } from "./prerender-render-D9qbLs2f.mjs";
|
|
34
|
-
import {
|
|
35
|
-
import { i as migrateBuiltWranglerConfig, n as prepareCfFrameworkBuildOutput, r as prepareCfStaticBuildOutput, t as prepareCfBuildOutput } from "./cf-build-output-BJ6yGEIS.mjs";
|
|
36
|
+
import { i as migrateBuiltWranglerConfig, n as prepareCfFrameworkBuildOutput, r as prepareCfStaticBuildOutput, t as prepareCfBuildOutput } from "./cf-build-output-BPqOT964.mjs";
|
|
36
37
|
import { n as getPackageDir } from "./agents-B_pX_HmQ.mjs";
|
|
37
|
-
import { i as isExpiredTokenError, n as PlatformClient, o as parsePlatformErrorBody, r as isCliOutdatedError, s as platformErrorMessage, t as PlatformApiError } from "./client-
|
|
38
|
-
import { a as
|
|
39
|
-
import { a as
|
|
38
|
+
import { i as isExpiredTokenError, n as PlatformClient, o as parsePlatformErrorBody, r as isCliOutdatedError, s as platformErrorMessage, t as PlatformApiError } from "./client-DKAsFA4X.mjs";
|
|
39
|
+
import { a as detectPreset, c as resolveCloudflareOperationArgv, i as FRAMEWORK_PRESETS, l as resolveProjectCommand, o as formatProjectCommand, s as hasBackendFiles, t as createCloudflareProcessRunner } from "./cloudflare-process-B-wekeR6.mjs";
|
|
40
|
+
import { a as parseCloudflareAuthSession, i as ensureCloudflareAuthentication, n as cloudflareCredentialOverrides, t as CloudflareAuthenticationError } from "./cloudflare-auth-Qdc7tw8F.mjs";
|
|
40
41
|
import { n as writeVoidProjectConfig } from "./config-write-B1f88wJA.mjs";
|
|
41
|
-
import { r as discoverFrameworkWranglerFiles, t as migrateLegacyVoidConfig } from "./migrate-
|
|
42
|
-
import { a as createCloudflareEmptyDomainPublisher, i as createCloudflareEmptyCronPublisher } from "./cloudflare-operations-
|
|
42
|
+
import { r as discoverFrameworkWranglerFiles, t as migrateLegacyVoidConfig } from "./migrate-q4_njtaW.mjs";
|
|
43
|
+
import { a as createCloudflareEmptyDomainPublisher, i as createCloudflareEmptyCronPublisher } from "./cloudflare-operations-DzH-A966.mjs";
|
|
43
44
|
import { t as formatCloudflareUserMessage } from "./cloudflare-user-output-Q-k0QoNQ.mjs";
|
|
44
|
-
import { c as import_picocolors$1, i as createSpinner, r as cliTitle } from "./output-
|
|
45
|
-
import { a as promptProjectSelection, i as reportProjectCreationWarnings, o as promptProjectSetupAction, r as promptAndCreateProject } from "./create-project-
|
|
45
|
+
import { c as import_picocolors$1, i as createSpinner, r as cliTitle } from "./output-CbM85T4k.mjs";
|
|
46
|
+
import { a as promptProjectSelection, i as reportProjectCreationWarnings, o as promptProjectSetupAction, r as promptAndCreateProject } from "./create-project-CYOOAYcn.mjs";
|
|
46
47
|
import { t as getRequestedProjectSlug } from "./resolve-project-BG5ORGID.mjs";
|
|
47
48
|
import { t as collectGitDeployMetadata } from "./git-metadata-D-gurjzG.mjs";
|
|
48
|
-
import { t as promptForLoginToken } from "./login-
|
|
49
|
+
import { t as promptForLoginToken } from "./login-BuiMyUrx.mjs";
|
|
49
50
|
import { createRequire } from "node:module";
|
|
50
51
|
import { copyFileSync, cpSync, createWriteStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
51
52
|
import { fileURLToPath } from "node:url";
|
|
@@ -60,6 +61,7 @@ import { Minimatch } from "minimatch";
|
|
|
60
61
|
import { CloudflareWorkerInspectionError, 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";
|
|
61
62
|
import { getWorkerAssetsDir, getWorkerBundleDir, getWorkerConfigPath, readBuildOutput } from "@cloudflare/build-output-utils";
|
|
62
63
|
import ignore from "ignore";
|
|
64
|
+
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
63
65
|
import mime from "mime";
|
|
64
66
|
import { hash } from "blake3-jit";
|
|
65
67
|
//#region src/asset-routing.ts
|
|
@@ -110,6 +112,7 @@ function resolveAssetRoutingPolicy(inputs) {
|
|
|
110
112
|
}
|
|
111
113
|
//#endregion
|
|
112
114
|
//#region src/cli/email-cloudflare.ts
|
|
115
|
+
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
113
116
|
/** The `send_email` binding name Void provisions and the runtime reads. */
|
|
114
117
|
const SEND_EMAIL_BINDING = "SEND_EMAIL";
|
|
115
118
|
/** The root-config `vars` key carrying `void.config.ts` `email.from` into the worker. */
|
|
@@ -240,127 +243,84 @@ function deriveAddresses(handlers, domain, mode) {
|
|
|
240
243
|
routes
|
|
241
244
|
};
|
|
242
245
|
}
|
|
243
|
-
function parseWhoamiJson(
|
|
244
|
-
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (!parsed || typeof parsed !== "object" || typeof parsed.loggedIn !== "boolean") return null;
|
|
249
|
-
return parsed;
|
|
250
|
-
} catch {
|
|
251
|
-
return null;
|
|
252
|
-
}
|
|
246
|
+
function parseWhoamiJson(data) {
|
|
247
|
+
if (!isRecord(data) || typeof data.loggedIn !== "boolean") return null;
|
|
248
|
+
if (data.tokenPermissions !== void 0 && (!Array.isArray(data.tokenPermissions) || data.tokenPermissions.some((scope) => typeof scope !== "string"))) return null;
|
|
249
|
+
if (data.accounts !== void 0 && (!Array.isArray(data.accounts) || data.accounts.some((account) => !isRecord(account) || typeof account.id !== "string" || typeof account.name !== "string"))) return null;
|
|
250
|
+
return data;
|
|
253
251
|
}
|
|
254
|
-
function
|
|
255
|
-
|
|
256
|
-
const enabled = /^\s*Enabled:\s+(true|false)\s*$/m.exec(stdout)?.[1];
|
|
257
|
-
const status = /^\s*Status:\s+(\S+)\s*$/m.exec(stdout)?.[1];
|
|
258
|
-
const tag = /^\s*Tag:\s+([0-9a-f]{32})\s*$/m.exec(stdout)?.[1];
|
|
259
|
-
if (!name || !enabled || !status || !tag) return null;
|
|
260
|
-
return {
|
|
261
|
-
name,
|
|
262
|
-
enabled: enabled === "true",
|
|
263
|
-
status,
|
|
264
|
-
tag
|
|
265
|
-
};
|
|
252
|
+
function isRecord(value) {
|
|
253
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
266
254
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
* Catch-all rule: disabled, action: drop
|
|
278
|
-
* (use `wrangler email routing rules get catch-all` to view details)
|
|
279
|
-
*
|
|
280
|
-
* With no rule at all: `No routing rules found.` / no custom rule: `No custom routing
|
|
281
|
-
* rules found.`. Both forms are pinned by fixture.
|
|
282
|
-
*/
|
|
283
|
-
function parseRoutingRules(stdout) {
|
|
284
|
-
const lines = stdout.split(/\r?\n/);
|
|
255
|
+
function readRoutingSettings(data) {
|
|
256
|
+
return isRecord(data) && typeof data.name === "string" && data.name.length > 0 && typeof data.enabled === "boolean" && typeof data.status === "string" && data.status.length > 0 && typeof data.tag === "string" && /^[0-9a-f]{32}$/.test(data.tag) ? {
|
|
257
|
+
name: data.name,
|
|
258
|
+
enabled: data.enabled,
|
|
259
|
+
status: data.status,
|
|
260
|
+
tag: data.tag
|
|
261
|
+
} : null;
|
|
262
|
+
}
|
|
263
|
+
function readRoutingRules(data) {
|
|
264
|
+
if (!Array.isArray(data)) return null;
|
|
285
265
|
const rules = [];
|
|
286
266
|
let catchAll = null;
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
267
|
+
for (const entry of data) {
|
|
268
|
+
if (!isRecord(entry) || typeof entry.enabled !== "boolean" || !Array.isArray(entry.actions) || entry.actions.length === 0 || !Array.isArray(entry.matchers) || entry.matchers.length === 0) return null;
|
|
269
|
+
const actions = [];
|
|
270
|
+
for (const action of entry.actions) {
|
|
271
|
+
if (!isRecord(action) || typeof action.type !== "string") return null;
|
|
272
|
+
if (action.type === "drop") actions.push("drop");
|
|
273
|
+
else if (action.type === "worker" || action.type === "forward") {
|
|
274
|
+
const values = typeof action.value === "string" ? [action.value] : action.value;
|
|
275
|
+
if (!Array.isArray(values) || values.length === 0 || !values.every((value) => typeof value === "string" && value.length > 0)) return null;
|
|
276
|
+
if (action.type === "worker") actions.push("worker:" + values.join(","));
|
|
277
|
+
else actions.push("forward:" + values.join(","));
|
|
278
|
+
} else return null;
|
|
279
|
+
}
|
|
280
|
+
const to = [];
|
|
281
|
+
let all = false;
|
|
282
|
+
for (const matcher of entry.matchers) {
|
|
283
|
+
if (!isRecord(matcher)) return null;
|
|
284
|
+
if (matcher.type === "all") all = true;
|
|
285
|
+
else if (matcher.type === "literal" && matcher.field === "to" || matcher.type === "to") {
|
|
286
|
+
if (typeof matcher.value !== "string" || matcher.value.length === 0) return null;
|
|
287
|
+
to.push(matcher.value.toLowerCase());
|
|
288
|
+
} else return null;
|
|
289
|
+
}
|
|
290
|
+
if (all) {
|
|
291
|
+
if (catchAll || entry.matchers.length !== 1) return null;
|
|
297
292
|
catchAll = {
|
|
298
|
-
enabled:
|
|
299
|
-
actions
|
|
293
|
+
enabled: entry.enabled,
|
|
294
|
+
actions
|
|
300
295
|
};
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
to: [],
|
|
311
|
-
actions: []
|
|
312
|
-
};
|
|
313
|
-
rules.push(current);
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
if (!current) continue;
|
|
317
|
-
const field = /^\s{2}(Name|Enabled|Matchers|Actions|Priority):\s*(.*)$/.exec(line);
|
|
318
|
-
if (!field) continue;
|
|
319
|
-
const value = (field[2] ?? "").trim();
|
|
320
|
-
switch (field[1]) {
|
|
321
|
-
case "Name":
|
|
322
|
-
current.name = value;
|
|
323
|
-
break;
|
|
324
|
-
case "Enabled":
|
|
325
|
-
current.enabled = value === "true";
|
|
326
|
-
break;
|
|
327
|
-
case "Matchers":
|
|
328
|
-
current.to = value.split(", ").filter((m) => m.startsWith("to:")).map((m) => m.slice(3).toLowerCase());
|
|
329
|
-
break;
|
|
330
|
-
case "Actions": current.actions = splitActionList(value);
|
|
296
|
+
} else {
|
|
297
|
+
if (typeof entry.id !== "string" || entry.id.length === 0 || entry.name !== void 0 && typeof entry.name !== "string") return null;
|
|
298
|
+
rules.push({
|
|
299
|
+
id: entry.id,
|
|
300
|
+
name: entry.name ?? "",
|
|
301
|
+
enabled: entry.enabled,
|
|
302
|
+
to,
|
|
303
|
+
actions
|
|
304
|
+
});
|
|
331
305
|
}
|
|
332
306
|
}
|
|
333
|
-
if (!sawSentinel && rules.length === 0 && !catchAll) return null;
|
|
334
307
|
return {
|
|
335
308
|
rules,
|
|
336
309
|
catchAll
|
|
337
310
|
};
|
|
338
311
|
}
|
|
339
|
-
function
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
const tag = /^\s*Tag:\s+([0-9a-f]{32})\s*$/m.exec(stdout)?.[1];
|
|
346
|
-
if (!name || !enabled || !tag) return null;
|
|
347
|
-
return {
|
|
348
|
-
name,
|
|
349
|
-
enabled: enabled === "true",
|
|
312
|
+
function readSendingSettings(data) {
|
|
313
|
+
if (!isRecord(data)) return null;
|
|
314
|
+
const tag = data.tag ?? data.id;
|
|
315
|
+
return typeof data.name === "string" && data.name.length > 0 && typeof data.enabled === "boolean" && typeof tag === "string" && /^[0-9a-f]{32}$/.test(tag) ? {
|
|
316
|
+
name: data.name,
|
|
317
|
+
enabled: data.enabled,
|
|
350
318
|
tag
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
/** wrangler renders an `APIError` note as `<message> [code: <n>]`; extract the code. */
|
|
354
|
-
function wranglerApiErrorCode(text) {
|
|
355
|
-
const match = /\[code:\s*(\d+)\]/.exec(stripAnsi(text));
|
|
356
|
-
return match ? Number(match[1]) : null;
|
|
319
|
+
} : null;
|
|
357
320
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
return text.replace(ANSI_SGR_RE, "");
|
|
321
|
+
function providerErrorCode(result) {
|
|
322
|
+
return result.errorCode ?? result.errors?.find((error) => error.code !== void 0)?.code ?? null;
|
|
361
323
|
}
|
|
362
|
-
const ZONE_NOT_FOUND_RE = /Could not find (?:a )?zone for `([^`]+)`/;
|
|
363
|
-
const SENDING_NOT_FOUND_RE = /No sending subdomain found for `([^`]+)`/;
|
|
364
324
|
function isHardFailure(result) {
|
|
365
325
|
return Boolean(result.signal) || Boolean(result.error);
|
|
366
326
|
}
|
|
@@ -417,8 +377,10 @@ async function preflightEmail(inputs) {
|
|
|
417
377
|
const domain = emailFromDomain(inputs.from);
|
|
418
378
|
if (!domain) throw new Error(`email.from must be an address like you@mail.example.com (got ${JSON.stringify(inputs.from)})`);
|
|
419
379
|
const apiBaseUrl = inputs.apiBaseUrl ?? "https://api.cloudflare.com/client/v4";
|
|
420
|
-
const
|
|
421
|
-
|
|
380
|
+
const run = async (operation) => inputs.runWrangler({
|
|
381
|
+
...operation,
|
|
382
|
+
...inputs.configPath ? { configPath: inputs.configPath } : {}
|
|
383
|
+
}, { capture: true });
|
|
422
384
|
const usageHandlers = [...inputs.handlers.addresses.map((d) => `email/${d.filePath}`), ...inputs.handlers.defaultHandler ? [`email/${inputs.handlers.defaultHandler}`] : []];
|
|
423
385
|
const pre = {
|
|
424
386
|
from: inputs.from,
|
|
@@ -481,8 +443,8 @@ async function preflightEmail(inputs) {
|
|
|
481
443
|
});
|
|
482
444
|
};
|
|
483
445
|
for (const conflict of inputs.configConflicts ?? []) block("all", conflict);
|
|
484
|
-
const whoami = await run(
|
|
485
|
-
const who = isHardFailure(whoami) || whoami.status !== 0 ? null : parseWhoamiJson(whoami.
|
|
446
|
+
const whoami = await run({ type: "auth.whoami" });
|
|
447
|
+
const who = isHardFailure(whoami) || whoami.status !== 0 ? null : parseWhoamiJson(whoami.data);
|
|
486
448
|
if (!who) {
|
|
487
449
|
pre.session.state = "unknown";
|
|
488
450
|
block("all", "could not read the Cloudflare session — run `void cloudflare login`");
|
|
@@ -509,22 +471,20 @@ async function preflightEmail(inputs) {
|
|
|
509
471
|
let settings = null;
|
|
510
472
|
let settingsMiss = false;
|
|
511
473
|
if (pre.session.state === "ok") for (const candidate of zoneCandidates(domain)) {
|
|
512
|
-
const result = await run(
|
|
513
|
-
"email",
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
candidate
|
|
517
|
-
]);
|
|
474
|
+
const result = await run({
|
|
475
|
+
type: "email.routing.settings",
|
|
476
|
+
domain: candidate
|
|
477
|
+
});
|
|
518
478
|
if (isHardFailure(result)) {
|
|
519
479
|
settingsMiss = true;
|
|
520
480
|
break;
|
|
521
481
|
}
|
|
482
|
+
if (result.status === 0 && result.data === null) continue;
|
|
522
483
|
if (result.status !== 0) {
|
|
523
|
-
if (ZONE_NOT_FOUND_RE.test(stripAnsi(result.stderr))) continue;
|
|
524
484
|
settingsMiss = true;
|
|
525
485
|
break;
|
|
526
486
|
}
|
|
527
|
-
settings =
|
|
487
|
+
settings = readRoutingSettings(result.data);
|
|
528
488
|
if (!settings) settingsMiss = true;
|
|
529
489
|
break;
|
|
530
490
|
}
|
|
@@ -621,14 +581,11 @@ async function preflightEmail(inputs) {
|
|
|
621
581
|
else if (pre.domainMx.state === "unknown") block("all", `could not read the MX records of ${domain} — unknown — run \`void email setup --platform cloudflare\``);
|
|
622
582
|
}
|
|
623
583
|
pre.derived = deriveAddresses(inputs.handlers, domain, mode);
|
|
624
|
-
const rulesResult = await run(
|
|
625
|
-
"email",
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
apex
|
|
630
|
-
]);
|
|
631
|
-
const rules = isHardFailure(rulesResult) || rulesResult.status !== 0 ? null : parseRoutingRules(rulesResult.stdout);
|
|
584
|
+
const rulesResult = await run({
|
|
585
|
+
type: "email.routing.rules.list",
|
|
586
|
+
domain: apex
|
|
587
|
+
});
|
|
588
|
+
const rules = isHardFailure(rulesResult) || rulesResult.status !== 0 ? null : readRoutingRules(rulesResult.data);
|
|
632
589
|
if (!rules) {
|
|
633
590
|
pre.rules.state = "unknown";
|
|
634
591
|
block("all", `could not read Email Routing rules — unknown — run \`void email setup --platform cloudflare\`${tokenHint}`);
|
|
@@ -658,18 +615,16 @@ async function preflightEmail(inputs) {
|
|
|
658
615
|
}
|
|
659
616
|
const foreign = new Set(pre.rules.foreign.map((f) => f.address));
|
|
660
617
|
pre.addresses = pre.derived.addresses.filter((a) => !foreign.has(a));
|
|
661
|
-
const sendingResult = await run(
|
|
662
|
-
"email",
|
|
663
|
-
"sending",
|
|
664
|
-
"settings",
|
|
618
|
+
const sendingResult = await run({
|
|
619
|
+
type: "email.sending.settings",
|
|
665
620
|
domain
|
|
666
|
-
|
|
621
|
+
});
|
|
667
622
|
if (isHardFailure(sendingResult)) pre.sending.state = "unknown";
|
|
623
|
+
else if (sendingResult.status === 0 && sendingResult.data === null) pre.sending.state = "pending";
|
|
668
624
|
else if (sendingResult.status === 0) {
|
|
669
|
-
const parsed =
|
|
625
|
+
const parsed = readSendingSettings(sendingResult.data);
|
|
670
626
|
pre.sending.state = parsed ? parsed.enabled ? "ready" : "pending" : "unknown";
|
|
671
|
-
} else
|
|
672
|
-
else pre.sending.state = "unknown";
|
|
627
|
+
} else pre.sending.state = "unknown";
|
|
673
628
|
if (pre.sending.state === "unknown") block("sending", `could not read Email Sending settings — unknown — run \`void email setup --platform cloudflare\`${tokenHint}`);
|
|
674
629
|
else if (pre.sending.state === "pending" && pre.sending.dnsConflicts.length > 0) block("sending", `${pre.sending.dnsConflicts.join(", ")} already exists; onboarding writes its own _dmarc (p=reject) and DKIM records and would conflict — remove them or keep sending off`);
|
|
675
630
|
const names = (inputs.existingSendEmail ?? []).map((e) => typeof e?.name === "string" ? e.name : "");
|
|
@@ -849,8 +804,10 @@ async function applyEmailSetup(pre, inputs) {
|
|
|
849
804
|
}
|
|
850
805
|
const apex = pre.apex;
|
|
851
806
|
const apiBaseUrl = inputs.apiBaseUrl ?? "https://api.cloudflare.com/client/v4";
|
|
852
|
-
const
|
|
853
|
-
|
|
807
|
+
const run = async (operation) => inputs.runWrangler({
|
|
808
|
+
...operation,
|
|
809
|
+
...inputs.configPath ? { configPath: inputs.configPath } : {}
|
|
810
|
+
}, { capture: true });
|
|
854
811
|
let bearer;
|
|
855
812
|
let bearerFailed = false;
|
|
856
813
|
let bearerObtained = false;
|
|
@@ -879,17 +836,15 @@ async function applyEmailSetup(pre, inputs) {
|
|
|
879
836
|
const apexRoutingOff = pre.mode === "subdomain" && pre.routing.enabled !== true;
|
|
880
837
|
if (!result.routingReady) {
|
|
881
838
|
if (pre.mode === "apex") {
|
|
882
|
-
const enable = await run(
|
|
883
|
-
"email",
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
apex
|
|
887
|
-
]);
|
|
839
|
+
const enable = await run({
|
|
840
|
+
type: "email.routing.enable",
|
|
841
|
+
domain: apex
|
|
842
|
+
});
|
|
888
843
|
if (!isHardFailure(enable) && enable.status === 0) {
|
|
889
844
|
result.routingReady = true;
|
|
890
845
|
lines.push(` ✔ routing ${apex} enabled`);
|
|
891
846
|
} else {
|
|
892
|
-
const code =
|
|
847
|
+
const code = providerErrorCode(enable);
|
|
893
848
|
lines.push(` ✘ routing could not enable Email Routing on ${apex}${code ? ` [code: ${code}]${CF_EMAIL_ERROR_CODES[code] ? ` — ${CF_EMAIL_ERROR_CODES[code]}` : ""}` : ""}`);
|
|
894
849
|
}
|
|
895
850
|
} else if (apexRoutingOff) {
|
|
@@ -920,13 +875,11 @@ async function applyEmailSetup(pre, inputs) {
|
|
|
920
875
|
const sendingBlocked = pre.blockers.filter((b) => b.scope === "sending");
|
|
921
876
|
if (!result.sendingReady && sendingBlocked.length > 0) for (const b of sendingBlocked) lines.push(` ! sending ${b.message}`);
|
|
922
877
|
else if (!result.sendingReady) {
|
|
923
|
-
const enable = await run(
|
|
924
|
-
"email",
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
]);
|
|
929
|
-
const code = isHardFailure(enable) ? null : wranglerApiErrorCode(enable.stderr);
|
|
878
|
+
const enable = await run({
|
|
879
|
+
type: "email.sending.enable",
|
|
880
|
+
domain: pre.domain
|
|
881
|
+
});
|
|
882
|
+
const code = isHardFailure(enable) ? null : providerErrorCode(enable);
|
|
930
883
|
if (!isHardFailure(enable) && (enable.status === 0 || code === 2040)) {
|
|
931
884
|
result.sendingReady = true;
|
|
932
885
|
lines.push(` ✔ sending ${pre.domain} onboarded`);
|
|
@@ -976,37 +929,6 @@ async function createNodeEmailDns() {
|
|
|
976
929
|
};
|
|
977
930
|
}
|
|
978
931
|
//#endregion
|
|
979
|
-
//#region src/durable/scan.ts
|
|
980
|
-
const MODULE_PATTERN = /\.(?:[cm]?[jt]s)$/;
|
|
981
|
-
function words(value) {
|
|
982
|
-
return value.split(/[^a-zA-Z0-9]+/).filter(Boolean);
|
|
983
|
-
}
|
|
984
|
-
function scanDurableObjectModules(root) {
|
|
985
|
-
const directory = join(root, "durable-objects");
|
|
986
|
-
if (!existsSync(directory)) return [];
|
|
987
|
-
const modules = readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isFile() && MODULE_PATTERN.test(entry.name) && !entry.name.endsWith(".d.ts")).sort((a, b) => a.name.localeCompare(b.name)).map((entry) => {
|
|
988
|
-
const parts = words(entry.name.replace(MODULE_PATTERN, ""));
|
|
989
|
-
if (parts.length === 0) throw new Error(`durable: cannot derive a name from durable-objects/${entry.name}.`);
|
|
990
|
-
const classBase = parts.map((part) => part[0].toUpperCase() + part.slice(1)).join("");
|
|
991
|
-
const bindingName = parts.join("_").toUpperCase();
|
|
992
|
-
const slug = parts.join("-").toLowerCase();
|
|
993
|
-
return {
|
|
994
|
-
filePath: join(directory, entry.name),
|
|
995
|
-
bindingName,
|
|
996
|
-
className: `${classBase}DurableObject`,
|
|
997
|
-
migrationTag: `void-durable-${slug}-v1`
|
|
998
|
-
};
|
|
999
|
-
});
|
|
1000
|
-
const bindings = /* @__PURE__ */ new Set();
|
|
1001
|
-
const classes = /* @__PURE__ */ new Set();
|
|
1002
|
-
for (const module of modules) {
|
|
1003
|
-
if (bindings.has(module.bindingName) || classes.has(module.className)) throw new Error(`durable: duplicate generated name for '${module.filePath}'. Rename one of the durable-objects files.`);
|
|
1004
|
-
bindings.add(module.bindingName);
|
|
1005
|
-
classes.add(module.className);
|
|
1006
|
-
}
|
|
1007
|
-
return modules;
|
|
1008
|
-
}
|
|
1009
|
-
//#endregion
|
|
1010
932
|
//#region ../../node_modules/.pnpm/ci-info@4.4.0/node_modules/ci-info/vendors.json
|
|
1011
933
|
var require_vendors = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
1012
934
|
module.exports = [
|
|
@@ -1617,8 +1539,8 @@ function buildPrerenderBindings(input) {
|
|
|
1617
1539
|
if (input.voidToken && input.voidProjectId) {
|
|
1618
1540
|
voidBindings.__VOID_TOKEN = input.voidToken;
|
|
1619
1541
|
voidBindings.__VOID_PROJECT_ID = input.voidProjectId;
|
|
1620
|
-
if (input.
|
|
1621
|
-
voidBindings.__VOID_PROXY_URL = input.voidProxyUrl
|
|
1542
|
+
if (!input.voidProxyUrl) throw new Error("prerender: No connected platform proxy is available. Run `void connect <url>` first.");
|
|
1543
|
+
voidBindings.__VOID_PROXY_URL = input.voidProxyUrl;
|
|
1622
1544
|
const access = scopedAccessCredentials(input.accessEnv ?? {}, voidBindings.__VOID_PROXY_URL);
|
|
1623
1545
|
if (access) voidBindings.__VOID_ACCESS_CREDENTIALS = access;
|
|
1624
1546
|
if (input.remoteMode) voidBindings.__VOID_REMOTE = "1";
|
|
@@ -1646,7 +1568,6 @@ async function createCloudflarePrerenderRunner(options) {
|
|
|
1646
1568
|
} catch {}
|
|
1647
1569
|
}
|
|
1648
1570
|
const voidToken = voidProjectId ? options.voidToken ?? getToken(root) : null;
|
|
1649
|
-
const voidStaging = isStagingMode(root);
|
|
1650
1571
|
const voidProxyUrl = voidToken && voidProjectId ? getProxyUrl(root) : void 0;
|
|
1651
1572
|
if (voidProxyUrl) ensurePlatformProxyAccess(getApiUrl(root), voidProxyUrl);
|
|
1652
1573
|
const bindings = buildPrerenderBindings({
|
|
@@ -1656,7 +1577,6 @@ async function createCloudflarePrerenderRunner(options) {
|
|
|
1656
1577
|
voidToken,
|
|
1657
1578
|
voidProjectId,
|
|
1658
1579
|
voidProxyUrl,
|
|
1659
|
-
voidStaging,
|
|
1660
1580
|
remoteMode
|
|
1661
1581
|
});
|
|
1662
1582
|
const { Miniflare, convertV4MiniflareOptions } = await import("miniflare");
|
|
@@ -1748,7 +1668,7 @@ async function prerenderPages(options) {
|
|
|
1748
1668
|
paths,
|
|
1749
1669
|
...await renderPrerenderPaths(paths, options.clientDir, (path) => runner.fetchPath(path), (path) => runner.fetchPageData(path), (path, outputFile, error) => {
|
|
1750
1670
|
if (error !== void 0) voidWarn(`prerender ${path} failed: ${error}`);
|
|
1751
|
-
else voidLog(`prerender
|
|
1671
|
+
else voidLog(`prerender ${import_picocolors.default.blue(outputFile)}`);
|
|
1752
1672
|
})
|
|
1753
1673
|
};
|
|
1754
1674
|
} finally {
|
|
@@ -1854,12 +1774,43 @@ async function prerenderPagesNode(options) {
|
|
|
1854
1774
|
ssrDir: options.ssrDir,
|
|
1855
1775
|
clientDir: options.clientDir
|
|
1856
1776
|
});
|
|
1857
|
-
for (const path of result.rendered) voidLog(`prerender
|
|
1777
|
+
for (const path of result.rendered) voidLog(`prerender ${import_picocolors.default.blue(outputFileForPath(path))}`);
|
|
1858
1778
|
for (const { path, error } of result.failed) voidWarn(`prerender ${path} failed: ${error}`);
|
|
1859
1779
|
return result;
|
|
1860
1780
|
}
|
|
1861
1781
|
//#endregion
|
|
1782
|
+
//#region src/shared/version-metadata.ts
|
|
1783
|
+
/** Build-only marker: an existing-site handoff must not add Worker bindings. */
|
|
1784
|
+
const CLOUDFLARE_PRESERVE_BINDINGS_BUILD_ENV = "VOID_CLOUDFLARE_PRESERVE_BINDINGS";
|
|
1785
|
+
const DEFAULT_VERSION_METADATA_BINDING = "__VOID_VERSION_METADATA";
|
|
1786
|
+
/** Keep the authored singleton name, and reject a cross-type binding collision. */
|
|
1787
|
+
function readVersionMetadataBinding(config) {
|
|
1788
|
+
const name = bindingNamesForField("version_metadata", config.version_metadata)[0];
|
|
1789
|
+
if (!name) return;
|
|
1790
|
+
const owner = findBindingNameOwner(config, "version_metadata", name);
|
|
1791
|
+
if (owner) throw new Error(`Cloudflare version metadata binding ${name} conflicts with ${owner}.`);
|
|
1792
|
+
return name;
|
|
1793
|
+
}
|
|
1794
|
+
/** Self-metadata adds no remote resource or plan entitlement. */
|
|
1795
|
+
function selectNativeVersionMetadataBinding(config, options) {
|
|
1796
|
+
if (!options.nativeBuild) return;
|
|
1797
|
+
const authored = readVersionMetadataBinding(config);
|
|
1798
|
+
if (authored || options.preserveBindings) return authored;
|
|
1799
|
+
const owner = findBindingNameOwner(config, "version_metadata", DEFAULT_VERSION_METADATA_BINDING);
|
|
1800
|
+
if (owner) throw new Error(`Cloudflare version metadata binding ${DEFAULT_VERSION_METADATA_BINDING} conflicts with ${owner}.`);
|
|
1801
|
+
return DEFAULT_VERSION_METADATA_BINDING;
|
|
1802
|
+
}
|
|
1803
|
+
//#endregion
|
|
1862
1804
|
//#region src/cli/cf-version-api.ts
|
|
1805
|
+
var CloudflareApiError = class extends Error {
|
|
1806
|
+
status;
|
|
1807
|
+
code;
|
|
1808
|
+
constructor(message, status, code) {
|
|
1809
|
+
super(message);
|
|
1810
|
+
this.status = status;
|
|
1811
|
+
this.code = code;
|
|
1812
|
+
}
|
|
1813
|
+
};
|
|
1863
1814
|
function object(value) {
|
|
1864
1815
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
1865
1816
|
}
|
|
@@ -1959,38 +1910,181 @@ function bindingsFromOutput(env, workerName, activeSecrets, explicitSecrets) {
|
|
|
1959
1910
|
...value.worker !== workerName ? { script_name: requiredString(value.worker, name) } : {}
|
|
1960
1911
|
});
|
|
1961
1912
|
break;
|
|
1913
|
+
case "unsafe:durable_object_namespace":
|
|
1914
|
+
if (Object.keys(value).some((key) => ![
|
|
1915
|
+
"type",
|
|
1916
|
+
"class_name",
|
|
1917
|
+
"dev"
|
|
1918
|
+
].includes(key))) throw new Error(`Cloudflare binding ${name} is not a verified local Durable Object.`);
|
|
1919
|
+
bindings.push({
|
|
1920
|
+
name,
|
|
1921
|
+
type: "durable_object_namespace",
|
|
1922
|
+
class_name: requiredString(value.class_name, name)
|
|
1923
|
+
});
|
|
1924
|
+
break;
|
|
1925
|
+
case "queue":
|
|
1926
|
+
bindings.push({
|
|
1927
|
+
name,
|
|
1928
|
+
type: "queue",
|
|
1929
|
+
queue_name: requiredString(value.name, name),
|
|
1930
|
+
...value.deliveryDelay === void 0 ? {} : { delivery_delay: value.deliveryDelay }
|
|
1931
|
+
});
|
|
1932
|
+
break;
|
|
1933
|
+
case "ai":
|
|
1934
|
+
case "browser":
|
|
1935
|
+
case "images":
|
|
1936
|
+
bindings.push({
|
|
1937
|
+
name,
|
|
1938
|
+
type: value.type
|
|
1939
|
+
});
|
|
1940
|
+
break;
|
|
1941
|
+
case "hyperdrive":
|
|
1942
|
+
bindings.push({
|
|
1943
|
+
name,
|
|
1944
|
+
type: "hyperdrive",
|
|
1945
|
+
id: requiredString(value.id, name)
|
|
1946
|
+
});
|
|
1947
|
+
break;
|
|
1948
|
+
case "worker":
|
|
1949
|
+
bindings.push({
|
|
1950
|
+
name,
|
|
1951
|
+
type: "service",
|
|
1952
|
+
service: requiredString(value.worker, name),
|
|
1953
|
+
...value.exportName === void 0 ? {} : { entrypoint: value.exportName },
|
|
1954
|
+
...value.props === void 0 ? {} : { props: value.props }
|
|
1955
|
+
});
|
|
1956
|
+
break;
|
|
1957
|
+
case "workflow":
|
|
1958
|
+
bindings.push({
|
|
1959
|
+
name,
|
|
1960
|
+
type: "workflow",
|
|
1961
|
+
workflow_name: requiredString(value.name, name),
|
|
1962
|
+
...value.worker === workerName ? { class_name: requiredString(value.exportName, name) } : { script_name: requiredString(value.worker, name) }
|
|
1963
|
+
});
|
|
1964
|
+
break;
|
|
1965
|
+
case "send-email":
|
|
1966
|
+
bindings.push({
|
|
1967
|
+
name,
|
|
1968
|
+
type: "send_email",
|
|
1969
|
+
...value.destinationAddress === void 0 ? {} : { destination_address: value.destinationAddress },
|
|
1970
|
+
...value.allowedDestinationAddresses === void 0 ? {} : { allowed_destination_addresses: value.allowedDestinationAddresses },
|
|
1971
|
+
...value.allowedSenderAddresses === void 0 ? {} : { allowed_sender_addresses: value.allowedSenderAddresses }
|
|
1972
|
+
});
|
|
1973
|
+
break;
|
|
1974
|
+
case "analytics-engine-dataset":
|
|
1975
|
+
bindings.push({
|
|
1976
|
+
name,
|
|
1977
|
+
type: "analytics_engine",
|
|
1978
|
+
...value.name === void 0 ? {} : { dataset: value.name }
|
|
1979
|
+
});
|
|
1980
|
+
break;
|
|
1981
|
+
case "vectorize":
|
|
1982
|
+
bindings.push({
|
|
1983
|
+
name,
|
|
1984
|
+
type: "vectorize",
|
|
1985
|
+
index_name: requiredString(value.name, name)
|
|
1986
|
+
});
|
|
1987
|
+
break;
|
|
1988
|
+
case "dispatch-namespace": {
|
|
1989
|
+
const outbound = object(value.outbound);
|
|
1990
|
+
bindings.push({
|
|
1991
|
+
name,
|
|
1992
|
+
type: "dispatch_namespace",
|
|
1993
|
+
namespace: requiredString(value.namespace, name),
|
|
1994
|
+
...outbound ? { outbound: {
|
|
1995
|
+
worker: { service: requiredString(outbound.worker, name) },
|
|
1996
|
+
...Array.isArray(outbound.parameters) ? { params: outbound.parameters.map((parameter) => ({ name: parameter })) } : {}
|
|
1997
|
+
} } : {}
|
|
1998
|
+
});
|
|
1999
|
+
break;
|
|
2000
|
+
}
|
|
1962
2001
|
case "assets":
|
|
1963
2002
|
bindings.push({
|
|
1964
2003
|
name,
|
|
1965
2004
|
type: "assets"
|
|
1966
2005
|
});
|
|
1967
2006
|
break;
|
|
2007
|
+
case "version-metadata":
|
|
2008
|
+
bindings.push({
|
|
2009
|
+
name,
|
|
2010
|
+
type: "version_metadata"
|
|
2011
|
+
});
|
|
2012
|
+
break;
|
|
1968
2013
|
default: throw new Error(`Cloudflare binding ${name} cannot be uploaded with pinned secrets.`);
|
|
1969
2014
|
}
|
|
1970
2015
|
}
|
|
1971
2016
|
return bindings;
|
|
1972
2017
|
}
|
|
1973
|
-
function exportsFromOutput(exports) {
|
|
2018
|
+
function exportsFromOutput(exports, bindings) {
|
|
1974
2019
|
if (exports === void 0) return;
|
|
1975
2020
|
const entries = object(exports);
|
|
1976
2021
|
if (!entries) throw new Error("Cloudflare Durable Object exports were not readable.");
|
|
1977
2022
|
const result = {};
|
|
2023
|
+
const workflows = /* @__PURE__ */ new Map();
|
|
1978
2024
|
for (const [name, raw] of Object.entries(entries)) {
|
|
1979
2025
|
const value = object(raw);
|
|
2026
|
+
if (value?.type === "workflow") {
|
|
2027
|
+
const workflowName = requiredString(value.name, `Workflow export ${name} name`);
|
|
2028
|
+
if (workflows.has(workflowName)) throw new Error(`Cloudflare Workflow ${workflowName} has multiple local exports.`);
|
|
2029
|
+
workflows.set(workflowName, name);
|
|
2030
|
+
result[name] = {
|
|
2031
|
+
type: "workflow",
|
|
2032
|
+
name: workflowName
|
|
2033
|
+
};
|
|
2034
|
+
continue;
|
|
2035
|
+
}
|
|
2036
|
+
if (value?.type === "worker") {
|
|
2037
|
+
result[name] = {
|
|
2038
|
+
type: "worker",
|
|
2039
|
+
...value.cache === void 0 ? {} : { cache: value.cache }
|
|
2040
|
+
};
|
|
2041
|
+
continue;
|
|
2042
|
+
}
|
|
1980
2043
|
if (!value || value.type !== "durable-object") throw new Error(`Cloudflare export ${name} cannot be uploaded with pinned secrets.`);
|
|
1981
2044
|
if (value.state === "deleted") result[name] = {
|
|
1982
2045
|
type: "durable-object",
|
|
1983
2046
|
state: "deleted"
|
|
1984
2047
|
};
|
|
1985
|
-
else if (value.
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
2048
|
+
else if (value.state === "renamed" || value.state === "transferred") {
|
|
2049
|
+
const renamed = value.state === "renamed";
|
|
2050
|
+
result[name] = {
|
|
2051
|
+
type: "durable-object",
|
|
2052
|
+
state: value.state,
|
|
2053
|
+
[renamed ? "renamed_to" : "transferred_to"]: requiredString(value[renamed ? "renamedTo" : "transferredTo"], name)
|
|
2054
|
+
};
|
|
2055
|
+
} else if (value.storage === "sqlite" || value.storage === "legacy-kv") {
|
|
2056
|
+
if (value.state !== void 0 && !["created", "expecting-transfer"].includes(String(value.state))) throw new Error(`Cloudflare Durable Object export ${name} has an unsupported state.`);
|
|
2057
|
+
result[name] = {
|
|
2058
|
+
type: "durable-object",
|
|
2059
|
+
storage: value.storage,
|
|
2060
|
+
state: value.state ?? "created",
|
|
2061
|
+
...value.container === void 0 ? {} : { container: requiredString(value.container, name) },
|
|
2062
|
+
...value.state === "expecting-transfer" ? { transfer_from: requiredString(value.transferFrom, name) } : {}
|
|
2063
|
+
};
|
|
2064
|
+
} else throw new Error(`Cloudflare Durable Object export ${name} has no storage type.`);
|
|
2065
|
+
}
|
|
2066
|
+
for (const binding of bindings) {
|
|
2067
|
+
if (binding.type !== "workflow") continue;
|
|
2068
|
+
const localExport = workflows.get(String(binding.workflow_name));
|
|
2069
|
+
if (localExport !== void 0 && (binding.script_name !== void 0 || binding.class_name !== localExport)) throw new Error(`Cloudflare Workflow binding ${binding.name} conflicts with its local export.`);
|
|
1991
2070
|
}
|
|
1992
2071
|
return result;
|
|
1993
2072
|
}
|
|
2073
|
+
async function preflightWorkflowExports(options) {
|
|
2074
|
+
for (const raw of Object.values(options.exports ?? {})) {
|
|
2075
|
+
const entry = object(raw);
|
|
2076
|
+
if (entry?.type !== "workflow") continue;
|
|
2077
|
+
const name = requiredString(entry.name, "Workflow name");
|
|
2078
|
+
let workflow;
|
|
2079
|
+
try {
|
|
2080
|
+
workflow = await apiResult(`${options.accountUrl}/workflows/${encodeURIComponent(name)}`, options.token, "GET", void 0, options.verifyUploader);
|
|
2081
|
+
} catch (cause) {
|
|
2082
|
+
if (cause instanceof CloudflareApiError && cause.status === 404 && cause.code === 10200) continue;
|
|
2083
|
+
throw cause;
|
|
2084
|
+
}
|
|
2085
|
+
if (workflow.name !== name || workflow.script_name !== options.workerName || typeof workflow.class_name !== "string" || !workflow.class_name) throw new Error(`Cloudflare Workflow ${name} is not owned by this Worker.`);
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
1994
2088
|
function assetConfigFromOutput(value) {
|
|
1995
2089
|
if (value === void 0) return;
|
|
1996
2090
|
const config = object(value);
|
|
@@ -2027,11 +2121,211 @@ async function apiResult(url, token, method, body, verifyUploader, timeout = 12e
|
|
|
2027
2121
|
if (!response.ok || parsed?.success !== true || !result) {
|
|
2028
2122
|
const error = Array.isArray(parsed?.errors) ? object(parsed.errors[0]) : null;
|
|
2029
2123
|
const code = Number.isSafeInteger(error?.code) ? ` [code: ${error.code}]` : "";
|
|
2030
|
-
|
|
2031
|
-
throw new Error(`Cloudflare version upload failed (${response.status})${code}.${message}`);
|
|
2124
|
+
throw new CloudflareApiError(`Cloudflare version upload failed (${response.status})${code}.`, response.status, typeof error?.code === "number" ? error.code : void 0);
|
|
2032
2125
|
}
|
|
2033
2126
|
return result;
|
|
2034
2127
|
}
|
|
2128
|
+
function assertContainerApplicationIdentity(application, plan, namespace) {
|
|
2129
|
+
if (application.id !== namespace || application.name !== plan.name || application.scheduling_policy !== "durable_object" || object(application.durable_objects)?.namespace_id !== namespace) throw new Error(`Cloudflare Container ${plan.name} application identity does not match the uploaded namespace.`);
|
|
2130
|
+
}
|
|
2131
|
+
function assertContainerApplicationSettings(application, plan) {
|
|
2132
|
+
const desired = object(plan.settings.configuration) ?? {};
|
|
2133
|
+
const current = object(application.configuration) ?? {};
|
|
2134
|
+
const changedConfiguration = Object.entries(desired).some(([key, value]) => {
|
|
2135
|
+
if (key === "wrangler_ssh") {
|
|
2136
|
+
const ssh = object(current.wrangler_ssh) ?? {};
|
|
2137
|
+
const expected = object(value) ?? {};
|
|
2138
|
+
return !isDeepStrictEqual(ssh.enabled ?? false, expected.enabled) || expected.enabled === true && expected.port !== void 0 && !isDeepStrictEqual(ssh.port, expected.port);
|
|
2139
|
+
}
|
|
2140
|
+
if (key === "experimental_flags" && Array.isArray(value)) {
|
|
2141
|
+
const flags = current.experimental_flags ?? [];
|
|
2142
|
+
return !Array.isArray(flags) || !isDeepStrictEqual([...flags].sort(), [...value].sort());
|
|
2143
|
+
}
|
|
2144
|
+
return !isDeepStrictEqual(current[key] ?? [], value);
|
|
2145
|
+
});
|
|
2146
|
+
const logs = object(object(plan.settings.observability)?.logs);
|
|
2147
|
+
const currentLogs = object(object(application.observability)?.logs);
|
|
2148
|
+
if (changedConfiguration || logs !== null && !isDeepStrictEqual(currentLogs?.enabled ?? false, logs.enabled)) throw new Error(`Cloudflare Container ${plan.name} settings differ from the live application. Version-aware deployment cannot safely change these shared settings. Keep the existing Container settings in your configuration, or update this Container explicitly in the Cloudflare dashboard before retrying.`);
|
|
2149
|
+
}
|
|
2150
|
+
async function preflightContainerApplications(plans, bindings, accountUrl, workerName, token, verifyUploader) {
|
|
2151
|
+
for (const plan of plans) {
|
|
2152
|
+
const matches = bindings.map(object).filter((binding) => binding?.type === "durable_object_namespace" && binding.class_name === plan.className && (binding.script_name === void 0 || binding.script_name === workerName) && binding.environment === void 0 && binding.dispatch_namespace === void 0 && binding.namespace_id !== void 0);
|
|
2153
|
+
const namespaces = new Set(matches.map((binding) => binding.namespace_id));
|
|
2154
|
+
if (namespaces.size > 1) throw new Error(`Cloudflare Container ${plan.name} active namespace was ambiguous.`);
|
|
2155
|
+
const namespace = [...namespaces][0];
|
|
2156
|
+
if (namespace === void 0) {
|
|
2157
|
+
if (Object.keys(plan.images).length === 0) throw new Error(`Cloudflare Container ${plan.name} has no images and no verified existing namespace application.`);
|
|
2158
|
+
continue;
|
|
2159
|
+
}
|
|
2160
|
+
if (typeof namespace !== "string" || !/^[a-f0-9]{32}$/.test(namespace)) throw new Error("The active Container namespace ID was invalid.");
|
|
2161
|
+
try {
|
|
2162
|
+
const application = await apiResult(`${accountUrl}/containers/applications/${encodeURIComponent(namespace)}`, token, "GET", void 0, verifyUploader);
|
|
2163
|
+
assertContainerApplicationIdentity(application, plan, namespace);
|
|
2164
|
+
assertContainerApplicationSettings(application, plan);
|
|
2165
|
+
} catch (cause) {
|
|
2166
|
+
if (!(cause instanceof CloudflareApiError) || cause.status !== 404 || Object.keys(plan.images).length === 0) throw cause;
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
function containerPlansFromOutput(containers, exports, bindings) {
|
|
2171
|
+
const plans = [];
|
|
2172
|
+
for (const { config } of containers) {
|
|
2173
|
+
if (config.schedulingPolicy !== "durable-object") throw new Error("Scheduler-managed Cloudflare Containers cannot be uploaded with pinned secrets.");
|
|
2174
|
+
const classes = Object.entries(exports ?? {}).filter(([, value]) => object(value)?.container === config.name);
|
|
2175
|
+
if (classes.length !== 1) throw new Error(`Cloudflare Container ${config.name} needs exactly one local SQLite export.`);
|
|
2176
|
+
const [className, raw] = classes[0];
|
|
2177
|
+
const declaration = object(raw);
|
|
2178
|
+
const localBindings = bindings.filter((binding) => binding.type === "durable_object_namespace" && binding.class_name === className && binding.script_name === void 0);
|
|
2179
|
+
if (declaration.storage !== "sqlite" || localBindings.length === 0) throw new Error(`Cloudflare Container ${config.name} needs a local SQLite Durable Object binding.`);
|
|
2180
|
+
const unsafe = object(config.unsafe);
|
|
2181
|
+
const configuration = object(unsafe?.configuration);
|
|
2182
|
+
if (unsafe && Object.keys(unsafe).some((key) => key !== "configuration") || configuration && Object.keys(configuration).some((key) => key !== "experimental_flags")) throw new Error(`Cloudflare Container ${config.name} has an unsupported setting.`);
|
|
2183
|
+
const settings = {
|
|
2184
|
+
...configuration || config.ssh || config.authorizedKeys ? { configuration: {
|
|
2185
|
+
...configuration ?? {},
|
|
2186
|
+
...config.ssh ? { wrangler_ssh: config.ssh } : {},
|
|
2187
|
+
...config.authorizedKeys ? { authorized_keys: config.authorizedKeys.map(({ name, publicKey }) => ({
|
|
2188
|
+
name,
|
|
2189
|
+
public_key: publicKey
|
|
2190
|
+
})) } : {}
|
|
2191
|
+
} } : {},
|
|
2192
|
+
...config.observability ? { observability: { logs: { enabled: config.observability.enabled === true || config.observability.logs?.enabled === true } } } : {}
|
|
2193
|
+
};
|
|
2194
|
+
plans.push({
|
|
2195
|
+
name: config.name,
|
|
2196
|
+
className,
|
|
2197
|
+
images: config.images ?? {},
|
|
2198
|
+
settings
|
|
2199
|
+
});
|
|
2200
|
+
}
|
|
2201
|
+
for (const [name, raw] of Object.entries(exports ?? {})) {
|
|
2202
|
+
const container = object(raw)?.container;
|
|
2203
|
+
if (container !== void 0 && !plans.some((plan) => plan.name === container && plan.className === name)) throw new Error(`Cloudflare export ${name} references a Container outside the verified output.`);
|
|
2204
|
+
}
|
|
2205
|
+
return plans;
|
|
2206
|
+
}
|
|
2207
|
+
async function dockerImageDigest(image, timeout, verifyUploader) {
|
|
2208
|
+
if (!verifyUploader()) throw new Error("The Cloudflare uploader changed during deployment.");
|
|
2209
|
+
const stdout = await new Promise((resolve, reject) => {
|
|
2210
|
+
execFile(process.env.WRANGLER_DOCKER_BIN ?? "docker", [
|
|
2211
|
+
"image",
|
|
2212
|
+
"inspect",
|
|
2213
|
+
"--format",
|
|
2214
|
+
"{{json .RepoDigests}}",
|
|
2215
|
+
image
|
|
2216
|
+
], {
|
|
2217
|
+
encoding: "utf8",
|
|
2218
|
+
timeout,
|
|
2219
|
+
maxBuffer: 1048576,
|
|
2220
|
+
windowsHide: true
|
|
2221
|
+
}, (error, stdout) => error ? reject(/* @__PURE__ */ new Error("Cloudflare Container image digest could not be verified after push.")) : resolve(stdout));
|
|
2222
|
+
});
|
|
2223
|
+
const digests = JSON.parse(stdout);
|
|
2224
|
+
const repository = image.replace(/:[^/:]+$/, "");
|
|
2225
|
+
const matching = Array.isArray(digests) ? digests.filter((digest) => typeof digest === "string" && digest.startsWith(`${repository}@sha256:`) && /^[a-f0-9]{64}$/.test(digest.slice(digest.lastIndexOf(":") + 1))) : [];
|
|
2226
|
+
if (matching.length !== 1) throw new Error("Cloudflare Container image digest could not be verified after push.");
|
|
2227
|
+
return matching[0];
|
|
2228
|
+
}
|
|
2229
|
+
async function prepareContainerMetadata(options) {
|
|
2230
|
+
if (options.plans.length === 0) return [];
|
|
2231
|
+
const deadline = Date.now() + 9e5;
|
|
2232
|
+
const remaining = () => {
|
|
2233
|
+
const duration = deadline - Date.now();
|
|
2234
|
+
if (duration <= 0) throw new Error("Cloudflare Container image preparation timed out.");
|
|
2235
|
+
return duration;
|
|
2236
|
+
};
|
|
2237
|
+
const prepared = /* @__PURE__ */ new Map();
|
|
2238
|
+
const result = [];
|
|
2239
|
+
for (const plan of options.plans) {
|
|
2240
|
+
const images = {};
|
|
2241
|
+
for (const [name, raw] of Object.entries(plan.images)) {
|
|
2242
|
+
const source = object(raw);
|
|
2243
|
+
const reference = requiredString(source.localReference ?? source.reference, `Container ${plan.name} image`);
|
|
2244
|
+
let image = prepared.get(reference);
|
|
2245
|
+
if (!image) {
|
|
2246
|
+
image = reference;
|
|
2247
|
+
if (source.localReference !== void 0) {
|
|
2248
|
+
if (!options.runCf || !options.verifyUploader()) throw new Error("The verified Cloudflare Container image uploader is unavailable.");
|
|
2249
|
+
const pushed = await options.runCf([
|
|
2250
|
+
"containers",
|
|
2251
|
+
"push",
|
|
2252
|
+
"--tag",
|
|
2253
|
+
reference
|
|
2254
|
+
], {
|
|
2255
|
+
cwd: options.directory,
|
|
2256
|
+
capture: true,
|
|
2257
|
+
timeoutMs: remaining(),
|
|
2258
|
+
maxOutputBytes: 16777216
|
|
2259
|
+
});
|
|
2260
|
+
if (pushed.status !== 0 || pushed.signal || pushed.error) throw new Error("Cloudflare Container image push failed.");
|
|
2261
|
+
const matches = [...pushed.stdout.matchAll(/Pushed image:\s*(\S+)/g)];
|
|
2262
|
+
const remote = matches.length === 1 ? matches[0][1] : "";
|
|
2263
|
+
if (!remote.startsWith(`registry.cloudflare.com/${options.accountId}/`) || [...remote].some((character) => character.charCodeAt(0) <= 32 || character.charCodeAt(0) === 127)) throw new Error("Cloudflare Container image push did not return the verified account registry.");
|
|
2264
|
+
image = await dockerImageDigest(remote, Math.min(12e4, remaining()), options.verifyUploader);
|
|
2265
|
+
}
|
|
2266
|
+
for (;;) {
|
|
2267
|
+
const ready = await apiResult(`${options.accountUrl}/containers/image-preparations`, options.token, "POST", { image }, options.verifyUploader, Math.min(12e4, remaining()));
|
|
2268
|
+
if (ready.image !== image) throw new Error("Cloudflare Container image preparation returned another image.");
|
|
2269
|
+
if (ready.status === "ready") break;
|
|
2270
|
+
if (ready.status !== "pending") throw new Error("Cloudflare Container image preparation failed or returned an unsupported state.");
|
|
2271
|
+
await setTimeout$1(Math.min(2e3, remaining()));
|
|
2272
|
+
}
|
|
2273
|
+
prepared.set(reference, image);
|
|
2274
|
+
}
|
|
2275
|
+
images[name] = image;
|
|
2276
|
+
}
|
|
2277
|
+
result.push({
|
|
2278
|
+
name: plan.name,
|
|
2279
|
+
class_name: plan.className,
|
|
2280
|
+
...Object.keys(images).length ? { images } : {}
|
|
2281
|
+
});
|
|
2282
|
+
}
|
|
2283
|
+
return result;
|
|
2284
|
+
}
|
|
2285
|
+
async function ensureContainerApplications(options) {
|
|
2286
|
+
if (options.plans.length === 0) return;
|
|
2287
|
+
const deadline = Date.now() + 6e4;
|
|
2288
|
+
let version;
|
|
2289
|
+
for (;;) try {
|
|
2290
|
+
version = await apiResult(`${options.accountUrl}/workers/scripts/${encodeURIComponent(options.workerName)}/versions/${encodeURIComponent(options.versionId)}`, options.token, "GET", void 0, options.verifyUploader, Math.max(1, Math.min(3e4, deadline - Date.now())));
|
|
2291
|
+
break;
|
|
2292
|
+
} catch (cause) {
|
|
2293
|
+
if (!(cause instanceof CloudflareApiError) || cause.code !== 100146 || Date.now() >= deadline) throw cause;
|
|
2294
|
+
await setTimeout$1(Math.min(2e3, deadline - Date.now()));
|
|
2295
|
+
}
|
|
2296
|
+
const versionBindings = object(version.resources)?.bindings;
|
|
2297
|
+
if (version.id !== options.versionId || !Array.isArray(versionBindings)) throw new Error("The uploaded Container namespace could not be verified.");
|
|
2298
|
+
const metadata = object(object(version.resources)?.script_runtime)?.containers;
|
|
2299
|
+
if (!Array.isArray(metadata) || metadata.length !== options.containers.length || options.containers.some((expected) => {
|
|
2300
|
+
const matching = metadata.map(object).filter((entry) => entry !== null && entry.name === expected.name && entry.class_name === expected.class_name);
|
|
2301
|
+
return matching.length !== 1 || !isDeepStrictEqual(matching[0].images ?? {}, expected.images ?? {});
|
|
2302
|
+
})) throw new Error("The uploaded Worker version did not retain the verified Container image metadata.");
|
|
2303
|
+
for (const plan of options.plans) {
|
|
2304
|
+
const matches = versionBindings.map(object).filter((binding) => binding?.type === "durable_object_namespace" && binding.class_name === plan.className && (binding.script_name === void 0 || binding.script_name === options.workerName) && binding.environment === void 0 && binding.dispatch_namespace === void 0);
|
|
2305
|
+
const namespaces = new Set(matches.map((binding) => binding.namespace_id));
|
|
2306
|
+
if (matches.length === 0 || namespaces.size !== 1) throw new Error(`Cloudflare Container ${plan.name} has no unambiguous uploaded local namespace.`);
|
|
2307
|
+
const namespace = requiredString([...namespaces][0], `Container ${plan.name} namespace`);
|
|
2308
|
+
if (!/^[a-f0-9]{32}$/.test(namespace)) throw new Error("The uploaded Container namespace ID was invalid.");
|
|
2309
|
+
const url = `${options.accountUrl}/containers/applications/${encodeURIComponent(namespace)}`;
|
|
2310
|
+
let application;
|
|
2311
|
+
try {
|
|
2312
|
+
application = await apiResult(url, options.token, "GET", void 0, options.verifyUploader);
|
|
2313
|
+
} catch (cause) {
|
|
2314
|
+
if (!(cause instanceof CloudflareApiError) || cause.status !== 404) throw cause;
|
|
2315
|
+
application = await apiResult(`${options.accountUrl}/containers/applications`, options.token, "POST", {
|
|
2316
|
+
name: plan.name,
|
|
2317
|
+
scheduling_policy: "durable_object",
|
|
2318
|
+
durable_objects: { namespace_id: namespace },
|
|
2319
|
+
...plan.settings
|
|
2320
|
+
}, options.verifyUploader);
|
|
2321
|
+
}
|
|
2322
|
+
assertContainerApplicationIdentity(application, plan, namespace);
|
|
2323
|
+
assertContainerApplicationSettings(application, plan);
|
|
2324
|
+
const confirmed = await apiResult(url, options.token, "GET", void 0, options.verifyUploader);
|
|
2325
|
+
assertContainerApplicationIdentity(confirmed, plan, namespace);
|
|
2326
|
+
assertContainerApplicationSettings(confirmed, plan);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2035
2329
|
async function uploadAssets(options) {
|
|
2036
2330
|
if (!options.output.assetsDirectory) return;
|
|
2037
2331
|
const directory = getWorkerAssetsDir(options.output.directory);
|
|
@@ -2094,7 +2388,8 @@ async function uploadAssets(options) {
|
|
|
2094
2388
|
async function uploadPinnedCloudflareVersion(options) {
|
|
2095
2389
|
const activeSecrets = options.output.activeSecrets;
|
|
2096
2390
|
if (!activeSecrets) throw new Error("The active Worker secret source was not verified.");
|
|
2097
|
-
const
|
|
2391
|
+
const built = await readBuildOutput(options.output.directory);
|
|
2392
|
+
const config = built.workers.default.config;
|
|
2098
2393
|
if (config.name !== options.workerName || !config.manifest || config.manifest.type !== "complete") throw new Error("The verified Cloudflare Worker output changed before upload.");
|
|
2099
2394
|
const unsupported = Object.keys(config).filter((key) => !(/* @__PURE__ */ new Set([
|
|
2100
2395
|
"name",
|
|
@@ -2118,6 +2413,8 @@ async function uploadPinnedCloudflareVersion(options) {
|
|
|
2118
2413
|
const explicitSecrets = options.secretsFilePath ? object(JSON.parse(readFileSync(options.secretsFilePath, "utf8"))) : {};
|
|
2119
2414
|
if (!explicitSecrets) throw new Error("The explicit Cloudflare secrets file was not readable.");
|
|
2120
2415
|
const bindings = bindingsFromOutput(config.env ?? {}, options.workerName, activeSecrets, explicitSecrets);
|
|
2416
|
+
const exports = exportsFromOutput(config.exports, bindings);
|
|
2417
|
+
const containerPlans = containerPlansFromOutput(built.containers, exports, bindings);
|
|
2121
2418
|
const active = await apiResult(`${options.apiBaseUrl.replace(/\/$/, "")}/accounts/${encodeURIComponent(options.accountId)}/workers/workers/${encodeURIComponent(options.workerName)}/versions/${encodeURIComponent(activeSecrets.versionId)}`, options.token, "GET", void 0, options.verifyUploader);
|
|
2122
2419
|
if (active.id !== activeSecrets.versionId || !Array.isArray(active.bindings)) throw new Error("The active Cloudflare Worker bindings could not be verified.");
|
|
2123
2420
|
const activeBindingNames = /* @__PURE__ */ new Set();
|
|
@@ -2137,7 +2434,6 @@ async function uploadPinnedCloudflareVersion(options) {
|
|
|
2137
2434
|
}
|
|
2138
2435
|
}
|
|
2139
2436
|
if (activeSecrets.bindings.some(({ name }) => !activeBindingNames.has(name))) throw new Error("The active Cloudflare Worker secrets changed before upload.");
|
|
2140
|
-
const exports = exportsFromOutput(config.exports);
|
|
2141
2437
|
const assetConfig = assetConfigFromOutput(config.assets);
|
|
2142
2438
|
if (bindings.some((binding) => binding.type === "assets") && !options.output.assetsDirectory) throw new Error("The Cloudflare Worker has an assets binding without verified assets.");
|
|
2143
2439
|
const modules = [];
|
|
@@ -2151,6 +2447,23 @@ async function uploadPinnedCloudflareVersion(options) {
|
|
|
2151
2447
|
});
|
|
2152
2448
|
}
|
|
2153
2449
|
const accountUrl = `${options.apiBaseUrl.replace(/\/$/, "")}/accounts/${encodeURIComponent(options.accountId)}`;
|
|
2450
|
+
await preflightWorkflowExports({
|
|
2451
|
+
exports,
|
|
2452
|
+
accountUrl,
|
|
2453
|
+
workerName: options.workerName,
|
|
2454
|
+
token: options.token,
|
|
2455
|
+
verifyUploader: options.verifyUploader
|
|
2456
|
+
});
|
|
2457
|
+
await preflightContainerApplications(containerPlans, active.bindings, accountUrl, options.workerName, options.token, options.verifyUploader);
|
|
2458
|
+
const containers = await prepareContainerMetadata({
|
|
2459
|
+
plans: containerPlans,
|
|
2460
|
+
directory: options.output.directory,
|
|
2461
|
+
accountUrl,
|
|
2462
|
+
accountId: options.accountId,
|
|
2463
|
+
token: options.token,
|
|
2464
|
+
verifyUploader: options.verifyUploader,
|
|
2465
|
+
runCf: options.runCf
|
|
2466
|
+
});
|
|
2154
2467
|
const jwt = await uploadAssets({
|
|
2155
2468
|
output: options.output,
|
|
2156
2469
|
accountUrl,
|
|
@@ -2165,14 +2478,30 @@ async function uploadPinnedCloudflareVersion(options) {
|
|
|
2165
2478
|
compatibility_flags: config.compatibilityFlags,
|
|
2166
2479
|
bindings,
|
|
2167
2480
|
...exports ? { exports } : {},
|
|
2481
|
+
...containers.length ? { containers } : {},
|
|
2168
2482
|
...jwt ? { assets: {
|
|
2169
2483
|
jwt,
|
|
2170
2484
|
...assetConfig ? { config: assetConfig } : {}
|
|
2171
2485
|
} } : {},
|
|
2172
2486
|
annotations: { "workers/message": options.message ?? "" }
|
|
2173
2487
|
}, options.verifyUploader);
|
|
2488
|
+
const versionId = uploaded.id;
|
|
2489
|
+
if (typeof versionId !== "string" || !/^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(versionId)) throw new Error("Cloudflare accepted the Worker upload but returned an invalid version identity. Read back the Worker deployment before retrying.");
|
|
2490
|
+
try {
|
|
2491
|
+
await ensureContainerApplications({
|
|
2492
|
+
plans: containerPlans,
|
|
2493
|
+
containers,
|
|
2494
|
+
accountUrl,
|
|
2495
|
+
workerName: options.workerName,
|
|
2496
|
+
versionId,
|
|
2497
|
+
token: options.token,
|
|
2498
|
+
verifyUploader: options.verifyUploader
|
|
2499
|
+
});
|
|
2500
|
+
} catch {
|
|
2501
|
+
throw new Error(`Cloudflare Worker version ${versionId} was uploaded${options.atomic ? " and may already be published" : ""}, but its Container applications could not be verified. Read back the Worker deployment and Container identities before retrying.`);
|
|
2502
|
+
}
|
|
2174
2503
|
return {
|
|
2175
|
-
id:
|
|
2504
|
+
id: versionId,
|
|
2176
2505
|
urls: Array.isArray(uploaded.urls) ? uploaded.urls.filter((url) => typeof url === "string") : []
|
|
2177
2506
|
};
|
|
2178
2507
|
}
|
|
@@ -2185,10 +2514,6 @@ function failed(message) {
|
|
|
2185
2514
|
stderr: message
|
|
2186
2515
|
};
|
|
2187
2516
|
}
|
|
2188
|
-
function flag(args, name) {
|
|
2189
|
-
const index = args.indexOf(name);
|
|
2190
|
-
return index < 0 ? void 0 : args[index + 1];
|
|
2191
|
-
}
|
|
2192
2517
|
function parseJson(value) {
|
|
2193
2518
|
try {
|
|
2194
2519
|
return JSON.parse(value);
|
|
@@ -2257,15 +2582,12 @@ function createCfResourceVerifier(options) {
|
|
|
2257
2582
|
const name = identifier("name");
|
|
2258
2583
|
if (!name) return failed(`Cloudflare Queue binding ${bindingName} has no name.`);
|
|
2259
2584
|
if (!options.verifyCompatibilityRunner()) return failed("The Cloudflare resource verifier changed during deployment.");
|
|
2260
|
-
const found = await Promise.resolve(options.runWrangler(
|
|
2261
|
-
"queues",
|
|
2262
|
-
"info",
|
|
2585
|
+
const found = await Promise.resolve(options.runWrangler({
|
|
2586
|
+
type: "queues.info",
|
|
2263
2587
|
name,
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
], { capture: true }));
|
|
2268
|
-
if (found.status !== 0 || found.signal || found.error || found.stdout.trim() !== `Queue Name: ${name}`) return failed(`Cloudflare Queue ${name} is unavailable; refusing automatic provisioning.`);
|
|
2588
|
+
configPath: options.configPath
|
|
2589
|
+
}, { capture: true }));
|
|
2590
|
+
if (found.status !== 0 || found.signal || found.error || !record(found.data) || found.data.name !== name) return failed(`Cloudflare Queue ${name} is unavailable; refusing automatic provisioning.`);
|
|
2269
2591
|
continue;
|
|
2270
2592
|
}
|
|
2271
2593
|
const resource = value.type === "r2" ? {
|
|
@@ -2314,7 +2636,7 @@ function createCfResourceVerifier(options) {
|
|
|
2314
2636
|
cwd: directory,
|
|
2315
2637
|
capture: true
|
|
2316
2638
|
});
|
|
2317
|
-
const body = parseJson(result.stdout);
|
|
2639
|
+
const body = result.data ?? parseJson(result.stdout);
|
|
2318
2640
|
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.`);
|
|
2319
2641
|
}
|
|
2320
2642
|
return {
|
|
@@ -2339,6 +2661,8 @@ function createCfCommand(options) {
|
|
|
2339
2661
|
if (env.HTTP_PROXY || env.HTTPS_PROXY || env.http_proxy || env.https_proxy) env.NODE_USE_ENV_PROXY = "1";
|
|
2340
2662
|
if (options.token) env.CLOUDFLARE_API_TOKEN = options.token;
|
|
2341
2663
|
return await new Promise((resolve) => {
|
|
2664
|
+
const bounded = run.timeoutMs !== void 0;
|
|
2665
|
+
const processGroup = bounded && process.platform !== "win32";
|
|
2342
2666
|
const child = spawn(process.execPath, [cf, ...args], {
|
|
2343
2667
|
cwd: run.cwd,
|
|
2344
2668
|
env,
|
|
@@ -2348,17 +2672,49 @@ function createCfCommand(options) {
|
|
|
2348
2672
|
"ignore",
|
|
2349
2673
|
"pipe",
|
|
2350
2674
|
"pipe"
|
|
2351
|
-
]
|
|
2675
|
+
],
|
|
2676
|
+
detached: processGroup
|
|
2352
2677
|
});
|
|
2353
2678
|
const stdout = [];
|
|
2354
2679
|
const stderr = [];
|
|
2355
2680
|
let bytes = 0;
|
|
2356
2681
|
let error = null;
|
|
2682
|
+
const stop = () => {
|
|
2683
|
+
if (processGroup && child.pid) try {
|
|
2684
|
+
process.kill(-child.pid, "SIGKILL");
|
|
2685
|
+
} catch (cause) {
|
|
2686
|
+
if (cause.code !== "ESRCH") child.kill("SIGKILL");
|
|
2687
|
+
}
|
|
2688
|
+
else if (bounded && process.platform === "win32" && child.pid) execFile("taskkill", [
|
|
2689
|
+
"/PID",
|
|
2690
|
+
String(child.pid),
|
|
2691
|
+
"/T",
|
|
2692
|
+
"/F"
|
|
2693
|
+
], {
|
|
2694
|
+
windowsHide: true,
|
|
2695
|
+
timeout: 1e4
|
|
2696
|
+
}, (cause) => {
|
|
2697
|
+
if (cause) child.kill("SIGKILL");
|
|
2698
|
+
});
|
|
2699
|
+
else child.kill("SIGKILL");
|
|
2700
|
+
};
|
|
2701
|
+
const interrupted = () => {
|
|
2702
|
+
error = "Cloudflare command interrupted.";
|
|
2703
|
+
stop();
|
|
2704
|
+
};
|
|
2705
|
+
if (bounded) {
|
|
2706
|
+
process.on("SIGINT", interrupted);
|
|
2707
|
+
process.on("SIGTERM", interrupted);
|
|
2708
|
+
}
|
|
2709
|
+
const timer = run.timeoutMs === void 0 ? void 0 : setTimeout(() => {
|
|
2710
|
+
error = "Cloudflare command timed out.";
|
|
2711
|
+
stop();
|
|
2712
|
+
}, run.timeoutMs);
|
|
2357
2713
|
const collect = (chunks, chunk) => {
|
|
2358
2714
|
bytes += chunk.length;
|
|
2359
|
-
if (bytes > 268435456) {
|
|
2360
|
-
error = "Cloudflare command output exceeded
|
|
2361
|
-
|
|
2715
|
+
if (bytes > (run.maxOutputBytes ?? 268435456)) {
|
|
2716
|
+
error = "Cloudflare command output exceeded its verified limit.";
|
|
2717
|
+
stop();
|
|
2362
2718
|
} else chunks.push(chunk);
|
|
2363
2719
|
};
|
|
2364
2720
|
child.stdout.on("data", (chunk) => collect(stdout, chunk));
|
|
@@ -2367,10 +2723,23 @@ function createCfCommand(options) {
|
|
|
2367
2723
|
error = cause.message;
|
|
2368
2724
|
});
|
|
2369
2725
|
child.on("close", (status, signal) => {
|
|
2726
|
+
clearTimeout(timer);
|
|
2727
|
+
if (bounded) {
|
|
2728
|
+
process.off("SIGINT", interrupted);
|
|
2729
|
+
process.off("SIGTERM", interrupted);
|
|
2730
|
+
}
|
|
2731
|
+
const output = Buffer.concat(stdout).toString("utf8");
|
|
2732
|
+
const diagnostic = Buffer.concat(stderr).toString("utf8");
|
|
2733
|
+
const completed = typeof status === "number" && signal == null && error == null;
|
|
2734
|
+
const code = completed ? (output + "\n" + diagnostic).match(/\[(?:code:\s*)?(\d{4,})\]/)?.[1] : void 0;
|
|
2735
|
+
const missingUploadTarget = completed && status !== 0 && code === void 0 && args[0] === "workers" && args[1] === "versions" && args[2] === "create" && (output + "\n" + diagnostic).replace(/\s+/g, " ").includes("You cannot upload a new version of a Worker that does not yet exist.");
|
|
2370
2736
|
resolve({
|
|
2371
2737
|
status: typeof status === "number" ? status : 1,
|
|
2372
|
-
stdout:
|
|
2373
|
-
stderr:
|
|
2738
|
+
stdout: output,
|
|
2739
|
+
stderr: diagnostic,
|
|
2740
|
+
...code ? { errorCode: Number(code) } : {},
|
|
2741
|
+
...missingUploadTarget ? { failure: "not-found" } : {},
|
|
2742
|
+
...completed && status !== 0 ? { errors: [{ message: output + "\n" + diagnostic }] } : {},
|
|
2374
2743
|
signal,
|
|
2375
2744
|
error
|
|
2376
2745
|
});
|
|
@@ -2384,10 +2753,31 @@ function createCfCommand(options) {
|
|
|
2384
2753
|
*/
|
|
2385
2754
|
function createCfVersionRunner(options) {
|
|
2386
2755
|
const { output, workerName, runCf } = options;
|
|
2387
|
-
const run = async (args, capture, cwd = output.directory) =>
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2756
|
+
const run = async (args, capture, cwd = output.directory) => {
|
|
2757
|
+
const result = await runCf(args, {
|
|
2758
|
+
cwd,
|
|
2759
|
+
capture
|
|
2760
|
+
});
|
|
2761
|
+
return {
|
|
2762
|
+
...result,
|
|
2763
|
+
data: result.data ?? parseJson(result.stdout)
|
|
2764
|
+
};
|
|
2765
|
+
};
|
|
2766
|
+
const uploadedResult = (result) => {
|
|
2767
|
+
if (result.status !== 0 || result.signal || result.error) return result;
|
|
2768
|
+
if (record(result.data) && typeof result.data.versionId === "string") return result;
|
|
2769
|
+
const versionId = result.stdout.match(/(?:Worker|Current) Version ID:\s*([0-9a-f]{8}-[0-9a-f-]{27})/i)?.[1];
|
|
2770
|
+
const previewUrl = result.stdout.match(/Version Preview(?: Alias)? URL:\s*(https:\/\/\S+)/i)?.[1];
|
|
2771
|
+
const workersDevUrl = result.stdout.match(/(https:\/\/[a-z0-9.-]+\.workers\.dev(?:\/[^\s]*)?)/i)?.[1];
|
|
2772
|
+
return {
|
|
2773
|
+
...result,
|
|
2774
|
+
data: versionId ? {
|
|
2775
|
+
versionId,
|
|
2776
|
+
...previewUrl ? { previewUrl } : {},
|
|
2777
|
+
...workersDevUrl ? { workersDevUrl } : {}
|
|
2778
|
+
} : void 0
|
|
2779
|
+
};
|
|
2780
|
+
};
|
|
2391
2781
|
const verifyResources = async (directory) => {
|
|
2392
2782
|
try {
|
|
2393
2783
|
return await options.verifyResources(directory);
|
|
@@ -2395,7 +2785,7 @@ function createCfVersionRunner(options) {
|
|
|
2395
2785
|
return failed("Cloudflare resources could not be verified before upload.");
|
|
2396
2786
|
}
|
|
2397
2787
|
};
|
|
2398
|
-
const uploadPinnedVersion = async (
|
|
2788
|
+
const uploadPinnedVersion = async (operation, atomic) => {
|
|
2399
2789
|
if (!options.pinnedUpload || !options.pinnedUpload.verifyUploader()) return failed("The version-aware Cloudflare uploader is unavailable.");
|
|
2400
2790
|
const token = await options.pinnedUpload.getToken();
|
|
2401
2791
|
if (!token) return failed("Cloudflare session has no bearer for version-aware upload.");
|
|
@@ -2406,23 +2796,28 @@ function createCfVersionRunner(options) {
|
|
|
2406
2796
|
apiBaseUrl: options.pinnedUpload.apiBaseUrl,
|
|
2407
2797
|
workerName,
|
|
2408
2798
|
token,
|
|
2409
|
-
...
|
|
2410
|
-
...
|
|
2799
|
+
...operation.message ? { message: operation.message } : {},
|
|
2800
|
+
...operation.secretsFilePath ? { secretsFilePath: operation.secretsFilePath } : {},
|
|
2411
2801
|
atomic,
|
|
2412
|
-
verifyUploader: options.pinnedUpload.verifyUploader
|
|
2802
|
+
verifyUploader: options.pinnedUpload.verifyUploader,
|
|
2803
|
+
runCf
|
|
2413
2804
|
});
|
|
2414
2805
|
const preview = version.urls.find((url) => /^https:\/\//.test(url));
|
|
2415
2806
|
return {
|
|
2416
2807
|
status: 0,
|
|
2417
|
-
stdout:
|
|
2808
|
+
stdout: "",
|
|
2809
|
+
data: {
|
|
2810
|
+
versionId: version.id,
|
|
2811
|
+
...preview ? { previewUrl: preview } : {}
|
|
2812
|
+
},
|
|
2418
2813
|
stderr: ""
|
|
2419
2814
|
};
|
|
2420
2815
|
} catch (cause) {
|
|
2421
2816
|
return failed(cause instanceof Error ? cause.message : "Cloudflare version upload failed.");
|
|
2422
2817
|
}
|
|
2423
2818
|
};
|
|
2424
|
-
return async (
|
|
2425
|
-
if (
|
|
2819
|
+
return async (operation, command) => {
|
|
2820
|
+
if (operation.type === "deployments.status") {
|
|
2426
2821
|
const result = await run([
|
|
2427
2822
|
"workers",
|
|
2428
2823
|
"deployments",
|
|
@@ -2430,17 +2825,20 @@ function createCfVersionRunner(options) {
|
|
|
2430
2825
|
"--worker",
|
|
2431
2826
|
workerName
|
|
2432
2827
|
], true);
|
|
2433
|
-
if (result.status !== 0) return result;
|
|
2434
|
-
const body =
|
|
2828
|
+
if (result.status !== 0 || result.signal || result.error) return result;
|
|
2829
|
+
const body = result.data;
|
|
2435
2830
|
const deployments = record(body) ? body.deployments : void 0;
|
|
2436
|
-
if (Array.isArray(deployments) && deployments.length === 0) return
|
|
2831
|
+
if (Array.isArray(deployments) && deployments.length === 0) return {
|
|
2832
|
+
...failed("The Cloudflare Worker has no deployments."),
|
|
2833
|
+
errorCode: 10007
|
|
2834
|
+
};
|
|
2437
2835
|
if (!Array.isArray(deployments) || !record(deployments[0])) return failed("The Cloudflare Worker deployment was not readable.");
|
|
2438
2836
|
return {
|
|
2439
2837
|
...result,
|
|
2440
|
-
|
|
2838
|
+
data: deployments[0]
|
|
2441
2839
|
};
|
|
2442
2840
|
}
|
|
2443
|
-
if (
|
|
2841
|
+
if (operation.type === "versions.list") {
|
|
2444
2842
|
const pageSize = 10;
|
|
2445
2843
|
const readPage = async (page) => {
|
|
2446
2844
|
const result = await run([
|
|
@@ -2454,19 +2852,20 @@ function createCfVersionRunner(options) {
|
|
|
2454
2852
|
"--page",
|
|
2455
2853
|
String(page)
|
|
2456
2854
|
], true);
|
|
2457
|
-
const body =
|
|
2855
|
+
const body = result.data;
|
|
2458
2856
|
return {
|
|
2459
2857
|
result,
|
|
2460
2858
|
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
|
|
2461
2859
|
};
|
|
2462
2860
|
};
|
|
2463
2861
|
const first = await readPage(1);
|
|
2464
|
-
if (first.result.status !== 0) return first.result;
|
|
2862
|
+
if (first.result.status !== 0 || first.result.signal || first.result.error) return first.result;
|
|
2465
2863
|
if (!first.versions) return failed("The Cloudflare Worker version list was not readable.");
|
|
2466
2864
|
const versions = [...first.versions];
|
|
2467
2865
|
if (versions.length === pageSize) {
|
|
2468
2866
|
const second = await readPage(2);
|
|
2469
|
-
if (second.result.status !== 0 ||
|
|
2867
|
+
if (second.result.status !== 0 || second.result.signal || second.result.error) return second.result;
|
|
2868
|
+
if (!second.versions) return failed("The Cloudflare Worker version history was not readable.");
|
|
2470
2869
|
if (second.versions.length > 0) {
|
|
2471
2870
|
const firstNumbers = versions.map((item) => item.number);
|
|
2472
2871
|
const secondNumbers = second.versions.map((item) => item.number);
|
|
@@ -2475,7 +2874,8 @@ function createCfVersionRunner(options) {
|
|
|
2475
2874
|
let last = Math.max(...secondNumbers);
|
|
2476
2875
|
for (let page = 3; page <= 1e3 && second.versions.length === pageSize; page++) {
|
|
2477
2876
|
const next = await readPage(page);
|
|
2478
|
-
if (next.result.status !== 0 ||
|
|
2877
|
+
if (next.result.status !== 0 || next.result.signal || next.result.error) return next.result;
|
|
2878
|
+
if (!next.versions) return failed("The Cloudflare Worker version history was not readable.");
|
|
2479
2879
|
if (next.versions.length === 0) break;
|
|
2480
2880
|
const numbers = next.versions.map((item) => item.number);
|
|
2481
2881
|
if (Math.min(...numbers) <= last) return failed("The Cloudflare Worker version history changed during inspection.");
|
|
@@ -2489,56 +2889,62 @@ function createCfVersionRunner(options) {
|
|
|
2489
2889
|
}
|
|
2490
2890
|
return {
|
|
2491
2891
|
...first.result,
|
|
2492
|
-
|
|
2892
|
+
data: versions.sort((a, b) => a.number - b.number).slice(-10)
|
|
2493
2893
|
};
|
|
2494
2894
|
}
|
|
2495
|
-
if (
|
|
2496
|
-
const
|
|
2895
|
+
if (operation.type === "versions.view") {
|
|
2896
|
+
const args = [
|
|
2497
2897
|
"workers",
|
|
2498
2898
|
"versions",
|
|
2499
2899
|
"get",
|
|
2500
|
-
|
|
2900
|
+
operation.versionId,
|
|
2501
2901
|
"--worker-id",
|
|
2502
|
-
workerName
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
const
|
|
2506
|
-
|
|
2902
|
+
workerName,
|
|
2903
|
+
...operation.includeSource ? ["--include", "modules"] : []
|
|
2904
|
+
];
|
|
2905
|
+
const called = operation.includeSource ? await runCf(args, {
|
|
2906
|
+
cwd: output.directory,
|
|
2907
|
+
capture: true,
|
|
2908
|
+
timeoutMs: 3e4,
|
|
2909
|
+
maxOutputBytes: 1048576
|
|
2910
|
+
}) : await run(args, true);
|
|
2911
|
+
const result = {
|
|
2912
|
+
...called,
|
|
2913
|
+
data: called.data ?? parseJson(called.stdout)
|
|
2914
|
+
};
|
|
2915
|
+
if (result.status !== 0 || result.signal || result.error) return result;
|
|
2916
|
+
const version = result.data;
|
|
2917
|
+
if (!record(version) || version.id !== operation.versionId || !Array.isArray(version.bindings)) return failed("The Cloudflare Worker version was not readable.");
|
|
2507
2918
|
return {
|
|
2508
2919
|
...result,
|
|
2509
|
-
|
|
2920
|
+
data: {
|
|
2510
2921
|
...version,
|
|
2511
2922
|
resources: { bindings: version.bindings }
|
|
2512
|
-
}
|
|
2923
|
+
}
|
|
2513
2924
|
};
|
|
2514
2925
|
}
|
|
2515
|
-
if (
|
|
2516
|
-
if (
|
|
2926
|
+
if (operation.type === "versions.upload") {
|
|
2927
|
+
if (operation.workerName !== workerName || operation.assetsDirectory !== void 0 && operation.assetsDirectory !== output.assetsDirectory) return failed("The Cloudflare version upload target changed.");
|
|
2517
2928
|
const verified = await verifyResources(output.directory);
|
|
2518
2929
|
if (verified.status !== 0 || verified.signal || verified.error) return verified;
|
|
2519
|
-
if (output.activeSecrets) return uploadPinnedVersion(
|
|
2520
|
-
return run([
|
|
2930
|
+
if (output.activeSecrets) return uploadPinnedVersion(operation, false);
|
|
2931
|
+
return uploadedResult(await run([
|
|
2521
2932
|
"workers",
|
|
2522
2933
|
"versions",
|
|
2523
2934
|
"create",
|
|
2524
2935
|
"--prebuilt",
|
|
2525
|
-
...
|
|
2526
|
-
...
|
|
2527
|
-
...
|
|
2528
|
-
], command.capture);
|
|
2529
|
-
}
|
|
2530
|
-
if (
|
|
2531
|
-
if (
|
|
2532
|
-
const
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
return {
|
|
2538
|
-
version_id,
|
|
2539
|
-
percentage: Number(percentage)
|
|
2540
|
-
};
|
|
2541
|
-
});
|
|
2936
|
+
...operation.message ? ["--message", operation.message] : [],
|
|
2937
|
+
...operation.secretsFilePath ? ["--secrets-file", operation.secretsFilePath] : [],
|
|
2938
|
+
...operation.previewAlias ? ["--preview-alias", operation.previewAlias] : []
|
|
2939
|
+
], command.capture));
|
|
2940
|
+
}
|
|
2941
|
+
if (operation.type === "versions.deploy") {
|
|
2942
|
+
if (operation.workerName !== workerName) return failed("The Cloudflare deployment target changed.");
|
|
2943
|
+
const parsed = operation.versions.map(({ versionId, percentage }) => ({
|
|
2944
|
+
version_id: versionId,
|
|
2945
|
+
percentage
|
|
2946
|
+
}));
|
|
2947
|
+
if (!parsed.every((version) => /^[0-9a-f-]{36}$/i.test(version.version_id) && Number.isFinite(version.percentage))) return failed("The Cloudflare deployment versions were invalid.");
|
|
2542
2948
|
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.");
|
|
2543
2949
|
return run([
|
|
2544
2950
|
"workers",
|
|
@@ -2550,28 +2956,28 @@ function createCfVersionRunner(options) {
|
|
|
2550
2956
|
"percentage",
|
|
2551
2957
|
"--versions",
|
|
2552
2958
|
JSON.stringify(parsed),
|
|
2553
|
-
...
|
|
2959
|
+
...operation.message ? ["--body", JSON.stringify({
|
|
2554
2960
|
strategy: "percentage",
|
|
2555
2961
|
versions: parsed,
|
|
2556
|
-
annotations: { "workers/message":
|
|
2962
|
+
annotations: { "workers/message": operation.message }
|
|
2557
2963
|
})] : []
|
|
2558
2964
|
], command.capture);
|
|
2559
2965
|
}
|
|
2560
|
-
if (
|
|
2561
|
-
if (
|
|
2966
|
+
if (operation.type === "worker.deploy") {
|
|
2967
|
+
if (operation.workerName !== workerName || operation.assetsDirectory !== void 0 && operation.assetsDirectory !== output.assetsDirectory) return failed("The Cloudflare bootstrap target changed.");
|
|
2562
2968
|
const verified = await verifyResources(output.directory);
|
|
2563
2969
|
if (verified.status !== 0 || verified.signal || verified.error) return verified;
|
|
2564
|
-
if (output.activeSecrets) return uploadPinnedVersion(
|
|
2565
|
-
return run([
|
|
2970
|
+
if (output.activeSecrets) return uploadPinnedVersion(operation, true);
|
|
2971
|
+
return uploadedResult(await run([
|
|
2566
2972
|
"deploy",
|
|
2567
2973
|
"--prebuilt",
|
|
2568
|
-
...
|
|
2569
|
-
...
|
|
2570
|
-
], command.capture);
|
|
2974
|
+
...operation.message ? ["--message", operation.message] : [],
|
|
2975
|
+
...operation.secretsFilePath ? ["--secrets-file", operation.secretsFilePath] : []
|
|
2976
|
+
], command.capture));
|
|
2571
2977
|
}
|
|
2572
|
-
if (
|
|
2573
|
-
const configPath =
|
|
2574
|
-
if (!configPath ||
|
|
2978
|
+
if (operation.type === "triggers.deploy") {
|
|
2979
|
+
const configPath = operation.configPath;
|
|
2980
|
+
if (!configPath || operation.workerName !== workerName) return failed("The Cloudflare trigger target changed.");
|
|
2575
2981
|
const raw = parseJson(readFileSync(configPath, "utf8"));
|
|
2576
2982
|
if (!record(raw) || raw.name !== workerName) return failed("The Cloudflare trigger snapshot was not readable.");
|
|
2577
2983
|
const directory = mkdtempSync(join(tmpdir(), "void-cf-triggers-"));
|
|
@@ -2621,12 +3027,12 @@ function createCfVersionRunner(options) {
|
|
|
2621
3027
|
});
|
|
2622
3028
|
}
|
|
2623
3029
|
}
|
|
2624
|
-
if (
|
|
2625
|
-
const queueName =
|
|
2626
|
-
if (!queueName ||
|
|
3030
|
+
if (operation.type === "queues.consumer.remove") {
|
|
3031
|
+
const queueName = operation.queueName;
|
|
3032
|
+
if (!queueName || operation.workerName !== workerName) return failed("The Cloudflare Queue consumer target changed.");
|
|
2627
3033
|
const queues = await run(["queues", "list"], true);
|
|
2628
|
-
if (queues.status !== 0) return queues;
|
|
2629
|
-
const allQueues =
|
|
3034
|
+
if (queues.status !== 0 || queues.signal || queues.error) return queues;
|
|
3035
|
+
const allQueues = queues.data;
|
|
2630
3036
|
if (!Array.isArray(allQueues)) return failed("The Cloudflare Queue list was not readable.");
|
|
2631
3037
|
const queue = allQueues.find((item) => record(item) && item.queue_name === queueName);
|
|
2632
3038
|
if (!record(queue) || typeof queue.queue_id !== "string") return failed(`Cloudflare Queue ${queueName} was not found.`);
|
|
@@ -2637,16 +3043,22 @@ function createCfVersionRunner(options) {
|
|
|
2637
3043
|
"--queue-id",
|
|
2638
3044
|
queue.queue_id
|
|
2639
3045
|
], true);
|
|
2640
|
-
if (consumers.status !== 0) return consumers;
|
|
2641
|
-
const allConsumers =
|
|
3046
|
+
if (consumers.status !== 0 || consumers.signal || consumers.error) return consumers;
|
|
3047
|
+
const allConsumers = consumers.data;
|
|
2642
3048
|
if (!Array.isArray(allConsumers)) return failed("The Cloudflare Queue consumers were not readable.");
|
|
2643
|
-
const matching =
|
|
3049
|
+
const matching = [];
|
|
3050
|
+
for (const item of allConsumers) {
|
|
3051
|
+
if (!record(item)) return failed("The Cloudflare Queue consumers were not readable.");
|
|
3052
|
+
const name = item.script_name ?? item.script;
|
|
3053
|
+
if (item.script_name !== void 0 && !safePositional(item.script_name) || item.script !== void 0 && !safePositional(item.script) || item.script_name !== void 0 && item.script !== void 0 && item.script_name !== item.script || item.type === "worker" && name === void 0) return failed("The Cloudflare Queue consumer Worker identity was ambiguous.");
|
|
3054
|
+
if (name === workerName) matching.push(item);
|
|
3055
|
+
}
|
|
2644
3056
|
if (matching.length === 0) return {
|
|
2645
3057
|
status: 0,
|
|
2646
3058
|
stdout: "",
|
|
2647
3059
|
stderr: ""
|
|
2648
3060
|
};
|
|
2649
|
-
if (matching.length !== 1 || !
|
|
3061
|
+
if (matching.length !== 1 || !safePositional(matching[0].consumer_id) || matching[0].type !== void 0 && matching[0].type !== "worker") return failed("The Cloudflare Queue consumer identity was ambiguous.");
|
|
2650
3062
|
return run([
|
|
2651
3063
|
"queues",
|
|
2652
3064
|
"consumers",
|
|
@@ -2657,7 +3069,7 @@ function createCfVersionRunner(options) {
|
|
|
2657
3069
|
"--force"
|
|
2658
3070
|
], command.capture);
|
|
2659
3071
|
}
|
|
2660
|
-
return failed(`Unsupported Cloudflare activation operation: ${
|
|
3072
|
+
return failed(`Unsupported Cloudflare activation operation: ${operation.type}`);
|
|
2661
3073
|
};
|
|
2662
3074
|
}
|
|
2663
3075
|
//#endregion
|
|
@@ -2708,13 +3120,13 @@ function clearCloudflareCandidate(root) {
|
|
|
2708
3120
|
* Narrow native Cloudflare deploys to app shapes whose emitted Worker artifact
|
|
2709
3121
|
* the current verifier understands. This runs before any account operation.
|
|
2710
3122
|
*/
|
|
2711
|
-
function classifyCloudflareDeployApp(root, voidConfig, options) {
|
|
3123
|
+
function classifyCloudflareDeployApp(root, voidConfig, options, application) {
|
|
2712
3124
|
if (isNodeTarget(voidConfig.target)) return unsupported([
|
|
2713
3125
|
`deploy: --platform cloudflare is not supported for the "${voidConfig.target}" target.`,
|
|
2714
3126
|
"This backend deploys Cloudflare Workers only. Deploy a node/bun/deno build with its",
|
|
2715
3127
|
"own host/runtime, or use the default Cloudflare target for --platform cloudflare."
|
|
2716
3128
|
].join("\n"));
|
|
2717
|
-
const framework = detectFramework(root);
|
|
3129
|
+
const framework = application?.framework ?? detectFramework(root);
|
|
2718
3130
|
if (framework) {
|
|
2719
3131
|
if (!FRAMEWORK_PRESETS[framework.name]) return unsupported(`deploy: --platform cloudflare has no deployment preset for framework ${framework.name}.`);
|
|
2720
3132
|
}
|
|
@@ -2733,13 +3145,16 @@ function classifyCloudflareDeployApp(root, voidConfig, options) {
|
|
|
2733
3145
|
"A full Void app has at least one of: routes/, pages/, middleware, crons/, queues/,",
|
|
2734
3146
|
"email/, or an SSR entry. Add your server code, or use `void deploy` for a static site."
|
|
2735
3147
|
].join("\n"));
|
|
2736
|
-
const paths = resolveProjectPaths(root, voidConfig);
|
|
2737
3148
|
try {
|
|
3149
|
+
const analysis = application ?? analyzeApplicationSync(root, {
|
|
3150
|
+
config: voidConfig,
|
|
3151
|
+
environment: "prod"
|
|
3152
|
+
});
|
|
3153
|
+
const paths = analysis.paths;
|
|
2738
3154
|
assertNoRootSourceConventionConflicts(paths);
|
|
2739
3155
|
validateSsrEntry(root, paths);
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
syncWranglerWebSockets(root, scanWebSocketRoutesSync(root, paths, "prod"));
|
|
3156
|
+
syncWranglerDurableObjects(root, analysis.durableObjects);
|
|
3157
|
+
syncWranglerWebSockets(root, analysis.websockets);
|
|
2743
3158
|
} catch (error) {
|
|
2744
3159
|
return unsupported(`deploy: ${getErrorMessage$1(error)}`);
|
|
2745
3160
|
}
|
|
@@ -2886,7 +3301,7 @@ async function prepareExistingCloudflareDeploy(options) {
|
|
|
2886
3301
|
}
|
|
2887
3302
|
/** Offer the existing destination before the legacy hosted-platform fallback. */
|
|
2888
3303
|
async function maybeLinkCloudflareDeploy(root, options = {}, deps = {}) {
|
|
2889
|
-
if (options.platform || options.
|
|
3304
|
+
if (options.platform || options.projectSlug || process.env.VOID_PROJECT || readDeploymentPlatform(root) !== null) return null;
|
|
2890
3305
|
const files = [.../* @__PURE__ */ new Set([...[
|
|
2891
3306
|
"wrangler.jsonc",
|
|
2892
3307
|
"wrangler.json",
|
|
@@ -3511,9 +3926,6 @@ function openDeployLog(opts) {
|
|
|
3511
3926
|
}
|
|
3512
3927
|
};
|
|
3513
3928
|
}
|
|
3514
|
-
//#endregion
|
|
3515
|
-
//#region src/cli/log-summary.ts
|
|
3516
|
-
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
3517
3929
|
const FIELD_VALUE_MAX = 80;
|
|
3518
3930
|
const LINE_MAX = 160;
|
|
3519
3931
|
const MSG_COLUMN_MAX = 28;
|
|
@@ -4029,8 +4441,7 @@ function buildVoidManifest(opts) {
|
|
|
4029
4441
|
};
|
|
4030
4442
|
if (opts.hasEmailHandlers) manifest.emailProtocolVersion = 1;
|
|
4031
4443
|
if (bindings.needsAuth) manifest.auth = true;
|
|
4032
|
-
|
|
4033
|
-
if (bindings.needsD1 || bindings.needsAuth || hasMigrations) {
|
|
4444
|
+
if (needsApplicationDatabase(bindings, migrations?.length ?? 0)) {
|
|
4034
4445
|
if (resolvedDialect !== "sqlite") manifest.bindings.hyperdrive = ["HYPERDRIVE"];
|
|
4035
4446
|
else manifest.bindings.d1 = [options?.bindingNames?.d1 ?? "DB"];
|
|
4036
4447
|
}
|
|
@@ -4145,8 +4556,7 @@ function buildFrameworkManifest(opts) {
|
|
|
4145
4556
|
assetManifestVersion: 2,
|
|
4146
4557
|
bindings: {}
|
|
4147
4558
|
};
|
|
4148
|
-
|
|
4149
|
-
if (opts.bindings.needsD1 || opts.bindings.needsAuth || hasMigrations) {
|
|
4559
|
+
if (needsApplicationDatabase(opts.bindings, opts.migrations?.length ?? 0)) {
|
|
4150
4560
|
if (dialect !== "sqlite") manifest.bindings.hyperdrive = ["HYPERDRIVE"];
|
|
4151
4561
|
else manifest.bindings.d1 = [po?.bindingNames?.d1 ?? "DB"];
|
|
4152
4562
|
}
|
|
@@ -4395,7 +4805,7 @@ async function generateWrapper(workerDir, workerMain, root, features) {
|
|
|
4395
4805
|
let migrationPlanBundle;
|
|
4396
4806
|
if (features.hasMigrations) {
|
|
4397
4807
|
const { collectMigrations } = await import("./collect-DLyFDiKW.mjs");
|
|
4398
|
-
const { buildMigrationPlanBundle } = await import("./plan-
|
|
4808
|
+
const { buildMigrationPlanBundle } = await import("./plan-D1Q5rf-r.mjs");
|
|
4399
4809
|
const migrationsDir = readProjectPaths(root).migrationsDir;
|
|
4400
4810
|
migrations = collectMigrations(migrationsDir);
|
|
4401
4811
|
migrationPlanBundle = features.migrationDialect === "sqlite" ? buildMigrationPlanBundle(migrations) : void 0;
|
|
@@ -4636,7 +5046,7 @@ function generateWrapperSource(renamedEntry, handlersModule, features, migration
|
|
|
4636
5046
|
}
|
|
4637
5047
|
if (features.readiness || features.crons.length > 0 || features.queues.length > 0 || features.hasMigrations) {
|
|
4638
5048
|
lines.push(" if (request.method === \"GET\" && url.pathname === \"/__void/ready\") {");
|
|
4639
|
-
lines.push(
|
|
5049
|
+
lines.push(` return Response.json({ ready: true${features.versionMetadataBinding ? `, versionId: env[${JSON.stringify(features.versionMetadataBinding)}]?.id` : ""} }${features.versionMetadataBinding ? ", { headers: { \"cache-control\": \"no-store\" } }" : ""});`);
|
|
4640
5050
|
lines.push(" }");
|
|
4641
5051
|
}
|
|
4642
5052
|
if (features.queues.length > 0) {
|
|
@@ -4806,7 +5216,7 @@ let loadedProvisionModule;
|
|
|
4806
5216
|
* so a managed deploy never imports it — and thus never loads `proper-lockfile`.
|
|
4807
5217
|
*/
|
|
4808
5218
|
async function loadProvisionModule() {
|
|
4809
|
-
loadedProvisionModule ??= await import("./provision-
|
|
5219
|
+
loadedProvisionModule ??= await import("./provision-CVku1JFU.mjs");
|
|
4810
5220
|
return loadedProvisionModule;
|
|
4811
5221
|
}
|
|
4812
5222
|
/**
|
|
@@ -4829,7 +5239,7 @@ const log = {
|
|
|
4829
5239
|
};
|
|
4830
5240
|
var DeployEventError = class extends Error {};
|
|
4831
5241
|
function resolveDeploymentPlatform(root, options) {
|
|
4832
|
-
return options?.platform ??
|
|
5242
|
+
return options?.platform ?? readDeploymentPlatform(root) ?? "void";
|
|
4833
5243
|
}
|
|
4834
5244
|
async function generateDeployWrapperIfNeeded(root, workerDir, workerMain, features) {
|
|
4835
5245
|
if (!needsWrapper(features)) return false;
|
|
@@ -4965,7 +5375,7 @@ async function runDeploy(root, options) {
|
|
|
4965
5375
|
* `VOID_DEPLOY_PROJECT_ID` is, so it cannot leak into an unrelated child process or a
|
|
4966
5376
|
* later `void dev` in the same shell.
|
|
4967
5377
|
*
|
|
4968
|
-
* Deliberately NOT set by `runCloudflareDeploy` (`--
|
|
5378
|
+
* Deliberately NOT set by `runCloudflareDeploy` (`--platform cloudflare`): that flow
|
|
4969
5379
|
* hands the built output to `wrangler deploy` against the user's own account and IS the
|
|
4970
5380
|
* self-host path the warning is about. (It rejects framework SSR outright today, so no
|
|
4971
5381
|
* Class A build reaches it either way.)
|
|
@@ -4975,6 +5385,7 @@ const MANAGED_DEPLOY_BUILD_ENV = { VOID_DEPLOY_BUILD: "1" };
|
|
|
4975
5385
|
function scrubManagedDeployBuildMarkers(env) {
|
|
4976
5386
|
const { deleteEnvVarCaseAware } = requireProvisionModule();
|
|
4977
5387
|
deleteEnvVarCaseAware(env, "VOID_DEPLOY_PROJECT_ID");
|
|
5388
|
+
deleteEnvVarCaseAware(env, CLOUDFLARE_PRESERVE_BINDINGS_BUILD_ENV);
|
|
4978
5389
|
for (const name of Object.keys(MANAGED_DEPLOY_BUILD_ENV)) deleteEnvVarCaseAware(env, name);
|
|
4979
5390
|
return env;
|
|
4980
5391
|
}
|
|
@@ -5391,14 +5802,14 @@ function reconstructExpectedDurableObjectState(config, root, rootConfig, options
|
|
|
5391
5802
|
name: sandbox.binding,
|
|
5392
5803
|
class_name: sandbox.className
|
|
5393
5804
|
});
|
|
5394
|
-
if (!migrations
|
|
5805
|
+
if (!hasSandboxSqliteMigration(migrations, sandbox.className)) migrations.push({
|
|
5395
5806
|
tag: SANDBOX_MIGRATION_TAG,
|
|
5396
5807
|
new_sqlite_classes: [sandbox.className]
|
|
5397
5808
|
});
|
|
5398
5809
|
}
|
|
5399
|
-
const
|
|
5400
|
-
const websocketRoutes =
|
|
5401
|
-
const durableObjects =
|
|
5810
|
+
const analysis = options.analysis ?? analyzeApplicationSync(root, { config });
|
|
5811
|
+
const websocketRoutes = analysis.allWebsockets;
|
|
5812
|
+
const durableObjects = analysis.durableObjects;
|
|
5402
5813
|
const live = options.needsLive ? resolveLiveBindingConfig(root, {
|
|
5403
5814
|
reservedBindings: [...websocketRoutes.map((route) => route.bindingName), ...durableObjects.map((module) => module.bindingName)],
|
|
5404
5815
|
reservedClasses: [
|
|
@@ -5428,11 +5839,11 @@ function reconstructExpectedDurableObjectState(config, root, rootConfig, options
|
|
|
5428
5839
|
* chunks from its own `__dirname` (the proxy workers, the experimental-config module), so the
|
|
5429
5840
|
* whole directory is the trust surface, not just the entry file. Content hash of the bytes, NOT
|
|
5430
5841
|
* mtime. Resolves the SAME entry {@link createDeployWranglerRunner} spawns (via
|
|
5431
|
-
* {@link
|
|
5842
|
+
* {@link resolveCloudflareOperationArgv}, whose launcher's LAST argv element is the JS entry). Returns
|
|
5432
5843
|
* `undefined` when the entry cannot be resolved or a file cannot be read, so the caller FAILS
|
|
5433
5844
|
* CLOSED — it never deploys a binary it could not verify. The resolver is injectable for tests.
|
|
5434
5845
|
*/
|
|
5435
|
-
function hashWranglerUploader(root, resolveArgv =
|
|
5846
|
+
function hashWranglerUploader(root, resolveArgv = resolveCloudflareOperationArgv) {
|
|
5436
5847
|
let entry;
|
|
5437
5848
|
try {
|
|
5438
5849
|
const argv = resolveArgv(root);
|
|
@@ -6261,42 +6672,30 @@ function assertDistinctKvNamespaces(kvNamespaces, config, configPath, isRealKvId
|
|
|
6261
6672
|
/**
|
|
6262
6673
|
* Compute the DESIRED id/name-bearing Cloudflare resources from SOURCE
|
|
6263
6674
|
* (pre-build, fail-fast) — the single set shared by the provision and drift
|
|
6264
|
-
* paths.
|
|
6265
|
-
*
|
|
6266
|
-
* signals) rather than `assembleVoidManifest`, which runs only inside the
|
|
6267
|
-
* managed `runFullDeploy` branches that need a `PlatformClient`.
|
|
6675
|
+
* paths. Consumes the same application analysis as the plugin and managed
|
|
6676
|
+
* packaging; provider identities and stored resource names are resolved here.
|
|
6268
6677
|
*
|
|
6269
6678
|
* Resource NAMES prefer the value already stored in the root wrangler config
|
|
6270
6679
|
* (so a re-provision reuses the same database/bucket and the provisioner's
|
|
6271
6680
|
* stored-name identity check passes); otherwise they default off the worker
|
|
6272
6681
|
* name. Returns a per-binding REASON map used to explain drift.
|
|
6273
6682
|
*/
|
|
6274
|
-
async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
|
|
6683
|
+
async function computeDesiredCloudflareResources(root, voidConfig, configPath, application) {
|
|
6275
6684
|
const { isRealD1Id, isRealKvId } = await loadProvisionModule();
|
|
6276
|
-
const
|
|
6685
|
+
const analysis = application ? await completeApplicationAnalysis(application) : await analyzeApplication(root, {
|
|
6686
|
+
config: voidConfig,
|
|
6687
|
+
environment: "prod"
|
|
6688
|
+
});
|
|
6689
|
+
const { paths, bindings, authEnabled, dialect, bindingNames, migrations, needsDatabase } = analysis;
|
|
6277
6690
|
const config = parseRootWranglerConfig(configPath);
|
|
6278
6691
|
const workerName = readWranglerTopLevelString(config, "name") ?? deriveWorkerName(root);
|
|
6279
|
-
const isFrameworkMode = detectFramework(root) != null;
|
|
6280
|
-
const scanDirs = voidConfig.inference?.scanDirs ?? (isFrameworkMode ? FRAMEWORK_SCAN_DIRS : void 0);
|
|
6281
|
-
const inferenceOptions = voidConfig.inference?.bindings ? { bindings: voidConfig.inference.bindings } : void 0;
|
|
6282
|
-
const bindings = inferProjectBindings(root, {
|
|
6283
|
-
...inferenceOptions,
|
|
6284
|
-
paths,
|
|
6285
|
-
environment: "prod"
|
|
6286
|
-
}, scanDirs);
|
|
6287
|
-
const authEnabled = bindings.needsAuth || findVoidAuthConfig(root, paths) !== null || voidConfig.auth !== void 0;
|
|
6288
|
-
const dialect = getDatabaseDialect(voidConfig);
|
|
6289
|
-
const bindingNames = resolveBindingNames(voidConfig.inference?.bindings);
|
|
6290
|
-
const migrations = collectMigrations(paths.migrationsDir);
|
|
6291
|
-
const hasMigrations = migrations.length > 0;
|
|
6292
6692
|
const migrationsDirRelative = paths.sourceDir ? `./${paths.sourceDir}/db/migrations` : "./db/migrations";
|
|
6293
6693
|
const desired = {
|
|
6294
6694
|
kvNamespaces: [],
|
|
6295
6695
|
queues: []
|
|
6296
6696
|
};
|
|
6297
6697
|
const reasons = /* @__PURE__ */ new Map();
|
|
6298
|
-
const
|
|
6299
|
-
const databaseReason = bindings.needsD1 ? "app uses env.DB (D1)" : authEnabled ? "auth requires a D1 database" : "checked-in migrations need a D1 database";
|
|
6698
|
+
const databaseReason = analysis.reasons.database[0];
|
|
6300
6699
|
if (needsDatabase && dialect === "sqlite") {
|
|
6301
6700
|
const binding = bindingNames?.d1 ?? "DB";
|
|
6302
6701
|
const storedName = readStoredResourceName(config, "d1_databases", binding, "database_name");
|
|
@@ -6315,7 +6714,7 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
|
|
|
6315
6714
|
binding,
|
|
6316
6715
|
title: suffixedResourceName(workerName, "kv")
|
|
6317
6716
|
});
|
|
6318
|
-
reasons.set(binding,
|
|
6717
|
+
reasons.set(binding, analysis.reasons.kv[0]);
|
|
6319
6718
|
}
|
|
6320
6719
|
if (bindings.needsR2) {
|
|
6321
6720
|
const binding = bindingNames?.r2 ?? "STORAGE";
|
|
@@ -6325,9 +6724,9 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
|
|
|
6325
6724
|
binding,
|
|
6326
6725
|
bucketName: storedName && !generatedDefault ? storedName : suffixedResourceName(workerName, "storage")
|
|
6327
6726
|
};
|
|
6328
|
-
reasons.set(binding,
|
|
6727
|
+
reasons.set(binding, analysis.reasons.r2[0]);
|
|
6329
6728
|
}
|
|
6330
|
-
desired.queues =
|
|
6729
|
+
desired.queues = analysis.queues.map((q) => q.name);
|
|
6331
6730
|
if (needsDatabase && dialect !== "sqlite") {
|
|
6332
6731
|
const binding = "HYPERDRIVE";
|
|
6333
6732
|
desired.hyperdrive = {
|
|
@@ -6337,10 +6736,8 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
|
|
|
6337
6736
|
};
|
|
6338
6737
|
reasons.set(binding, `app uses ${dialect === "mysql" ? "MySQL" : "PostgreSQL"} (needs a Hyperdrive config)`);
|
|
6339
6738
|
}
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
paths
|
|
6343
|
-
}) : null))) {
|
|
6739
|
+
const pageScan = analysis.scan.pages;
|
|
6740
|
+
if (hasRevalidate(collectRevalidate(voidConfig, pageScan))) {
|
|
6344
6741
|
const binding = "ISR_CACHE";
|
|
6345
6742
|
desired.kvNamespaces.push({
|
|
6346
6743
|
binding,
|
|
@@ -6349,9 +6746,10 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
|
|
|
6349
6746
|
reasons.set(binding, "routes use `revalidate` (ISR) — needs an ISR_CACHE KV namespace");
|
|
6350
6747
|
}
|
|
6351
6748
|
assertDistinctKvNamespaces(desired.kvNamespaces, config, configPath, isRealKvId);
|
|
6352
|
-
const expectedCrons = [...new Set(
|
|
6353
|
-
const emailHandlers =
|
|
6749
|
+
const expectedCrons = [...new Set(analysis.jobs.flatMap((job) => job.crons))];
|
|
6750
|
+
const emailHandlers = analysis.email;
|
|
6354
6751
|
return {
|
|
6752
|
+
analysis,
|
|
6355
6753
|
desired,
|
|
6356
6754
|
reasons,
|
|
6357
6755
|
authEnabled,
|
|
@@ -6363,7 +6761,7 @@ async function computeDesiredCloudflareResources(root, voidConfig, configPath) {
|
|
|
6363
6761
|
expectedCrons,
|
|
6364
6762
|
needsEmail: bindings.needsEmail === true || hasEmailHandlers(emailHandlers),
|
|
6365
6763
|
emailHandlers,
|
|
6366
|
-
needsSandbox:
|
|
6764
|
+
needsSandbox: bindings.needsSandbox,
|
|
6367
6765
|
needsLive: bindings.needsLive === true
|
|
6368
6766
|
};
|
|
6369
6767
|
}
|
|
@@ -6717,49 +7115,15 @@ async function checkWranglerMigrationApplySet(configPath, config, binding, migra
|
|
|
6717
7115
|
};
|
|
6718
7116
|
return { ok: true };
|
|
6719
7117
|
}
|
|
6720
|
-
/**
|
|
6721
|
-
* Default {@link DeployWranglerRun}: spawns the project-local wrangler REAL CLI
|
|
6722
|
-
* (via {@link resolveWranglerArgv}, shell-free) with ONE pinned transport in the
|
|
6723
|
-
* child env (via {@link deployChildEnv} — reused provisioner scrub/pin: CF Access +
|
|
6724
|
-
* every transport selector incl. `CLOUDFLARE_ENV` + the deploy config-override vars
|
|
6725
|
-
* scrubbed, one account + API base pinned), so `whoami`/`migrate`/`deploy` can never
|
|
6726
|
-
* consult a different ambient account or endpoint. Noninteractive output is captured so Void
|
|
6727
|
-
* controls the terminal; browser login still inherits stdio. `opts.env` layers one more pin
|
|
6728
|
-
* over the child env for a single spawn (`auth token` gets
|
|
6729
|
-
* `WRANGLER_WRITE_LOGS=false`, see {@link runWranglerAuthToken}).
|
|
6730
|
-
*/
|
|
7118
|
+
/** Run typed provider operations in the pinned account and API context. */
|
|
6731
7119
|
function createDeployWranglerRunner(root, accountId, apiBaseUrl) {
|
|
6732
|
-
const
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
cwd: root,
|
|
6740
|
-
stdio: interactiveLogin ? "inherit" : opts.input === void 0 ? [
|
|
6741
|
-
"ignore",
|
|
6742
|
-
"pipe",
|
|
6743
|
-
"pipe"
|
|
6744
|
-
] : [
|
|
6745
|
-
"pipe",
|
|
6746
|
-
"pipe",
|
|
6747
|
-
"pipe"
|
|
6748
|
-
],
|
|
6749
|
-
input: opts.input,
|
|
6750
|
-
encoding: "utf-8",
|
|
6751
|
-
env: childEnv,
|
|
6752
|
-
shell: false,
|
|
6753
|
-
windowsHide: true
|
|
6754
|
-
});
|
|
6755
|
-
return {
|
|
6756
|
-
status: typeof result.status === "number" ? result.status : 1,
|
|
6757
|
-
stdout: result.stdout ?? "",
|
|
6758
|
-
stderr: result.stderr ?? "",
|
|
6759
|
-
signal: result.signal ?? null,
|
|
6760
|
-
error: result.error ? result.error.message : null
|
|
6761
|
-
};
|
|
6762
|
-
};
|
|
7120
|
+
const runner = createCloudflareProcessRunner({
|
|
7121
|
+
root,
|
|
7122
|
+
accountId,
|
|
7123
|
+
apiBaseUrl,
|
|
7124
|
+
env: () => deployChildEnv(accountId, apiBaseUrl)
|
|
7125
|
+
});
|
|
7126
|
+
return (operation, opts) => runner(operation, opts);
|
|
6763
7127
|
}
|
|
6764
7128
|
/** Retry an existing-Worker read only when a fresh identity check proves the session is gone. */
|
|
6765
7129
|
async function prepareExistingCloudflareDeployWithAuth(options, beforeRun) {
|
|
@@ -6768,18 +7132,17 @@ async function prepareExistingCloudflareDeployWithAuth(options, beforeRun) {
|
|
|
6768
7132
|
} catch (error) {
|
|
6769
7133
|
if (!(error instanceof CloudflareWorkerInspectionError)) throw error;
|
|
6770
7134
|
if (!beforeRun()) throw new CloudflareAuthenticationError("The Cloudflare uploader changed during Worker verification.", "uploader-changed");
|
|
6771
|
-
const
|
|
6772
|
-
const identity = await options.runWrangler(
|
|
6773
|
-
"whoami",
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
const session = isCleanWranglerExit(identity) ? parseCloudflareAuthSession(identity.stdout) : null;
|
|
7135
|
+
const configPath = existsSync(options.configPath) ? options.configPath : void 0;
|
|
7136
|
+
const identity = await options.runWrangler({
|
|
7137
|
+
type: "auth.whoami",
|
|
7138
|
+
configPath
|
|
7139
|
+
}, { capture: true });
|
|
7140
|
+
const session = isCleanWranglerExit(identity) ? parseCloudflareAuthSession(identity.data) : null;
|
|
6778
7141
|
const wrongAccount = session !== null && session.accounts.length > 0 && !session.accounts.some((account) => account.id === options.accountId);
|
|
6779
7142
|
if (session && !wrongAccount) throw error;
|
|
6780
7143
|
let loggedOut = false;
|
|
6781
7144
|
try {
|
|
6782
|
-
loggedOut =
|
|
7145
|
+
loggedOut = identity.data?.loggedIn === false;
|
|
6783
7146
|
} catch {}
|
|
6784
7147
|
if (!(loggedOut || wrongAccount || /authentication is required|not authenticated|no api token|invalid.*token|expired.*token|unauthorized/i.test(identity.stderr)) || identity.signal || identity.error) throw new Error("Could not verify the Cloudflare session after the Worker check failed. Run `void cloudflare status` and retry.");
|
|
6785
7148
|
const overrides = cloudflareCredentialOverrides();
|
|
@@ -6790,8 +7153,8 @@ async function prepareExistingCloudflareDeployWithAuth(options, beforeRun) {
|
|
|
6790
7153
|
forceLogin: true,
|
|
6791
7154
|
requireAccounts: true,
|
|
6792
7155
|
beforeRun,
|
|
6793
|
-
runWrangler: (
|
|
6794
|
-
|
|
7156
|
+
runWrangler: (operation, capture) => options.runWrangler(operation, { capture }),
|
|
7157
|
+
configPath
|
|
6795
7158
|
})).accounts.some((account) => account.id === options.accountId)) throw new Error(`The signed-in Cloudflare user cannot access account ${options.accountId}. Sign in with a user who can access it, then retry.`);
|
|
6796
7159
|
if (!beforeRun()) throw new CloudflareAuthenticationError("The Cloudflare uploader changed during sign-in.", "uploader-changed");
|
|
6797
7160
|
return await prepareExistingCloudflareDeploy(options);
|
|
@@ -6801,8 +7164,8 @@ async function chooseCloudflareDeployAccount(options) {
|
|
|
6801
7164
|
const accounts = (await ensureCloudflareAuthentication({
|
|
6802
7165
|
beforeRun: options.beforeWranglerRun,
|
|
6803
7166
|
requireAccounts: true,
|
|
6804
|
-
runWrangler: (
|
|
6805
|
-
|
|
7167
|
+
runWrangler: (operation, capture) => options.runWrangler(operation, { capture }),
|
|
7168
|
+
configPath: existsSync(options.configPath) ? options.configPath : void 0
|
|
6806
7169
|
})).accounts;
|
|
6807
7170
|
let account = accounts[0];
|
|
6808
7171
|
if (accounts.length > 1) {
|
|
@@ -6848,14 +7211,10 @@ function isWranglerNonInteractiveOrCI() {
|
|
|
6848
7211
|
async function runWranglerAuthToken(runWrangler, configPath) {
|
|
6849
7212
|
let result;
|
|
6850
7213
|
try {
|
|
6851
|
-
result = await Promise.resolve(runWrangler(
|
|
6852
|
-
"auth",
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
"-c",
|
|
6856
|
-
configPath,
|
|
6857
|
-
"--env="
|
|
6858
|
-
], {
|
|
7214
|
+
result = await Promise.resolve(runWrangler({
|
|
7215
|
+
type: "auth.token",
|
|
7216
|
+
configPath
|
|
7217
|
+
}, {
|
|
6859
7218
|
capture: true,
|
|
6860
7219
|
env: { WRANGLER_WRITE_LOGS: "false" }
|
|
6861
7220
|
}));
|
|
@@ -6863,15 +7222,7 @@ async function runWranglerAuthToken(runWrangler, configPath) {
|
|
|
6863
7222
|
return null;
|
|
6864
7223
|
}
|
|
6865
7224
|
if (!isCleanWranglerExit(result)) return null;
|
|
6866
|
-
const
|
|
6867
|
-
const end = result.stdout.lastIndexOf("}");
|
|
6868
|
-
if (start === -1 || end <= start) return null;
|
|
6869
|
-
let parsed;
|
|
6870
|
-
try {
|
|
6871
|
-
parsed = JSON.parse(result.stdout.slice(start, end + 1));
|
|
6872
|
-
} catch {
|
|
6873
|
-
return null;
|
|
6874
|
-
}
|
|
7225
|
+
const parsed = result.data;
|
|
6875
7226
|
const type = parsed?.type;
|
|
6876
7227
|
const token = parsed?.token;
|
|
6877
7228
|
return (type === "oauth" || type === "api_token") && typeof token === "string" && token.length > 0 ? token : null;
|
|
@@ -6907,7 +7258,8 @@ async function runCloudflareEmailStep(input) {
|
|
|
6907
7258
|
};
|
|
6908
7259
|
const from = input.voidConfig.email?.from;
|
|
6909
7260
|
if (!from) {
|
|
6910
|
-
|
|
7261
|
+
if (Array.isArray(input.rootConfig.send_email) && input.rootConfig.send_email.some((binding) => binding?.name === "SEND_EMAIL") || Array.isArray(input.rootConfig.addresses) && input.rootConfig.addresses.length > 0) log.info("deploy: email.from is unset; skipping automatic email setup. Existing Cloudflare email configuration is preserved.");
|
|
7262
|
+
else 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 — automatic email setup skipped."].join("\n"));
|
|
6911
7263
|
return without;
|
|
6912
7264
|
}
|
|
6913
7265
|
const { rootConfig } = input;
|
|
@@ -6921,11 +7273,7 @@ async function runCloudflareEmailStep(input) {
|
|
|
6921
7273
|
existingAddresses: rootConfig.addresses,
|
|
6922
7274
|
existingVars: rootConfig.vars && typeof rootConfig.vars === "object" && !Array.isArray(rootConfig.vars) ? rootConfig.vars : void 0,
|
|
6923
7275
|
configConflicts: findEmailConfigConflicts(rootConfig),
|
|
6924
|
-
|
|
6925
|
-
"-c",
|
|
6926
|
-
input.configPath,
|
|
6927
|
-
"--env="
|
|
6928
|
-
],
|
|
7276
|
+
configPath: input.configPath,
|
|
6929
7277
|
apiBaseUrl: input.apiBaseUrl,
|
|
6930
7278
|
runWrangler: input.runWrangler,
|
|
6931
7279
|
getSessionBearer: () => runWranglerAuthToken(input.runWrangler, input.configPath),
|
|
@@ -7086,14 +7434,12 @@ async function ensureCloudflareAuthSecret(options) {
|
|
|
7086
7434
|
beforeRun();
|
|
7087
7435
|
let put;
|
|
7088
7436
|
try {
|
|
7089
|
-
put = await Promise.resolve(options.runWrangler(
|
|
7090
|
-
"secret",
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
"--env="
|
|
7096
|
-
], {
|
|
7437
|
+
put = await Promise.resolve(options.runWrangler({
|
|
7438
|
+
type: "secret.put",
|
|
7439
|
+
name: BETTER_AUTH_SECRET_NAME,
|
|
7440
|
+
configPath: options.configPath,
|
|
7441
|
+
workerName: options.workerName
|
|
7442
|
+
}, {
|
|
7097
7443
|
capture: true,
|
|
7098
7444
|
input: `${secret}\n`
|
|
7099
7445
|
}));
|
|
@@ -7120,13 +7466,23 @@ async function prepareCloudflareDeploySource(root, options, voidConfig) {
|
|
|
7120
7466
|
].join("\n"));
|
|
7121
7467
|
return null;
|
|
7122
7468
|
}
|
|
7123
|
-
|
|
7469
|
+
let application;
|
|
7470
|
+
try {
|
|
7471
|
+
application = analyzeApplicationSync(root, {
|
|
7472
|
+
config: voidConfig,
|
|
7473
|
+
environment: "prod"
|
|
7474
|
+
});
|
|
7475
|
+
} catch (error) {
|
|
7476
|
+
log.error(`deploy: ${getErrorMessage(error)}`);
|
|
7477
|
+
return null;
|
|
7478
|
+
}
|
|
7479
|
+
const classification = classifyCloudflareDeployApp(root, voidConfig, options, application);
|
|
7124
7480
|
if (!classification.supported) {
|
|
7125
7481
|
log.error(classification.reason);
|
|
7126
7482
|
return null;
|
|
7127
7483
|
}
|
|
7128
7484
|
const configPath = discoverRootWranglerConfig(root);
|
|
7129
|
-
const facts = await computeDesiredCloudflareResources(root, voidConfig, configPath);
|
|
7485
|
+
const facts = await computeDesiredCloudflareResources(root, voidConfig, configPath, application);
|
|
7130
7486
|
const { desired, dialect, migrations: preBuildMigrations, migrationsDir } = facts;
|
|
7131
7487
|
if (dialect !== "sqlite" && preBuildMigrations.length > 0 && !process.env.DATABASE_URL) {
|
|
7132
7488
|
log.error([
|
|
@@ -7154,51 +7510,35 @@ async function applyAndVerifyRemoteD1Migrations(d1MigrateToken, configPath, runW
|
|
|
7154
7510
|
if (d1MigrateToken) {
|
|
7155
7511
|
log.step("Applying D1 migrations...");
|
|
7156
7512
|
if (!assertUploaderStillPinned()) return false;
|
|
7157
|
-
const migrate = await Promise.resolve(runWrangler(
|
|
7158
|
-
"d1",
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
"--remote",
|
|
7163
|
-
"-c",
|
|
7164
|
-
configPath,
|
|
7165
|
-
"--env="
|
|
7166
|
-
], { capture: false }));
|
|
7513
|
+
const migrate = await Promise.resolve(runWrangler({
|
|
7514
|
+
type: "d1.migrations.apply",
|
|
7515
|
+
database: d1MigrateToken,
|
|
7516
|
+
configPath
|
|
7517
|
+
}, { capture: false }));
|
|
7167
7518
|
if (!isCleanWranglerExit(migrate)) {
|
|
7168
7519
|
log.error(`deploy: remote D1 migrations failed for "${d1MigrateToken}" (exit ${String(migrate.status)}). Fix the migration and rerun. Note: D1 always enforces foreign_keys=ON — a Drizzle table-rebuild using PRAGMA foreign_keys=OFF must use PRAGMA defer_foreign_keys instead.`);
|
|
7169
7520
|
return false;
|
|
7170
7521
|
}
|
|
7171
7522
|
if (!assertUploaderStillPinned()) return false;
|
|
7172
|
-
const migrateList = await Promise.resolve(runWrangler(
|
|
7173
|
-
"d1",
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
"--remote",
|
|
7178
|
-
"-c",
|
|
7179
|
-
configPath,
|
|
7180
|
-
"--env="
|
|
7181
|
-
], { capture: true }));
|
|
7523
|
+
const migrateList = await Promise.resolve(runWrangler({
|
|
7524
|
+
type: "d1.migrations.list",
|
|
7525
|
+
database: d1MigrateToken,
|
|
7526
|
+
configPath
|
|
7527
|
+
}, { capture: true }));
|
|
7182
7528
|
if (!isCleanWranglerExit(migrateList)) {
|
|
7183
7529
|
log.error(`deploy: could not verify the remote migration state for "${d1MigrateToken}" (\`d1 migrations list\` exit ${String(migrateList.status)}). Refusing to deploy against an unverified schema — rerun once wrangler can reach your account.`);
|
|
7184
7530
|
return false;
|
|
7185
7531
|
}
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
"`wrangler d1 migrations apply` exits 0 even when its confirmation is declined, so",
|
|
7190
|
-
"the schema may be un-migrated while the code that needs it is about to deploy.",
|
|
7191
|
-
"Re-run and confirm the migration (or apply it non-interactively), then rerun."
|
|
7192
|
-
].join("\n"));
|
|
7532
|
+
const migrationState = migrateList.data;
|
|
7533
|
+
if (Array.isArray(migrationState?.pending) && migrationState.pending.length > 0) {
|
|
7534
|
+
log.error([`deploy: remote D1 still has UNAPPLIED migrations for "${d1MigrateToken}" after apply.`, "The schema is not current for this deployment. Fix or apply the pending migrations, then retry."].join("\n"));
|
|
7193
7535
|
return false;
|
|
7194
7536
|
}
|
|
7195
|
-
if (!
|
|
7537
|
+
if (!Array.isArray(migrationState?.pending) || !migrationState.pending.every((name) => typeof name === "string")) {
|
|
7196
7538
|
log.error([
|
|
7197
7539
|
`deploy: could not confirm the remote migration state for "${d1MigrateToken}".`,
|
|
7198
|
-
"
|
|
7199
|
-
"
|
|
7200
|
-
"suppressed) — refusing to deploy against an unverified schema. Rerun once wrangler",
|
|
7201
|
-
"can reach your account."
|
|
7540
|
+
"Cloudflare returned an invalid pending migration set. Refusing to deploy against an unverified schema.",
|
|
7541
|
+
"Retry once the database migration state can be read."
|
|
7202
7542
|
].join("\n"));
|
|
7203
7543
|
return false;
|
|
7204
7544
|
}
|
|
@@ -7334,6 +7674,12 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
7334
7674
|
if (!source) return exit(1);
|
|
7335
7675
|
const { configPath, desired, reasons, authEnabled, dialect, migrationsDir, migrations: preBuildMigrations, needsAI, aiBindingName, needsSandbox, needsLive, expectedCrons, needsEmail, emailHandlers } = source;
|
|
7336
7676
|
let rootConfig = parseRootWranglerConfig(configPath);
|
|
7677
|
+
if (needsSandbox) try {
|
|
7678
|
+
assertSandboxNamespaceConfig(rootConfig, resolveSandboxConfig(voidConfig, root));
|
|
7679
|
+
} catch (error) {
|
|
7680
|
+
log.error(`deploy: ${getErrorMessage(error)}`);
|
|
7681
|
+
return exit(1);
|
|
7682
|
+
}
|
|
7337
7683
|
let apiBaseUrl;
|
|
7338
7684
|
try {
|
|
7339
7685
|
apiBaseUrl = resolveDeployTransport(root, rootConfig);
|
|
@@ -7449,8 +7795,8 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
7449
7795
|
await ensureCloudflareAuthentication({
|
|
7450
7796
|
acceptApiToken: true,
|
|
7451
7797
|
beforeRun: assertUploaderStillPinned,
|
|
7452
|
-
runWrangler: (
|
|
7453
|
-
|
|
7798
|
+
runWrangler: (operation, capture) => runWrangler(operation, { capture }),
|
|
7799
|
+
configPath: existsSync(configPath) ? configPath : void 0
|
|
7454
7800
|
});
|
|
7455
7801
|
} catch (error) {
|
|
7456
7802
|
if (error instanceof CloudflareAuthenticationError && error.reason === "uploader-changed") return exit(1);
|
|
@@ -7509,13 +7855,10 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
7509
7855
|
}
|
|
7510
7856
|
if (needsSandbox) {
|
|
7511
7857
|
if (!assertUploaderStillPinned()) return exit(1);
|
|
7512
|
-
if (!isCleanWranglerExit(await Promise.resolve(runWrangler(
|
|
7513
|
-
"containers",
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
...existingWranglerConfigArgs(configPath),
|
|
7517
|
-
"--env="
|
|
7518
|
-
], { capture: true })))) {
|
|
7858
|
+
if (!isCleanWranglerExit(await Promise.resolve(runWrangler({
|
|
7859
|
+
type: "containers.list",
|
|
7860
|
+
configPath: existsSync(configPath) ? configPath : void 0
|
|
7861
|
+
}, { capture: true })))) {
|
|
7519
7862
|
log.error(formatCloudflareSandboxUnavailable({ preflight: true }));
|
|
7520
7863
|
return exit(1);
|
|
7521
7864
|
}
|
|
@@ -7594,19 +7937,16 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
7594
7937
|
}
|
|
7595
7938
|
const absentQueues = [];
|
|
7596
7939
|
for (const name of desired.queues) {
|
|
7597
|
-
const info = await Promise.resolve(runWrangler(
|
|
7598
|
-
"queues",
|
|
7599
|
-
"info",
|
|
7940
|
+
const info = await Promise.resolve(runWrangler({
|
|
7941
|
+
type: "queues.info",
|
|
7600
7942
|
name,
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
"--env="
|
|
7604
|
-
], { capture: true }));
|
|
7943
|
+
configPath
|
|
7944
|
+
}, { capture: true }));
|
|
7605
7945
|
if (provisionModule.isQueueConfirmedAbsent(info, name)) absentQueues.push(name);
|
|
7606
7946
|
}
|
|
7607
7947
|
if (absentQueues.length > 0) await provisionAndVerify();
|
|
7608
7948
|
}
|
|
7609
|
-
const frameworkQueues = detectedFramework ?
|
|
7949
|
+
const frameworkQueues = detectedFramework ? source.analysis.queues : [];
|
|
7610
7950
|
writeProvisionedWranglerConfig(root, {
|
|
7611
7951
|
name: workerName,
|
|
7612
7952
|
accountId,
|
|
@@ -7632,12 +7972,15 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
7632
7972
|
const expectedContainers = reconstructExpectedContainers(voidConfig, root, preBuildRootConfig, needsSandbox);
|
|
7633
7973
|
const expectedDurableObjectState = reconstructExpectedDurableObjectState(voidConfig, root, preBuildRootConfig, {
|
|
7634
7974
|
needsSandbox,
|
|
7635
|
-
needsLive
|
|
7975
|
+
needsLive,
|
|
7976
|
+
analysis: source.analysis
|
|
7636
7977
|
});
|
|
7637
7978
|
removeDeployPointer(root);
|
|
7638
7979
|
const buildChildEnv = scrubManagedDeployBuildMarkers(scrubWranglerAuthCredentials(deployChildEnv(accountId, apiBaseUrl)));
|
|
7639
7980
|
requireProvisionModule().deleteEnvVarCaseAware(buildChildEnv, CLOUDFLARE_DEPLOY_BUILD_ENV);
|
|
7640
7981
|
buildChildEnv[CLOUDFLARE_DEPLOY_BUILD_ENV] = "1";
|
|
7982
|
+
requireProvisionModule().deleteEnvVarCaseAware(buildChildEnv, CLOUDFLARE_PRESERVE_BINDINGS_BUILD_ENV);
|
|
7983
|
+
if (existingWorker) buildChildEnv[CLOUDFLARE_PRESERVE_BINDINGS_BUILD_ENV] = "1";
|
|
7641
7984
|
requireProvisionModule().deleteEnvVarCaseAware(buildChildEnv, "NODE_ENV");
|
|
7642
7985
|
buildChildEnv.NODE_ENV = "production";
|
|
7643
7986
|
const runBuild = deps.runBuild ?? ((env) => {
|
|
@@ -7656,7 +7999,7 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
7656
7999
|
}
|
|
7657
8000
|
log.step("Preparing deployment...");
|
|
7658
8001
|
if (detectedFramework && frameworkPreset) try {
|
|
7659
|
-
await (deps.prepareFrameworkArtifact ?? prepareCloudflareFrameworkArtifact)(root, configPath, accountId, workerName, voidConfig, detectedFramework, frameworkPreset, schemaFacts.requiredKeys, needsAI ? { binding: aiBindingName } : void 0);
|
|
8002
|
+
await (deps.prepareFrameworkArtifact ?? prepareCloudflareFrameworkArtifact)(root, configPath, accountId, workerName, voidConfig, detectedFramework, frameworkPreset, schemaFacts.requiredKeys, needsAI ? { binding: aiBindingName } : void 0, existingWorker !== null);
|
|
7660
8003
|
} catch (error) {
|
|
7661
8004
|
log.error(`deploy: could not prepare ${detectedFramework.name} for Cloudflare — ${getErrorMessage(error)}`);
|
|
7662
8005
|
return exit(1);
|
|
@@ -7907,6 +8250,8 @@ async function runCloudflareDeploy(root, options, cliLog, deps = {}) {
|
|
|
7907
8250
|
workerName,
|
|
7908
8251
|
configPath: generatedConfigPath,
|
|
7909
8252
|
preserveTriggers: existingWorker !== null,
|
|
8253
|
+
requireVersionMetadata: existingWorker === null || readVersionMetadataBinding(parseRootWranglerConfig(generatedConfigPath)) !== void 0,
|
|
8254
|
+
requirePreviewForReadiness: existingWorker !== null && readVersionMetadataBinding(parseRootWranglerConfig(generatedConfigPath)) === void 0,
|
|
7910
8255
|
expectedPreviousVersionId: existingWorker?.versionId,
|
|
7911
8256
|
trustedInheritanceVersionIds: existingWorker ? candidateReceipt?.parentVersionId === existingWorker.versionId ? candidateReceipt.versionIds : void 0 : initialCloudflareCandidate?.versionIds,
|
|
7912
8257
|
validateUploadedVersion: existingWorker ? async (versionId) => {
|
|
@@ -7982,10 +8327,6 @@ function discoverRootWranglerConfig(root) {
|
|
|
7982
8327
|
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.");
|
|
7983
8328
|
return materializeCloudflareConfig(root);
|
|
7984
8329
|
}
|
|
7985
|
-
/** Avoid making Wrangler open a config path that Void has not created yet. */
|
|
7986
|
-
function existingWranglerConfigArgs(configPath) {
|
|
7987
|
-
return existsSync(configPath) ? ["-c", configPath] : [];
|
|
7988
|
-
}
|
|
7989
8330
|
async function reportCloudflareActivationFailure(cliLog, message) {
|
|
7990
8331
|
cliLog.error("cloudflare_deploy_failed", new Error(message));
|
|
7991
8332
|
await cliLog.close().catch(() => {});
|
|
@@ -8018,7 +8359,9 @@ function formatCloudflareActivationError(result) {
|
|
|
8018
8359
|
if (result.rollback === "failed") return "deploy: the verified Wrangler uploader changed after version activation, and automatic traffic restoration failed. Inspect `void project status` immediately.";
|
|
8019
8360
|
if (result.rollback === "unsafe") return "deploy: the verified Wrangler uploader changed after version activation. Void did not invoke the changed binary to restore traffic; reinstall Wrangler from a trusted lockfile and inspect `void project status` immediately.";
|
|
8020
8361
|
return "deploy: the verified Wrangler uploader changed before version activation.";
|
|
8021
|
-
case "status-failed":
|
|
8362
|
+
case "status-failed":
|
|
8363
|
+
if (result.versionId) return `deploy: Worker version ${result.versionId} was published, but current deployment status could not be verified${status}. Inspect \`void project status\` before retrying.`;
|
|
8364
|
+
return `deploy: could not snapshot the current Cloudflare deployment${status}; no version was uploaded.`;
|
|
8022
8365
|
case "deployment-changed": return result.triggerRepair === "succeeded" ? `deploy: another Cloudflare operation superseded this deployment. Void restored triggers for the active version ${result.activeVersionId ?? "(unknown)"}; retry from fresh deployment status.` : `deploy: another Cloudflare operation superseded this deployment, but its trigger state could not be verified. Inspect the active Worker version ${result.activeVersionId ?? "(unknown)"} immediately.`;
|
|
8023
8366
|
case "inheritance-source-unavailable": return "deploy: could not verify which Worker Version would supply inherited secrets; production traffic is unchanged.";
|
|
8024
8367
|
case "inheritance-source-changed": return [
|
|
@@ -8034,16 +8377,18 @@ function formatCloudflareActivationError(result) {
|
|
|
8034
8377
|
].join("\n");
|
|
8035
8378
|
case "upload-failed": return `deploy: Cloudflare Worker Version upload failed${status}; production traffic is unchanged.${cloudflareCode}${diagnostic}`;
|
|
8036
8379
|
case "upload-output-invalid": return "deploy: Wrangler uploaded a version but did not report its version id; production traffic is unchanged.";
|
|
8037
|
-
case "preview-unavailable":
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
|
|
8041
|
-
|
|
8380
|
+
case "preview-unavailable":
|
|
8381
|
+
if (result.diagnostic) return `deploy: candidate readiness cannot be verified.\n\n${result.diagnostic}`;
|
|
8382
|
+
return [
|
|
8383
|
+
"deploy: the uploaded Worker Version has no preview URL, so Void cannot verify readiness.",
|
|
8384
|
+
"Set CLOUDFLARE_WORKERS_SUBDOMAIN to your account subdomain (for example \"my-team\")",
|
|
8385
|
+
"and retry. Void caches it after a successful workers.dev deployment; production traffic is unchanged."
|
|
8386
|
+
].join("\n");
|
|
8042
8387
|
case "readiness-staging-failed": return `deploy: Cloudflare could not stage the uploaded Worker Version at zero-percent traffic${status}; production traffic is unchanged.${cloudflareCode}${diagnostic}${result.cloudflareErrorCode === 10210 && /Durable Object migration/i.test(result.diagnostic ?? "") ? "\n\nReview the Durable Object migration, then run `void deploy --platform cloudflare --atomic`. For future deploys, set deploy.cloudflare.mode to \"atomic\" in void.config.ts." : ""}`;
|
|
8043
8388
|
case "atomic-failed": return `deploy: Cloudflare could not publish the Worker atomically${status}; inspect production status before retrying.${cloudflareCode}${diagnostic}`;
|
|
8044
8389
|
case "atomic-output-invalid": return "deploy: Cloudflare published atomically but did not report a version id or URL. Inspect `void project status` immediately.";
|
|
8045
8390
|
case "atomic-readiness-failed":
|
|
8046
|
-
case "atomic-readiness-access-denied": return
|
|
8391
|
+
case "atomic-readiness-access-denied": return `deploy: the atomic Worker deployment is live, but /__void/ready could not be verified. Inspect \`void project status\` and Worker logs immediately.${diagnostic}`;
|
|
8047
8392
|
case "readiness-failed": return ["deploy: the uploaded Worker Version did not pass /__void/ready.", formatCloudflareReadinessRestoration(result)].join("\n");
|
|
8048
8393
|
case "readiness-access-denied": return [
|
|
8049
8394
|
"deploy: Cloudflare Access blocked the uploaded Worker Version readiness probe.",
|
|
@@ -8058,7 +8403,7 @@ function formatCloudflareActivationError(result) {
|
|
|
8058
8403
|
"deploy: the first Worker deployment did not pass /__void/ready.",
|
|
8059
8404
|
"Cloudflare requires this bootstrap to be non-versioned, so the new Worker is already active;",
|
|
8060
8405
|
"inspect its logs and `void project status` before retrying."
|
|
8061
|
-
].join("\n");
|
|
8406
|
+
].join("\n") + diagnostic;
|
|
8062
8407
|
case "bootstrap-readiness-access-denied": return [
|
|
8063
8408
|
"deploy: Cloudflare Access blocked the first Worker deployment readiness probe.",
|
|
8064
8409
|
"For CI, set CF_ACCESS_CLIENT_ID and CF_ACCESS_CLIENT_SECRET to an admitted service token;",
|
|
@@ -8068,7 +8413,7 @@ function formatCloudflareActivationError(result) {
|
|
|
8068
8413
|
"Worker is already active behind Access."
|
|
8069
8414
|
].join("\n");
|
|
8070
8415
|
case "activation-failed": return `deploy: the ready Worker Version could not be activated${status}; production traffic is unchanged.`;
|
|
8071
|
-
case "triggers-failed": return `deploy: the Worker activated, but Cloudflare trigger synchronization failed${status}. ${result.rollback === "succeeded" ? "Traffic was restored to the previous version." : result.rollback === "unavailable" ? result.previousVersionId === null ? "This was the first deployment, so no previous version was available to restore." : "Traffic
|
|
8416
|
+
case "triggers-failed": return `deploy: the Worker activated, but Cloudflare trigger synchronization failed${status}. ${result.rollback === "succeeded" ? "Traffic was restored to the previous version." : result.rollback === "unavailable" ? result.previousVersionId === null ? "This was the first deployment, so no previous version was available to restore." : "Traffic or trigger restoration could not be completed. Inspect its routes, schedules, queues, and workflows in Cloudflare before retrying." : "Automatic traffic restoration failed; inspect `void project status` immediately."}`;
|
|
8072
8417
|
}
|
|
8073
8418
|
}
|
|
8074
8419
|
function formatCloudflareReadinessRestoration(result) {
|
|
@@ -8089,29 +8434,36 @@ function cloudflareWorkerReadinessHeaders() {
|
|
|
8089
8434
|
});
|
|
8090
8435
|
}
|
|
8091
8436
|
/** Build the trusted Wrangler pointer for a framework that emits Worker files directly. */
|
|
8092
|
-
async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, workerName, voidConfig, framework, preset, requiredSecretNames = [], ai) {
|
|
8437
|
+
async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, workerName, voidConfig, framework, preset, requiredSecretNames = [], ai, preserveBindings = false) {
|
|
8093
8438
|
const workerMain = join(root, preset.workerDir, preset.workerMain);
|
|
8094
8439
|
const assetsDirectory = join(root, preset.assetsDir);
|
|
8095
8440
|
if (!existsSync(workerMain)) throw new Error(`framework ${framework.name} did not emit its Worker entry at ${preset.workerDir}/${preset.workerMain}`);
|
|
8096
8441
|
if (!existsSync(assetsDirectory)) throw new Error(`framework ${framework.name} did not emit its asset directory at ${preset.assetsDir}`);
|
|
8097
|
-
const
|
|
8098
|
-
|
|
8099
|
-
|
|
8442
|
+
const analysis = analyzeApplicationSync(root, {
|
|
8443
|
+
config: voidConfig,
|
|
8444
|
+
environment: "prod"
|
|
8445
|
+
});
|
|
8446
|
+
const crons = analysis.jobs;
|
|
8447
|
+
const queues = analysis.queues;
|
|
8100
8448
|
const revalidate = collectRevalidate(voidConfig, null);
|
|
8449
|
+
const rootConfig = parseRootWranglerConfig(configPath);
|
|
8450
|
+
const versionMetadataBinding = selectNativeVersionMetadataBinding(rootConfig, {
|
|
8451
|
+
nativeBuild: true,
|
|
8452
|
+
preserveBindings
|
|
8453
|
+
});
|
|
8101
8454
|
await generateDeployWrapperIfNeeded(root, join(root, preset.workerDir), preset.workerMain, {
|
|
8102
|
-
auth: null,
|
|
8103
8455
|
crons,
|
|
8104
8456
|
queues,
|
|
8105
8457
|
hasMigrations: false,
|
|
8106
|
-
migrationDialect:
|
|
8458
|
+
migrationDialect: analysis.dialect,
|
|
8107
8459
|
readiness: true,
|
|
8460
|
+
versionMetadataBinding,
|
|
8108
8461
|
...hasRevalidate(revalidate) && { isr: {
|
|
8109
8462
|
revalidate,
|
|
8110
8463
|
queryAllowlist: voidConfig.routing?.revalidateQueryAllowlist
|
|
8111
8464
|
} }
|
|
8112
8465
|
});
|
|
8113
8466
|
if (preset.cloudflareArtifact === "vite-plugin") return;
|
|
8114
|
-
const rootConfig = parseRootWranglerConfig(configPath);
|
|
8115
8467
|
writeCloudflareFrameworkDeployConfig({
|
|
8116
8468
|
configPath,
|
|
8117
8469
|
deployPointerPath: deployPointerPath(root),
|
|
@@ -8123,6 +8475,7 @@ async function prepareCloudflareFrameworkArtifact(root, configPath, accountId, w
|
|
|
8123
8475
|
compatibilityFlags: preset.cloudflareCompatibilityFlags,
|
|
8124
8476
|
crons: [...new Set(crons.flatMap((job) => job.crons))],
|
|
8125
8477
|
requiredSecrets: requiredSecretNames,
|
|
8478
|
+
versionMetadataBinding,
|
|
8126
8479
|
...ai ? { ai: {
|
|
8127
8480
|
...ai,
|
|
8128
8481
|
gateway: voidConfig.ai?.gateway
|
|
@@ -8162,23 +8515,14 @@ function resolveCloudflareStaticPreset(root, voidConfig, options) {
|
|
|
8162
8515
|
*/
|
|
8163
8516
|
async function resolveCloudflareVoidStaticPreset(root, voidConfig) {
|
|
8164
8517
|
if (voidConfig.output !== "static") return null;
|
|
8165
|
-
const
|
|
8166
|
-
|
|
8167
|
-
const routeScan = await scanRoutes(root, {
|
|
8168
|
-
output: voidConfig.output,
|
|
8169
|
-
paths,
|
|
8518
|
+
const analysis = await analyzeApplication(root, {
|
|
8519
|
+
config: voidConfig,
|
|
8170
8520
|
environment: "prod"
|
|
8171
8521
|
});
|
|
8172
|
-
const
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
});
|
|
8522
|
+
const { paths, authEnabled, bindings, scan: routeScan } = analysis;
|
|
8523
|
+
if (!existsSync(paths.pagesDir) || validateSsrEntry(root, paths) !== null) return null;
|
|
8524
|
+
const pageScan = routeScan.pages;
|
|
8176
8525
|
if (pageScan.pages.length === 0 || !pageScan.pages.every((page) => page.shouldPrerender && (page.params.length === 0 && !page.catchAll || page.hasGetPrerenderPaths))) return null;
|
|
8177
|
-
const bindings = inferProjectBindings(root, {
|
|
8178
|
-
paths,
|
|
8179
|
-
environment: "prod"
|
|
8180
|
-
});
|
|
8181
|
-
const authEnabled = bindings.needsAuth || findVoidAuthConfig(root, paths) !== null || voidConfig.auth !== void 0;
|
|
8182
8526
|
if (hasNonPageBackend({
|
|
8183
8527
|
hasRoutes: routeScan.routes.length > 0,
|
|
8184
8528
|
hasMiddleware: routeScan.middleware.length > 0,
|
|
@@ -8186,7 +8530,7 @@ async function resolveCloudflareVoidStaticPreset(root, voidConfig) {
|
|
|
8186
8530
|
hasEmail: routeScan.email !== void 0 && hasEmailHandlers(routeScan.email),
|
|
8187
8531
|
authEnabled,
|
|
8188
8532
|
hasLive: bindings.needsLive === true
|
|
8189
|
-
}) ||
|
|
8533
|
+
}) || analysis.jobs.length > 0 || analysis.queues.length > 0) return null;
|
|
8190
8534
|
return {
|
|
8191
8535
|
buildCommand: resolveFullDeployBuildCommand(root, voidConfig.inference?.build).command,
|
|
8192
8536
|
outputDir: join(root, "dist", "client"),
|
|
@@ -8247,8 +8591,8 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
|
|
|
8247
8591
|
await ensureCloudflareAuthentication({
|
|
8248
8592
|
acceptApiToken: true,
|
|
8249
8593
|
beforeRun: uploaderIsPinned,
|
|
8250
|
-
runWrangler: (
|
|
8251
|
-
|
|
8594
|
+
runWrangler: (operation, capture) => runWrangler(operation, { capture }),
|
|
8595
|
+
configPath: existsSync(configPath) ? configPath : void 0
|
|
8252
8596
|
});
|
|
8253
8597
|
} catch (error) {
|
|
8254
8598
|
if (error instanceof CloudflareAuthenticationError && error.reason === "uploader-changed") return exit(1);
|
|
@@ -8316,12 +8660,6 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
|
|
|
8316
8660
|
});
|
|
8317
8661
|
const entryPath = join(root, ".void", "deploy", "cloudflare", "static-edge.mjs");
|
|
8318
8662
|
mkdirSync(dirname(entryPath), { recursive: true });
|
|
8319
|
-
writeFileSync(entryPath, renderCloudflareStaticEntry({
|
|
8320
|
-
runtimeImport: "void/edge",
|
|
8321
|
-
headerRules: manifest.headerRules,
|
|
8322
|
-
redirectRules: manifest.redirectRules,
|
|
8323
|
-
fallbackRules: manifest.fallbackRules
|
|
8324
|
-
}));
|
|
8325
8663
|
const workerName = readWranglerTopLevelString(rootConfig, "name") ?? deriveWorkerName(root);
|
|
8326
8664
|
const staticConfigPath = join(dirname(entryPath), "wrangler-static.json");
|
|
8327
8665
|
writeFileSync(staticConfigPath, `${JSON.stringify(rootConfig, null, 2)}\n`, { mode: 384 });
|
|
@@ -8335,6 +8673,22 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
|
|
|
8335
8673
|
assetConfig: manifest.assetConfig ?? { not_found_handling: "none" }
|
|
8336
8674
|
});
|
|
8337
8675
|
deduplicateGeneratedCompatibilityFlags(staticConfigPath, configPath);
|
|
8676
|
+
const staticConfig = parseRootWranglerConfig(staticConfigPath);
|
|
8677
|
+
const versionMetadataBinding = selectNativeVersionMetadataBinding(staticConfig, {
|
|
8678
|
+
nativeBuild: true,
|
|
8679
|
+
preserveBindings: existingWorker !== null
|
|
8680
|
+
});
|
|
8681
|
+
if (versionMetadataBinding && staticConfig.version_metadata === void 0) writeFileSync(staticConfigPath, `${JSON.stringify({
|
|
8682
|
+
...staticConfig,
|
|
8683
|
+
version_metadata: { binding: versionMetadataBinding }
|
|
8684
|
+
}, null, 2)}\n`, { mode: 384 });
|
|
8685
|
+
writeFileSync(entryPath, renderCloudflareStaticEntry({
|
|
8686
|
+
runtimeImport: "void/edge",
|
|
8687
|
+
headerRules: manifest.headerRules,
|
|
8688
|
+
redirectRules: manifest.redirectRules,
|
|
8689
|
+
fallbackRules: manifest.fallbackRules,
|
|
8690
|
+
versionMetadataBinding
|
|
8691
|
+
}));
|
|
8338
8692
|
if (existingWorker) assertExistingCloudflareConfig(existingWorker, parseRootWranglerConfig(staticConfigPath), true);
|
|
8339
8693
|
const stagedAssetsDirectory = join(root, ".void", "deploy", "cloudflare", "assets");
|
|
8340
8694
|
stageCloudflareStaticAssets({
|
|
@@ -8385,6 +8739,8 @@ async function runCloudflareStaticDeploy(root, options, voidConfig, preset, cliL
|
|
|
8385
8739
|
verifyUploader: cfOutput ? cfUploaderIsPinned : uploaderIsPinned,
|
|
8386
8740
|
configPath: staticConfigPath,
|
|
8387
8741
|
preserveTriggers: existingWorker !== null,
|
|
8742
|
+
requireVersionMetadata: existingWorker === null || versionMetadataBinding !== void 0,
|
|
8743
|
+
requirePreviewForReadiness: existingWorker !== null && versionMetadataBinding === void 0,
|
|
8388
8744
|
expectedPreviousVersionId: existingWorker?.versionId,
|
|
8389
8745
|
trustedInheritanceVersionIds: existingWorker ? candidateReceipt?.parentVersionId === existingWorker.versionId ? candidateReceipt.versionIds : void 0 : initialCloudflareCandidate?.versionIds,
|
|
8390
8746
|
validateUploadedVersion: existingWorker ? async (versionId) => {
|
|
@@ -8537,11 +8893,16 @@ async function runDeployInner(root, options, cliLog) {
|
|
|
8537
8893
|
}
|
|
8538
8894
|
}
|
|
8539
8895
|
async function runManagedDeploy(root, options, cliLog) {
|
|
8896
|
+
const apiUrl = getApiUrl(root);
|
|
8897
|
+
const requestedProjectSlug = getRequestedProjectSlug(options);
|
|
8540
8898
|
let reauthenticated = false;
|
|
8541
8899
|
while (true) try {
|
|
8900
|
+
const savedProject = readProjectConfig(root);
|
|
8901
|
+
const linkedProject = savedProject?.platformUrl === apiUrl ? savedProject : null;
|
|
8902
|
+
if (savedProject && !linkedProject && !requestedProjectSlug) throw new Error(`deploy: This project is linked to ${savedProject.platformUrl}. Pass --project <slug> to deploy to ${apiUrl} without changing the saved link.`);
|
|
8542
8903
|
let token = process.env.VOID_TOKEN ? getToken(root) : null;
|
|
8543
8904
|
if (!token && isGithubActionsOidcAvailable()) {
|
|
8544
|
-
const slug =
|
|
8905
|
+
const slug = requestedProjectSlug ?? linkedProject?.slug;
|
|
8545
8906
|
if (!slug) throw new Error("deploy: running in GitHub Actions but the project is unknown — pass --project <slug> or link the project.");
|
|
8546
8907
|
cliLog.info("github_oidc_exchange_start", { slug });
|
|
8547
8908
|
const tokenOrigin = getApiUrl(root);
|
|
@@ -8560,8 +8921,6 @@ async function runManagedDeploy(root, options, cliLog) {
|
|
|
8560
8921
|
root,
|
|
8561
8922
|
cliLog
|
|
8562
8923
|
});
|
|
8563
|
-
const requestedProjectSlug = getRequestedProjectSlug(options);
|
|
8564
|
-
const linkedProject = readProjectConfig(root);
|
|
8565
8924
|
let config = null;
|
|
8566
8925
|
if (requestedProjectSlug) {
|
|
8567
8926
|
const linked = linkedProject?.slug === requestedProjectSlug ? await client.getProject(linkedProject.projectId) : null;
|
|
@@ -8659,24 +9018,31 @@ function assertProjectDeployAccess(project) {
|
|
|
8659
9018
|
}
|
|
8660
9019
|
async function promptDeployProjectConfig(root, client, cliLog) {
|
|
8661
9020
|
const projects = await client.listProjectChoices();
|
|
9021
|
+
const link = shouldLinkDeployProject(root, client.apiUrl);
|
|
8662
9022
|
const deployableProjects = projects.filter((project) => project.role !== "reader");
|
|
8663
9023
|
if (deployableProjects.length !== projects.length) log.warn("Projects with reader access are hidden from deploy selection. Ask a project admin or owner to grant collaborator access to deploy to them.");
|
|
8664
|
-
if (await promptProjectSetupAction("Set up a Void project for deploy:", {
|
|
9024
|
+
if (await promptProjectSetupAction("Set up a Void project for deploy:", {
|
|
9025
|
+
includeLink: deployableProjects.length > 0,
|
|
9026
|
+
...link ? {} : { link: false }
|
|
9027
|
+
}) === "create") return promptAndCreateProject(root, client, { link });
|
|
8665
9028
|
const result = await promptProjectSelection(deployableProjects, "Select a project to deploy to:", root, {
|
|
8666
9029
|
confirmExisting: true,
|
|
8667
|
-
includeCreate: false
|
|
9030
|
+
includeCreate: false,
|
|
9031
|
+
...link ? {} : { link: false }
|
|
8668
9032
|
});
|
|
8669
9033
|
if (result.action === "create") throw new Error("Unexpected project selection result.");
|
|
8670
9034
|
const config = {
|
|
8671
9035
|
projectId: result.project.id,
|
|
8672
9036
|
slug: result.project.slug
|
|
8673
9037
|
};
|
|
8674
|
-
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
9038
|
+
if (shouldLinkDeployProject(root, client.apiUrl)) {
|
|
9039
|
+
writeProjectConfig(root, attachSelectedPlatform(root, config, client.apiUrl));
|
|
9040
|
+
log.step(`Linked to ${import_picocolors$1.default.blue(config.slug)}`);
|
|
9041
|
+
cliLog?.info("project_linked", {
|
|
9042
|
+
projectId: config.projectId,
|
|
9043
|
+
slug: config.slug
|
|
9044
|
+
});
|
|
9045
|
+
} else log.step(`Using ${import_picocolors$1.default.blue(config.slug)} for this deployment. Saved destination unchanged.`);
|
|
8680
9046
|
return config;
|
|
8681
9047
|
}
|
|
8682
9048
|
function resolveStaticBuildCommand(preset, buildOverride, hasExplicitDir = false) {
|
|
@@ -8785,7 +9151,9 @@ function applyDeployEvent(event, s) {
|
|
|
8785
9151
|
kind: "start",
|
|
8786
9152
|
deploymentId: event.deploymentId
|
|
8787
9153
|
};
|
|
8788
|
-
case "heartbeat":
|
|
9154
|
+
case "heartbeat":
|
|
9155
|
+
if (event.status === "recovering") s.message("Recovering interrupted deployment...");
|
|
9156
|
+
return { kind: "continue" };
|
|
8789
9157
|
case "asset_upload":
|
|
8790
9158
|
if (event.new > 0) s.message(`Uploading assets (${event.new} new, ${event.cached} cached)`);
|
|
8791
9159
|
else s.message(`Uploading assets (${event.total} cached)`);
|
|
@@ -8838,6 +9206,8 @@ function applyDeployEvent(event, s) {
|
|
|
8838
9206
|
async function streamDeployEvents(projectId, events, s, cliLog) {
|
|
8839
9207
|
const startedAt = Date.now();
|
|
8840
9208
|
let deploymentId = null;
|
|
9209
|
+
let lastProgressAt = startedAt;
|
|
9210
|
+
let waitNotice;
|
|
8841
9211
|
let interrupted = false;
|
|
8842
9212
|
cliLog?.info("stream_start", { projectId });
|
|
8843
9213
|
const onSigint = () => {
|
|
@@ -8852,6 +9222,26 @@ async function streamDeployEvents(projectId, events, s, cliLog) {
|
|
|
8852
9222
|
process.once("SIGINT", onSigint);
|
|
8853
9223
|
try {
|
|
8854
9224
|
for await (const event of events) {
|
|
9225
|
+
if (event.event === "heartbeat") {
|
|
9226
|
+
const fields = {
|
|
9227
|
+
deploymentId,
|
|
9228
|
+
step: event.step,
|
|
9229
|
+
status: event.status,
|
|
9230
|
+
recoveryAt: event.recoveryAt
|
|
9231
|
+
};
|
|
9232
|
+
if (event.status === "recovering" && waitNotice !== "recovering") {
|
|
9233
|
+
log.info(`Deployment ${deploymentId ?? event.deploymentId ?? ""} is recovering; waiting for its result.`);
|
|
9234
|
+
cliLog?.info("deploy_recovering", fields);
|
|
9235
|
+
waitNotice = "recovering";
|
|
9236
|
+
} else if (Date.now() - lastProgressAt >= 9e4 && waitNotice === void 0) {
|
|
9237
|
+
log.warn(`Deployment ${deploymentId ?? event.deploymentId ?? ""} has not reported new progress for 90 seconds (last reported progress: ${event.step.replaceAll("_", " ")}).` + (event.recoveryAt ? ` Automatic recovery can start after ${event.recoveryAt} if execution was interrupted.` : "") + " Inspect with `void project status`.");
|
|
9238
|
+
cliLog?.warn("deploy_progress_stalled", fields);
|
|
9239
|
+
waitNotice = "stalled";
|
|
9240
|
+
}
|
|
9241
|
+
} else {
|
|
9242
|
+
lastProgressAt = Date.now();
|
|
9243
|
+
waitNotice = void 0;
|
|
9244
|
+
}
|
|
8855
9245
|
const result = applyDeployEvent(event, s);
|
|
8856
9246
|
if (result.kind === "start") {
|
|
8857
9247
|
deploymentId = result.deploymentId;
|
|
@@ -9142,7 +9532,6 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
|
|
|
9142
9532
|
mode: "framework",
|
|
9143
9533
|
framework: detected.name
|
|
9144
9534
|
});
|
|
9145
|
-
const dialect = getDatabaseDialect(voidConfig);
|
|
9146
9535
|
const buildCmd = voidConfig.inference?.build ?? formatProjectCommand(root, fwPreset.buildCommand);
|
|
9147
9536
|
if (!skipBuild) {
|
|
9148
9537
|
log.step(`Building (${buildCmd})...`);
|
|
@@ -9172,15 +9561,12 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
|
|
|
9172
9561
|
log.error(`deploy: Worker output '${fwPreset.workerDir}' not found. Run '${buildCmd}' first.`);
|
|
9173
9562
|
process.exit(1);
|
|
9174
9563
|
}
|
|
9175
|
-
const
|
|
9176
|
-
|
|
9177
|
-
const scanDirs = voidConfig.inference?.scanDirs ?? FRAMEWORK_SCAN_DIRS;
|
|
9178
|
-
const bindings = inferProjectBindings(root, {
|
|
9179
|
-
...inferenceOptions,
|
|
9180
|
-
paths,
|
|
9564
|
+
const analysis = analyzeApplicationSync(root, {
|
|
9565
|
+
config: voidConfig,
|
|
9181
9566
|
environment: "prod"
|
|
9182
|
-
}
|
|
9183
|
-
|
|
9567
|
+
});
|
|
9568
|
+
const { paths, bindings, authEnabled, dialect } = analysis;
|
|
9569
|
+
if (authEnabled) {
|
|
9184
9570
|
log.error("deploy: Void-managed Better Auth is only supported in Void apps. Use Better Auth's official integration for this framework instead.");
|
|
9185
9571
|
process.exit(1);
|
|
9186
9572
|
}
|
|
@@ -9190,7 +9576,7 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
|
|
|
9190
9576
|
}
|
|
9191
9577
|
const migrationsDir = paths.migrationsDir;
|
|
9192
9578
|
assertDeploySchemaDriftFree(root, dialect);
|
|
9193
|
-
const rawMigrations =
|
|
9579
|
+
const rawMigrations = analysis.migrations;
|
|
9194
9580
|
let validatedMigrations;
|
|
9195
9581
|
try {
|
|
9196
9582
|
assertJournalCoherence(migrationsDir, rawMigrations);
|
|
@@ -9205,14 +9591,14 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
|
|
|
9205
9591
|
log.error(getErrorMessage(err));
|
|
9206
9592
|
process.exit(1);
|
|
9207
9593
|
}
|
|
9208
|
-
if (dialect !== "sqlite" &&
|
|
9594
|
+
if (dialect !== "sqlite" && analysis.needsDatabase) {
|
|
9209
9595
|
let resources = null;
|
|
9210
9596
|
try {
|
|
9211
9597
|
resources = await client.getResources(config.projectId);
|
|
9212
9598
|
} catch {}
|
|
9213
9599
|
if (resources) {
|
|
9214
9600
|
if (!resources.some((resource) => resource.type === "hyperdrive")) {
|
|
9215
|
-
const { text: promptText, isCancel: isCancelPrompt } = await import("./
|
|
9601
|
+
const { text: promptText, isCancel: isCancelPrompt } = await import("./prompts-2TGE6oXx.mjs");
|
|
9216
9602
|
const connectionString = await promptText({
|
|
9217
9603
|
message: `Your project uses ${dialect === "mysql" ? "MySQL" : "PostgreSQL"}. Enter your connection string:`,
|
|
9218
9604
|
placeholder: dialect === "mysql" ? "mysql://user:pass@host:3306/dbname" : "postgresql://user:pass@host:5432/dbname",
|
|
@@ -9229,11 +9615,10 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
|
|
|
9229
9615
|
}
|
|
9230
9616
|
}
|
|
9231
9617
|
}
|
|
9232
|
-
const rawJobs =
|
|
9233
|
-
const rawQueues =
|
|
9618
|
+
const rawJobs = analysis.jobs;
|
|
9619
|
+
const rawQueues = analysis.queues;
|
|
9234
9620
|
const originalEntry = join(workerDir, fwPreset.workerMain);
|
|
9235
9621
|
const wrapperFeatures = {
|
|
9236
|
-
auth: null,
|
|
9237
9622
|
crons: rawJobs,
|
|
9238
9623
|
queues: rawQueues,
|
|
9239
9624
|
hasMigrations: validatedMigrations != null && validatedMigrations.length > 0,
|
|
@@ -9289,7 +9674,7 @@ async function runFrameworkDeploy(root, config, client, detected, fwPreset, void
|
|
|
9289
9674
|
const packageStartedAt = Date.now();
|
|
9290
9675
|
const neededSet = skipped > 0 ? new Set(needed) : null;
|
|
9291
9676
|
const packageOptions = {
|
|
9292
|
-
bindingNames:
|
|
9677
|
+
bindingNames: analysis.bindingNames,
|
|
9293
9678
|
workerMain: actualWorkerMain,
|
|
9294
9679
|
compatibilityDate: wranglerCompat?.compatibilityDate,
|
|
9295
9680
|
compatibilityFlags: wranglerCompat?.compatibilityFlags,
|
|
@@ -9396,20 +9781,12 @@ async function runFullDeploy(root, config, client, voidConfig, fwPreset, skipBui
|
|
|
9396
9781
|
if (result.paths.length === 0) log.info("No pages to prerender");
|
|
9397
9782
|
else if (result.failed.length > 0) voidWarn(`${result.failed.length} page(s) failed to prerender`);
|
|
9398
9783
|
}
|
|
9399
|
-
const
|
|
9400
|
-
|
|
9401
|
-
const deployScanDirs = deployConfig.inference?.scanDirs ?? (isFrameworkMode ? FRAMEWORK_SCAN_DIRS : void 0);
|
|
9402
|
-
const bindings = inferProjectBindings(root, {
|
|
9403
|
-
paths,
|
|
9784
|
+
const analysis = await analyzeApplication(root, {
|
|
9785
|
+
config: deployConfig,
|
|
9404
9786
|
environment: "prod"
|
|
9405
|
-
}
|
|
9406
|
-
|
|
9407
|
-
const
|
|
9408
|
-
const effectiveBindings = authEnabled ? {
|
|
9409
|
-
...bindings,
|
|
9410
|
-
needsAuth: true,
|
|
9411
|
-
needsD1: true
|
|
9412
|
-
} : bindings;
|
|
9787
|
+
});
|
|
9788
|
+
const { paths, dialect, bindings, authEnabled, scan: routeScan } = analysis;
|
|
9789
|
+
const effectiveBindings = bindings;
|
|
9413
9790
|
if (isFrameworkMode && authEnabled) {
|
|
9414
9791
|
log.error("Void-managed Better Auth is only supported in Void apps. Use Better Auth's official integration for this framework instead.");
|
|
9415
9792
|
process.exit(1);
|
|
@@ -9439,7 +9816,7 @@ async function runFullDeploy(root, config, client, voidConfig, fwPreset, skipBui
|
|
|
9439
9816
|
lintDestinationSplats(fallbackRules, "fallbacks (post-asset)");
|
|
9440
9817
|
const migrationsDir = paths.migrationsDir;
|
|
9441
9818
|
assertDeploySchemaDriftFree(root, dialect);
|
|
9442
|
-
const rawMigrations =
|
|
9819
|
+
const rawMigrations = analysis.migrations;
|
|
9443
9820
|
let validatedMigrations;
|
|
9444
9821
|
try {
|
|
9445
9822
|
assertJournalCoherence(migrationsDir, rawMigrations);
|
|
@@ -9454,14 +9831,14 @@ async function runFullDeploy(root, config, client, voidConfig, fwPreset, skipBui
|
|
|
9454
9831
|
log.error(getErrorMessage(err));
|
|
9455
9832
|
process.exit(1);
|
|
9456
9833
|
}
|
|
9457
|
-
if (dialect !== "sqlite" &&
|
|
9834
|
+
if (dialect !== "sqlite" && analysis.needsDatabase) {
|
|
9458
9835
|
let resources = null;
|
|
9459
9836
|
try {
|
|
9460
9837
|
resources = await client.getResources(config.projectId);
|
|
9461
9838
|
} catch {}
|
|
9462
9839
|
if (resources) {
|
|
9463
9840
|
if (!resources.some((resource) => resource.type === "hyperdrive")) {
|
|
9464
|
-
const { text: promptText, isCancel: isCancelPrompt } = await import("./
|
|
9841
|
+
const { text: promptText, isCancel: isCancelPrompt } = await import("./prompts-2TGE6oXx.mjs");
|
|
9465
9842
|
const connectionString = await promptText({
|
|
9466
9843
|
message: `Your project uses ${dialect === "mysql" ? "MySQL" : "PostgreSQL"}. Enter your connection string:`,
|
|
9467
9844
|
placeholder: dialect === "mysql" ? "mysql://user:pass@host:3306/dbname" : "postgresql://user:pass@host:5432/dbname",
|
|
@@ -9478,18 +9855,13 @@ async function runFullDeploy(root, config, client, voidConfig, fwPreset, skipBui
|
|
|
9478
9855
|
}
|
|
9479
9856
|
}
|
|
9480
9857
|
}
|
|
9481
|
-
const rawJobs =
|
|
9482
|
-
const rawQueues =
|
|
9858
|
+
const rawJobs = analysis.jobs;
|
|
9859
|
+
const rawQueues = analysis.queues;
|
|
9483
9860
|
const schedules = rawJobs.flatMap((job) => job.crons.map((cron) => ({
|
|
9484
9861
|
name: job.name,
|
|
9485
9862
|
cron
|
|
9486
9863
|
})));
|
|
9487
|
-
const
|
|
9488
|
-
output: deployConfig.output,
|
|
9489
|
-
paths,
|
|
9490
|
-
environment: "prod"
|
|
9491
|
-
});
|
|
9492
|
-
const webSockets = routeScan.websockets ?? scanWebSocketRoutesSync(root, paths, "prod");
|
|
9864
|
+
const webSockets = analysis.websockets;
|
|
9493
9865
|
const liveConfig = await resolveDeployLiveBindingConfig(root, client, config.projectId, {
|
|
9494
9866
|
isFrameworkMode,
|
|
9495
9867
|
needsLive: effectiveBindings.needsLive,
|
|
@@ -9511,10 +9883,7 @@ async function runFullDeploy(root, config, client, voidConfig, fwPreset, skipBui
|
|
|
9511
9883
|
const hasWebSockets = webSockets.length > 0;
|
|
9512
9884
|
const ssrEntry = isFrameworkMode ? null : validateSsrEntry(root, paths);
|
|
9513
9885
|
const isSsr = isFrameworkMode ? true : Boolean(ssrEntry) || hasPages && deployConfig.output !== "static";
|
|
9514
|
-
const pageScan =
|
|
9515
|
-
output: deployConfig.output,
|
|
9516
|
-
paths
|
|
9517
|
-
}) : null;
|
|
9886
|
+
const pageScan = hasPages ? routeScan.pages : null;
|
|
9518
9887
|
const revalidate = collectRevalidate(deployConfig, pageScan);
|
|
9519
9888
|
if (deployConfig.output === "static" && pageScan && !isSsr) {
|
|
9520
9889
|
const allPrerenderable = pageScan.pages.every((p) => p.shouldPrerender && (p.params.length === 0 && !p.catchAll || p.hasGetPrerenderPaths));
|
|
@@ -9638,7 +10007,6 @@ async function runFullDeploy(root, config, client, voidConfig, fwPreset, skipBui
|
|
|
9638
10007
|
const workerDir = join(distDir, workerDirName);
|
|
9639
10008
|
if (isFrameworkMode) {
|
|
9640
10009
|
const wrapperFeatures = {
|
|
9641
|
-
auth: null,
|
|
9642
10010
|
crons: rawJobs,
|
|
9643
10011
|
queues: rawQueues,
|
|
9644
10012
|
hasMigrations: validatedMigrations != null && validatedMigrations.length > 0,
|
|
@@ -9680,7 +10048,7 @@ async function createProjectFromSlug(root, client, slug, cliLog) {
|
|
|
9680
10048
|
projectId: project.id,
|
|
9681
10049
|
slug: project.slug
|
|
9682
10050
|
};
|
|
9683
|
-
writeProjectConfig(root, attachSelectedPlatform(root, config, client.apiUrl));
|
|
10051
|
+
if (shouldLinkDeployProject(root, client.apiUrl)) writeProjectConfig(root, attachSelectedPlatform(root, config, client.apiUrl));
|
|
9684
10052
|
log.success(`Project created: ${import_picocolors$1.default.blue(config.slug)}`);
|
|
9685
10053
|
reportProjectCreationWarnings(project);
|
|
9686
10054
|
cliLog?.info("project_create_success", {
|
|
@@ -9909,4 +10277,4 @@ function resolveWorkerDirName(distDir, fwPreset, buildCommand) {
|
|
|
9909
10277
|
throw new Error("deploy: Worker output not found. Expected dist/ssr/ or dist/rsc/.");
|
|
9910
10278
|
}
|
|
9911
10279
|
//#endregion
|
|
9912
|
-
export { snapshotPassthroughRawFields as $, parseRootWranglerConfig$1 as A, resolveDeploymentPlatform as B, generateDeployWrapperIfNeeded as C,
|
|
10280
|
+
export { snapshotPassthroughRawFields as $, parseRootWranglerConfig$1 as A, resolveDeploymentPlatform as B, generateDeployWrapperIfNeeded as C, hasDocumentRoutes as Ct, hashWranglerUploader as D, hasPrerenderSources as E, resolveCloudflareVoidStaticPreset as F, resolveWorkerDirName as G, resolveFullDeployBuildCommand as H, resolveDeployLiveBindingConfig as I, runDeploy as J, resolveWranglerMigrationPattern as K, resolveDeployTransport as L, promptDeployProjectConfig as M, reconstructExpectedContainers as N, isWranglerNonInteractiveOrCI as O, reconstructExpectedDurableObjectState as P, snapshotPassthroughIdentities as Q, resolveDeployWorkerMain as R, formatCloudflareSandboxUnavailable as S, hasApiRoutes as St, hasNonPageBackend as T, resolveAssetRoutingPolicy as Tt, resolveStaticBuildCommand as U, resolveDistDir as V, resolveStaticDeployPreset as W, runWranglerAuthToken as X, runStaticDeploy as Y, snapshotBindingIdentities as Z, deriveWorkerName as _, createNodeEmailDns as _t, applyDeployEvent as a, warnUnpublishedRouting as at, ensurePreviouslyDeployedLiveBindingConfig as b, renderAddressMap as bt, assertMigrationsProduceAuthSchema as c, selectNativeVersionMetadataBinding as ct, assertWranglerUploaderUnchanged as d, buildEnv as dt, streamDeployEvents as et, checkWranglerMigrationApplySet as f, collectPages as ft, deployChildEnv as g, applyEmailSetup as gt, createDeployWranglerRunner as h, SEND_EMAIL_BINDING as ht, DEPLOY_WHOLE_OBJECT_PINNED_FIELDS as i, warnRedundantForceOn3xx as it, prepareCloudflareFrameworkArtifact as j, loadProvisionModule as k, assertNoConfigOverrideInProjectDotenv as l, prerenderPages as lt, computeDesiredCloudflareResources as m, hasRevalidate as mt, DEPLOY_PASSTHROUGH_ASSERT_FIELDS as n, verifyGeneratedDeployConfig as nt, assembleVoidManifest as o, generateQueueResolverSource as ot, compareWranglerMigrationPaths as p, collectRevalidate as pt, runCloudflareDeploy as q, DEPLOY_PASSTHROUGH_EXCLUDE_FIELDS as r, warnIgnoredNotFoundForFramework as rt, assertManagedDurableStateSupported as s, CLOUDFLARE_PRESERVE_BINDINGS_BUILD_ENV as st, CloudflareAuthSecretError as t, validateAuthMigrationSchema as tt, assertRemoteMigrationsDeployable as u, prerenderPagesNode as ut, discoverRootWranglerConfig as v, findEmailConfigConflicts as vt, hasDeploySchemaDrift as w, resolveAssetConfig as wt, formatCloudflareActivationError as x, renderEmailChecklist as xt, ensureCloudflareAuthSecret as y, preflightEmail as yt, resolveDeployWranglerCompat as z };
|