void 0.20.3 → 0.21.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 +2 -2
- package/dist/agents-gni4eqBu.mjs +111 -0
- package/dist/auth-3sGB0zJ1.mjs +22 -0
- package/dist/{auth-DPl6kck4.mjs → auth-B9_D6ygs.mjs} +6 -241
- package/dist/auth-CAw7zHqj.mjs +2 -0
- package/dist/auth-client-BWBT8HLp.mjs +6 -0
- package/dist/auth-client-Bawdj38n.d.mts +7 -0
- package/dist/auth-client-react-7GFffu8R.d.mts +7 -0
- package/dist/auth-client-react-CMLwT2xI.mjs +6 -0
- package/dist/auth-client-solid-DyTFL4cq.d.mts +7 -0
- package/dist/auth-client-solid-UoreJWZG.mjs +6 -0
- package/dist/auth-client-svelte-Cv_WvrRk.mjs +6 -0
- package/dist/auth-client-svelte-zetW0KIH.d.mts +7 -0
- package/dist/auth-client-vue-CFk7Xbv3.mjs +6 -0
- package/dist/auth-client-vue-bChShbQP.d.mts +7 -0
- package/dist/{auth-cmd-CzwquNiP.mjs → auth-cmd-MkBG2u1f.mjs} +5 -5
- package/dist/{auth-link-ElDTgF7j.mjs → auth-link-Devmv96E.mjs} +5 -5
- package/dist/{better-auth-shared-DSCeohOK.d.mts → better-auth-shared-BoVwA5Vm.d.mts} +1 -6
- package/dist/{better-auth-shared-CYw1T3k4.mjs → better-auth-shared-syGYYmnY.mjs} +1 -1
- package/dist/{build-cmd-BpJe6boP.mjs → build-cmd-DsBGwtfs.mjs} +6 -4
- package/dist/{cache-D98YTqeE.mjs → cache-BMw8eMyF.mjs} +6 -4
- package/dist/{cancel-deploy-CPbEQLMG.mjs → cancel-deploy-B3_s9NIN.mjs} +5 -3
- package/dist/cf-access-rAZxzMkL.mjs +181 -0
- package/dist/cf-build-output-CTdlo6Rt.mjs +520 -0
- package/dist/cli/cf-compat.d.mts +1 -0
- package/dist/cli/cf-compat.mjs +934 -0
- package/dist/cli/cli.mjs +60 -38
- package/dist/cli/env-schema-probe.mjs +3 -3
- package/dist/client-DAAivdid.mjs +2 -0
- package/dist/{client-BQBrZoCX.mjs → client-PdAJ-F0t.mjs} +6 -12
- package/dist/{cloudflare-auth-6M5llVPC.mjs → cloudflare-auth-BCmTc1X_.mjs} +13 -44
- package/dist/{cloudflare-cmd-4RPGN3KB.mjs → cloudflare-cmd-D6PrKn7o.mjs} +4 -7
- package/dist/{cloudflare-connect-t1UU5svD.mjs → cloudflare-connect-DloREDlc.mjs} +6 -6
- package/dist/cloudflare-operations-BHNJVDbN.mjs +2 -0
- package/dist/{cloudflare-operations-BzWnlC1_.mjs → cloudflare-operations-CPEdHYhM.mjs} +37 -39
- package/dist/cloudflare-user-output-Q-k0QoNQ.mjs +20 -0
- package/dist/collect-DAUItMDS.mjs +2 -0
- package/dist/collect-DXHNWHcT.mjs +48 -0
- package/dist/config--T87TD8T.mjs +2 -0
- package/dist/{config-NOG_U1aK.mjs → config-BSe70f4T.mjs} +4 -6
- package/dist/config-DDIFxQYx.mjs +2 -0
- package/dist/{config-uNGuFsI2.mjs → config-Dxr6cTXn.mjs} +22 -37
- package/dist/config-DywxBLQC.d.mts +185 -0
- package/dist/config-entry.d.mts +6 -0
- package/dist/config-entry.mjs +7 -0
- package/dist/config-uP7ZDtVZ.mjs +21 -0
- package/dist/config-write-y3CBI_ux.mjs +60 -0
- package/dist/{connect-WCQZ_u3m.mjs → connect-BvC9kolB.mjs} +8 -6
- package/dist/{create-project-D0oXA090.mjs → create-project-C9lQhRzj.mjs} +8 -23
- package/dist/create-project-CI-17RVJ.mjs +2 -0
- package/dist/database-provider-Cx525bwX.mjs +6 -0
- package/dist/database-provider.mjs +1 -5
- package/dist/{db-DJ-9qs3S.mjs → db-R7IQgOv5.mjs} +48 -44
- package/dist/{delete-BZ4-WaGm.mjs → delete-CghI_NXn.mjs} +6 -4
- package/dist/deploy-CYPymbtG.mjs +2 -0
- package/dist/{deploy-BAhhcg5q.mjs → deploy-H968Lo4T.mjs} +751 -190
- package/dist/discover-BBzDZe_o.mjs +2 -0
- package/dist/{discover-xvfrgJeo.mjs → discover-C4O6YxVS.mjs} +3 -8
- package/dist/{dist-BrsS7cai.mjs → dist-4WkAWhWx.mjs} +1 -15
- package/dist/{dist-m40_XgNh.mjs → dist-Bn8Kodjp.mjs} +1 -1
- package/dist/dist-C5fND3R0.mjs +2 -0
- package/dist/dist-D7-nEOXi.mjs +2 -0
- package/dist/{output-B0cfNSx5.mjs → dist-Dn6nn2IU.mjs} +3 -926
- package/dist/{domain-BxAyhxXN.mjs → domain-CITt8lC-.mjs} +7 -5
- package/dist/{route-types-Da-DpyUp.mjs → drizzle-Beb2Am5S.mjs} +1 -280
- package/dist/{email-Ce6SQq-i.mjs → email-C5kaZXzJ.mjs} +2 -2
- package/dist/{email-Bj7Cvdwp.mjs → email-_8VmyX7V.mjs} +14 -12
- package/dist/{entry-DU3oDoQ3.mjs → entry-DdRFGK0y.mjs} +2 -2
- package/dist/{env-DP_EErve.mjs → env-DV4r3nHz.mjs} +9 -7
- package/dist/{env-DBKmK4vc.mjs → env-DX_v-Q-v.mjs} +1 -1
- package/dist/env-Yz4HcvHs.mjs +78 -0
- package/dist/env-helpers--wFmQ_5Q.mjs +136 -0
- package/dist/{env-types-BNPhro-M.mjs → env-types-CWDtqHgw.mjs} +6 -2
- package/dist/{env-validation-CF6KvTRf.mjs → env-validation-BsFEXps5.mjs} +19 -28
- package/dist/env-validation-DIDGM7h4.mjs +2 -0
- package/dist/fetch-CXDChK7B.mjs +18 -0
- package/dist/fetch-_SeGZao9.d.mts +57 -0
- package/dist/fetch-stream-AOByI7Ki.mjs +81 -0
- package/dist/fetch-stream-Bjf0hoZb.d.mts +49 -0
- package/dist/gen-BBiIZw6g.mjs +2 -0
- package/dist/{gen-B_wPnVTK.mjs → gen-CFOEEc-t.mjs} +13 -11
- package/dist/{generate-RTK8_kK1.mjs → generate-C0VY6RVf.mjs} +2 -2
- package/dist/{github-cmd-C-z_xRrQ.mjs → github-cmd-jYjha2LO.mjs} +6 -4
- package/dist/{handler-D1hLsObx.d.mts → handler-BXJTXd02.d.mts} +6 -1
- package/dist/handler-DghKr6dU.mjs +150 -0
- package/dist/head-D_QRR5Yd.mjs +112 -0
- package/dist/head-client-DzmJGN4C.mjs +90 -0
- package/dist/{headers-BAHwgHdW.mjs → headers-B_HBMgi0.mjs} +2 -2
- package/dist/{help-CwOX-zmI.mjs → help-C46mnlUS.mjs} +17 -12
- package/dist/help-CS_nAsWu.mjs +2 -0
- package/dist/index.d.mts +2 -20
- package/dist/index.mjs +116 -60
- package/dist/{init-BGktCXgA.mjs → init-CSXmvxKu.mjs} +49 -50
- package/dist/{link-D2kbqhWb.mjs → link-DxMOALXk.mjs} +7 -5
- package/dist/{list-CvkK_G7k.mjs → list-0wQs0oYg.mjs} +7 -5
- package/dist/live-CB1y5IuC.mjs +411 -0
- package/dist/live-CKiJilLr.d.mts +105 -0
- package/dist/local-d1-DzykTWY8.mjs +104 -0
- package/dist/{login-WIjNc77c.mjs → login-CKk5NX4d.mjs} +6 -11
- package/dist/login-Ch9cgWRF.mjs +2 -0
- package/dist/{logs-dLUFCapG.mjs → logs-hxWBSoej.mjs} +6 -4
- package/dist/migrate-CLty4mZR.mjs +2 -0
- package/dist/migrate-DcW8F2W8.mjs +285 -0
- package/dist/migration-handler-DM4clYj5.d.mts +51 -0
- package/dist/{neon-DHwd2zvC.mjs → neon-n74ta1Pr.mjs} +1 -1
- package/dist/{node-Ez5KW5rn.mjs → node-Cupyf7-s.mjs} +6 -6
- package/dist/{operator-auth-B3e08unv.mjs → operator-auth-BkVgJqv-.mjs} +2 -2
- package/dist/{operator-client-LUZnlnYk.mjs → operator-client-A0iex2yi.mjs} +2 -1
- package/dist/{operator-cmd-CKJ7xIRs.mjs → operator-cmd-BEUYhaHB.mjs} +6 -6
- package/dist/output-urU86XeT.mjs +146 -0
- package/dist/{package-json-CPoWX79C.mjs → package-json-iCbMg5XF.mjs} +1 -1
- package/dist/pages/client.d.mts +5 -2
- package/dist/pages/client.mjs +5 -3
- package/dist/pages/head-client.mjs +1 -89
- package/dist/pages/head.mjs +1 -111
- package/dist/pages/index.d.mts +2 -3
- package/dist/pages/index.mjs +7 -7
- package/dist/pages/islands-plugin.mjs +2 -2
- package/dist/pages/prefetch.d.mts +2 -30
- package/dist/pages/prefetch.mjs +1 -89
- package/dist/pages/protocol.d.mts +2 -2
- package/dist/pages/protocol.mjs +3 -3
- package/dist/pages/serialize.d.mts +2 -9
- package/dist/pages/serialize.mjs +1 -13
- package/dist/plan-BEZ8VJW0.mjs +256 -0
- package/dist/plan-DpuOr14e.mjs +2 -0
- package/dist/{platform-auth-config-CdVWRRJr.mjs → platform-auth-config-Df6yVw-e.mjs} +6 -6
- package/dist/{platform-auth-protection-Drl0qhrn.mjs → platform-auth-protection-Jb0yftay.mjs} +7 -5
- package/dist/{platform-auth-recovery-CmKEWpDo.mjs → platform-auth-recovery-DmRyIfW0.mjs} +6 -5
- package/dist/platform-cmd-C9Vt7m-d.mjs +2 -0
- package/dist/{platform-cmd-5q_k56xS.mjs → platform-cmd-DRxCOTwy.mjs} +8 -5
- package/dist/{platform-domain-4GiDlcqx.mjs → platform-domain-IjiXgrXJ.mjs} +4 -3
- package/dist/{platform-lifecycle-R9xAxvtG.mjs → platform-lifecycle-BquAaU-5.mjs} +208 -37
- package/dist/platform-lifecycle-CuJIZNvA.mjs +2 -0
- package/dist/{platform-management-BfWsXHEW.mjs → platform-management-CCQKGsq4.mjs} +8 -5
- package/dist/platform-management-Cgyed0WY.mjs +2 -0
- package/dist/{platform-recovery-CbK-I1FB.mjs → platform-recovery-DS8ih1SW.mjs} +3 -3
- package/dist/platform-registry-BJbgZLS1.mjs +431 -0
- package/dist/{plugin-inference-BDRfZngg.mjs → plugin-inference-DsvtJLll.mjs} +4 -4
- package/dist/prefetch-Bsc_Pb6c.mjs +90 -0
- package/dist/prefetch-Ce6la4EI.d.mts +31 -0
- package/dist/{prepare-blNRQvQl.mjs → prepare-CaUxODOU.mjs} +3 -2
- package/dist/prepare-D4CkM3_v.mjs +2 -0
- package/dist/{prepare-CtDJjoOj.mjs → prepare-pcWcxSCh.mjs} +13 -11
- package/dist/prerender-render-Cf_WDE9W.mjs +111 -0
- package/dist/prerender-render.mjs +1 -110
- package/dist/{preset-lAy0B0BQ.mjs → preset-Dowh9tTt.mjs} +16 -118
- package/dist/project-BEBFDFLz.mjs +2 -0
- package/dist/project-CWNIPoXc.mjs +209 -0
- package/dist/{project-cmd-CTdmnzvc.mjs → project-cmd-2lN--YAX.mjs} +18 -16
- package/dist/{project-paths-SK8nMHPp.mjs → project-paths-CKQ-Q5JS.mjs} +47 -14
- package/dist/project-slug-23TpquG4.mjs +8 -0
- package/dist/project-slug-DofjTFd-.mjs +2 -0
- package/dist/{project-team-CGxsQe3_.mjs → project-team-Dapn9HZn.mjs} +6 -4
- package/dist/{project-token-Cirx7uwZ.mjs → project-token-C90v9SJK.mjs} +6 -4
- package/dist/{project-tsconfig-Ql2XsSQp.mjs → project-tsconfig-CwfqUnVp.mjs} +2 -2
- package/dist/{protocol-C-pqYJjE.d.mts → protocol-ZH3jP4a7.d.mts} +1 -1
- package/dist/providers-BNKRacMr.d.mts +7 -0
- package/dist/provision-CNgEBkVA.mjs +3 -0
- package/dist/{provision-CSJOjjQk.mjs → provision-Cck2m3jJ.mjs} +11 -25
- package/dist/queues-BWKt1Xo4.d.mts +7 -0
- package/dist/{requests-4Nq59hOr.mjs → requests-CzX46I0i.mjs} +5 -3
- package/dist/resolve-project-BTotl8Nn.mjs +2 -0
- package/dist/{resolve-project--Vxawf7z.mjs → resolve-project-Xvis70DG.mjs} +2 -8
- package/dist/response-Tn7rU0MV.mjs +30 -0
- package/dist/{rollback-Dr7u0Ljx.mjs → rollback-BEeyc73H.mjs} +6 -4
- package/dist/{rolldown-runtime-rQ84J-ij.mjs → rolldown-runtime-DXIUcv95.mjs} +1 -10
- package/dist/route-types-Id82-veQ.mjs +280 -0
- package/dist/{local-d1-D2I6Ox5F.mjs → runner-BGVsGgkb.mjs} +6 -114
- package/dist/runner-CQs_cDSG.mjs +2 -0
- package/dist/runner-mysql-1o47achK.mjs +2 -0
- package/dist/{runner-mysql-7BPUNGmL.mjs → runner-mysql-BhwMk2Bm.mjs} +2 -9
- package/dist/{runner-pg-BkEza-dX.mjs → runner-pg-CJ_JeGF6.mjs} +2 -9
- package/dist/runner-pg-D7z01mQS.mjs +2 -0
- package/dist/runtime/ai.mjs +1 -1
- package/dist/runtime/auth-client-react.d.mts +2 -6
- package/dist/runtime/auth-client-react.mjs +1 -5
- package/dist/runtime/auth-client-solid.d.mts +2 -6
- package/dist/runtime/auth-client-solid.mjs +1 -5
- package/dist/runtime/auth-client-svelte.d.mts +2 -6
- package/dist/runtime/auth-client-svelte.mjs +1 -5
- package/dist/runtime/auth-client-vue.d.mts +2 -6
- package/dist/runtime/auth-client-vue.mjs +1 -5
- package/dist/runtime/auth-client.d.mts +2 -6
- package/dist/runtime/auth-client.mjs +1 -5
- package/dist/runtime/auth.mjs +1 -21
- package/dist/runtime/better-auth-mysql.d.mts +1 -1
- package/dist/runtime/better-auth-mysql.mjs +1 -1
- package/dist/runtime/better-auth-pg.d.mts +1 -1
- package/dist/runtime/better-auth-pg.mjs +1 -1
- package/dist/runtime/better-auth.d.mts +1 -1
- package/dist/runtime/better-auth.mjs +1 -1
- package/dist/runtime/client-react.d.mts +3 -3
- package/dist/runtime/client-react.mjs +3 -3
- package/dist/runtime/client-solid.d.mts +3 -3
- package/dist/runtime/client-solid.mjs +3 -3
- package/dist/runtime/client-svelte.d.mts +3 -3
- package/dist/runtime/client-svelte.mjs +3 -3
- package/dist/runtime/client-vue.d.mts +3 -3
- package/dist/runtime/client-vue.mjs +3 -3
- package/dist/runtime/client.d.mts +3 -3
- package/dist/runtime/client.mjs +3 -3
- package/dist/runtime/db.mjs +1 -1
- package/dist/runtime/durable.mjs +1 -1
- package/dist/runtime/email/testing.mjs +1 -1
- package/dist/runtime/env-helpers.mjs +1 -135
- package/dist/runtime/env-public-client.mjs +1 -1
- package/dist/runtime/env-public.mjs +2 -2
- package/dist/runtime/env.mjs +1 -77
- package/dist/runtime/fetch-stream.d.mts +2 -49
- package/dist/runtime/fetch-stream.mjs +2 -80
- package/dist/runtime/fetch.d.mts +2 -57
- package/dist/runtime/fetch.mjs +2 -17
- package/dist/runtime/handler.d.mts +1 -1
- package/dist/runtime/handler.mjs +1 -149
- package/dist/runtime/kv.mjs +1 -1
- package/dist/runtime/live-client.d.mts +1 -1
- package/dist/runtime/live-server.mjs +2 -2
- package/dist/runtime/live.d.mts +2 -104
- package/dist/runtime/live.mjs +1 -410
- package/dist/runtime/migration-handler-mysql.d.mts +1 -1
- package/dist/runtime/migration-handler-pg.d.mts +1 -1
- package/dist/runtime/migration-handler.d.mts +2 -50
- package/dist/runtime/queues.d.mts +2 -6
- package/dist/runtime/queues.mjs +1 -1
- package/dist/runtime/response.mjs +1 -29
- package/dist/runtime/sandbox.mjs +1 -1
- package/dist/runtime/sse.mjs +1 -171
- package/dist/runtime/storage.mjs +1 -1
- package/dist/runtime/validator.d.mts +1 -1
- package/dist/runtime/validator.mjs +1 -71
- package/dist/runtime/ws-server.d.mts +2 -2
- package/dist/runtime/ws-server.mjs +2 -2
- package/dist/runtime/ws.d.mts +2 -121
- package/dist/{scan-CpK-57ug.mjs → scan-DJbooZm2.mjs} +3 -3
- package/dist/{scan-BMH4rzlv.mjs → scan-DdDvRCU1.mjs} +8 -26
- package/dist/{secret-AcPi-FoA.mjs → secret-wnTel5Yw.mjs} +8 -6
- package/dist/serialize-BPvnNQuA.mjs +14 -0
- package/dist/serialize-CfSwWfF2.d.mts +10 -0
- package/dist/{skills-C0RvGjeE.mjs → skills-B-690E7h.mjs} +3 -2
- package/dist/sse-BaC1jXko.mjs +172 -0
- package/dist/{subcommand-prompt-Bmyn5Rlc.mjs → subcommand-prompt-Gj3VzLIh.mjs} +2 -1
- package/dist/sveltekit.d.mts +2 -1
- package/dist/sveltekit.mjs +3 -2
- package/dist/validate-DqJ33oHj.mjs +2 -0
- package/dist/validate-qNhV00PD.mjs +180 -0
- package/dist/validator-BTOu0fB0.mjs +72 -0
- package/dist/{wrangler--imS8n0d.mjs → wrangler-D01qs6VB.mjs} +259 -71
- package/dist/ws-BwcqizuH.d.mts +122 -0
- package/dist/{yarn-pnp-DxSInkzL.mjs → yarn-pnp-CVEc3gE7.mjs} +1 -1
- package/package.json +19 -8
- package/skills/void/SKILL.md +6 -4
- package/skills/void/docs/guide/ai.md +3 -3
- package/skills/void/docs/guide/app-types.md +12 -11
- package/skills/void/docs/guide/auth.md +2 -2
- package/skills/void/docs/guide/database/d1.md +1 -1
- package/skills/void/docs/guide/database/mysql.md +1 -1
- package/skills/void/docs/guide/database/postgresql.md +3 -3
- package/skills/void/docs/guide/deployment.md +2 -2
- package/skills/void/docs/guide/durable-state.md +2 -2
- package/skills/void/docs/guide/edge/headers.md +3 -3
- package/skills/void/docs/guide/edge/prerendering.md +1 -1
- package/skills/void/docs/guide/edge/redirects.md +4 -4
- package/skills/void/docs/guide/edge/revalidation.md +6 -6
- package/skills/void/docs/guide/edge/rewrites.md +28 -27
- package/skills/void/docs/guide/edge/static-assets.md +1 -1
- package/skills/void/docs/guide/email.md +15 -15
- package/skills/void/docs/guide/env-migration.md +1 -1
- package/skills/void/docs/guide/index.md +1 -1
- package/skills/void/docs/guide/pages-routing/head.md +1 -1
- package/skills/void/docs/guide/platform/administration/access.md +13 -5
- package/skills/void/docs/guide/platform/administration/projects.md +3 -1
- package/skills/void/docs/guide/platform/installation/ci.md +3 -0
- package/skills/void/docs/guide/platform/installation/credentials.md +15 -5
- package/skills/void/docs/guide/platform/installation/prerequisites.md +2 -0
- package/skills/void/docs/guide/platform/installation/setup.md +1 -1
- package/skills/void/docs/guide/remote-dev.md +2 -2
- package/skills/void/docs/guide/sandboxes.md +1 -1
- package/skills/void/docs/guide/ssg.md +1 -1
- package/skills/void/docs/guide/websockets.md +1 -1
- package/skills/void/docs/integrations/cloudflare.md +86 -84
- package/skills/void/docs/integrations/frameworks/analog.md +14 -9
- package/skills/void/docs/integrations/frameworks/astro.md +14 -10
- package/skills/void/docs/integrations/frameworks/nuxt.md +14 -9
- package/skills/void/docs/integrations/frameworks/overview.md +35 -29
- package/skills/void/docs/integrations/frameworks/react-router.md +1 -1
- package/skills/void/docs/integrations/frameworks/sveltekit.md +33 -30
- package/skills/void/docs/integrations/frameworks/tanstack-start.md +1 -1
- package/skills/void/docs/integrations/nodejs-bun-deno.md +5 -5
- package/skills/void/docs/reference/api.md +21 -4
- package/skills/void/docs/reference/cli.md +32 -23
- package/skills/void/docs/reference/config.md +56 -33
- package/skills/void/docs/reference/structure.md +2 -2
- package/dist/validate-tBBN_dXH.mjs +0 -505
|
@@ -0,0 +1,934 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as join, n as dirname, u as resolve } from "../dist-4WkAWhWx.mjs";
|
|
3
|
+
import { t as prepareCfBuildOutput } from "../cf-build-output-CTdlo6Rt.mjs";
|
|
4
|
+
import { copyFileSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
import { parse } from "jsonc-parser";
|
|
9
|
+
import { readBuildOutput } from "@cloudflare/build-output-utils";
|
|
10
|
+
import { EnvHttpProxyAgent, fetch as fetch$1 } from "undici";
|
|
11
|
+
//#region src/cli/cf-compat.ts
|
|
12
|
+
/**
|
|
13
|
+
* Private transport for the existing Void Cloudflare command seams. The
|
|
14
|
+
* orchestrators still use their established argument/result contracts; this
|
|
15
|
+
* process translates them to the pinned cf CLI. It never invokes Wrangler.
|
|
16
|
+
*/
|
|
17
|
+
const cf = join(dirname(fileURLToPath(import.meta.resolve("cf/package.json"))), "bin", "cf");
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
function cfEnvironment() {
|
|
20
|
+
const env = {
|
|
21
|
+
...process.env,
|
|
22
|
+
CF_DELEGATION: "1"
|
|
23
|
+
};
|
|
24
|
+
if (env.HTTP_PROXY || env.HTTPS_PROXY || env.http_proxy || env.https_proxy) env.NODE_USE_ENV_PROXY = "1";
|
|
25
|
+
for (const [canonical, alias] of [
|
|
26
|
+
["CLOUDFLARE_API_TOKEN", "CF_API_TOKEN"],
|
|
27
|
+
["CLOUDFLARE_API_KEY", "CF_API_KEY"],
|
|
28
|
+
["CLOUDFLARE_EMAIL", "CF_EMAIL"],
|
|
29
|
+
["CLOUDFLARE_ACCOUNT_ID", "CF_ACCOUNT_ID"]
|
|
30
|
+
]) if (!env[canonical] && env[alias]) env[canonical] = env[alias];
|
|
31
|
+
return env;
|
|
32
|
+
}
|
|
33
|
+
function result(status, stdout = "", stderr = "") {
|
|
34
|
+
return {
|
|
35
|
+
status,
|
|
36
|
+
stdout,
|
|
37
|
+
stderr
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function runCf(command, cwd = process.cwd(), useLoginProfile = false) {
|
|
41
|
+
const env = cfEnvironment();
|
|
42
|
+
if (useLoginProfile) delete env.CLOUDFLARE_AUTH_USE_KEYRING;
|
|
43
|
+
const child = spawnSync(process.execPath, [cf, ...command], {
|
|
44
|
+
cwd,
|
|
45
|
+
env,
|
|
46
|
+
encoding: "utf8",
|
|
47
|
+
shell: false,
|
|
48
|
+
windowsHide: true,
|
|
49
|
+
maxBuffer: 33554432,
|
|
50
|
+
stdio: [
|
|
51
|
+
"ignore",
|
|
52
|
+
"pipe",
|
|
53
|
+
"pipe"
|
|
54
|
+
]
|
|
55
|
+
});
|
|
56
|
+
const stderr = (child.stderr || child.error?.message || "").replace(/\[(\d{4,})\]/g, "[code: $1]");
|
|
57
|
+
return result(child.status ?? 1, child.stdout ?? "", stderr);
|
|
58
|
+
}
|
|
59
|
+
function runInteractiveCf(command) {
|
|
60
|
+
const child = spawnSync(process.execPath, [cf, ...command], {
|
|
61
|
+
cwd: process.cwd(),
|
|
62
|
+
env: cfEnvironment(),
|
|
63
|
+
shell: false,
|
|
64
|
+
stdio: "inherit",
|
|
65
|
+
windowsHide: true
|
|
66
|
+
});
|
|
67
|
+
return result(child.status ?? 1, "", child.error?.message ?? "");
|
|
68
|
+
}
|
|
69
|
+
async function withBuildOutput(raw, sourceMain, action) {
|
|
70
|
+
const scratch = mkdtempSync(join(tmpdir(), "void-cf-command-"));
|
|
71
|
+
try {
|
|
72
|
+
const main = "index.js";
|
|
73
|
+
if (sourceMain) copyFileSync(sourceMain, join(scratch, main));
|
|
74
|
+
else writeFileSync(join(scratch, main), "export default { fetch() { return new Response(\"\"); } };\n");
|
|
75
|
+
writeFileSync(join(scratch, "wrangler.json"), JSON.stringify({
|
|
76
|
+
...raw,
|
|
77
|
+
main,
|
|
78
|
+
compatibility_date: raw.compatibility_date ?? "2025-01-01"
|
|
79
|
+
}), { mode: 384 });
|
|
80
|
+
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID ?? raw.account_id;
|
|
81
|
+
if (typeof accountId !== "string" || !accountId) throw new Error("Cloudflare account is not pinned for Worker deployment.");
|
|
82
|
+
const output = await prepareCfBuildOutput(scratch, accountId);
|
|
83
|
+
if (!output) throw new Error("Could not prepare the Cloudflare Worker build output.");
|
|
84
|
+
try {
|
|
85
|
+
await assertExistingProvisionableResources(output.directory, accountId);
|
|
86
|
+
return action(output.directory);
|
|
87
|
+
} finally {
|
|
88
|
+
output.dispose();
|
|
89
|
+
}
|
|
90
|
+
} finally {
|
|
91
|
+
rmSync(scratch, {
|
|
92
|
+
recursive: true,
|
|
93
|
+
force: true
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function parsedJson(value) {
|
|
98
|
+
return JSON.parse(value);
|
|
99
|
+
}
|
|
100
|
+
function object(value) {
|
|
101
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Cloudflare returned an unexpected response.");
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
function field(name) {
|
|
105
|
+
const index = args.indexOf(name);
|
|
106
|
+
return index >= 0 ? args[index + 1] : void 0;
|
|
107
|
+
}
|
|
108
|
+
function configPath() {
|
|
109
|
+
return field("-c") ?? field("--config");
|
|
110
|
+
}
|
|
111
|
+
function config() {
|
|
112
|
+
const path = configPath();
|
|
113
|
+
if (!path) throw new Error("Cloudflare config path is required for this operation.");
|
|
114
|
+
return object(parse(readFileSync(path, "utf8")));
|
|
115
|
+
}
|
|
116
|
+
function workerName() {
|
|
117
|
+
const name = field("--name") ?? config().name;
|
|
118
|
+
if (typeof name !== "string" || !name) throw new Error("Cloudflare Worker name is missing from the generated config.");
|
|
119
|
+
return name;
|
|
120
|
+
}
|
|
121
|
+
function updateBinding(section, binding, values) {
|
|
122
|
+
const path = configPath();
|
|
123
|
+
if (!path || !binding) throw new Error("Cloudflare resource binding and config are required.");
|
|
124
|
+
const current = config();
|
|
125
|
+
const previous = Array.isArray(current[section]) ? current[section] : [];
|
|
126
|
+
const existing = previous.map(object).find((entry) => entry.binding === binding);
|
|
127
|
+
current[section] = [...previous.filter((entry) => object(entry).binding !== binding), {
|
|
128
|
+
...existing,
|
|
129
|
+
binding,
|
|
130
|
+
...values
|
|
131
|
+
}];
|
|
132
|
+
writeFileSync(path, `${JSON.stringify(current, null, 2)}\n`);
|
|
133
|
+
}
|
|
134
|
+
function d1Database(token) {
|
|
135
|
+
const entries = config().d1_databases;
|
|
136
|
+
if (!Array.isArray(entries)) throw new Error("D1 database binding is unavailable.");
|
|
137
|
+
const selected = entries.map(object).find((entry) => entry.database_id === token || entry.database_name === token || entry.binding === token);
|
|
138
|
+
if (!selected || typeof selected.database_id !== "string") throw new Error("D1 database binding is unavailable.");
|
|
139
|
+
return {
|
|
140
|
+
id: selected.database_id,
|
|
141
|
+
dir: typeof selected.migrations_dir === "string" ? selected.migrations_dir : "./migrations",
|
|
142
|
+
...typeof selected.migrations_pattern === "string" ? { pattern: selected.migrations_pattern } : {},
|
|
143
|
+
table: typeof selected.migrations_table === "string" ? selected.migrations_table : "d1_migrations"
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function cleanJson(command, transform) {
|
|
147
|
+
const called = runCf(command);
|
|
148
|
+
if (called.status !== 0 || !transform) return called;
|
|
149
|
+
return result(0, `${JSON.stringify(transform(parsedJson(called.stdout)))}\n`, called.stderr);
|
|
150
|
+
}
|
|
151
|
+
function accountId() {
|
|
152
|
+
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID ?? config().account_id;
|
|
153
|
+
if (typeof accountId !== "string" || !accountId) throw new Error("Cloudflare account is not pinned for API inspection.");
|
|
154
|
+
return accountId;
|
|
155
|
+
}
|
|
156
|
+
async function cloudflareApiGet(path, failure, extraHeaders = {}) {
|
|
157
|
+
const url = `${(process.env.CLOUDFLARE_API_BASE_URL ?? "https://api.cloudflare.com/client/v4").replace(/\/$/, "")}${path}`;
|
|
158
|
+
const proxy = process.env.HTTP_PROXY || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.https_proxy ? new EnvHttpProxyAgent() : null;
|
|
159
|
+
try {
|
|
160
|
+
const response = await fetch$1(url, {
|
|
161
|
+
headers: {
|
|
162
|
+
...apiHeaders(),
|
|
163
|
+
...extraHeaders
|
|
164
|
+
},
|
|
165
|
+
redirect: "error",
|
|
166
|
+
signal: AbortSignal.timeout(3e4),
|
|
167
|
+
...proxy ? { dispatcher: proxy } : {}
|
|
168
|
+
});
|
|
169
|
+
const body = object(await response.json());
|
|
170
|
+
if (!response.ok || body.success !== true) throw new Error(failure);
|
|
171
|
+
return body;
|
|
172
|
+
} finally {
|
|
173
|
+
await proxy?.close();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async function clearWorkerCronSchedules(worker) {
|
|
177
|
+
const endpoint = `${(process.env.CLOUDFLARE_API_BASE_URL ?? "https://api.cloudflare.com/client/v4").replace(/\/$/, "")}/accounts/${encodeURIComponent(accountId())}/workers/scripts/${encodeURIComponent(worker)}/schedules`;
|
|
178
|
+
const proxy = process.env.HTTP_PROXY || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.https_proxy ? new EnvHttpProxyAgent() : null;
|
|
179
|
+
try {
|
|
180
|
+
const response = await fetch$1(endpoint, {
|
|
181
|
+
method: "PUT",
|
|
182
|
+
headers: {
|
|
183
|
+
...apiHeaders(),
|
|
184
|
+
"Content-Type": "application/json"
|
|
185
|
+
},
|
|
186
|
+
body: "[]",
|
|
187
|
+
redirect: "error",
|
|
188
|
+
signal: AbortSignal.timeout(3e4),
|
|
189
|
+
...proxy ? { dispatcher: proxy } : {}
|
|
190
|
+
});
|
|
191
|
+
const body = object(await response.json());
|
|
192
|
+
const schedules = object(body.result).schedules;
|
|
193
|
+
if (!response.ok || body.success !== true || !Array.isArray(schedules) || schedules.length !== 0) throw new Error(`Cloudflare did not clear the Worker Cron Triggers (HTTP ${response.status}).`);
|
|
194
|
+
return result(0);
|
|
195
|
+
} finally {
|
|
196
|
+
await proxy?.close();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
async function assertExistingProvisionableResources(directory, account) {
|
|
200
|
+
const bindings = (await readBuildOutput(directory)).workers.default.config.env ?? {};
|
|
201
|
+
const queueNames = /* @__PURE__ */ new Set();
|
|
202
|
+
const accountPath = `/accounts/${encodeURIComponent(account)}`;
|
|
203
|
+
for (const [bindingName, value] of Object.entries(bindings)) {
|
|
204
|
+
const binding = object(value);
|
|
205
|
+
const identifier = (key) => {
|
|
206
|
+
const id = binding[key];
|
|
207
|
+
if (typeof id !== "string" || !id) throw new Error(`Cloudflare binding ${bindingName} has no ${key}; refusing automatic provisioning.`);
|
|
208
|
+
return id;
|
|
209
|
+
};
|
|
210
|
+
if (binding.type === "kv" || binding.type === "d1") identifier("id");
|
|
211
|
+
else if (binding.type === "r2") {
|
|
212
|
+
const name = identifier("name");
|
|
213
|
+
const jurisdiction = binding.jurisdiction;
|
|
214
|
+
if (jurisdiction !== void 0 && typeof jurisdiction !== "string") throw new Error(`Cloudflare R2 binding ${bindingName} has an invalid jurisdiction.`);
|
|
215
|
+
await cloudflareApiGet(`${accountPath}/r2/buckets/${encodeURIComponent(name)}`, `Cloudflare R2 bucket ${name} is unavailable; refusing automatic provisioning.`, jurisdiction ? { "cf-r2-jurisdiction": jurisdiction } : {});
|
|
216
|
+
} else if (binding.type === "queue") queueNames.add(identifier("name"));
|
|
217
|
+
else if (binding.type === "dispatch-namespace") {
|
|
218
|
+
const name = identifier("namespace");
|
|
219
|
+
await cloudflareApiGet(`${accountPath}/workers/dispatch/namespaces/${encodeURIComponent(name)}`, `Cloudflare dispatch namespace ${name} is unavailable; refusing automatic provisioning.`);
|
|
220
|
+
} else if (binding.type === "ai-search-namespace") {
|
|
221
|
+
const name = identifier("namespace");
|
|
222
|
+
await cloudflareApiGet(`${accountPath}/ai-search/namespaces/${encodeURIComponent(name)}`, `Cloudflare AI Search namespace ${name} is unavailable; refusing automatic provisioning.`);
|
|
223
|
+
} else if (binding.type === "agent-memory") {
|
|
224
|
+
const name = identifier("namespace");
|
|
225
|
+
await cloudflareApiGet(`${accountPath}/agent-memory/namespaces/${encodeURIComponent(name)}`, `Cloudflare Agent Memory namespace ${name} is unavailable; refusing automatic provisioning.`);
|
|
226
|
+
} else if (binding.type === "flagship") identifier("id");
|
|
227
|
+
}
|
|
228
|
+
if (queueNames.size > 0) {
|
|
229
|
+
const existing = new Set((await readAllQueues()).map((queue) => queue.queue_name));
|
|
230
|
+
for (const name of queueNames) if (!existing.has(name)) throw new Error(`Cloudflare Queue ${name} is unavailable; refusing automatic provisioning.`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async function readVersionResources(worker, versionId) {
|
|
234
|
+
const resources = object(object((await cloudflareApiGet(`/accounts/${encodeURIComponent(accountId())}/workers/scripts/${encodeURIComponent(worker)}/versions/${encodeURIComponent(versionId)}`, "Cloudflare did not return Worker version resources.")).result).resources);
|
|
235
|
+
if (!Array.isArray(resources.bindings) || !resources.script || !resources.script_runtime) throw new Error("Cloudflare Worker version resources were incomplete.");
|
|
236
|
+
return resources;
|
|
237
|
+
}
|
|
238
|
+
function apiHeaders() {
|
|
239
|
+
const key = process.env.CLOUDFLARE_API_KEY ?? process.env.CF_API_KEY;
|
|
240
|
+
const email = process.env.CLOUDFLARE_EMAIL ?? process.env.CF_EMAIL;
|
|
241
|
+
if (key && email) return {
|
|
242
|
+
"X-Auth-Key": key,
|
|
243
|
+
"X-Auth-Email": email
|
|
244
|
+
};
|
|
245
|
+
const credential = sessionCredential();
|
|
246
|
+
if (!credential) throw new Error("Cloudflare session bearer is unavailable.");
|
|
247
|
+
return { Authorization: `Bearer ${credential.token}` };
|
|
248
|
+
}
|
|
249
|
+
async function withSecretFile(content, action) {
|
|
250
|
+
const directory = mkdtempSync(join(tmpdir(), "void-cf-secret-"));
|
|
251
|
+
try {
|
|
252
|
+
const path = join(directory, "body.json");
|
|
253
|
+
writeFileSync(path, content, { mode: 384 });
|
|
254
|
+
return await action(path);
|
|
255
|
+
} finally {
|
|
256
|
+
rmSync(directory, {
|
|
257
|
+
recursive: true,
|
|
258
|
+
force: true
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function sessionCredential() {
|
|
263
|
+
const token = process.env.CLOUDFLARE_API_TOKEN || process.env.CF_API_TOKEN;
|
|
264
|
+
if (token) return {
|
|
265
|
+
type: "api_token",
|
|
266
|
+
token
|
|
267
|
+
};
|
|
268
|
+
const identity = runCf(["auth", "whoami"], process.cwd(), true);
|
|
269
|
+
if (identity.status !== 0) return null;
|
|
270
|
+
const state = object(parsedJson(identity.stdout));
|
|
271
|
+
if (state.authenticated !== true || state.tokenValid !== true) return null;
|
|
272
|
+
const source = state.authSource;
|
|
273
|
+
if (typeof source !== "string" || !source.startsWith("OAuth token from ")) return null;
|
|
274
|
+
const credential = object(parsedJson(readFileSync(source.slice(17), "utf8")));
|
|
275
|
+
return typeof credential.oauth_token === "string" && credential.oauth_token ? {
|
|
276
|
+
type: "oauth",
|
|
277
|
+
token: credential.oauth_token
|
|
278
|
+
} : null;
|
|
279
|
+
}
|
|
280
|
+
function auth() {
|
|
281
|
+
if (args[0] === "login") return runInteractiveCf([
|
|
282
|
+
"auth",
|
|
283
|
+
"login",
|
|
284
|
+
"--force"
|
|
285
|
+
]);
|
|
286
|
+
if (args[0] === "logout") return runCf(["auth", "logout"]);
|
|
287
|
+
if (args[0] === "whoami") {
|
|
288
|
+
const called = runCf(["auth", "whoami"]);
|
|
289
|
+
if (called.status !== 0) return called;
|
|
290
|
+
const identity = object(parsedJson(called.stdout));
|
|
291
|
+
if (identity.authenticated !== true || identity.tokenValid !== true) return result(1, JSON.stringify({ loggedIn: false }), "Cloudflare authentication is required.");
|
|
292
|
+
return result(0, JSON.stringify({
|
|
293
|
+
loggedIn: true,
|
|
294
|
+
accounts: identity.accounts,
|
|
295
|
+
email: identity.email,
|
|
296
|
+
tokenPermissions: identity.scopes,
|
|
297
|
+
authType: process.env.CLOUDFLARE_API_KEY || process.env.CF_API_KEY ? "Global API Key" : String(identity.authSource).startsWith("OAuth token") ? "OAuth Token" : "API Token"
|
|
298
|
+
}), called.stderr);
|
|
299
|
+
}
|
|
300
|
+
if (args[0] === "auth" && args[1] === "token") {
|
|
301
|
+
const credential = sessionCredential();
|
|
302
|
+
return credential ? result(0, `${JSON.stringify(credential)}\n`) : result(1, "", "Cloudflare session has no OAuth bearer.");
|
|
303
|
+
}
|
|
304
|
+
return result(1, "", "Unsupported Cloudflare authentication operation.");
|
|
305
|
+
}
|
|
306
|
+
function listAllResourcePages(command, extraFlags = []) {
|
|
307
|
+
const pageSize = 100;
|
|
308
|
+
const entries = [];
|
|
309
|
+
for (let page = 1; page <= 100; page++) {
|
|
310
|
+
const listed = runCf([
|
|
311
|
+
...command,
|
|
312
|
+
"--page",
|
|
313
|
+
String(page),
|
|
314
|
+
"--per-page",
|
|
315
|
+
String(pageSize),
|
|
316
|
+
...extraFlags
|
|
317
|
+
]);
|
|
318
|
+
if (listed.status !== 0) return listed;
|
|
319
|
+
const items = parsedJson(listed.stdout);
|
|
320
|
+
if (!Array.isArray(items) || items.length > pageSize) throw new Error(`Cloudflare returned an invalid ${command.join(" ")} page.`);
|
|
321
|
+
entries.push(...items);
|
|
322
|
+
if (items.length < pageSize) return result(0, `${JSON.stringify(entries)}\n`);
|
|
323
|
+
}
|
|
324
|
+
throw new Error(`Cloudflare ${command.join(" ")} exceeded the supported page limit.`);
|
|
325
|
+
}
|
|
326
|
+
async function readAllQueues() {
|
|
327
|
+
const queues = [];
|
|
328
|
+
const seen = /* @__PURE__ */ new Set();
|
|
329
|
+
for (let page = 1; page <= 1e3; page++) {
|
|
330
|
+
const body = await cloudflareApiGet(`/accounts/${encodeURIComponent(accountId())}/queues?page=${page}`, "Cloudflare did not return the Queue list.");
|
|
331
|
+
const entries = body.result;
|
|
332
|
+
const info = object(body.result_info);
|
|
333
|
+
if (!Array.isArray(entries) || !Number.isSafeInteger(info.page) || info.page !== page || !Number.isSafeInteger(info.total_pages) || info.total_pages < 0 || info.total_pages > 1e3) throw new Error("Cloudflare returned incomplete Queue pagination.");
|
|
334
|
+
for (const entry of entries) {
|
|
335
|
+
const queue = object(entry);
|
|
336
|
+
if (typeof queue.queue_id !== "string" || typeof queue.queue_name !== "string" || seen.has(queue.queue_id)) throw new Error("Cloudflare returned an invalid Queue list.");
|
|
337
|
+
seen.add(queue.queue_id);
|
|
338
|
+
queues.push(queue);
|
|
339
|
+
}
|
|
340
|
+
if (page >= info.total_pages) return queues;
|
|
341
|
+
}
|
|
342
|
+
throw new Error("Cloudflare Queue list exceeded the supported page limit.");
|
|
343
|
+
}
|
|
344
|
+
async function resources() {
|
|
345
|
+
const [group, verb, third] = args;
|
|
346
|
+
if (group === "d1" && verb === "execute" && third) {
|
|
347
|
+
const database = d1Database(third);
|
|
348
|
+
const sql = field("--command");
|
|
349
|
+
if (!sql) throw new Error("D1 SQL command is missing.");
|
|
350
|
+
return runCf([
|
|
351
|
+
"d1",
|
|
352
|
+
"query",
|
|
353
|
+
database.id,
|
|
354
|
+
"--sql",
|
|
355
|
+
sql
|
|
356
|
+
]);
|
|
357
|
+
}
|
|
358
|
+
if (group === "d1" && verb === "migrations" && (third === "list" || third === "apply")) {
|
|
359
|
+
const token = args[3];
|
|
360
|
+
if (!token) throw new Error("D1 migration target is missing.");
|
|
361
|
+
const database = d1Database(token);
|
|
362
|
+
const called = runCf([
|
|
363
|
+
"d1",
|
|
364
|
+
"migrations",
|
|
365
|
+
third,
|
|
366
|
+
database.id,
|
|
367
|
+
"--dir",
|
|
368
|
+
database.dir,
|
|
369
|
+
...database.pattern ? ["--pattern", database.pattern] : [],
|
|
370
|
+
"--table",
|
|
371
|
+
database.table
|
|
372
|
+
]);
|
|
373
|
+
if (called.status !== 0 || third !== "list") return called;
|
|
374
|
+
const pending = parsedJson(called.stdout);
|
|
375
|
+
if (!Array.isArray(pending)) throw new Error("D1 migration list was malformed.");
|
|
376
|
+
return result(0, pending.length ? `Migrations to be applied:\n${pending.map((item) => object(item).Name).join("\n")}\n` : "No migrations to apply!\n");
|
|
377
|
+
}
|
|
378
|
+
if (group === "containers" && verb === "list") return runCf([
|
|
379
|
+
"containers",
|
|
380
|
+
"applications",
|
|
381
|
+
"list"
|
|
382
|
+
]);
|
|
383
|
+
if (group === "d1" && verb === "list") return listAllResourcePages(["d1", "list"]);
|
|
384
|
+
if (group === "d1" && verb === "info" && third) {
|
|
385
|
+
const listed = listAllResourcePages(["d1", "list"]);
|
|
386
|
+
if (listed.status !== 0) return listed;
|
|
387
|
+
const value = parsedJson(listed.stdout);
|
|
388
|
+
if (!Array.isArray(value)) throw new Error("D1 list was malformed.");
|
|
389
|
+
const selected = value.find((item) => object(item).name === third) ?? null;
|
|
390
|
+
return selected === null ? result(1, "", `D1 database ${JSON.stringify(third)} does not exist.`) : result(0, `${JSON.stringify(selected)}\n`);
|
|
391
|
+
}
|
|
392
|
+
if (group === "d1" && verb === "create" && third) {
|
|
393
|
+
const created = runCf([
|
|
394
|
+
"d1",
|
|
395
|
+
"create",
|
|
396
|
+
"--name",
|
|
397
|
+
third
|
|
398
|
+
]);
|
|
399
|
+
if (created.status !== 0) return created;
|
|
400
|
+
const database = object(parsedJson(created.stdout));
|
|
401
|
+
if (typeof database.uuid !== "string") throw new Error("D1 creation returned no database ID.");
|
|
402
|
+
updateBinding("d1_databases", field("--binding") ?? "", {
|
|
403
|
+
database_name: third,
|
|
404
|
+
database_id: database.uuid
|
|
405
|
+
});
|
|
406
|
+
return created;
|
|
407
|
+
}
|
|
408
|
+
if (group === "kv" && verb === "namespace" && third === "list") return listAllResourcePages([
|
|
409
|
+
"kv",
|
|
410
|
+
"namespaces",
|
|
411
|
+
"list"
|
|
412
|
+
], [
|
|
413
|
+
"--order",
|
|
414
|
+
"id",
|
|
415
|
+
"--direction",
|
|
416
|
+
"asc"
|
|
417
|
+
]);
|
|
418
|
+
if (group === "kv" && verb === "namespace" && third === "create" && args[3]) {
|
|
419
|
+
const created = runCf([
|
|
420
|
+
"kv",
|
|
421
|
+
"namespaces",
|
|
422
|
+
"create",
|
|
423
|
+
"--title",
|
|
424
|
+
args[3]
|
|
425
|
+
]);
|
|
426
|
+
if (created.status !== 0) return created;
|
|
427
|
+
const namespace = object(parsedJson(created.stdout));
|
|
428
|
+
if (typeof namespace.id !== "string") throw new Error("KV creation returned no namespace ID.");
|
|
429
|
+
updateBinding("kv_namespaces", field("--binding") ?? "", { id: namespace.id });
|
|
430
|
+
return created;
|
|
431
|
+
}
|
|
432
|
+
if (group === "r2" && verb === "bucket" && third === "info" && args[3]) {
|
|
433
|
+
const read = runCf([
|
|
434
|
+
"r2",
|
|
435
|
+
"buckets",
|
|
436
|
+
"get",
|
|
437
|
+
args[3]
|
|
438
|
+
]);
|
|
439
|
+
return read.status !== 0 && /\[code:\s*10006\]/.test(read.stderr) ? result(1, "", "[code: 10006] The specified bucket does not exist.") : read;
|
|
440
|
+
}
|
|
441
|
+
if (group === "r2" && verb === "bucket" && third === "create" && args[3]) {
|
|
442
|
+
const created = runCf([
|
|
443
|
+
"r2",
|
|
444
|
+
"buckets",
|
|
445
|
+
"create",
|
|
446
|
+
"--name",
|
|
447
|
+
args[3]
|
|
448
|
+
]);
|
|
449
|
+
if (created.status === 0) updateBinding("r2_buckets", field("--binding") ?? "", { bucket_name: args[3] });
|
|
450
|
+
return created;
|
|
451
|
+
}
|
|
452
|
+
if (group === "hyperdrive" && verb === "create" && third) {
|
|
453
|
+
const connection = args.find((part) => part.startsWith("--connection-string="))?.slice(20);
|
|
454
|
+
if (!connection) throw new Error("Hyperdrive connection string is missing.");
|
|
455
|
+
const url = new URL(connection);
|
|
456
|
+
const created = await withSecretFile(JSON.stringify({
|
|
457
|
+
name: third,
|
|
458
|
+
origin: {
|
|
459
|
+
host: url.hostname,
|
|
460
|
+
port: Number(url.port || (url.protocol.startsWith("mysql") ? 3306 : 5432)),
|
|
461
|
+
database: decodeURIComponent(url.pathname.replace(/^\//, "")),
|
|
462
|
+
scheme: url.protocol.replace(":", ""),
|
|
463
|
+
user: decodeURIComponent(url.username),
|
|
464
|
+
password: decodeURIComponent(url.password)
|
|
465
|
+
}
|
|
466
|
+
}), (path) => runCf([
|
|
467
|
+
"hyperdrive",
|
|
468
|
+
"create",
|
|
469
|
+
"--body",
|
|
470
|
+
`@${path}`
|
|
471
|
+
]));
|
|
472
|
+
if (created.status !== 0) return result(created.status, "", "Hyperdrive creation failed.");
|
|
473
|
+
const hyperdrive = object(parsedJson(created.stdout));
|
|
474
|
+
if (typeof hyperdrive.id !== "string") throw new Error("Hyperdrive creation returned no ID.");
|
|
475
|
+
updateBinding("hyperdrive", field("--binding") ?? "", { id: hyperdrive.id });
|
|
476
|
+
return result(0, `${JSON.stringify({
|
|
477
|
+
id: hyperdrive.id,
|
|
478
|
+
name: third
|
|
479
|
+
})}\n`);
|
|
480
|
+
}
|
|
481
|
+
if (group === "queues" && (verb === "info" || verb === "create") && third) {
|
|
482
|
+
if (verb === "create") return runCf([
|
|
483
|
+
"queues",
|
|
484
|
+
"create",
|
|
485
|
+
"--queue-name",
|
|
486
|
+
third
|
|
487
|
+
]);
|
|
488
|
+
return (await readAllQueues()).find((item) => item.queue_name === third) ? result(0, `Queue Name: ${third}\n`) : result(1, "", `Queue "${third}" does not exist`);
|
|
489
|
+
}
|
|
490
|
+
return result(1, "", `Unsupported Cloudflare resource operation: ${group} ${verb}.`);
|
|
491
|
+
}
|
|
492
|
+
function emailZone(domain) {
|
|
493
|
+
const labels = domain.split(".");
|
|
494
|
+
for (let offset = 0; offset <= labels.length - 2; offset++) {
|
|
495
|
+
const candidate = labels.slice(offset).join(".");
|
|
496
|
+
const read = runCf([
|
|
497
|
+
"email-routing",
|
|
498
|
+
"settings",
|
|
499
|
+
"get",
|
|
500
|
+
"--zone",
|
|
501
|
+
candidate
|
|
502
|
+
]);
|
|
503
|
+
if (read.status === 0) return candidate;
|
|
504
|
+
if (!/Zone not found:/.test(read.stderr)) throw new Error("Cloudflare could not resolve the Email zone.");
|
|
505
|
+
}
|
|
506
|
+
throw new Error(`Cloudflare Email zone for ${domain} was not found.`);
|
|
507
|
+
}
|
|
508
|
+
function email() {
|
|
509
|
+
const [group, product, operation, candidate] = args;
|
|
510
|
+
if (group !== "email" || !candidate) return result(1, "", "Unsupported Cloudflare email operation.");
|
|
511
|
+
if (product === "routing" && operation === "settings") {
|
|
512
|
+
const read = runCf([
|
|
513
|
+
"email-routing",
|
|
514
|
+
"settings",
|
|
515
|
+
"get",
|
|
516
|
+
"--zone",
|
|
517
|
+
candidate
|
|
518
|
+
]);
|
|
519
|
+
if (read.status !== 0) return /Zone not found:/.test(read.stderr) ? result(1, "", `Could not find a zone for \`${candidate}\`.`) : read;
|
|
520
|
+
const settings = object(parsedJson(read.stdout));
|
|
521
|
+
if (typeof settings.tag !== "string" || typeof settings.name !== "string") throw new Error("Email Routing settings were incomplete.");
|
|
522
|
+
return result(0, `Email Routing for ${settings.name}:\n Enabled: ${settings.enabled === true}\n Status: ${settings.status}\n Tag: ${settings.tag}\n`);
|
|
523
|
+
}
|
|
524
|
+
if (product === "routing" && operation === "enable") return runCf([
|
|
525
|
+
"email-routing",
|
|
526
|
+
"enable",
|
|
527
|
+
"--zone",
|
|
528
|
+
candidate,
|
|
529
|
+
"--name",
|
|
530
|
+
candidate
|
|
531
|
+
]);
|
|
532
|
+
if (product === "routing" && operation === "rules" && args[3] === "list" && args[4]) {
|
|
533
|
+
const zone = args[4];
|
|
534
|
+
const lines = [];
|
|
535
|
+
for (let page = 1; page <= 100; page++) {
|
|
536
|
+
const listed = runCf([
|
|
537
|
+
"email-routing",
|
|
538
|
+
"rules",
|
|
539
|
+
"list-account",
|
|
540
|
+
"--zone",
|
|
541
|
+
zone,
|
|
542
|
+
"--page",
|
|
543
|
+
String(page),
|
|
544
|
+
"--per-page",
|
|
545
|
+
"100"
|
|
546
|
+
]);
|
|
547
|
+
if (listed.status !== 0) return listed;
|
|
548
|
+
const items = parsedJson(listed.stdout);
|
|
549
|
+
if (!Array.isArray(items)) throw new Error("Email Routing rules were malformed.");
|
|
550
|
+
for (const entry of items.map(object)) {
|
|
551
|
+
const actions = Array.isArray(entry.actions) ? entry.actions.map((action) => {
|
|
552
|
+
const item = object(action);
|
|
553
|
+
return item.type === "worker" ? `worker:${item.value}` : item.type === "forward" && Array.isArray(item.value) ? `forward:${item.value.join(",")}` : String(item.type);
|
|
554
|
+
}) : [];
|
|
555
|
+
const matchers = Array.isArray(entry.matchers) ? entry.matchers.map(object) : [];
|
|
556
|
+
if (matchers.some((item) => item.type === "all")) lines.push(`Catch-all rule: ${entry.enabled === true ? "enabled" : "disabled"}, action: ${actions.join(", ")}`);
|
|
557
|
+
else {
|
|
558
|
+
if (typeof entry.id !== "string") throw new Error("Email Routing rule ID was missing.");
|
|
559
|
+
const recipients = matchers.filter((item) => item.type === "literal" || item.type === "to").map((item) => `to:${item.value}`);
|
|
560
|
+
lines.push(`Rule: ${entry.id}\n Name: ${entry.name || "(none)"}\n Enabled: ${entry.enabled === true}\n Matchers: ${recipients.join(", ")}\n Actions: ${actions.join(", ")}\n Priority: ${entry.priority ?? 0}`);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (items.length < 100) return result(0, lines.length ? `${lines.join("\n")}\n` : "No routing rules found.\n");
|
|
564
|
+
}
|
|
565
|
+
throw new Error("Email Routing rules exceeded the supported page limit.");
|
|
566
|
+
}
|
|
567
|
+
if (product === "sending" && operation === "settings") {
|
|
568
|
+
const listed = runCf([
|
|
569
|
+
"email-sending",
|
|
570
|
+
"subdomains",
|
|
571
|
+
"list",
|
|
572
|
+
"--zone",
|
|
573
|
+
emailZone(candidate)
|
|
574
|
+
]);
|
|
575
|
+
if (listed.status !== 0) return listed;
|
|
576
|
+
const values = parsedJson(listed.stdout);
|
|
577
|
+
if (!Array.isArray(values)) throw new Error("Email Sending subdomains were malformed.");
|
|
578
|
+
const match = values.map(object).find((item) => item.name === candidate);
|
|
579
|
+
if (!match) return result(1, "", `No sending subdomain found for \`${candidate}\`.`);
|
|
580
|
+
const tag = match.tag ?? match.id;
|
|
581
|
+
if (typeof tag !== "string") throw new Error("Email Sending subdomain ID was missing.");
|
|
582
|
+
return result(0, `Email Sending for ${candidate}:\n Enabled: ${match.enabled === true}\n Tag: ${tag}\n`);
|
|
583
|
+
}
|
|
584
|
+
if (product === "sending" && operation === "enable") return runCf([
|
|
585
|
+
"email-sending",
|
|
586
|
+
"subdomains",
|
|
587
|
+
"create",
|
|
588
|
+
"--zone",
|
|
589
|
+
emailZone(candidate),
|
|
590
|
+
"--name",
|
|
591
|
+
candidate
|
|
592
|
+
]);
|
|
593
|
+
return result(1, "", `Unsupported Cloudflare email operation: ${product} ${operation}.`);
|
|
594
|
+
}
|
|
595
|
+
async function secrets() {
|
|
596
|
+
const worker = workerName();
|
|
597
|
+
const verb = args[1];
|
|
598
|
+
const apply = async (action) => {
|
|
599
|
+
const first = action();
|
|
600
|
+
if (first.status === 0 || !/\[code:\s*10007\]/.test(first.stderr)) return first;
|
|
601
|
+
const draft = await withBuildOutput({
|
|
602
|
+
name: worker,
|
|
603
|
+
account_id: process.env.CLOUDFLARE_ACCOUNT_ID ?? config().account_id,
|
|
604
|
+
compatibility_date: config().compatibility_date ?? "2025-01-01",
|
|
605
|
+
workers_dev: false,
|
|
606
|
+
preview_urls: false
|
|
607
|
+
}, null, (directory) => runCf([
|
|
608
|
+
"deploy",
|
|
609
|
+
"--prebuilt",
|
|
610
|
+
"--message",
|
|
611
|
+
"void:secret-draft"
|
|
612
|
+
], directory));
|
|
613
|
+
return draft.status === 0 ? action() : draft;
|
|
614
|
+
};
|
|
615
|
+
if (verb === "list") {
|
|
616
|
+
const listed = runCf([
|
|
617
|
+
"workers",
|
|
618
|
+
"secrets",
|
|
619
|
+
"list",
|
|
620
|
+
"--worker",
|
|
621
|
+
worker
|
|
622
|
+
]);
|
|
623
|
+
if (listed.status !== 0 && /\[code:\s*(?:10007|10090)\]/.test(listed.stderr)) return result(1, "", `Worker "${worker}" not found. [code: 10007]`);
|
|
624
|
+
return listed;
|
|
625
|
+
}
|
|
626
|
+
if (verb === "put" && args[2]) {
|
|
627
|
+
const value = readFileSync(0, "utf8").replace(/\n$/, "");
|
|
628
|
+
return await withSecretFile(JSON.stringify({
|
|
629
|
+
name: args[2],
|
|
630
|
+
text: value,
|
|
631
|
+
type: "secret_text"
|
|
632
|
+
}), (path) => apply(() => runCf([
|
|
633
|
+
"workers",
|
|
634
|
+
"secrets",
|
|
635
|
+
"update",
|
|
636
|
+
args[2],
|
|
637
|
+
"--worker",
|
|
638
|
+
worker,
|
|
639
|
+
"--body",
|
|
640
|
+
`@${path}`
|
|
641
|
+
])));
|
|
642
|
+
}
|
|
643
|
+
if (verb === "bulk") {
|
|
644
|
+
const input = object(parsedJson(readFileSync(0, "utf8")));
|
|
645
|
+
const patch = Object.fromEntries(Object.entries(input).map(([name, text]) => [name, {
|
|
646
|
+
type: "secret_text",
|
|
647
|
+
text
|
|
648
|
+
}]));
|
|
649
|
+
return await withSecretFile(JSON.stringify(patch), (path) => apply(() => runCf([
|
|
650
|
+
"workers",
|
|
651
|
+
"secrets",
|
|
652
|
+
"bulk",
|
|
653
|
+
"--worker",
|
|
654
|
+
worker,
|
|
655
|
+
"--file",
|
|
656
|
+
path
|
|
657
|
+
])));
|
|
658
|
+
}
|
|
659
|
+
if (verb === "delete" && args[2]) return runCf([
|
|
660
|
+
"workers",
|
|
661
|
+
"secrets",
|
|
662
|
+
"delete",
|
|
663
|
+
args[2],
|
|
664
|
+
"--worker",
|
|
665
|
+
worker,
|
|
666
|
+
"--force"
|
|
667
|
+
]);
|
|
668
|
+
return result(1, "", `Unsupported Cloudflare secret operation: ${verb}.`);
|
|
669
|
+
}
|
|
670
|
+
async function workerHistory() {
|
|
671
|
+
const worker = workerName();
|
|
672
|
+
const [group, verb, third] = args;
|
|
673
|
+
if (group === "deployments" && (verb === "status" || verb === "list")) {
|
|
674
|
+
const called = runCf([
|
|
675
|
+
"workers",
|
|
676
|
+
"deployments",
|
|
677
|
+
"list",
|
|
678
|
+
"--worker",
|
|
679
|
+
worker
|
|
680
|
+
]);
|
|
681
|
+
if (called.status !== 0) return called;
|
|
682
|
+
const deployments = object(parsedJson(called.stdout)).deployments;
|
|
683
|
+
if (!Array.isArray(deployments)) throw new Error("Worker deployments were malformed.");
|
|
684
|
+
if (verb === "status") return deployments[0] ? result(0, `${JSON.stringify(deployments[0])}\n`) : result(1, "", "Worker has no active deployment.");
|
|
685
|
+
return result(0, `${JSON.stringify(deployments)}\n`);
|
|
686
|
+
}
|
|
687
|
+
if (group === "versions" && verb === "list") return cleanJson([
|
|
688
|
+
"workers",
|
|
689
|
+
"versions",
|
|
690
|
+
"list",
|
|
691
|
+
"--worker-id",
|
|
692
|
+
worker
|
|
693
|
+
], (value) => {
|
|
694
|
+
if (!Array.isArray(value)) throw new Error("Worker versions were malformed.");
|
|
695
|
+
return value.map((entry) => {
|
|
696
|
+
const version = object(entry);
|
|
697
|
+
return {
|
|
698
|
+
...version,
|
|
699
|
+
metadata: { created_on: version.created_on }
|
|
700
|
+
};
|
|
701
|
+
});
|
|
702
|
+
});
|
|
703
|
+
if (group === "versions" && verb === "view" && third) {
|
|
704
|
+
const called = runCf([
|
|
705
|
+
"workers",
|
|
706
|
+
"versions",
|
|
707
|
+
"get",
|
|
708
|
+
third,
|
|
709
|
+
"--worker-id",
|
|
710
|
+
worker
|
|
711
|
+
]);
|
|
712
|
+
if (called.status !== 0) return called;
|
|
713
|
+
const version = object(parsedJson(called.stdout));
|
|
714
|
+
if (version.id !== third || !Array.isArray(version.bindings)) throw new Error("Worker version bindings were malformed.");
|
|
715
|
+
const resources = await readVersionResources(worker, third);
|
|
716
|
+
return result(0, `${JSON.stringify({
|
|
717
|
+
...version,
|
|
718
|
+
resources
|
|
719
|
+
})}\n`);
|
|
720
|
+
}
|
|
721
|
+
if (group === "versions" && verb === "deploy") {
|
|
722
|
+
const firstFlag = args.findIndex((part, index) => index >= 2 && part.startsWith("-"));
|
|
723
|
+
const versions = args.slice(2, firstFlag === -1 ? void 0 : firstFlag).map((part) => {
|
|
724
|
+
const [version_id, fraction] = part.split("@");
|
|
725
|
+
const percentage = Number(fraction);
|
|
726
|
+
if (!/^[0-9a-f-]{36}$/i.test(version_id ?? "") || !Number.isFinite(percentage)) throw new Error("Cloudflare deployment version was malformed.");
|
|
727
|
+
return {
|
|
728
|
+
version_id,
|
|
729
|
+
percentage
|
|
730
|
+
};
|
|
731
|
+
});
|
|
732
|
+
if (!versions.length || Math.abs(versions.reduce((sum, entry) => sum + entry.percentage, 0) - 100) > .001) throw new Error("Cloudflare deployment percentages must total 100.");
|
|
733
|
+
const message = field("--message");
|
|
734
|
+
return runCf([
|
|
735
|
+
"workers",
|
|
736
|
+
"deployments",
|
|
737
|
+
"create",
|
|
738
|
+
"--worker",
|
|
739
|
+
worker,
|
|
740
|
+
"--body",
|
|
741
|
+
JSON.stringify({
|
|
742
|
+
strategy: "percentage",
|
|
743
|
+
versions,
|
|
744
|
+
...message ? { annotations: { "workers/message": message } } : {}
|
|
745
|
+
})
|
|
746
|
+
]);
|
|
747
|
+
}
|
|
748
|
+
return result(1, "", `Unsupported Cloudflare Worker history operation: ${group} ${verb}.`);
|
|
749
|
+
}
|
|
750
|
+
async function workerChanges() {
|
|
751
|
+
if (args[0] === "queues" && args[1] === "consumer" && args[2] === "remove") {
|
|
752
|
+
const queueName = args[3];
|
|
753
|
+
const worker = args[4];
|
|
754
|
+
if (!queueName || !worker) throw new Error("Queue consumer target is missing.");
|
|
755
|
+
const queue = (await readAllQueues()).find((item) => item.queue_name === queueName);
|
|
756
|
+
if (!queue || typeof queue.queue_id !== "string") return result(1, "", `Queue "${queueName}" does not exist`);
|
|
757
|
+
const consumers = runCf([
|
|
758
|
+
"queues",
|
|
759
|
+
"consumers",
|
|
760
|
+
"list",
|
|
761
|
+
"--queue-id",
|
|
762
|
+
queue.queue_id
|
|
763
|
+
]);
|
|
764
|
+
if (consumers.status !== 0) return consumers;
|
|
765
|
+
const members = parsedJson(consumers.stdout);
|
|
766
|
+
if (!Array.isArray(members)) throw new Error("Queue consumer list was malformed.");
|
|
767
|
+
for (const item of members.map(object).filter((entry) => entry.script === worker)) {
|
|
768
|
+
if (typeof item.consumer_id !== "string") throw new Error("Queue consumer ID is missing.");
|
|
769
|
+
const deleted = runCf([
|
|
770
|
+
"queues",
|
|
771
|
+
"consumers",
|
|
772
|
+
"delete",
|
|
773
|
+
item.consumer_id,
|
|
774
|
+
"--queue-id",
|
|
775
|
+
queue.queue_id,
|
|
776
|
+
"--force"
|
|
777
|
+
]);
|
|
778
|
+
if (deleted.status !== 0) return deleted;
|
|
779
|
+
}
|
|
780
|
+
return result(0);
|
|
781
|
+
}
|
|
782
|
+
if (args[0] === "triggers" && args[1] === "deploy") {
|
|
783
|
+
const raw = config();
|
|
784
|
+
const name = workerName();
|
|
785
|
+
if (raw.name !== name) throw new Error("Cloudflare trigger Worker name changed.");
|
|
786
|
+
return await withBuildOutput(raw, null, (directory) => runCf([
|
|
787
|
+
"workers",
|
|
788
|
+
"triggers",
|
|
789
|
+
"deploy",
|
|
790
|
+
"--prebuilt",
|
|
791
|
+
...args.includes("--dry-run") ? ["--dry-run"] : []
|
|
792
|
+
], directory));
|
|
793
|
+
}
|
|
794
|
+
if (args[0] === "triggers" && args[1] === "clear-crons") {
|
|
795
|
+
const raw = config();
|
|
796
|
+
const name = workerName();
|
|
797
|
+
if (raw.name !== name || raw.account_id !== void 0 && raw.account_id !== accountId()) throw new Error("Cloudflare trigger target changed.");
|
|
798
|
+
return await clearWorkerCronSchedules(name);
|
|
799
|
+
}
|
|
800
|
+
if (args[0] === "versions" && args[1] === "upload" || args[0] === "deploy") {
|
|
801
|
+
const raw = config();
|
|
802
|
+
const path = configPath();
|
|
803
|
+
if (typeof raw.main !== "string" || !raw.main || raw.no_bundle !== true) throw new Error("Cloudflare Worker upload requires a prebuilt platform Worker.");
|
|
804
|
+
const source = resolve(dirname(path), raw.main);
|
|
805
|
+
const message = field("--message");
|
|
806
|
+
const secrets = field("--secrets-file");
|
|
807
|
+
return await withBuildOutput(raw, source, (directory) => runCf([
|
|
808
|
+
...args[0] === "deploy" ? ["deploy"] : [
|
|
809
|
+
"workers",
|
|
810
|
+
"versions",
|
|
811
|
+
"create"
|
|
812
|
+
],
|
|
813
|
+
"--prebuilt",
|
|
814
|
+
...message ? ["--message", message] : [],
|
|
815
|
+
...secrets ? ["--secrets-file", secrets] : [],
|
|
816
|
+
...args.includes("--dry-run") ? ["--dry-run"] : []
|
|
817
|
+
], directory));
|
|
818
|
+
}
|
|
819
|
+
return result(1, "", `Unsupported Cloudflare Worker operation: ${args.slice(0, 2).join(" ")}.`);
|
|
820
|
+
}
|
|
821
|
+
async function tail() {
|
|
822
|
+
const worker = args[1];
|
|
823
|
+
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID ?? config().account_id;
|
|
824
|
+
if (!worker || typeof accountId !== "string" || !accountId || worker !== workerName()) throw new Error("Cloudflare tail target is not pinned.");
|
|
825
|
+
const filters = [];
|
|
826
|
+
if (field("--search")) filters.push({ query: field("--search") });
|
|
827
|
+
if (field("--version-id")) filters.push({ scriptVersion: field("--version-id") });
|
|
828
|
+
if (field("--status") === "error") filters.push({ outcome: [
|
|
829
|
+
"exception",
|
|
830
|
+
"exceededCpu",
|
|
831
|
+
"exceededMemory",
|
|
832
|
+
"unknown"
|
|
833
|
+
] });
|
|
834
|
+
const endpoint = `${(process.env.CLOUDFLARE_API_BASE_URL ?? "https://api.cloudflare.com/client/v4").replace(/\/$/, "")}/accounts/${encodeURIComponent(accountId)}/workers/scripts/${encodeURIComponent(worker)}/tails`;
|
|
835
|
+
const headers = {
|
|
836
|
+
...apiHeaders(),
|
|
837
|
+
"Content-Type": "application/json"
|
|
838
|
+
};
|
|
839
|
+
const stopped = new AbortController();
|
|
840
|
+
let socket;
|
|
841
|
+
let finish;
|
|
842
|
+
const stop = () => {
|
|
843
|
+
stopped.abort();
|
|
844
|
+
socket?.close();
|
|
845
|
+
finish?.();
|
|
846
|
+
};
|
|
847
|
+
process.once("SIGINT", stop);
|
|
848
|
+
process.once("SIGTERM", stop);
|
|
849
|
+
let record;
|
|
850
|
+
try {
|
|
851
|
+
const created = await fetch(endpoint, {
|
|
852
|
+
method: "POST",
|
|
853
|
+
headers,
|
|
854
|
+
body: JSON.stringify({ filters }),
|
|
855
|
+
signal: AbortSignal.any([stopped.signal, AbortSignal.timeout(3e4)])
|
|
856
|
+
});
|
|
857
|
+
const body = object(await created.json());
|
|
858
|
+
if (!created.ok || body.success !== true) return result(1, "", "Could not start the Cloudflare Worker tail.");
|
|
859
|
+
record = object(body.result);
|
|
860
|
+
if (typeof record.id !== "string" || typeof record.url !== "string") throw new Error("Cloudflare Worker tail response was incomplete.");
|
|
861
|
+
const tailUrl = record.url;
|
|
862
|
+
if (stopped.signal.aborted) return result(0);
|
|
863
|
+
await new Promise((resolve, reject) => {
|
|
864
|
+
finish = resolve;
|
|
865
|
+
socket = new WebSocket(tailUrl, "trace-v1");
|
|
866
|
+
socket.addEventListener("open", () => {
|
|
867
|
+
socket.send(JSON.stringify({ debug: false }));
|
|
868
|
+
});
|
|
869
|
+
socket.addEventListener("message", (event) => {
|
|
870
|
+
try {
|
|
871
|
+
const log = object(parsedJson(String(event.data)));
|
|
872
|
+
const detail = object(log.event ?? {});
|
|
873
|
+
const request = object(detail.request ?? {});
|
|
874
|
+
const prefix = typeof request.url === "string" ? `${request.method ?? "GET"} ${request.url}` : typeof detail.queue === "string" ? `Queue ${detail.queue}` : typeof detail.mailFrom === "string" ? `Email from ${detail.mailFrom}` : "Worker event";
|
|
875
|
+
process.stdout.write(`${prefix} - ${log.outcome ?? "unknown"} @ ${new Date(Number(log.eventTimestamp)).toLocaleString()}\n`);
|
|
876
|
+
if (Array.isArray(log.logs)) for (const line of log.logs.map(object)) process.stdout.write(` (${line.level ?? "log"}) ${Array.isArray(line.message) ? line.message.join(" ") : ""}\n`);
|
|
877
|
+
if (Array.isArray(log.exceptions)) for (const exception of log.exceptions.map(object)) process.stderr.write(` ${exception.name ?? "Error"}: ${exception.message ?? ""}\n`);
|
|
878
|
+
} catch {
|
|
879
|
+
process.stderr.write("Cloudflare returned a malformed tail event.\n");
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
socket.addEventListener("error", () => reject(/* @__PURE__ */ new Error("Cloudflare Worker tail connection failed.")));
|
|
883
|
+
socket.addEventListener("close", () => resolve());
|
|
884
|
+
if (stopped.signal.aborted) resolve();
|
|
885
|
+
});
|
|
886
|
+
} catch (error) {
|
|
887
|
+
if (stopped.signal.aborted) return result(0);
|
|
888
|
+
throw error;
|
|
889
|
+
} finally {
|
|
890
|
+
process.off("SIGINT", stop);
|
|
891
|
+
process.off("SIGTERM", stop);
|
|
892
|
+
socket?.close();
|
|
893
|
+
if (record && typeof record.id === "string") await fetch(`${endpoint}/${encodeURIComponent(record.id)}`, {
|
|
894
|
+
method: "DELETE",
|
|
895
|
+
headers,
|
|
896
|
+
signal: AbortSignal.timeout(5e3)
|
|
897
|
+
}).catch(() => {});
|
|
898
|
+
if (stopped.signal.aborted) process.exit(0);
|
|
899
|
+
}
|
|
900
|
+
return result(0);
|
|
901
|
+
}
|
|
902
|
+
async function main() {
|
|
903
|
+
if ([
|
|
904
|
+
"whoami",
|
|
905
|
+
"login",
|
|
906
|
+
"logout",
|
|
907
|
+
"auth"
|
|
908
|
+
].includes(args[0] ?? "")) return auth();
|
|
909
|
+
if (args[0] === "secret") return await secrets();
|
|
910
|
+
if (args[0] === "tail") return await tail();
|
|
911
|
+
if (args[0] === "email") return email();
|
|
912
|
+
if (args[0] === "deployments" || args[0] === "versions" && args[1] !== "upload") return await workerHistory();
|
|
913
|
+
if (args[0] === "triggers" || args[0] === "deploy" || args[0] === "versions" && args[1] === "upload" || args[0] === "queues" && args[1] === "consumer") return await workerChanges();
|
|
914
|
+
if ([
|
|
915
|
+
"d1",
|
|
916
|
+
"kv",
|
|
917
|
+
"r2",
|
|
918
|
+
"hyperdrive",
|
|
919
|
+
"queues",
|
|
920
|
+
"containers"
|
|
921
|
+
].includes(args[0] ?? "")) return await resources();
|
|
922
|
+
return result(1, "", `Unsupported Cloudflare operation: ${args.slice(0, 2).join(" ")}.`);
|
|
923
|
+
}
|
|
924
|
+
try {
|
|
925
|
+
const output = await main();
|
|
926
|
+
if (output.stdout) process.stdout.write(output.stdout);
|
|
927
|
+
if (output.stderr) process.stderr.write(output.stderr);
|
|
928
|
+
process.exitCode = output.status;
|
|
929
|
+
} catch (error) {
|
|
930
|
+
process.stderr.write(error instanceof Error ? error.message : "Cloudflare command failed.");
|
|
931
|
+
process.exitCode = 1;
|
|
932
|
+
}
|
|
933
|
+
//#endregion
|
|
934
|
+
export {};
|