Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
826db02
Delete the Workers for Platforms dispatch namespace by name on uninstall
Brooooooklyn Oct 5, 2026
45e5425
Refuse databases with leftover migration history before claiming them
Brooooooklyn Oct 5, 2026
af6d776
List the resources uninstall leaves behind
Brooooooklyn Oct 5, 2026
cfccc04
Draw CLI notes safely in zero-width and tiny terminals
Brooooooklyn Oct 5, 2026
a92a2b2
Document a manual cleanup order that Cloudflare accepts
Brooooooklyn Oct 5, 2026
5ce1e49
Add Cloudflare calls needed to tear down a platform
Brooooooklyn Oct 5, 2026
1794a91
Add `void platform uninstall --purge-all` to remove everything Void c…
Brooooooklyn Oct 5, 2026
7331f9b
Prove each --purge-all deletion against the right owner
Brooooooklyn Oct 5, 2026
878cbf6
Keep changed resources, detach Email Routing, and finish stopped unin…
Brooooooklyn Oct 5, 2026
c6d5c64
Tell installers to switch token zone policies to Specified Domains
Brooooooklyn Oct 5, 2026
08e5226
Read markdown page frontmatter after a leading script block
Brooooooklyn Oct 5, 2026
c368981
Keep the React Pages live stream in a scanned directory
Brooooooklyn Oct 5, 2026
9103b46
Prove reopened resources before any change, and list kept Access reso…
Brooooooklyn Oct 5, 2026
faf9dfd
Add Drizzle metadata to playgrounds with hand-written migrations
Brooooooklyn Oct 5, 2026
b9ea2ce
Explain how to add Drizzle metadata when deploy finds hand-written mi…
Brooooooklyn Oct 5, 2026
210342a
Give the 101-project Zero Trust disable test room under a loaded machine
Brooooooklyn Oct 5, 2026
445bf27
Keep the runtime token on All Domains when Void creates the zone
Brooooooklyn Oct 5, 2026
34d7387
Say that a custom live stream directory must keep the default scan list
Brooooooklyn Oct 5, 2026
89dd0ca
Read the queue consumer Worker from script_name during --purge-all
Brooooooklyn Oct 5, 2026
1ea4335
Refuse new projects once purge-all passes its final project check
Brooooooklyn Oct 5, 2026
f47ef16
Warn against running purge-all while the platform's Workers or routes…
Brooooooklyn Oct 5, 2026
e54ba51
Tell project creation the platform is being uninstalled
Brooooooklyn Oct 5, 2026
d16e31d
Write each user log line once when the dispatch Worker also tails it
Brooooooklyn Oct 5, 2026
66cf307
Store platform ISR edge copies as cache hits
Brooooooklyn Oct 5, 2026
c144304
Run legacy multi-statement migrations statement by statement
Brooooooklyn Oct 5, 2026
b68a979
Show migration warnings after deploy and describe the migration check…
Brooooooklyn Oct 5, 2026
7bd7095
Build the vinext worker entry regardless of plugin order
Brooooooklyn Oct 5, 2026
ba4b877
Name the DNS permission when the install plan cannot read DNS records
Brooooooklyn Oct 5, 2026
b163a16
Keep the platform tail worker off workers.dev and preview URLs
Brooooooklyn Oct 5, 2026
02f1b5a
Report the deployed asset count without the internal cache-buster
Brooooooklyn Oct 5, 2026
b066962
Show per-path ISR rules in the project status ISR column
Brooooooklyn Oct 5, 2026
b6a29f9
Give each concurrent deploy its own log file
Brooooooklyn Oct 5, 2026
4134a65
Report a disabled platform clearly in platform status and operator co…
Brooooooklyn Oct 5, 2026
49e1a32
Describe the platform disable plan in plain terms
Brooooooklyn Oct 5, 2026
fa26db4
Document platform disable scope, enable redeploy, SPA asset 404s, and…
Brooooooklyn Oct 5, 2026
782516b
Return ISO-8601 timestamps from project token endpoints
Brooooooklyn Oct 5, 2026
0856cf2
Show readable labels in operator output and platform auth config
Brooooooklyn Oct 5, 2026
c805240
Delete the platform API and proxy Workers that bind to each other dur…
Brooooooklyn Oct 5, 2026
8808165
Read AI Gateway creation times as UTC so --purge-all deletes the inst…
Brooooooklyn Oct 5, 2026
dc00c83
Print one result line when deleting a project
Brooooooklyn Oct 5, 2026
d2a37db
Prove a Worker's dependents before --purge-all forces its delete
Brooooooklyn Oct 5, 2026
b8fda92
Tell an upgrade or repair apart from a disabled platform
Brooooooklyn Oct 5, 2026
b255cd6
Warn only about migrations that have not been applied yet
Brooooooklyn Oct 5, 2026
7dad32a
Explain how to commit .void/project.json in an app that ignores .void
Brooooooklyn Oct 5, 2026
61a1637
Correct which invocations skip the dispatch Worker in the tail Worker…
Brooooooklyn Oct 5, 2026
b03ab84
Load the platform discovery module under Node's TypeScript type strip…
Brooooooklyn Oct 5, 2026
31cf75f
Collapse duplicate runtime log rows when reading project logs
Brooooooklyn Oct 5, 2026
edd5b17
Rename platform uninstall --purge-all to --delete-resources
Brooooooklyn Oct 6, 2026
277617d
Rename platform uninstall --delete-resources to --purge-resources
Brooooooklyn Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/guide/app-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Add `voidPlugin()` to the framework's Vite config to get binding inference, type

