void 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_TEMPLATE.md +1 -1
- package/README.md +19 -106
- package/dist/{account-cmd-C84Ee8cO.mjs → account-cmd-DcR1ywt8.mjs} +5 -5
- package/dist/{auth-CSkdO2Bb.mjs → auth-7wuZ5ob8.mjs} +22 -49
- package/dist/auth-CdgZ9uag.mjs +2 -0
- package/dist/{auth-link-CioEg6uY.mjs → auth-link-Z6E5DYvM.mjs} +5 -6
- package/dist/{auth-router-BsR981d4.mjs → auth-router-BdM4avI8.mjs} +7 -7
- package/dist/{build-cmd-LzvNJORH.mjs → build-cmd-CEE7D-hM.mjs} +7 -8
- package/dist/{cache-C4MvnrMH.mjs → cache-TcZnBLtH.mjs} +6 -7
- package/dist/{cancel-deploy-abUxpP2n.mjs → cancel-deploy-CYoZmcmR.mjs} +4 -6
- package/dist/{cf-access-P0iZnu0q.mjs → cf-access-AHKBzmuu.mjs} +4 -48
- package/dist/{cf-access-DRsQRe6k.mjs → cf-access-TWNzXltp.mjs} +3 -11
- package/dist/cf-build-output-ChY6-XWP.mjs +2 -0
- package/dist/cli/cli.mjs +49 -46
- package/dist/cli/cloudflare-operation-process.mjs +16 -7
- package/dist/cli/env-schema-probe.mjs +3 -3
- package/dist/client-B4Me-9HE.mjs +2 -0
- package/dist/{client-RV8NVeB8.mjs → client-RsPo8wsP.mjs} +129 -33
- package/dist/{cloudflare-cmd-BcrVyTmJ.mjs → cloudflare-cmd-bhwCxAN6.mjs} +2 -2
- package/dist/{cloudflare-connect-B8uPZ4nx.mjs → cloudflare-connect-CuhRgk3k.mjs} +2 -2
- package/dist/{cloudflare-operations-AiWashgg.mjs → cloudflare-operations-BhbK6yTq.mjs} +1 -1
- package/dist/{cloudflare-operations-fxHb-byx.mjs → cloudflare-operations-CjaV4lZi.mjs} +2 -2
- package/dist/{connect-Bd4kJd9U.mjs → connect-DCvUmPXY.mjs} +13 -10
- package/dist/{create-project-Boczwj5r.mjs → create-project-C734I-Mu.mjs} +1 -1
- package/dist/{create-project-bMf6ffLZ.mjs → create-project-eAPgYq35.mjs} +13 -13
- package/dist/{db-8uG64XLl.mjs → db-C07GEdKF.mjs} +27 -30
- package/dist/{delete-NvbiyeJf.mjs → delete-pKMVsrpJ.mjs} +5 -6
- package/dist/deploy-BDu1vhSH.mjs +2 -0
- package/dist/{deploy-DzAIwqNU.mjs → deploy-DfsAe-T0.mjs} +9567 -9215
- package/dist/{dev-inbox-P0u4tM8Y.mjs → dev-inbox-D64ZKUod.mjs} +5 -6
- package/dist/{domain-y5Tvydvo.mjs → domain-D3uA9ize.mjs} +8 -8
- package/dist/{email-B3umsW75.mjs → email-z3o2cwjH.mjs} +8 -8
- package/dist/{env-BS6qYHDb.mjs → env-3Q8-_2IH.mjs} +7 -9
- package/dist/{env-types-C2_bIk_b.mjs → env-types-D5kds_OZ.mjs} +1 -1
- package/dist/{env-validation-DbTg7-ar.mjs → env-validation-cZBvGWaP.mjs} +1 -1
- package/dist/{env-validation-BPn7vk-V.mjs → env-validation-vBSQ8gw5.mjs} +3 -3
- package/dist/gen-ById9r2j.mjs +2 -0
- package/dist/{gen-B580--vC.mjs → gen-NjwoG9FK.mjs} +2 -4
- package/dist/{github-cmd-v45BdfKX.mjs → github-cmd-DquUq-b1.mjs} +15 -24
- package/dist/{headers-DWi2IXWx.mjs → headers-2rKda9Y6.mjs} +1 -1
- package/dist/help-DPGBwomV.mjs +2 -0
- package/dist/{help-daGKjXGk.mjs → help-DRZXC4fj.mjs} +8 -4
- package/dist/{inbound-aVHEUhKo.mjs → inbound-fRkqcXaC.mjs} +1 -1
- package/dist/index.d.mts +18 -14
- package/dist/index.mjs +2176 -2110
- package/dist/{info-B97bTX9N.mjs → info-BmA3_IFZ.mjs} +1 -3
- package/dist/{init-Bvy7zrBo.mjs → init-DT7yuuyl.mjs} +28 -27
- package/dist/{link-CDqqCjFl.mjs → link-CXOlqh2F.mjs} +6 -7
- package/dist/{list-CZj0dzKY.mjs → list-eEWVJEPn.mjs} +8 -9
- package/dist/{local-d1-2CMnpuW_.mjs → local-d1-Df4XpwhW.mjs} +1 -1
- package/dist/log-vqY3pqwI.mjs +29 -0
- package/dist/login-C98-sw79.mjs +2 -0
- package/dist/{login-UZKFM_u7.mjs → login-pWQHYVu2.mjs} +12 -10
- package/dist/{logs-CUZ6t9t3.mjs → logs-DnxVX7TR.mjs} +11 -13
- package/dist/migrate-CEu2X5DB.mjs +2 -0
- package/dist/{migrate-DHul7PRV.mjs → migrate-CV1on-yJ.mjs} +2 -4
- package/dist/{operator-args-CLgKGlwU.mjs → operator-args-CAVcmwUt.mjs} +12 -5
- package/dist/{operator-auth-8KnOVXVd.mjs → operator-auth-CkmTE3rt.mjs} +2 -2
- package/dist/{operator-client-DUwumHpQ.mjs → operator-client-LmwjxT6q.mjs} +3 -3
- package/dist/{operator-cmd-DBA6dl0m.mjs → operator-cmd-d-IEKgNk.mjs} +6 -6
- package/dist/{output-Dm_A4Tbv.mjs → output-BBsUwdyT.mjs} +22 -14
- package/dist/pages/client.d.mts +3 -0
- package/dist/pages/client.mjs +120 -29
- package/dist/pages/index.mjs +1 -1
- package/dist/{platform-args-BJdRtlLq.mjs → platform-args-Bzf8JPc2.mjs} +11 -3
- package/dist/platform-args-Cq6EjQro.mjs +2 -0
- package/dist/{platform-auth-config-B56E9YP1.mjs → platform-auth-config-0V0lA3pF.mjs} +7 -7
- package/dist/{platform-auth-protection-BDWO_aER.mjs → platform-auth-protection-DFeJ-JkK.mjs} +9 -9
- package/dist/{platform-auth-recovery-1gg4CSRe.mjs → platform-auth-recovery-ICy4muq6.mjs} +7 -7
- package/dist/{platform-cmd-Bt-1w6pY.mjs → platform-cmd-BPySFOew.mjs} +1 -1
- package/dist/{platform-cmd-DMcQStSc.mjs → platform-cmd-D7vSWMvV.mjs} +38 -28
- package/dist/platform-discovery-DDDUvnqp.mjs +27 -0
- package/dist/{platform-domain-BNkcz0OB.mjs → platform-domain-CUdY064e.mjs} +5 -5
- package/dist/{platform-lifecycle-BE6C_jxh.mjs → platform-lifecycle-BaUdTRPU.mjs} +1 -1
- package/dist/{platform-lifecycle-9OyBALhH.mjs → platform-lifecycle-Dm09JNkn.mjs} +4404 -3297
- package/dist/{platform-management-CjwLVQwN.mjs → platform-management-BSEc_ZeG.mjs} +48 -11
- package/dist/platform-management-Bp6aoH2C.mjs +2 -0
- package/dist/{platform-plans-config-BNGKGr4P.mjs → platform-plans-config-B0pOVQyW.mjs} +3 -3
- package/dist/{platform-recovery-D6KSpuFm.mjs → platform-recovery-WOZ95Uze.mjs} +4 -4
- package/dist/{platform-registry-QBa4DK32.mjs → platform-registry-KfNEF84O.mjs} +3 -3
- package/dist/{prepare-B5Mkic5u.mjs → prepare-39EvOhI6.mjs} +2 -4
- package/dist/prepare-CnjcTV2s.mjs +2 -0
- package/dist/{prepare-DOsL0CC9.mjs → prepare-DnaKBi--.mjs} +1 -1
- package/dist/{project-C0Fqu05O.mjs → project-BkbfDs0V.mjs} +15 -82
- package/dist/project-IOjBU8R6.mjs +2 -0
- package/dist/{project-cmd-CNzrqvBv.mjs → project-cmd-Bs5A392E.mjs} +21 -22
- package/dist/{project-team-DQOWPfQT.mjs → project-team-ohAWWaew.mjs} +8 -9
- package/dist/{project-token-CTDYU0Cc.mjs → project-token-CP01Jna6.mjs} +6 -9
- package/dist/{project-zero-trust-BNAkW-_0.mjs → project-zero-trust-BzkVgx35.mjs} +5 -6
- package/dist/prompts-6OSVA7DJ.mjs +2087 -0
- package/dist/prompts-ZAuJlyCj.mjs +2 -0
- package/dist/{provision-C4ORE7G7.mjs → provision-BEv0k-qz.mjs} +1 -1
- package/dist/{provision-CJFgTZY8.mjs → provision-Btj1jppf.mjs} +5 -7
- package/dist/{requests-MhxYnau8.mjs → requests-B3PBuGlX.mjs} +5 -6
- package/dist/{rollback-CJ6iSDoU.mjs → rollback-DDub9GsO.mjs} +9 -10
- package/dist/runtime/ai.mjs +3 -5
- package/dist/runtime/email/testing.mjs +2 -2
- package/dist/runtime/email.mjs +36 -18
- package/dist/runtime/remote/index.mjs +2 -2
- package/dist/runtime/routing.mjs +1 -1
- package/dist/{secret-Dli5fP0B.mjs → secret-3c72lY1U.mjs} +15 -16
- package/dist/{skills-D1II1Juz.mjs → skills-BPQUGClu.mjs} +1 -1
- package/dist/{subcommand-prompt-CY1C4fvl.mjs → subcommand-prompt-Dhom39bd.mjs} +40 -32
- package/dist/sveltekit.d.mts +1 -1
- package/dist/sveltekit.mjs +4 -9
- package/dist/{wrangler-7K-bW_DL.mjs → wrangler-DhUerFkW.mjs} +10 -15
- package/package.json +22 -23
- package/sandbox.Dockerfile +1 -1
- package/skills/void/SKILL.md +6 -1
- package/skills/void/docs/guide/ai.md +24 -86
- package/skills/void/docs/guide/auth.md +0 -2
- package/skills/void/docs/guide/database/d1.md +7 -7
- package/skills/void/docs/guide/deployment.md +58 -102
- package/skills/void/docs/guide/edge/headers.md +1 -1
- package/skills/void/docs/guide/email/domains.md +5 -1
- package/skills/void/docs/guide/email/sending.md +1 -1
- 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/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 +24 -9
- package/skills/void/docs/guide/platform/development/schema-ci.md +7 -1
- package/skills/void/docs/guide/platform/installation/ci.md +1 -1
- package/skills/void/docs/guide/platform/installation/credentials.md +10 -3
- package/skills/void/docs/guide/platform/installation/domains.md +8 -3
- package/skills/void/docs/guide/platform/installation/first-deployment.md +2 -2
- package/skills/void/docs/guide/platform/installation/maintenance.md +37 -5
- package/skills/void/docs/guide/platform/installation/prerequisites.md +87 -14
- package/skills/void/docs/guide/platform/installation/setup.md +80 -10
- package/skills/void/docs/guide/quickstart.md +37 -80
- package/skills/void/docs/guide/remote-dev.md +1 -1
- package/skills/void/docs/guide/sandboxes.md +36 -46
- 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 +27 -0
- package/skills/void/docs/reference/api.md +1 -1
- package/skills/void/docs/reference/cli/auth.md +4 -3
- package/skills/void/docs/reference/cli/database.md +1 -1
- package/skills/void/docs/reference/cli/deploy.md +21 -1
- package/skills/void/docs/reference/cli/platform-installation.md +42 -27
- package/skills/void/docs/reference/cli/platform-operations.md +4 -8
- package/skills/void/docs/reference/cli/platform-zero-trust.md +14 -0
- package/skills/void/docs/reference/cli/platform.md +5 -0
- package/skills/void/docs/reference/config.md +1 -1
- package/skills/void/docs/reference/resource-inference.md +11 -8
- package/dist/auth-CCjt0hcq.mjs +0 -2
- package/dist/cf-build-output-_0HNWysu.mjs +0 -2
- package/dist/client-Cu7jWiF1.mjs +0 -2
- package/dist/deploy-bjXdFCtn.mjs +0 -2
- package/dist/dist-BuDuKZJv.mjs +0 -2
- package/dist/dist-CTBk70IR.mjs +0 -1310
- package/dist/gen-BVaUUumi.mjs +0 -2
- package/dist/help-DofyZuY7.mjs +0 -2
- package/dist/log-ChfPKsVd.mjs +0 -26
- package/dist/login-DYt_An22.mjs +0 -2
- package/dist/migrate-8_2u55MD.mjs +0 -2
- package/dist/platform-args-D3RXyR6h.mjs +0 -2
- package/dist/platform-management-CnyTdcWX.mjs +0 -2
- package/dist/prepare-cgvDMtSb.mjs +0 -2
- package/dist/project-BuUwfj6f.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/AGENTS_TEMPLATE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
## Void
|
|
2
2
|
|
|
3
3
|
- This project uses [Void](https://void.cloud), a full-stack Vite framework for Cloudflare Workers with file-based API routing, server-rendered pages, and typed backend services.
|
|
4
|
-
- Deploy to your Cloudflare account with `void deploy --platform cloudflare`, or connect to
|
|
4
|
+
- Deploy to your Cloudflare account with `void deploy --platform cloudflare`, or explicitly connect to your team’s Void platform with `void connect <url>` before deploying with `void deploy --platform void`. `void deploy` uses the saved destination.
|
|
5
5
|
- Use Void's CLI and typed APIs for development and infrastructure. Void infers Cloudflare bindings from your imports; use Void commands to manage them.
|
|
6
6
|
- Before working with Void, read the relevant Markdown docs in `node_modules/void/skills/void/docs/`. Start with `guide/quickstart.md` for setup and `reference/cli.md` for commands; consult the other guides and references for any Void feature.
|
package/README.md
CHANGED
|
@@ -1,124 +1,37 @@
|
|
|
1
1
|
# void
|
|
2
2
|
|
|
3
|
-
Vite
|
|
3
|
+
Build and deploy full-stack Vite apps on Cloudflare Workers. Void provides server routes, server-rendered pages, and typed access to databases, storage, and AI.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
`void platform auth login`, then manage users, signup access, projects, and logs.
|
|
7
|
-
Commands show a preview before applying changes and support `--json` for scripts.
|
|
8
|
-
See [Platform Administration](../../docs/guide/platform-administration.md) for a
|
|
9
|
-
walkthrough and the [CLI reference](../../docs/reference/cli/platform.md#operator-commands)
|
|
10
|
-
for every command.
|
|
5
|
+
## Getting Started
|
|
11
6
|
|
|
12
|
-
Use
|
|
13
|
-
Use `void platform config plans` to manage account plans, enforced limits, and the default for new accounts. See [Plans and Limits](../../docs/guide/platform/administration/plans.md).
|
|
14
|
-
Cloudflare Access protection has separate create/connect controls. Users can
|
|
15
|
-
link another enabled login to their account with `void account link`.
|
|
7
|
+
Use Node.js 24.21.0 or later. In an empty directory, run:
|
|
16
8
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- file-based API routes from `routes/`
|
|
20
|
-
- Pages mode from `pages/`
|
|
21
|
-
- typed Drizzle access via `void/db`
|
|
22
|
-
- `crons/` and `queues/`
|
|
23
|
-
- URL redirects, rewrites, and fallbacks (`void.config.ts` / `public/_redirects`, plus `c.rewrite()` from middleware)
|
|
24
|
-
- binding inference for D1, KV, R2, AI, auth, queues, and typed Durable Objects
|
|
25
|
-
- remote bindings for local development
|
|
26
|
-
- one target-aware deploy path for Void-hosted and direct Cloudflare apps
|
|
27
|
-
- automatic Cloudflare provisioning, verified Worker Version activation, and operational commands
|
|
28
|
-
|
|
29
|
-
## Quick Start
|
|
30
|
-
|
|
31
|
-
Install the Void CLI:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
9
|
+
```sh
|
|
34
10
|
npm install -D void
|
|
11
|
+
npx void init
|
|
12
|
+
npm run dev
|
|
35
13
|
```
|
|
36
14
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Init offers to initialize Git and suggests an optional initial commit command. Use `--git` or `--no-git` to choose without the Git prompt. Existing repositories are preserved; Void does not commit automatically.
|
|
40
|
-
|
|
41
|
-
To install a team platform, use `void platform install`. A domain is recommended; the visible workers.dev testing option is also available as `--workers-dev`. Add a domain later with `void platform domain set example.com`, preserving projects, deployments, and API connections. See the [platform setup guide](../../docs/guide/self-hosted-platform.md).
|
|
15
|
+
Choose a UI framework, starter, and deployment target. Then deploy:
|
|
42
16
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Then run `npx void init`. In an empty directory, the full interactive flow can scaffold a starter and configure local project files. It then asks where to deploy: Cloudflare (the default) writes `void.config.ts`, handles secure browser sign-in through Void's bundled tooling, and saves the selected account; Void asks for the API URL of an explicitly connected company platform (`void connect <url>` or `void platform install`). Existing `void.json` and root Wrangler JSON/JSONC files are migrated automatically; commit `void.config.ts` and `void.lock.json` when created. Back up `~/.void/platforms/` after installing a company platform because its owner-only recovery material contains runtime keys that Cloudflare cannot return. The next app step is just `npx void deploy`. Auth-enabled deploys preserve an existing `BETTER_AUTH_SECRET` or create a persistent encrypted secret when missing on either platform. Root `.env` is local-only; production server keys declared in `env.ts` use encrypted remote secret storage and are rejected as plaintext Worker vars. In an existing app, init configures Void in place by adding missing Vite scripts and creating or patching `vite.config.*` with `voidPlugin()`.
|
|
46
|
-
|
|
47
|
-
```ts
|
|
48
|
-
// vite.config.ts
|
|
49
|
-
import { defineConfig } from 'vite';
|
|
50
|
-
import { voidPlugin } from 'void';
|
|
51
|
-
|
|
52
|
-
export default defineConfig({
|
|
53
|
-
plugins: [voidPlugin()],
|
|
54
|
-
});
|
|
17
|
+
```sh
|
|
18
|
+
npx void deploy
|
|
55
19
|
```
|
|
56
20
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
- `voidPlugin()` — Vite integration, routing, pages mode, codegen, migrations, packaging
|
|
60
|
-
- `void prepare` — generate `.void` artifacts for CI, editors, and fresh clones
|
|
61
|
-
- `void info [--json]` — discover persistent resource names before moving definitions
|
|
62
|
-
- `void auth login` — sign in to the project's saved Cloudflare or Void destination
|
|
63
|
-
- `void account login` — platform auth
|
|
64
|
-
- `void connect [url]` — choose Cloudflare or a Void platform, sign in, and save the deployment destination
|
|
65
|
-
- `void platform *` — list, select, inspect, install, recover, repair, upgrade, disable, and safely uninstall a company platform
|
|
66
|
-
- `void deploy` — build and deploy to the saved Cloudflare or Void target
|
|
67
|
-
- `void db *` — local DB and migration commands
|
|
68
|
-
- `void project *` — target-aware status, logs, rollback, managed-project operations, and scoped CI deploy credentials
|
|
69
|
-
- `void secret *` / `void domain *` — target-aware Worker secrets and custom domains
|
|
70
|
-
|
|
71
|
-
Runtime helpers include:
|
|
21
|
+
Void builds your app, provisions its resources, applies migrations, and prints the deployed URL.
|
|
72
22
|
|
|
73
|
-
|
|
74
|
-
- `defineMiddleware`
|
|
75
|
-
- `basicAuth`
|
|
76
|
-
- `defineScheduled`
|
|
77
|
-
- `defineQueue`
|
|
78
|
-
- `void/db`
|
|
79
|
-
- `void/kv`
|
|
80
|
-
- `void/storage`
|
|
81
|
-
- `void/durable`
|
|
82
|
-
- `void/ai`
|
|
83
|
-
- `void/isr`
|
|
84
|
-
- `void/client`
|
|
85
|
-
- `void/auth`
|
|
86
|
-
|
|
87
|
-
## Supported App Shapes
|
|
88
|
-
|
|
89
|
-
- native Void apps (`routes/`, `pages/`, `middleware/`, `crons/`, `queues/`)
|
|
90
|
-
- supported meta-framework deploy targets:
|
|
91
|
-
- TanStack Start
|
|
92
|
-
- React Router
|
|
93
|
-
- vinext App Router and Pages Router
|
|
94
|
-
- SvelteKit
|
|
95
|
-
- Nuxt
|
|
96
|
-
- Analog
|
|
97
|
-
- Astro
|
|
98
|
-
- static and SPA deploys
|
|
99
|
-
- non-Cloudflare server targets (`node`, `bun`, `deno`)
|
|
100
|
-
|
|
101
|
-
Direct Cloudflare deployments also support D1, KV, R2, Queues, Hyperdrive, auth, cron jobs, AI, ISR, typed SQLite Durable Objects, and WebSocket rooms. They upload an immutable Worker Version, probe it before activation (using a 0%-traffic version override when Durable Objects disable preview URLs), and retain version metadata for migration-aware rollback.
|
|
102
|
-
|
|
103
|
-
Durable State and WebSocket definitions accept optional `name` to preserve their resource identity when files move. Run `void info` and pin the displayed name before moving deployed code. See [Durable State](../../docs/guide/durable-state.md#rename-a-file-while-keeping-its-state) and [WebSockets](../../docs/guide/websockets.md#move-a-route-while-keeping-its-state), including how to preserve room instances when renaming route parameters.
|
|
104
|
-
|
|
105
|
-
Self-hosted platform upgrades verify every packaged PostgreSQL migration and require the live Drizzle history to be an exact prefix. Pending SQL is allowed only for an explicitly attested old-version/schema compatibility edge, runs in one transaction, and leaves the old Worker version authoritative until the target runtime passes discovery and health checks.
|
|
106
|
-
|
|
107
|
-
An upgrade that changes the authenticated usage protocol briefly gates application traffic while it verifies the complete Worker set. An interruption leaves the gate closed for the next resumable upgrade instead of enabling an unsigned compatibility path.
|
|
108
|
-
|
|
109
|
-
## Database Model
|
|
110
|
-
|
|
111
|
-
`void/db` is Drizzle-first.
|
|
112
|
-
|
|
113
|
-
- D1 is the default managed database target; development and local database commands share the configured binding ID and persistence directory
|
|
114
|
-
- apps can opt into PostgreSQL or MySQL mode
|
|
115
|
-
- route types, DB types, and queue types are generated into `.void/*.d.ts`
|
|
116
|
-
|
|
117
|
-
Node.js, Bun, and Deno Pages builds include production hydration assets. Deploy `dist/ssr` together with `dist/client`; the server loads its manifest and assets relative to the emitted module.
|
|
23
|
+
Follow the [Quickstart](https://void.cloud/guide/quickstart) for your first app or to add Void to an existing project.
|
|
118
24
|
|
|
119
25
|
## Documentation
|
|
120
26
|
|
|
121
|
-
|
|
27
|
+
- [Introduction](https://void.cloud/guide/)
|
|
28
|
+
- [Server routing](https://void.cloud/guide/server-routing) and [Pages routing](https://void.cloud/guide/pages-routing/overview)
|
|
29
|
+
- [Database](https://void.cloud/guide/database) and [type safety](https://void.cloud/guide/type-safety)
|
|
30
|
+
- [Deployment](https://void.cloud/guide/deployment)
|
|
31
|
+
- [Framework integrations](https://void.cloud/integrations/frameworks/overview)
|
|
32
|
+
- [API](https://void.cloud/reference/api) and [CLI](https://void.cloud/reference/cli) reference
|
|
33
|
+
|
|
34
|
+
To share a deployment platform with your team, see [Install a Void Platform](https://void.cloud/guide/self-hosted-platform).
|
|
122
35
|
|
|
123
36
|
## License
|
|
124
37
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { c as getToken,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as runLoginCommand } from "./login-
|
|
1
|
+
import { c as getToken, f as removeToken } from "./auth-7wuZ5ob8.mjs";
|
|
2
|
+
import { L as log } from "./prompts-6OSVA7DJ.mjs";
|
|
3
|
+
import { r as PlatformClient } from "./client-RsPo8wsP.mjs";
|
|
4
|
+
import { n as runLoginCommand } from "./login-pWQHYVu2.mjs";
|
|
5
5
|
import { execSync } from "node:child_process";
|
|
6
6
|
//#region src/cli/account-cmd.ts
|
|
7
7
|
async function runAccountCommand(root, args) {
|
|
8
8
|
switch (args.subcommand) {
|
|
9
9
|
case "login": return runLoginCommand(root);
|
|
10
|
-
case "link": return import("./auth-link-
|
|
10
|
+
case "link": return import("./auth-link-Z6E5DYvM.mjs").then(({ runAuthLink }) => runAuthLink(root, args.connectionId));
|
|
11
11
|
case "logout":
|
|
12
12
|
if (removeToken(root)) log.success("Logged out.");
|
|
13
13
|
else log.info("Not logged in.");
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { a as join } from "./dist-BVqXeR_h.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as
|
|
5
|
-
import {
|
|
2
|
+
import { C as writeKeyringPassword, S as readKeyringPassword, c as platformCredentialAccount, o as listPlatformConnections, r as getActivePlatformConnection, s as normalizePlatformApiUrl, x as deleteKeyringPassword } from "./platform-registry-KfNEF84O.mjs";
|
|
3
|
+
import { i as readProjectPlatformUrl, r as readProjectConfig } from "./project-BkbfDs0V.mjs";
|
|
4
|
+
import { t as cfAccessHeaders } from "./cf-access-TWNzXltp.mjs";
|
|
5
|
+
import { t as ensureCloudflaredToken } from "./cf-access-AHKBzmuu.mjs";
|
|
6
6
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { createHash, randomBytes } from "node:crypto";
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
|
-
//#region src/shared/proxy.ts
|
|
10
|
-
const DEFAULT_PROXY_URL = "https://proxy.void.cloud";
|
|
11
|
-
const STAGING_PROXY_URL = "https://proxy.staging.void.cloud";
|
|
12
|
-
//#endregion
|
|
13
9
|
//#region src/cli/auth.ts
|
|
14
10
|
const CONFIG_DIR = join(homedir(), ".void");
|
|
15
11
|
const CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
@@ -50,19 +46,22 @@ function readOriginScopedToken(apiUrl, config) {
|
|
|
50
46
|
}
|
|
51
47
|
return fileToken;
|
|
52
48
|
}
|
|
53
|
-
function
|
|
54
|
-
|
|
49
|
+
function connectedPlatform(apiUrl) {
|
|
50
|
+
if (!apiUrl) throw new Error("platform: No Void platform connected. Run `void connect <url>` first.");
|
|
51
|
+
const origin = normalizePlatformApiUrl(apiUrl);
|
|
52
|
+
const connection = listPlatformConnections().find((entry) => entry.apiUrl === origin);
|
|
53
|
+
if (!connection) throw new Error(`platform: No connection to ${origin}. Run \`void connect ${origin}\` first.`);
|
|
54
|
+
return connection;
|
|
55
55
|
}
|
|
56
56
|
function getSiteDomain(root = process.cwd()) {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return domain;
|
|
57
|
+
const connection = connectedPlatform(getApiUrl(root));
|
|
58
|
+
if (!connection.applicationDomain) throw new Error(`platform: Missing application domain. Run \`void connect ${connection.apiUrl}\` to refresh the connection.`);
|
|
59
|
+
return connection.applicationDomain;
|
|
61
60
|
}
|
|
62
61
|
/**
|
|
63
62
|
* Read the deploy token.
|
|
64
63
|
* Priority: origin-bound VOID_TOKEN > system keychain > migrated config.
|
|
65
|
-
*
|
|
64
|
+
* Environment tokens must name their recipient with VOID_API_URL.
|
|
66
65
|
*/
|
|
67
66
|
function getToken(root = process.cwd()) {
|
|
68
67
|
const envToken = process.env.VOID_TOKEN;
|
|
@@ -79,7 +78,7 @@ function getToken(root = process.cwd()) {
|
|
|
79
78
|
/** Account actions follow the selected connection, independently of application metadata. */
|
|
80
79
|
function getAccountCredential() {
|
|
81
80
|
const config = readConfig();
|
|
82
|
-
const apiUrl =
|
|
81
|
+
const apiUrl = connectedPlatform(process.env.VOID_API_URL || getActivePlatformConnection()?.apiUrl).apiUrl;
|
|
83
82
|
return {
|
|
84
83
|
apiUrl,
|
|
85
84
|
token: readTokenForOrigin(apiUrl, config)
|
|
@@ -88,7 +87,8 @@ function getAccountCredential() {
|
|
|
88
87
|
function readTokenForOrigin(apiUrl, config) {
|
|
89
88
|
const envToken = process.env.VOID_TOKEN;
|
|
90
89
|
if (envToken) {
|
|
91
|
-
if (
|
|
90
|
+
if (!process.env.VOID_API_URL) throw new Error("auth: Set VOID_API_URL alongside VOID_TOKEN to identify the connected platform that issued it.");
|
|
91
|
+
if (apiUrl !== normalizePlatformApiUrl(process.env.VOID_API_URL)) throw new Error(`auth: VOID_TOKEN is not bound to ${apiUrl}. Set VOID_API_URL to this platform's URL with its matching token, or unset VOID_TOKEN to use the saved login.`);
|
|
92
92
|
return envToken;
|
|
93
93
|
}
|
|
94
94
|
return readOriginScopedToken(apiUrl, config);
|
|
@@ -126,8 +126,6 @@ function removeToken(root = process.cwd()) {
|
|
|
126
126
|
} catch {}
|
|
127
127
|
return removed;
|
|
128
128
|
}
|
|
129
|
-
const DEFAULT_API_URL = VOID_CLOUD_PLATFORM.apiUrl;
|
|
130
|
-
const STAGING_API_URL = VOID_CLOUD_STAGING_PLATFORM.apiUrl;
|
|
131
129
|
function base64Url(buffer) {
|
|
132
130
|
return buffer.toString("base64").replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
|
|
133
131
|
}
|
|
@@ -163,40 +161,15 @@ async function exchangeLoginCode(apiUrl, code, state, codeVerifier) {
|
|
|
163
161
|
if (!body || typeof body !== "object" || !("token" in body) || typeof body.token !== "string" || body.token.length === 0) throw new Error("auth: Login code exchange did not return a token.");
|
|
164
162
|
return body.token;
|
|
165
163
|
}
|
|
166
|
-
/**
|
|
167
|
-
* Read the API URL from environment or config file.
|
|
168
|
-
* Priority: VOID_API_URL env var > ~/.void/config.json > default
|
|
169
|
-
*/
|
|
164
|
+
/** Environment and project selections must refer to a verified local connection. */
|
|
170
165
|
function getApiUrl(root = process.cwd()) {
|
|
171
|
-
if (process.env.VOID_API_URL) return normalizePlatformApiUrl(process.env.VOID_API_URL);
|
|
172
|
-
if (isStagingMode(root)) return STAGING_API_URL;
|
|
173
166
|
const projectApiUrl = readProjectPlatformUrl(root);
|
|
174
|
-
if (projectApiUrl)
|
|
175
|
-
|
|
176
|
-
if (listPlatformConnections().some((connection) => connection.apiUrl === projectApiUrl)) return projectApiUrl;
|
|
177
|
-
throw new Error(`platform: Project metadata selected unverified platform ${projectApiUrl}. Connect to it explicitly with \`void connect ${projectApiUrl}\` before forwarding credentials.`);
|
|
178
|
-
}
|
|
179
|
-
const config = readConfig();
|
|
180
|
-
const legacySelection = readLegacyHostedPlatformSelection();
|
|
181
|
-
let apiUrl = (isLegacyVoidCloudProject(root) ? DEFAULT_API_URL : void 0) ?? getActivePlatformConnection()?.apiUrl ?? config.api ?? legacySelection?.apiUrl;
|
|
182
|
-
apiUrl ??= process.env.VOID_TOKEN ? DEFAULT_API_URL : void 0;
|
|
183
|
-
if (!apiUrl) {
|
|
184
|
-
apiUrl = keyringGet("token") ? DEFAULT_API_URL : keyringGet("stagingToken") ? STAGING_API_URL : void 0;
|
|
185
|
-
if (apiUrl) try {
|
|
186
|
-
writeConfig({
|
|
187
|
-
...config,
|
|
188
|
-
api: apiUrl
|
|
189
|
-
});
|
|
190
|
-
} catch {}
|
|
191
|
-
}
|
|
192
|
-
if (!apiUrl) throw new Error("platform: No Void platform selected. Run `void connect <url>` or `void platform install` first.");
|
|
193
|
-
return normalizePlatformApiUrl(apiUrl);
|
|
167
|
+
if (readProjectConfig(root) && !projectApiUrl) throw new Error("platform: This project link has no platform URL. Run `void connect <url>`, then `void project link` to choose its destination.");
|
|
168
|
+
return connectedPlatform(process.env.VOID_API_URL || projectApiUrl || getActivePlatformConnection()?.apiUrl).apiUrl;
|
|
194
169
|
}
|
|
195
170
|
function getProxyUrl(root = process.cwd()) {
|
|
171
|
+
const apiUrl = getApiUrl(root);
|
|
196
172
|
if (process.env.VOID_PROXY_URL) return normalizePlatformApiUrl(process.env.VOID_PROXY_URL);
|
|
197
|
-
const apiUrl = normalizePlatformApiUrl(getApiUrl(root));
|
|
198
|
-
if (apiUrl === STAGING_API_URL) return STAGING_PROXY_URL;
|
|
199
|
-
if (apiUrl === DEFAULT_API_URL) return DEFAULT_PROXY_URL;
|
|
200
173
|
const proxyUrl = listPlatformConnections().find((connection) => connection.apiUrl === apiUrl)?.proxyUrl;
|
|
201
174
|
if (proxyUrl === null || proxyUrl === void 0) throw new Error(`platform: No verified proxy is registered for ${apiUrl}. Reconnect with \`void connect ${apiUrl}\` or set VOID_PROXY_URL explicitly.`);
|
|
202
175
|
return proxyUrl;
|
|
@@ -369,4 +342,4 @@ async function runPlatformLogin(origin, provider = "github", onUrl) {
|
|
|
369
342
|
});
|
|
370
343
|
}
|
|
371
344
|
//#endregion
|
|
372
|
-
export {
|
|
345
|
+
export { getApiUrl as a, getToken as c, readPlatformToken as d, removeToken as f, saveToken as g, savePlatformToken as h, getAccountCredential as i, getTokenSource as l, runPlatformLogin as m, createCodeChallenge as n, getProxyUrl as o, runLogin as p, createCodeVerifier as r, getSiteDomain as s, awaitBrowserCallback as t, openBrowser as u };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { a as getApiUrl, c as getToken,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { r as selectPlatformLoginMethod } from "./login-
|
|
5
|
-
import { t as discoverPlatform } from "./platform-cmd-
|
|
1
|
+
import { a as getApiUrl, c as getToken, h as savePlatformToken, m as runPlatformLogin, u as openBrowser } from "./auth-7wuZ5ob8.mjs";
|
|
2
|
+
import { L as log } from "./prompts-6OSVA7DJ.mjs";
|
|
3
|
+
import { r as PlatformClient } from "./client-RsPo8wsP.mjs";
|
|
4
|
+
import { r as selectPlatformLoginMethod } from "./login-pWQHYVu2.mjs";
|
|
5
|
+
import { t as discoverPlatform } from "./platform-cmd-D7vSWMvV.mjs";
|
|
6
6
|
import { execFile } from "node:child_process";
|
|
7
7
|
//#region src/cli/auth-link.ts
|
|
8
8
|
async function runAuthLink(root, connectionId) {
|
|
@@ -13,7 +13,6 @@ async function runAuthLink(root, connectionId) {
|
|
|
13
13
|
if (!platform.authentication) throw new Error("auth: This platform must be upgraded before linking login methods.");
|
|
14
14
|
const target = await selectPlatformLoginMethod(platform, connectionId);
|
|
15
15
|
const existing = await new PlatformClient(token, apiUrl).whoami();
|
|
16
|
-
if (!existing.id) throw new Error("auth: This platform does not support account linking.");
|
|
17
16
|
log.info(`Sign in again to ${existing.login} using an already linked login method.`);
|
|
18
17
|
const source = await selectPlatformLoginMethod(platform);
|
|
19
18
|
const freshToken = await runPlatformLogin(apiUrl, source.id, (url) => log.info(`Sign in: ${url}`));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { o as listPlatformConnections } from "./platform-registry-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { o as listPlatformConnections } from "./platform-registry-KfNEF84O.mjs";
|
|
2
|
+
import { n as readDeploymentPlatform } from "./project-BkbfDs0V.mjs";
|
|
3
|
+
import { K as select, tt as isCancel } from "./prompts-6OSVA7DJ.mjs";
|
|
4
4
|
//#region src/cli/auth-router.ts
|
|
5
5
|
async function chooseDestination(root, args, interactive) {
|
|
6
6
|
const saved = readDeploymentPlatform(root);
|
|
@@ -37,7 +37,7 @@ async function chooseDestination(root, args, interactive) {
|
|
|
37
37
|
}
|
|
38
38
|
async function runAuthRouter(root, args, interactive = Boolean(process.stdin.isTTY)) {
|
|
39
39
|
if (args.subcommand === "link") {
|
|
40
|
-
const { runAccountCommand } = await import("./account-cmd-
|
|
40
|
+
const { runAccountCommand } = await import("./account-cmd-DcR1ywt8.mjs");
|
|
41
41
|
await runAccountCommand(root, {
|
|
42
42
|
subcommand: "link",
|
|
43
43
|
...args.connectionId ? { connectionId: args.connectionId } : {}
|
|
@@ -45,17 +45,17 @@ async function runAuthRouter(root, args, interactive = Boolean(process.stdin.isT
|
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
47
|
if (args.subcommand === "token") {
|
|
48
|
-
const { runAccountCommand } = await import("./account-cmd-
|
|
48
|
+
const { runAccountCommand } = await import("./account-cmd-DcR1ywt8.mjs");
|
|
49
49
|
await runAccountCommand(root, { subcommand: "token" });
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
const destination = await chooseDestination(root, args, interactive);
|
|
53
53
|
if (destination.platform === "cloudflare") {
|
|
54
|
-
const { runCloudflareCommand } = await import("./cloudflare-cmd-
|
|
54
|
+
const { runCloudflareCommand } = await import("./cloudflare-cmd-bhwCxAN6.mjs");
|
|
55
55
|
await runCloudflareCommand(root, { subcommand: args.subcommand === "whoami" || args.subcommand === "status" ? "status" : args.subcommand });
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
-
const { runAccountCommand } = await import("./account-cmd-
|
|
58
|
+
const { runAccountCommand } = await import("./account-cmd-DcR1ywt8.mjs");
|
|
59
59
|
const subcommand = args.subcommand === "status" ? "whoami" : args.subcommand;
|
|
60
60
|
if (!destination.apiUrl) {
|
|
61
61
|
await runAccountCommand(root, { subcommand });
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as
|
|
5
|
-
import {
|
|
1
|
+
import { r as readProjectConfig } from "./project-BkbfDs0V.mjs";
|
|
2
|
+
import { c as getToken } from "./auth-7wuZ5ob8.mjs";
|
|
3
|
+
import { H as outro, L as log } from "./prompts-6OSVA7DJ.mjs";
|
|
4
|
+
import { n as PlatformApiError, r as PlatformClient } from "./client-RsPo8wsP.mjs";
|
|
5
|
+
import { c as import_picocolors, i as dim } from "./output-BBsUwdyT.mjs";
|
|
6
6
|
import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-BG5ORGID.mjs";
|
|
7
7
|
import { appendFileSync, writeFileSync } from "node:fs";
|
|
8
8
|
//#region src/cli/build-cmd.ts
|
|
@@ -10,7 +10,7 @@ const POLL_MS = 1e3;
|
|
|
10
10
|
const BUILD_LOG_DRAIN_TIMEOUT_MS = 12e4;
|
|
11
11
|
function isBuildLogComplete(page) {
|
|
12
12
|
if (!page.terminal) return false;
|
|
13
|
-
if (page.logsComplete === null
|
|
13
|
+
if (page.logsComplete === null) throw new Error("This platform cannot confirm that the final build logs were captured. Ask its administrator to upgrade the platform runtime, or read the retained logs without --follow.");
|
|
14
14
|
return page.logsComplete === true;
|
|
15
15
|
}
|
|
16
16
|
function sleep(ms) {
|
|
@@ -74,7 +74,6 @@ async function runBuildCommand(root, args) {
|
|
|
74
74
|
}
|
|
75
75
|
async function runBuildLogsCommand(root, args) {
|
|
76
76
|
console.log();
|
|
77
|
-
intro(cliTitle("build logs"));
|
|
78
77
|
const token = getToken(root);
|
|
79
78
|
if (!token) {
|
|
80
79
|
log.error("Not logged in. Run `void account login` first.");
|
|
@@ -128,7 +127,7 @@ async function runBuildLogsCommand(root, args) {
|
|
|
128
127
|
await sleep(POLL_MS);
|
|
129
128
|
}
|
|
130
129
|
if (first.external) {
|
|
131
|
-
log.message(`This build ran on GitHub Actions. View logs:\n${import_picocolors.default.
|
|
130
|
+
log.message(`This build ran on GitHub Actions. View logs:\n${import_picocolors.default.blue(first.external)}`);
|
|
132
131
|
return;
|
|
133
132
|
}
|
|
134
133
|
if (args.output) writeFileSync(args.output, "");
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { r as readProjectConfig } from "./project-BkbfDs0V.mjs";
|
|
2
|
+
import { c as getToken } from "./auth-7wuZ5ob8.mjs";
|
|
3
|
+
import { H as outro, L as log } from "./prompts-6OSVA7DJ.mjs";
|
|
4
|
+
import { r as PlatformClient } from "./client-RsPo8wsP.mjs";
|
|
5
|
+
import { i as dim, o as formatCount, r as createSpinner } from "./output-BBsUwdyT.mjs";
|
|
6
6
|
import { r as resolveProjectBySlug, t as getRequestedProjectSlug } from "./resolve-project-BG5ORGID.mjs";
|
|
7
7
|
//#region src/cli/cache.ts
|
|
8
8
|
async function runPurgeCacheCommand(root, projectSlug) {
|
|
9
9
|
console.log();
|
|
10
|
-
intro(cliTitle("project purge-cache"));
|
|
11
10
|
const token = getToken(root);
|
|
12
11
|
if (!token) {
|
|
13
12
|
log.error("Not logged in. Run `void account login` first.");
|
|
@@ -39,7 +38,7 @@ async function runPurgeCacheCommand(root, projectSlug) {
|
|
|
39
38
|
try {
|
|
40
39
|
const result = await client.purgeCache(projectId);
|
|
41
40
|
s.stop("Cache purged.");
|
|
42
|
-
log.success(`Purged ${result.purged
|
|
41
|
+
log.success(`Purged ${formatCount(result.purged, "cached page")}.`);
|
|
43
42
|
} catch (err) {
|
|
44
43
|
s.stop("Cache purge failed.");
|
|
45
44
|
log.error(err instanceof Error ? err.message : String(err));
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { r as cliTitle } from "./output-Dm_A4Tbv.mjs";
|
|
1
|
+
import { r as readProjectConfig } from "./project-BkbfDs0V.mjs";
|
|
2
|
+
import { c as getToken } from "./auth-7wuZ5ob8.mjs";
|
|
3
|
+
import { A as confirm, H as outro, L as log, tt as isCancel } from "./prompts-6OSVA7DJ.mjs";
|
|
4
|
+
import { r as PlatformClient } from "./client-RsPo8wsP.mjs";
|
|
6
5
|
//#region src/cli/cancel-deploy.ts
|
|
7
6
|
const ACTIVE_STATUSES = /* @__PURE__ */ new Set([
|
|
8
7
|
"pending",
|
|
@@ -12,7 +11,6 @@ const ACTIVE_STATUSES = /* @__PURE__ */ new Set([
|
|
|
12
11
|
]);
|
|
13
12
|
async function runCancelDeployCommand(root, deployId) {
|
|
14
13
|
console.log();
|
|
15
|
-
intro(cliTitle("project cancel"));
|
|
16
14
|
const token = getToken(root);
|
|
17
15
|
if (!token) {
|
|
18
16
|
log.error("Not logged in. Run `void account login` first.");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { C as writeKeyringPassword, S as readKeyringPassword, c as platformCredentialAccount, s as normalizePlatformApiUrl } from "./platform-registry-KfNEF84O.mjs";
|
|
2
|
+
import { t as cfAccessHeaders } from "./cf-access-TWNzXltp.mjs";
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
//#region src/cli/cf-access.ts
|
|
5
5
|
const ACCESS_KEYRING_SERVICE = "dev.void.cli.access";
|
|
@@ -106,53 +106,9 @@ function ensurePlatformAccessToken(apiUrl, challenged = false, required = false,
|
|
|
106
106
|
keyringTokens.set(origin, token);
|
|
107
107
|
writeKeyringPassword(ACCESS_KEYRING_SERVICE, account, token);
|
|
108
108
|
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* If the CLI is about to talk to a Cloudflare-Access-gated staging host,
|
|
112
|
-
* probe the locally-installed `cloudflared` binary for a cached user JWT
|
|
113
|
-
* and export it as `CF_ACCESS_TOKEN`. On interactive shells with no cached
|
|
114
|
-
* token, open a browser login flow to populate the cache, then re-read it.
|
|
115
|
-
*
|
|
116
|
-
* Cached per-host so that an early non-gated call (e.g. prod) does not
|
|
117
|
-
* permanently disable the probe for a later gated call (e.g. staging) in
|
|
118
|
-
* the same process. Noop when:
|
|
119
|
-
* - a service-token pair is already set (CI path)
|
|
120
|
-
* - `CF_ACCESS_TOKEN` is already set (manual override or prior probe)
|
|
121
|
-
* - the target host is not gated
|
|
122
|
-
* - `cloudflared` is not installed
|
|
123
|
-
*/
|
|
109
|
+
/** Restore only credentials scoped to this explicitly selected platform origin. */
|
|
124
110
|
function ensureCloudflaredToken(apiUrl) {
|
|
125
|
-
|
|
126
|
-
ensurePlatformAccessToken(apiUrl);
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
if (process.env.CF_ACCESS_CLIENT_ID && process.env.CF_ACCESS_CLIENT_SECRET) return;
|
|
130
|
-
if (process.env.CF_ACCESS_TOKEN) return;
|
|
131
|
-
if (!isVoidAccessGatedUrl(apiUrl)) return;
|
|
132
|
-
const host = new URL(apiUrl).hostname;
|
|
133
|
-
if (probedHosts.has(host)) return;
|
|
134
|
-
probedHosts.add(host);
|
|
135
|
-
let token = runCloudflared([
|
|
136
|
-
"access",
|
|
137
|
-
"token",
|
|
138
|
-
`-app=${apiUrl}`
|
|
139
|
-
]);
|
|
140
|
-
if (!token && process.stdin.isTTY && process.stdout.isTTY) {
|
|
141
|
-
runCloudflared([
|
|
142
|
-
"access",
|
|
143
|
-
"login",
|
|
144
|
-
apiUrl
|
|
145
|
-
], {
|
|
146
|
-
inherit: true,
|
|
147
|
-
timeoutMs: 12e4
|
|
148
|
-
});
|
|
149
|
-
token = runCloudflared([
|
|
150
|
-
"access",
|
|
151
|
-
"token",
|
|
152
|
-
`-app=${apiUrl}`
|
|
153
|
-
]);
|
|
154
|
-
}
|
|
155
|
-
if (token) process.env.CF_ACCESS_TOKEN = token;
|
|
111
|
+
ensurePlatformAccessToken(apiUrl);
|
|
156
112
|
}
|
|
157
113
|
function runCloudflared(args, opts) {
|
|
158
114
|
try {
|
|
@@ -7,14 +7,6 @@
|
|
|
7
7
|
* 2. User JWT (`CF_ACCESS_TOKEN`) — dev path, typically populated via `cloudflared access token`
|
|
8
8
|
* 3. No headers — prod, or unprotected hostnames
|
|
9
9
|
*/
|
|
10
|
-
function isVoidAccessGatedUrl(targetUrl) {
|
|
11
|
-
try {
|
|
12
|
-
const url = new URL(targetUrl);
|
|
13
|
-
return url.protocol === "https:" && (url.hostname.endsWith(".staging.void.cloud") || url.hostname.endsWith(".staging.void.app"));
|
|
14
|
-
} catch {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
10
|
function accessHeaders(env) {
|
|
19
11
|
const id = env.CF_ACCESS_CLIENT_ID;
|
|
20
12
|
const secret = env.CF_ACCESS_CLIENT_SECRET;
|
|
@@ -26,7 +18,7 @@ function accessHeaders(env) {
|
|
|
26
18
|
if (typeof token === "string" && token.length > 0) return { "cf-access-token": token };
|
|
27
19
|
return {};
|
|
28
20
|
}
|
|
29
|
-
/** Attach
|
|
21
|
+
/** Attach Access credentials only to their explicitly scoped origin. */
|
|
30
22
|
function cfAccessHeaders(env, targetUrl) {
|
|
31
23
|
let origin;
|
|
32
24
|
try {
|
|
@@ -52,7 +44,7 @@ function cfAccessHeaders(env, targetUrl) {
|
|
|
52
44
|
} catch {
|
|
53
45
|
return {};
|
|
54
46
|
}
|
|
55
|
-
return
|
|
47
|
+
return {};
|
|
56
48
|
}
|
|
57
49
|
/**
|
|
58
50
|
* Capture credentials for a Cloudflare Worker readiness request whose target
|
|
@@ -72,4 +64,4 @@ function scopedAccessCredentials(env, targetUrl) {
|
|
|
72
64
|
} : { CF_ACCESS_TOKEN: headers["cf-access-token"] } });
|
|
73
65
|
}
|
|
74
66
|
//#endregion
|
|
75
|
-
export {
|
|
67
|
+
export { scopedAccessCredentials as n, trustedCloudflareWorkerAccessHeaders as r, cfAccessHeaders as t };
|