void 0.20.0 → 0.20.2
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 +5 -1
- package/dist/{auth-W9WII-mN.mjs → auth-DPl6kck4.mjs} +46 -26
- package/dist/{auth-cmd-CYVhSNFy.mjs → auth-cmd-gniL2fNt.mjs} +5 -4
- package/dist/auth-link-NZdjCmSc.mjs +28 -0
- package/dist/{build-cmd-CkVD1uOh.mjs → build-cmd-sI18tX_O.mjs} +3 -3
- package/dist/{cache-QcUfR-ff.mjs → cache-IHn5MwBC.mjs} +3 -3
- package/dist/{cancel-deploy-DsvWKFTe.mjs → cancel-deploy-C5qTOdLi.mjs} +3 -3
- package/dist/cf-access-DRsQRe6k.mjs +75 -0
- package/dist/cli/cli.mjs +364 -1883
- package/dist/cli/env-schema-probe.mjs +11 -2
- package/dist/{client-CyCHWSO_.mjs → client-dHfSJvAN.mjs} +336 -58
- package/dist/{cloudflare-auth-DRkGe7-s.mjs → cloudflare-auth-6M5llVPC.mjs} +53 -6
- package/dist/{cloudflare-cmd-D3ME2GAe.mjs → cloudflare-cmd-4RPGN3KB.mjs} +2 -2
- package/dist/{cloudflare-connect-BivMefMA.mjs → cloudflare-connect-t1UU5svD.mjs} +2 -2
- package/dist/{cloudflare-operations-CPTpRW6d.mjs → cloudflare-operations-BzWnlC1_.mjs} +1 -1
- package/dist/{config-BQFq7QvD.mjs → config-uNGuFsI2.mjs} +1 -1
- package/dist/{connect-D9Yr-T5f.mjs → connect-Bfk31O_8.mjs} +6 -6
- package/dist/{create-project-DMV-csEm.mjs → create-project-Bk9Z0-Jg.mjs} +6 -5
- package/dist/{db-BxoUWL0F.mjs → db-BkRoptAt.mjs} +75 -48
- package/dist/{delete-iJOqxBz1.mjs → delete-DouASY9P.mjs} +3 -3
- package/dist/{deploy-CcDoeBIf.mjs → deploy-DTaWUS1S.mjs} +137 -128
- package/dist/{dev-inbox-DkgRWLkW.mjs → dev-inbox-P0u4tM8Y.mjs} +1 -1
- package/dist/{domain-gu_iaHmn.mjs → domain-1RhhOVrC.mjs} +4 -4
- package/dist/email-C-lGh51B.mjs +795 -0
- package/dist/{env-D4Emu-M_.mjs → env-DBKmK4vc.mjs} +1 -0
- package/dist/{env-DmU2To0C.mjs → env-DJHsPE7Z.mjs} +5 -5
- package/dist/{env-validation-ENpMy6Ez.mjs → env-validation-CF6KvTRf.mjs} +3 -1
- package/dist/{gen-BKw6qHIg.mjs → gen-B_wPnVTK.mjs} +3 -3
- package/dist/generate-RTK8_kK1.mjs +47 -0
- package/dist/{github-cmd-DJS5Ab-H.mjs → github-cmd-PW7ZnWTp.mjs} +3 -3
- package/dist/{headers-D8QfRX9Y.mjs → headers-BAHwgHdW.mjs} +1 -1
- package/dist/help-CwOX-zmI.mjs +2216 -0
- package/dist/{inbound-BJ70in1n.d.mts → inbound-CH5Mksyy.d.mts} +37 -42
- package/dist/{inbound-CNKxb3FY.mjs → inbound-aVHEUhKo.mjs} +143 -101
- package/dist/index.mjs +69 -30
- package/dist/{init-Dx5cgKqK.mjs → init-BWZ7q5Z4.mjs} +11 -11
- package/dist/{link-D_rm5sRH.mjs → link-Rmvu2Wl_.mjs} +4 -4
- package/dist/{list-M8XShti7.mjs → list-DEE2S6mY.mjs} +4 -4
- package/dist/{local-d1-BE8KBbMy.mjs → local-d1-D2I6Ox5F.mjs} +1 -1
- package/dist/{login-C8-UuLnp.mjs → login-Uvferzmm.mjs} +28 -10
- package/dist/{logs-DwFU7dMW.mjs → logs-27FenuiC.mjs} +4 -4
- package/dist/{mime-BJD7d_qL.mjs → mime-D5Nmdzf7.mjs} +23 -9
- package/dist/{node-BkaXcpAc.mjs → node-Ez5KW5rn.mjs} +3 -3
- package/dist/operator-auth-B3e08unv.mjs +52 -0
- package/dist/operator-client-LUZnlnYk.mjs +82 -0
- package/dist/{operator-cmd-DYWRbWUA.mjs → operator-cmd-CjOTmAYE.mjs} +35 -55
- package/dist/{output-tFQLLj26.mjs → output-B0cfNSx5.mjs} +316 -2
- package/dist/pages/index.mjs +2 -2
- package/dist/platform-auth-config-DrbQXXiW.mjs +368 -0
- package/dist/platform-auth-protection-Bhtvp0B_.mjs +219 -0
- package/dist/platform-auth-recovery-CeOKGVeJ.mjs +310 -0
- package/dist/{platform-cmd-BEOVv1PN.mjs → platform-cmd-BFhieCdV.mjs} +16 -6
- package/dist/{platform-domain-BszUfiS8.mjs → platform-domain-C74PULqV.mjs} +4 -4
- package/dist/{platform-lifecycle-CjSr6xf0.mjs → platform-lifecycle-BwAIgz-t.mjs} +1667 -191
- package/dist/{platform-management-W30iCaTL.mjs → platform-management-COogu_Se.mjs} +33 -7
- package/dist/{platform-recovery-pHHv4ZSg.mjs → platform-recovery-ewqLefp1.mjs} +6 -5
- package/dist/{prepare-CBetXvsN.mjs → prepare-CtDJjoOj.mjs} +2 -2
- package/dist/{prepare-BfJvFUtJ.mjs → prepare-blNRQvQl.mjs} +2 -2
- package/dist/prerender-render.d.mts +11 -0
- package/dist/prerender-render.mjs +111 -0
- package/dist/{project-cmd-DCpk1cDt.mjs → project-cmd-DmZK9Hxf.mjs} +32 -14
- package/dist/project-team-D8jOJMUJ.mjs +130 -0
- package/dist/project-token-DA34bf-C.mjs +75 -0
- package/dist/{provision-Blnstcm2.mjs → provision-CSJOjjQk.mjs} +2 -0
- package/dist/{requests-Dn8Vheh1.mjs → requests-CUExwGQQ.mjs} +3 -3
- package/dist/{rollback-CtlPXEBi.mjs → rollback-CDNGU1gr.mjs} +4 -4
- package/dist/{runner-mysql-CgRFl3s6.mjs → runner-mysql-7BPUNGmL.mjs} +1 -1
- package/dist/{runner-pg-DCkWPsWS.mjs → runner-pg-BkEza-dX.mjs} +1 -1
- package/dist/runtime/ai.mjs +3 -2
- package/dist/runtime/email/testing.d.mts +1 -1
- package/dist/runtime/email/testing.mjs +3 -3
- package/dist/runtime/email-protocol.d.mts +15 -0
- package/dist/runtime/email-protocol.mjs +70 -0
- package/dist/runtime/email.d.mts +2 -2
- package/dist/runtime/email.mjs +189 -96
- package/dist/runtime/remote/index.mjs +5 -3
- package/dist/{secret-BqTxGqki.mjs → secret-Bzzi2e9E.mjs} +5 -5
- package/dist/{skills-Q46GZMO-.mjs → skills-C0RvGjeE.mjs} +1 -1
- package/dist/sqlite-validation-BzKMWnO4.mjs +25 -0
- package/dist/{subcommand-prompt-WfySCQ7S.mjs → subcommand-prompt-Bmyn5Rlc.mjs} +1 -1
- package/dist/{validate-Bihr8WBi.mjs → validate-tBBN_dXH.mjs} +1 -0
- package/package.json +12 -7
- package/skills/void/SKILL.md +35 -4
- package/skills/void/docs/guide/deployment.md +2 -0
- package/skills/void/docs/guide/email.md +121 -98
- package/skills/void/docs/guide/platform-administration.md +214 -2
- package/skills/void/docs/guide/platform-development.md +93 -2
- package/skills/void/docs/guide/project-collaboration.md +94 -0
- package/skills/void/docs/guide/self-hosted-platform.md +184 -30
- package/skills/void/docs/reference/cli.md +294 -15
- package/dist/cf-access-AJ1ehiFR.mjs +0 -42
- package/dist/cf-access-DsSsZUPr.mjs +0 -67
- package/dist/email-r6DHJyAB.mjs +0 -262
|
@@ -41,11 +41,12 @@ Use this page as a command reference. If you are setting up a project for the fi
|
|
|
41
41
|
| `void build logs` | Stream, tail, or download build logs |
|
|
42
42
|
| `void email status` | Show email readiness on your own Cloudflare account (`--platform cloudflare`) |
|
|
43
43
|
| `void email setup` | Set email up on your own Cloudflare account, without deploying |
|
|
44
|
-
| `void email usage` | Show monthly
|
|
44
|
+
| `void email usage` | Show monthly recipient attempts, inbound receipts, and quota |
|
|
45
45
|
| `void email logs` | Show recent email delivery activity |
|
|
46
46
|
| `void email destinations` | List verified recipient addresses |
|
|
47
47
|
| `void email allow <address>` | Add a recipient and send a verification email |
|
|
48
48
|
| `void email disallow <address>` | Remove a recipient from the allowlist |
|
|
49
|
+
| `void email domain` | Send and receive at your own domain on a Cloudflare zone |
|
|
49
50
|
| `void init` | Setup wizard for new or existing projects |
|
|
50
51
|
|
|
51
52
|
## Binary Invocation
|
|
@@ -165,7 +166,7 @@ In a non-interactive shell, supply a URL or explicit target. Cloudflare requires
|
|
|
165
166
|
|
|
166
167
|
### `void auth login`
|
|
167
168
|
|
|
168
|
-
|
|
169
|
+
Browser login through one of the platform's currently enabled methods. The token is saved in the operating-system keychain, scoped to the platform origin. Login fails closed when no keychain is available instead of writing the token to a plaintext file; headless environments use `VOID_TOKEN` from their secret manager.
|
|
169
170
|
|
|
170
171
|
Set `VOID_API_URL` alongside `VOID_TOKEN` to identify the platform that issued it.
|
|
171
172
|
A token without an API URL is only used for Void Cloud's production API; a saved
|
|
@@ -174,6 +175,13 @@ saved login instead, unset `VOID_TOKEN`.
|
|
|
174
175
|
|
|
175
176
|
This is optional if you already completed auth during `void connect` or the interactive `void init` flow.
|
|
176
177
|
|
|
178
|
+
### `void auth link [connection-id]`
|
|
179
|
+
|
|
180
|
+
Link another enabled login method to your current account. Sign in again if your
|
|
181
|
+
session is no longer recent, complete the additional provider's browser login,
|
|
182
|
+
and confirm the displayed identity. With no connection ID, choose an enabled
|
|
183
|
+
method interactively. The optional dashboard exposes the same flow in **Account**.
|
|
184
|
+
|
|
177
185
|
### `void auth logout`
|
|
178
186
|
|
|
179
187
|
Removes saved credentials.
|
|
@@ -184,7 +192,11 @@ Prints your current login.
|
|
|
184
192
|
|
|
185
193
|
### `void auth token`
|
|
186
194
|
|
|
187
|
-
Copies your auth token to the system clipboard.
|
|
195
|
+
Copies your human auth token to the system clipboard. It is intended for
|
|
196
|
+
interactive troubleshooting and remains subject to login-method revocation. Do
|
|
197
|
+
not combine it with a Cloudflare Access service token for CI; machine Access
|
|
198
|
+
proof cannot turn a human Void token into an automation identity. Create a
|
|
199
|
+
project-scoped credential with `void project token create` instead.
|
|
188
200
|
|
|
189
201
|
## Cloudflare authentication
|
|
190
202
|
|
|
@@ -216,7 +228,80 @@ Link current directory to an existing hosted Void project by slug, or select int
|
|
|
216
228
|
|
|
217
229
|
### `void project list`
|
|
218
230
|
|
|
219
|
-
List all hosted projects (slug,
|
|
231
|
+
List all accessible hosted projects (slug, role, type, URL). Shared projects are included and the role column distinguishes them from projects you own. For a saved Cloudflare target, this displays the current Worker's versions instead because there is no Void project registry.
|
|
232
|
+
|
|
233
|
+
### `void project team`
|
|
234
|
+
|
|
235
|
+
Manage access to a project hosted on a Void platform:
|
|
236
|
+
|
|
237
|
+
```sh
|
|
238
|
+
void project team list [--project <slug>]
|
|
239
|
+
void project team invite <email> --role <reader|collaborator|admin> [--project <slug>]
|
|
240
|
+
void project team invitations [--project <slug>]
|
|
241
|
+
void project team role <user-id> <reader|collaborator|admin> [--project <slug>]
|
|
242
|
+
void project team remove <user-id> [--project <slug>]
|
|
243
|
+
void project team revoke <invitation-id> [--project <slug>]
|
|
244
|
+
void project team leave [--project <slug>]
|
|
245
|
+
void project team pending
|
|
246
|
+
void project team accept <invitation-id>
|
|
247
|
+
void project team decline <invitation-id>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Project-scoped commands use `--project`, then `VOID_PROJECT`, then the linked project. Invitations can target only an email address already registered to a user on that platform; they do not create accounts or grant signup access. Only the invited account can accept or decline its invitation.
|
|
251
|
+
|
|
252
|
+
Readers can view the project but cannot deploy. Collaborators can deploy and manage deploy prerequisites. Project administrators can additionally manage domains, email destinations, GitHub configuration, and the project team. The owner alone can delete the project. See [Project Collaboration](../guide/project-collaboration.md) for the full role boundaries.
|
|
253
|
+
|
|
254
|
+
Project-scoped team management commands are not available for projects deployed
|
|
255
|
+
directly to Cloudflare. The account-scoped `pending`, `accept`, and `decline`
|
|
256
|
+
commands use the active connection selected by `void connect <url>`, regardless
|
|
257
|
+
of the current project's link or deploy target. `VOID_API_URL` takes precedence;
|
|
258
|
+
an unscoped `VOID_TOKEN` selects Void Cloud. These commands display their
|
|
259
|
+
platform, and accepting an invitation leaves directory links intact. To link
|
|
260
|
+
the invited application, run `void project link` in an unlinked checkout of
|
|
261
|
+
that application.
|
|
262
|
+
|
|
263
|
+
### `void project token <create|list|renew|revoke>`
|
|
264
|
+
|
|
265
|
+
Manage revocable `aud: deploy` credentials for one Void platform project. The
|
|
266
|
+
credential can only call the endpoints used by `void deploy`; it cannot access
|
|
267
|
+
operator, account, secret-writing, project-deletion, or other projects' routes.
|
|
268
|
+
|
|
269
|
+
```sh
|
|
270
|
+
void project token create --name github-actions --expires-in 30
|
|
271
|
+
void project token list
|
|
272
|
+
void project token renew <credential-id> --expires-in 30
|
|
273
|
+
void project token revoke <credential-id>
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Pass `--project <name>` outside a linked project. Expiry is bounded to 1–90
|
|
277
|
+
days. Create and renew display the bearer value once; replace the stored secret
|
|
278
|
+
immediately after renewal because the previous credential is revoked in the
|
|
279
|
+
same operation. Project deletion and owner suspension also stop its use. Login
|
|
280
|
+
method disablement does not revoke these independent deploy credentials.
|
|
281
|
+
|
|
282
|
+
Store the printed `VOID_TOKEN` and `VOID_API_URL` in the CI secret manager. The
|
|
283
|
+
Access pair passes the perimeter; the scoped Void credential authorizes only
|
|
284
|
+
this project's deploy workflow. When prerendering or remote proxy bindings are
|
|
285
|
+
used on an Access-protected platform, store `VOID_ACCESS_CREDENTIALS` as an
|
|
286
|
+
origin-keyed JSON secret containing both exact HTTPS origins, even if both use
|
|
287
|
+
the same service-token pair:
|
|
288
|
+
|
|
289
|
+
```json
|
|
290
|
+
{
|
|
291
|
+
"https://void-company-api.example.workers.dev": {
|
|
292
|
+
"CF_ACCESS_CLIENT_ID": "<service-token client ID>",
|
|
293
|
+
"CF_ACCESS_CLIENT_SECRET": "<service-token client secret>"
|
|
294
|
+
},
|
|
295
|
+
"https://void-company-proxy.example.workers.dev": {
|
|
296
|
+
"CF_ACCESS_CLIENT_ID": "<service-token client ID>",
|
|
297
|
+
"CF_ACCESS_CLIENT_SECRET": "<service-token client secret>"
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
`VOID_ACCESS_ORIGIN` scopes a pair to one origin, so selecting only the API
|
|
303
|
+
origin is insufficient for a workflow that calls the proxy. Use distinct pairs
|
|
304
|
+
in the two entries when the Access policies require them.
|
|
220
305
|
|
|
221
306
|
### `void project logs`
|
|
222
307
|
|
|
@@ -361,13 +446,78 @@ Void does not automatically retry changes. If a request loses its connection or
|
|
|
361
446
|
Sign in, inspect your session, or sign out:
|
|
362
447
|
|
|
363
448
|
```sh
|
|
364
|
-
void platform auth login [--provider
|
|
449
|
+
void platform auth login [--provider <connection-id>] [--token-stdin]
|
|
365
450
|
void platform auth status
|
|
366
451
|
void platform auth logout
|
|
367
452
|
void platform auth token [--token-stdin]
|
|
368
453
|
```
|
|
369
454
|
|
|
370
|
-
|
|
455
|
+
With no `--provider`, browser login offers the platform's enabled login methods.
|
|
456
|
+
|
|
457
|
+
#### Authentication configuration
|
|
458
|
+
|
|
459
|
+
`void platform config auth` opens interactive configuration. These commands use
|
|
460
|
+
your administrator session from `void platform auth login`:
|
|
461
|
+
|
|
462
|
+
```sh
|
|
463
|
+
void platform config auth list
|
|
464
|
+
void platform config auth show company
|
|
465
|
+
void platform config auth add google
|
|
466
|
+
void platform config auth add oidc --id company
|
|
467
|
+
void platform config auth add cloudflare-access --id access
|
|
468
|
+
void platform config auth configure company
|
|
469
|
+
void platform config auth test company
|
|
470
|
+
void platform config auth link company
|
|
471
|
+
void platform config auth enable company
|
|
472
|
+
void platform config auth disable github
|
|
473
|
+
void platform config auth admission
|
|
474
|
+
void platform config auth protection show
|
|
475
|
+
void platform config auth protection enable --installation <id>
|
|
476
|
+
void platform config auth protection disable --installation <id>
|
|
477
|
+
void platform config auth recover company --installation <id> --file recovery.json
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
When configuring an existing installation for the first time, run
|
|
481
|
+
`void platform config auth initialize`, then sign in again. Its current login
|
|
482
|
+
methods and signup policy are preserved.
|
|
483
|
+
|
|
484
|
+
Adding or editing a method saves a pending configuration. Enabling it verifies the
|
|
485
|
+
login in your browser before applying it. Linking the verified identity to your
|
|
486
|
+
account is a separate, explicit action. Before disabling a method, verify a linked
|
|
487
|
+
alternative; the last method cannot be disabled. Disabling revokes human sessions
|
|
488
|
+
created through that method, including operator sessions. Scoped deployment tokens
|
|
489
|
+
remain valid; a human login token used as `VOID_TOKEN` is still revoked.
|
|
490
|
+
|
|
491
|
+
Commands accept `--connection <registered-id-or-url>` and `--json`. Changes accept
|
|
492
|
+
`--plan` or `--yes`. For scripted configuration, use `--file <path>` for the
|
|
493
|
+
nonsecret fields and `--client-secret-env <name>` for the environment variable
|
|
494
|
+
containing the secret. Omit the secret when editing to retain its saved value.
|
|
495
|
+
For `enable` or `link` in scripts, supply `--test-id <id>` from a completed test.
|
|
496
|
+
`test --json` returns a browser URL, test ID, and expiry without waiting for completion.
|
|
497
|
+
|
|
498
|
+
`admission` chooses invited/allowlisted, company-approved, or public signup.
|
|
499
|
+
Company-approved signup creates ordinary accounts automatically when a user
|
|
500
|
+
passes a configured company rule. Select an enabled, company-restricted OIDC or
|
|
501
|
+
Google Workspace method, or an enabled Cloudflare Access gate. In scripts,
|
|
502
|
+
`admission --file <path> --yes` reads a policy such as
|
|
503
|
+
`{"mode":"company","connections":["company"],"access":false}`.
|
|
504
|
+
|
|
505
|
+
Browser login offers the platform's enabled methods; `--provider <connection-id>` selects one. Login saves a one-hour administrator session in your system keychain. Logout revokes that session and removes its local credential.
|
|
506
|
+
|
|
507
|
+
`protection enable` creates or connects Cloudflare Access applications independently
|
|
508
|
+
of login methods. Its `--file` accepts the `cloudflareAccess` object described in
|
|
509
|
+
[installation setup](../guide/self-hosted-platform.md#configure-github-oauth).
|
|
510
|
+
Protection changes require installation ownership, the saved recovery credentials,
|
|
511
|
+
and a human administrator session. They revoke current human sessions. Before
|
|
512
|
+
removing protection, change any signup rule that depends on that gate. Cloudflare
|
|
513
|
+
applications are retained for deliberate cleanup.
|
|
514
|
+
|
|
515
|
+
`recover <connection-id>` restores an existing administrator when normal login is
|
|
516
|
+
unavailable. Its file contains `administratorUserId`, optional nonsecret provider
|
|
517
|
+
`configuration`, and an `expectedIdentity` object with exact `issuer` and `subject`
|
|
518
|
+
when using `--yes`. Recovery requires Cloudflare management/database authority,
|
|
519
|
+
original recovery keys, and a successful browser provider test. Use
|
|
520
|
+
`--client-secret-env <name>` for new or rotated credentials.
|
|
371
521
|
|
|
372
522
|
`auth token` prints your current operator token. With `--token-stdin`, it exchanges a full administrator API login session from standard input for a new operator token. `auth login --token-stdin` saves the exchanged token to the keychain instead of printing it.
|
|
373
523
|
|
|
@@ -406,10 +556,13 @@ List projects across the platform, filter them by owner, or inspect one project'
|
|
|
406
556
|
void platform project list [--user <user-id>] [--search <text>] [--page <n>] [--limit <n>]
|
|
407
557
|
void platform project show <id>
|
|
408
558
|
void platform project delete <id>
|
|
559
|
+
void platform project owner <project-id> <user-id>
|
|
409
560
|
```
|
|
410
561
|
|
|
411
562
|
Search matches a project's slug, ID, or owner's login. `show` includes resources, domains, the latest 10 deployments, and the latest 20 builds. `delete` removes the project and its resources.
|
|
412
563
|
|
|
564
|
+
`owner` transfers a project to another registered user. Preview it with `--plan`; apply it interactively or with `--yes`. The preview reports active-work blockers and the account plan that will apply. The former owner becomes a project administrator, existing project-scoped CI deploy credentials are revoked, and usage already incurred remains with the former owner.
|
|
565
|
+
|
|
413
566
|
#### Deployments {#operator-deployments}
|
|
414
567
|
|
|
415
568
|
Find a deployment, inspect its manifest, or request cancellation:
|
|
@@ -455,14 +608,24 @@ void platform signup open
|
|
|
455
608
|
void platform signup restrict
|
|
456
609
|
```
|
|
457
610
|
|
|
458
|
-
Add and remove entries by their type and pattern:
|
|
611
|
+
Add and remove GitHub or email entries by their type and pattern:
|
|
459
612
|
|
|
460
613
|
```sh
|
|
461
614
|
void platform signup allow <github|email> <pattern> [--note <text>]
|
|
615
|
+
void platform signup disallow <github|email> <pattern>
|
|
462
616
|
void platform signup remove <github|email> <pattern>
|
|
463
617
|
```
|
|
464
618
|
|
|
465
|
-
GitHub entries match a login. Email entries match an address or a domain pattern such as `*@example.com`, across sign-in providers. Quote wildcard patterns in your shell.
|
|
619
|
+
`remove` remains available as an alias for existing scripts. GitHub entries match a login. Email entries match an address or a domain pattern such as `*@example.com`, across sign-in providers. Quote wildcard patterns in your shell.
|
|
620
|
+
|
|
621
|
+
For an OIDC identity that has no verified email, grant access using its configured connection ID and stable provider subject:
|
|
622
|
+
|
|
623
|
+
```sh
|
|
624
|
+
void platform signup allow identity <connection-id> <subject> [--note <text>]
|
|
625
|
+
void platform signup disallow identity <connection-id> <subject>
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
Connection IDs are shown by `void platform config auth list`. Identity subjects match exactly and case-sensitively; wildcards, email inference, and account linking are not applied. The login method's domain or group restrictions must still pass, and a newly admitted account has the ordinary user role. With restrictions enabled and an empty allowlist, nobody new can sign up.
|
|
466
629
|
|
|
467
630
|
#### Invitations {#operator-invitations}
|
|
468
631
|
|
|
@@ -476,6 +639,61 @@ void platform invitation revoke <id>
|
|
|
476
639
|
|
|
477
640
|
Send accepts up to 100 comma-separated addresses. Invitations grant signup access even if email delivery is unavailable or fails; delivery is reported separately. Revoking a pending invitation removes its exact email grant. A broader domain entry can still allow that person to sign up.
|
|
478
641
|
|
|
642
|
+
#### Email {#operator-email}
|
|
643
|
+
|
|
644
|
+
Decide who mail from the shared sender may reach, who registers email domains, and a project's outbound caps:
|
|
645
|
+
|
|
646
|
+
```sh
|
|
647
|
+
void platform email policy
|
|
648
|
+
void platform email policy-set <verified|domains|any> [--domains <domain[,domain...]>]
|
|
649
|
+
void platform email settings
|
|
650
|
+
void platform email settings-set --domains <self-serve|admin>
|
|
651
|
+
void platform email limit <project-id|slug> [--monthly <n>] [--burst <n>]
|
|
652
|
+
void platform email logs <project-id|slug> [--page <n>] [--limit <n>] [--json]
|
|
653
|
+
void platform email attempts [--project <id|slug>] [--page <n>] [--limit <n>]
|
|
654
|
+
void platform email attempt-resolve <attempt-id> --ended --reason <text>
|
|
655
|
+
void platform email operation-resolve <operation-id> --ended --outcome <applied|not-applied> --reason <text>
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
`policy` decides which recipients a project's `<slug>+tag@<mail domain>` sender reaches: `verified` (the default) means only that project's verified destinations; `domains` adds every address on the listed domains; `any` lifts the check. Neither widens delivery to addresses on the platform's own mail domain: those stay verified-destination-only, so no project reaches another project's inbox without its consent. Cloudflare still refuses a destination it has not verified until the platform mail domain is onboarded for Email Sending, so under `domains` or `any` such refusals arrive as per-recipient `UNVERIFIED_DESTINATION` results. Custom-domain sends are not affected.
|
|
659
|
+
|
|
660
|
+
`settings-set --domains admin` tells `void email domain add` to print the administrator's command instead of starting token setup. `limit` overrides the project's monthly and rolling 60-second caps (defaults 200 and 10); a project page in the admin UI shows and clears them.
|
|
661
|
+
|
|
662
|
+
`logs` inspects retained receipt and recipient outcomes, including operation IDs, provider references, error codes, and policy versions. Pages contain at most 100 records, newest first; use `--json` for all fields. After project deletion, use its project ID to inspect metadata until the 30-day retention period expires. Message content and credentials are never included.
|
|
663
|
+
|
|
664
|
+
`attempts` lists interrupted provider calls and their earliest resolution time. Once
|
|
665
|
+
the original Worker execution has ended and the attempt is at least 24 hours old,
|
|
666
|
+
`attempt-resolve` records `outcome_unknown`, retains its quota charge, and releases
|
|
667
|
+
the project/domain cleanup fence. `--ended` is your attestation that the call is no
|
|
668
|
+
longer active; `--reason` is stored in the operator audit log. Keep recipient
|
|
669
|
+
addresses and message content out of the reason. The send is never retried. Use
|
|
670
|
+
`--plan` to preview and `--yes` to apply without a prompt.
|
|
671
|
+
|
|
672
|
+
`operation-resolve` recovers a Cloudflare routing, Worker, secret, catch-all, or
|
|
673
|
+
Sending mutation whose outcome remains unknown. After the original execution
|
|
674
|
+
has ended and the operation is at least 24 hours old, inspect the exact resource
|
|
675
|
+
named by the preview and attest whether its write was `applied` or `not-applied`.
|
|
676
|
+
Applied writes continue at the next step; not-applied writes retry the same
|
|
677
|
+
persisted intent. The running platform version must match that intent, so restore
|
|
678
|
+
the matching version before recovering an operation created by older code. The
|
|
679
|
+
preview pins the step, attempt, connection and route generations, resource
|
|
680
|
+
identity, and digest used by the apply request. Time alone never retries a write.
|
|
681
|
+
|
|
682
|
+
Register and maintain email domains for projects whose owners hold no Cloudflare credential:
|
|
683
|
+
|
|
684
|
+
```sh
|
|
685
|
+
void platform email domains [--project <id|slug>]
|
|
686
|
+
void platform email domain-add <domain> --project <id|slug> [--token-stdin]
|
|
687
|
+
void platform email domain-status <domain>
|
|
688
|
+
void platform email domain-sync <domain>
|
|
689
|
+
void platform email domain-rotate-secret <domain>
|
|
690
|
+
void platform email domain-remove <domain> [--token-stdin]
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
`domain-add` uses the platform's Cloudflare credential for zones in its account. For another account, pipe a scoped Cloudflare API token on standard input with `--token-stdin --yes`. Name the exact mail domain (`mail.example.com`, or the apex when it receives no mail yet). `domain-status` shows inbound, outbound, and credential-management readiness with the latest operation. A blocked operation resumes through `domain-sync`; a blocked rotation resumes through `domain-rotate-secret`, preserving already confirmed steps and its staged credential. An uncertain operation remains stopped until read-back proves the result or an administrator uses `operation-resolve`. Domains an administrator adds show `managed_by: admin`; their owners can list and inspect them but use these commands for `sync`, `domain-rotate-secret`, and `remove`.
|
|
694
|
+
|
|
695
|
+
If project deletion leaves cleanup blocked by an expired or revoked Cloudflare token, use `domain-remove <domain> --token-stdin --yes` with a replacement scoped to the same account and zone. This resumes the retained cleanup only when no other project uses the connection. For a live project, renew its token through `domain-add` instead.
|
|
696
|
+
|
|
479
697
|
#### System {#operator-system}
|
|
480
698
|
|
|
481
699
|
Inspect activity, check service health, or review administrative changes:
|
|
@@ -516,6 +734,7 @@ void platform install [options] [--yes]
|
|
|
516
734
|
| `--name <slug>` | Installation name used in `void-<name>-<role>` resource names; choose an unused name |
|
|
517
735
|
| `--display-name <name>` | Human-readable platform name |
|
|
518
736
|
| `--account <id>` | Cloudflare account id |
|
|
737
|
+
| `--auth-config <path>` | Login methods, signup policy, and environment references for provider secrets |
|
|
519
738
|
| `--application-domain <domain>` | Base domain for deployed apps |
|
|
520
739
|
| `--workers-dev` | Explicit testing mode; add an application domain later |
|
|
521
740
|
| `--zone <domain>` | Cloudflare zone containing the application domain |
|
|
@@ -532,7 +751,9 @@ Read-only plans, workers.dev installations with the default API hostname, and su
|
|
|
532
751
|
|
|
533
752
|
The installed platform needs a separate runtime token to provision resources for apps. The interactive installer prompts for it and the other setup values. For non-interactive installs, inject the variables listed in [Install from CI](../guide/self-hosted-platform.md#install-from-ci).
|
|
534
753
|
|
|
535
|
-
|
|
754
|
+
To enable email during install or upgrade, set both `VOID_EMAIL_SENDER_DOMAIN` and `VOID_EMAIL_SHARED_ZONE_ID`. Void records the pair for later upgrades; supplying only one is an error.
|
|
755
|
+
|
|
756
|
+
`--plan` prints the actual resource names, selected login methods, login callback, and direct setup links without opening credential pages or saving a draft; Cloudflare browser login still opens if needed. New platform resources use `void-<name>-<role>` names without random suffixes. Existing installations keep their recorded names, and unowned name conflicts stop installation without overwriting resources. After you confirm an interactive install, Void opens each missing credential's setup page and shows a short permission/checklist fallback. The runtime-token link preselects all required account permissions, including Workers Tail, Hyperdrive, and AI Gateway when needed; domain installations must also select the indicated zone. Supplied credentials skip browser opening. Setup drafts pin Worker names and the login callback and save partial credentials encrypted locally. Interactive installs list unfinished installations, including interrupted provisioning, or offer a new install. Entering an existing unfinished name asks to resume it; declining returns to name entry. Starting new leaves previous setup, credentials, and resources untouched. Completed platforms are not offered for resumption. `--resume` skips the choice and is required for non-interactive recovery.
|
|
536
757
|
|
|
537
758
|
Use an empty PostgreSQL database dedicated to the installation. You can correct a failed initial connection, but after the database is claimed or Hyperdrive is provisioned, commands reject a different URL.
|
|
538
759
|
|
|
@@ -574,7 +795,7 @@ void platform uninstall [id] [--plan] [--purge-data] [--keep-zone] [--yes]
|
|
|
574
795
|
|
|
575
796
|
Omit `id` when only one installation is configured, or choose from the interactive picker. Non-interactive commands need an ID when several installations exist. Commands that make changes also require `--yes`; `--plan` only previews changes.
|
|
576
797
|
|
|
577
|
-
After discovery on another machine, set `VOID_PLATFORM_DATABASE_URL`.
|
|
798
|
+
After discovery on another machine, set `VOID_PLATFORM_DATABASE_URL`. An upgrade that preserves every deployed Worker also preserves its secrets. For an email-enabled installation without its encrypted recovery file, restore `VOID_PLATFORM_EMAIL_SIGNING_SECRET`; recreating only the email gateway needs that key and does not need the Cloudflare runtime token or JWT signing key. Recreating the API or proxy also requires the email key when email is enabled, in addition to their normal secrets. Recreating the API requires its original runtime-token, GitHub, R2, JWT, and project-encryption values; recreating the proxy requires the runtime token and JWT signing key.
|
|
578
799
|
|
|
579
800
|
| Command | Behavior |
|
|
580
801
|
| ----------- | --------------------------------------------------------------------------------------------- |
|
|
@@ -598,7 +819,7 @@ Platform migrations only move forward. Void checks compatibility before updating
|
|
|
598
819
|
|
|
599
820
|
An upgrade completes after the new Workers pass health checks. If rollout fails, Void attempts to restore the previous Workers. Retrying does not repeat completed migrations.
|
|
600
821
|
|
|
601
|
-
`platform rollback` restores a compatible earlier runtime without reversing database migrations. Pass its files with `--runtime`. If the installed version is a custom build, also supply that version with `--from-runtime`. Void refuses
|
|
822
|
+
`platform rollback` restores a compatible earlier runtime without reversing database migrations. Pass its files with `--runtime`. If the installed version is a custom build, also supply that version with `--from-runtime`. Void refuses targets that are incompatible with the current database or predate installed authentication, sandbox-drain, or ownership-aware usage protocols. A later `upgrade` can move forward again.
|
|
602
823
|
|
|
603
824
|
Uninstall verifies remote ownership before removing anything. Data resources are retained unless you pass `--purge-data`. Workers, R2, AI Gateway, DNS records, routes, custom domains, adopted resources, external PostgreSQL, and zones are always retained for manual review.
|
|
604
825
|
|
|
@@ -724,7 +945,7 @@ Provisioning reuses known resource IDs and writes newly resolved IDs into `wrang
|
|
|
724
945
|
|
|
725
946
|
Existing remote secrets are preserved. Void also preserves or creates `BETTER_AUTH_SECRET` for auth apps.
|
|
726
947
|
|
|
727
|
-
**Email.** When the app uses email (`sendEmail()` or `email/` handlers) and `void.json` has `email.from`, the deploy reads the state of that address's zone before the build — session scopes, zone, MX records, Email Routing, subaddressing, routing rules, Email Sending, and what `wrangler.jsonc` holds — prints a checklist of what it would change in your account, and asks once (default Yes). On Yes it enables what is missing, writes `send_email: [{ "name": "SEND_EMAIL" }]`, the `__VOID_EMAIL_FROM` var and the `addresses` array into `wrangler.jsonc`, and lets wrangler create the routing rules when the activated version's triggers are synchronized; the deploy ends with the address map. A deploy with nothing left to set up asks nothing. Without `email.from` the deploy prints `add "email": { "from": "you@mail.acme.com" } to void.json` and continues without email. Non-interactive runs (CI, or stdin/stdout not a terminal) never prompt: they print the checklist plus `Run void email setup --platform cloudflare once locally, commit wrangler.jsonc, then redeploy` and deploy without email (or with the setup `wrangler.jsonc` already carries, when the binding is committed
|
|
948
|
+
**Email.** When the app uses email (`sendEmail()` or `email/` handlers) and `void.json` has `email.from`, the deploy reads the state of that address's zone before the build — session scopes, zone, MX records, Email Routing, subaddressing, routing rules, Email Sending, and what `wrangler.jsonc` holds — prints a checklist of what it would change in your account, and asks once (default Yes). On Yes it enables what is missing, writes `send_email: [{ "name": "SEND_EMAIL" }]`, the `__VOID_EMAIL_FROM` var and the `addresses` array into `wrangler.jsonc`, and lets wrangler create the routing rules when the activated version's triggers are synchronized; the deploy ends with the address map. A deploy with nothing left to set up asks nothing. Without `email.from` the deploy prints `add "email": { "from": "you@mail.acme.com" } to void.json` and continues without email. Non-interactive runs (CI, or stdin/stdout not a terminal) never prompt: they print the checklist plus `Run void email setup --platform cloudflare once locally, commit wrangler.jsonc, then redeploy` and deploy without email (or with the setup `wrangler.jsonc` already carries, when the binding is committed) — unless `--require-email` is passed, which fails instead. If setup has committed the exact subdomain `addresses` plan but the deploy's resolver still sees no MX records, Void preserves the plan and stops before build or upload until DNS can be verified. A deploy whose account rows all read ready reconciles the two config rows — `addresses` against the current derivation and `vars.__VOID_EMAIL_FROM` against `email.from` — with a plain file write and no prompt. See [Your own Cloudflare account](../guide/email.md#your-own-cloudflare-account) for the whole flow, including the subdomain-vs-apex rule and what stays manual.
|
|
728
949
|
|
|
729
950
|
See the [Cloudflare guide](../integrations/cloudflare.md#deploy-to-your-own-cloudflare-account) for the complete deployment sequence, first-deploy exceptions, secret precedence, and recovery behavior.
|
|
730
951
|
|
|
@@ -742,6 +963,8 @@ Generate SQL migration files from schema changes.
|
|
|
742
963
|
|
|
743
964
|
The command compares your current `db/schema.ts` or `db/schema/` modules against the last generated Drizzle snapshot and writes new migration artifacts under `db/migrations/`. When Void-managed auth is enabled, it also resolves the Better Auth schema in production mode and includes those tables automatically, including configured renames and plugin tables. This works for auth-only apps without an application schema. Review and commit the generated files before deploying.
|
|
744
965
|
|
|
966
|
+
For SQLite, Void checks that the migration history applies to a fresh database. If generation fails this check, the previous SQL, snapshots, and journal are restored. If an existing migration fails, repair that unapplied migration first: rerunning generation compares snapshots and does not repair existing SQL. This check does not verify that a migration preserves existing data; review table rebuilds and foreign-key actions carefully.
|
|
967
|
+
|
|
745
968
|
### `void db status`
|
|
746
969
|
|
|
747
970
|
Show migration status. Displays which migrations are applied or pending locally, then uses the saved deployment target for remote status: the hosted API for Void projects, the pinned D1 database and its configured migration table for direct Cloudflare SQLite projects, or the shell `DATABASE_URL` for direct Cloudflare PostgreSQL/MySQL projects. If the remote credential or service is unavailable, local status is still shown.
|
|
@@ -1283,7 +1506,7 @@ Project resolution for email commands follows the same order as deploy (`--proje
|
|
|
1283
1506
|
void email usage [--project <name>]
|
|
1284
1507
|
```
|
|
1285
1508
|
|
|
1286
|
-
Show the current month's
|
|
1509
|
+
Show the current month's recipient attempts and inbound receipts, the monthly attempt limit, and how much of it is left. Reserved submissions count toward the limit; started attempts remain charged even if delivery fails or its outcome is unknown. A suspended project is flagged in the output.
|
|
1287
1510
|
|
|
1288
1511
|
### `void email logs`
|
|
1289
1512
|
|
|
@@ -1291,7 +1514,7 @@ Show the current month's outbound and inbound counts, the monthly outbound limit
|
|
|
1291
1514
|
void email logs [--limit <n>] [--project <name>]
|
|
1292
1515
|
```
|
|
1293
1516
|
|
|
1294
|
-
Show recent email
|
|
1517
|
+
Show recent email operation metadata retained for 30 days: timestamp, direction, operation ID, recipient, and state. `--limit` accepts 1–100. Subjects, bodies, and attachments are not stored. Provider acceptance does not confirm mailbox delivery; inspect unknown outcomes before retrying.
|
|
1295
1518
|
|
|
1296
1519
|
### `void email destinations`
|
|
1297
1520
|
|
|
@@ -1317,7 +1540,63 @@ The project owner's email is added automatically when the project is created, so
|
|
|
1317
1540
|
void email disallow <address> [--project <name>]
|
|
1318
1541
|
```
|
|
1319
1542
|
|
|
1320
|
-
Remove one recipient from the project's destination list.
|
|
1543
|
+
Remove one recipient from the project's destination list. New sends to that address are refused immediately; previously admitted attempts may finish. No deploy is involved.
|
|
1544
|
+
|
|
1545
|
+
### `void email domain`
|
|
1546
|
+
|
|
1547
|
+
```
|
|
1548
|
+
void email domain <add|status|list|sync|rotate-secret|remove> [<domain>] [--project <name>]
|
|
1549
|
+
```
|
|
1550
|
+
|
|
1551
|
+
Send and receive at your own domain on a Cloudflare zone you own, registered to the project. Void platform only — on your own Cloudflare account the mail domain comes from `email.from` instead (see `void email setup`). The walkthrough is [Your own domain on the platform](../guide/email.md#your-own-domain-on-the-platform).
|
|
1552
|
+
|
|
1553
|
+
#### `void email domain add`
|
|
1554
|
+
|
|
1555
|
+
```
|
|
1556
|
+
void email domain add <domain> [--subdomain <label|host>] [--project <name>]
|
|
1557
|
+
```
|
|
1558
|
+
|
|
1559
|
+
Register an exact domain with the project using a scoped Cloudflare API token. The CLI opens a token template, accepts a masked paste or newly copied token, and asks you to confirm account and zone restrictions. Credentials are encrypted for the zone connection. The CLI proposes `mail.<domain>` when the apex already has MX records; `--subdomain` overrides that proposal. Several domains can share a zone connection, but each domain belongs to one project. Setup returns an operation ID so an interrupted request can be checked without restarting the operation.
|
|
1560
|
+
|
|
1561
|
+
#### `void email domain status`
|
|
1562
|
+
|
|
1563
|
+
```
|
|
1564
|
+
void email domain status <domain> [--project <name>]
|
|
1565
|
+
```
|
|
1566
|
+
|
|
1567
|
+
Show the recorded inbound, outbound, and management readiness, observation times, and latest operation. Use `sync` to reconcile setup and refresh readiness.
|
|
1568
|
+
|
|
1569
|
+
#### `void email domain list`
|
|
1570
|
+
|
|
1571
|
+
```
|
|
1572
|
+
void email domain list [--project <name>]
|
|
1573
|
+
```
|
|
1574
|
+
|
|
1575
|
+
List the project's registered email domains and readiness.
|
|
1576
|
+
|
|
1577
|
+
#### `void email domain sync`
|
|
1578
|
+
|
|
1579
|
+
```
|
|
1580
|
+
void email domain sync <domain> [--project <name>]
|
|
1581
|
+
```
|
|
1582
|
+
|
|
1583
|
+
Reconcile the domain connection and refresh readiness. Sync does not rotate its secret. A blocked or uncertain operation exits unsuccessfully and names the operation to inspect.
|
|
1584
|
+
|
|
1585
|
+
#### `void email domain rotate-secret`
|
|
1586
|
+
|
|
1587
|
+
```sh
|
|
1588
|
+
void email domain rotate-secret <domain> [--project <name>]
|
|
1589
|
+
```
|
|
1590
|
+
|
|
1591
|
+
Rotate the ingress secret for the zone connection shared by this domain and its siblings. Inbound must be ready; run `void email domain sync <domain>` first if setup is incomplete. The platform accepts the staged secret before updating the Worker and promotes it only after verifying the deployed generation. An uncertain update stays recorded for reconciliation.
|
|
1592
|
+
|
|
1593
|
+
#### `void email domain remove`
|
|
1594
|
+
|
|
1595
|
+
```
|
|
1596
|
+
void email domain remove <domain> [--project <name>]
|
|
1597
|
+
```
|
|
1598
|
+
|
|
1599
|
+
Disable the domain assignment and record cleanup. Zone resources used by another domain remain available. Unfinished or uncertain cleanup remains recorded until it can be reconciled safely.
|
|
1321
1600
|
|
|
1322
1601
|
### `void email status`
|
|
1323
1602
|
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
//#region src/shared/cf-access.ts
|
|
2
|
-
/**
|
|
3
|
-
* Resolve Cloudflare Access headers from an env-like object.
|
|
4
|
-
*
|
|
5
|
-
* Priority:
|
|
6
|
-
* 1. Service token pair (`CF_ACCESS_CLIENT_ID` + `CF_ACCESS_CLIENT_SECRET`) — CI path
|
|
7
|
-
* 2. User JWT (`CF_ACCESS_TOKEN`) — dev path, typically populated via `cloudflared access token`
|
|
8
|
-
* 3. No headers — prod, or unprotected hostnames
|
|
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
|
-
function accessHeaders(env) {
|
|
19
|
-
const id = env.CF_ACCESS_CLIENT_ID;
|
|
20
|
-
const secret = env.CF_ACCESS_CLIENT_SECRET;
|
|
21
|
-
if (typeof id === "string" && typeof secret === "string" && id.length > 0 && secret.length > 0) return {
|
|
22
|
-
"CF-Access-Client-Id": id,
|
|
23
|
-
"CF-Access-Client-Secret": secret
|
|
24
|
-
};
|
|
25
|
-
const token = env.CF_ACCESS_TOKEN;
|
|
26
|
-
if (typeof token === "string" && token.length > 0) return { "cf-access-token": token };
|
|
27
|
-
return {};
|
|
28
|
-
}
|
|
29
|
-
/** Attach shared Void Access credentials only to known hosted staging origins. */
|
|
30
|
-
function cfAccessHeaders(env, targetUrl) {
|
|
31
|
-
return isVoidAccessGatedUrl(targetUrl) ? accessHeaders(env) : {};
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Capture credentials for a Cloudflare Worker readiness request whose target
|
|
35
|
-
* is resolved and constrained by the direct-deploy adapter rather than a
|
|
36
|
-
* user-connected Void platform URL.
|
|
37
|
-
*/
|
|
38
|
-
function trustedCloudflareWorkerAccessHeaders(env) {
|
|
39
|
-
return accessHeaders(env);
|
|
40
|
-
}
|
|
41
|
-
//#endregion
|
|
42
|
-
export { isVoidAccessGatedUrl as n, trustedCloudflareWorkerAccessHeaders as r, cfAccessHeaders as t };
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { n as isVoidAccessGatedUrl } from "./cf-access-AJ1ehiFR.mjs";
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
|
-
//#region src/cli/cf-access.ts
|
|
4
|
-
const probedHosts = /* @__PURE__ */ new Set();
|
|
5
|
-
/**
|
|
6
|
-
* If the CLI is about to talk to a Cloudflare-Access-gated staging host,
|
|
7
|
-
* probe the locally-installed `cloudflared` binary for a cached user JWT
|
|
8
|
-
* and export it as `CF_ACCESS_TOKEN`. On interactive shells with no cached
|
|
9
|
-
* token, open a browser login flow to populate the cache, then re-read it.
|
|
10
|
-
*
|
|
11
|
-
* Cached per-host so that an early non-gated call (e.g. prod) does not
|
|
12
|
-
* permanently disable the probe for a later gated call (e.g. staging) in
|
|
13
|
-
* the same process. Noop when:
|
|
14
|
-
* - a service-token pair is already set (CI path)
|
|
15
|
-
* - `CF_ACCESS_TOKEN` is already set (manual override or prior probe)
|
|
16
|
-
* - the target host is not gated
|
|
17
|
-
* - `cloudflared` is not installed
|
|
18
|
-
*/
|
|
19
|
-
function ensureCloudflaredToken(apiUrl) {
|
|
20
|
-
if (process.env.CF_ACCESS_CLIENT_ID && process.env.CF_ACCESS_CLIENT_SECRET) return;
|
|
21
|
-
if (process.env.CF_ACCESS_TOKEN) return;
|
|
22
|
-
if (!isVoidAccessGatedUrl(apiUrl)) return;
|
|
23
|
-
const host = new URL(apiUrl).hostname;
|
|
24
|
-
if (probedHosts.has(host)) return;
|
|
25
|
-
probedHosts.add(host);
|
|
26
|
-
let token = runCloudflared([
|
|
27
|
-
"access",
|
|
28
|
-
"token",
|
|
29
|
-
`-app=${apiUrl}`
|
|
30
|
-
]);
|
|
31
|
-
if (!token && process.stdin.isTTY && process.stdout.isTTY) {
|
|
32
|
-
runCloudflared([
|
|
33
|
-
"access",
|
|
34
|
-
"login",
|
|
35
|
-
apiUrl
|
|
36
|
-
], {
|
|
37
|
-
inherit: true,
|
|
38
|
-
timeoutMs: 12e4
|
|
39
|
-
});
|
|
40
|
-
token = runCloudflared([
|
|
41
|
-
"access",
|
|
42
|
-
"token",
|
|
43
|
-
`-app=${apiUrl}`
|
|
44
|
-
]);
|
|
45
|
-
}
|
|
46
|
-
if (token) process.env.CF_ACCESS_TOKEN = token;
|
|
47
|
-
}
|
|
48
|
-
function runCloudflared(args, opts) {
|
|
49
|
-
try {
|
|
50
|
-
const result = spawnSync("cloudflared", args, {
|
|
51
|
-
encoding: "utf-8",
|
|
52
|
-
stdio: opts?.inherit ? "inherit" : [
|
|
53
|
-
"ignore",
|
|
54
|
-
"pipe",
|
|
55
|
-
"pipe"
|
|
56
|
-
],
|
|
57
|
-
timeout: opts?.timeoutMs ?? 5e3
|
|
58
|
-
});
|
|
59
|
-
if (result.error || result.status !== 0) return null;
|
|
60
|
-
const out = (result.stdout ?? "").trim();
|
|
61
|
-
return out.length > 0 ? out : null;
|
|
62
|
-
} catch {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
//#endregion
|
|
67
|
-
export { ensureCloudflaredToken as t };
|