Any project that produces static files, whether that is an SPA, a static site, or a plain directory. Void serves the assets without requiring application code.

**SPAs** (client-side single-page apps) fall back all non-file paths to `index.html` with a 200 status, so client-side routing works out of the box. Detected when `vite` is a dependency and no backend files exist.
**SPAs** (client-side single-page apps) serve `index.html` with a 200 status for paths that match no file, so client-side routing works out of the box. On a Void platform, missing files under the hashed assets folder (`/assets/`) return 404 instead. Detected when `vite` is a dependency and no backend files exist.

**Static sites** (static site generators like VitePress, Docusaurus, or any pre-built directory) produce per-page HTML files. Detected when a known SSG is a dependency, or when using the `--dir` flag.

Expand Down
2 changes: 2 additions & 0 deletions docs/guide/live.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export const live = defineLiveStream({
});
```

Void enables live streams when a [scanned file](../reference/resource-inference.md#scanned-directories) imports `void/live`, so keep this module in `src/` or another scanned directory. To keep it in an unscanned directory such as `lib/`, add that directory to [`inference.scanDirs`](../reference/resource-inference.md#custom-scan-directories) and list the default directories you still use, because `scanDirs` replaces them.

Expose it from a normal route:

```ts
Expand Down
4 changes: 2 additions & 2 deletions docs/guide/platform/installation/credentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Keep one password-manager entry for this platform. Paste the saved values into t

## Cloudflare API Tokens {#runtime-token-permissions}

For a domain installation or Cloudflare Access setup, the installer guides you through creating separate management and runtime tokens using Cloudflare's [API token setup](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/). Its links preselect the permissions and suggest names based on your platform's display name. Scope the tokens to your selected account and, when using a domain, its zone, save them in your password manager, and paste them into the masked CLI prompts.
For a domain installation or Cloudflare Access setup, the installer guides you through creating separate management and runtime tokens using Cloudflare's [API token setup](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/). Its links preselect the permissions and suggest names based on your platform's display name, but Cloudflare's form cannot preselect a zone: for a domain installation, change the zone policy from **All Domains** to **Specified Domains** and select your zone. If Void will create the zone, keep **All Domains** on both tokens: the zone does not exist yet, and the runtime token needs it to purge cache. Save the tokens in your password manager and paste them into the masked CLI prompts.

For workers.dev testing with the default API hostname, browser login can authorize
infrastructure setup. Void also checks account-wide Access requirements; if the
Expand All @@ -21,7 +21,7 @@ Browser login does not grant AI Gateway access. Include **Account → AI Gateway

The management token lets your CLI install and maintain the platform. The runtime token is stored as a Worker secret so the platform can deploy apps after you close your terminal. They are separate credentials.

