Skip to content

Commit efcaf75

Browse files
committed
Merge remote-tracking branch 'origin/main' into docs-update-main-page
2 parents a7dadaf + 7546eb8 commit efcaf75

819 files changed

Lines changed: 51699 additions & 43582 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/scripts/packed-consumer.mjs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ try {
176176
[join(root, '.github/scripts/packed-init.mjs'), fixture, framework, manager, version],
177177
work,
178178
);
179+
const agentInstructions = readFileSync(join(fixture, 'AGENTS.md'), 'utf8');
180+
assert.equal(agentInstructions.match(/^- /gm)?.length, 2);
181+
assert(agentInstructions.includes('node_modules/void/docs/'));
182+
assert(existsSync(join(fixture, 'node_modules/void/docs/guide/quickstart.md')));
179183
assert(
180184
existsSync(join(fixture, '.git')),
181185
'Init should initialize the accepted Git repository',

‎.github/scripts/packed-registry.mjs‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ export function inspectPackage(tarball) {
1212
const files = new Set(
1313
execFileSync('tar', ['-tf', tarball], { encoding: 'utf8' }).trim().split(/\r?\n/),
1414
);
15+
if (manifest.name === 'void') {
16+
for (const file of [
17+
'docs/guide/quickstart.md',
18+
'docs/reference/cli.md',
19+
'skills/void/SKILL.md',
20+
'skills/migrate-vite-cloudflare-to-void/SKILL.md',
21+
'AGENTS_TEMPLATE.md',
22+
]) {
23+
assert(files.has(`package/${file}`), `void: missing bundled ${file}`);
24+
}
25+
assert(
26+
![...files].some((file) => file.startsWith('package/skills/void/docs/')),
27+
'void: docs must be bundled at the package root',
28+
);
29+
}
1530
for (const field of [
1631
'dependencies',
1732
'optionalDependencies',
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { spawnSync } from 'node:child_process';
2+
import { readFileSync } from 'node:fs';
3+
// eslint-disable-next-line no-restricted-imports -- Native filesystem paths are never embedded in source.
4+
import { join } from 'node:path';
5+
import { fileURLToPath, pathToFileURL } from 'node:url';
6+
import { parseSync } from 'vite';
7+
import { isRecord } from '../../packages/deploy-core/src/is-record.ts';
8+
import { compatibilityTestFiles } from './schema-compat-tests.ts';
9+
10+
function memberName(node: unknown): string | undefined {
11+
if (!isRecord(node) || node.type !== 'MemberExpression' || !isRecord(node.property)) {
12+
return undefined;
13+
}
14+
if (!node.computed && node.property.type === 'Identifier') {
15+
return typeof node.property.name === 'string' ? node.property.name : undefined;
16+
}
17+
return node.computed && typeof node.property.value === 'string' ? node.property.value : undefined;
18+
}
19+
20+
function usesPostgresEnvironment(node: unknown): boolean {
21+
if (Array.isArray(node)) {
22+
return node.some(usesPostgresEnvironment);
23+
}
24+
if (!isRecord(node)) {
25+
return false;
26+
}
27+
if (
28+
memberName(node) === 'VOID_TEST_DATABASE_URL' &&
29+
isRecord(node.object) &&
30+
memberName(node.object) === 'env' &&
31+
isRecord(node.object.object) &&
32+
node.object.object.type === 'Identifier' &&
33+
node.object.object.name === 'process'
34+
) {
35+
return true;
36+
}
37+
return Object.values(node).some(usesPostgresEnvironment);
38+
}
39+
40+
/** Select real PostgreSQL cases without repeating the whole in-memory API suite. */
41+
export function postgresConcurrencyTestFiles(root: string): Array<string> {
42+
const files = compatibilityTestFiles(root).filter((file) => {
43+
const parsed = parseSync(file, readFileSync(join(root, file), 'utf8'));
44+
if (parsed.errors.length > 0) {
45+
throw new Error(`Cannot inspect PostgreSQL test coverage in ${file}.`);
46+
}
47+
return usesPostgresEnvironment(parsed.program);
48+
});
49+
if (files.length === 0) {
50+
throw new Error('No PostgreSQL concurrency test files were found.');
51+
}
52+
return files;
53+
}
54+
55+
if (process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url) {
56+
const files = postgresConcurrencyTestFiles(process.cwd());
57+
// Reuse the bounded runner's independent database clones and cleanup for every file.
58+
const result = spawnSync(
59+
process.execPath,
60+
[fileURLToPath(new URL('./schema-compat-tests.ts', import.meta.url)), ...files],
61+
{ stdio: 'inherit' },
62+
);
63+
if (result.error) {
64+
throw result.error;
65+
}
66+
process.exitCode = result.status ?? 1;
67+
}

‎.github/workflows/platform-ci.yml‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ on:
1414
- '.github/scripts/production-baseline.ts'
1515
- '.github/scripts/schema-fixture.mjs'
1616
- '.github/scripts/schema-compat-tests.ts'
17+
- '.github/scripts/postgres-concurrency-tests.ts'
1718
workflow_call:
1819
inputs:
1920
require-schema-compat:
@@ -89,6 +90,48 @@ jobs:
8990
- run: vp run --filter './platform/packages/**' build
9091
- run: vp test run --project '${{ matrix.project }}*'
9192

93+
postgres-concurrency:
94+
runs-on: ${{ github.repository == 'voidzero-dev/void' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-latest' }}
95+
timeout-minutes: 10
96+
permissions:
97+
contents: read
98+
env:
99+
POSTGRES_USER: void_ci
100+
POSTGRES_PASSWORD: void_ci_pass
101+
POSTGRES_DB: void_schema_compat
102+
COMPAT_DATABASE_URL: postgresql://void_ci:void_ci_pass@localhost:5432/void_schema_compat
103+
TZ: UTC
104+
services:
105+
postgres:
106+
image: postgres:18
107+
env:
108+
POSTGRES_USER: ${{ env.POSTGRES_USER }}
109+
POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
110+
POSTGRES_DB: ${{ env.POSTGRES_DB }}
111+
ports:
112+
- 5432:5432
113+
options: >-
114+
--health-cmd="pg_isready -U $POSTGRES_USER"
115+
--health-interval=5s
116+
--health-timeout=5s
117+
--health-retries=5
118+
steps:
119+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
120+
with:
121+
persist-credentials: false
122+
- uses: voidzero-dev/setup-vp@1b32467adbe183473499fd9d5d372c3ed9641754 # v1.18.0
123+
with:
124+
cache: true
125+
node-version-file: .node-version
126+
- run: vp run build
127+
- run: vp run --filter './platform/packages/**' build
128+
- name: Create the candidate PostgreSQL schema
129+
run: vp run --filter @voidcloud/api migrate
130+
env:
131+
DATABASE_URL: ${{ env.COMPAT_DATABASE_URL }}
132+
- name: Run candidate PostgreSQL concurrency tests
133+
run: node .github/scripts/postgres-concurrency-tests.ts
134+
92135
# Upgrade a populated previous schema, then run that immutable runtime's tests.
93136
# The prod branch can already be the candidate, so never use it as the baseline.
94137
schema-compat:

‎AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ own README under `packages/{react,vue,svelte,solid}`.
8888
The [API reference](./docs/reference/api.md) and
8989
[CLI reference](./docs/reference/cli.md) describe the supported public surface.
9090

91-
`packages/void/skills/void/docs` is ignored by Git and copied from `docs/`
91+
`packages/void/docs` is ignored by Git and copied from `docs/`
9292
during the build. Edit the source documentation instead.
9393

9494
## Tooling

‎README.md‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
# Void
22

3-
Full-stack apps with [Vite](https://vite.dev), running on Cloudflare Workers.
3+
Build and deploy full-stack apps with [Vite](https://vite.dev), running on Cloudflare Workers.
44

5-
Build APIs and server-rendered pages with typed access to databases, storage, and AI. Void detects the resources your app uses and provisions them when you deploy. Use React, Vue, Svelte, Solid, or a [supported framework](https://void.cloud/integrations/frameworks/overview).
5+
Void brings together three open-source tools for you and your coding agents:
6+
7+
- **Void SDK:** Build your server and client together with file-based API routes, server-rendered pages, and typed APIs for databases, storage, and AI. Carry types from database queries to the UI.
8+
- **Void CLI:** Build your app, provision the Cloudflare resources it uses, apply migrations, and deploy with one command. Manage resources, inspect logs, and roll back through the same CLI.
9+
- **Void Platform:** Install a shared deployment environment in your Cloudflare account for your team or customers, with access controls, resource limits, and usage reporting.
10+
11+
The SDK's features are optional and composable. Use React, Vue, Svelte, or Solid for Void pages, or keep a [supported application framework](https://void.cloud/integrations/frameworks/overview) for routing and rendering while Void handles resource APIs, migrations, and deployment.
612

713
## Getting Started
814

@@ -20,19 +26,23 @@ Choose your UI framework and starter, then select Cloudflare to deploy to your a
2026
npx void deploy
2127
```
2228

23-
Void builds the app, provisions resources, applies database migrations, and prints your deployed URL. Follow the [Quickstart](https://void.cloud/guide/quickstart) to explore your app or add Void to an existing Vite project.
29+
Void builds the app, provisions resources, applies database migrations, and prints your deployed URL. Follow the [Quickstart](https://void.cloud/guide/quickstart) for your first app or to add Void to an existing Vite project.
30+
31+
To deploy to a team platform, run `npx void connect <url>` first, then use the same deploy command. See [Install a Void Platform](https://void.cloud/guide/self-hosted-platform) to host one in your Cloudflare account or customize its open-source runtime.
2432

2533
## Documentation
2634

27-
- [How Void works](https://void.cloud/guide/)
35+
Read the [Void documentation](https://void.cloud) online or use the Markdown guides and references in `node_modules/void/docs/`, included with the `void` package.
36+
37+
`void init` adds a minimal `AGENTS.md` in new projects and asks before changing instructions in existing projects. It also links bundled skills for detected coding agents.
38+
2839
- [Server routes](https://void.cloud/guide/server-routing) and [pages](https://void.cloud/guide/pages-routing/overview)
2940
- [Database](https://void.cloud/guide/database) and [type safety](https://void.cloud/guide/type-safety)
3041
- [Deployment](https://void.cloud/guide/deployment)
3142
- [Framework integrations](https://void.cloud/integrations/frameworks/overview)
43+
- [API](https://void.cloud/reference/api) and [CLI](https://void.cloud/reference/cli) reference
3244
- [Coding agents](https://void.cloud/integrations/agents)
3345

34-
Teams can [install a Void platform](https://void.cloud/guide/self-hosted-platform) in a shared Cloudflare account. The framework, CLI, and platform source are included in this repository.
35-
3646
## Contributing
3747

3848
```sh

‎TESTING.md‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,14 @@ API integration fixtures reset their tables with one ordered SQL block. Use `cle
166166
than repeating per-table cleanup; it keeps foreign-key delete behavior and migration history
167167
intact in PGlite and PostgreSQL.
168168

169+
Platform CI runs the candidate's PostgreSQL concurrency cases in a separate job. The selector
170+
finds API integration files that read `process.env.VOID_TEST_DATABASE_URL`, excluding mentions
171+
in comments or strings. Each selected file runs against its own database clone, with two files
172+
in flight, using the same bounded runner as schema compatibility. This exercises real locks
173+
without repeating the entire API suite. To run it locally, migrate a disposable loopback
174+
`void_schema_compat` database as `void_ci`, then set `COMPAT_DATABASE_URL` and run
175+
`node .github/scripts/postgres-concurrency-tests.ts`.
176+
169177
Staging CI on main also runs the production schema-compatibility gate, so its failures are caught
170178
before tagging a release. The job copies the candidate's `.github/scripts/schema-compat-tests.ts` runner
171179
before checking out the deployed revision. It runs every deployed API test file against its own
@@ -221,6 +229,14 @@ utility and Bash; it has no Python or native npm dependency.
221229

222230
## Browser readiness and Windows CI
223231

232+
Pages scroll regressions run in Chromium by default. On a machine with Playwright WebKit support,
233+
run the same document navigation, reload, SPA navigation, and suspended-render cases in WebKit:
234+
235+
```sh
236+
vp exec playwright install webkit
237+
VOID_TEST_BROWSER=webkit vp test run packages/react/test/integration packages/vue/test/integration packages/svelte/test/integration packages/solid/test/integration -t 'restores.*scroll'
238+
```
239+
224240
Use `waitForIslandsHydrated` from `test/browser-helpers.ts` before asserting island state or
225241
interacting with islands. Pass the expected minimum count when checking a multi-island fixture.
226242
Each island imports and hydrates independently, so a selector matching one hydrated island does
@@ -308,7 +324,7 @@ Use the intended test account rather than an account name embedded in a script.
308324
- setting `CLOUDFLARE_ACCOUNT_ID` in the current shell.
309325

310326
When a version has no preview URL, also set `CLOUDFLARE_WORKERS_SUBDOMAIN` to the account's
311-
workers.dev subdomain. For `https://my-worker.my-team.workers.dev`, the value is `my-team`. The
327+
workers.dev subdomain. For [`https://my-worker.my-team.workers.dev`](https://my-worker.my-team.workers.dev), the value is `my-team`. The
312328
account name shown in the dashboard is not necessarily the workers.dev subdomain.
313329

314330
Never commit account IDs, resource IDs, API tokens, or Access credentials. CI should receive them

‎docs/.vitepress/redirects/reference-cli.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,6 @@
110110
"void-email-domain-remove": "/reference/cli/email#void-email-domain-remove",
111111
"void-email-status": "/reference/cli/email#void-email-status",
112112
"void-email-setup": "/reference/cli/email#void-email-setup",
113-
"agent": "/reference/cli/setup#agent",
114-
"void-init-agents": "/reference/cli/setup#void-init-agents"
113+
"agent": "/reference/cli/setup#void-init",
114+
"void-init-agents": "/reference/cli/setup#void-init"
115115
}

‎docs/.vitepress/theme/FileTree.vue‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,6 @@ const TreeNode = defineComponent({
365365
color: var(--vp-c-brand-1);
366366
}
367367
368-
/* Adapter tabs */
369368
/* Adapter tabs */
370369
.adapter-tabs {
371370
display: flex;

0 commit comments

Comments
 (0)