void 1.1.0 → 1.1.12
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/dist/{account-cmd-BTcUzv9L.mjs → account-cmd-Cj6sCMTk.mjs} +4 -4
- package/dist/{application-analysis-AB_YYWgH.mjs → application-analysis-D7nNmNJb.mjs} +6 -6
- package/dist/{application-routing-L7V-TFhZ.mjs → application-routing-CZH66gXn.mjs} +1 -1
- package/dist/{auth-link-DUJuvRx5.mjs → auth-link-Dj7lAC_K.mjs} +4 -4
- package/dist/{auth-migrations-Cgs0k6lS.mjs → auth-migrations-BO27GDNr.mjs} +38 -2
- package/dist/{auth-router-CIxiMG7i.mjs → auth-router-CNsMOFCa.mjs} +5 -4
- package/dist/{better-auth-shared-B74NJIus.d.mts → better-auth-shared-Bv18bB-l.d.mts} +2 -0
- package/dist/{better-auth-shared-CMXlZG7W.mjs → better-auth-shared-D-6z0q0f.mjs} +28 -1
- package/dist/{build-cmd-BkIv25PA.mjs → build-cmd-ByhegwRC.mjs} +2 -2
- package/dist/{cache-Ctzfig-W.mjs → cache-CEFb5ban.mjs} +2 -2
- package/dist/{cancel-deploy-CD9o-SsC.mjs → cancel-deploy-CaARY26n.mjs} +2 -2
- package/dist/{cf-build-output-Bc8i3dzE.mjs → cf-build-output-ChEKWan2.mjs} +71 -7
- package/dist/cf-build-output-Dcmxa-Zm.mjs +1 -0
- package/dist/{cf-user-agent-ChjQp2MU.mjs → cf-command-values-b8OqDoo9.mjs} +5 -16
- package/dist/cf-user-agent-BkEHPDLA.mjs +16 -0
- package/dist/cli/cli.mjs +180 -57
- package/dist/cli/cloudflare-operation-process.mjs +46 -9
- package/dist/cli/env-schema-probe.mjs +3 -3
- package/dist/{client-DM9Kcf4e.mjs → client-BdzxubTS.mjs} +58 -13
- package/dist/client-DAnfyMe9.mjs +1 -0
- package/dist/{cloudflare-auth-CqFBDo52.mjs → cloudflare-auth-DSvBc1Gu.mjs} +1 -1
- package/dist/{cloudflare-cmd-BIAF_BIY.mjs → cloudflare-cmd-D_2-Q-_i.mjs} +4 -4
- package/dist/{cloudflare-config-DV60XFFK.mjs → cloudflare-config-rdFOys4X.mjs} +2 -2
- package/dist/{cloudflare-connect-WjwnVOJA.mjs → cloudflare-connect-BN-k2kD-.mjs} +2 -2
- package/dist/{cloudflare-operations-CrSUFRzJ.mjs → cloudflare-operations-BFLCpUCV.mjs} +1 -1
- package/dist/{cloudflare-operations-B42EZeJy.mjs → cloudflare-operations-D5PLrOqD.mjs} +18 -8
- package/dist/{cloudflare-process-CeDWJRhj.mjs → cloudflare-process-CZJ4viYl.mjs} +2 -2
- package/dist/collect-BWhkgtAn.mjs +1 -0
- package/dist/{collect-xjffdCdk.mjs → collect-Dew86qce.mjs} +4 -3
- package/dist/{config-D0GY5ItR.mjs → config-CyUJzi3q.mjs} +1 -1
- package/dist/{config-Bx_1SpnO.mjs → config-D26zcdKy.mjs} +2 -2
- package/dist/{config-BEm9vRvS.mjs → config-DC5llZaI.mjs} +2 -2
- package/dist/{config-QrJWu0IX.mjs → config-DYJV8aEH.mjs} +1 -1
- package/dist/{connect-CKtk-EZe.mjs → connect-C4_m2moF.mjs} +5 -5
- package/dist/{create-project-B-ewF_Af.mjs → create-project-CvuYDD-l.mjs} +1 -1
- package/dist/{create-project-yInGo72M.mjs → create-project-D8jQTwVQ.mjs} +2 -2
- package/dist/database-provider.d.mts +6 -0
- package/dist/{db-7I_gfdVq.mjs → db-BsiOAa0A.mjs} +306 -111
- package/dist/{db-types-Bb4WBWIs.mjs → db-types-NGxPwnlt.mjs} +1 -1
- package/dist/{delete-Cy-M1u-r.mjs → delete-CAma7nFi.mjs} +2 -2
- package/dist/{deploy-BYYlnsiy.mjs → deploy-D1gIPiAq.mjs} +148 -64
- package/dist/deploy-Dc0XsCQj.mjs +2 -0
- package/dist/{deploy-managed-static-Ca4TFdmx.mjs → deploy-managed-static-B9KVxY3X.mjs} +80 -34
- package/dist/{deploy-transport-DWlWBe6M.mjs → deploy-transport-B3mtEi_q.mjs} +2 -2
- package/dist/deploy.d.mts +22 -1
- package/dist/deploy.mjs +49 -8
- package/dist/discover-D4TPKo57.mjs +1 -0
- package/dist/{discover-D2PGT63u.mjs → discover-LaV0tbIu.mjs} +1 -1
- package/dist/{dispatch-DrTTk8Xg.mjs → dispatch-BAbbn3jg.mjs} +6 -6
- package/dist/{domain-CZGxPv9u.mjs → domain-BAdwm-QS.mjs} +3 -3
- package/dist/{drizzle-CF84FOVM.mjs → drizzle-BQfyvQKX.mjs} +13 -2
- package/dist/{email-DzyNVuoU.mjs → email-MwjA7kaL.mjs} +11 -12
- package/dist/{email-cloudflare-DfG6UEMm.mjs → email-cloudflare-etpKiITL.mjs} +7 -10
- package/dist/{entry-ehmBvs5w.mjs → entry-B_0IhV64.mjs} +1 -1
- package/dist/{env-Nx3yf50r.mjs → env-B163-G1s.mjs} +5 -5
- package/dist/{env-types-DS2_y4X8.mjs → env-types-GRchm5dw.mjs} +1 -1
- package/dist/{env-validation-BT7z-qpQ.mjs → env-validation-CuGfWRJd.mjs} +1 -1
- package/dist/{env-validation-DYxjz_Wo.mjs → env-validation-D_KyMdab.mjs} +2 -2
- package/dist/{fetch-BPCYVi3H.d.mts → fetch-CUX0tB78.d.mts} +16 -3
- package/dist/fetch-CtESUYWd.mjs +26 -0
- package/dist/{fetch-error-Dj3crt0e.mjs → fetch-error-Bw0n-IY-.mjs} +1 -1
- package/dist/{fetch-stream-PGgz4uGz.mjs → fetch-stream-BspOeTAI.mjs} +1 -1
- package/dist/{fetch-stream-obvZ7fvO.d.mts → fetch-stream-DfkAzZf-.d.mts} +1 -1
- package/dist/{gen-CufHEf42.mjs → gen-CYN3wiov.mjs} +26 -20
- package/dist/gen-Cf-RBVg4.mjs +1 -0
- package/dist/{generate-Dat0UTry.mjs → generate-B1m4Cm4n.mjs} +1 -1
- package/dist/{generate-ClI89brV.mjs → generate-DkEb9rL-.mjs} +1 -1
- package/dist/{github-cmd-FU8EjFyU.mjs → github-cmd-C8QsnJQs.mjs} +2 -2
- package/dist/{handler-_PqY82xe.d.mts → handler-D5K_yP6T.d.mts} +1 -1
- package/dist/{headers-Di1FsD3e.mjs → headers-Bi4bOAwp.mjs} +1 -1
- package/dist/{help-BT2hovNI.mjs → help-B2sFwn9b.mjs} +60 -15
- package/dist/help-w-xlx_kq.mjs +1 -0
- package/dist/{inbound-brj2-TM5.d.mts → inbound-Da7XsjH3.d.mts} +6 -12
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +139 -126
- package/dist/{info-l249eUdH.mjs → info-Bxunp14X.mjs} +4 -4
- package/dist/{init-D0A6M64Q.mjs → init-DGFQMnbk.mjs} +51 -28
- package/dist/{link-WMoJFf4i.mjs → link-CwrfpjIM.mjs} +3 -3
- package/dist/{list-CQ2EQEHL.mjs → list-hKoW5z-b.mjs} +3 -3
- package/dist/{live-DJONVlQK.d.mts → live-JheIDZKc.d.mts} +1 -1
- package/dist/{local-d1-BxvQYEFi.mjs → local-d1-CpaPbd_L.mjs} +5 -5
- package/dist/login-08mBwZfI.mjs +1 -0
- package/dist/{login-C2T1oVG-.mjs → login-f2eu2TQh.mjs} +3 -3
- package/dist/{logs-DnC1d7xB.mjs → logs-CEWqD-_B.mjs} +3 -3
- package/dist/{migrate-BDIprOYd.mjs → migrate-DYfdWBXt.mjs} +5 -5
- package/dist/migrate-Di-4EuoE.mjs +1 -0
- package/dist/{neon-n74ta1Pr.mjs → neon-DTZr7Bu7.mjs} +0 -1
- package/dist/nitro.mjs +3 -3
- package/dist/{node-cPadMgUO.mjs → node-uN8_zxJr.mjs} +15 -9
- package/dist/operator-cmd-Bv20yLu2.mjs +1 -0
- package/dist/{operator-cmd-DHieWtFp.mjs → operator-cmd-DCr_QGMH.mjs} +4 -4
- package/dist/{output-Ba6ZbrzY.mjs → output-CKguMgr7.mjs} +13 -1
- package/dist/pages/client.d.mts +2 -2
- package/dist/pages/client.mjs +18 -5
- package/dist/pages/index.d.mts +2 -2
- package/dist/pages/index.mjs +5 -5
- package/dist/pages/islands-plugin.d.mts +44 -6
- package/dist/pages/islands-plugin.mjs +99 -28
- package/dist/pages/protocol.d.mts +2 -2
- package/dist/pages/protocol.mjs +1 -1
- package/dist/pages/serialize.d.mts +2 -2
- package/dist/pages/serialize.mjs +1 -1
- package/dist/{platform-args-CaCL_1Ch.mjs → platform-args-B7ke06up.mjs} +1 -4
- package/dist/platform-args-B_LrqEZB.mjs +1 -0
- package/dist/{platform-auth-config-Z16-I8nT.mjs → platform-auth-config-qGvEuns3.mjs} +5 -5
- package/dist/{platform-auth-protection-BXwZiJSF.mjs → platform-auth-protection-CyLcD6ot.mjs} +3 -3
- package/dist/{platform-auth-recovery-CXjfqyOv.mjs → platform-auth-recovery-B2LKI8V2.mjs} +3 -3
- package/dist/{platform-cmd-PT4YwMLM.mjs → platform-cmd-B2ec5eFg.mjs} +1 -1
- package/dist/{platform-cmd-DaAOiWTl.mjs → platform-cmd-CX7phm7V.mjs} +6 -6
- package/dist/{platform-domain-CxpvUeo0.mjs → platform-domain-DDNK2y-4.mjs} +3 -3
- package/dist/{platform-lifecycle-DBiS0cJd.mjs → platform-lifecycle-3CR98Tg2.mjs} +399 -40
- package/dist/{platform-lifecycle-u9pMOvxC.mjs → platform-lifecycle-CWc5gr6c.mjs} +1 -1
- package/dist/{platform-management-DvBS83rC.mjs → platform-management-DAE6g2QU.mjs} +1 -1
- package/dist/{platform-management-DhEFdQAf.mjs → platform-management-o3LCCeE4.mjs} +40 -4
- package/dist/{platform-plans-config-BWn1S2Rv.mjs → platform-plans-config-CBMZxCep.mjs} +1 -1
- package/dist/{platform-recovery-BUGOB4RC.mjs → platform-recovery-Dmsg7lWA.mjs} +2 -2
- package/dist/{platform-setup-YvN9VQXV.mjs → platform-setup-hFbnWAVQ.mjs} +1 -1
- package/dist/{plugin-inference-DsARdQKE.mjs → plugin-inference-Bekzjuqw.mjs} +2 -2
- package/dist/{prepare-DEB5SeVJ.mjs → prepare-DepAGBcV.mjs} +9 -9
- package/dist/prepare-EVEbQ9n2.mjs +1 -0
- package/dist/{prepare-PQCgsny0.mjs → prepare-HKo7Rh5V.mjs} +2 -2
- package/dist/{project-cmd-DVatD8Ev.mjs → project-cmd-8ylYGx-O.mjs} +18 -18
- package/dist/{project-paths-DMvEeSau.mjs → project-paths-DGu_QZ_Q.mjs} +1 -1
- package/dist/{project-team-DJrWEAG1.mjs → project-team-Bvpl78we.mjs} +2 -2
- package/dist/{project-token-CBgLBuL6.mjs → project-token-QWHoJH2t.mjs} +2 -2
- package/dist/{project-tsconfig-bveqhlYA.mjs → project-tsconfig-Itv1f4WC.mjs} +1 -1
- package/dist/{project-zero-trust-92gLtZ25.mjs → project-zero-trust-8tJ-RFvu.mjs} +2 -2
- package/dist/{protocol-4H7V_3Os.d.mts → protocol-Ssc_LhHj.d.mts} +2 -2
- package/dist/{protocol-RNP0u7UY.mjs → protocol-bAUUkx70.mjs} +1 -1
- package/dist/{providers-BXuhmuub.mjs → providers-BUHwJlmM.mjs} +10 -1
- package/dist/provision-BgXFDv0d.mjs +1 -0
- package/dist/{provision-BnSSkiED.mjs → provision-DZKYCEJg.mjs} +66 -66
- package/dist/r2-conditions-B8xUgJRc.mjs +61 -0
- package/dist/{requests-7W1Pygt2.mjs → requests-Vk5Zyhcy.mjs} +2 -2
- package/dist/{rollback-BcASVnwP.mjs → rollback-CH4yMQys.mjs} +9 -8
- package/dist/{runner-CabsQ-iM.mjs → runner-3uGC-oLF.mjs} +9 -7
- package/dist/{runner-So9mYfcm.mjs → runner-WCdfeI0q.mjs} +1 -1
- package/dist/{runner-mysql-BhRaONkO.mjs → runner-mysql-BWmbk5IE.mjs} +1 -1
- package/dist/{runner-mysql-DWwE8jKi.mjs → runner-mysql-BcHnLUuM.mjs} +1 -1
- package/dist/{runner-pg-_Xncr3H5.mjs → runner-pg-Cgp-cr_p.mjs} +1 -1
- package/dist/{runner-pg-BRemq_GX.mjs → runner-pg-Cr3qrqi4.mjs} +1 -1
- package/dist/runtime/ai.d.mts +4 -0
- package/dist/runtime/ai.mjs +2 -37
- package/dist/runtime/better-auth-mysql.d.mts +1 -1
- package/dist/runtime/better-auth-mysql.mjs +2 -2
- package/dist/runtime/better-auth-pg.d.mts +1 -1
- package/dist/runtime/better-auth-pg.mjs +2 -2
- package/dist/runtime/better-auth.d.mts +1 -1
- package/dist/runtime/better-auth.mjs +2 -2
- package/dist/runtime/client-react.d.mts +2 -2
- package/dist/runtime/client-react.mjs +3 -3
- package/dist/runtime/client-solid.d.mts +2 -2
- package/dist/runtime/client-solid.mjs +3 -3
- package/dist/runtime/client-svelte.d.mts +2 -2
- package/dist/runtime/client-svelte.mjs +3 -3
- package/dist/runtime/client-vue.d.mts +2 -2
- package/dist/runtime/client-vue.mjs +3 -3
- package/dist/runtime/client.d.mts +2 -2
- package/dist/runtime/client.mjs +3 -3
- package/dist/runtime/email/testing.d.mts +1 -1
- package/dist/runtime/email.d.mts +2 -3
- package/dist/runtime/email.mjs +2 -3
- package/dist/runtime/fetch-server.d.mts +8 -0
- package/dist/runtime/fetch-server.mjs +30 -0
- package/dist/runtime/fetch-stream.d.mts +2 -2
- package/dist/runtime/fetch-stream.mjs +2 -2
- package/dist/runtime/fetch.d.mts +2 -2
- package/dist/runtime/fetch.mjs +3 -3
- package/dist/runtime/handler.d.mts +1 -1
- package/dist/runtime/live-client.d.mts +1 -1
- package/dist/runtime/live.d.mts +1 -1
- package/dist/runtime/migration-handler-mysql.mjs +4 -4
- package/dist/runtime/migration-handler-pg.mjs +9 -1
- package/dist/runtime/remote/binding-handler.mjs +25 -25
- package/dist/runtime/remote/index.d.mts +3 -0
- package/dist/runtime/remote/index.mjs +86 -23
- package/dist/runtime/routing.d.mts +2 -2
- package/dist/runtime/routing.mjs +1 -1
- package/dist/runtime/sse-client.d.mts +4 -0
- package/dist/runtime/validator.d.mts +1 -1
- package/dist/runtime/ws-server.d.mts +2 -2
- package/dist/runtime/ws.d.mts +1 -1
- package/dist/{scan-C0BMdmEd.mjs → scan-D2-FcLHs.mjs} +13 -5
- package/dist/{secret-bg73f1Ge.mjs → secret-wr6Sn4Xa.mjs} +4 -4
- package/dist/serialize-DtR8Vwa_.d.mts +18 -0
- package/dist/serialize-YHvlcG3Q.mjs +31 -0
- package/dist/{subcommand-prompt-Bm3ZlYgA.mjs → subcommand-prompt-CNZc4XUd.mjs} +1 -1
- package/dist/{types-BAp5AEBU.d.mts → types-7AIz0OZu.d.mts} +1 -1
- package/dist/{validate-CheZGRE7.mjs → validate-CnZPMq4q.mjs} +22 -17
- package/dist/validate-D7Wn8PUX.mjs +1 -0
- package/dist/{version-metadata-DIrqEHQo.mjs → version-metadata-B1Bm2wSq.mjs} +1 -1
- package/dist/{wrangler-BYs07Rxy.mjs → wrangler-C9XSzrju.mjs} +3 -3
- package/dist/wrangler-DAdxHEzh.mjs +1 -0
- package/dist/{wrapper-CwhpNWtH.mjs → wrapper-DGsYwNi6.mjs} +6 -4
- package/dist/{ws-aKVYB-fA.d.mts → ws-nnFnAyQb.d.mts} +6 -1
- package/docs/guide/auth.md +1 -1
- package/docs/guide/database/d1.md +2 -2
- package/docs/guide/database/mysql.md +1 -1
- package/docs/guide/deployment.md +2 -0
- package/docs/guide/edge/headers.md +10 -2
- package/docs/guide/edge/revalidation.md +2 -0
- package/docs/guide/email/receiving.md +1 -1
- package/docs/guide/email/sending.md +3 -3
- package/docs/guide/pages-routing/islands.md +2 -2
- package/docs/guide/pages-routing/markdown.md +3 -1
- package/docs/guide/platform/administration/connected-apps.md +18 -2
- package/docs/guide/platform/administration/email.md +7 -1
- package/docs/guide/platform/installation/ci.md +2 -0
- package/docs/guide/platform/installation/credentials.md +23 -5
- package/docs/guide/platform/installation/maintenance.md +32 -2
- package/docs/guide/platform/installation/setup.md +1 -1
- package/docs/guide/remote-dev.md +2 -0
- package/docs/guide/typed-fetch.md +1 -1
- package/docs/guide/websockets.md +2 -2
- package/docs/index.md +78 -22
- package/docs/integrations/cloudflare.md +1 -1
- package/docs/integrations/frameworks/tanstack-start.md +25 -0
- package/docs/reference/api/deploy.md +35 -3
- package/docs/reference/api/pages.md +7 -5
- package/docs/reference/api.md +2 -0
- package/docs/reference/cli/database.md +22 -5
- package/docs/reference/cli/deploy.md +12 -10
- package/docs/reference/cli/email.md +1 -1
- package/docs/reference/cli/generate.md +1 -1
- package/docs/reference/cli/platform-installation.md +4 -2
- package/docs/reference/cli/project.md +8 -4
- package/docs/reference/cli.md +2 -1
- package/docs/reference/config.md +12 -2
- package/package.json +8 -7
- package/dist/cf-build-output-BU3hqdHu.mjs +0 -1
- package/dist/client-B60PwCC4.mjs +0 -1
- package/dist/collect-Cae8A7Zr.mjs +0 -1
- package/dist/deploy-9lgfhrXS.mjs +0 -2
- package/dist/discover-ClzFSwns.mjs +0 -1
- package/dist/fetch-sAcwjzLO.mjs +0 -18
- package/dist/gen-sXyp5DFO.mjs +0 -1
- package/dist/help-i2YGGnTH.mjs +0 -1
- package/dist/login-XD844Xs-.mjs +0 -1
- package/dist/migrate-BRwU-blY.mjs +0 -1
- package/dist/operator-cmd-D6gnZsnK.mjs +0 -1
- package/dist/platform-args-B0HeTh0C.mjs +0 -1
- package/dist/prepare-CYT6tAzD.mjs +0 -1
- package/dist/r2-conditions-D1Wk8i7b.mjs +0 -30
- package/dist/serialize-BtQyaYoC.mjs +0 -20
- package/dist/serialize-CfSwWfF2.d.mts +0 -10
- package/dist/validate-BQFdf0Pi.mjs +0 -1
|
@@ -4,12 +4,12 @@ import { S as writePendingInstallationSecrets, a as latestPlatformWorkerCutoverG
|
|
|
4
4
|
import { t as cfAccessHeaders } from "./cf-access-BM9G0lhO.mjs";
|
|
5
5
|
import { t as ensurePlatformAccessToken } from "./cf-access-CWP4avfP.mjs";
|
|
6
6
|
import { A as confirm, H as outro, K as select, L as log, U as password, X as text$1, tt as isCancel, z as multiselect } from "./dist-BVdsO7Py.mjs";
|
|
7
|
-
import { f as import_picocolors, l as formatUrl, m as printSuccess, n as cliCommandName, p as note, r as createSpinner, u as getErrorMessage } from "./output-
|
|
8
|
-
import { l as resolveCloudflareOperationArgv } from "./cloudflare-process-
|
|
9
|
-
import {
|
|
10
|
-
import { t as parsePlatformArgs } from "./platform-args-
|
|
11
|
-
import { o as runCloudflareAuthCommand } from "./cloudflare-auth-
|
|
12
|
-
import { a as platformManagementSetupPage, c as platformSetupLink, i as platformInstallCommandArguments, l as platformSetupPages, n as formatPlatformSetupPlan, o as platformPromptAnswer, r as openPlatformSetupPage, s as platformSetupFieldHelp, t as formatPlatformInstallCommand } from "./platform-setup-
|
|
7
|
+
import { f as import_picocolors, l as formatUrl, m as printSuccess, n as cliCommandName, p as note, r as createSpinner, u as getErrorMessage } from "./output-CKguMgr7.mjs";
|
|
8
|
+
import { l as resolveCloudflareOperationArgv } from "./cloudflare-process-CZJ4viYl.mjs";
|
|
9
|
+
import { o as createDefaultRunWrangler, v as resolvePinnedApiBaseUrl } from "./provision-DZKYCEJg.mjs";
|
|
10
|
+
import { t as parsePlatformArgs } from "./platform-args-B7ke06up.mjs";
|
|
11
|
+
import { o as runCloudflareAuthCommand } from "./cloudflare-auth-DSvBc1Gu.mjs";
|
|
12
|
+
import { a as platformManagementSetupPage, c as platformSetupLink, i as platformInstallCommandArguments, l as platformSetupPages, n as formatPlatformSetupPlan, o as platformPromptAnswer, r as openPlatformSetupPage, s as platformSetupFieldHelp, t as formatPlatformInstallCommand } from "./platform-setup-hFbnWAVQ.mjs";
|
|
13
13
|
import { copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
15
|
import { isRecord } from "@void/deploy-core";
|
|
@@ -19,6 +19,7 @@ import { tmpdir } from "node:os";
|
|
|
19
19
|
import { stripVTControlCharacters } from "node:util";
|
|
20
20
|
import { cloudflareCommandDiagnostic, encodeCloudflareVersionMessage, parseCloudflareVersionMessage, readCloudflareTriggerConfig, readCloudflareVersionMigrationTag, stabilizeCloudflareVersionTriggers } from "@void/deploy-cloudflare";
|
|
21
21
|
import { createServer, request } from "node:http";
|
|
22
|
+
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
22
23
|
import { readFile } from "node:fs/promises";
|
|
23
24
|
import { PLATFORM_ADMIN_ASSETS_DIRECTORY, platformDatabaseSchemaDigest, resolvePlatformRuntime } from "@void/platform/installer";
|
|
24
25
|
import { request as request$1 } from "node:https";
|
|
@@ -45,12 +46,29 @@ var PlatformWorkerRoutesChangedError = class extends Error {
|
|
|
45
46
|
this.name = "PlatformWorkerRoutesChangedError";
|
|
46
47
|
}
|
|
47
48
|
};
|
|
49
|
+
/**
|
|
50
|
+
* The runtime token cannot read the shared email zone. The operator can add
|
|
51
|
+
* the permission to the same token, so callers keep its saved value.
|
|
52
|
+
*/
|
|
53
|
+
var PlatformRuntimeTokenEmailPermissionError = class extends Error {
|
|
54
|
+
/** Cloudflare answered HTTP 401 at least once: it did not accept the token. */
|
|
55
|
+
tokenNotValid;
|
|
56
|
+
constructor(message, tokenNotValid, options) {
|
|
57
|
+
super(message, options);
|
|
58
|
+
this.name = "PlatformRuntimeTokenEmailPermissionError";
|
|
59
|
+
this.tokenNotValid = tokenNotValid;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
48
62
|
async function verifyPlatformRuntimeTokenPermissions(client, input) {
|
|
49
63
|
try {
|
|
50
64
|
await client.listHyperdriveConfigs(input.accountId);
|
|
51
65
|
} catch (error) {
|
|
52
66
|
throw runtimeTokenPreflightError("Account → Hyperdrive → Write", error);
|
|
53
67
|
}
|
|
68
|
+
if (input.emailZoneId) await verifyPlatformRuntimeTokenEmailPermissions(client, {
|
|
69
|
+
accountId: input.accountId,
|
|
70
|
+
zoneId: input.emailZoneId
|
|
71
|
+
});
|
|
54
72
|
if (!input.zoneId) return;
|
|
55
73
|
const probeUrl = `https://${input.applicationDomain}/.well-known/void/runtime-token-preflight-${randomUUID()}`;
|
|
56
74
|
try {
|
|
@@ -67,6 +85,37 @@ async function verifyPlatformRuntimeTokenPermissions(client, input) {
|
|
|
67
85
|
throw runtimeTokenPreflightError("Zone → SSL and Certificates → Edit", error);
|
|
68
86
|
}
|
|
69
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Shared email setup uses the runtime token after the platform pauses traffic.
|
|
90
|
+
* Read-only requests find a missing Email Routing permission before that. A
|
|
91
|
+
* read cannot prove Edit access. Email Sending is not checked, because its
|
|
92
|
+
* answer depends on the account plan.
|
|
93
|
+
*/
|
|
94
|
+
async function verifyPlatformRuntimeTokenEmailPermissions(client, input) {
|
|
95
|
+
const zone = `/zones/${encodeURIComponent(input.zoneId)}`;
|
|
96
|
+
const probes = [
|
|
97
|
+
["Zone → Zone → Read", zone],
|
|
98
|
+
["Zone → Zone Settings → Edit", `${zone}/email/routing`],
|
|
99
|
+
["Zone → Email Routing Rules → Edit", `${zone}/email/routing/rules?per_page=5`],
|
|
100
|
+
["Account → Email Routing Addresses → Edit", `/accounts/${encodeURIComponent(input.accountId)}/email/routing/addresses?per_page=5`]
|
|
101
|
+
];
|
|
102
|
+
const missing = [];
|
|
103
|
+
let denial;
|
|
104
|
+
let tokenNotValid = false;
|
|
105
|
+
for (const [permission, path] of probes) try {
|
|
106
|
+
await client.request(path);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error instanceof PlatformCloudflareApiError && (error.status === 401 || error.status === 403)) {
|
|
109
|
+
missing.push(permission);
|
|
110
|
+
denial ??= error;
|
|
111
|
+
tokenNotValid ||= error.status === 401;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (denial) {
|
|
115
|
+
const denied = `Cloudflare denied: ${missing.join(", ")} (HTTP ${denial.status}).`;
|
|
116
|
+
throw new PlatformRuntimeTokenEmailPermissionError(input.savedToken ? `platform: The runtime API token saved on this machine cannot use platform email. ${denied} Void checked this token because VOID_PLATFORM_RUNTIME_CLOUDFLARE_API_TOKEN is not set. If the platform uses a different runtime token, set VOID_PLATFORM_RUNTIME_CLOUDFLARE_API_TOKEN to that token, and Void checks that token instead. Otherwise, check that the zone permissions of the saved token include the email zone ${input.zoneId}. To add a missing permission, edit the token in the Cloudflare dashboard. The token value stays the same. Then run the command again.` : `platform: The runtime API token cannot use platform email. ${denied} Check that the token is valid and that its zone permissions include the email zone ${input.zoneId}. To add a missing permission, edit the token in the Cloudflare dashboard. The token value stays the same. Or set VOID_PLATFORM_RUNTIME_CLOUDFLARE_API_TOKEN to a valid token that has these permissions. Then run the command again.`, tokenNotValid, { cause: denial });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
70
119
|
function runtimeTokenPreflightError(permission, cause) {
|
|
71
120
|
const status = cause instanceof PlatformCloudflareApiError ? cause.status : null;
|
|
72
121
|
const message = status === 401 || status === 403 ? `Cloudflare denied the runtime-token check (HTTP ${status}). Check that the token is valid, scoped to this account, and includes ${permission}.` : status === 429 ? `Cloudflare rate-limited the runtime-token check for ${permission} (HTTP 429). Retry shortly; this does not mean the token is missing a permission.` : `Could not complete the runtime-token check for ${permission}${status === null ? "" : ` (Cloudflare HTTP ${status})`}. Retry the check; this failure does not establish that a permission is missing.`;
|
|
@@ -535,6 +584,22 @@ var PlatformCloudflareClient = class PlatformCloudflareClient {
|
|
|
535
584
|
for (const binding of settings.bindings ?? []) if (binding.type === "plain_text" && typeof binding.name === "string" && typeof binding.text === "string") bindings[binding.name] = binding.text;
|
|
536
585
|
return bindings;
|
|
537
586
|
}
|
|
587
|
+
/**
|
|
588
|
+
* Where the last change to a Worker came from, for example `cf_cli`, `dash`
|
|
589
|
+
* (Cloudflare dashboard) or `api` (Workers API). Null when the Worker does
|
|
590
|
+
* not exist or Cloudflare does not report it.
|
|
591
|
+
*/
|
|
592
|
+
async getWorkerLastDeployedFrom(accountId, workerName) {
|
|
593
|
+
let service;
|
|
594
|
+
try {
|
|
595
|
+
service = await this.request(`/accounts/${encodeURIComponent(accountId)}/workers/services/${encodeURIComponent(workerName)}`);
|
|
596
|
+
} catch (error) {
|
|
597
|
+
if (error instanceof PlatformCloudflareApiError && error.status === 404) return null;
|
|
598
|
+
throw error;
|
|
599
|
+
}
|
|
600
|
+
const source = service?.default_environment?.script?.last_deployed_from;
|
|
601
|
+
return typeof source === "string" && source !== "" ? source : null;
|
|
602
|
+
}
|
|
538
603
|
async deleteKvValue(accountId, namespaceId, key) {
|
|
539
604
|
try {
|
|
540
605
|
await this.request(`/accounts/${encodeURIComponent(accountId)}/storage/kv/namespaces/${encodeURIComponent(namespaceId)}/values/${encodeURIComponent(key)}`, { method: "DELETE" });
|
|
@@ -3645,8 +3710,30 @@ function createPlatformHealthProbeToken(ownershipNonce) {
|
|
|
3645
3710
|
//#endregion
|
|
3646
3711
|
//#region src/cli/platform-installer-errors.ts
|
|
3647
3712
|
const ANALYTICS_ENGINE_NOT_ENABLED = 10089;
|
|
3713
|
+
const UPLOAD_CONFLICT = "Aborting the upload operation because of conflicts";
|
|
3714
|
+
/** Why the Cloudflare CLI stopped an upload, and what to do. Null for other failures. */
|
|
3715
|
+
function uploadConflictMessage(result, operation) {
|
|
3716
|
+
const output = stripVTControlCharacters(`${result.stdout}\n${result.stderr}`);
|
|
3717
|
+
if (!output.includes(UPLOAD_CONFLICT)) return null;
|
|
3718
|
+
const lines = output.split(/\r?\n/).map((line) => line.replace(/^[\s▲│]+/, "").trim());
|
|
3719
|
+
const outsideChange = lines.find((line) => line.includes("last updated via the script API") || line.includes("set via the Cloudflare Dashboard"));
|
|
3720
|
+
if (outsideChange) return `platform: The Cloudflare CLI did not ${operation}: ${outsideChange.replace(/:$/, ".")} This Worker was changed outside Void. Run the same command in a terminal. Void then lists the changes and asks you before it replaces them.`;
|
|
3721
|
+
const secretNames = [...(lines.find((line) => / with (?:an )?existing remote secrets?\./.test(line))?.split(" conflict")[0] ?? "").matchAll(/`[^`]+`/g)].map(([name]) => name);
|
|
3722
|
+
if (secretNames.length === 1) return `platform: The Cloudflare CLI did not ${operation}: the Worker has a secret with the same name as a value that Void sets: ${secretNames[0]}. Delete that secret from the Worker in the Cloudflare dashboard, then run the command again.`;
|
|
3723
|
+
if (secretNames.length > 1) return `platform: The Cloudflare CLI did not ${operation}: the Worker has secrets with the same names as values that Void sets: ${new Intl.ListFormat("en").format(secretNames)}. Delete those secrets from the Worker in the Cloudflare dashboard, then run the command again.`;
|
|
3724
|
+
const workflow = lines.findIndex((line) => line.includes("already exist and belong to different workers"));
|
|
3725
|
+
if (workflow !== -1) {
|
|
3726
|
+
const owners = lines.slice(workflow + 1);
|
|
3727
|
+
const end = owners.findIndex((line) => !line.startsWith("- "));
|
|
3728
|
+
const workflows = owners.slice(0, end === -1 ? void 0 : end);
|
|
3729
|
+
return `platform: The Cloudflare CLI did not ${operation}: ${[lines[workflow], ...workflows].join(" ")}. ${workflows.length > 1 ? "Other Workers own these workflows. Delete each workflow, or rename it in the configuration of the Worker that owns it." : "Another Worker owns this workflow. Delete the workflow, or rename it in the configuration of that Worker."} Then run the command again.`;
|
|
3730
|
+
}
|
|
3731
|
+
return `platform: The Cloudflare CLI did not ${operation}. It stopped the upload because of a conflict that it could not confirm without a terminal. Fix the conflict, then run the command again.`;
|
|
3732
|
+
}
|
|
3648
3733
|
function assertCleanPlatformWrangler(result, operation) {
|
|
3649
3734
|
if (result.status !== 0 || result.signal || result.error) {
|
|
3735
|
+
const conflict = uploadConflictMessage(result, operation);
|
|
3736
|
+
if (conflict) throw new Error(conflict);
|
|
3650
3737
|
const diagnostic = cloudflareCommandDiagnostic({
|
|
3651
3738
|
...result,
|
|
3652
3739
|
stderr: result.stderr.trim() || result.errors?.map((error) => error.message).join("\n") || ""
|
|
@@ -3675,6 +3762,36 @@ async function readActivePlatformWorkerVersion(configPath, accountId, workerName
|
|
|
3675
3762
|
if (active.length !== 1 || typeof active[0].version_id !== "string") return null;
|
|
3676
3763
|
return active[0].version_id;
|
|
3677
3764
|
}
|
|
3765
|
+
/**
|
|
3766
|
+
* The active version in a Cloudflare API answer for the deployments of a
|
|
3767
|
+
* platform Worker. deployPlatformWorker continues only when the latest
|
|
3768
|
+
* deployment sends all traffic to one version (deploymentRunsOnlyVersion).
|
|
3769
|
+
* `split` is each other answer, for example a gradual deployment.
|
|
3770
|
+
*/
|
|
3771
|
+
function readActivePlatformWorkerDeployment(response) {
|
|
3772
|
+
const deployments = response && typeof response === "object" && !Array.isArray(response) ? response.deployments : null;
|
|
3773
|
+
if (!Array.isArray(deployments)) return { kind: "malformed" };
|
|
3774
|
+
if (deployments.length === 0) return { kind: "split" };
|
|
3775
|
+
const latest = deployments[0];
|
|
3776
|
+
const versions = latest && typeof latest === "object" ? latest.versions : null;
|
|
3777
|
+
if (!Array.isArray(versions) || versions.some((version) => !version || typeof version !== "object" || typeof version.version_id !== "string" || !Number.isFinite(Number(version.percentage)))) return { kind: "malformed" };
|
|
3778
|
+
const [only] = versions;
|
|
3779
|
+
return versions.length === 1 && only && Number(only.percentage) === 100 ? {
|
|
3780
|
+
kind: "active",
|
|
3781
|
+
versionId: only.version_id
|
|
3782
|
+
} : { kind: "split" };
|
|
3783
|
+
}
|
|
3784
|
+
/**
|
|
3785
|
+
* Whether a version of a platform Worker has Void's record of its triggers.
|
|
3786
|
+
* This is the rule of the upgrade: it refuses a version without the record,
|
|
3787
|
+
* for example a version deployed outside Void.
|
|
3788
|
+
*/
|
|
3789
|
+
async function platformWorkerVersionHasTriggerRecord(readCloudflare, accountId, workerName, versionId) {
|
|
3790
|
+
const version = await readCloudflare(`/accounts/${encodeURIComponent(accountId)}/workers/scripts/${encodeURIComponent(workerName)}/versions/${encodeURIComponent(versionId)}`);
|
|
3791
|
+
const annotations = version && typeof version === "object" ? version.annotations : null;
|
|
3792
|
+
const message = annotations && typeof annotations === "object" ? annotations["workers/message"] : null;
|
|
3793
|
+
return parseCloudflareVersionMessage(typeof message === "string" ? message : null)?.schema === 2;
|
|
3794
|
+
}
|
|
3678
3795
|
async function readPlatformWorkerDeployments(configPath, accountId, workerName, runner = runPlatformWrangler) {
|
|
3679
3796
|
const result = await runner({
|
|
3680
3797
|
type: "deployments.list",
|
|
@@ -3753,15 +3870,15 @@ function readPlatformWorkerOwnershipMarker(config) {
|
|
|
3753
3870
|
if (typeof marker !== "string" || marker === "") throw new Error("platform: Platform Worker config is missing its ownership marker.");
|
|
3754
3871
|
return marker;
|
|
3755
3872
|
}
|
|
3756
|
-
async function readActivePlatformWorkerSnapshot(configPath, accountId, workerName, expectedOwnershipMarker, runner = runPlatformWrangler) {
|
|
3873
|
+
async function readActivePlatformWorkerSnapshot(configPath, accountId, workerName, expectedOwnershipMarker, runner = runPlatformWrangler, unrecordedTriggerConfig) {
|
|
3757
3874
|
const readActiveVersion = () => readActivePlatformWorkerVersion(configPath, accountId, workerName, runner);
|
|
3758
3875
|
const versionId = await readActiveVersion();
|
|
3759
3876
|
if (!versionId) throw new Error(`platform: Existing Worker ${workerName} has no single active production version.`);
|
|
3760
3877
|
return await readPlatformWorkerVersionSnapshot(configPath, accountId, workerName, expectedOwnershipMarker, versionId, runner, async () => {
|
|
3761
3878
|
if (await readActiveVersion() !== versionId) throw new Error(`platform: Worker ${workerName} changed concurrently while its active version was inspected.`);
|
|
3762
|
-
});
|
|
3879
|
+
}, unrecordedTriggerConfig);
|
|
3763
3880
|
}
|
|
3764
|
-
async function readPlatformWorkerVersionSnapshot(configPath, accountId, workerName, expectedOwnershipMarker, versionId, runner, validateCurrentVersion) {
|
|
3881
|
+
async function readPlatformWorkerVersionSnapshot(configPath, accountId, workerName, expectedOwnershipMarker, versionId, runner, validateCurrentVersion, unrecordedTriggerConfig) {
|
|
3765
3882
|
const result = await runner({
|
|
3766
3883
|
type: "versions.view",
|
|
3767
3884
|
versionId,
|
|
@@ -3779,6 +3896,11 @@ async function readPlatformWorkerVersionSnapshot(configPath, accountId, workerNa
|
|
|
3779
3896
|
const annotations = value.annotations;
|
|
3780
3897
|
const message = annotations && typeof annotations === "object" && typeof annotations["workers/message"] === "string" ? annotations["workers/message"] ?? null : null;
|
|
3781
3898
|
const metadata = parseCloudflareVersionMessage(message);
|
|
3899
|
+
if (metadata?.schema !== 2 && unrecordedTriggerConfig) return {
|
|
3900
|
+
migrationTag: readCloudflareVersionMigrationTag(value),
|
|
3901
|
+
triggerConfig: unrecordedTriggerConfig,
|
|
3902
|
+
versionId
|
|
3903
|
+
};
|
|
3782
3904
|
if (metadata?.schema !== 2) throw new Error(`platform: Active Worker ${workerName} predates safe trigger snapshots. Refusing to upgrade because its routes, cron, and queue consumers could not be restored after a failed cutover.`);
|
|
3783
3905
|
const migrationTag = readCloudflareVersionMigrationTag(value);
|
|
3784
3906
|
return {
|
|
@@ -4383,7 +4505,7 @@ async function deployPlatformWorker(config, secrets, options) {
|
|
|
4383
4505
|
}
|
|
4384
4506
|
}
|
|
4385
4507
|
if (options.workerExisted) {
|
|
4386
|
-
const previous = await readActivePlatformWorkerSnapshot(configPath, accountId, workerName, readPlatformWorkerOwnershipMarker(config), readRunner);
|
|
4508
|
+
const previous = await readActivePlatformWorkerSnapshot(configPath, accountId, workerName, readPlatformWorkerOwnershipMarker(config), readRunner, options.replaceOutsideChanges ? previousTriggers : void 0);
|
|
4387
4509
|
previousVersionId = previous.versionId;
|
|
4388
4510
|
const deployments = await readPlatformWorkerDeployments(configPath, accountId, workerName, readRunner);
|
|
4389
4511
|
if (!deploymentRunsOnlyVersion(deployments[0], previousVersionId)) throw new Error(`platform: Worker ${workerName} changed concurrently while its deployment lineage was inspected.`);
|
|
@@ -4559,6 +4681,37 @@ async function deployPlatformWorker(config, secrets, options) {
|
|
|
4559
4681
|
});
|
|
4560
4682
|
}
|
|
4561
4683
|
}
|
|
4684
|
+
/**
|
|
4685
|
+
* Upload a version of a platform Worker that was changed outside Void, and do
|
|
4686
|
+
* not deploy it. The Cloudflare CLI uses this terminal: it shows what the
|
|
4687
|
+
* upload replaces and asks the operator. After the operator agrees, later
|
|
4688
|
+
* uploads of this Worker work without a terminal again.
|
|
4689
|
+
*/
|
|
4690
|
+
async function uploadPlatformWorkerForReview(config, options) {
|
|
4691
|
+
const directory = mkdtempSync(join(tmpdir(), "void-platform-review-"));
|
|
4692
|
+
const workerName = String(config.name);
|
|
4693
|
+
const accountId = String(config.account_id);
|
|
4694
|
+
const readRunner = platformWorkerApiReadRunner(accountId, workerName, options.readCloudflare, options.runner);
|
|
4695
|
+
try {
|
|
4696
|
+
const { wranglerConfig } = isolatePlatformWorkerCustomDomains(config);
|
|
4697
|
+
const configPath = join(directory, "wrangler.json");
|
|
4698
|
+
const writeConfig = (value) => writeFileSync(configPath, `${JSON.stringify(value, null, 2)}\n`, { mode: 384 });
|
|
4699
|
+
writeConfig(withoutPlatformWorkerTrafficAttachments(wranglerConfig));
|
|
4700
|
+
const active = await readActivePlatformWorkerSnapshot(configPath, accountId, workerName, readPlatformWorkerOwnershipMarker(config), readRunner, readTriggerConfigFromObject(wranglerConfig));
|
|
4701
|
+
writeConfig(withoutCompletedPlatformWorkerMigrations(withoutPlatformWorkerTrafficAttachments(wranglerConfig), active.migrationTag));
|
|
4702
|
+
return await options.runner({
|
|
4703
|
+
type: "versions.upload",
|
|
4704
|
+
configPath,
|
|
4705
|
+
message: "Void: replace changes made outside Void",
|
|
4706
|
+
interactive: true
|
|
4707
|
+
}, accountId, directory, true);
|
|
4708
|
+
} finally {
|
|
4709
|
+
rmSync(directory, {
|
|
4710
|
+
force: true,
|
|
4711
|
+
recursive: true
|
|
4712
|
+
});
|
|
4713
|
+
}
|
|
4714
|
+
}
|
|
4562
4715
|
async function recoverFailedPlatformWorkerDeployment(input) {
|
|
4563
4716
|
const failures = [];
|
|
4564
4717
|
const attempt = async (label, operation) => {
|
|
@@ -4799,6 +4952,7 @@ async function uploadInstallationWorkers(input) {
|
|
|
4799
4952
|
preservedRoutes,
|
|
4800
4953
|
previousConfig: previousWorkerConfig,
|
|
4801
4954
|
previousPublicEndpoints,
|
|
4955
|
+
...dependencies.replaceOutsideChanges?.includes(action.name) ? { replaceOutsideChanges: true } : {},
|
|
4802
4956
|
runner: parallelWorkerUploads ? runParallelPinnedPlatformWrangler : runPinnedPlatformWrangler,
|
|
4803
4957
|
workerExisted: action.action !== "create"
|
|
4804
4958
|
});
|
|
@@ -4942,6 +5096,12 @@ async function verifyPlatformDeploymentExecutionDrain(apiUrl, healthProbeToken,
|
|
|
4942
5096
|
if (status?.protocolVersion !== 1 || status.installationId !== installationId || typeof status.admissionClosed !== "boolean" || !Number.isSafeInteger(status.pendingDeployments) || Number(status.pendingDeployments) < 0) throw new Error("platform: Deployment execution drain probe returned an invalid document.");
|
|
4943
5097
|
if (!status.admissionClosed || status.pendingDeployments !== 0) throw new Error("platform: Durable deployment operations are still admitted or unfinished. Keep the current runtime and retry this command after they finish.");
|
|
4944
5098
|
}
|
|
5099
|
+
const sharedEmailStepPermissions = /* @__PURE__ */ new Map([
|
|
5100
|
+
["routing_enable", "Zone → Zone Settings → Edit"],
|
|
5101
|
+
["subaddressing_ensure", "Zone → Zone Settings → Edit"],
|
|
5102
|
+
["inbound_probe", "Zone → Zone Settings → Edit"],
|
|
5103
|
+
["sending_onboard", "Account → Email Sending → Edit"]
|
|
5104
|
+
]);
|
|
4945
5105
|
async function bootstrapPlatformSharedEmail(apiUrl, healthProbeToken, fetcher = fetch) {
|
|
4946
5106
|
const deadline = Date.now() + 3e5;
|
|
4947
5107
|
let operationId = null;
|
|
@@ -5024,6 +5184,9 @@ async function bootstrapPlatformSharedEmail(apiUrl, healthProbeToken, fetcher =
|
|
|
5024
5184
|
if (typeof status?.failureDetail === "string" && safeDetails.includes(status.failureDetail)) {
|
|
5025
5185
|
details.push(`${status.failureDetail}.`);
|
|
5026
5186
|
if (currentStep === "inbound_probe" && status.failureDetail === mxDetail) details.push(`Enable Email Routing for ${domain} in the Cloudflare dashboard, then resume this installation.`);
|
|
5187
|
+
} else if (failureCode === "blocked" && currentStep && sharedEmailStepPermissions.has(currentStep)) {
|
|
5188
|
+
const permission = sharedEmailStepPermissions.get(currentStep);
|
|
5189
|
+
details.push(`This step needs ${permission} on the runtime API token. If the token does not have it, edit the token in the Cloudflare dashboard and add it. The token value stays the same. Or set VOID_PLATFORM_RUNTIME_CLOUDFLARE_API_TOKEN to a token that has it. Then resume this installation.`);
|
|
5027
5190
|
}
|
|
5028
5191
|
const detail = details.length ? ` ${details.join(" ")}` : "";
|
|
5029
5192
|
throw new Error(`platform: Shared email bootstrap did not reach inbound readiness at ${apiUrl} (HTTP ${response.status}).${detail} Traffic remains disabled.`);
|
|
@@ -5287,7 +5450,7 @@ async function verifyInstalledPlatformAccessProtection(input) {
|
|
|
5287
5450
|
}
|
|
5288
5451
|
const existingWorkers = input.plan.actions.filter((action) => action.kind === "worker" && action.action === "update").map((action) => action.name);
|
|
5289
5452
|
if (existingWorkers.length) {
|
|
5290
|
-
const { verifyProtectionWorkerOrigins } = await import("./platform-auth-protection-
|
|
5453
|
+
const { verifyProtectionWorkerOrigins } = await import("./platform-auth-protection-CyLcD6ot.mjs");
|
|
5291
5454
|
await verifyProtectionWorkerOrigins({
|
|
5292
5455
|
request: input.client.request.bind(input.client),
|
|
5293
5456
|
listWorkerDomains: input.client.listWorkerDomains.bind(input.client),
|
|
@@ -6447,6 +6610,7 @@ async function installPlatform(plan, secrets, existing, dependencies) {
|
|
|
6447
6610
|
const runtime = resolvedRuntime.manifest;
|
|
6448
6611
|
if (plan.deployment.appAccess && runtime.appAccessSetup !== 1) throw new Error("platform: This runtime does not support the installation’s app access setup.");
|
|
6449
6612
|
const hasEmailGatewayArtifact = runtime.artifacts.emailGateway !== void 0;
|
|
6613
|
+
if (existing?.steps.some((step) => step.key === "private-previews-initialized:v1") && runtime.privatePreviews !== 1) throw new Error("platform: This installation has private previews. Use a runtime with private preview support.");
|
|
6450
6614
|
if (runtime.emailProtocolVersion !== 1 && plan.deployment.capabilities.email) throw new Error("platform: This runtime cannot serve enabled platform email without email protocol version 1.");
|
|
6451
6615
|
if (runtime.emailProtocolVersion !== 1 && existing?.resources.some((resource) => resource.key === "email-gateway-worker" && resource.state === "ready")) throw new Error("platform: This runtime cannot replace an installed email gateway Worker. Use a runtime with email protocol version 1.");
|
|
6452
6616
|
const workerKeys = hasEmailGatewayArtifact ? [
|
|
@@ -6657,22 +6821,7 @@ async function installPlatform(plan, secrets, existing, dependencies) {
|
|
|
6657
6821
|
const createsWorker = state.plan.actions.some((action) => action.kind === "worker" && action.action === "create" && (hasEmailGatewayArtifact || action.key !== "email-gateway-worker"));
|
|
6658
6822
|
const recoveringCreatedWorker = interruptedCutover !== null && [...interruptedCutover.staged.values()].some((snapshot) => snapshot.previousVersionId === null);
|
|
6659
6823
|
const requiresSandboxDrain = !preserveDisabled && targetSandboxDrainProtocol >= 1 && sandboxDrainState === "pending";
|
|
6660
|
-
const requiresTrafficGuard = !previousPublicEndpoints || recoveringUnsafeTraffic || createsWorker || recoveringCreatedWorker || state.manifest.usageProtocolVersion !== targetUsageProtocolVersion || authenticationProtocolTransition || shouldBootstrapSharedEmail || requiresSandboxDrain || !!state.plan.deployment.appAccess && !state.manifest.steps.some((step) => step.key === "app-access-initialized:v1");
|
|
6661
|
-
if (requiresTrafficGuard) {
|
|
6662
|
-
await dependencies.client.putKvValue(state.plan.account.id, requireId(ids, "routing-kv"), PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE);
|
|
6663
|
-
workerTrafficGuarded = true;
|
|
6664
|
-
dependencies.onProgress?.("Application traffic paused for a safe platform cutover");
|
|
6665
|
-
}
|
|
6666
|
-
if (!preserveDisabled) {
|
|
6667
|
-
const trafficGeneration = nextTrafficGeneration(state.manifest);
|
|
6668
|
-
state.manifest = recordInstallationStep(state.manifest, {
|
|
6669
|
-
completedAt: now(),
|
|
6670
|
-
key: `traffic-enabled:${trafficGeneration}`,
|
|
6671
|
-
resultHash: String(trafficGeneration)
|
|
6672
|
-
}, now());
|
|
6673
|
-
writeInstallationManifest(state.manifest);
|
|
6674
|
-
await writeRemoteInstallationCheckpoint(dependencies.client, state.plan, state.manifest);
|
|
6675
|
-
}
|
|
6824
|
+
const requiresTrafficGuard = !previousPublicEndpoints || recoveringUnsafeTraffic || createsWorker || recoveringCreatedWorker || state.manifest.usageProtocolVersion !== targetUsageProtocolVersion || runtime.privatePreviews === 1 && !state.manifest.steps.some((step) => step.key === "private-previews-initialized:v1") || authenticationProtocolTransition || shouldBootstrapSharedEmail || requiresSandboxDrain || !!state.plan.deployment.appAccess && !state.manifest.steps.some((step) => step.key === "app-access-initialized:v1");
|
|
6676
6825
|
const configInput = {
|
|
6677
6826
|
authenticationDatabaseUncached: true,
|
|
6678
6827
|
proxyHealthBinding: true,
|
|
@@ -6696,23 +6845,43 @@ async function installPlatform(plan, secrets, existing, dependencies) {
|
|
|
6696
6845
|
runtimeEntrypoints: entrypoints,
|
|
6697
6846
|
...runtime.assets ? { runtimeApiAssetsDirectory: join(runtimeDirectory, PLATFORM_ADMIN_ASSETS_DIRECTORY) } : {}
|
|
6698
6847
|
};
|
|
6699
|
-
const workerDeploymentSecrets = {
|
|
6700
|
-
...state.secrets,
|
|
6701
|
-
workerSecretUpdates: state.workerSecretUpdateIntent?.updates ?? {}
|
|
6702
|
-
};
|
|
6703
|
-
const requiresStagedCommit = !preserveDisabled && requiresTrafficGuard;
|
|
6704
6848
|
const enabledConfigs = createPlatformWorkerConfigs({
|
|
6705
6849
|
...configInput,
|
|
6850
|
+
privatePreviews: runtime.privatePreviews === 1,
|
|
6706
6851
|
publicEndpoints: !preserveDisabled,
|
|
6707
6852
|
trafficState: preserveDisabled ? "staging" : "enabled"
|
|
6708
6853
|
});
|
|
6854
|
+
const outsideChangeConfigs = workerKeys.map((key) => enabledConfigs[key]).filter((config) => dependencies.replaceOutsideChanges?.includes(String(config.name)));
|
|
6855
|
+
if (outsideChangeConfigs.length > 0) await dependencies.uploadOutsideChanges?.(outsideChangeConfigs);
|
|
6856
|
+
if (requiresTrafficGuard) {
|
|
6857
|
+
await dependencies.client.putKvValue(state.plan.account.id, requireId(ids, "routing-kv"), PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE);
|
|
6858
|
+
workerTrafficGuarded = true;
|
|
6859
|
+
dependencies.onProgress?.("Application traffic paused for a safe platform cutover");
|
|
6860
|
+
}
|
|
6861
|
+
if (!preserveDisabled) {
|
|
6862
|
+
const trafficGeneration = nextTrafficGeneration(state.manifest);
|
|
6863
|
+
state.manifest = recordInstallationStep(state.manifest, {
|
|
6864
|
+
completedAt: now(),
|
|
6865
|
+
key: `traffic-enabled:${trafficGeneration}`,
|
|
6866
|
+
resultHash: String(trafficGeneration)
|
|
6867
|
+
}, now());
|
|
6868
|
+
writeInstallationManifest(state.manifest);
|
|
6869
|
+
await writeRemoteInstallationCheckpoint(dependencies.client, state.plan, state.manifest);
|
|
6870
|
+
}
|
|
6871
|
+
const workerDeploymentSecrets = {
|
|
6872
|
+
...state.secrets,
|
|
6873
|
+
workerSecretUpdates: state.workerSecretUpdateIntent?.updates ?? {}
|
|
6874
|
+
};
|
|
6875
|
+
const requiresStagedCommit = !preserveDisabled && requiresTrafficGuard;
|
|
6709
6876
|
const configs = requiresStagedCommit ? createPlatformWorkerConfigs({
|
|
6710
6877
|
...configInput,
|
|
6878
|
+
privatePreviews: runtime.privatePreviews === 1,
|
|
6711
6879
|
publicEndpoints: true,
|
|
6712
6880
|
trafficState: requiresSandboxDrain ? "sandbox-drain" : "staging"
|
|
6713
6881
|
}) : enabledConfigs;
|
|
6714
6882
|
const previousConfigs = createPlatformWorkerConfigs({
|
|
6715
6883
|
...configInput,
|
|
6884
|
+
privatePreviews: existing?.steps.some((step) => step.key === "private-previews-initialized:v1"),
|
|
6716
6885
|
publicEndpoints: previousPublicEndpoints,
|
|
6717
6886
|
trafficState: previousPublicEndpoints ? "enabled" : "staging"
|
|
6718
6887
|
});
|
|
@@ -6943,6 +7112,11 @@ async function installPlatform(plan, secrets, existing, dependencies) {
|
|
|
6943
7112
|
runtime,
|
|
6944
7113
|
runtimeProvenance
|
|
6945
7114
|
})).emailOperationId;
|
|
7115
|
+
if (runtime.privatePreviews === 1) state.manifest = recordInstallationStep(state.manifest, {
|
|
7116
|
+
key: "private-previews-initialized:v1",
|
|
7117
|
+
completedAt: now(),
|
|
7118
|
+
resultHash: hash("private-previews:v1")
|
|
7119
|
+
}, now());
|
|
6946
7120
|
await checkpointOperation("complete");
|
|
6947
7121
|
writeInstallationManifest(state.manifest);
|
|
6948
7122
|
await writeRemoteInstallationCheckpoint(dependencies.client, state.plan, state.manifest);
|
|
@@ -7304,6 +7478,171 @@ async function replacePendingInstallationAuthentication(input) {
|
|
|
7304
7478
|
};
|
|
7305
7479
|
}
|
|
7306
7480
|
//#endregion
|
|
7481
|
+
//#region src/cli/platform-installer-outside-changes.ts
|
|
7482
|
+
const OUTSIDE_SOURCES = {
|
|
7483
|
+
dash: "changed in the Cloudflare dashboard",
|
|
7484
|
+
api: "changed in the Cloudflare API",
|
|
7485
|
+
unrecorded: "has an active version without a Void deployment record"
|
|
7486
|
+
};
|
|
7487
|
+
const PLATFORM_WORKER_KEYS = [
|
|
7488
|
+
"api",
|
|
7489
|
+
"proxy",
|
|
7490
|
+
"emailGateway",
|
|
7491
|
+
"tail",
|
|
7492
|
+
"dispatch"
|
|
7493
|
+
];
|
|
7494
|
+
const NO_WORKER_CHANGED = "No platform Worker changed. This command did not pause application traffic.";
|
|
7495
|
+
/** The wait before the second and the third read of a Worker. */
|
|
7496
|
+
const READ_RETRY_DELAYS_MS = [250, 500];
|
|
7497
|
+
/** Stop before the run changes a Worker, because Void cannot tell what the run replaces. */
|
|
7498
|
+
function unreadablePlatformWorker(workerName, error) {
|
|
7499
|
+
const status = error instanceof PlatformCloudflareApiError ? error.status : null;
|
|
7500
|
+
const answer = status === null ? `no HTTP response: ${error instanceof Error ? error.message : String(error)}` : `HTTP ${status}`;
|
|
7501
|
+
return new Error([
|
|
7502
|
+
`platform: Void cannot read the platform Worker ${workerName} (${answer}), so it cannot find changes made outside Void.`,
|
|
7503
|
+
NO_WORKER_CHANGED,
|
|
7504
|
+
status === 401 || status === 403 ? "Make sure that the Cloudflare API token has Account → Workers Scripts → Edit for this account. Then run the command again." : "Run the command again."
|
|
7505
|
+
].join(" "), { cause: error });
|
|
7506
|
+
}
|
|
7507
|
+
/**
|
|
7508
|
+
* Read a Worker again after a rate limit, a Cloudflare server error or a
|
|
7509
|
+
* network failure. Each other failure, or a third failure, stops the run.
|
|
7510
|
+
*/
|
|
7511
|
+
async function readPlatformWorker(workerName, read) {
|
|
7512
|
+
for (let attempt = 0;; attempt++) try {
|
|
7513
|
+
return await read();
|
|
7514
|
+
} catch (error) {
|
|
7515
|
+
const status = error instanceof PlatformCloudflareApiError ? error.status : null;
|
|
7516
|
+
const wait = READ_RETRY_DELAYS_MS[attempt];
|
|
7517
|
+
if (wait === void 0 || status !== null && status !== 429 && status < 500) throw unreadablePlatformWorker(workerName, error);
|
|
7518
|
+
await setTimeout$1(wait);
|
|
7519
|
+
}
|
|
7520
|
+
}
|
|
7521
|
+
/** The Cloudflare CLI asks only about these changes. The others need no upload for review. */
|
|
7522
|
+
function needsReviewUpload(change) {
|
|
7523
|
+
return change.source !== "unrecorded";
|
|
7524
|
+
}
|
|
7525
|
+
/**
|
|
7526
|
+
* The earlier version of each Worker that the installer makes active again
|
|
7527
|
+
* before it deploys. A run that stopped during a Worker cutover left Void's
|
|
7528
|
+
* version active, and the next run first restores the earlier one. Like the
|
|
7529
|
+
* installer, keep Void's version while the platform changes to configurable
|
|
7530
|
+
* sign-in and already requires sign-in. Every Worker that this check reads
|
|
7531
|
+
* exists, so the installation had Workers before.
|
|
7532
|
+
*/
|
|
7533
|
+
async function restoredPlatformWorkerVersions(installation, runtime) {
|
|
7534
|
+
const cutover = interruptedWorkerCutover(installation.manifest);
|
|
7535
|
+
if (!cutover || installation.manifest.deployment.authentication.configurable !== true && runtime.manifest.authenticationProtocolVersion === 1 && (await installation.readAuthenticationState?.())?.sessionsRequired === true) return /* @__PURE__ */ new Map();
|
|
7536
|
+
return new Map([...cutover.staged.values()].flatMap((snapshot) => snapshot.previousVersionId === null ? [] : [[snapshot.workerName, snapshot.previousVersionId]]));
|
|
7537
|
+
}
|
|
7538
|
+
/** Find the existing platform Workers that a run uploads and that were changed outside Void. */
|
|
7539
|
+
async function findPlatformWorkerOutsideChanges(client, plan, runtime, installation) {
|
|
7540
|
+
const workers = PLATFORM_WORKER_KEYS.flatMap((key) => {
|
|
7541
|
+
if (key === "emailGateway" && runtime.manifest.artifacts.emailGateway === void 0) return [];
|
|
7542
|
+
const action = plan.actions.find((entry) => entry.key === platformWorkerResourceKey(key));
|
|
7543
|
+
return action?.kind === "worker" && action.action !== "create" ? [{
|
|
7544
|
+
key,
|
|
7545
|
+
name: action.name
|
|
7546
|
+
}] : [];
|
|
7547
|
+
});
|
|
7548
|
+
const restored = workers.length > 0 ? await restoredPlatformWorkerVersions(installation, runtime) : /* @__PURE__ */ new Map();
|
|
7549
|
+
return (await Promise.all(workers.map(async (worker) => {
|
|
7550
|
+
const readCloudflare = (path) => readPlatformWorker(worker.name, () => client.request(path));
|
|
7551
|
+
const source = await readPlatformWorker(worker.name, () => client.getWorkerLastDeployedFrom(plan.account.id, worker.name));
|
|
7552
|
+
const deployments = await readPlatformWorker(worker.name, () => client.request(`/accounts/${encodeURIComponent(plan.account.id)}/workers/scripts/${encodeURIComponent(worker.name)}/deployments`).catch((error) => {
|
|
7553
|
+
if (error instanceof PlatformCloudflareApiError && error.status === 404) return null;
|
|
7554
|
+
throw error;
|
|
7555
|
+
}));
|
|
7556
|
+
if (deployments === null) return source === "dash" || source === "api" ? {
|
|
7557
|
+
...worker,
|
|
7558
|
+
source
|
|
7559
|
+
} : null;
|
|
7560
|
+
const active = readActivePlatformWorkerDeployment(deployments);
|
|
7561
|
+
if (active.kind === "malformed") throw new Error(`platform: Cloudflare returned malformed deployment data for the platform Worker ${worker.name}, so Void cannot find changes made outside Void. ${NO_WORKER_CHANGED} Run the command again.`);
|
|
7562
|
+
if (active.kind === "split") throw new Error(`platform: The platform Worker ${worker.name} has no single version that gets 100% of traffic, for example after a gradual deployment. This command deploys a new version only when one version gets all traffic. ${NO_WORKER_CHANGED} In the Cloudflare dashboard, deploy one version of ${worker.name} to 100% of traffic. Then run this command once in a terminal, so that you can approve the dashboard change.`);
|
|
7563
|
+
if (source === "dash" || source === "api") return {
|
|
7564
|
+
...worker,
|
|
7565
|
+
source
|
|
7566
|
+
};
|
|
7567
|
+
const restoredVersion = restored.get(worker.name);
|
|
7568
|
+
return (await Promise.all([active.versionId, ...restoredVersion === void 0 ? [] : [restoredVersion]].map((versionId) => platformWorkerVersionHasTriggerRecord(readCloudflare, plan.account.id, worker.name, versionId)))).includes(false) ? {
|
|
7569
|
+
...worker,
|
|
7570
|
+
source: "unrecorded"
|
|
7571
|
+
} : null;
|
|
7572
|
+
}))).filter((change) => change !== null);
|
|
7573
|
+
}
|
|
7574
|
+
function listPlatformWorkerOutsideChanges(changes) {
|
|
7575
|
+
return changes.map((change) => `${change.name}: ${OUTSIDE_SOURCES[change.source]}`).join("\n");
|
|
7576
|
+
}
|
|
7577
|
+
/**
|
|
7578
|
+
* The list of Workers after a heading. The heading must be true for each
|
|
7579
|
+
* source: an older Void release can have deployed the active version.
|
|
7580
|
+
*/
|
|
7581
|
+
function formatPlatformWorkerOutsideChanges(changes) {
|
|
7582
|
+
return `These platform Workers need your approval before this command replaces their configuration:\n${listPlatformWorkerOutsideChanges(changes)}`;
|
|
7583
|
+
}
|
|
7584
|
+
/**
|
|
7585
|
+
* Do this before a run changes a Worker or pauses traffic. When platform
|
|
7586
|
+
* Workers were changed outside Void, stop, or ask the operator in a terminal.
|
|
7587
|
+
* Returns the Workers whose outside changes the operator agreed to replace.
|
|
7588
|
+
* The installer uploads them later with uploadPlatformWorkerOutsideChanges.
|
|
7589
|
+
*/
|
|
7590
|
+
async function reviewPlatformWorkerOutsideChanges(input) {
|
|
7591
|
+
const changes = await findPlatformWorkerOutsideChanges(input.client, input.plan, input.runtime, input.installation);
|
|
7592
|
+
if (changes.length === 0) return [];
|
|
7593
|
+
if (!input.interactive) throw new Error([
|
|
7594
|
+
`platform: ${formatPlatformWorkerOutsideChanges(changes)}`,
|
|
7595
|
+
NO_WORKER_CHANGED,
|
|
7596
|
+
"This command replaces their configuration with the Void configuration. It can ask for your approval only in a terminal.",
|
|
7597
|
+
`Run this command once in a terminal to review them:\n${input.command}`
|
|
7598
|
+
].join("\n"));
|
|
7599
|
+
note([
|
|
7600
|
+
listPlatformWorkerOutsideChanges(changes),
|
|
7601
|
+
"",
|
|
7602
|
+
"This command replaces the configuration of these Workers with the Void configuration.",
|
|
7603
|
+
"It removes values that Void does not set, for example an EMAIL_FROM that you added.",
|
|
7604
|
+
"It resets values that Void sets, for example AUTH_REDIRECT_URI.",
|
|
7605
|
+
...changes.some(needsReviewUpload) ? [
|
|
7606
|
+
"First, it prepares the platform resources and the database.",
|
|
7607
|
+
"Then, before it pauses traffic or deploys a Worker, the Cloudflare CLI asks you again for each Worker changed in the Cloudflare dashboard or API. For a dashboard change, it shows the differences.",
|
|
7608
|
+
"It uploads a new version of each of these Workers and does not deploy it."
|
|
7609
|
+
] : []
|
|
7610
|
+
].join("\n"), "Approval needed");
|
|
7611
|
+
const answer = await confirm({
|
|
7612
|
+
message: "Replace the configuration of these Workers?",
|
|
7613
|
+
initialValue: false
|
|
7614
|
+
});
|
|
7615
|
+
if (isCancel(answer) || typeof answer === "symbol" || !answer) throw new Error(`platform: Cancelled. ${NO_WORKER_CHANGED}`);
|
|
7616
|
+
return changes;
|
|
7617
|
+
}
|
|
7618
|
+
/**
|
|
7619
|
+
* Upload a new version of each Worker that the operator agreed to replace, and
|
|
7620
|
+
* do not deploy it. The installer gives the configs after it creates the
|
|
7621
|
+
* resources that they use, and before it pauses traffic. The Cloudflare CLI
|
|
7622
|
+
* uses this terminal: it shows what the upload replaces and asks the operator.
|
|
7623
|
+
*/
|
|
7624
|
+
async function uploadPlatformWorkerOutsideChanges(configs, input) {
|
|
7625
|
+
const { client } = input;
|
|
7626
|
+
const reviewed = configs.filter((config) => input.changes.some((change) => change.name === config.name && needsReviewUpload(change)));
|
|
7627
|
+
if (reviewed.length === 0) return;
|
|
7628
|
+
const runner = input.runner ?? ((operation, accountId, cwd, capture) => runPlatformWranglerAtApiBase(operation, accountId, cwd, capture, client.apiBaseUrl, false, input.operatorApiToken));
|
|
7629
|
+
input.progress?.pause();
|
|
7630
|
+
try {
|
|
7631
|
+
for (const config of reviewed) {
|
|
7632
|
+
const name = String(config.name);
|
|
7633
|
+
log.step(`Uploading a new version of ${name} without deploying it`);
|
|
7634
|
+
const uploaded = await uploadPlatformWorkerForReview(config, {
|
|
7635
|
+
readCloudflare: (path) => client.request(path),
|
|
7636
|
+
runner
|
|
7637
|
+
});
|
|
7638
|
+
const source = await client.getWorkerLastDeployedFrom(String(config.account_id), name);
|
|
7639
|
+
if (uploaded.status !== 0 || source === "dash" || source === "api") throw new Error(`platform: The Cloudflare CLI did not replace the changes to ${name}. Its output above shows why. No deployment changed. This command did not pause application traffic.`);
|
|
7640
|
+
}
|
|
7641
|
+
} finally {
|
|
7642
|
+
input.progress?.resume();
|
|
7643
|
+
}
|
|
7644
|
+
}
|
|
7645
|
+
//#endregion
|
|
7307
7646
|
//#region src/cli/platform-saved-plans.ts
|
|
7308
7647
|
function planId(args) {
|
|
7309
7648
|
return createHash("sha256").update(JSON.stringify([args.account, args.name])).digest("hex");
|
|
@@ -7428,14 +7767,14 @@ function resolvePlatformInstallDatabaseUrl(checkpoint, manifest = null) {
|
|
|
7428
7767
|
}
|
|
7429
7768
|
async function runPlatformLifecycleCommand(commandArgs) {
|
|
7430
7769
|
if (commandArgs.subcommand === "domain") {
|
|
7431
|
-
const { runPlatformDomainCommand } = await import("./platform-domain-
|
|
7770
|
+
const { runPlatformDomainCommand } = await import("./platform-domain-DDNK2y-4.mjs");
|
|
7432
7771
|
await runPlatformDomainCommand(commandArgs);
|
|
7433
7772
|
return;
|
|
7434
7773
|
}
|
|
7435
7774
|
if (commandArgs.subcommand === "discover") {
|
|
7436
7775
|
const client = new PlatformCloudflareClient((await resolvePlatformCloudflareCredential()).token);
|
|
7437
7776
|
const accountId = await selectAccount(await readAccounts(client), commandArgs.account);
|
|
7438
|
-
const { recoverPlatformInstallations } = await import("./platform-recovery-
|
|
7777
|
+
const { recoverPlatformInstallations } = await import("./platform-recovery-Dmsg7lWA.mjs");
|
|
7439
7778
|
const recovered = await recoverPlatformInstallations(client, accountId, void 0, commandArgs.selector);
|
|
7440
7779
|
if (recovered.length === 0) {
|
|
7441
7780
|
log.info(`No recoverable Void platform installations were found in ${accountId}.`);
|
|
@@ -7446,7 +7785,7 @@ async function runPlatformLifecycleCommand(commandArgs) {
|
|
|
7446
7785
|
return;
|
|
7447
7786
|
}
|
|
7448
7787
|
if (commandArgs.subcommand !== "install") {
|
|
7449
|
-
const { runInstalledPlatformCommand } = await import("./platform-management-
|
|
7788
|
+
const { runInstalledPlatformCommand } = await import("./platform-management-DAE6g2QU.mjs");
|
|
7450
7789
|
await runInstalledPlatformCommand(commandArgs);
|
|
7451
7790
|
return;
|
|
7452
7791
|
}
|
|
@@ -7622,7 +7961,7 @@ async function runPlatformLifecycleCommand(commandArgs) {
|
|
|
7622
7961
|
progress?.stop("Read the saved installation.");
|
|
7623
7962
|
progress = void 0;
|
|
7624
7963
|
if (authoritative) {
|
|
7625
|
-
const { selectAuthoritativePlatformManifest } = await import("./platform-management-
|
|
7964
|
+
const { selectAuthoritativePlatformManifest } = await import("./platform-management-DAE6g2QU.mjs");
|
|
7626
7965
|
const selected = selectAuthoritativePlatformManifest(existing, authoritative);
|
|
7627
7966
|
authoritativeProvisionIntents = true;
|
|
7628
7967
|
if (!args.plan && JSON.stringify(selected) !== JSON.stringify(existing)) writeInstallationManifest(selected);
|
|
@@ -7831,8 +8170,10 @@ async function runPlatformLifecycleCommand(commandArgs) {
|
|
|
7831
8170
|
break;
|
|
7832
8171
|
} catch (error) {
|
|
7833
8172
|
if (!isPlatformTokenAuthorizationError(error)) throw error;
|
|
8173
|
+
const details = /* @__PURE__ */ new Set();
|
|
8174
|
+
for (let cause = error, depth = 0; depth < 5 && cause instanceof Error; depth++, cause = cause.cause) details.add(cause.message.replaceAll(token, "[redacted]"));
|
|
7834
8175
|
forgetRejectedManagementToken();
|
|
7835
|
-
log.warn("
|
|
8176
|
+
log.warn([...details, "Check the token permissions and account/zone scope, then paste a replacement."].join("\n"));
|
|
7836
8177
|
}
|
|
7837
8178
|
}
|
|
7838
8179
|
} else if (managementAccess) await verifyPlatformManagementAccess(client, accountId, managementAccess);
|
|
@@ -7878,6 +8219,7 @@ async function runPlatformLifecycleCommand(commandArgs) {
|
|
|
7878
8219
|
accountId,
|
|
7879
8220
|
applicationDomain,
|
|
7880
8221
|
customDomains: plan.deployment.capabilities.customDomains,
|
|
8222
|
+
...plan.deployment.capabilities.email && plan.deployment.emailSharedZoneId ? { emailZoneId: plan.deployment.emailSharedZoneId } : {},
|
|
7881
8223
|
zoneId: plan.zone?.id ?? null
|
|
7882
8224
|
});
|
|
7883
8225
|
checkingRuntimePermissions = false;
|
|
@@ -7886,7 +8228,7 @@ async function runPlatformLifecycleCommand(commandArgs) {
|
|
|
7886
8228
|
plan = await verifyPlatformAiGatewayPlan(client, planInput, existing, plan, authoritativeProvisionIntents);
|
|
7887
8229
|
}
|
|
7888
8230
|
} catch (error) {
|
|
7889
|
-
if (credentialSetup && token === values.cloudflareApiToken && isPlatformTokenAuthorizationError(error, checkingRuntimePermissions ? void 0 : "/ai-gateway/")) {
|
|
8231
|
+
if (credentialSetup && token === values.cloudflareApiToken && !(error instanceof PlatformRuntimeTokenEmailPermissionError) && isPlatformTokenAuthorizationError(error, checkingRuntimePermissions ? void 0 : "/ai-gateway/")) {
|
|
7890
8232
|
delete values.cloudflareApiToken;
|
|
7891
8233
|
writePendingInstallationSecrets(setupManifest, values);
|
|
7892
8234
|
rejectedSavedRuntimeToken = true;
|
|
@@ -7981,6 +8323,14 @@ async function runPlatformLifecycleCommand(commandArgs) {
|
|
|
7981
8323
|
title: "About these keys",
|
|
7982
8324
|
url: "https://void.cloud/guide/platform/installation/credentials#signing-and-encryption-keys"
|
|
7983
8325
|
}));
|
|
8326
|
+
const outsideChanges = await reviewPlatformWorkerOutsideChanges({
|
|
8327
|
+
client,
|
|
8328
|
+
plan,
|
|
8329
|
+
runtime,
|
|
8330
|
+
installation: { manifest: existing },
|
|
8331
|
+
interactive: process.stdin.isTTY === true && process.stdout.isTTY === true && !args.yes,
|
|
8332
|
+
command: `${cliCommandName()} platform install --resume --name ${existing.id}`
|
|
8333
|
+
});
|
|
7984
8334
|
progress = startProgress("Installing the platform");
|
|
7985
8335
|
if (credentialSetup) {
|
|
7986
8336
|
saveValues({
|
|
@@ -7999,6 +8349,15 @@ async function runPlatformLifecycleCommand(commandArgs) {
|
|
|
7999
8349
|
},
|
|
8000
8350
|
client,
|
|
8001
8351
|
operatorApiToken: managementApiToken || operatorCredential.token,
|
|
8352
|
+
...outsideChanges.length > 0 ? {
|
|
8353
|
+
replaceOutsideChanges: outsideChanges.map((change) => change.name),
|
|
8354
|
+
uploadOutsideChanges: (configs) => uploadPlatformWorkerOutsideChanges(configs, {
|
|
8355
|
+
changes: outsideChanges,
|
|
8356
|
+
client,
|
|
8357
|
+
operatorApiToken: managementApiToken || operatorCredential.token,
|
|
8358
|
+
progress
|
|
8359
|
+
})
|
|
8360
|
+
} : {},
|
|
8002
8361
|
runtime,
|
|
8003
8362
|
healthCheckResumeCommand: `${cliCommandName()} platform install --resume --name ${existing.id}`,
|
|
8004
8363
|
onProgress: (message) => progress?.message(message),
|
|
@@ -8040,7 +8399,7 @@ async function runPlatformLifecycleCommand(commandArgs) {
|
|
|
8040
8399
|
})).actions.filter((action) => action.kind === "worker"),
|
|
8041
8400
|
revalidateBeforeWorkerDeploy: (manifest, action) => revalidatePlatformInstallAction(client, plan, manifest, action),
|
|
8042
8401
|
verifyExistingOwnership: async (manifest, databaseCheckpointExists) => {
|
|
8043
|
-
const { verifyPlatformInstallationOwnership } = await import("./platform-management-
|
|
8402
|
+
const { verifyPlatformInstallationOwnership } = await import("./platform-management-DAE6g2QU.mjs");
|
|
8044
8403
|
const retainedReplacementKeys = new Set(plan.actions.filter((action) => {
|
|
8045
8404
|
const previous = manifest.resources.find((resource) => resource.key === action.key);
|
|
8046
8405
|
return action.action === "create" && previous && previous.name !== action.name;
|
|
@@ -8197,4 +8556,4 @@ async function promptSecret(message, masked = true, validate, placeholder) {
|
|
|
8197
8556
|
return value;
|
|
8198
8557
|
}
|
|
8199
8558
|
//#endregion
|
|
8200
|
-
export {
|
|
8559
|
+
export { hyperdriveOriginMatches as $, dnsRecordConfigHash as A, turnOffInstalledProjectZeroTrust as B, createPlatformHealthProbeToken as C, platformTrafficAttachmentWorker as D, recordResource as E, platformAdoptionIntentHash as F, checkpointPlatformAccessResources as G, resolvePlatformCloudflareCredential as H, r2BucketConfigHash as I, PlatformCloudflareApiError as J, parsePlatformAccessSetupSpec as K, resourceMarkerProblem as L, hasProvisionIntentStep as M, legacyResourceConfigHash as N, recordPlatformWorkerTraffic as O, matchesRecordedR2Fingerprint as P, hyperdriveOriginFromConnectionString as Q, revalidatePlatformInstallAction as R, loadPlatformRuntime as S, resolveBootstrapGitHubId as T, verifyPlatformCloudflareCredential as U, assertPlatformOperatorCredentialCanApplyPlan as V, activatePlatformAccessCredentials as W, PlatformRuntimeTokenEmailPermissionError as X, PlatformCloudflareClient as Y, hyperdriveOriginConfigHash as Z, readPlatformProjectSlugs as _, findPlatformWorkerOutsideChanges as a, formatZeroTrustApplications as b, uploadPlatformWorkerOutsideChanges as c, replacePendingInstallationAuthentication as d, verifyPlatformRuntimeTokenEmailPermissions as et, REMOTE_INSTALLATION_MANIFEST_KEY as f, platformDatabaseClientUrl as g, acquirePlatformDatabaseLifecycleLockConnection as h, verifyPlatformAiGatewayPlan as i, formatPlatformInstallPlan as j, createPlatformInstallPlan as k, authenticationSetupRequestHash as l, acquirePlatformDatabaseLifecycleLock as m, resolvePlatformInstallDatabaseUrl as n, formatPlatformWorkerOutsideChanges as o, installPlatform as p, preparePlatformAccessSetup as q, runPlatformLifecycleCommand as r, reviewPlatformWorkerOutsideChanges as s, assertNoninteractivePlatformMutationAcknowledged as t, verifyPlatformRuntimeTokenPermissions as tt, readLoginReplacementFile as u, readPlatformProjectZeroTrustState as v, createPlatformInstallationSecrets as w, readPlatformDatabase as x, assertProjectZeroTrustAllowsUninstall as y, platformDatabaseNameFromOwnerUrl as z };
|