Compare each token's form with the permission checklist below, and select the indicated account and zone for a domain installation. The installer saves a management token entered at the prompt in this installation’s encrypted local checkpoint and reuses it on resume. Upgrades, repairs, and other lifecycle maintenance also use that saved management token. During installation, a rejected token can be replaced at the prompt. An explicit `CLOUDFLARE_API_TOKEN` or `CF_API_TOKEN` takes precedence. Keep your password-manager copy for maintenance or another machine; scripts supply it through `CLOUDFLARE_API_TOKEN`.
Compare each token's form with the permission checklist below. The installer saves a management token entered at the prompt in this installation’s encrypted local checkpoint and reuses it on resume. Upgrades, repairs, and other lifecycle maintenance also use that saved management token. During installation, a rejected token can be replaced at the prompt. An explicit `CLOUDFLARE_API_TOKEN` or `CF_API_TOKEN` takes precedence. Keep your password-manager copy for maintenance or another machine; scripts supply it through `CLOUDFLARE_API_TOKEN`.

::: details Permissions to select for each token

Expand Down
6 changes: 5 additions & 1 deletion docs/guide/platform/installation/first-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ void project token create --name ci --expires-in 30

Store the printed `VOID_TOKEN` and `VOID_API_URL` in the CI secret manager, then
run `void connect "$VOID_API_URL" --no-login` before deploying in each fresh CI
environment. Project files do not replace this connection step. Rotate with `void project token renew <id>` and revoke with
environment. Project files do not replace this connection step. CI cannot answer
the project prompt, so choose the project before `void deploy`: set `VOID_PROJECT`,
pass `--project <slug>`, or commit `.void/project.json` from `void project link`.
New apps ignore `.void` in `.gitignore`; to commit the link, replace that line
with `.void/*` and `!.void/project.json`. Rotate with `void project token renew <id>` and revoke with
`void project token revoke <id>`. A human login token is not a CI credential.

If Cloudflare Access protects the platform, Access proof and the project
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/platform/installation/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ For workers.dev testing, start the interactive install and choose your login met
void platform install --workers-dev
```

For a domain installation or Access setup, Void guides you to create a management API token and paste it into a masked prompt. Browser login can preview DNS, but cannot change it or configure Access. The token-creation link preselects the permissions for your choices; scope the token to your account and, when using a domain, its zone. No shell environment variable is needed for interactive installation.
For a domain installation or Access setup, Void guides you to create a management API token and paste it into a masked prompt. Browser login can preview DNS, but cannot change it or configure Access. The token-creation link preselects the permissions for your choices. When using an existing domain, change the zone policy from **All Domains** to **Specified Domains** and select your zone, as the CLI prompt describes. No shell environment variable is needed for interactive installation.

::: details Use an existing management token from the shell

Expand Down
54 changes: 43 additions & 11 deletions docs/guide/platform/installation/uninstall.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ void platform disable [id] --plan
void platform disable [id]
```

Disabled platforms reject application traffic while retaining domains and routes. Repair and upgrade preserve that state. Restore traffic with:
Disabled platforms reject application traffic while retaining domains and routes. The platform API also rejects requests, so CLI commands that use it, including login and deploy, fail until you enable the platform again. Only the administrator status page at `<api-url>/admin/status` and administrator sign-in stay available. Repair and upgrade preserve that state.

Enabling redeploys the platform Workers from the selected runtime, verifies them, and then restores traffic. Pass `--runtime <path>` to enable with a custom platform build:

```sh
void platform enable [id] --plan
Expand All @@ -31,28 +33,58 @@ void platform uninstall [id] --plan
void platform uninstall [id]
```

Uninstall blocks platform traffic, removes Queues that no remaining platform Worker uses, and records the resources left for you to review. By default, Workers, the Queues they use, KV, R2, Hyperdrive, the dispatch namespace, and AI Gateway remain in your account. Adopted resources, external PostgreSQL, zones, DNS records, routes, custom domains, and Cloudflare Access resources are always retained.
Uninstall blocks platform traffic, removes Queues that no remaining platform Worker uses, and lists the resources left for you to review. `--plan` shows the same list before any change. By default, Workers, the Queues they use, KV, R2, Hyperdrive, the dispatch namespace, and AI Gateway remain in your account. Adopted resources, external PostgreSQL, and zones are always retained. Email Routing settings are retained; `--purge-resources` removes only the rules that send mail to the platform. DNS records, routes, custom domains, and Cloudflare Access resources are retained unless you use `--purge-resources`.

