void 0.20.2 → 0.20.3

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.
Files changed (68) hide show
  1. package/dist/{auth-cmd-gniL2fNt.mjs → auth-cmd-CzwquNiP.mjs} +3 -3
  2. package/dist/{auth-link-NZdjCmSc.mjs → auth-link-ElDTgF7j.mjs} +3 -3
  3. package/dist/{build-cmd-sI18tX_O.mjs → build-cmd-BpJe6boP.mjs} +1 -1
  4. package/dist/{cache-IHn5MwBC.mjs → cache-D98YTqeE.mjs} +1 -1
  5. package/dist/{cancel-deploy-C5qTOdLi.mjs → cancel-deploy-CPbEQLMG.mjs} +1 -1
  6. package/dist/cli/cli.mjs +27 -26
  7. package/dist/{client-dHfSJvAN.mjs → client-BQBrZoCX.mjs} +143 -78
  8. package/dist/{connect-Bfk31O_8.mjs → connect-WCQZ_u3m.mjs} +3 -3
  9. package/dist/{create-project-Bk9Z0-Jg.mjs → create-project-D0oXA090.mjs} +2 -3
  10. package/dist/{db-BkRoptAt.mjs → db-DJ-9qs3S.mjs} +2 -2
  11. package/dist/{delete-DouASY9P.mjs → delete-BZ4-WaGm.mjs} +1 -1
  12. package/dist/{deploy-DTaWUS1S.mjs → deploy-BAhhcg5q.mjs} +17 -10
  13. package/dist/{domain-1RhhOVrC.mjs → domain-BxAyhxXN.mjs} +1 -1
  14. package/dist/{email-C-lGh51B.mjs → email-Bj7Cvdwp.mjs} +2 -2
  15. package/dist/{env-DJHsPE7Z.mjs → env-DP_EErve.mjs} +1 -1
  16. package/dist/{github-cmd-PW7ZnWTp.mjs → github-cmd-C-z_xRrQ.mjs} +13 -19
  17. package/dist/index.mjs +4 -4
  18. package/dist/{init-BWZ7q5Z4.mjs → init-BGktCXgA.mjs} +4 -4
  19. package/dist/{link-Rmvu2Wl_.mjs → link-D2kbqhWb.mjs} +2 -2
  20. package/dist/{list-DEE2S6mY.mjs → list-CvkK_G7k.mjs} +1 -1
  21. package/dist/{login-Uvferzmm.mjs → login-WIjNc77c.mjs} +2 -2
  22. package/dist/{logs-27FenuiC.mjs → logs-dLUFCapG.mjs} +1 -1
  23. package/dist/{operator-cmd-CjOTmAYE.mjs → operator-cmd-CKJ7xIRs.mjs} +2 -2
  24. package/dist/{platform-auth-config-DrbQXXiW.mjs → platform-auth-config-CdVWRRJr.mjs} +2 -2
  25. package/dist/{platform-auth-protection-Bhtvp0B_.mjs → platform-auth-protection-Drl0qhrn.mjs} +2 -2
  26. package/dist/{platform-auth-recovery-CeOKGVeJ.mjs → platform-auth-recovery-CmKEWpDo.mjs} +2 -2
  27. package/dist/{platform-cmd-BFhieCdV.mjs → platform-cmd-5q_k56xS.mjs} +3 -3
  28. package/dist/{platform-domain-C74PULqV.mjs → platform-domain-4GiDlcqx.mjs} +2 -2
  29. package/dist/{platform-lifecycle-BwAIgz-t.mjs → platform-lifecycle-R9xAxvtG.mjs} +61 -25
  30. package/dist/{platform-management-COogu_Se.mjs → platform-management-BfWsXHEW.mjs} +5 -3
  31. package/dist/{platform-recovery-ewqLefp1.mjs → platform-recovery-CbK-I1FB.mjs} +2 -2
  32. package/dist/{project-cmd-DmZK9Hxf.mjs → project-cmd-CTdmnzvc.mjs} +12 -12
  33. package/dist/{project-team-D8jOJMUJ.mjs → project-team-CGxsQe3_.mjs} +4 -2
  34. package/dist/{project-token-DA34bf-C.mjs → project-token-Cirx7uwZ.mjs} +1 -1
  35. package/dist/{requests-CUExwGQQ.mjs → requests-4Nq59hOr.mjs} +1 -1
  36. package/dist/{rollback-CDNGU1gr.mjs → rollback-Dr7u0Ljx.mjs} +1 -1
  37. package/dist/runtime/remote/index.mjs +49 -8
  38. package/dist/runtime/sandbox.d.mts +4 -56
  39. package/dist/runtime/sandbox.mjs +81 -220
  40. package/dist/{secret-Bzzi2e9E.mjs → secret-AcPi-FoA.mjs} +1 -1
  41. package/package.json +7 -7
  42. package/skills/void/SKILL.md +2 -2
  43. package/skills/void/docs/guide/deployment.md +14 -14
  44. package/skills/void/docs/guide/email.md +12 -10
  45. package/skills/void/docs/guide/platform/administration/access.md +163 -0
  46. package/skills/void/docs/guide/platform/administration/email.md +121 -0
  47. package/skills/void/docs/guide/platform/administration/operations.md +97 -0
  48. package/skills/void/docs/guide/platform/administration/projects.md +54 -0
  49. package/skills/void/docs/guide/platform/development/local.md +119 -0
  50. package/skills/void/docs/guide/platform/development/runtime.md +124 -0
  51. package/skills/void/docs/guide/platform/development/schema-ci.md +95 -0
  52. package/skills/void/docs/guide/platform/installation/ci.md +55 -0
  53. package/skills/void/docs/guide/platform/installation/credentials.md +80 -0
  54. package/skills/void/docs/guide/platform/installation/domains.md +68 -0
  55. package/skills/void/docs/guide/platform/installation/first-deployment.md +82 -0
  56. package/skills/void/docs/guide/platform/installation/maintenance.md +137 -0
  57. package/skills/void/docs/guide/platform/installation/prerequisites.md +86 -0
  58. package/skills/void/docs/guide/platform/installation/setup.md +169 -0
  59. package/skills/void/docs/guide/platform/installation/uninstall.md +54 -0
  60. package/skills/void/docs/guide/platform-administration.md +6 -414
  61. package/skills/void/docs/guide/platform-development.md +5 -316
  62. package/skills/void/docs/guide/project-collaboration.md +1 -1
  63. package/skills/void/docs/guide/sandboxes.md +9 -24
  64. package/skills/void/docs/guide/self-hosted-platform.md +11 -694
  65. package/skills/void/docs/reference/api.md +34 -34
  66. package/skills/void/docs/reference/cli.md +28 -11
  67. package/skills/void/docs/reference/config.md +1 -1
  68. package/skills/void/docs/reference/resource-inference.md +10 -10
