void 0.24.0 → 0.26.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/README.md +19 -106
- package/dist/{account-cmd-vJhh5lrb.mjs → account-cmd-CDry3B5V.mjs} +5 -5
- package/dist/{application-analysis-BVsVqc11.mjs → application-analysis-DC2yPvzY.mjs} +1 -1
- package/dist/{application-routing-B7QEjqSR.mjs → application-routing-C9khgLiS.mjs} +1 -1
- package/dist/{auth-DX3JURcX.mjs → auth-B60QDbjg.mjs} +1 -1
- package/dist/{auth-CQkSDS50.mjs → auth-D52yG7hl.mjs} +3 -3
- package/dist/{auth-link-D75t9wO2.mjs → auth-link-DjeOptYi.mjs} +5 -6
- package/dist/{auth-router-ClfhL1J7.mjs → auth-router-BRxIuqDi.mjs} +7 -7
- package/dist/{build-cmd-zMi1iFnS.mjs → build-cmd-Ce3C8huo.mjs} +6 -7
- package/dist/{cache-ZtQmyxVV.mjs → cache-CS8Yxr5a.mjs} +6 -7
- package/dist/{cancel-deploy-Box0kkEV.mjs → cancel-deploy-mZsD88Xa.mjs} +4 -6
- package/dist/{cf-access-BGe5sWXF.mjs → cf-access-YTlqvAsk.mjs} +1 -1
- package/dist/cf-build-output-ChY6-XWP.mjs +2 -0
- package/dist/cli/cli.mjs +45 -45
- package/dist/cli/cloudflare-operation-process.mjs +3 -3
- package/dist/cli/env-schema-probe.d.mts +1 -1
- package/dist/cli/env-schema-probe.mjs +2 -2
- package/dist/client-BxVixJBI.mjs +2 -0
- package/dist/{client-DKAsFA4X.mjs → client-mC-dFGDD.mjs} +103 -25
- package/dist/{cloudflare-cmd-CmY8dGkd.mjs → cloudflare-cmd-bhwCxAN6.mjs} +2 -2
- package/dist/{cloudflare-connect-IiR3ZieC.mjs → cloudflare-connect-CuhRgk3k.mjs} +2 -2
- package/dist/{cloudflare-operations-DzH-A966.mjs → cloudflare-operations-DYa3coIk.mjs} +2 -2
- package/dist/{cloudflare-operations-BCdXSsmo.mjs → cloudflare-operations-DoQrVHAt.mjs} +1 -1
- package/dist/{connect-B-usTnlF.mjs → connect-H6EvP62X.mjs} +12 -9
- package/dist/{create-project-CYOOAYcn.mjs → create-project-B2kk9Q0o.mjs} +6 -6
- package/dist/{create-project-FWbf5Olo.mjs → create-project-Dbb4uiN-.mjs} +1 -1
- package/dist/{db-Ck2eZ2iB.mjs → db-DpCKZto0.mjs} +35 -38
- package/dist/{delete-sK56qtzZ.mjs → delete-CxlSvsvW.mjs} +6 -7
- package/dist/{deploy-gCVaiJbS.mjs → deploy-CeEbnv4b.mjs} +9249 -8925
- package/dist/deploy-qmiLE1G1.mjs +2 -0
- package/dist/{dev-inbox-P0u4tM8Y.mjs → dev-inbox-D64ZKUod.mjs} +5 -6
- package/dist/{domain-DFfQE8jg.mjs → domain-B_9VgOm6.mjs} +8 -8
- package/dist/{email-CdnhUHvJ.mjs → email-BokHgjKj.mjs} +7 -7
- package/dist/{env-DmGdHi5i.mjs → env-BdTc-K2L.mjs} +7 -8
- package/dist/{env-public-BX_r8HR6.d.mts → env-public-DR7ZM6d-.d.mts} +1 -1
- package/dist/{env-validation-zZOCcQVZ.mjs → env-validation-cZBvGWaP.mjs} +1 -1
- package/dist/{fetch-stream-IvCYKyQL.mjs → fetch-stream-Nm3hkZbT.mjs} +8 -1
- package/dist/{gen-CshAkukR.mjs → gen-BhDlTpwW.mjs} +2 -4
- package/dist/gen-qCBwH3fZ.mjs +2 -0
- package/dist/{github-cmd-DftuEvIt.mjs → github-cmd-hhkTzlGS.mjs} +7 -16
- package/dist/{handler-CZ4nAylQ.d.mts → handler-BeK3weD4.d.mts} +1 -1
- package/dist/{help-Dotbf6iz.mjs → help-Bv44e2tm.mjs} +13 -9
- package/dist/help-Dw5f9Xrg.mjs +2 -0
- package/dist/index.d.mts +19 -15
- package/dist/index.mjs +2225 -2142
- package/dist/{info-B97bTX9N.mjs → info-DhtTKh65.mjs} +2 -4
- package/dist/{init-BTQEZZGJ.mjs → init-BMf4T03q.mjs} +17 -18
- package/dist/{limits-Bq5LG8Id.d.mts → limits-CFsDKQvU.d.mts} +1 -10
- package/dist/{limits-Cjuk2VPm.mjs → limits-D0vD1M9A.mjs} +1 -22
- package/dist/{link-B46sYH0K.mjs → link-BqYsSS_I.mjs} +6 -7
- package/dist/{list-BnPrIsU_.mjs → list-_kBToO-l.mjs} +10 -10
- package/dist/{live-Chw1eIMv.d.mts → live-iAuEH1hd.d.mts} +1 -1
- package/dist/{local-d1-2CMnpuW_.mjs → local-d1-fGxYrVD6.mjs} +2 -2
- package/dist/login-D7meQg_3.mjs +2 -0
- package/dist/{login-BuiMyUrx.mjs → login-DFuo-RWO.mjs} +9 -7
- package/dist/{logs-CZG9d-ic.mjs → logs-DYgnh6dH.mjs} +7 -8
- package/dist/migrate-CEu2X5DB.mjs +2 -0
- package/dist/{migrate-q4_njtaW.mjs → migrate-CV1on-yJ.mjs} +2 -4
- package/dist/{node-BkyRWRx8.mjs → node-C6Q6e1Es.mjs} +1 -1
- package/dist/{operator-args-B3BTmSoi.mjs → operator-args-DdY54Bgb.mjs} +1 -1
- package/dist/{operator-auth-7erYc6Lt.mjs → operator-auth-2dsGlTT5.mjs} +4 -8
- package/dist/{operator-client-CpHjTd0t.mjs → operator-client-BFqpp6z0.mjs} +3 -3
- package/dist/{operator-cmd-DGqPJUD3.mjs → operator-cmd-CUGHXrQf.mjs} +27 -9
- package/dist/operator-cmd-DRPvhpjM.mjs +2 -0
- package/dist/{output-CbM85T4k.mjs → output-BvdaehtE.mjs} +28 -4
- package/dist/pages/client.d.mts +4 -1
- package/dist/pages/client.mjs +120 -29
- package/dist/pages/index.mjs +1 -1
- package/dist/pages/islands-plugin.mjs +1 -1
- package/dist/pages/protocol.d.mts +2 -2
- package/dist/{plan-NPpwZ_kc.mjs → plan-CJGEeTEI.mjs} +2 -2
- package/dist/plan-COtUvdMA.mjs +2 -0
- package/dist/{platform-args-3k8X9-H_.mjs → platform-args-DSV2p4nY.mjs} +4 -2
- package/dist/platform-args-Dcy_5b_Y.mjs +2 -0
- package/dist/{platform-auth-config-DDrxUy4m.mjs → platform-auth-config-Bosx7U1h.mjs} +20 -19
- package/dist/{platform-auth-protection-BLadnnct.mjs → platform-auth-protection-DcbL_LW_.mjs} +8 -8
- package/dist/{platform-auth-recovery-CmCzX2Fl.mjs → platform-auth-recovery-WfTZ8K6o.mjs} +7 -7
- package/dist/{platform-cmd-DMDEc9uS.mjs → platform-cmd-DbKtQb_4.mjs} +73 -38
- package/dist/{platform-cmd-pMTRhvYs.mjs → platform-cmd-dyFUof0t.mjs} +1 -1
- package/dist/platform-discovery-BC0HCKYt.mjs +41 -0
- package/dist/{platform-domain-Di6EYrQl.mjs → platform-domain-Bsq43AJp.mjs} +5 -4
- package/dist/{platform-lifecycle-BFdSi9Qt.mjs → platform-lifecycle--5gWmDoI.mjs} +1 -1
- package/dist/{platform-lifecycle-BBoNzojY.mjs → platform-lifecycle-Cfi0o6xM.mjs} +4605 -3527
- package/dist/platform-management-Bbwf6-Dq.mjs +2 -0
- package/dist/{platform-management-CWOQOWXm.mjs → platform-management-BrF9STZp.mjs} +211 -31
- package/dist/{platform-plans-config-Vl9BP3H4.mjs → platform-plans-config-DU-8nC2Y.mjs} +3 -3
- package/dist/{platform-recovery-BJnQJEtQ.mjs → platform-recovery-DQAqAQYu.mjs} +3 -3
- package/dist/{platform-registry-DkPPXfp_.mjs → platform-registry-P387v42A.mjs} +18 -11
- package/dist/prepare-BBknoZI1.mjs +2 -0
- package/dist/{prepare-CBLT3CHH.mjs → prepare-BMrRWLwP.mjs} +3 -4
- package/dist/{prepare-DnaKBi--.mjs → prepare-WoUubFKL.mjs} +1 -1
- package/dist/{project-DsblYifa.mjs → project-BiaPQ7ur.mjs} +1 -1
- package/dist/{project-DKG5Ra8p.mjs → project-DQstYTxO.mjs} +1 -1
- package/dist/{project-cmd-DxnXstAq.mjs → project-cmd-BbH2LptN.mjs} +21 -22
- package/dist/{project-team-BmHcaALJ.mjs → project-team-Yiww3-go.mjs} +8 -9
- package/dist/{project-token-GionZlBI.mjs → project-token-BrtT2NkY.mjs} +6 -9
- package/dist/{project-zero-trust-JLCjVQA7.mjs → project-zero-trust-nYJ2V2nc.mjs} +5 -6
- package/dist/{prompts-BNUoTiaf.mjs → prompts-6OSVA7DJ.mjs} +58 -15
- package/dist/{prompts-2TGE6oXx.mjs → prompts-ZAuJlyCj.mjs} +1 -1
- package/dist/{protocol-CjF_iI9X.d.mts → protocol-BX8t2jiw.d.mts} +1 -1
- package/dist/{provision-CVku1JFU.mjs → provision-DMTPG8Rh.mjs} +1 -1
- package/dist/{provision-CaoxO_U7.mjs → provision-VeqAC77A.mjs} +18 -8
- package/dist/{requests-BOjIVAeF.mjs → requests-TIz_jtSu.mjs} +5 -6
- package/dist/{rollback-CwR3pLj3.mjs → rollback-dBqICPzj.mjs} +9 -10
- package/dist/{runner-Ol0TNjk6.mjs → runner--2KF6Kua.mjs} +1 -1
- package/dist/{runner-CXA9Fh8h.mjs → runner-voIltZrY.mjs} +1 -1
- package/dist/runtime/ai.d.mts +10 -11
- package/dist/runtime/ai.mjs +13 -18
- package/dist/runtime/client-react.mjs +1 -1
- package/dist/runtime/client-solid.mjs +1 -1
- package/dist/runtime/client-svelte.mjs +1 -1
- package/dist/runtime/client-vue.mjs +1 -1
- package/dist/runtime/client.mjs +1 -1
- package/dist/runtime/email/testing.mjs +1 -1
- package/dist/runtime/email.mjs +35 -17
- package/dist/runtime/env-public.d.mts +1 -1
- package/dist/runtime/fetch-stream.mjs +1 -1
- package/dist/runtime/handler.d.mts +1 -1
- package/dist/runtime/limits.d.mts +2 -2
- package/dist/runtime/limits.mjs +2 -2
- package/dist/runtime/live-client.d.mts +1 -1
- package/dist/runtime/live.d.mts +1 -1
- package/dist/runtime/migration-handler.mjs +33 -7
- package/dist/runtime/routing.d.mts +1 -1
- package/dist/runtime/routing.mjs +1 -1
- package/dist/runtime/sandbox.d.mts +1 -1
- package/dist/runtime/sandbox.mjs +12 -22
- package/dist/runtime/validator.d.mts +1 -1
- package/dist/runtime/ws-server.d.mts +1 -1
- package/dist/runtime/ws.d.mts +1 -1
- package/dist/{sandbox-XZAqzFlG.d.mts → sandbox-C5LFoJMf.d.mts} +7 -7
- package/dist/{scan-C7okrLyM.mjs → scan-C8dA7iM4.mjs} +10 -6
- package/dist/{secret-ByWJWBUG.mjs → secret-AKnNXNP5.mjs} +15 -16
- package/dist/{skills-C1PlclPt.mjs → skills-BPQUGClu.mjs} +1 -1
- package/dist/{subcommand-prompt-klFCfcor.mjs → subcommand-prompt-B6WS9Aoz.mjs} +2 -2
- package/dist/sveltekit.d.mts +1 -1
- package/dist/sveltekit.mjs +4 -9
- package/dist/validate-pna7R3Pv.mjs +2 -0
- package/dist/{validate-ctOrgiS3.mjs → validate-ymhap6M_.mjs} +1 -1
- package/dist/{wrangler-7K-bW_DL.mjs → wrangler-DhUerFkW.mjs} +10 -15
- package/dist/{ws-CL1w7GXU.d.mts → ws-C79j4aED.d.mts} +1 -1
- package/package.json +21 -21
- package/sandbox.Dockerfile +1 -1
- package/skills/void/SKILL.md +5 -2
- package/skills/void/docs/guide/ai.md +78 -137
- package/skills/void/docs/guide/app-types.md +1 -1
- package/skills/void/docs/guide/auth.md +0 -2
- package/skills/void/docs/guide/database/d1.md +7 -7
- package/skills/void/docs/guide/database.md +15 -0
- package/skills/void/docs/guide/deployment.md +58 -124
- package/skills/void/docs/guide/env-vars.md +1 -5
- package/skills/void/docs/guide/index.md +19 -18
- package/skills/void/docs/guide/kv.md +0 -2
- package/skills/void/docs/guide/live.md +2 -0
- package/skills/void/docs/guide/pages-routing/actions-and-forms.md +49 -47
- package/skills/void/docs/guide/pages-routing/overview.md +2 -2
- package/skills/void/docs/guide/platform/administration/email.md +0 -2
- package/skills/void/docs/guide/platform/administration/operations.md +11 -22
- package/skills/void/docs/guide/platform/administration/plans.md +1 -5
- package/skills/void/docs/guide/platform/administration/zero-trust.md +1 -4
- package/skills/void/docs/guide/platform/development/schema-ci.md +7 -1
- package/skills/void/docs/guide/platform/installation/credentials.md +2 -2
- package/skills/void/docs/guide/platform/installation/first-deployment.md +5 -1
- package/skills/void/docs/guide/platform/installation/maintenance.md +33 -11
- package/skills/void/docs/guide/platform/installation/prerequisites.md +79 -7
- package/skills/void/docs/guide/platform/installation/setup.md +1 -1
- package/skills/void/docs/guide/platform/installation/uninstall.md +44 -11
- package/skills/void/docs/guide/quickstart.md +37 -80
- package/skills/void/docs/guide/sandboxes.md +75 -66
- package/skills/void/docs/guide/self-hosted-platform.md +20 -0
- package/skills/void/docs/guide/websockets.md +0 -2
- package/skills/void/docs/integrations/frameworks/overview.md +2 -2
- package/skills/void/docs/integrations/frameworks/sveltekit.md +40 -25
- package/skills/void/docs/integrations/nodejs-bun-deno.md +7 -2
- package/skills/void/docs/reference/api/resources.md +38 -14
- package/skills/void/docs/reference/api.md +35 -34
- package/skills/void/docs/reference/cli/auth.md +3 -1
- package/skills/void/docs/reference/cli/deploy.md +1 -1
- package/skills/void/docs/reference/cli/platform-config.md +2 -2
- package/skills/void/docs/reference/cli/platform-installation.md +14 -12
- package/skills/void/docs/reference/cli/platform-operations.md +4 -8
- package/skills/void/docs/reference/cli/platform.md +9 -2
- package/skills/void/docs/reference/cli.md +1 -1
- package/skills/void/docs/reference/resource-inference.md +12 -8
- package/dist/cf-build-output-_0HNWysu.mjs +0 -2
- package/dist/client-B9UBI03V.mjs +0 -2
- package/dist/deploy-irP5q0-x.mjs +0 -2
- package/dist/gen-DvQTWzDU.mjs +0 -2
- package/dist/help-mabuIV98.mjs +0 -2
- package/dist/login-DIy9Sb-U.mjs +0 -2
- package/dist/migrate-BCiJ8w0f.mjs +0 -2
- package/dist/plan-D1Q5rf-r.mjs +0 -2
- package/dist/platform-args-DdnM6WIf.mjs +0 -2
- package/dist/platform-management-DG47jys8.mjs +0 -2
- package/dist/prepare-CnjcTV2s.mjs +0 -2
- package/dist/validate-Dq_L3s0S.mjs +0 -2
- package/skills/void/docs/guide/env-migration.md +0 -109
- package/dist/{cf-build-output-BPqOT964.mjs → cf-build-output-U8o1Gl6X.mjs} +1 -1
- package/dist/{env-validation-C_8tPdhs.mjs → env-validation-vBSQ8gw5.mjs} +1 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { c as runInstalledPlatformCommand, d as verifyPlatformInstallationOwnership, l as selectAuthoritativePlatformManifest } from "./platform-management-BrF9STZp.mjs";
|
|
2
|
+
export { runInstalledPlatformCommand, selectAuthoritativePlatformManifest, verifyPlatformInstallationOwnership };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { A as confirm,
|
|
3
|
-
import {
|
|
4
|
-
import { A as
|
|
5
|
-
import { createHash } from "node:crypto";
|
|
1
|
+
import { _ as removePlatformConnectionForInstallation, g as removeInstallationRecoverySecrets, m as readInstallationRecoverySecrets, o as listInstallationManifests, t as acquirePlatformLifecycleLock, v as resolveInstallationManifest, x as writeInstallationManifest } from "./platform-registry-P387v42A.mjs";
|
|
2
|
+
import { A as confirm, H as outro, K as select, L as log, tt as isCancel } from "./prompts-6OSVA7DJ.mjs";
|
|
3
|
+
import { c as import_picocolors, l as note, r as createSpinner } from "./output-BvdaehtE.mjs";
|
|
4
|
+
import { A as resolveBootstrapGitHubId, B as assertPlatformOperatorCredentialCanApplyPlan, C as purgeResourcesKeptReason, D as loadPlatformRuntime, E as runPurgeResourcesTeardown, F as formatPlatformInstallPlan, H as verifyPlatformCloudflareCredential, I as platformAdoptionIntentHash, J as hyperdriveOriginFromConnectionString, K as PlatformCloudflareClient, L as platformProvisionIntentHash, N as trackedPlatformWorkerTraffic, P as createPlatformInstallPlan, R as revalidatePlatformInstallAction, S as purgeResourcesHandlesEmailRouting, T as purgeResourcesPermissions, V as resolvePlatformCloudflareCredential, X as verifyPlatformRuntimeTokenPermissions, Y as hyperdriveOriginMatches, _ as describePurgeResourcesPlan, a as REMOTE_INSTALLATION_MANIFEST_KEY, b as isPurgedAccessResource, d as readPlatformProjectZeroTrustState, f as assertProjectZeroTrustAllowsUninstall, g as checkPurgeResourcesCredentials, h as assertNoPlatformProjects, k as createPlatformInstallationSecrets, m as PlatformResourceChangedError, n as resolvePlatformInstallDatabaseUrl, o as installPlatform, q as hyperdriveOriginConfigHash, s as acquirePlatformDatabaseLifecycleLock, t as assertNoninteractivePlatformMutationAcknowledged, u as readPlatformProjectSlugs, v as isPlatformTailWorker, w as purgeResourcesKeptResources, x as purgeResourcesAlwaysKept, y as isPurgeResourcesCandidate, z as platformDatabaseNameFromOwnerUrl } from "./platform-lifecycle-Cfi0o6xM.mjs";
|
|
6
5
|
import { PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE, PLATFORM_R2_OWNERSHIP_MARKER_KEY, createPlatformResourceOwnershipMarker, parsePlatformInstallationManifest, parsePlatformResourceOwnershipMarker, recordInstallationResource, recordInstallationStep, setInstallationDesiredState, transitionInstallation } from "@void/platform";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
7
|
//#region src/cli/platform-management.ts
|
|
8
8
|
async function verifyPlatformInstallationOwnership(client, manifest, options = {}) {
|
|
9
9
|
const ready = manifest.resources.filter((resource) => resource.state === "ready" && isOwnershipVerifiableKind(resource.kind) && !options.retainedReplacementKeys?.has(resource.key));
|
|
@@ -23,6 +23,22 @@ function selectAuthoritativePlatformManifest(local, authoritative) {
|
|
|
23
23
|
if (authoritative.id !== local.id || authoritative.ownershipNonce !== local.ownershipNonce || authoritative.account.id !== local.account.id) throw new Error("platform: The authoritative lifecycle state belongs to another installation.");
|
|
24
24
|
return authoritative;
|
|
25
25
|
}
|
|
26
|
+
function commandArgument(value) {
|
|
27
|
+
return /^[a-zA-Z0-9_./:@-]+$/.test(value) ? value : `'${value.replaceAll("'", "'\\''")}'`;
|
|
28
|
+
}
|
|
29
|
+
function platformLifecycleResumeCommand(args, installationId) {
|
|
30
|
+
const command = [
|
|
31
|
+
"void",
|
|
32
|
+
"platform",
|
|
33
|
+
args.subcommand,
|
|
34
|
+
commandArgument(installationId)
|
|
35
|
+
];
|
|
36
|
+
if (args.runtime) command.push("--runtime", commandArgument(args.runtime));
|
|
37
|
+
if (args.subcommand === "rollback" && args.fromRuntime) command.push("--from-runtime", commandArgument(args.fromRuntime));
|
|
38
|
+
if ("dashboardUrl" in args && args.dashboardUrl) command.push("--dashboard-url", commandArgument(args.dashboardUrl));
|
|
39
|
+
if (args.yes) command.push("--yes");
|
|
40
|
+
return command.join(" ");
|
|
41
|
+
}
|
|
26
42
|
async function runInstalledPlatformCommand(args) {
|
|
27
43
|
if (args.subcommand !== "upgrade" && args.subcommand !== "rollback" && args.subcommand !== "repair" && args.subcommand !== "disable" && args.subcommand !== "enable" && args.subcommand !== "uninstall") throw new Error(`platform: Unsupported lifecycle command ${args.subcommand}.`);
|
|
28
44
|
assertNoninteractivePlatformMutationAcknowledged(args, process.stdin.isTTY === true);
|
|
@@ -37,6 +53,13 @@ async function runInstalledPlatformCommand(args) {
|
|
|
37
53
|
const manifest = await resolveInstalledPlatformManifest(args.selector);
|
|
38
54
|
const operatorCredential = await resolvePlatformCloudflareCredential({ savedManagementToken: readInstallationRecoverySecrets(manifest)?.managementApiToken });
|
|
39
55
|
const operatorClient = new PlatformCloudflareClient(operatorCredential.token);
|
|
56
|
+
await verifyPlatformCloudflareCredential(operatorClient, {
|
|
57
|
+
account: manifest.account,
|
|
58
|
+
source: operatorCredential.source,
|
|
59
|
+
r2Buckets: args.subcommand === "disable" || args.subcommand === "uninstall" ? [] : manifest.resources.filter((resource) => resource.kind === "r2-bucket").map((resource) => resource.name),
|
|
60
|
+
allowMissingR2Buckets: args.subcommand === "repair"
|
|
61
|
+
});
|
|
62
|
+
markPhase("operator credential");
|
|
40
63
|
const runtime = args.subcommand === "uninstall" || args.subcommand === "disable" ? null : loadPlatformRuntime(args.runtime);
|
|
41
64
|
const rollbackSourceRuntime = args.subcommand === "rollback" ? loadPlatformRuntime(args.fromRuntime) : null;
|
|
42
65
|
let progress;
|
|
@@ -62,7 +85,12 @@ async function runInstalledPlatformCommand(args) {
|
|
|
62
85
|
readProjectZeroTrust: databaseLock ? databaseLock.readProjectZeroTrust : () => readPlatformProjectZeroTrustState(databaseUrl, manifest.id, manifest.ownershipNonce),
|
|
63
86
|
lockProjectZeroTrust: databaseLock?.lockProjectZeroTrust,
|
|
64
87
|
fenceProjectZeroTrust: databaseLock?.fenceProjectZeroTrust,
|
|
65
|
-
liftProjectZeroTrustFence: databaseLock?.liftProjectZeroTrustFence
|
|
88
|
+
liftProjectZeroTrustFence: databaseLock?.liftProjectZeroTrustFence,
|
|
89
|
+
readProjects: databaseLock ? databaseLock.readProjects : () => readPlatformProjectSlugs(databaseUrl, manifest.id, manifest.ownershipNonce),
|
|
90
|
+
credential: {
|
|
91
|
+
source: operatorCredential.source,
|
|
92
|
+
aiGatewayToken: !!gatewayToken
|
|
93
|
+
}
|
|
66
94
|
});
|
|
67
95
|
return;
|
|
68
96
|
}
|
|
@@ -94,20 +122,17 @@ async function runInstalledPlatformCommand(args) {
|
|
|
94
122
|
markPhase("plan");
|
|
95
123
|
note(formatPlatformInstallPlan(plan), args.subcommand === "upgrade" ? "Upgrade plan" : args.subcommand === "rollback" ? "Rollback plan" : args.subcommand === "enable" ? "Enable plan" : "Repair plan");
|
|
96
124
|
note([
|
|
97
|
-
`Version: ${runtime.manifest.platformVersion}`,
|
|
125
|
+
`Version: ${manifest.platformVersion} → ${runtime.manifest.platformVersion}`,
|
|
98
126
|
`Source: ${runtime.source}`,
|
|
99
127
|
`Revision: ${runtime.manifest.sourceRevision ?? "not recorded"}`,
|
|
100
128
|
`Manifest SHA-256: ${runtime.manifestSha256}`
|
|
101
129
|
].join("\n"), "Platform runtime");
|
|
130
|
+
log.info(manifest.desiredState === "disabled" && args.subcommand !== "enable" ? "Application traffic will stay paused because this installation is disabled." : "Application traffic may pause briefly during a safe cutover.");
|
|
102
131
|
if (args.plan) {
|
|
103
132
|
outro("No Cloudflare or local installation state was changed.");
|
|
104
133
|
return;
|
|
105
134
|
}
|
|
106
135
|
assertPlatformOperatorCredentialCanApplyPlan(operatorCredential, plan);
|
|
107
|
-
progress = createSpinner({ onCancel: () => {
|
|
108
|
-
if (!process.emit("SIGINT")) process.exit(130);
|
|
109
|
-
} });
|
|
110
|
-
progress.start(args.subcommand === "upgrade" ? "Upgrading the platform" : args.subcommand === "rollback" ? "Rolling back the platform" : args.subcommand === "enable" ? "Enabling the platform" : "Repairing the platform");
|
|
111
136
|
const repairingMissingRoutingCheckpoint = args.subcommand === "repair" && plan.actions.some((action) => action.key === "routing-kv" && action.action === "create" && action.id === null);
|
|
112
137
|
await verifyPlatformMutationOwnership(client, manifest, new Set(manifest.resources.filter((resource) => isOwnershipVerifiableKind(resource.kind) && !plan.actions.some((action) => action.key === resource.key && action.action === "create" && action.name !== resource.name)).map((resource) => resource.key)), {
|
|
113
138
|
allowMissingRoutingCheckpoint: repairingMissingRoutingCheckpoint,
|
|
@@ -116,7 +141,6 @@ async function runInstalledPlatformCommand(args) {
|
|
|
116
141
|
});
|
|
117
142
|
markPhase("ownership");
|
|
118
143
|
const installation = args.subcommand === "enable" ? setInstallationDesiredState(manifest, "enabled", (/* @__PURE__ */ new Date()).toISOString()) : manifest;
|
|
119
|
-
if (installation !== manifest) writeInstallationManifest(installation);
|
|
120
144
|
const bootstrapGitHubLogin = process.env.VOID_PLATFORM_ADMIN_GITHUB_LOGIN || recovery?.bootstrapGitHubLogin || "";
|
|
121
145
|
const bootstrapGitHubId = process.env.VOID_PLATFORM_ADMIN_GITHUB_ID || recovery?.bootstrapGitHubId || (bootstrapGitHubLogin ? await resolveBootstrapGitHubId(bootstrapGitHubLogin) : "");
|
|
122
146
|
const secrets = createPlatformInstallationSecrets({
|
|
@@ -148,6 +172,11 @@ async function runInstalledPlatformCommand(args) {
|
|
|
148
172
|
});
|
|
149
173
|
markPhase("runtime token");
|
|
150
174
|
if (!databaseLock?.readAuthenticationState) throw new Error("platform: The database lifecycle lock cannot read authoritative authentication settings.");
|
|
175
|
+
progress = createSpinner({ onCancel: () => {
|
|
176
|
+
if (!process.emit("SIGINT")) process.exit(130);
|
|
177
|
+
} });
|
|
178
|
+
progress.start(args.subcommand === "upgrade" ? "Upgrading the platform" : args.subcommand === "rollback" ? "Rolling back the platform" : args.subcommand === "enable" ? "Enabling the platform" : "Repairing the platform");
|
|
179
|
+
if (installation !== manifest) writeInstallationManifest(installation);
|
|
151
180
|
const result = await installPlatform(plan, secrets, installation, {
|
|
152
181
|
acquireDatabaseLifecycleLock: async () => Object.assign(async () => {}, {
|
|
153
182
|
checkpoint: databaseLock?.checkpoint,
|
|
@@ -159,12 +188,14 @@ async function runInstalledPlatformCommand(args) {
|
|
|
159
188
|
verifyDatabase: databaseLock?.verifyDatabase
|
|
160
189
|
}),
|
|
161
190
|
client,
|
|
191
|
+
operatorApiToken: operatorCredential.token,
|
|
162
192
|
databaseRollbackSource: rollbackSourceRuntime ?? void 0,
|
|
163
193
|
onProgress: (message) => {
|
|
164
194
|
markPhase(message);
|
|
165
195
|
progress?.message(message);
|
|
166
196
|
},
|
|
167
197
|
runtime,
|
|
198
|
+
operation: args.subcommand,
|
|
168
199
|
replanWorkers: async (recoveryManifest) => (await createPlatformInstallPlan(client, planInput, recoveryManifest, {
|
|
169
200
|
authoritativeProvisionIntents: true,
|
|
170
201
|
repairMissing: true,
|
|
@@ -183,14 +214,22 @@ async function runInstalledPlatformCommand(args) {
|
|
|
183
214
|
progress?.stop(result.waitingForDns || result.waitingForSandboxDrain ? "Platform operation paused; progress is saved." : `Platform ${args.subcommand} complete.`);
|
|
184
215
|
progress = void 0;
|
|
185
216
|
if (result.waitingForDns) {
|
|
186
|
-
note(`Wait for ${deployment.application.zoneName} to become active, then
|
|
217
|
+
note(`Wait for ${deployment.application.zoneName} to become active, then resume:\n${platformLifecycleResumeCommand(args, manifest.id)}`, "Waiting for nameservers");
|
|
187
218
|
return;
|
|
188
219
|
}
|
|
189
220
|
if (result.waitingForSandboxDrain) {
|
|
190
|
-
note(
|
|
221
|
+
note([
|
|
222
|
+
"Application traffic is paused. Saved progress is ready to resume.",
|
|
223
|
+
"1. Review remaining Sandbox work: void platform system sandbox-drain --plan",
|
|
224
|
+
"2. Apply: void platform system sandbox-drain --yes (follow nextCursor with --cursor '<value>' until complete: true).",
|
|
225
|
+
`3. Resume: ${platformLifecycleResumeCommand(args, manifest.id)}`,
|
|
226
|
+
`Administrator status: ${plan.apiUrl}/admin/status`
|
|
227
|
+
].join("\n"), "Waiting for managed Sandbox drain");
|
|
191
228
|
return;
|
|
192
229
|
}
|
|
193
|
-
log.success(
|
|
230
|
+
log.success(`${deployment.displayName}: runtime ${runtime.manifest.platformVersion} ${args.subcommand === "rollback" ? "restored" : "ready"}.`);
|
|
231
|
+
log.info(result.manifest.desiredState === "disabled" ? "Application traffic remains paused. Enable the installation when you are ready." : `Platform verification passed. Traffic is enabled at ${plan.apiUrl}.`);
|
|
232
|
+
if (args.subcommand === "rollback") log.info("PostgreSQL migrations were retained; rollback changes the runtime only.");
|
|
194
233
|
if (result.emailOperationId) log.info(`Shared email routing ready (operation ${result.emailOperationId}).`);
|
|
195
234
|
if (result.setupPending) {
|
|
196
235
|
const code = readInstallationRecoverySecrets(result.manifest)?.authBootstrapCode;
|
|
@@ -226,8 +265,15 @@ async function runInstalledPlatformCommand(args) {
|
|
|
226
265
|
reportResult?.();
|
|
227
266
|
markPhase("complete");
|
|
228
267
|
} catch (error) {
|
|
268
|
+
const operationStarted = progress !== void 0;
|
|
229
269
|
progress?.error(`Platform ${args.subcommand} failed.`);
|
|
230
270
|
progress = void 0;
|
|
271
|
+
if (operationStarted && args.subcommand !== "uninstall" && args.subcommand !== "disable") note([
|
|
272
|
+
"Traffic may remain paused. Inspect the saved state before continuing:",
|
|
273
|
+
`void platform status ${commandArgument(manifest.id)}`,
|
|
274
|
+
"After resolving the error, resume with the same runtime:",
|
|
275
|
+
platformLifecycleResumeCommand(args, manifest.id)
|
|
276
|
+
].join("\n"), "Recovery");
|
|
231
277
|
throw error;
|
|
232
278
|
} finally {
|
|
233
279
|
try {
|
|
@@ -276,7 +322,7 @@ async function disablePlatform(client, initialManifest, planOnly, dependencies =
|
|
|
276
322
|
const reconciled = await recoverDurablyMarkedProvisionIntents(client, initialManifest);
|
|
277
323
|
const writeLifecycleCheckpoint = (checkpointClient, checkpointManifest) => writeLifecycleCheckpointWithoutDatabase(checkpointClient, checkpointManifest, dependencies.checkpoint);
|
|
278
324
|
const writeRemoteManifestIfPresent = (checkpointClient, checkpointManifest) => writeRemoteManifestIfPresentWithoutDatabase(checkpointClient, checkpointManifest, dependencies.checkpoint);
|
|
279
|
-
note("Block platform traffic
|
|
325
|
+
note("Block all platform traffic and the platform API. Routes, custom domains, Workers, and data stay installed.", "Disable plan");
|
|
280
326
|
if (planOnly) {
|
|
281
327
|
outro("No Cloudflare or local installation state was changed.");
|
|
282
328
|
return;
|
|
@@ -321,14 +367,33 @@ async function uninstallPlatform(client, initialManifest, args, dependencies = {
|
|
|
321
367
|
const writeLifecycleCheckpoint = (checkpointClient, checkpointManifest) => writeLifecycleCheckpointWithoutDatabase(checkpointClient, checkpointManifest, dependencies.checkpoint);
|
|
322
368
|
const writeRemoteManifestIfPresent = (checkpointClient, checkpointManifest) => writeRemoteManifestIfPresentWithoutDatabase(checkpointClient, checkpointManifest, dependencies.checkpoint);
|
|
323
369
|
const retainData = !args.purgeData;
|
|
324
|
-
const
|
|
370
|
+
const purgeResources = args.purgeResources;
|
|
371
|
+
const routingKv = manifest.resources.find((resource) => resource.key === "routing-kv");
|
|
372
|
+
const reopenedRouting = purgeResources && routingKv?.state === "retained" && isPurgeResourcesCandidate(manifest, routingKv);
|
|
373
|
+
const hasRoutingCheckpoint = routingKv?.state === "ready" || reopenedRouting;
|
|
325
374
|
const createdZone = manifest.resources.find((resource) => resource.key === "zone" && resource.ownership === "created");
|
|
326
375
|
const interactive = dependencies.interactive ?? process.stdin.isTTY;
|
|
327
376
|
const confirmAction = dependencies.confirm ?? promptForConfirmation;
|
|
328
377
|
if (createdZone && args.deleteZone === true) throw new Error(`platform: Refusing to delete Cloudflare zone ${JSON.stringify(createdZone.name)} automatically. A zone can contain unrelated DNS, settings, and products that the installer cannot exhaustively prove ownership of. Uninstall with --keep-zone, inspect the retained zone in Cloudflare, and delete it manually if appropriate.`);
|
|
329
378
|
await assertProjectZeroTrustAllowsUninstall(dependencies.readProjectZeroTrust);
|
|
330
|
-
|
|
331
|
-
|
|
379
|
+
if (purgeResources) await assertNoPlatformProjects(dependencies.readProjects);
|
|
380
|
+
const purgeResourcesClient = purgeResources ? requirePurgeResourcesClient(client) : null;
|
|
381
|
+
if (args.plan || interactive && !args.yes) note(purgeResources ? purgeResourcesPlanText(manifest) : [
|
|
382
|
+
"Disable platform traffic.",
|
|
383
|
+
retainData ? "Keep Workers and data." : "Delete eligible data; keep Workers, R2, and AI Gateway.",
|
|
384
|
+
"Delete unused Queues.",
|
|
385
|
+
...describeKeptResources(manifest, plannedKeptResources(manifest, retainData, hasRoutingCheckpoint), "Keep for manual cleanup:", "Keep Access resources:")
|
|
386
|
+
].join("\n"), import_picocolors.default.bold("Uninstall plan"));
|
|
387
|
+
if (purgeResourcesClient) {
|
|
388
|
+
const credentialCheck = checkPurgeResourcesCredentials(purgeResourcesClient, manifest, dependencies.credential ?? {
|
|
389
|
+
source: "environment",
|
|
390
|
+
aiGatewayToken: false
|
|
391
|
+
});
|
|
392
|
+
if (args.plan) await credentialCheck.catch((error) => {
|
|
393
|
+
log.warn(error instanceof Error ? error.message : String(error));
|
|
394
|
+
});
|
|
395
|
+
else await credentialCheck;
|
|
396
|
+
}
|
|
332
397
|
if (args.plan) {
|
|
333
398
|
outro("No Cloudflare or local installation state was changed.");
|
|
334
399
|
return;
|
|
@@ -336,20 +401,29 @@ async function uninstallPlatform(client, initialManifest, args, dependencies = {
|
|
|
336
401
|
if (manifest !== initialManifest) writeInstallationManifest(manifest);
|
|
337
402
|
if (!interactive && !args.yes) throw new Error("platform: Non-interactive `void platform uninstall` requires --yes to acknowledge Cloudflare changes. Run with --plan first to inspect them.");
|
|
338
403
|
if (interactive && !args.yes) {
|
|
339
|
-
if (!await confirmAction(args.purgeData ? "Permanently purge installer-owned platform data?" : "Uninstall this platform?", false)) {
|
|
404
|
+
if (!await confirmAction(purgeResources ? "Permanently delete every Cloudflare resource this installation created?" : args.purgeData ? "Permanently purge installer-owned platform data?" : "Uninstall this platform?", false)) {
|
|
340
405
|
outro("No changes made.");
|
|
341
406
|
return;
|
|
342
407
|
}
|
|
343
408
|
}
|
|
344
|
-
|
|
409
|
+
log.step(`Uninstalling ${manifest.deployment.displayName}...`);
|
|
410
|
+
const purgeResourcesKept = new Set(purgeResources ? purgeResourcesKeptResources(manifest).map((resource) => resource.key) : []);
|
|
411
|
+
const resourcesToDelete = new Set(manifest.resources.filter((resource) => (shouldDeleteResource(resource, retainData) || purgeResources && (resource.state === "ready" || isPurgeResourcesCandidate(manifest, resource)) && !purgeResourcesKept.has(resource.key) && isOwnershipVerifiableKind(resource.kind) && resource.kind !== "dns-record" && !hasLifecycleStep(manifest, `uninstall:purge-resources:r2-marker:${resource.key}`)) && (hasRoutingCheckpoint || resource.kind === "zone") && !(resource.kind === "dns-record" && !manifest.resources.some((entry) => entry.key === "zone"))).map((resource) => resource.key));
|
|
345
412
|
const ownershipTargets = /* @__PURE__ */ new Set([
|
|
346
413
|
...hasRoutingCheckpoint ? ["routing-kv"] : [],
|
|
347
414
|
"zone",
|
|
348
415
|
...manifest.resources.filter((resource) => resource.kind === "worker").map((resource) => resource.key),
|
|
349
416
|
...resourcesToDelete
|
|
350
417
|
]);
|
|
418
|
+
const proofManifest = {
|
|
419
|
+
...manifest,
|
|
420
|
+
resources: manifest.resources.map((resource) => resource.state === "retained" && resourcesToDelete.has(resource.key) ? {
|
|
421
|
+
...resource,
|
|
422
|
+
state: "ready"
|
|
423
|
+
} : resource)
|
|
424
|
+
};
|
|
351
425
|
let missingResources;
|
|
352
|
-
if (hasRoutingCheckpoint) missingResources = await verifyPlatformMutationOwnership(client,
|
|
426
|
+
if (hasRoutingCheckpoint) missingResources = await verifyPlatformMutationOwnership(client, proofManifest, ownershipTargets, {
|
|
353
427
|
allowDeletedRoutingCheckpoint: args.purgeData,
|
|
354
428
|
databaseUrl: dependencies.databaseUrl
|
|
355
429
|
});
|
|
@@ -371,6 +445,7 @@ async function uninstallPlatform(client, initialManifest, args, dependencies = {
|
|
|
371
445
|
let next = manifest;
|
|
372
446
|
try {
|
|
373
447
|
await assertProjectZeroTrustAllowsUninstall(dependencies.readProjectZeroTrust);
|
|
448
|
+
if (purgeResources) await assertNoPlatformProjects(dependencies.readProjects);
|
|
374
449
|
fenced = true;
|
|
375
450
|
await fenceProjectZeroTrust();
|
|
376
451
|
next = transitionInstallation(manifest, "uninstalling", (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -381,7 +456,7 @@ async function uninstallPlatform(client, initialManifest, args, dependencies = {
|
|
|
381
456
|
}
|
|
382
457
|
try {
|
|
383
458
|
await writeRemoteManifestIfPresent(client, next);
|
|
384
|
-
const routing =
|
|
459
|
+
const routing = hasRoutingCheckpoint ? requireResource(next, "routing-kv") : void 0;
|
|
385
460
|
disablingTraffic = true;
|
|
386
461
|
if (routing) await client.putKvValue(next.account.id, routing.id, PLATFORM_DISABLED_KEY, PLATFORM_DISABLED_VALUE);
|
|
387
462
|
await releaseProjectZeroTrust();
|
|
@@ -405,6 +480,23 @@ async function uninstallPlatform(client, initialManifest, args, dependencies = {
|
|
|
405
480
|
await writeLifecycleCheckpoint(client, next);
|
|
406
481
|
}
|
|
407
482
|
}
|
|
483
|
+
if (purgeResourcesClient && hasRoutingCheckpoint) next = await runPurgeResourcesTeardown({
|
|
484
|
+
client: purgeResourcesClient,
|
|
485
|
+
checkpoint: async (checkpointManifest) => {
|
|
486
|
+
next = checkpointManifest;
|
|
487
|
+
await writeLifecycleCheckpoint(client, checkpointManifest);
|
|
488
|
+
},
|
|
489
|
+
verify: (checkpointManifest, keys) => verifyPlatformMutationOwnership(client, checkpointManifest, keys, {
|
|
490
|
+
allowDeletedRoutingCheckpoint: true,
|
|
491
|
+
databaseUrl: dependencies.databaseUrl
|
|
492
|
+
}),
|
|
493
|
+
bucketGeneration: async (checkpointManifest, bucket) => {
|
|
494
|
+
const live = (await client.listR2Buckets(checkpointManifest.account.id)).find((entry) => entry.id === bucket.id && entry.name === bucket.name);
|
|
495
|
+
if (!live) return null;
|
|
496
|
+
return live.fingerprint === void 0 ? "unknown" : r2BucketConfigHash(bucket.name, live.fingerprint);
|
|
497
|
+
},
|
|
498
|
+
readProjects: () => dependencies.readProjects()
|
|
499
|
+
}, next);
|
|
408
500
|
const deletionPriority = {
|
|
409
501
|
worker: 0,
|
|
410
502
|
queue: 1,
|
|
@@ -418,7 +510,11 @@ async function uninstallPlatform(client, initialManifest, args, dependencies = {
|
|
|
418
510
|
};
|
|
419
511
|
const resources = [...next.resources].sort((left, right) => resourceDeletionPriority(left, deletionPriority) - resourceDeletionPriority(right, deletionPriority));
|
|
420
512
|
const queuesInUse = hasRoutingCheckpoint && resources.some((resource) => resource.kind === "queue" && shouldDeleteResource(resource, retainData)) && await hasLiveInstallationWorker(client, next);
|
|
421
|
-
for (const
|
|
513
|
+
for (const listed of resources) {
|
|
514
|
+
const resource = reopenedRouting && listed.key === "routing-kv" ? {
|
|
515
|
+
...listed,
|
|
516
|
+
state: "ready"
|
|
517
|
+
} : listed;
|
|
422
518
|
if (resource.state !== "ready") continue;
|
|
423
519
|
if (!hasRoutingCheckpoint && resource.kind !== "zone") {
|
|
424
520
|
next = updateResourceState(next, resource.key, "retained");
|
|
@@ -426,7 +522,8 @@ async function uninstallPlatform(client, initialManifest, args, dependencies = {
|
|
|
426
522
|
continue;
|
|
427
523
|
}
|
|
428
524
|
if (!shouldDeleteResource(resource, retainData)) {
|
|
429
|
-
|
|
525
|
+
const removed = resource.kind === "ai-gateway" && resource.ownership === "created" && !hasNamedResource(await client.listAiGateways(next.account.id), resource);
|
|
526
|
+
next = updateResourceState(next, resource.key, removed ? "deleted" : "retained");
|
|
430
527
|
await writeLifecycleCheckpoint(client, next);
|
|
431
528
|
continue;
|
|
432
529
|
}
|
|
@@ -443,7 +540,7 @@ async function uninstallPlatform(client, initialManifest, args, dependencies = {
|
|
|
443
540
|
await writeLifecycleCheckpoint(client, next);
|
|
444
541
|
continue;
|
|
445
542
|
}
|
|
446
|
-
await client.deleteResource(next.account.id, resource
|
|
543
|
+
await client.deleteResource(next.account.id, resource, zone?.id);
|
|
447
544
|
next = updateResourceState(next, resource.key, "deleted");
|
|
448
545
|
await writeLifecycleCheckpoint(client, next);
|
|
449
546
|
}
|
|
@@ -453,7 +550,9 @@ async function uninstallPlatform(client, initialManifest, args, dependencies = {
|
|
|
453
550
|
writeInstallationManifest(completed);
|
|
454
551
|
if (!retainData) removeInstallationRecoverySecrets(next);
|
|
455
552
|
removePlatformConnectionForInstallation(next.id);
|
|
456
|
-
|
|
553
|
+
const kept = describeKeptResources(next, next.resources.filter((resource) => resource.state === "retained"), "Cloudflare resources:", "Access resources:", purgeResources && purgeResourcesHandlesEmailRouting(next));
|
|
554
|
+
if (kept.length) note(kept.join("\n"), import_picocolors.default.bold("Kept resources"));
|
|
555
|
+
log.success(`Uninstalled ${next.deployment.displayName}.`);
|
|
457
556
|
} catch (error) {
|
|
458
557
|
await stopProjectZeroTrustHold().catch(() => {});
|
|
459
558
|
next = transitionInstallation(next, "failed", (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -531,6 +630,87 @@ const DATA_RESOURCE_KINDS = /* @__PURE__ */ new Set([
|
|
|
531
630
|
function isOwnershipVerifiableKind(kind) {
|
|
532
631
|
return kind === "ai-gateway" || kind === "dispatch-namespace" || kind === "dns-record" || kind === "hyperdrive" || kind === "kv-namespace" || kind === "queue" || kind === "r2-bucket" || kind === "worker" || kind === "zone";
|
|
533
632
|
}
|
|
633
|
+
const KEPT_RESOURCE_ORDER = [
|
|
634
|
+
"dns-record",
|
|
635
|
+
"worker-route",
|
|
636
|
+
"worker-custom-domain",
|
|
637
|
+
"queue",
|
|
638
|
+
"worker",
|
|
639
|
+
"dispatch-namespace",
|
|
640
|
+
"kv-namespace",
|
|
641
|
+
"hyperdrive",
|
|
642
|
+
"r2-bucket",
|
|
643
|
+
"ai-gateway",
|
|
644
|
+
"analytics-dataset",
|
|
645
|
+
"zone"
|
|
646
|
+
];
|
|
647
|
+
/** Resources an uninstall with these options leaves in the account. */
|
|
648
|
+
function plannedKeptResources(manifest, retainData, hasRoutingCheckpoint) {
|
|
649
|
+
const workersRemain = manifest.resources.some((resource) => resource.kind === "worker" && resource.state === "ready");
|
|
650
|
+
return manifest.resources.filter((resource) => resource.state === "retained" || resource.state === "ready" && (!hasRoutingCheckpoint && resource.kind !== "zone" || !shouldDeleteResource(resource, retainData) || resource.kind === "queue" && workersRemain));
|
|
651
|
+
}
|
|
652
|
+
function keptResourceRank(manifest, resource) {
|
|
653
|
+
return isPlatformTailWorker(manifest, resource) ? KEPT_RESOURCE_ORDER.indexOf("dispatch-namespace") + .5 : KEPT_RESOURCE_ORDER.indexOf(resource.kind);
|
|
654
|
+
}
|
|
655
|
+
function purgeResourcesPlanText(manifest) {
|
|
656
|
+
const permissions = purgeResourcesPermissions(manifest);
|
|
657
|
+
const keepManifest = {
|
|
658
|
+
...manifest,
|
|
659
|
+
authenticationResources: (manifest.authenticationResources ?? []).filter((resource) => resource.ownership !== "created" || purgeResourcesKeptReason(manifest, `access:${resource.key}`) !== null)
|
|
660
|
+
};
|
|
661
|
+
return [
|
|
662
|
+
"Disable platform traffic.",
|
|
663
|
+
...describePurgeResourcesPlan(manifest),
|
|
664
|
+
...describeKeptResources(keepManifest, purgeResourcesKeptResources(manifest), "Keep for manual cleanup:", "Keep Access resources you connected:", purgeResourcesHandlesEmailRouting(manifest)),
|
|
665
|
+
"Always kept:",
|
|
666
|
+
...purgeResourcesAlwaysKept(),
|
|
667
|
+
...permissions.length ? [`API token needs: ${permissions.join(", ")}. Browser login cannot delete DNS records or Access resources.`] : []
|
|
668
|
+
].join("\n");
|
|
669
|
+
}
|
|
670
|
+
function requirePurgeResourcesClient(client) {
|
|
671
|
+
if ([
|
|
672
|
+
"deleteAccessResource",
|
|
673
|
+
"deleteDispatchNamespaceScript",
|
|
674
|
+
"deleteEmailRoutingRule",
|
|
675
|
+
"deleteQueueConsumer",
|
|
676
|
+
"deleteR2Object",
|
|
677
|
+
"deleteWorkerDomain",
|
|
678
|
+
"deleteWorkerRoute",
|
|
679
|
+
"emptyR2Bucket",
|
|
680
|
+
"forceDeleteWorker",
|
|
681
|
+
"getAccessResource",
|
|
682
|
+
"getEmailRoutingCatchAll",
|
|
683
|
+
"listDispatchNamespaceScripts",
|
|
684
|
+
"listEmailRoutingRules",
|
|
685
|
+
"listQueueConsumers",
|
|
686
|
+
"listWorkerDependents",
|
|
687
|
+
"listWorkerRoutes",
|
|
688
|
+
"resetEmailRoutingCatchAll"
|
|
689
|
+
].some((method) => typeof client[method] !== "function")) throw new Error("platform: This Cloudflare client cannot run --purge-resources.");
|
|
690
|
+
return client;
|
|
691
|
+
}
|
|
692
|
+
function describeKeptResources(manifest, resources, heading, accessHeading, emailRulesRemoved = false) {
|
|
693
|
+
const sorted = [...resources].sort((left, right) => keptResourceRank(manifest, left) - keptResourceRank(manifest, right));
|
|
694
|
+
const isTraffic = (resource) => KEPT_RESOURCE_ORDER.indexOf(resource.kind) < KEPT_RESOURCE_ORDER.indexOf("queue");
|
|
695
|
+
const why = (key) => {
|
|
696
|
+
const reason = purgeResourcesKeptReason(manifest, key);
|
|
697
|
+
return reason === null ? "" : `, kept because ${reason}`;
|
|
698
|
+
};
|
|
699
|
+
const line = (resource) => ` ${resource.kind}: ${resource.name}${resource.name === resource.id ? "" : ` (${resource.id})`}${why(resource.key)}`;
|
|
700
|
+
const { capabilities, emailSenderDomain, emailSharedZoneId, resources: names } = manifest.deployment;
|
|
701
|
+
const email = capabilities.email ? [emailRulesRemoved && emailSenderDomain ? ` Email Routing for ${emailSenderDomain} (zone ${emailSharedZoneId}): its settings and the sender domain's MX, SPF, and DKIM records.` : emailSenderDomain ? ` Email Routing for ${emailSenderDomain} (zone ${emailSharedZoneId}): its routing DNS records and any catch-all rule that sends mail to ${names.emailGatewayWorker}.` : ` Email Routing: any catch-all rule that sends mail to ${names.emailGatewayWorker}.`] : [];
|
|
702
|
+
const remainingAccess = (manifest.authenticationResources ?? []).filter((resource) => !isPurgedAccessResource(manifest, resource));
|
|
703
|
+
const accessLine = (resource) => ` ${resource.ownership} ${resource.kind}: ${resource.name} (${resource.id}, account ${resource.accountId})${why(`access:${resource.key}`)}`;
|
|
704
|
+
const keptAccess = (resource) => purgeResourcesKeptReason(manifest, `access:${resource.key}`) !== null;
|
|
705
|
+
const kept = [
|
|
706
|
+
...sorted.filter(isTraffic).map(line),
|
|
707
|
+
...remainingAccess.filter(keptAccess).map(accessLine),
|
|
708
|
+
...email,
|
|
709
|
+
...sorted.filter((resource) => !isTraffic(resource)).map(line)
|
|
710
|
+
];
|
|
711
|
+
const access = remainingAccess.filter((resource) => !keptAccess(resource)).map(accessLine);
|
|
712
|
+
return [...kept.length ? [heading, ...kept] : [], ...access.length ? [accessHeading, ...access] : []];
|
|
713
|
+
}
|
|
534
714
|
function shouldDeleteResource(resource, retainData) {
|
|
535
715
|
if (resource.state !== "ready" || resource.ownership !== "created") return false;
|
|
536
716
|
if (resource.kind === "zone") return false;
|
|
@@ -604,7 +784,7 @@ async function verifyPlatformMutationOwnership(client, manifest, targetKeys, opt
|
|
|
604
784
|
const zone = manifest.resources.find((resource) => resource.key === "zone");
|
|
605
785
|
const [aiGateways, dispatchNamespaces, hyperdrives, kvNamespaces, r2Buckets, workerNames] = await Promise.all([
|
|
606
786
|
client.listAiGateways(accountId),
|
|
607
|
-
client.listDispatchNamespaces(accountId),
|
|
787
|
+
targetResources.some((resource) => resource.kind === "dispatch-namespace") ? client.listDispatchNamespaces(accountId) : Promise.resolve([]),
|
|
608
788
|
client.listHyperdriveConfigs(accountId),
|
|
609
789
|
client.listKvNamespaces(accountId),
|
|
610
790
|
client.listR2Buckets(accountId),
|
|
@@ -649,7 +829,7 @@ async function verifyPlatformMutationOwnership(client, manifest, targetKeys, opt
|
|
|
649
829
|
name: resource.name
|
|
650
830
|
})).digest("hex");
|
|
651
831
|
const expectedHash = dnsRecordConfigHash(resource.name, "AAAA", "100::", true);
|
|
652
|
-
if (liveHash !== resource.configHash && !(resource.configHash === legacyHash && liveHash === expectedHash)) throw ownershipError(`dns-record ${resource.name} changed configuration after installation`);
|
|
832
|
+
if (liveHash !== resource.configHash && !(resource.configHash === legacyHash && liveHash === expectedHash)) throw new PlatformResourceChangedError(resource.key, "its configuration changed after installation", ownershipError(`dns-record ${resource.name} changed configuration after installation`).message);
|
|
653
833
|
}
|
|
654
834
|
}
|
|
655
835
|
} else if (resource.kind === "worker") {
|
|
@@ -688,7 +868,7 @@ function isPlatformManifestMonotonicExtension(earlier, later) {
|
|
|
688
868
|
if (earlier.id !== later.id || earlier.ownershipNonce !== later.ownershipNonce || earlier.account.id !== later.account.id || earlier.createdAt !== later.createdAt || JSON.stringify(earlier.deployment) !== JSON.stringify(later.deployment) || Date.parse(later.updatedAt) < Date.parse(earlier.updatedAt)) return false;
|
|
689
869
|
const resourcesAdvance = earlier.resources.every((resource) => {
|
|
690
870
|
const next = later.resources.find((entry) => entry.key === resource.key);
|
|
691
|
-
return next?.id === resource.id && next.kind === resource.kind && next.name === resource.name && next.ownership === resource.ownership && (next.state === resource.state || resource.state === "ready" && (next.state === "deleted" || next.state === "retained"));
|
|
871
|
+
return next?.id === resource.id && next.kind === resource.kind && next.name === resource.name && next.ownership === resource.ownership && (next.state === resource.state || resource.state === "ready" && (next.state === "deleted" || next.state === "retained") || resource.state === "retained" && next.state === "deleted");
|
|
692
872
|
});
|
|
693
873
|
const stepsAdvance = earlier.steps.every((step) => later.steps.some((entry) => entry.key === step.key && entry.completedAt === step.completedAt && entry.resultHash === step.resultHash));
|
|
694
874
|
const authenticationResourcesAdvance = (earlier.authenticationResources ?? []).every((resource) => (later.authenticationResources ?? []).some((next) => JSON.stringify(next) === JSON.stringify(resource)));
|
|
@@ -791,4 +971,4 @@ async function promptForConfirmation(message, initialValue) {
|
|
|
791
971
|
return answer;
|
|
792
972
|
}
|
|
793
973
|
//#endregion
|
|
794
|
-
export {
|
|
974
|
+
export { recoverDurablyMarkedProvisionIntents as a, runInstalledPlatformCommand as c, verifyPlatformInstallationOwnership as d, platformLifecycleResumeCommand as i, selectAuthoritativePlatformManifest as l, disablePlatform as n, resolveInstalledPlatformManifest as o, isPlatformManifestMonotonicExtension as r, resolvePlatformRuntimeTokenToPreflight as s, assertPlatformRollbackCompatibility as t, uninstallPlatform as u };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as confirm, K as select, X as text, tt as isCancel } from "./prompts-
|
|
2
|
-
import { n as OperatorClient, r as OperatorClientError } from "./operator-client-
|
|
3
|
-
import { a as resolveOperatorOrigin, r as readOperatorToken } from "./operator-auth-
|
|
1
|
+
import { A as confirm, K as select, X as text, tt as isCancel } from "./prompts-6OSVA7DJ.mjs";
|
|
2
|
+
import { n as OperatorClient, r as OperatorClientError } from "./operator-client-BFqpp6z0.mjs";
|
|
3
|
+
import { a as resolveOperatorOrigin, r as readOperatorToken } from "./operator-auth-2dsGlTT5.mjs";
|
|
4
4
|
import { stripVTControlCharacters } from "node:util";
|
|
5
5
|
import { PLAN_EDITABLE_LIMIT_KEYS, PLAN_LIMITS, parseBuildInstanceType, parsePlanLimitsPatch, parsePlanName, parsePlatformPlanId } from "@void/platform/plans";
|
|
6
6
|
import { readFile } from "node:fs/promises";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { o as listInstallationManifests, t as acquirePlatformLifecycleLock, x as writeInstallationManifest, y as savePlatformConnection } from "./platform-registry-P387v42A.mjs";
|
|
1
2
|
import { t as cfAccessHeaders } from "./cf-access-TWNzXltp.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { a as
|
|
4
|
-
import { i as recoverDurablyMarkedProvisionIntents, r as isPlatformManifestMonotonicExtension, u as verifyPlatformInstallationOwnership } from "./platform-management-CWOQOWXm.mjs";
|
|
3
|
+
import { P as createPlatformInstallPlan, a as REMOTE_INSTALLATION_MANIFEST_KEY } from "./platform-lifecycle-Cfi0o6xM.mjs";
|
|
4
|
+
import { a as recoverDurablyMarkedProvisionIntents, d as verifyPlatformInstallationOwnership, r as isPlatformManifestMonotonicExtension } from "./platform-management-BrF9STZp.mjs";
|
|
5
5
|
import { parsePlatformInstallationManifest, setInstallationEndpoints } from "@void/platform";
|
|
6
6
|
//#region src/cli/platform-recovery.ts
|
|
7
7
|
async function recoverPlatformInstallations(client, accountId, verifyEndpoint = verifyInstallationEndpoint, selector = "") {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { a as join, u as resolve } from "./dist-BVqXeR_h.mjs";
|
|
2
2
|
import { closeSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { parsePlatformInstallationManifest } from "@void/platform";
|
|
3
4
|
import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:crypto";
|
|
4
5
|
import { homedir, hostname } from "node:os";
|
|
5
6
|
import { Entry } from "@napi-rs/keyring";
|
|
6
|
-
import { parsePlatformInstallationManifest } from "@void/platform";
|
|
7
7
|
//#region src/cli/keyring.ts
|
|
8
8
|
function readKeyringPassword(service, account) {
|
|
9
9
|
try {
|
|
@@ -189,6 +189,19 @@ function getActivePlatformConnection(directory = platformRegistryDirectory()) {
|
|
|
189
189
|
const registry = readRegistry(directory);
|
|
190
190
|
return registry.connections.find((connection) => connection.id === registry.activeConnectionId) ?? (registry.connections.length === 1 ? registry.connections[0] : null);
|
|
191
191
|
}
|
|
192
|
+
function platformConnectionSlug(connection, installations) {
|
|
193
|
+
const matches = installations.filter((manifest) => manifest.status !== "uninstalled" && manifest.id === connection.installationId && (connection.accountId === null || connection.accountId === manifest.account.id));
|
|
194
|
+
return matches.length === 1 ? matches[0].deployment.installationSlug : null;
|
|
195
|
+
}
|
|
196
|
+
/** Resolve saved platforms without selecting one or changing its credentials. */
|
|
197
|
+
function findPlatformConnections(selector, directory = platformRegistryDirectory(), connections = listPlatformConnections(directory)) {
|
|
198
|
+
let normalizedUrl = null;
|
|
199
|
+
try {
|
|
200
|
+
normalizedUrl = normalizePlatformApiUrl(selector);
|
|
201
|
+
} catch {}
|
|
202
|
+
const installations = connections.some((connection) => connection.installationId) ? listInstallationManifests(directory) : [];
|
|
203
|
+
return connections.filter((entry) => entry.id === selector || entry.installationId === selector || entry.displayName.toLowerCase() === selector.toLowerCase() || entry.apiUrl === normalizedUrl || platformConnectionSlug(entry, installations) === selector.toLowerCase());
|
|
204
|
+
}
|
|
192
205
|
function savePlatformConnection(input, directory = platformRegistryDirectory()) {
|
|
193
206
|
const apiUrl = normalizePlatformApiUrl(input.apiUrl);
|
|
194
207
|
const id = platformConnectionId(apiUrl);
|
|
@@ -214,14 +227,7 @@ function savePlatformConnection(input, directory = platformRegistryDirectory())
|
|
|
214
227
|
function selectPlatformConnection(selector, directory = platformRegistryDirectory()) {
|
|
215
228
|
return withRegistryLock(directory, () => {
|
|
216
229
|
const current = readRegistry(directory);
|
|
217
|
-
const
|
|
218
|
-
try {
|
|
219
|
-
return normalizePlatformApiUrl(selector);
|
|
220
|
-
} catch {
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
})();
|
|
224
|
-
const matches = current.connections.filter((entry) => entry.id === selector || entry.installationId === selector || entry.displayName.toLowerCase() === selector.toLowerCase() || normalizedUrl !== null && entry.apiUrl === normalizedUrl);
|
|
230
|
+
const matches = findPlatformConnections(selector, directory, current.connections);
|
|
225
231
|
if (matches.length !== 1) throw new Error(matches.length === 0 ? `platform: No installed or connected platform matches ${JSON.stringify(selector)}.` : `platform: More than one platform matches ${JSON.stringify(selector)}. Use its id or URL.`);
|
|
226
232
|
const selected = {
|
|
227
233
|
...matches[0],
|
|
@@ -273,7 +279,8 @@ function listInstallationManifests(directory = platformRegistryDirectory()) {
|
|
|
273
279
|
return manifests.sort((left, right) => left.deployment.displayName.localeCompare(right.deployment.displayName));
|
|
274
280
|
}
|
|
275
281
|
function resolveInstallationManifest(selector, directory = platformRegistryDirectory()) {
|
|
276
|
-
const
|
|
282
|
+
const connection = selector ? listPlatformConnections(directory).find((entry) => entry.id === selector) : void 0;
|
|
283
|
+
const manifests = listInstallationManifests(directory).filter((manifest) => manifest.status !== "uninstalled" && (!selector || manifest.id === selector || manifest.id === connection?.installationId && (connection.accountId === null || connection.accountId === manifest.account.id) || manifest.deployment.installationSlug === selector || manifest.deployment.displayName.toLowerCase() === selector.toLowerCase()));
|
|
277
284
|
if (manifests.length !== 1) throw new Error(manifests.length === 0 ? `platform: No local installation matches ${JSON.stringify(selector)}.` : "platform: Multiple local installations match; specify an installation id.");
|
|
278
285
|
return manifests[0];
|
|
279
286
|
}
|
|
@@ -428,4 +435,4 @@ function removePlatformConnectionForInstallation(installationId, directory = pla
|
|
|
428
435
|
});
|
|
429
436
|
}
|
|
430
437
|
//#endregion
|
|
431
|
-
export {
|
|
438
|
+
export { deleteKeyringPassword as C, writePendingInstallationSecrets as S, writeKeyringPassword as T, removePlatformConnectionForInstallation as _, latestPlatformWorkerCutoverGeneration as a, selectPlatformConnection as b, normalizePlatformApiUrl as c, platformRegistryDirectory as d, platformWorkerSecretUpdateIntentState as f, removeInstallationRecoverySecrets as g, readPendingInstallationSecrets as h, getActivePlatformConnection as i, platformConnectionSlug as l, readInstallationRecoverySecrets as m, assertPlatformInstallationSlugAvailable as n, listInstallationManifests as o, promoteInstallationSecrets as p, findPlatformConnections as r, listPlatformConnections as s, acquirePlatformLifecycleLock as t, platformCredentialAccount as u, resolveInstallationManifest as v, readKeyringPassword as w, writeInstallationManifest as x, savePlatformConnection as y };
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { t as prepareProject } from "./prepare-
|
|
1
|
+
import { H as outro, L as log } from "./prompts-6OSVA7DJ.mjs";
|
|
2
|
+
import { l as note } from "./output-BvdaehtE.mjs";
|
|
3
|
+
import { t as prepareProject } from "./prepare-WoUubFKL.mjs";
|
|
4
4
|
//#region src/cli/prepare.ts
|
|
5
5
|
async function runPrepareCommand(root, _args) {
|
|
6
6
|
console.log();
|
|
7
|
-
intro(cliTitle("prepare"));
|
|
8
7
|
const result = await prepareProject(root);
|
|
9
8
|
if (result.written.length > 0) note(result.written.join("\n"), "Wrote");
|
|
10
9
|
if (result.removed.length > 0) note(result.removed.join("\n"), "Removed stale files");
|
|
@@ -6,7 +6,7 @@ import { i as generateDbDts, n as generateQueueTypes, t as generateRouteTypes }
|
|
|
6
6
|
import { t as discoverSchema } from "./discover-BcPPiF1o.mjs";
|
|
7
7
|
import { r as generateEnvTypes, t as findEnvFile } from "./env-types-D5kds_OZ.mjs";
|
|
8
8
|
import { a as loadLocalEnv } from "./env-_v349JBd.mjs";
|
|
9
|
-
import { t as analyzeApplication } from "./application-routing-
|
|
9
|
+
import { t as analyzeApplication } from "./application-routing-C9khgLiS.mjs";
|
|
10
10
|
import { n as generateVoidAuthDrizzleSchema, t as generateVoidAuthDatabaseModule } from "./drizzle-Beb2Am5S.mjs";
|
|
11
11
|
import { existsSync, mkdirSync, rmSync } from "node:fs";
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { l as writeProjectConfig, t as attachSelectedPlatform } from "./project-
|
|
1
|
+
import { l as writeProjectConfig, t as attachSelectedPlatform } from "./project-DQstYTxO.mjs";
|
|
2
2
|
export { attachSelectedPlatform, writeProjectConfig };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as join, n as dirname } from "./dist-BVqXeR_h.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { c as normalizePlatformApiUrl, s as listPlatformConnections } from "./platform-registry-P387v42A.mjs";
|
|
3
3
|
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { normalizeApplicationDomain } from "@void/platform";
|
|
5
5
|
//#region src/cli/project.ts
|