When uninstall finishes, the record of what was kept stays at `~/.void/platforms/<account-id>/<installation-id>.json`. Without `--purge-data`, the encrypted credentials file `<installation-id>.recovery.enc` next to it is kept too. Delete both once you have finished the manual cleanup below.

To also remove eligible data resources owned by the installer:

```sh
void platform uninstall [id] --purge-data
```

Even with `--purge-data`, Void retains Workers, the Queues they use, R2, AI Gateway, DNS records, routes, custom domains, Access resources, adopted resources, external PostgreSQL, and zones. Review those in the Cloudflare dashboard if you want to remove them.
Even with `--purge-data`, Void retains Workers, the Queues they use, R2, AI Gateway, DNS records, routes, custom domains, Access resources, adopted resources, external PostgreSQL, and zones. Review those in the Cloudflare dashboard if you want to remove them, or use `--purge-resources`.

### Remove everything Void created

To delete every Cloudflare resource the installation created:

```sh
void platform uninstall [id] --purge-resources --plan
void platform uninstall [id] --purge-resources
```

`--purge-resources` includes `--purge-data`. It also deletes the platform Workers, Queues, the application Workers left in the dispatch namespace, the R2 bucket and its objects, the AI Gateway, the platform DNS record, Worker routes and custom domains, and the Access applications and service tokens the installer created. The plan lists each resource in deletion order, and everything that stays. If Cloudflare shows that the AI Gateway was created after installation, for example because it was deleted and created again under the same name, it is kept and listed.

If the platform sends email, it first deletes the Email Routing rules in the sender domain's zone that send mail to the platform email gateway Worker, and resets such a catch-all rule to drop mail. It leaves Email Routing enabled and keeps the sender domain's MX, SPF, and DKIM records.

It never removes zones, adopted resources, external PostgreSQL, other Email Routing settings, Analytics Engine datasets, Access policies or identity providers you chose, or API tokens. Revoke the API tokens you created for the platform afterward.

Before it changes anything, `--purge-resources` stops if:

- projects remain. Delete each one with `void project delete <name>` first.
- the credential cannot make every planned deletion. Browser login cannot delete DNS records or Access resources, so set `CLOUDFLARE_API_TOKEN` to a token with the permissions the plan lists. If you connected Access from a separate identity account, the token also needs the Access permissions in that account. If the platform sends email, it also needs **Zone → Email Routing Rules → Edit** for the sender domain's zone.

If a route, custom domain, DNS record, or Access resource no longer matches what the installation recorded, for example a route that now sends traffic to another Worker, it is kept and listed with the reason, and uninstall continues. Do not run `--purge-resources` while someone else is changing the platform's Workers, routes, or custom domains: a change made after Void checks a resource and before it deletes it is not detected.

If Cloudflare refuses a deletion, for example because a Worker you created yourself still sends logs to the platform tail Worker, uninstall stops and names the resource. Fix it, then rerun the same command to continue.

If a plain or `--purge-data` uninstall stopped before it finished, rerun it with `--purge-resources` to also delete what it kept. Once an uninstall finishes, use the manual steps below instead.

### Remove retained resources

Cloudflare refuses to delete a resource while a platform Worker still uses it. In the Cloudflare dashboard, remove what is left in this order, skipping anything already gone:
After an uninstall without `--purge-resources`, Cloudflare refuses to delete a resource while a platform Worker still uses it. In the Cloudflare dashboard, remove what is left in this order, skipping anything already gone:

1. Delete the platform DNS record, Worker routes, and custom domains.
2. Open each platform Queue and remove the platform API Worker from its consumers.
3. Delete the platform Workers.
4. Delete the platform Queues.
5. Delete the application Workers in the dispatch namespace, then delete the namespace.
6. Delete the platform KV namespaces and Hyperdrive configuration.
7. Empty the R2 bucket, then delete it.
8. Delete the AI Gateway.
2. If the platform sends email, open **Email Routing** for the sender domain's zone. Delete the routing rules and any catch-all rule that send mail to the platform email gateway Worker. Then remove the sender subdomain from Email Routing, or disable Email Routing if you enabled it only for the platform.
3. Open each platform Queue and remove the platform API Worker from its consumers.
4. Delete the platform Workers, except the tail Worker (its name ends in `-tail`).
5. Delete the platform Queues.
6. Delete the application Workers in the dispatch namespace, then delete the namespace.
7. Delete the tail Worker. Cloudflare refuses while other Workers still send logs to it.
8. Delete the platform KV namespaces and Hyperdrive configuration.
9. Empty the R2 bucket, then delete it.
10. Delete the AI Gateway.