@@ -0,0 +1,163 @@
1
+ ---
2
+ outline: deep
3
+ ---
4
+
5
+ # Sign-in and Access
6
+
7
+ ## Signing In
8
+
9
+ For the browser admin UI, open `<API URL>/admin` and use the administrator login method selected during setup. On a new installation, follow the printed administrator setup instructions to create the first admin user. You do not need to create an app or sign in through the CLI first.
10
+
11
+ Connect to your platform's API URL, then sign in as an administrator:
12
+
13
+ ```sh
14
+ void connect https://platform.example.com --no-login
15
+ void platform auth login
16
+ ```
17
+
18
+ The first command saves the connection. The second opens your browser to sign in and saves an administrator session in your system keychain. Sessions last for one hour and are stored separately for each platform.
19
+
20
+ You can check which account is signed in at any time:
21
+
22
+ ```sh
23
+ void platform auth status
24
+ ```
25
+
26
+ This shows your account, the session's expiry, and the features available on the platform. To end the session, run `void platform auth logout`.
27
+
28
+ If the platform is protected by Cloudflare Access, `void connect <url>` handles
29
+ the company sign-in before Void login. Interactive Access authentication uses a
30
+ locally installed `cloudflared` and saves its short-lived credential in your
31
+ system keychain for that platform origin. You do not need to copy browser cookies.
32
+
33
+ For CI, Access credentials do not replace Void deployment credentials. A project
34
+ owner creates the latter with `void project token create`; it is independently
35
+ revocable, expires within 90 days, and authorizes only that project's deploy
36
+ workflow. Human and operator tokens cannot be renewed by Access service proof.
37
+
38
+ Store Access credentials in origin-keyed `VOID_ACCESS_CREDENTIALS`. A deploy
39
+ that uses prerendering or remote bindings needs entries for both the exact API
40
+ and proxy HTTPS origins, even when both entries contain the same admitted
41
+ service-token pair. `VOID_ACCESS_ORIGIN` selects only one recipient and therefore
42
+ cannot cover both calls. Keep the JSON value in your secret manager, not in
43
+ application configuration. See [CI deployment setup](/guide/platform/installation/first-deployment)
44
+ for the required shape.
45
+
46
+ ## Choosing a Platform
47
+
48
+ If you manage more than one platform, list your connections and choose a default:
49
+
50
+ ```sh
51
+ void platform list
52
+ void platform use <connection-id>
53
+ ```
54
+
55
+ You can also select a platform for a single command with `--connection`:
56
+
57
+ ```sh
58
+ void platform user list --connection <connection-id>
59
+ ```
60
+
61
+ Use an ID or URL from the connection list. Administrative commands use this selection even when you run them inside an app with a different deployment destination.
62
+
63
+ ## Recovering Administrator Login
64
+
65
+ If no administrator can use the configured identity provider, the installation
66
+ owner can recover an existing administrator with Cloudflare management access,
67
+ direct database access, and the original encrypted recovery credentials:
68
+
69
+ ```sh
70
+ void platform config auth recover company --installation <id> --file recovery.json
71
+ ```
72
+
73
+ The file identifies the existing account, for example
74
+ `{"administratorUserId":"existing-admin-id"}`. Recovery opens a real login test
75
+ and asks you to confirm the exact identity before restoring access. It does not
76
+ create a new administrator. To use a replacement provider, include its nonsecret
77
+ `configuration` with a new connection ID and supply the secret through
78
+ `--client-secret-env <name>`. To rotate an existing provider's secret, keep its
79
+ connection ID and identity configuration.
80
+
81
+ For `--yes`, also pin `expectedIdentity` with the exact `issuer` and `subject` in
82
+ the file. A successful browser login is still required. Use `--plan` to preview
83
+ the affected administrator and connection before starting recovery.
84
+
85
+ ## Giving People Access
86
+
87
+ Open **Settings** in the administrator UI, or run `void platform config auth`,
88
+ to add, test, enable, or disable login methods. Access protection and login
89
+ methods are separate settings. A provider test shows the authenticated account
90
+ before you explicitly link it or enable the configuration.
91
+
92
+ To change the company gate after installation, use the installing workstation
93
+ with its saved recovery credentials:
94
+
95
+ ```sh
96
+ void platform config auth protection show
97
+ void platform config auth protection enable --installation <id>
98
+ void platform config auth protection disable --installation <id>
99
+ ```
100
+
101
+ Enabling offers application creation or connection to an existing application.
102
+ It checks every API, proxy, and configured dashboard origin and requires a company
103
+ user sign-in. Changing protection ends all current human sessions; sign in again
104
+ afterwards. Before removing a gate used for company signup, select another
105
+ verified company rule or restricted signup. Removing protection retains the
106
+ Cloudflare applications for deliberate cleanup. Disabling an Access login method
107
+ does not remove the gate.
108
+
109
+ Users can add another enabled login to their existing account with
110
+ `void auth link <connection-id>` or **Account** in the optional
111
+ dashboard. Sign in again first if prompted, then authenticate with the additional
112
+ provider and confirm the identity shown. Matching email addresses alone do not
113
+ link accounts.
114
+
115
+ For company installations, choose **Company-approved users** under **Who can
116
+ join?** to create accounts automatically for users accepted by your configured
117
+ company rules. Individual invitations are not required. Invited/allowlisted
118
+ signup remains available when you need to approve people individually.
119
+
120
+ With invited/allowlisted signup selected, let a teammate join with GitHub by adding their login to the allowlist:
121
+
122
+ ```sh
123
+ void platform signup allow github teammate
124
+ ```
125
+
126
+ Void shows the change and asks you to confirm it. The teammate can then run `void connect` with the platform's URL and sign in.
127
+
128
+ You can allow an email address or a whole email domain in the same way:
129
+
130
+ ```sh
131
+ void platform signup allow email teammate@example.com
132
+ void platform signup allow email '*@example.com'
133
+ ```
134
+
135
+ Email patterns apply across the platform's sign-in providers. Quote a domain pattern so your shell passes the `*` to Void.
136
+
137
+ For an OIDC login without a verified email, allow the identity by its login connection and stable provider subject instead:
138
+
139
+ ```sh
140
+ void platform signup allow identity company-sso 'Employee-42'
141
+ ```
142
+
143
+ Use the connection ID shown by `void platform config auth list` and the exact subject reported by your identity provider. The match is case-sensitive and does not infer an email address or link another account. Any domain or group restrictions configured for that login method still apply, and the account joins as an ordinary user. Remove the grant with `void platform signup disallow identity company-sso 'Employee-42'`.
144
+
145
+ To invite someone else by email, use:
146
+
147
+ ```sh
148
+ void platform invitation send alex@example.org
149
+ ```
150
+
151
+ An invitation grants signup access and sends an email when the platform has email delivery configured. If delivery is unavailable or fails, the result tells you; the person can still join using the platform's URL.
152
+
153
+ Inspect the current access settings and invitations with:
154
+
155
+ ```sh
156
+ void platform signup show
157
+ void platform invitation list
158
+ ```
159
+
160
+ Invitation history remains available after an involved account is removed. The stored actor ID
161
+ remains visible when that account's login no longer exists.
162
+
163
+ `void platform signup open` allows anyone to sign up. Use `void platform signup restrict` to require an allowlist match again. Disallowing an entry affects future signup; it does not suspend an existing account.
@@ -0,0 +1,121 @@
1
+ ---
2
+ outline: deep
3
+ ---
4
+
5
+ # Email
6
+
7
+ ## Managing Email
8
+
9
+ These commands apply to a platform that enables email. Every project can send from and receive at `<slug>+tag@<mail domain>` on the platform's shared mail domain; the [email guide](/guide/email) describes what applications do with that.
10
+
11
+ ### Deciding who mail may reach
12
+
13
+ By default, mail from the shared sender reaches only the recipients each project has verified. For a team whose applications mainly mail colleagues, widen that once for the whole installation:
14
+
15
+ ```sh
16
+ void platform email policy
17
+ void platform email policy-set domains --domains example.com,corp.example.net
18
+ void platform email policy-set any
19
+ void platform email policy-set verified
20
+ ```
21
+
22
+ `domains` lets every project mail any address on the listed domains in addition to its verified recipients; `any` lifts the check. Cloudflare still refuses a recipient it has not verified until your mail domain is onboarded for Email Sending, which needs Workers Paid on the platform's account. Until then such sends come back as `UNVERIFIED_DESTINATION` for that recipient, whatever the policy says. Two things the policy never changes: sends from a project's own custom domain, and mail to any address on the platform's own mail domain — those stay verified-recipient-only, so no project reaches another project's inbox without its consent. A tightening applies to new send admissions as soon as it commits; previously admitted attempts may finish. The same setting is on the admin UI's **Email** page.
23
+
24
+ ### Project caps
25
+
26
+ Each project has 200 recipient submissions per UTC calendar month and 10 in a rolling 60-second window by default. An attempt stays charged once it starts, including a failed or uncertain outcome. Raise or lower a project's caps by id or slug:
27
+
28
+ ```sh
29
+ void platform email limit hr-portal --monthly 2000 --burst 30
30
+ ```
31
+
32
+ The project's page in the admin UI shows the current values and clears an override.
33
+
34
+ ### Recovering an interrupted send
35
+
36
+ If a sender stops after beginning a provider call, its unresolved attempt blocks
37
+ removal of the project or sender domain. Inspect the attempt ID and start time:
38
+
39
+ ```sh
40
+ void platform email attempts --project hr-portal
41
+ ```
42
+
43
+ First confirm that the original execution has ended through your Worker logs or
44
+ incident records. Once the attempt is at least 24 hours old, resolve it with an
45
+ audit reason that contains no recipient address or message content:
46
+
47
+ ```sh
48
+ void platform email attempt-resolve <attempt-id> --ended --reason "Original Worker execution ended; provider outcome could not be verified" --plan
49
+ void platform email attempt-resolve <attempt-id> --ended --reason "Original Worker execution ended; provider outcome could not be verified"
50
+ ```
51
+
52
+ This records the send as `outcome_unknown` and releases its cleanup fence. The
53
+ attempt remains charged and is never retried. If its 30-day delivery record has
54
+ expired, only its recipient-free fence is removed. Do not resolve an attempt
55
+ while its original execution may still be active.
56
+
57
+ Inspect a project's retained receipt and recipient outcomes with:
58
+
59
+ ```sh
60
+ void platform email logs hr-portal --page 1 --limit 50 --json
61
+ ```
62
+
63
+ Logs include operation IDs, recorded outcomes, provider references, and error codes.
64
+ After project deletion, use its project ID until the 30-day metadata retention
65
+ period expires. Message bodies, subjects, attachments, and credentials are not logged.
66
+
67
+ ### Registering email domains for projects
68
+
69
+ Your users may hold no Cloudflare account. Tell the platform that administrators register email domains, so `void email domain add` prints the command to ask you for instead of opening a token-creation page:
70
+
71
+ ```sh
72
+ void platform email settings-set --domains admin
73
+ ```
74
+
75
+ Then register a domain for a project. The zone must be in the platform's Cloudflare account; the platform's own credential does the setup, and no Cloudflare credential is stored per domain:
76
+
77
+ ```sh
78
+ void platform email domain-add mail.example.com --project hr-portal
79
+ void platform email domain-status mail.example.com
80
+ void platform email domain-rotate-secret mail.example.com
81
+ void platform email domains
82
+ ```
83
+
84
+ Name the exact mail domain: a subdomain such as `mail.example.com` when the apex already receives mail, otherwise the apex itself. `domain-status` reports inbound, outbound, and management readiness separately. Follow any required DNS or Cloudflare dashboard step, then use `domain-sync` to reconcile. Use `domain-rotate-secret` when you need to replace the zone ingress credential explicitly. Email Sending onboarding needs Workers Paid; after upgrading, `domain-sync` re-attempts it. For a zone in another Cloudflare account, pipe an API token for that account on standard input:
85
+
86
+ ```sh
87
+ void platform email domain-add mail.other.example --project hr-portal --token-stdin --yes < token.txt
88
+ ```
89
+
90
+ Project owners see administrator-registered domains in `void email domain list` and `status`; `status` names the `void platform email` command for any step they cannot take themselves, and `sync` and `remove` point them at `domain-sync` and `domain-remove`. A domain an owner registered before you switched to `admin` stays theirs to renew, sync and remove. The runtime token needs the email permissions listed in the [self-hosting guide](/guide/platform/installation/credentials#runtime-token-permissions) for this to work.
91
+
92
+ A permission refusal leaves setup blocked. After correcting it, run `domain-sync`
93
+ to resume that same setup operation; repeat `domain-rotate-secret` to resume a
94
+ blocked rotation without replacing its staged secret. If project deletion leaves
95
+ a blocked domain cleanup, correct the permission and run `domain-remove <domain>`
96
+ to finish the retained cleanup. If its token has expired or been revoked, provide
97
+ a replacement scoped to the same account and zone:
98
+
99
+ ```sh
100
+ void platform email domain-remove mail.other.example --token-stdin --yes < token.txt
101
+ ```
102
+
103
+ This recovery is available only after project deletion has begun and no other
104
+ project uses the connection. For a live project, renew its token through
105
+ `domain-add`. A timed-out Cloudflare
106
+ mutation stays stopped because replay may duplicate a provider write. After
107
+ confirming the original execution ended, wait 24 hours, inspect the exact
108
+ routing, Worker, secret, catch-all, or Sending resource named by the preview,
109
+ and use its recovery fence:
110
+
111
+ ```sh
112
+ void platform email operation-resolve <operation-id> --ended --outcome <applied|not-applied> --reason "Provider state verified" --plan
113
+ void platform email operation-resolve <operation-id> --ended --outcome <applied|not-applied> --reason "Provider state verified"
114
+ ```
115
+
116
+ Run recovery with the same platform version that created the persisted intent.
117
+ `applied` continues without replaying the write; `not-applied` permits that exact
118
+ step to retry. Secret rotation keeps its staged generation, and removal resumes
119
+ from the unresolved cleanup step. Age alone never authorizes a retry.
120
+
121
+ Register administrator domains only after a platform upgrade has completed, and remove them before rolling the platform back to a version that predates this feature: an earlier runtime cannot use the platform credential for them and does not distinguish administrator-registered domains from owner-registered ones.
@@ -0,0 +1,97 @@
1
+ ---
2
+ outline: deep
3
+ ---
4
+
5
+ # Operations
6
+
7
+ ## Previewing Changes
8
+
9
+ Commands that change the platform show the affected objects before asking for confirmation. To inspect a change without applying it, add `--plan`:
10
+
11
+ ```sh
12
+ void platform user suspend <user-id> --reason "Investigating unexpected traffic" --plan
13
+ ```
14
+
15
+ The preview shows which account will be suspended and the effect on its projects. Run the command again without `--plan` to confirm interactively, or use `--yes` when the change is ready to apply:
16
+
17
+ ```sh
18
+ void platform user suspend <user-id> --reason "Investigating unexpected traffic" --yes
19
+ ```
20
+
21
+ Scripts must use `--yes` to apply these changes. The `void platform auth` session commands run directly and do not use `--plan` or `--yes`; changes under `void platform config auth` do use previews and confirmation. After a change, `void platform system events` shows the administrator, affected objects, and recorded outcome.
22
+
23
+ Changes can take longer when an account owns many resources. Requests that change the platform allow five minutes by default; use `--timeout` to set a different limit in seconds:
24
+
25
+ ```sh
26
+ void platform user delete <user-id> --timeout 600 --plan
27
+ ```
28
+
29
+ If a request times out or loses its connection, some work may already have finished. Check the affected objects and `system events` before retrying. Void reports partial results when it can and does not automatically repeat the change.
30
+
31
+ ## Following Logs
32
+
33
+ To investigate a deployment, find its ID and follow its runtime logs:
34
+
35
+ ```sh
36
+ void platform deployment list --project <project-id>
37
+ void platform deployment logs <deployment-id> --since 10m --follow
38
+ ```
39
+
40
+ Runtime logs include application messages, exceptions, and HTTP status codes. Without `--follow`, the command reads a page of historical logs. Use `--since` to choose a duration, an ISO date, or a timestamp in milliseconds.
41
+
42
+ Logs can become available after a request finishes. Following checks a five-minute overlap to pick up delayed records without printing them again. Records delayed longer than that may need a later historical query.
43
+
44
+ Build logs use the build's ID:
45
+
46
+ ```sh
47
+ void platform build logs <build-id> --follow
48
+ ```
49
+
50
+ Following waits for the final logs before stopping, including diagnostics written after the build's status changes. For a GitHub Actions build, the command gives you the URL of its logs.
51
+
52
+ ## Checking the Platform
53
+
54
+ Use the overview to see recent activity, or run a health check to test the platform's services and database:
55
+
56
+ ```sh
57
+ void platform system overview
58
+ void platform system health
59
+ ```
60
+
61
+ Health checks use the services configured for the selected platform. An unhealthy result exits with a nonzero status, so the same command can be used in a script.
62
+
63
+ The browser dashboard's **System Status** checks refresh every 30 seconds. Failed checks show an HTTP status or connection error beside the service name. If the dashboard cannot refresh the checks, it reports that status is unavailable instead of displaying stale results.
64
+
65
+ Use `void platform upgrade`, `repair`, `disable`, and `enable` to maintain your platform. See [platform maintenance](/guide/platform/installation/maintenance#resume-repair-recover-and-upgrade).
66
+
67
+ For disaster recovery, keep a matching PostgreSQL backup, provider data backups, installation identity and complete project-encryption keyring, and immutable runtime artifacts. Keep traffic disabled while restoring data, run `discover` to reconstruct verified local metadata, and review `repair --plan` before recreating missing installer-owned infrastructure. Neither command restores backed-up data. See [Prepare for disaster recovery](/guide/platform/installation/maintenance#prepare-for-disaster-recovery) for the full sequence.
68
+
69
+ ## Using Scripts
70
+
71
+ Add `--json` to read a command's result from another program:
72
+
73
+ ```sh
74
+ void platform user list --page 1 --limit 50 --json
75
+ void platform system health --json
76
+ ```
77
+
78
+ Results go to standard output. Command errors go to standard error as JSON and exit with a nonzero status. With `--follow`, each log response is a separate JSON line.
79
+
80
+ Operator tokens expire after one hour. For CI, mint a new operator token at the start of each job from a valid full API login session belonging to an active administrator. Choose the platform explicitly, inject the full session as `VOID_TOKEN` from your secret manager, and capture the exchange output directly into the protected job environment:
81
+
82
+ ```sh
83
+ export VOID_API_URL=https://platform.example.com
84
+ VOID_OPERATOR_TOKEN="$(
85
+ printf '%s' "$VOID_TOKEN" | void platform auth token --token-stdin
86
+ )" || exit 1
87
+ export VOID_OPERATOR_TOKEN
88
+ unset VOID_TOKEN
89
+ void platform system health --json
90
+ unset VOID_OPERATOR_TOKEN
91
+ ```
92
+
93
+ Disable shell tracing for the exchange and do not write either token to logs or plaintext files. A full API login session expires after 30 days and can be revoked sooner; renew it through the normal authenticated login flow and update the protected CI secret. A job that runs longer than one hour must repeat the exchange while its full API session is still valid. An expired operator token cannot refresh itself, and Void does not issue permanent service tokens for administrator automation.
94
+
95
+ `auth login --token-stdin` performs the same elevation and saves the one-hour operator token in the system keychain for interactive use. See [operator authentication](/reference/cli#operator-authentication) for the full command syntax.
96
+
97
+ An email zone has one connection and ingress Worker shared by its exact domain assignments. Removing one assignment preserves resources used by the others. The Email administration page can explicitly rotate that connection secret; ordinary synchronization does not rotate it. Setup and cleanup outcomes include operation IDs, and uncertain provider writes remain recorded until reconciled.
@@ -0,0 +1,54 @@
1
+ ---
2
+ outline: deep
3
+ ---
4
+
5
+ # Users and Projects
6
+
7
+ ## Managing Users and Projects
8
+
9
+ Start by finding the user you want to inspect:
10
+
11
+ ```sh
12
+ void platform user list --search teammate
13
+ void platform user show <user-id>
14
+ ```
15
+
16
+ Use the ID from the list in the second command. The detail view shows the user's projects and usage. You can change their plan or list just their projects:
17
+
18
+ ```sh
19
+ void platform user plan <user-id> pro
20
+ void platform project list --user <user-id>
21
+ void platform project show <project-id>
22
+ ```
23
+
24
+ Project details include resources, domains, and recent builds and deployments. The [command reference](/reference/cli#operator-commands) also covers suspending and restoring users, deleting projects, and removing accounts.
25
+
26
+ ### Transferring Project Ownership
27
+
28
+ Only an installation administrator can change a project's owner. The new owner must already have an account on this platform. Preview the transfer before applying it:
29
+
30
+ ```sh
31
+ void platform project owner <project-id> <new-owner-user-id> --plan
32
+ void platform project owner <project-id> <new-owner-user-id> --yes
33
+ ```
34
+
35
+ The preview shows both owners, their plans and suspension state, blockers, and the changes to routing and usage counters. Wait for active rollbacks and builds to finish. For an ordinary active deployment, wait or use `void platform deployment cancel <id>`; rollback deployments cannot be canceled. A managed Sandbox controller also blocks transfer until its cleanup completes, even if no Sandbox container is running; the preview identifies the deployment that owns it.
36
+
37
+ After the transfer, the former owner becomes a project administrator. Existing project-scoped CI deploy credentials are revoked; create replacements as the new owner. The new owner's plan and limits apply immediately. Usage before the transfer remains charged to the former owner; later usage is charged to the new owner. If an apply reports partial convergence, inspect the project and operator event log before repeating it.
38
+
39
+ New users on a self-hosted installation start with the `custom` profile, which
40
+ does not cap application requests, AI usage, deployment frequency, or retained
41
+ Worker deployments. Named profiles such as `pro` apply the platform's quota and
42
+ retention policies; they do not purchase Cloudflare services or bill your users.
43
+ Storage figures are not a hard storage-quota boundary. Set an operating budget
44
+ and retention policy before opening signup beyond your invited team.
45
+
46
+ The last active administrator cannot be deleted or suspended, including through
47
+ the browser admin UI. Another administrator must still have access. Automatic
48
+ usage limits do not remove administrator access and do not count as a manual
49
+ suspension.
50
+
51
+ When removing another administrator, Void revokes their administrator access
52
+ before changing application traffic or deleting resources. If cleanup fails,
53
+ access stays revoked and the error describes the partial result. A remaining
54
+ administrator can inspect it and retry cleanup.
@@ -0,0 +1,119 @@
1
+ ---
2
+ outline: deep
3
+ ---
4
+
5
+ # Local Development
6
+
7
+ ## Setting Up the Repository
8
+
9
+ Clone your fork and install the workspace dependencies with Vite+:
10
+
11
+ ```sh
12
+ git clone https://github.com/your-org/void.git
13
+ cd void
14
+ vp install
15
+ vpr install:void-dev
16
+ void-dev --help
17
+ ```
18
+
19
+ Use the Node.js version recorded in `.node-version`. The workspace uses public npm packages; a GitHub Packages token is not required.
20
+
21
+ `install:void-dev` builds the CLI, shared packages, and platform runtime, then makes this checkout's built CLI globally available as `void-dev`. Public packages export their built files, so run `vp run build:core` after later source changes to refresh the alias. The installer refuses to replace an unrelated global command. Remove only this checkout's alias with `vpr uninstall:void-dev`. The commands on these development pages run from the repository root.
22
+
23
+ ## Finding the Implementation
24
+
25
+ | Directory | Purpose |
26
+ | ---------------------------------------------------- | -------------------------------------------------------------------- |
27
+ | `packages/void` | Framework, application runtime, and CLI |
28
+ | `packages/platform` | Installer contracts, packaged Workers, and platform migrations |
29
+ | `packages/deploy-core`, `packages/deploy-cloudflare` | Shared deployment contracts and Cloudflare upload code |
30
+ | `platform/packages/api` | Users, projects, deployments, provisioning, and administrator API/UI |
31
+ | `platform/packages/dispatch` | Application routing and static assets |
32
+ | `platform/packages/proxy` | AI, remote bindings, and revalidation |
33
+ | `platform/packages/email-gateway` | Inbound mail routing and tenant delivery |
34
+ | `platform/packages/tail` | Runtime log ingestion |
35
+ | `platform/packages/dashboard` | Dashboard source and local UI components in `ui/` |
36
+
37
+ The `@voidcloud/*` names identify workspace implementation packages. Their `private: true` flags prevent publishing those packages to npm. Deployable core Workers are bundled into the public `@void/platform` package.
38
+
39
+ The core installer creates the API, dispatch, proxy, and tail Workers. The dashboard and managed GitHub build services are available in the source tree but are not included in that installation. Adding an optional service requires its infrastructure, bindings, authentication, and capability configuration together.
40
+
41
+ ## Running the API Locally
42
+
43
+ Start a local PostgreSQL server and make `psql` and `pg_isready` available on your path. Then create the development database, apply its migrations, and seed an administrator:
44
+
45
+ ```sh
46
+ vp run --filter @voidcloud/api setup --admin-email dev@example.com
47
+ vp run --filter @voidcloud/api dev --local --enable-containers=false --host localhost --port 8787
48
+ ```
49
+
50
+ The command disables the optional build containers, so basic API and admin work
51
+ does not require Docker. To develop managed builds, install Docker and run the
52
+ API with containers enabled.
53
+
54
+ Open `http://localhost:8787/admin/`. Setup writes local development values to the API and dashboard `.dev.vars` files, including the development authentication bypass and local database connection. Those files are ignored by Git. Production installations get separate credentials through the installer.
55
+
56
+ The API's development bypass lets you work on the browser admin UI without setting up OAuth. Operator CLI sessions still require administrator authentication; they do not use the browser bypass.
57
+
58
+ ## Running the Dashboard Locally
59
+
60
+ The dashboard is a separate source app. After API setup, start it in another terminal:
61
+
62
+ ```sh
63
+ vp run --filter @voidcloud/dashboard dev
64
+ ```
65
+
66
+ Its local `.dev.vars` should point to the API you started:
67
+
68
+ ```dotenv
69
+ API_URL=http://localhost:8787
70
+ SITE_DOMAIN=apps.example.com
71
+ ```
72
+
73
+ Open the Vite URL and choose **Dev login (local API)**. That button appears for a localhost API and uses the local development sign-in endpoint.
74
+
75
+ You can also point the dashboard at an API that you operate. If Cloudflare Access protects that API, install `cloudflared` and opt into the dashboard's local token helper with matching origins:
76
+
77
+ ```dotenv
78
+ API_URL=https://platform.example.com
79
+ CF_ACCESS_APP_URL=https://platform.example.com
80
+ SITE_DOMAIN=apps.example.com
81
+ ```
82
+
83
+ The helper refreshes an Access session before the dev server starts. Human
84
+ dashboard requests require the user's Access session as well as their Void login;
85
+ a service token does not represent that user. Service-token pairs are for scoped
86
+ machine operations. This is dashboard development configuration; Access
87
+ credentials are separate from platform login credentials.
88
+
89
+ For a deployed dashboard, bind its `API` service to your platform API, configure
90
+ `DASHBOARD_URL` on both the dashboard and API, and include that exact dashboard origin in the
91
+ platform's Access protection application. The dashboard passes the browser's
92
+ company identity to the API using that service binding. Its login page shows
93
+ the platform's currently enabled methods, and **Account** supports adding an
94
+ additional login identity.
95
+
96
+ ## Testing Changes
97
+
98
+ Run tests for the area you changed while developing:
99
+
100
+ ```sh
101
+ vp test run platform/packages/api/test/integration/operator-auth.test.ts
102
+ vp run check
103
+ ```
104
+
105
+ Before preparing a release, build the packages and run the complete checks:
106
+
107
+ ```sh
108
+ vp run build:all
109
+ vp run check
110
+ vp lint
111
+ vp run lint:platform
112
+ vp fmt --check
113
+ vp test run
114
+ vp run build:docs
115
+ ```
116
+
117
+ Platform integration tests use their local test database by default. To test against PostgreSQL, set `VOID_TEST_DATABASE_URL` to a disposable database: these tests clear tables between cases.
118
+
119
+ To exercise a deployed application, deploy a disposable copy of `playground/kitchen-sink` and pass its URL as `SMOKE_URL` to the smoke test described in `platform/scripts/kitchen-sink-smoke-test.md`. That test creates and removes application data.