diff --git a/docs/how-to/create-a-repository.md b/docs/how-to/create-a-repository.md
index b56bbf4..129f346 100644
--- a/docs/how-to/create-a-repository.md
+++ b/docs/how-to/create-a-repository.md
@@ -55,7 +55,7 @@ install from the versioned snapshot under `.lvbt/web-platform`, so no registry l
- Rename the root package in `package.json`.
- Rename `packages/example`, `apps/site`, or `apps/app` to your first real package or app, or
scaffold one with `turbo gen workspace` and delete the sample. Deployable templates also need the
- Worker name in `apps/*/wrangler.jsonc` and, for a site, `site` in `astro.config.ts`.
+ Worker name in `apps/deploy/cloudflare.config.ts` and, for a site, `site` in `astro.config.ts`.
- Replace the scopes in `.lvbt/commit-scopes.txt` with this repository's boundaries.
- `.github/workflows/ci.yml` runs a job named `Validate`. Keep that name: the organization ruleset
requires it on every pull request. Add steps to the job.
diff --git a/docs/reference/examples.md b/docs/reference/examples.md
index aceade1..645fba1 100644
--- a/docs/reference/examples.md
+++ b/docs/reference/examples.md
@@ -45,13 +45,13 @@ files.
`with-astro` and `with-vite-react` carry everything above, minus `packages/example`, plus:
-| Path | Purpose |
-| ------------------------------ | ---------------------------------------------------------------------------------------------------- |
-| `apps/site` or `apps/app` | The application: source under `src/`, unit tests under `tests/`, end-to-end tests under `tests/e2e/` |
-| `apps/*/wrangler.jsonc` | A static-assets Worker serving `dist/`; `pnpm run deploy` deploys every app that has one |
-| `apps/*/playwright.config.ts` | Spreads `@lasvegasfortransit/playwright-config` and starts the app's `preview` server |
-| `.github/workflows/deploy.yml` | Validates, then runs `pnpm run deploy` on every push to `main` with the Cloudflare secrets |
-| root `preview` and `deploy` | `turbo run preview` and `lvbt deploy` |
+| Path | Purpose |
+| ---------------------------------- | ---------------------------------------------------------------------------------------------------- |
+| `apps/site` or `apps/app` | The application: source under `src/`, unit tests under `tests/`, end-to-end tests under `tests/e2e/` |
+| `apps/deploy/cloudflare.config.ts` | The `cf` Worker project, which serves the app's built static assets |
+| `apps/*/playwright.config.ts` | Spreads `@lasvegasfortransit/playwright-config` and starts the app's `preview` server |
+| `.github/workflows/deploy.yml` | Validates, then runs `pnpm run deploy` on every push to `main` with the Cloudflare secrets |
+| root `preview` and `deploy` | `turbo run preview` and `lvbt deploy`; CI builds the app and dry-runs `cf deploy` |
The Astro example also adds `prettier-plugin-astro` to its Prettier config and extends
`@lasvegasfortransit/typescript-config/astro.json`; the React example extends `react-library.json`
diff --git a/docs/reference/release-0-6-1.md b/docs/reference/release-0-6-1.md
new file mode 100644
index 0000000..2563333
--- /dev/null
+++ b/docs/reference/release-0-6-1.md
@@ -0,0 +1,14 @@
+# Repository tooling 0.6.1
+
+The Astro and Vite templates now deploy through `cf` from a separate `apps/deploy` package. This
+package reads the app's built static assets, preserving the existing Worker name, compatibility
+date, preview URLs, observability, and missing-page behavior. New templates contain one deploy
+target, so `lvbt deploy` cannot publish a second copy through Wrangler.
+
+`lvbt deploy` builds the app before invoking `cf deploy`. New repositories must provide
+`CLOUDFLARE_ACCOUNT_ID` and an account-owned `CLOUDFLARE_API_TOKEN` in their production GitHub
+environment. `cf` is still in beta; its Wrangler build adapter remains an explicit dependency of the
+deploy package. The required repository check builds the app and dry-runs its Cloudflare bundle.
+
+The source and new templates pin patched `brace-expansion`, `fast-uri`, and both supported `undici`
+major lines to avoid high-severity transitive advisories in the current toolchain.
diff --git a/examples/basic/.claude/settings.json b/examples/basic/.claude/settings.json
index 294578b..95b7427 100644
--- a/examples/basic/.claude/settings.json
+++ b/examples/basic/.claude/settings.json
@@ -4,7 +4,7 @@
"source": {
"source": "github",
"repo": "LasVegasForTransit/repository-tooling",
- "ref": "v0.6.0"
+ "ref": "v0.6.1"
}
}
},
diff --git a/examples/basic/package.json b/examples/basic/package.json
index 9774548..0adfa24 100644
--- a/examples/basic/package.json
+++ b/examples/basic/package.json
@@ -21,8 +21,8 @@
"*": "prettier --write --ignore-unknown"
},
"devDependencies": {
- "@lasvegasfortransit/cli": "0.6.0",
- "@lasvegasfortransit/prettier-config": "0.6.0",
+ "@lasvegasfortransit/cli": "0.6.1",
+ "@lasvegasfortransit/prettier-config": "0.6.1",
"lint-staged": "catalog:",
"markdownlint-cli2": "catalog:",
"markdownlint-rule-relative-links": "catalog:",
diff --git a/examples/basic/packages/example/package.json b/examples/basic/packages/example/package.json
index a5682ee..c8b17de 100644
--- a/examples/basic/packages/example/package.json
+++ b/examples/basic/packages/example/package.json
@@ -16,9 +16,9 @@
"test": "vitest run"
},
"devDependencies": {
- "@lasvegasfortransit/eslint-config": "0.6.0",
- "@lasvegasfortransit/typescript-config": "0.6.0",
- "@lasvegasfortransit/vitest-config": "0.6.0",
+ "@lasvegasfortransit/eslint-config": "0.6.1",
+ "@lasvegasfortransit/typescript-config": "0.6.1",
+ "@lasvegasfortransit/vitest-config": "0.6.1",
"@types/node": "catalog:",
"eslint": "catalog:",
"typescript": "catalog:",
diff --git a/examples/basic/pnpm-workspace.yaml b/examples/basic/pnpm-workspace.yaml
index e94d737..fec240d 100644
--- a/examples/basic/pnpm-workspace.yaml
+++ b/examples/basic/pnpm-workspace.yaml
@@ -16,7 +16,11 @@ minimumReleaseAge: 1440
# Temporary transitive pins for published security fixes not yet selected by
# their direct dependents.
overrides:
+ brace-expansion: 5.0.12
+ fast-uri: 3.1.8
sharp: 0.35.4
+ 'undici@^7.0.0': 7.29.1
+ 'undici@^8.0.0': 8.10.2
smol-toml: 1.8.0
svgo: 4.1.0
diff --git a/examples/with-astro/.claude/settings.json b/examples/with-astro/.claude/settings.json
index 294578b..95b7427 100644
--- a/examples/with-astro/.claude/settings.json
+++ b/examples/with-astro/.claude/settings.json
@@ -4,7 +4,7 @@
"source": {
"source": "github",
"repo": "LasVegasForTransit/repository-tooling",
- "ref": "v0.6.0"
+ "ref": "v0.6.1"
}
}
},
diff --git a/examples/with-astro/.gitignore b/examples/with-astro/.gitignore
index 4cf35a7..94646a7 100644
--- a/examples/with-astro/.gitignore
+++ b/examples/with-astro/.gitignore
@@ -7,6 +7,7 @@ blob-report/
**/playwright/.cache/
.turbo/
.wrangler/
+.cloudflare/
.env
.env.*
!.env.example
diff --git a/examples/with-astro/README.md b/examples/with-astro/README.md
index a787103..4bc99a9 100644
--- a/examples/with-astro/README.md
+++ b/examples/with-astro/README.md
@@ -15,7 +15,7 @@ pnpm check # the same check CI runs
pnpm dev # the site at http://127.0.0.1:4321
```
-Then rename the root package and the Worker in `apps/site/wrangler.jsonc`, set `site` in
+Then rename the root package and the Worker in `apps/deploy/cloudflare.config.ts`, set `site` in
`apps/site/astro.config.ts`, and replace the scopes in `.lvbt/commit-scopes.txt` with this
repository's boundaries.
@@ -23,9 +23,10 @@ repository's boundaries.
- `apps/site` is the Astro site: pages under `src/pages`, layouts under `src/layouts`, Tailwind in
`src/styles/global.css`, unit tests under `tests/`, end-to-end tests under `tests/e2e/`
+- `apps/deploy` holds the `cf` Worker configuration and reads `apps/site/dist` after the site build
- `packages/` for libraries the site shares with other apps
-`pnpm run deploy` builds and deploys every app with a `cloudflare.config.ts` or Wrangler config;
+`pnpm run deploy` builds the site and deploys the canonical `cf` project in `apps/deploy`;
`.github/workflows/deploy.yml` does the same on every push to `main`.
Lint, format, TypeScript, and test settings extend the `@lasvegasfortransit/*` packages from
diff --git a/examples/with-astro/apps/deploy/cloudflare.config.ts b/examples/with-astro/apps/deploy/cloudflare.config.ts
new file mode 100644
index 0000000..9be2e6e
--- /dev/null
+++ b/examples/with-astro/apps/deploy/cloudflare.config.ts
@@ -0,0 +1,16 @@
+import { defineConfig } from 'cf/config';
+
+// Set CLOUDFLARE_ACCOUNT_ID in the deploy environment before publishing.
+export default defineConfig({
+ worker: {
+ name: 'lvbt-site',
+ compatibilityDate: '2026-08-31',
+ previewUrls: true,
+ assets: {
+ notFoundHandling: '404-page',
+ },
+ observability: {
+ enabled: true,
+ },
+ },
+});
diff --git a/examples/with-astro/apps/deploy/eslint.config.js b/examples/with-astro/apps/deploy/eslint.config.js
new file mode 100644
index 0000000..fe2b986
--- /dev/null
+++ b/examples/with-astro/apps/deploy/eslint.config.js
@@ -0,0 +1,3 @@
+import { config } from '@lasvegasfortransit/eslint-config/base';
+
+export default config;
diff --git a/examples/with-astro/apps/deploy/package.json b/examples/with-astro/apps/deploy/package.json
new file mode 100644
index 0000000..06d9c97
--- /dev/null
+++ b/examples/with-astro/apps/deploy/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "@lasvegasfortransit/deploy",
+ "version": "0.0.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "lint": "eslint . --max-warnings 0",
+ "check-types": "tsc --noEmit",
+ "test": "node --test",
+ "validate": "cf deploy --dry-run"
+ },
+ "devDependencies": {
+ "@lasvegasfortransit/eslint-config": "0.6.1",
+ "@lasvegasfortransit/site": "workspace:*",
+ "@lasvegasfortransit/typescript-config": "0.6.1",
+ "cf": "catalog:",
+ "eslint": "catalog:",
+ "typescript": "catalog:",
+ "wrangler": "catalog:"
+ }
+}
diff --git a/examples/with-astro/apps/deploy/tsconfig.json b/examples/with-astro/apps/deploy/tsconfig.json
new file mode 100644
index 0000000..424aa9e
--- /dev/null
+++ b/examples/with-astro/apps/deploy/tsconfig.json
@@ -0,0 +1,4 @@
+{
+ "extends": "@lasvegasfortransit/typescript-config/base.json",
+ "include": ["*.config.ts"]
+}
diff --git a/examples/with-astro/apps/deploy/wrangler.config.ts b/examples/with-astro/apps/deploy/wrangler.config.ts
new file mode 100644
index 0000000..2cb09ad
--- /dev/null
+++ b/examples/with-astro/apps/deploy/wrangler.config.ts
@@ -0,0 +1,8 @@
+import { defineWranglerConfig } from 'wrangler/experimental-config';
+
+export default defineWranglerConfig({
+ types: {
+ generate: false,
+ },
+ assetsDirectory: '../site/dist',
+});
diff --git a/examples/with-astro/apps/site/package.json b/examples/with-astro/apps/site/package.json
index 153e7bf..d896c56 100644
--- a/examples/with-astro/apps/site/package.json
+++ b/examples/with-astro/apps/site/package.json
@@ -21,10 +21,10 @@
},
"devDependencies": {
"@astrojs/check": "catalog:",
- "@lasvegasfortransit/eslint-config": "0.6.0",
- "@lasvegasfortransit/playwright-config": "0.6.0",
- "@lasvegasfortransit/typescript-config": "0.6.0",
- "@lasvegasfortransit/vitest-config": "0.6.0",
+ "@lasvegasfortransit/eslint-config": "0.6.1",
+ "@lasvegasfortransit/playwright-config": "0.6.1",
+ "@lasvegasfortransit/typescript-config": "0.6.1",
+ "@lasvegasfortransit/vitest-config": "0.6.1",
"@playwright/test": "catalog:",
"@types/node": "catalog:",
"eslint": "catalog:",
diff --git a/examples/with-astro/apps/site/wrangler.jsonc b/examples/with-astro/apps/site/wrangler.jsonc
deleted file mode 100644
index a4aab15..0000000
--- a/examples/with-astro/apps/site/wrangler.jsonc
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "$schema": "./node_modules/wrangler/config-schema.json",
- // The Worker name. Rename it before the first deploy.
- "name": "lvbt-site",
- "compatibility_date": "2026-08-31",
- "preview_urls": true,
- "assets": {
- "directory": "./dist",
- "not_found_handling": "404-page",
- },
- "observability": {
- "enabled": true,
- },
-}
diff --git a/examples/with-astro/docs/development/reference/glossary.md b/examples/with-astro/docs/development/reference/glossary.md
index 55588ff..c3eaa61 100644
--- a/examples/with-astro/docs/development/reference/glossary.md
+++ b/examples/with-astro/docs/development/reference/glossary.md
@@ -51,7 +51,7 @@ request. The required status is named `Validate`.
deploy this repository, with a fix printed for anything missing.
**Platform manifest**: `platform.json`, next to an app's production
-`wrangler.jsonc`, which lists everything the app needs in production: its database, bucket, bot
-check, admin sign-in, email domain, secrets, and the values that must never be set there.
+configuration, which lists everything the app needs in production: its database, bucket, bot check,
+admin sign-in, email domain, secrets, and the values that must never be set there.
`pnpm preflight --production` checks production against it, and `pnpm bootstrap --production` sets
up what is missing.
diff --git a/examples/with-astro/docs/development/tutorials/start-here.md b/examples/with-astro/docs/development/tutorials/start-here.md
index 3646d2c..f22ffcc 100644
--- a/examples/with-astro/docs/development/tutorials/start-here.md
+++ b/examples/with-astro/docs/development/tutorials/start-here.md
@@ -34,7 +34,7 @@ prints one line per check:
ok git hooks core.hooksPath is .githooks
ok commit scopes .lvbt/commit-scopes.txt is present
ok GitHub CLI gh is installed and signed in
- ok Cloudflare wrangler is signed in; deployables: apps/site
+ ok Cloudflare cf ready for: apps/deploy
preflight: all 7 checks passed
```
@@ -47,9 +47,9 @@ pnpm check
```
This is the same command CI runs: formatting, documentation links, the repository-shape rules, then
-lint, typecheck, and tests for every package. On a fresh clone it passes. When it fails, the output
-names the package and file; `pnpm check:fix` repairs everything a machine can (formatting and
-auto-fixable lint findings).
+lint, typecheck, tests, a site build, and a Cloudflare deploy dry run. On a fresh clone it passes.
+When it fails, the output names the package and file; `pnpm check:fix` repairs formatting and
+auto-fixable lint findings.
## 3. Make a change and commit it
diff --git a/examples/with-astro/package.json b/examples/with-astro/package.json
index 3819e56..07fe528 100644
--- a/examples/with-astro/package.json
+++ b/examples/with-astro/package.json
@@ -23,8 +23,8 @@
"*": "prettier --write --ignore-unknown"
},
"devDependencies": {
- "@lasvegasfortransit/cli": "0.6.0",
- "@lasvegasfortransit/prettier-config": "0.6.0",
+ "@lasvegasfortransit/cli": "0.6.1",
+ "@lasvegasfortransit/prettier-config": "0.6.1",
"lint-staged": "catalog:",
"markdownlint-cli2": "catalog:",
"markdownlint-rule-relative-links": "catalog:",
diff --git a/examples/with-astro/pnpm-workspace.yaml b/examples/with-astro/pnpm-workspace.yaml
index e94d737..fec240d 100644
--- a/examples/with-astro/pnpm-workspace.yaml
+++ b/examples/with-astro/pnpm-workspace.yaml
@@ -16,7 +16,11 @@ minimumReleaseAge: 1440
# Temporary transitive pins for published security fixes not yet selected by
# their direct dependents.
overrides:
+ brace-expansion: 5.0.12
+ fast-uri: 3.1.8
sharp: 0.35.4
+ 'undici@^7.0.0': 7.29.1
+ 'undici@^8.0.0': 8.10.2
smol-toml: 1.8.0
svgo: 4.1.0
diff --git a/examples/with-vite-react/.claude/settings.json b/examples/with-vite-react/.claude/settings.json
index 294578b..95b7427 100644
--- a/examples/with-vite-react/.claude/settings.json
+++ b/examples/with-vite-react/.claude/settings.json
@@ -4,7 +4,7 @@
"source": {
"source": "github",
"repo": "LasVegasForTransit/repository-tooling",
- "ref": "v0.6.0"
+ "ref": "v0.6.1"
}
}
},
diff --git a/examples/with-vite-react/.gitignore b/examples/with-vite-react/.gitignore
index 65717d9..393f057 100644
--- a/examples/with-vite-react/.gitignore
+++ b/examples/with-vite-react/.gitignore
@@ -7,6 +7,7 @@ blob-report/
**/playwright/.cache/
.turbo/
.wrangler/
+.cloudflare/
.env
.env.*
!.env.example
diff --git a/examples/with-vite-react/README.md b/examples/with-vite-react/README.md
index a787103..42ad025 100644
--- a/examples/with-vite-react/README.md
+++ b/examples/with-vite-react/README.md
@@ -15,17 +15,17 @@ pnpm check # the same check CI runs
pnpm dev # the site at http://127.0.0.1:4321
```
-Then rename the root package and the Worker in `apps/site/wrangler.jsonc`, set `site` in
-`apps/site/astro.config.ts`, and replace the scopes in `.lvbt/commit-scopes.txt` with this
-repository's boundaries.
+Then rename the root package and the Worker in `apps/deploy/cloudflare.config.ts`, and replace the
+scopes in `.lvbt/commit-scopes.txt` with this repository's boundaries.
## Layout
-- `apps/site` is the Astro site: pages under `src/pages`, layouts under `src/layouts`, Tailwind in
- `src/styles/global.css`, unit tests under `tests/`, end-to-end tests under `tests/e2e/`
+- `apps/app` is the Vite app: source under `src/`, unit tests under `tests/`, and end-to-end tests
+ under `tests/e2e/`
+- `apps/deploy` holds the `cf` Worker configuration and reads `apps/app/dist` after the app build
- `packages/` for libraries the site shares with other apps
-`pnpm run deploy` builds and deploys every app with a `cloudflare.config.ts` or Wrangler config;
+`pnpm run deploy` builds the app and deploys the canonical `cf` project in `apps/deploy`;
`.github/workflows/deploy.yml` does the same on every push to `main`.
Lint, format, TypeScript, and test settings extend the `@lasvegasfortransit/*` packages from
diff --git a/examples/with-vite-react/apps/app/package.json b/examples/with-vite-react/apps/app/package.json
index 6a301e1..ab8dd5c 100644
--- a/examples/with-vite-react/apps/app/package.json
+++ b/examples/with-vite-react/apps/app/package.json
@@ -17,10 +17,10 @@
"react-dom": "catalog:"
},
"devDependencies": {
- "@lasvegasfortransit/eslint-config": "0.6.0",
- "@lasvegasfortransit/playwright-config": "0.6.0",
- "@lasvegasfortransit/typescript-config": "0.6.0",
- "@lasvegasfortransit/vitest-config": "0.6.0",
+ "@lasvegasfortransit/eslint-config": "0.6.1",
+ "@lasvegasfortransit/playwright-config": "0.6.1",
+ "@lasvegasfortransit/typescript-config": "0.6.1",
+ "@lasvegasfortransit/vitest-config": "0.6.1",
"@playwright/test": "catalog:",
"@tailwindcss/vite": "catalog:",
"@types/node": "catalog:",
diff --git a/examples/with-vite-react/apps/app/wrangler.jsonc b/examples/with-vite-react/apps/app/wrangler.jsonc
deleted file mode 100644
index 9c876a5..0000000
--- a/examples/with-vite-react/apps/app/wrangler.jsonc
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "$schema": "./node_modules/wrangler/config-schema.json",
- // The Worker name. Rename it before the first deploy.
- "name": "lvbt-app",
- "compatibility_date": "2026-08-31",
- "preview_urls": true,
- "assets": {
- "directory": "./dist",
- "not_found_handling": "single-page-application",
- },
- "observability": {
- "enabled": true,
- },
-}
diff --git a/examples/with-vite-react/apps/deploy/cloudflare.config.ts b/examples/with-vite-react/apps/deploy/cloudflare.config.ts
new file mode 100644
index 0000000..f5541d9
--- /dev/null
+++ b/examples/with-vite-react/apps/deploy/cloudflare.config.ts
@@ -0,0 +1,16 @@
+import { defineConfig } from 'cf/config';
+
+// Set CLOUDFLARE_ACCOUNT_ID in the deploy environment before publishing.
+export default defineConfig({
+ worker: {
+ name: 'lvbt-app',
+ compatibilityDate: '2026-08-31',
+ previewUrls: true,
+ assets: {
+ notFoundHandling: 'single-page-application',
+ },
+ observability: {
+ enabled: true,
+ },
+ },
+});
diff --git a/examples/with-vite-react/apps/deploy/eslint.config.js b/examples/with-vite-react/apps/deploy/eslint.config.js
new file mode 100644
index 0000000..fe2b986
--- /dev/null
+++ b/examples/with-vite-react/apps/deploy/eslint.config.js
@@ -0,0 +1,3 @@
+import { config } from '@lasvegasfortransit/eslint-config/base';
+
+export default config;
diff --git a/examples/with-vite-react/apps/deploy/package.json b/examples/with-vite-react/apps/deploy/package.json
new file mode 100644
index 0000000..2415f96
--- /dev/null
+++ b/examples/with-vite-react/apps/deploy/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "@lasvegasfortransit/deploy",
+ "version": "0.0.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "lint": "eslint . --max-warnings 0",
+ "check-types": "tsc --noEmit",
+ "test": "node --test",
+ "validate": "cf deploy --dry-run"
+ },
+ "devDependencies": {
+ "@lasvegasfortransit/eslint-config": "0.6.1",
+ "@lasvegasfortransit/app": "workspace:*",
+ "@lasvegasfortransit/typescript-config": "0.6.1",
+ "cf": "catalog:",
+ "eslint": "catalog:",
+ "typescript": "catalog:",
+ "wrangler": "catalog:"
+ }
+}
diff --git a/examples/with-vite-react/apps/deploy/tsconfig.json b/examples/with-vite-react/apps/deploy/tsconfig.json
new file mode 100644
index 0000000..424aa9e
--- /dev/null
+++ b/examples/with-vite-react/apps/deploy/tsconfig.json
@@ -0,0 +1,4 @@
+{
+ "extends": "@lasvegasfortransit/typescript-config/base.json",
+ "include": ["*.config.ts"]
+}
diff --git a/examples/with-vite-react/apps/deploy/wrangler.config.ts b/examples/with-vite-react/apps/deploy/wrangler.config.ts
new file mode 100644
index 0000000..fa36cac
--- /dev/null
+++ b/examples/with-vite-react/apps/deploy/wrangler.config.ts
@@ -0,0 +1,8 @@
+import { defineWranglerConfig } from 'wrangler/experimental-config';
+
+export default defineWranglerConfig({
+ types: {
+ generate: false,
+ },
+ assetsDirectory: '../app/dist',
+});
diff --git a/examples/with-vite-react/docs/development/reference/glossary.md b/examples/with-vite-react/docs/development/reference/glossary.md
index 55588ff..c3eaa61 100644
--- a/examples/with-vite-react/docs/development/reference/glossary.md
+++ b/examples/with-vite-react/docs/development/reference/glossary.md
@@ -51,7 +51,7 @@ request. The required status is named `Validate`.
deploy this repository, with a fix printed for anything missing.
**Platform manifest**: `platform.json`, next to an app's production
-`wrangler.jsonc`, which lists everything the app needs in production: its database, bucket, bot
-check, admin sign-in, email domain, secrets, and the values that must never be set there.
+configuration, which lists everything the app needs in production: its database, bucket, bot check,
+admin sign-in, email domain, secrets, and the values that must never be set there.
`pnpm preflight --production` checks production against it, and `pnpm bootstrap --production` sets
up what is missing.
diff --git a/examples/with-vite-react/docs/development/tutorials/start-here.md b/examples/with-vite-react/docs/development/tutorials/start-here.md
index dc39c88..acf377f 100644
--- a/examples/with-vite-react/docs/development/tutorials/start-here.md
+++ b/examples/with-vite-react/docs/development/tutorials/start-here.md
@@ -34,7 +34,7 @@ prints one line per check:
ok git hooks core.hooksPath is .githooks
ok commit scopes .lvbt/commit-scopes.txt is present
ok GitHub CLI gh is installed and signed in
- ok Cloudflare wrangler is signed in; deployables: apps/app
+ ok Cloudflare cf ready for: apps/deploy
preflight: all 7 checks passed
```
@@ -47,9 +47,9 @@ pnpm check
```
This is the same command CI runs: formatting, documentation links, the repository-shape rules, then
-lint, typecheck, and tests for every package. On a fresh clone it passes. When it fails, the output
-names the package and file; `pnpm check:fix` repairs everything a machine can (formatting and
-auto-fixable lint findings).
+lint, typecheck, tests, an app build, and a Cloudflare deploy dry run. On a fresh clone it passes.
+When it fails, the output names the package and file; `pnpm check:fix` repairs formatting and
+auto-fixable lint findings.
## 3. Make a change and commit it
diff --git a/examples/with-vite-react/package.json b/examples/with-vite-react/package.json
index de29b0b..a4261bc 100644
--- a/examples/with-vite-react/package.json
+++ b/examples/with-vite-react/package.json
@@ -23,8 +23,8 @@
"*": "prettier --write --ignore-unknown"
},
"devDependencies": {
- "@lasvegasfortransit/cli": "0.6.0",
- "@lasvegasfortransit/prettier-config": "0.6.0",
+ "@lasvegasfortransit/cli": "0.6.1",
+ "@lasvegasfortransit/prettier-config": "0.6.1",
"lint-staged": "catalog:",
"markdownlint-cli2": "catalog:",
"markdownlint-rule-relative-links": "catalog:",
diff --git a/examples/with-vite-react/pnpm-workspace.yaml b/examples/with-vite-react/pnpm-workspace.yaml
index e94d737..fec240d 100644
--- a/examples/with-vite-react/pnpm-workspace.yaml
+++ b/examples/with-vite-react/pnpm-workspace.yaml
@@ -16,7 +16,11 @@ minimumReleaseAge: 1440
# Temporary transitive pins for published security fixes not yet selected by
# their direct dependents.
overrides:
+ brace-expansion: 5.0.12
+ fast-uri: 3.1.8
sharp: 0.35.4
+ 'undici@^7.0.0': 7.29.1
+ 'undici@^8.0.0': 8.10.2
smol-toml: 1.8.0
svgo: 4.1.0
diff --git a/package.json b/package.json
index 4fcbc04..1f9ae0e 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "lvbt-repository-tooling",
"private": true,
- "version": "0.6.0",
+ "version": "0.6.1",
"type": "module",
"description": "Source of truth for the LVBT repository standard: the shared @lasvegasfortransit packages and the example repositories create-turbo copies.",
"packageManager": "pnpm@11.25.0",
@@ -39,6 +39,7 @@
"@types/react-dom": "catalog:",
"@vitejs/plugin-react": "catalog:",
"astro": "catalog:",
+ "cf": "catalog:",
"eslint": "catalog:",
"lint-staged": "catalog:",
"markdownlint-cli2": "catalog:",
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 497fb58..6c90379 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@lasvegasfortransit/cli",
- "version": "0.6.0",
+ "version": "0.6.1",
"description": "The lvbt command every LVBT repository runs for bootstrap, preflight, and deploy, plus the production platform setup, the shared git hooks, and the lvbt-contributions agent plugin.",
"license": "MIT",
"type": "module",
diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json
index dbc81e9..bfb8e9a 100644
--- a/packages/eslint-config/package.json
+++ b/packages/eslint-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@lasvegasfortransit/eslint-config",
- "version": "0.6.0",
+ "version": "0.6.1",
"description": "The ESLint configurations every LVBT repository uses.",
"license": "MIT",
"type": "module",
diff --git a/packages/playwright-config/package.json b/packages/playwright-config/package.json
index ad22bff..f706fb5 100644
--- a/packages/playwright-config/package.json
+++ b/packages/playwright-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@lasvegasfortransit/playwright-config",
- "version": "0.6.0",
+ "version": "0.6.1",
"description": "The Playwright configuration every LVBT repository spreads into its own: end-to-end tests under tests/e2e, desktop and mobile projects, traces on failure.",
"license": "MIT",
"type": "module",
diff --git a/packages/prettier-config/package.json b/packages/prettier-config/package.json
index 284568f..d7a43ad 100644
--- a/packages/prettier-config/package.json
+++ b/packages/prettier-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@lasvegasfortransit/prettier-config",
- "version": "0.6.0",
+ "version": "0.6.1",
"description": "The Prettier configuration every LVBT repository uses.",
"license": "MIT",
"type": "module",
diff --git a/packages/typescript-config/package.json b/packages/typescript-config/package.json
index ff21f71..e3747a2 100644
--- a/packages/typescript-config/package.json
+++ b/packages/typescript-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@lasvegasfortransit/typescript-config",
- "version": "0.6.0",
+ "version": "0.6.1",
"description": "TypeScript configurations every LVBT repository extends.",
"license": "MIT",
"repository": {
diff --git a/packages/vitest-config/package.json b/packages/vitest-config/package.json
index 5e7f867..ce83c81 100644
--- a/packages/vitest-config/package.json
+++ b/packages/vitest-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@lasvegasfortransit/vitest-config",
- "version": "0.6.0",
+ "version": "0.6.1",
"description": "The Vitest configuration every LVBT repository spreads into its own.",
"license": "MIT",
"type": "module",
diff --git a/packages/web-platform/package.json b/packages/web-platform/package.json
index e03030d..31e77b3 100644
--- a/packages/web-platform/package.json
+++ b/packages/web-platform/package.json
@@ -1,6 +1,6 @@
{
"name": "@lasvegasfortransit/web-platform",
- "version": "0.6.0",
+ "version": "0.6.1",
"description": "Provider-neutral deployment, provisioning, and validation primitives for LVBT web repositories.",
"license": "MIT",
"type": "module",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index db1789a..dcc878c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -33,6 +33,9 @@ catalogs:
astro:
specifier: 7.2.10
version: 7.2.10
+ cf:
+ specifier: 1.0.0-beta.5
+ version: 1.0.0-beta.5
eslint:
specifier: 10.9.1
version: 10.9.1
@@ -80,7 +83,11 @@ catalogs:
version: 4.141.0
overrides:
+ brace-expansion: 5.0.12
+ fast-uri: 3.1.8
sharp: 0.35.4
+ undici@^7.0.0: 7.29.1
+ undici@^8.0.0: 8.10.2
smol-toml: 1.8.0
svgo: 4.1.0
@@ -133,6 +140,9 @@ importers:
astro:
specifier: 'catalog:'
version: 7.2.10(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@24.13.3)(jiti@2.7.0)(tsx@4.23.13)(yaml@2.9.0)
+ cf:
+ specifier: 'catalog:'
+ version: 1.0.0-beta.5(@types/node@24.13.3)
eslint:
specifier: 'catalog:'
version: 10.9.1(jiti@2.7.0)(supports-color@10.2.2)
@@ -491,10 +501,23 @@ packages:
resolution: {integrity: sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==}
engines: {node: '>= 20.12.0'}
+ '@cloudflare/build-output-utils@0.8.2':
+ resolution: {integrity: sha512-DHKF7p5p1ZapZbh2GyF3mfBW7D45IKtcnwMdKnVZ72A/a2rfwd1kczBYFH+O4cHnNI7e9HRwTm+Z76IDZfxVLw==}
+
+ '@cloudflare/codemods@0.2.1':
+ resolution: {integrity: sha512-nAoXTs5JPlQ8HeaTJQaxkvbJtGjXG19HoNx/W/Cz1d2PBETAt1Pdv4KqKqMw62DNq6Wfh4lwG2lJLvyn4X+Rhg==}
+ hasBin: true
+
+ '@cloudflare/config@0.20.0':
+ resolution: {integrity: sha512-Dv/UDLkqsmvW95+CmM2nE55pdkLPWnJ63KDMjAFe/5KW1hc2SzJW4f8CUagqarivQugf5+oJMWYlHSmtA4KVlA==}
+
'@cloudflare/kv-asset-handler@0.5.0':
resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==}
engines: {node: '>=22.0.0'}
+ '@cloudflare/runtime-types@0.1.4':
+ resolution: {integrity: sha512-Jp3Za6h0KybVoi/4D6La3HicW71L8nyS7AGf0WHpbKqCs17lLkCuTbOcAuUTraoib8+SR74L+AbqxwcDq3VhTw==}
+
'@cloudflare/unenv-preset@2.16.2':
resolution: {integrity: sha512-JBP1+Z7ZSNG/d4mRP+y8VC5dka3tZVMLEZRvS+rzQ4DGV1EoxRFQckcJTTkXbHSQiTj0DtNI01Zwb/V2fX0mvQ==}
peerDependencies:
@@ -510,30 +533,60 @@ packages:
cpu: [x64]
os: [darwin]
+ '@cloudflare/workerd-darwin-64@1.20260926.1':
+ resolution: {integrity: sha512-VCIpwgJu5Dm1o+VHLclNOKIdpttEqss7oDHS5DYxgVoonM9Dxxxr1xCQvJbh6IXFuQ1DDrbm5krjte5NsTgX3Q==}
+ engines: {node: '>=16'}
+ cpu: [x64]
+ os: [darwin]
+
'@cloudflare/workerd-darwin-arm64@1.20260925.1':
resolution: {integrity: sha512-b3BLoP9NkF6b2QOQFs8wFfOt9XSH3jVtacdGn9lcvkUCdPq7F6CfDlleHqyQEnDfZ32lH5jgMRTdaMHUPf/XbA==}
engines: {node: '>=16'}
cpu: [arm64]
os: [darwin]
+ '@cloudflare/workerd-darwin-arm64@1.20260926.1':
+ resolution: {integrity: sha512-oVuLXfCnr1Xu9sBMNYrEPcFZQNMcviNcacz9l+oqQiLHc5UrVp++lpKbsuWstCfh+/c39Pp37TVeaNBLA8+ReA==}
+ engines: {node: '>=16'}
+ cpu: [arm64]
+ os: [darwin]
+
'@cloudflare/workerd-linux-64@1.20260925.1':
resolution: {integrity: sha512-LczXd6uEMqEmBxBJPFwplRIwKmUHqj5t8hilIWOtbX5i0TFp7/iMYBXbAiIhvZnev+8yiTyA7uWBBjDvfPh5Ug==}
engines: {node: '>=16'}
cpu: [x64]
os: [linux]
+ '@cloudflare/workerd-linux-64@1.20260926.1':
+ resolution: {integrity: sha512-BjmiDvYBVBG5248gCHSZS3yONbcm3/3qKTu9RaQA8o7jQHJfXx9JnWbhkld2KsbXnRGEGHFwpLLidIpIGtQYUA==}
+ engines: {node: '>=16'}
+ cpu: [x64]
+ os: [linux]
+
'@cloudflare/workerd-linux-arm64@1.20260925.1':
resolution: {integrity: sha512-hziOugQbLuva85w8z9bGJbEtABKzSip653x0NgvxgP/Q3n1TpRqRyIJRBufbSUZRkJlfH2se2nQaTx2OU0TT3g==}
engines: {node: '>=16'}
cpu: [arm64]
os: [linux]
+ '@cloudflare/workerd-linux-arm64@1.20260926.1':
+ resolution: {integrity: sha512-28bdfQDIFcpaKXMPisADy8BchpIsX+tEAhD+bhfEBXukFGFr8F3ouyiG3HzN3CqAh/OYvifJizzFZtptUPCy7w==}
+ engines: {node: '>=16'}
+ cpu: [arm64]
+ os: [linux]
+
'@cloudflare/workerd-windows-64@1.20260925.1':
resolution: {integrity: sha512-mG0JYuF6HVCgXSsNeB5os8Vtdprk5jHPysviKNNMHJSLA3Q1djFjSmK4+pnQR/zOAgzNo0HJ+Tpcz+tZj1Q7fQ==}
engines: {node: '>=16'}
cpu: [x64]
os: [win32]
+ '@cloudflare/workerd-windows-64@1.20260926.1':
+ resolution: {integrity: sha512-ehdL3ataKdEmlnW9oom6OZUR8n3XsTL/zl8+KGREpLi5sMSW0mek0PrF4wK9SX51f3Alnlu8tF8eKBg+mc3xFw==}
+ engines: {node: '>=16'}
+ cpu: [x64]
+ os: [win32]
+
'@cspotcode/source-map-support@0.8.1':
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
@@ -1738,8 +1791,8 @@ packages:
boolbase@1.0.0:
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
- brace-expansion@5.0.9:
- resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==}
+ brace-expansion@5.0.12:
+ resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==}
engines: {node: 20 || >=22}
braces@3.0.3:
@@ -1765,6 +1818,11 @@ packages:
ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
+ cf@1.0.0-beta.5:
+ resolution: {integrity: sha512-IKGKDAQNs8hbu7jOt3qSWKxDjmJTS+hcHCJ5B0IkF7gZ3RmEfMTUxZ0Fi7GRftjag04J127u8Nk8uppXx3OBZw==}
+ engines: {node: '>=22'}
+ hasBin: true
+
chai@6.2.2:
resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
engines: {node: '>=18'}
@@ -2057,8 +2115,8 @@ packages:
fast-string-width@3.0.2:
resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==}
- fast-uri@3.1.6:
- resolution: {integrity: sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==}
+ fast-uri@3.1.8:
+ resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==}
fast-wrap-ansi@0.2.2:
resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==}
@@ -2610,10 +2668,17 @@ packages:
resolution: {integrity: sha512-ly2ygNOfuouMiPcyTNEUW6f3+zgndfC45e1nQZ2LSciOSFfrih8V7ciaZ01I/64Ccp3F6fWraxh5VuHPsP3AAw==}
engines: {node: '>=22.0.0'}
+ miniflare@5.20260926.0-alpha:
+ resolution: {integrity: sha512-m/M3rpLnaouw6QSoKzylfw6Z1dnOwRM48idnZ7kc5ivRqBXANFQ8XqKCyQ/V+xqQ9Rg1L99j4WkZGVU9uT4L2w==}
+ engines: {node: '>=22.0.0'}
+
minimatch@10.2.6:
resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==}
engines: {node: 18 || 20 || >=22}
+ minisearch@7.2.0:
+ resolution: {integrity: sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==}
+
mrmime@2.0.1:
resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
engines: {node: '>=10'}
@@ -3058,12 +3123,12 @@ packages:
undici-types@7.18.2:
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
- undici@7.29.0:
- resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==}
+ undici@7.29.1:
+ resolution: {integrity: sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==}
engines: {node: '>=20.18.1'}
- undici@8.10.1:
- resolution: {integrity: sha512-YQ3WlbqjYMmNpdvDH64jAgLjxuAR9+649calDWhbshYaeQGO2bR4nI94ORJmwI3J9YhoKQnpyGOK+0zlWS5N5Q==}
+ undici@8.10.2:
+ resolution: {integrity: sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==}
engines: {node: '>=22.19.0'}
unenv@2.0.0-rc.24:
@@ -3390,6 +3455,11 @@ packages:
engines: {node: '>=16'}
hasBin: true
+ workerd@1.20260926.1:
+ resolution: {integrity: sha512-YojhsWBuZwk3Jk9OC0QfTgVbLeQOD1tK1olC9ZXAUcmeip8z4NE/xtttpxCsuTvQBRqppvy7Tkac0kxPYMjIXA==}
+ engines: {node: '>=16'}
+ hasBin: true
+
wrangler@4.141.0:
resolution: {integrity: sha512-8+LRZEcynBMfVYgO4N378z5XyuajaILt2IzsdWRLCHrRWz7mmGWv4igdVjqbRQMJtE0S5bSmyz0W2XpA6UM/ow==}
engines: {node: '>=22.0.0'}
@@ -3468,6 +3538,9 @@ packages:
peerDependencies:
zod: ^3.25.0 || ^4.0.0
+ zod@4.4.3:
+ resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
+
zod@4.5.4:
resolution: {integrity: sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==}
@@ -3759,8 +3832,27 @@ snapshots:
fast-wrap-ansi: 0.2.2
sisteransi: 1.0.5
+ '@cloudflare/build-output-utils@0.8.2':
+ dependencies:
+ '@cloudflare/config': 0.20.0
+
+ '@cloudflare/codemods@0.2.1': {}
+
+ '@cloudflare/config@0.20.0':
+ dependencies:
+ zod: 4.4.3
+
'@cloudflare/kv-asset-handler@0.5.0': {}
+ '@cloudflare/runtime-types@0.1.4(@types/node@24.13.3)':
+ dependencies:
+ miniflare: 5.20260926.0-alpha(@types/node@24.13.3)
+ workerd: 1.20260926.1
+ transitivePeerDependencies:
+ - '@types/node'
+ - bufferutil
+ - utf-8-validate
+
'@cloudflare/unenv-preset@2.16.2(unenv@2.0.0-rc.24)(workerd@1.20260925.1)':
dependencies:
unenv: 2.0.0-rc.24
@@ -3770,18 +3862,33 @@ snapshots:
'@cloudflare/workerd-darwin-64@1.20260925.1':
optional: true
+ '@cloudflare/workerd-darwin-64@1.20260926.1':
+ optional: true
+
'@cloudflare/workerd-darwin-arm64@1.20260925.1':
optional: true
+ '@cloudflare/workerd-darwin-arm64@1.20260926.1':
+ optional: true
+
'@cloudflare/workerd-linux-64@1.20260925.1':
optional: true
+ '@cloudflare/workerd-linux-64@1.20260926.1':
+ optional: true
+
'@cloudflare/workerd-linux-arm64@1.20260925.1':
optional: true
+ '@cloudflare/workerd-linux-arm64@1.20260926.1':
+ optional: true
+
'@cloudflare/workerd-windows-64@1.20260925.1':
optional: true
+ '@cloudflare/workerd-windows-64@1.20260926.1':
+ optional: true
+
'@cspotcode/source-map-support@0.8.1':
dependencies:
'@jridgewell/trace-mapping': 0.3.9
@@ -4680,7 +4787,7 @@ snapshots:
ajv@8.20.0:
dependencies:
fast-deep-equal: 3.1.3
- fast-uri: 3.1.6
+ fast-uri: 3.1.8
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
@@ -4810,7 +4917,7 @@ snapshots:
boolbase@1.0.0: {}
- brace-expansion@5.0.9:
+ brace-expansion@5.0.12:
dependencies:
balanced-match: 4.0.4
@@ -4834,6 +4941,20 @@ snapshots:
ccount@2.0.1: {}
+ cf@1.0.0-beta.5(@types/node@24.13.3):
+ dependencies:
+ '@cloudflare/build-output-utils': 0.8.2
+ '@cloudflare/codemods': 0.2.1
+ '@cloudflare/config': 0.20.0
+ '@cloudflare/runtime-types': 0.1.4(@types/node@24.13.3)
+ blake3-wasm: 2.1.5
+ miniflare: 5.20260926.0-alpha(@types/node@24.13.3)
+ minisearch: 7.2.0
+ transitivePeerDependencies:
+ - '@types/node'
+ - bufferutil
+ - utf-8-validate
+
chai@6.2.2: {}
character-entities-html4@2.1.0: {}
@@ -5180,7 +5301,7 @@ snapshots:
dependencies:
fast-string-truncated-width: 3.0.3
- fast-uri@3.1.6: {}
+ fast-uri@3.1.8: {}
fast-wrap-ansi@0.2.2:
dependencies:
@@ -5776,7 +5897,7 @@ snapshots:
dependencies:
'@cspotcode/source-map-support': 0.8.1
sharp: 0.35.4(@types/node@24.13.3)
- undici: 7.29.0
+ undici: 7.29.1
workerd: 1.20260925.1
ws: 8.21.0
youch: 4.1.0-beta.10
@@ -5785,9 +5906,24 @@ snapshots:
- bufferutil
- utf-8-validate
+ miniflare@5.20260926.0-alpha(@types/node@24.13.3):
+ dependencies:
+ '@cspotcode/source-map-support': 0.8.1
+ sharp: 0.35.4(@types/node@24.13.3)
+ undici: 7.29.1
+ workerd: 1.20260926.1
+ ws: 8.21.0
+ youch: 4.1.0-beta.10
+ transitivePeerDependencies:
+ - '@types/node'
+ - bufferutil
+ - utf-8-validate
+
minimatch@10.2.6:
dependencies:
- brace-expansion: 5.0.9
+ brace-expansion: 5.0.12
+
+ minisearch@7.2.0: {}
mrmime@2.0.1: {}
@@ -6237,9 +6373,9 @@ snapshots:
undici-types@7.18.2: {}
- undici@7.29.0: {}
+ undici@7.29.1: {}
- undici@8.10.1: {}
+ undici@8.10.2: {}
unenv@2.0.0-rc.24:
dependencies:
@@ -6261,7 +6397,7 @@ snapshots:
dependencies:
css-tree: 3.2.1
ohash: 2.0.12
- undici: 8.10.1
+ undici: 8.10.2
unist-util-is@6.0.1:
dependencies:
@@ -6490,6 +6626,14 @@ snapshots:
'@cloudflare/workerd-linux-arm64': 1.20260925.1
'@cloudflare/workerd-windows-64': 1.20260925.1
+ workerd@1.20260926.1:
+ optionalDependencies:
+ '@cloudflare/workerd-darwin-64': 1.20260926.1
+ '@cloudflare/workerd-darwin-arm64': 1.20260926.1
+ '@cloudflare/workerd-linux-64': 1.20260926.1
+ '@cloudflare/workerd-linux-arm64': 1.20260926.1
+ '@cloudflare/workerd-windows-64': 1.20260926.1
+
wrangler@4.141.0(@types/node@24.13.3):
dependencies:
'@cloudflare/kv-asset-handler': 0.5.0
@@ -6572,6 +6716,8 @@ snapshots:
dependencies:
zod: 4.5.4
+ zod@4.4.3: {}
+
zod@4.5.4: {}
zwitch@2.0.4: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 9c4d163..c93f5f6 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -15,7 +15,11 @@ minimumReleaseAge: 1440
# Temporary transitive pins for published security fixes not yet selected by
# their direct dependents.
overrides:
+ brace-expansion: 5.0.12
+ fast-uri: 3.1.8
sharp: 0.35.4
+ 'undici@^7.0.0': 7.29.1
+ 'undici@^8.0.0': 8.10.2
smol-toml: 1.8.0
svgo: 4.1.0
diff --git a/tests/example.test.mjs b/tests/example.test.mjs
index 495dc36..741802e 100644
--- a/tests/example.test.mjs
+++ b/tests/example.test.mjs
@@ -137,7 +137,7 @@ for (const [name, { uses, deploys }] of Object.entries(examples)) {
Object.assign(specifiers, manifest.dependencies, manifest.devDependencies);
}
for (const [dependency, range] of Object.entries(specifiers)) {
- if (dependency.startsWith('@lasvegasfortransit/')) {
+ if (sharedPackages.some((shared) => dependency === `@lasvegasfortransit/${shared}`)) {
assert.equal(range, version, `${dependency} must be pinned to ${version}`);
}
}
@@ -436,7 +436,7 @@ test('source and generated repositories pin audited transitive fixes', async ()
);
assert.match(
workspace,
- /^overrides:\n {2}sharp: 0\.35\.4\n {2}smol-toml: 1\.8\.0\n {2}svgo: 4\.1\.0$/m,
+ /^overrides:\n {2}brace-expansion: 5\.0\.12\n {2}fast-uri: 3\.1\.8\n {2}sharp: 0\.35\.4\n {2}'undici@\^7\.0\.0': 7\.29\.1\n {2}'undici@\^8\.0\.0': 8\.10\.2\n {2}smol-toml: 1\.8\.0\n {2}svgo: 4\.1\.0$/m,
);
}
});
diff --git a/tests/web-platform.test.mjs b/tests/web-platform.test.mjs
index 04e309b..90820fd 100644
--- a/tests/web-platform.test.mjs
+++ b/tests/web-platform.test.mjs
@@ -7,6 +7,7 @@ import path from 'node:path';
import { applyPreset, verifyPreset, fingerprint } from '../standards/web-platform.ts';
import { readCommit, readRelease } from '../standards/web-platform-source.ts';
+import { deployables } from '../packages/cli/src/lib/operate.mjs';
async function fixture(run) {
const directory = await mkdtemp(path.join(os.tmpdir(), 'lvbt-preset-'));
@@ -211,13 +212,33 @@ test('reads an unpublished preset only from an exact commit', () =>
assert.throws(() => readCommit(repository, 'main'), /full commit/i);
}));
-test('web profiles preserve immutable Worker version previews', async () => {
- for (const file of [
- 'examples/with-astro/apps/site/wrangler.jsonc',
- 'examples/with-vite-react/apps/app/wrangler.jsonc',
+test('web profiles deploy once through cf and preserve Worker version previews', async () => {
+ const root = new URL('..', import.meta.url).pathname;
+ for (const profile of ['with-astro', 'with-vite-react']) {
+ const example = path.join(root, 'examples', profile);
+ assert.deepEqual(await deployables(example), [{ directory: 'apps/deploy', tool: 'cf' }]);
+ const config = await readFile(path.join(example, 'apps/deploy/cloudflare.config.ts'), 'utf8');
+ assert.match(config, /previewUrls: true/);
+ }
+});
+
+test('web profiles validate the cf bundle after building their app', () => {
+ const root = new URL('..', import.meta.url).pathname;
+ for (const [profile, app] of [
+ ['with-astro', 'site'],
+ ['with-vite-react', 'app'],
]) {
- const config = await readFile(path.join(new URL('..', import.meta.url).pathname, file), 'utf8');
- assert.match(config, /"preview_urls": true/);
+ const example = path.join(root, 'examples', profile);
+ const result = spawnSync(
+ path.join(root, 'node_modules/turbo/bin/turbo'),
+ ['run', 'validate', '--dry-run=json', '--cwd', example],
+ { encoding: 'utf8' },
+ );
+ assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`);
+ const tasks = JSON.parse(result.stdout).tasks;
+ const deploy = tasks.find((task) => task.taskId === '@lasvegasfortransit/deploy#validate');
+ assert.equal(deploy?.command, 'cf deploy --dry-run');
+ assert.deepEqual(deploy.dependencies, [`@lasvegasfortransit/${app}#build`]);
}
});