If installation configured Cloudflare Access, the uninstall plan lists its recorded applications and service tokens with their ownership and IDs. Review them in Zero Trust after uninstall. Remove installer-created resources only when nothing else uses them; resources connected from an existing company setup remain under their owner's control.

Expand Down
24 changes: 13 additions & 11 deletions docs/reference/cli/platform-installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ void platform rollback [id] --runtime <earlier-path> [--from-runtime <current-pa
void platform repair [id] [--runtime <path>] [--dashboard-url <origin>] [--plan] [--yes]
void platform disable [id] [--plan] [--yes]
void platform enable [id] [--runtime <path>] [--plan] [--yes]
void platform uninstall [id] [--plan] [--purge-data] [--keep-zone] [--yes]
void platform uninstall [id] [--plan] [--purge-data | --purge-resources] [--keep-zone] [--yes]
```

`discover --installation` limits recovery and endpoint verification to one installation in a shared Cloudflare account.
Expand All @@ -115,15 +115,15 @@ dashboard origin before maintenance can proceed. See [Optional Dashboard](../../

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.

| Command | Behavior |
| ----------- | --------------------------------------------------------------------------------------------- |
| `discover` | Verifies remote ownership and restores local installation records without downloading secrets |
| `repair` | Recreates missing resources owned by the installer |
| `upgrade` | Deploys the selected runtime and supported pending migrations |
| `rollback` | Restores a declared-compatible earlier runtime without reversing PostgreSQL migrations |
| `disable` | Blocks platform traffic through routing storage without removing data |
| `enable` | Restores traffic after checking the platform |
| `uninstall` | Blocks traffic and removes eligible resources, retaining data by default |
| Command | Behavior |
| ----------- | ----------------------------------------------------------------------------------------------------------- |
| `discover` | Verifies remote ownership and restores local installation records without downloading secrets |
| `repair` | Recreates missing resources owned by the installer |
| `upgrade` | Deploys the selected runtime and supported pending migrations |
| `rollback` | Restores a declared-compatible earlier runtime without reversing PostgreSQL migrations |
| `disable` | Blocks app traffic and the platform API without removing data; only admin status and sign-in stay available |
| `enable` | Redeploys and verifies the platform Workers, then restores traffic |
| `uninstall` | Blocks traffic and removes eligible resources, retaining data by default |

Repair and upgrade preserve disabled state. New, resumed, and previously disabled installations block user traffic until all target Workers pass verification; the installer's health probes can still run. Routes and custom domains remain attached.

Expand All @@ -137,6 +137,8 @@ An upgrade completes after the new Workers pass health checks. If rollout fails,

`platform rollback` restores a compatible earlier runtime without reversing database migrations. Pass its files with `--runtime`; if the installed version is custom, also supply that version with `--from-runtime`. Void refuses incompatible targets.

Uninstall verifies remote ownership before removing anything. Data resources are retained unless you pass `--purge-data`. Workers, the Queues they use, R2, AI Gateway, DNS records, routes, custom domains, adopted resources, external PostgreSQL, and zones are always retained for manual review.
Uninstall verifies remote ownership before removing anything. Data resources are retained unless you pass `--purge-data`. Workers, the Queues they use, R2, AI Gateway, DNS records, routes, custom domains, adopted resources, external PostgreSQL, and zones are retained for manual review.

`--purge-resources` includes `--purge-data` and also deletes every other resource the installation created, including Workers, Queues, R2, AI Gateway, the platform DNS record, routes, custom domains, and installer-created Access resources. It removes only the Email Routing rules that send mail to the platform email gateway, and keeps zones, adopted resources, external PostgreSQL, other Email Routing settings, and API tokens. A route, custom domain, DNS record, or Access resource that no longer matches the installation's record is kept and listed. It refuses before any change while projects remain or when the credential cannot make the planned deletions. Rerun the same command to continue after an interruption, or after a plain or `--purge-data` uninstall stopped.

See [Disable and Uninstall](../../guide/platform/installation/uninstall.md#remove-retained-resources) for the full removal policy and the cleanup order.
Loading
Loading