From 6a19dfc0cec69225ad6ee334f04642d49b2b9929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E8=A7=81=E6=99=93=E7=A9=BA?= Date: Fri, 28 Aug 2026 14:46:08 +0800 Subject: [PATCH 1/8] ci: harden verification and deployment workflows --- .github/workflows/ci.yml | 27 +++- .github/workflows/deploy.yml | 119 ++++++++++++++++++ docs/ROADMAP.md | 8 +- .../subman-skill/references/deployment.md | 41 +++--- docs/ci-cd.md | 88 +++++++++++++ package.json | 5 +- playwright.config.ts | 8 +- src/github-actions.test.ts | 72 +++++++++++ 8 files changed, 343 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/deploy.yml create mode 100644 docs/ci-cd.md create mode 100644 src/github-actions.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 772bc30..546045b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ on: branches: - main pull_request: + workflow_dispatch: permissions: contents: read @@ -15,11 +16,13 @@ concurrency: jobs: verify: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 20 steps: - name: Check out repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 + with: + persist-credentials: false - name: Set up Bun uses: oven-sh/setup-bun@v2 @@ -29,9 +32,6 @@ jobs: - name: Install dependencies run: bun install --frozen-lockfile - - name: Install Chromium - run: bunx playwright install --with-deps chromium - - name: Run unit tests run: bun test @@ -47,5 +47,22 @@ jobs: - name: Run Cloudflare integration tests run: bun run test:cf + - name: Verify Cloudflare deployment bundle + run: bunx wrangler deploy --dry-run --outdir .wrangler/deploy-check + + - name: Install Chromium + run: bunx playwright install --with-deps chromium + - name: Run browser tests run: bun run test:e2e + + - name: Upload browser failure artifacts + if: failure() + uses: actions/upload-artifact@v7 + with: + name: playwright-artifacts-${{ github.run_id }} + path: | + playwright-report/ + test-results/ + if-no-files-found: ignore + retention-days: 7 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..d840c37 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,119 @@ +name: Deploy production + +on: + workflow_dispatch: + inputs: + confirmation: + description: Type "deploy" to confirm a production deployment from main + required: true + type: string + +permissions: + contents: read + +concurrency: + group: deploy-production + cancel-in-progress: false + +jobs: + gate: + runs-on: ubuntu-24.04 + timeout-minutes: 2 + steps: + - name: Validate deployment request + env: + CONFIRMATION: ${{ inputs.confirmation }} + run: | + if [[ "$GITHUB_REF" != "refs/heads/main" ]]; then + echo "::error::Production deployments must run from the main branch." + exit 1 + fi + if [[ "$CONFIRMATION" != "deploy" ]]; then + echo "::error::Enter deploy in the confirmation field." + exit 1 + fi + + deploy: + needs: gate + runs-on: ubuntu-24.04 + timeout-minutes: 20 + environment: + name: production + steps: + - name: Validate deployment credentials + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + run: | + if [[ -z "$CLOUDFLARE_API_TOKEN" ]]; then + echo "::error::Missing production environment secret CLOUDFLARE_API_TOKEN." + exit 1 + fi + if [[ -z "$CLOUDFLARE_ACCOUNT_ID" ]]; then + echo "::error::Missing production environment secret CLOUDFLARE_ACCOUNT_ID." + exit 1 + fi + + - name: Check out repository + uses: actions/checkout@v6 + with: + persist-credentials: false + + - name: Set up Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.14 + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Run unit tests + run: bun test + + - name: Run type and Svelte checks + run: bun run check + + - name: Run lint + run: bun run lint + + - name: Build + run: bun run build + + - name: Run Cloudflare integration tests + run: bun run test:cf + + - name: Verify Cloudflare deployment bundle + run: bunx wrangler deploy --dry-run --outdir .wrangler/deploy-check + + - name: Install Chromium + run: bunx playwright install --with-deps chromium + + - name: Run browser tests + run: bun run test:e2e + + - name: Deploy Worker + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + run: bunx wrangler deploy --strict --message "GitHub Actions ${GITHUB_SHA}" + + - name: Record deployment summary + run: | + { + echo "### SubMan production deployment" + echo "" + echo "- Commit: \`${GITHUB_SHA}\`" + echo "- Workflow run: \`${GITHUB_RUN_ID}\`" + echo "- Environment: \`production\`" + } >> "$GITHUB_STEP_SUMMARY" + + - name: Upload browser failure artifacts + if: failure() + uses: actions/upload-artifact@v7 + with: + name: deploy-playwright-artifacts-${{ github.run_id }} + path: | + playwright-report/ + test-results/ + if-no-files-found: ignore + retention-days: 7 diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 57c5c4f..6c236c7 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -25,6 +25,10 @@ not a promise to deploy or mutate a production Workspace. - Structured Worker observability with an allowlisted field set and hashed Workspace identifiers. Wrangler type generation is reproducible and checked for drift. +- GitHub CI validates generated Worker types, the Cloudflare integration suite, + a Wrangler deployment dry run, and browser behavior through the local Workers + runtime before Chromium-dependent checks. Production deployment is an + explicit, environment-gated workflow rather than an automatic push action. ## Next product and reliability work @@ -39,7 +43,8 @@ not a promise to deploy or mutate a production Workspace. Workspace or production evidence. 4. Keep generated Worker types and Cloudflare configuration in the normal local and CI verification path; change the compatibility date only after the - complete runtime, Cloudflare, and browser gates pass. + complete runtime, Cloudflare, browser, deployment dry-run, and type gates + pass. ## Deferred Workspace V3 design work @@ -67,6 +72,7 @@ bun run check bun run lint bun run build bun run test:cf +bun run deploy:check bun run test:e2e ``` diff --git a/docs/agents/subman-skill/references/deployment.md b/docs/agents/subman-skill/references/deployment.md index 3fe40f9..ff30cde 100644 --- a/docs/agents/subman-skill/references/deployment.md +++ b/docs/agents/subman-skill/references/deployment.md @@ -5,13 +5,14 @@ Install and validate: ```bash -bun install +bun install --frozen-lockfile bun test bun run check bun run lint bun run build bun run test:cf -bun wrangler deploy --dry-run +bun run deploy:check +bun run test:e2e ``` Local runtimes: @@ -21,6 +22,14 @@ bun run dev bun run dev:cf -- --ip :: --port 8787 ``` +`dev:cf` builds first and then starts `wrangler dev --local`, which is the +required local runtime when validating Durable Object exports, migrations, and +bindings. The Vite development server remains the faster UI-only path. + +GitHub Actions behavior, required production environment secrets, and the +historical Worker-type CI failure are documented in +[`docs/ci-cd.md`](../../../ci-cd.md). + ## Worker types and compatibility date `src/worker-configuration.d.ts` is generated from `wrangler.toml`: @@ -38,10 +47,10 @@ configuration and declaration drift fails locally and in CI. The current compatibility date is intentionally the newest date supported by the local Workers test runtime. Advance it only after the complete build, -Cloudflare, browser, and type-generation gates pass, then rerun all gates. If a -local `workerd` or Wrangler binary reports that a newer date is unsupported, -upgrade that toolchain first or keep the last supported date; do not silently -skip the Cloudflare test suite. +Cloudflare, browser, deployment dry-run, and type-generation gates pass, then +rerun all gates. If a local `workerd` or Wrangler binary reports that a newer +date is unsupported, upgrade that toolchain first or keep the last supported +date; do not silently skip the Cloudflare test suite. ## Safe Worker observability @@ -56,8 +65,8 @@ code, and safe GitHub operation/status/category/request ID metadata. Never add tokens, Authorization or Cookie values, subscription URLs, raw proxy URIs, mutation payloads, Workspace documents, generated outputs, quarantine contents, exception messages, or stacks to Worker logs. Tombstone counts may be -warnings, but they never authorize compaction. There is no time-based cleanup -of tombstones or processed mutations. +warnings, but they never authorize compaction. There is no time-based cleanup of +tombstones or processed mutations. Deploy only with explicit operator approval: @@ -65,6 +74,10 @@ Deploy only with explicit operator approval: bun run deploy ``` +The deploy script builds and uses Wrangler strict mode. For GitHub Actions, use +the manually dispatched `Deploy production` workflow; do not add a push-triggered +production deploy. + ## Durable Object Configuration `wrangler.toml` binds one SQLite-backed coordinator class: @@ -97,8 +110,8 @@ bun wrangler secret put SUBMAN_API_TOKEN Worker request and coordinator RPC. - `SUBMAN_API_TOKEN`: bearer token for trusted backend scripts. -Neither secret belongs in source, Wrangler variables, mutation payloads, or -local test fixtures. +Neither secret belongs in source, Wrangler variables, mutation payloads, GitHub +Actions deployment credentials, or local test fixtures. ## Post-Deployment Verification @@ -139,9 +152,9 @@ Follow `docs/workspace-v2-operations.md`. In particular: The browser UI can still run in local mode without a GitHub token. Business state remains in the `subman-workspace` IndexedDB database; only explicit token -persistence uses localStorage. -The trusted Server API always depends on Worker secrets and the -`WORKSPACE_COORDINATOR` binding. +persistence uses localStorage. The trusted Server API always depends on Worker +secrets and the `WORKSPACE_COORDINATOR` binding. For the current URI support matrix, subscription CORS requirements, and export -publication boundary, see [`docs/sing-box-export.md`](../../../sing-box-export.md). +publication boundary, see +[`docs/sing-box-export.md`](../../../sing-box-export.md). diff --git a/docs/ci-cd.md b/docs/ci-cd.md new file mode 100644 index 0000000..69aaf46 --- /dev/null +++ b/docs/ci-cd.md @@ -0,0 +1,88 @@ +# SubMan CI/CD + +## Continuous integration + +The `CI` workflow runs for pushes to `main`, pull requests, and manual +dispatches. It uses the repository-pinned Bun and Wrangler toolchain and keeps +`GITHUB_TOKEN` read-only. + +The verification order is intentionally fail-fast: + +1. install the frozen lockfile; +2. run unit tests; +3. run Svelte and TypeScript checks, including generated Worker type drift; +4. run Biome; +5. build the SvelteKit Worker; +6. run the Cloudflare Durable Object integration suite; +7. run `wrangler deploy --dry-run` and retain its bundle under + `.wrangler/deploy-check`; +8. install Chromium and run Playwright through `wrangler dev --local`. + +Using Wrangler for the browser server validates the generated Worker entrypoint, +the `WORKSPACE_COORDINATOR` class export, the Durable Object migration, and +Workers Assets configuration. Plain `vite preview` is not accepted as evidence +for those Cloudflare runtime boundaries. + +When Playwright fails, traces, screenshots, videos, and reports are uploaded as +a seven-day GitHub Actions artifact. If an earlier gate fails, the workflow does +not spend time installing Chromium. + +## Historical CI failure + +The formal `CI` run on 2026-08-24 (`run #5`, commit +`e82147c5d370734c27a03fa681fccf07028721d8`) passed all unit tests, then failed +the type and Svelte check stage because `check:worker-types` detected a stale +generated declaration. Wrangler had stopped generating the obsolete +`Cloudflare.GlobalProps.durableNamespaces` declaration, while the checked-in +`src/worker-configuration.d.ts` still contained it. + +The correction is committed in the current line: + +```bash +bun run generate:worker-types +bun run check:worker-types +``` + +Do not hand-edit the generated declaration. Any future `wrangler.toml`, Wrangler, +binding, migration, or compatibility-date change must regenerate the file and +pass the complete CI workflow. + +## Production deployment + +Production deployment is intentionally not automatic. Use the +`Deploy production` workflow from the `main` branch and enter `deploy` in the +confirmation input. + +The deployment job references the GitHub `production` environment. Configure +that environment with required reviewers and these environment secrets: + +- `CLOUDFLARE_ACCOUNT_ID` +- `CLOUDFLARE_API_TOKEN` + +Scope the API token to the target Cloudflare account and the minimum Workers +deployment permissions. The workflow validates both secrets, reruns the complete +quality and browser gates, creates a deployment dry-run bundle, and then runs: + +```bash +wrangler deploy --strict +``` + +Strict mode fails closed when a non-interactive deployment could overwrite +conflicting remote settings. + +The deployment credentials above are separate from the Worker runtime secrets: + +- `GITHUB_TOKEN` +- `SUBMAN_API_TOKEN` + +Runtime secrets remain managed with `wrangler secret put`; they must not be +copied into repository files, workflow inputs, build variables, or test +fixtures. + +## Repository settings + +Require the `CI / verify` check before merging or updating `main`. Keep direct +production deployment behind the `production` environment rather than a +push-triggered workflow. Do not enable automatic deployment until branch +protection, required checks, environment approval, rollback, and post-deployment +health verification are all configured. diff --git a/package.json b/package.json index 2dfe339..725496e 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,9 @@ "test:e2e": "playwright test", "build": "vite build", "preview": "vite preview", - "dev:cf": "wrangler dev", - "deploy": "wrangler deploy", + "dev:cf": "bun run build && wrangler dev --local", + "deploy:check": "bun run build && wrangler deploy --dry-run --outdir .wrangler/deploy-check", + "deploy": "bun run build && wrangler deploy --strict", "prepare": "svelte-kit sync || echo ''", "generate:worker-types": "bash scripts/generate-worker-types.sh", "check:worker-types": "bash scripts/generate-worker-types.sh --check", diff --git a/playwright.config.ts b/playwright.config.ts index 818f4f2..1b04062 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -9,11 +9,12 @@ export default defineConfig({ forbidOnly: Boolean(process.env.CI), retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, - reporter: "line", + reporter: process.env.CI ? [["github"], ["line"]] : "line", use: { baseURL, trace: "on-first-retry", screenshot: "only-on-failure", + video: "retain-on-failure", }, projects: [ { @@ -22,11 +23,12 @@ export default defineConfig({ }, ], webServer: { - command: `bun run build && bun run preview -- --host 127.0.0.1 --port ${port}`, + command: `bun run dev:cf -- --ip 127.0.0.1 --port ${port}`, url: baseURL, env: { WRANGLER_LOG_PATH: "/tmp/subman-playwright-wrangler-logs", - WRANGLER_REGISTRY_PATH: "/tmp/subman-playwright-wrangler-registry", + WRANGLER_REGISTRY_PATH: + "/tmp/subman-playwright-wrangler-registry", }, reuseExistingServer: !process.env.CI, timeout: 120_000, diff --git a/src/github-actions.test.ts b/src/github-actions.test.ts new file mode 100644 index 0000000..40eccfc --- /dev/null +++ b/src/github-actions.test.ts @@ -0,0 +1,72 @@ +import { expect, test } from "bun:test"; +import { readFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; + +const root = fileURLToPath(new URL("../", import.meta.url)); +const ciWorkflow = readFileSync( + `${root}/.github/workflows/ci.yml`, + "utf8", +); +const deployWorkflow = readFileSync( + `${root}/.github/workflows/deploy.yml`, + "utf8", +); +const playwrightConfig = readFileSync( + `${root}/playwright.config.ts`, + "utf8", +); +const packageJson = JSON.parse( + readFileSync(`${root}/package.json`, "utf8"), +) as { + scripts: Record; +}; + +function sourcePosition(source: string, marker: string): number { + const position = source.indexOf(marker); + expect(position).toBeGreaterThanOrEqual(0); + return position; +} + +test("CI fails fast before installing Chromium and validates the Worker bundle", () => { + expect(ciWorkflow).toContain("workflow_dispatch:"); + expect(ciWorkflow).toContain("permissions:\n contents: read"); + expect(ciWorkflow).toContain("uses: actions/checkout@v6"); + expect(ciWorkflow).toContain("persist-credentials: false"); + + const browserInstall = sourcePosition(ciWorkflow, "Install Chromium"); + for (const gate of [ + "Run unit tests", + "Run type and Svelte checks", + "Run lint", + "Build", + "Run Cloudflare integration tests", + "Verify Cloudflare deployment bundle", + ]) { + expect(sourcePosition(ciWorkflow, gate)).toBeLessThan(browserInstall); + } + + expect(ciWorkflow).toContain("wrangler deploy --dry-run"); + expect(ciWorkflow).toContain("actions/upload-artifact@v7"); +}); + +test("browser CI starts the built Worker through Wrangler local mode", () => { + expect(playwrightConfig).toContain("bun run dev:cf"); + expect(playwrightConfig).not.toContain("bun run preview"); + expect(packageJson.scripts["dev:cf"]).toContain("wrangler dev --local"); + expect(packageJson.scripts["deploy:check"]).toContain( + "wrangler deploy --dry-run", + ); +}); + +test("production deployment is manual, main-only, and environment gated", () => { + expect(deployWorkflow).toContain("workflow_dispatch:"); + expect(deployWorkflow).not.toContain("\n push:"); + expect(deployWorkflow).toContain('GITHUB_REF" != "refs/heads/main'); + expect(deployWorkflow).toContain('CONFIRMATION" != "deploy'); + expect(deployWorkflow).toContain("name: production"); + expect(deployWorkflow).toContain("CLOUDFLARE_API_TOKEN"); + expect(deployWorkflow).toContain("CLOUDFLARE_ACCOUNT_ID"); + expect(deployWorkflow).toContain("wrangler deploy --strict"); + expect(deployWorkflow).toContain("cancel-in-progress: false"); + expect(packageJson.scripts.deploy).toContain("--strict"); +}); From c7a3835b693f076c04f5277faa4b48d8663e43fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E8=A7=81=E6=99=93=E7=A9=BA?= Date: Fri, 28 Aug 2026 14:47:54 +0800 Subject: [PATCH 2/8] test(ci): exclude workflow source test from app typing --- src/github-actions.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/github-actions.test.ts b/src/github-actions.test.ts index 40eccfc..f966ea5 100644 --- a/src/github-actions.test.ts +++ b/src/github-actions.test.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { expect, test } from "bun:test"; import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; From 76cc0256943ae324cde2ad13dd420f53ec9daa9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E8=A7=81=E6=99=93=E7=A9=BA?= Date: Fri, 28 Aug 2026 14:49:33 +0800 Subject: [PATCH 3/8] style(ci): apply Biome formatting --- playwright.config.ts | 3 +-- src/github-actions.test.ts | 10 ++-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 1b04062..ff14983 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -27,8 +27,7 @@ export default defineConfig({ url: baseURL, env: { WRANGLER_LOG_PATH: "/tmp/subman-playwright-wrangler-logs", - WRANGLER_REGISTRY_PATH: - "/tmp/subman-playwright-wrangler-registry", + WRANGLER_REGISTRY_PATH: "/tmp/subman-playwright-wrangler-registry", }, reuseExistingServer: !process.env.CI, timeout: 120_000, diff --git a/src/github-actions.test.ts b/src/github-actions.test.ts index f966ea5..1591301 100644 --- a/src/github-actions.test.ts +++ b/src/github-actions.test.ts @@ -4,18 +4,12 @@ import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; const root = fileURLToPath(new URL("../", import.meta.url)); -const ciWorkflow = readFileSync( - `${root}/.github/workflows/ci.yml`, - "utf8", -); +const ciWorkflow = readFileSync(`${root}/.github/workflows/ci.yml`, "utf8"); const deployWorkflow = readFileSync( `${root}/.github/workflows/deploy.yml`, "utf8", ); -const playwrightConfig = readFileSync( - `${root}/playwright.config.ts`, - "utf8", -); +const playwrightConfig = readFileSync(`${root}/playwright.config.ts`, "utf8"); const packageJson = JSON.parse( readFileSync(`${root}/package.json`, "utf8"), ) as { From 3983eb932b8250fe2bcee8ed2cb8f044f6f8cf48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E8=A7=81=E6=99=93=E7=A9=BA?= Date: Fri, 28 Aug 2026 14:56:04 +0800 Subject: [PATCH 4/8] ci: refresh locked Wrangler runtime --- .../workflows/refresh-wrangler-runtime.yml | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .github/workflows/refresh-wrangler-runtime.yml diff --git a/.github/workflows/refresh-wrangler-runtime.yml b/.github/workflows/refresh-wrangler-runtime.yml new file mode 100644 index 0000000..88a65c7 --- /dev/null +++ b/.github/workflows/refresh-wrangler-runtime.yml @@ -0,0 +1,59 @@ +name: Refresh Wrangler runtime + +on: + push: + branches: + - ci/harden-cloudflare-pipeline-20260828 + +permissions: + contents: write + +concurrency: + group: refresh-wrangler-runtime + cancel-in-progress: false + +jobs: + refresh: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - name: Check out feature branch + uses: actions/checkout@v6 + with: + ref: ci/harden-cloudflare-pipeline-20260828 + fetch-depth: 0 + + - name: Set up Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.14 + + - name: Install locked dependencies + run: bun install --frozen-lockfile + + - name: Upgrade and pin Wrangler + run: bun add --dev --exact wrangler@4.127.0 + + - name: Refresh generated Worker types + run: bun run generate:worker-types + + - name: Format generated sources + run: bunx biome check --write package.json src/worker-configuration.d.ts + + - name: Verify the upgraded runtime + run: | + bunx wrangler --version + bun run check:worker-types + + - name: Remove one-shot workflow + run: rm .github/workflows/refresh-wrangler-runtime.yml + + - name: Commit runtime upgrade + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + git commit -m "build(deps): upgrade Wrangler runtime" + git push origin HEAD:ci/harden-cloudflare-pipeline-20260828 From 7ce25dc2757dbe1b959e1a569702994df01b4d87 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2026 06:56:28 +0000 Subject: [PATCH 5/8] build(deps): upgrade Wrangler runtime --- .../workflows/refresh-wrangler-runtime.yml | 59 ---------- bun.lock | 104 +++++++++--------- package.json | 2 +- src/worker-configuration.d.ts | 15 +-- 4 files changed, 62 insertions(+), 118 deletions(-) delete mode 100644 .github/workflows/refresh-wrangler-runtime.yml diff --git a/.github/workflows/refresh-wrangler-runtime.yml b/.github/workflows/refresh-wrangler-runtime.yml deleted file mode 100644 index 88a65c7..0000000 --- a/.github/workflows/refresh-wrangler-runtime.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Refresh Wrangler runtime - -on: - push: - branches: - - ci/harden-cloudflare-pipeline-20260828 - -permissions: - contents: write - -concurrency: - group: refresh-wrangler-runtime - cancel-in-progress: false - -jobs: - refresh: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Check out feature branch - uses: actions/checkout@v6 - with: - ref: ci/harden-cloudflare-pipeline-20260828 - fetch-depth: 0 - - - name: Set up Bun - uses: oven-sh/setup-bun@v2 - with: - bun-version: 1.3.14 - - - name: Install locked dependencies - run: bun install --frozen-lockfile - - - name: Upgrade and pin Wrangler - run: bun add --dev --exact wrangler@4.127.0 - - - name: Refresh generated Worker types - run: bun run generate:worker-types - - - name: Format generated sources - run: bunx biome check --write package.json src/worker-configuration.d.ts - - - name: Verify the upgraded runtime - run: | - bunx wrangler --version - bun run check:worker-types - - - name: Remove one-shot workflow - run: rm .github/workflows/refresh-wrangler-runtime.yml - - - name: Commit runtime upgrade - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - git commit -m "build(deps): upgrade Wrangler runtime" - git push origin HEAD:ci/harden-cloudflare-pipeline-20260828 diff --git a/bun.lock b/bun.lock index 842bc3a..04b6313 100644 --- a/bun.lock +++ b/bun.lock @@ -27,7 +27,7 @@ "typescript": "^5.9.3", "vite": "^7.3.1", "vitest": "^4.1.0", - "wrangler": "^4.69.0", + "wrangler": "4.127.0", }, }, }, @@ -50,21 +50,21 @@ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.10", "", { "os": "win32", "cpu": "x64" }, "sha512-aW/JU5GuyH4uxMrNYpoC2kjaHlyJGLgIa3XkhPEZI0uKhZhJZU8BuEyJmvgzSPQNGozBwWjC972RaNdcJ9KyJg=="], - "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.2", "", {}, "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ=="], + "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.5.0", "", {}, "sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg=="], - "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.16.0", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": "1.20260301.1 || ~1.20260302.1 || ~1.20260303.1 || ~1.20260304.1 || >1.20260305.0 <2.0.0-0" }, "optionalPeers": ["workerd"] }, "sha512-8ovsRpwzPoEqPUzoErAYVv8l3FMZNeBVQfJTvtzP4AgLSRGZISRfuChFxHWUQd3n6cnrwkuTGxT+2cGo8EsyYg=="], + "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.16.1", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": ">1.20260305.0 <2.0.0-0" }, "optionalPeers": ["workerd"] }, "sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw=="], "@cloudflare/vitest-pool-workers": ["@cloudflare/vitest-pool-workers@0.18.7", "", { "dependencies": { "cjs-module-lexer": "1.2.3", "esbuild": "0.28.1", "miniflare": "4.20260721.0", "wrangler": "4.113.0", "zod": "3.25.76" }, "peerDependencies": { "@vitest/runner": "^4.1.0", "@vitest/snapshot": "^4.1.0", "vitest": "^4.1.0" } }, "sha512-PGYToiFoGpuRV2Uh33S4fI7JcmSkDxk6LQeneYtgfsITEkVi5iGxc3Vms6yW9Jr6uSzVK4Be9XZfdyZDr5GWYw=="], - "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260405.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-EbmdBcmeIGogKG4V1odSWQe7z4rHssUD4iaXv0cXA22/MFrzH3iQT0R+FJFyhucGtih/9B9E+6j0QbSQD8xT3w=="], + "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260826.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-8UsGGY8ZUiYHOWdsxBlNsGmaHBGArVwJ3CM4nWpfBhthjjYe4M/OqrTpqKF7NNWb63qQiv1d8Z+Z6/hmUqNKIQ=="], - "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20260405.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-r44r418bOQtoP+Odu+L/BQM9q5cRSXRd1N167PgZQIo4MlqzTwHO4L0wwXhxbcV/PF46rrQre/uTFS8R0R+xSQ=="], + "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20260826.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0bLqVQYsQ3v3FdYGmzh23vi9fJeYTBx19o4LUySIsRcgBggGSlR39ml162vTXvZzUISOjVW2qfL7Y+SMrrfXmQ=="], - "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20260405.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Aaq3RWnaTCzMBo77wC8fjOx+SFdO/rlcXa6HAf+PJs51LyMISFOBCJKqSlS6Irphen0WHHxFKPHUO9bjfj8g2g=="], + "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20260826.1", "", { "os": "linux", "cpu": "x64" }, "sha512-DTC0yWzybX4gUH5Q1pJo3UwEQjp0Gmz0Q71I+39xT9SXBesX5QndOIQv45yHQ86Z84EzK2WwaENdlpmDSvJKmw=="], - "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20260405.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Lbp9Z2wiMzy3Sji3YwMHK5WDlejsH3jF4swAFEv7+jIf3NowZHga3GzwTypNRmcwnfz/XrqQ7Hc0Ul9OoU/lCw=="], + "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20260826.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-PFerWi+DP2Ckc6eATAS4dhotBt8IeXJjTzIgy18H+uqsswlXc7A8HsnAunHL9v/7/BjCgq46iMo2g4iUAsEpDw=="], - "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20260405.1", "", { "os": "win32", "cpu": "x64" }, "sha512-FhE0kt93kj5JnSPVqi4BAXpQQENyKnuSOoJLd35mkMMGhtPrwv5EsReJdck0S8hUocCBlb+U0RmP8ta6k41HjQ=="], + "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20260826.1", "", { "os": "win32", "cpu": "x64" }, "sha512-X26hulrG2MSSfpRmjZbCq98LNaZnrRqbmGcgo7g1U/U0nJ5npYruPm3fAyZ2y6VDr5CmQo9BLCahxP8VB/QR6A=="], "@cloudflare/workers-types": ["@cloudflare/workers-types@4.20260408.1", "", {}, "sha512-kE1tKfHUyIldsj3ea2XEqvLRHkDwc83YM7nar6SS5+cj81IoAFR/OZNDwZWHb6vx+pC31PBJGtROlfZzsgxudQ=="], @@ -130,6 +130,8 @@ "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], + "@img/sharp-freebsd-wasm32": ["@img/sharp-freebsd-wasm32@0.35.2", "", { "dependencies": { "@img/sharp-wasm32": "0.35.2" }, "os": "freebsd" }, "sha512-YoAxdnd8hPUkvLHd3bWY+YA8nw3xM/RyRopYucNsWHVSan8NLVM3X2volsfoRDcXdUJPg6tXahSd7HXPK7lRnw=="], + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], @@ -168,6 +170,8 @@ "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], + "@img/sharp-webcontainers-wasm32": ["@img/sharp-webcontainers-wasm32@0.35.2", "", { "dependencies": { "@img/sharp-wasm32": "0.35.2" }, "cpu": "none" }, "sha512-QNV27pxs9wpApEiCfvHM1RDoP1w1+2KrUWWDPEhEwg+latvOrfuhWrHWZKwdSFwU6jh3myjw/yOCRsUIuOft3g=="], + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], @@ -494,11 +498,11 @@ "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], - "workerd": ["workerd@1.20260405.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260405.1", "@cloudflare/workerd-darwin-arm64": "1.20260405.1", "@cloudflare/workerd-linux-64": "1.20260405.1", "@cloudflare/workerd-linux-arm64": "1.20260405.1", "@cloudflare/workerd-windows-64": "1.20260405.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-bSaRWCv9iO8/FWpgZRjHLGZLolX5s1AErRSYaTECMMHOZKuCbl2+ehnSyc+ZZ/70y+9owADmN6HoYEWvBlJdYw=="], + "workerd": ["workerd@1.20260826.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260826.1", "@cloudflare/workerd-darwin-arm64": "1.20260826.1", "@cloudflare/workerd-linux-64": "1.20260826.1", "@cloudflare/workerd-linux-arm64": "1.20260826.1", "@cloudflare/workerd-windows-64": "1.20260826.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-oTG9ot5zxO9OjjKCskt86+nVrBL0kiUqExHnYaTg4OCkHf/K4zr+9hYvgwmG8DdCWG0TQGErHzD+1h50TM5b+w=="], "worktop": ["worktop@0.8.0-next.18", "", { "dependencies": { "mrmime": "^2.0.0", "regexparam": "^3.0.0" } }, "sha512-+TvsA6VAVoMC3XDKR5MoC/qlLqDixEfOBysDEKnPIPou/NvoPWCAuXHXMsswwlvmEuvX56lQjvELLyLuzTKvRw=="], - "wrangler": ["wrangler@4.81.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.2", "@cloudflare/unenv-preset": "2.16.0", "blake3-wasm": "2.1.5", "esbuild": "0.27.3", "miniflare": "4.20260405.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20260405.1" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20260405.1" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-9fLPDuDcb8Nu6iXrl5E3HGYt3TVhQr/UvqtTvWr9Nl1X7PlQrmWMwQCfSioqN8VHYyQCyESV5jQsoKg8Sx+sEA=="], + "wrangler": ["wrangler@4.127.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.5.0", "@cloudflare/unenv-preset": "2.16.1", "blake3-wasm": "2.1.5", "esbuild": "0.28.1", "miniflare": "5.20260826.0-alpha", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20260826.1" }, "optionalDependencies": { "fsevents": "2.3.3" }, "peerDependencies": { "@cloudflare/workers-types": "^5.20260826.1" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js", "cf-wrangler": "bin/cf-wrangler.js" } }, "sha512-4dPqcBEMJfGeZeNnjHT7ThNJs+EiNYxUTg4ywqIdQubcXHBhFeVMQyHV4A9AOhZRFr83cckqdds034KGcr/dtw=="], "ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], @@ -514,6 +518,10 @@ "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + "@img/sharp-freebsd-wasm32/@img/sharp-wasm32": ["@img/sharp-wasm32@0.35.2", "", { "dependencies": { "@emnapi/runtime": "^1.11.1" } }, "sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw=="], + + "@img/sharp-webcontainers-wasm32/@img/sharp-wasm32": ["@img/sharp-wasm32@0.35.2", "", { "dependencies": { "@emnapi/runtime": "^1.11.1" } }, "sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw=="], @@ -532,17 +540,15 @@ "vite/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], - "wrangler/esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], - - "wrangler/miniflare": ["miniflare@4.20260405.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "^0.34.5", "undici": "7.24.4", "workerd": "1.20260405.1", "ws": "8.18.0", "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-tpr4XdWMq7zFdsHH+CS0XS47nQzlRZH0rMJ1vobOZbkrs3cIj7qbD40ON616hDnzHxwqwB2qKHzmmuj6oRisSQ=="], + "wrangler/miniflare": ["miniflare@5.20260826.0-alpha", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "0.35.2", "undici": "7.29.0", "workerd": "1.20260826.1", "ws": "8.21.0", "youch": "4.1.0-beta.10" } }, "sha512-ZXR3Bieg+B5MK0T/zYIWaZiCGCb9Z3en4+/TleYKhIGPLx/e0cRcG/ZvvTviUapVBBK2zODB+aiypdIojU3x6Q=="], "youch/cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], - "@cloudflare/vitest-pool-workers/wrangler/@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.5.0", "", {}, "sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd": ["workerd@1.20260721.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260721.1", "@cloudflare/workerd-darwin-arm64": "1.20260721.1", "@cloudflare/workerd-linux-64": "1.20260721.1", "@cloudflare/workerd-linux-arm64": "1.20260721.1", "@cloudflare/workerd-windows-64": "1.20260721.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-b/DWhpV0jTudzQpLhDovcOgBz233386q+3Hbari7CLCNT9UXxjQziSTZ9yCoKdT2K3TSx5jrwlOisq8hlLWXYg=="], - "@cloudflare/vitest-pool-workers/wrangler/@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.16.1", "", { "peerDependencies": { "unenv": "2.0.0-rc.24", "workerd": ">1.20260305.0 <2.0.0-0" }, "optionalPeers": ["workerd"] }, "sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw=="], + "@img/sharp-freebsd-wasm32/@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="], - "@cloudflare/vitest-pool-workers/wrangler/workerd": ["workerd@1.20260721.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260721.1", "@cloudflare/workerd-darwin-arm64": "1.20260721.1", "@cloudflare/workerd-linux-64": "1.20260721.1", "@cloudflare/workerd-linux-arm64": "1.20260721.1", "@cloudflare/workerd-windows-64": "1.20260721.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-b/DWhpV0jTudzQpLhDovcOgBz233386q+3Hbari7CLCNT9UXxjQziSTZ9yCoKdT2K3TSx5jrwlOisq8hlLWXYg=="], + "@img/sharp-webcontainers-wasm32/@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="], "miniflare/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260721.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-VivNMhiEdZIB4JBWxf1RMJGROErv53qmQ+dvhjA1evrCouvqRYW718VqDideU3PSV7Ythl5Df48NqZYWoaEHpQ=="], @@ -606,70 +612,66 @@ "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], - "wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], - - "wrangler/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], + "wrangler/miniflare/sharp": ["sharp@0.35.2", "", { "dependencies": { "@img/colour": "^1.1.0", "detect-libc": "^2.1.2", "semver": "^7.8.4" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.35.2", "@img/sharp-darwin-x64": "0.35.2", "@img/sharp-freebsd-wasm32": "0.35.2", "@img/sharp-libvips-darwin-arm64": "1.3.1", "@img/sharp-libvips-darwin-x64": "1.3.1", "@img/sharp-libvips-linux-arm": "1.3.1", "@img/sharp-libvips-linux-arm64": "1.3.1", "@img/sharp-libvips-linux-ppc64": "1.3.1", "@img/sharp-libvips-linux-riscv64": "1.3.1", "@img/sharp-libvips-linux-s390x": "1.3.1", "@img/sharp-libvips-linux-x64": "1.3.1", "@img/sharp-libvips-linuxmusl-arm64": "1.3.1", "@img/sharp-libvips-linuxmusl-x64": "1.3.1", "@img/sharp-linux-arm": "0.35.2", "@img/sharp-linux-arm64": "0.35.2", "@img/sharp-linux-ppc64": "0.35.2", "@img/sharp-linux-riscv64": "0.35.2", "@img/sharp-linux-s390x": "0.35.2", "@img/sharp-linux-x64": "0.35.2", "@img/sharp-linuxmusl-arm64": "0.35.2", "@img/sharp-linuxmusl-x64": "0.35.2", "@img/sharp-webcontainers-wasm32": "0.35.2", "@img/sharp-win32-arm64": "0.35.2", "@img/sharp-win32-ia32": "0.35.2", "@img/sharp-win32-x64": "0.35.2" } }, "sha512-FVtFjtBCMiJS6yb5CX7Sop45WFMpeGw6oRKuJnXYgf/f1ms/D7LE/ZUSNxnW7rZ/dbslQWYkoqFHGPaDBtaK4w=="], - "wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], + "wrangler/miniflare/undici": ["undici@7.29.0", "", {}, "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw=="], - "wrangler/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], - - "wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260721.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-VivNMhiEdZIB4JBWxf1RMJGROErv53qmQ+dvhjA1evrCouvqRYW718VqDideU3PSV7Ythl5Df48NqZYWoaEHpQ=="], - "wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20260721.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-k7oye1ZiuwnnBBA2eTMduconr/ud5ZxFtRNTsYwMdmJeeeislw2+M72otrHxxvybCP7JWPPlJ38uhfajpcyhOA=="], - "wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20260721.1", "", { "os": "linux", "cpu": "x64" }, "sha512-hon0lW4ZQ4boAVgaw+0ZFTNS8v5MWPWvK0HZnt4tDpKYnDUviLZawtUW3KqvFmCQTipVHl1S34j3J8Eqb93hGQ=="], - "wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20260721.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-nAl+HRQqpX5b7xVwWcvLPZmCk8NQ2yjI0yvJTWcHiRswbMEg1ZZckVmjJUAn0PHzZARbCSyIV7v3UjM+SPRmIQ=="], - "wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20260721.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9paFG5cMTKz/CRixnEEnZbe5uvFPBFSDthxJHANfCWhUtBj49GSL1FPIokIg+Q+H8DGJEExU0lL92LtxD0lTxQ=="], - "wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], + "wrangler/miniflare/sharp/@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.35.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.3.1" }, "os": "darwin", "cpu": "arm64" }, "sha512-eEieHsMksAW4IiO5NzauESRl2D2qz3J/kwUxUrSfV06A93eEaRfMpHXyUb1mAqrR7i8U9A0GRqE9pjn6u1Jjpg=="], - "wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], + "wrangler/miniflare/sharp/@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.35.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.3.1" }, "os": "darwin", "cpu": "x64" }, "sha512-BaktuGPCeHJMARpodR8jK4uKiZrPAy9WrfQW0sdI37clracq8Bp01AYS3SZgi5FS/y5twa9t4+LIuuxQjqRrWw=="], - "wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], + "wrangler/miniflare/sharp/@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.3.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-4V/M3roRMTYjiwZY9IOVQOE8OyeCxFAkYmyZDrZl51uOKjibm3oeEJ4WAmLxutAfzFbC9jqUiPs2gbnGflH+7g=="], - "wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], + "wrangler/miniflare/sharp/@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.3.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-c0/DxItpJv2+dGhgycJBBgotdqruGYDvA79drdh0MD1dFpy7JzJ/PlXwi1H4rFf0eTy8tgbI91aHDnZIceY3jQ=="], - "wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], + "wrangler/miniflare/sharp/@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.3.1", "", { "os": "linux", "cpu": "arm" }, "sha512-aGGy9aWzXgHBG7HNyQPWorZthlp7+x6fDRoPAQbGO3ThcttuTyKIx3NuSHb6zb4gBNq6/yNn9f1cy9nFKS/Vmg=="], - "wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], + "wrangler/miniflare/sharp/@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-JznefmcK9j1JKPz8AkQDh89kjojubyfOasWBPKfzMIhPwsgDy9evpE/naJTXXXmghS1iFwR8u/kTwh/I2/+GCw=="], - "wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], + "wrangler/miniflare/sharp/@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.3.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1EkwGNCZk6iWNCMWqrvdJ+r1j0PT1zIz60CNPhYnJlK/zyeWqlsPZIe+ocBVqPF8k/Ssee/NCk+tE9Ryrko6ng=="], - "wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], + "wrangler/miniflare/sharp/@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.3.1", "", { "os": "linux", "cpu": "none" }, "sha512-Ilays+w2bXdnxzxtQdmXR62u8o8GYa3eL4+Gr+1KiE4xperMZUslRaVPJwwPkzlHEjGfXAfRVAa/7CYCtSqsBw=="], - "wrangler/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], + "wrangler/miniflare/sharp/@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.3.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-VfBwVHQTbRoj4XlpA/KLZ7ltgMpz+4WSejFzQ+GnoImjo1PtEJ59QB2qR1xQEeRPYIkNrPIm2L4cICMvz4C2ew=="], - "wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], + "wrangler/miniflare/sharp/@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-+c8ukgwU62DS54nCAjw7keOfHUkmr0B5QHEdcOqRnodF/MNXJbVI8Eopoj4B/0H8Asr65I+A4Amrn7a85/md6A=="], - "wrangler/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], + "wrangler/miniflare/sharp/@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-qlKb/pwbkAi1WMsJrYHk7CuDrd12s27U2QnRhFYUoJNrRCmkosMTttuRFat/DDB3IlDm5qE1TJgZ4JDnHX8Ldw=="], - "wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], + "wrangler/miniflare/sharp/@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-yO21HwoUVLN8Qa+/SBjQLMYwBWAVJjeGPNe+hc0OUeMeifEtJqu5a1c4HayE1nNpDih9y3/KkoltfkDodmKAlg=="], - "wrangler/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], + "wrangler/miniflare/sharp/@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.35.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.3.1" }, "os": "linux", "cpu": "arm" }, "sha512-SE4kzF2mepn6z+6E7L6lsV8FzuLL6IPQdyX8ZiwROAG/G8td+hP/m7FsFPwidtrF19gvajuC9l6TxAVcsA4S7A=="], - "wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], + "wrangler/miniflare/sharp/@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.35.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.3.1" }, "os": "linux", "cpu": "arm64" }, "sha512-af12Pnd0ZGu2HfP8NayB0kk6eC/lrfbQE6HlR4jD+34wdJ1Vw9TF6TMn6ZvffT+WgqVsl0hRbmNvz2u/23VmwA=="], - "wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], + "wrangler/miniflare/sharp/@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.35.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.3.1" }, "os": "linux", "cpu": "ppc64" }, "sha512-hYSBm7zcNtDCozCxQHYZJiu63b/bXsgRZuOxCIBZsStMM9Vap47iFHdbX4kCvQsblPB/k+clhELpdQJHQLSHvg=="], - "wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], + "wrangler/miniflare/sharp/@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.35.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.3.1" }, "os": "linux", "cpu": "none" }, "sha512-qQt0Kc13+Hoan/Awq/qMSQw3L+RI1NCRPgD5cUJ/1WSSmIoysLOc72jlRM3E0OHN9Yr313jgeQ2T+zW+F03QFA=="], - "wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], + "wrangler/miniflare/sharp/@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.35.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.3.1" }, "os": "linux", "cpu": "s390x" }, "sha512-E4fLLfRPzDLlEeDaTzI98OFLcv++WL5ChLLMwPoVd0CIoZQqupBSNbOisPL5am9XsbQ9T84+iiMpUvbFtkunbA=="], - "wrangler/miniflare/undici": ["undici@7.24.4", "", {}, "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w=="], + "wrangler/miniflare/sharp/@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.35.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.3.1" }, "os": "linux", "cpu": "x64" }, "sha512-gi0zFJJRLswfCZmHtJdikXPOc5u7qamSOS3NHedLqLd4W8Q0NqjdBr6TTRIgsfFjqfTsHFgdfvJ9LwqSgcHiAA=="], - "wrangler/miniflare/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], + "wrangler/miniflare/sharp/@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.35.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.3.1" }, "os": "linux", "cpu": "arm64" }, "sha512-siWbOW1u6HFnFLrp0waKyW7VEf7jYvcDWdrXEFa8AkdAQgEvuu5Fz8/Y70w9EeqAdwDtfU012BhEHHaDqvQNzg=="], - "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260721.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-VivNMhiEdZIB4JBWxf1RMJGROErv53qmQ+dvhjA1evrCouvqRYW718VqDideU3PSV7Ythl5Df48NqZYWoaEHpQ=="], + "wrangler/miniflare/sharp/@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.35.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.3.1" }, "os": "linux", "cpu": "x64" }, "sha512-YBqMMcjDi4QGYiSn4vNOYBhmlC4z5AXqkOUUqI2e0AFA4urNv4ESgOgwNl3K+4etQhha0twXlzeF20bbULm9Yg=="], - "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20260721.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-k7oye1ZiuwnnBBA2eTMduconr/ud5ZxFtRNTsYwMdmJeeeislw2+M72otrHxxvybCP7JWPPlJ38uhfajpcyhOA=="], + "wrangler/miniflare/sharp/@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.35.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-BiVRYc/t6/Vl3e1hBx0hugG4oN9Pydf4fgMSpxTQJmwGUg/YoXTWHiFeRymHfCZzifxu4F4rpk/I67D0LQ20wQ=="], - "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20260721.1", "", { "os": "linux", "cpu": "x64" }, "sha512-hon0lW4ZQ4boAVgaw+0ZFTNS8v5MWPWvK0HZnt4tDpKYnDUviLZawtUW3KqvFmCQTipVHl1S34j3J8Eqb93hGQ=="], + "wrangler/miniflare/sharp/@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.35.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YYEhx9PImCC7T0tI8JDMi4DB9LwLCXCU5OWNYEXAxh5Q1ShKkyC6byxzoBJ3gEFDnH2lQckWuDe70G7mB2XJog=="], - "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20260721.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-nAl+HRQqpX5b7xVwWcvLPZmCk8NQ2yjI0yvJTWcHiRswbMEg1ZZckVmjJUAn0PHzZARbCSyIV7v3UjM+SPRmIQ=="], + "wrangler/miniflare/sharp/@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.35.2", "", { "os": "win32", "cpu": "x64" }, "sha512-imoOyBcoM/iiUr4J6VPpCNjPnjvP/Gks95898yB8YqoGGYmHYbOyCuNv9FMhFgtaiHFGbHW8bxKqRV6VjtXThQ=="], - "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20260721.1", "", { "os": "win32", "cpu": "x64" }, "sha512-9paFG5cMTKz/CRixnEEnZbe5uvFPBFSDthxJHANfCWhUtBj49GSL1FPIokIg+Q+H8DGJEExU0lL92LtxD0lTxQ=="], + "wrangler/miniflare/sharp/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], } } diff --git a/package.json b/package.json index 725496e..7aa7724 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "typescript": "^5.9.3", "vite": "^7.3.1", "vitest": "^4.1.0", - "wrangler": "^4.69.0" + "wrangler": "4.127.0" }, "dependencies": { "@primer/octicons": "^19.23.1", diff --git a/src/worker-configuration.d.ts b/src/worker-configuration.d.ts index b09a09a..6899567 100644 --- a/src/worker-configuration.d.ts +++ b/src/worker-configuration.d.ts @@ -1,11 +1,12 @@ /* eslint-disable */ // Generated by scripts/generate-worker-types.sh from wrangler.toml. +interface __BaseEnv_Env { + ASSETS: Fetcher; + WORKSPACE_COORDINATOR: DurableObjectNamespace< + import("./lib/server/workspace-coordinator").WorkspaceCoordinator + >; +} declare namespace Cloudflare { - interface Env { - ASSETS: Fetcher; - WORKSPACE_COORDINATOR: DurableObjectNamespace< - import("./lib/server/workspace-coordinator").WorkspaceCoordinator - >; - } + interface Env extends __BaseEnv_Env {} } -interface Env extends Cloudflare.Env {} +interface Env extends __BaseEnv_Env {} From 57eca09861e5afd33ea44313d4e2ca9fe4cbfa21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E8=A7=81=E6=99=93=E7=A9=BA?= Date: Fri, 28 Aug 2026 14:57:53 +0800 Subject: [PATCH 6/8] docs(ci): record Wrangler runtime compatibility fix --- docs/ci-cd.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/ci-cd.md b/docs/ci-cd.md index 69aaf46..cbb19eb 100644 --- a/docs/ci-cd.md +++ b/docs/ci-cd.md @@ -4,7 +4,9 @@ The `CI` workflow runs for pushes to `main`, pull requests, and manual dispatches. It uses the repository-pinned Bun and Wrangler toolchain and keeps -`GITHUB_TOKEN` read-only. +`GITHUB_TOKEN` read-only. Wrangler is pinned exactly at `4.127.0`; the frozen +lockfile therefore carries a `workerd` release new enough to execute the +project's `compatibility_date = "2026-07-28"` locally. The verification order is intentionally fail-fast: @@ -27,7 +29,9 @@ When Playwright fails, traces, screenshots, videos, and reports are uploaded as a seven-day GitHub Actions artifact. If an earlier gate fails, the workflow does not spend time installing Chromium. -## Historical CI failure +## Historical CI failures + +### Generated Worker type drift The formal `CI` run on 2026-08-24 (`run #5`, commit `e82147c5d370734c27a03fa681fccf07028721d8`) passed all unit tests, then failed @@ -47,6 +51,21 @@ Do not hand-edit the generated declaration. Any future `wrangler.toml`, Wrangler binding, migration, or compatibility-date change must regenerate the file and pass the complete CI workflow. +### Local Workers runtime behind the compatibility date + +The first CI run that replaced `vite preview` with `wrangler dev --local` +successfully passed unit, type, lint, build, Cloudflare integration, and +deployment dry-run gates, but the browser server could not start. The locked +Wrangler `4.81.0` bundled a `workerd` runtime supporting compatibility dates only +through `2026-04-12`, while SubMan requires `2026-07-28`. + +The production compatibility date was not rolled back. Wrangler was upgraded +and pinned to `4.127.0`, whose lockfile resolves `workerd` `1.20260826.1`. This +keeps local browser evidence aligned with the checked-in production +configuration. Future compatibility-date changes must first update the pinned +runtime and pass local Worker startup, deployment dry-run, Cloudflare +integration, and browser gates. + ## Production deployment Production deployment is intentionally not automatic. Use the From fb375c53e90a4a18fe10e108797e74dcc1e867a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E8=A7=81=E6=99=93=E7=A9=BA?= Date: Fri, 28 Aug 2026 14:59:09 +0800 Subject: [PATCH 7/8] test(cloudflare): follow generated Env inheritance --- src/cloudflare-binding.test.ts | 42 ++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/cloudflare-binding.test.ts b/src/cloudflare-binding.test.ts index 397d223..3ab6056 100644 --- a/src/cloudflare-binding.test.ts +++ b/src/cloudflare-binding.test.ts @@ -7,23 +7,51 @@ import ts from "typescript"; const root = fileURLToPath(new URL("../", import.meta.url)); function interfaceMembers(source: ts.SourceFile, name: string): string[] { - const members: string[] = []; + const declarations = new Map(); const visit = (node: ts.Node): void => { - if (ts.isInterfaceDeclaration(node) && node.name.text === name) { - for (const member of node.members) { + if (ts.isInterfaceDeclaration(node)) { + const existing = declarations.get(node.name.text) ?? []; + existing.push(node); + declarations.set(node.name.text, existing); + } + ts.forEachChild(node, visit); + }; + visit(source); + + const resolve = (interfaceName: string, seen: Set): Set => { + if (seen.has(interfaceName)) return new Set(); + const nextSeen = new Set(seen).add(interfaceName); + const members = new Set(); + + for (const declaration of declarations.get(interfaceName) ?? []) { + for (const member of declaration.members) { if ( ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name) ) { - members.push(member.name.text); + members.add(member.name.text); + } + } + + for (const clause of declaration.heritageClauses ?? []) { + if (clause.token !== ts.SyntaxKind.ExtendsKeyword) continue; + for (const inherited of clause.types) { + if (!ts.isIdentifier(inherited.expression)) continue; + for (const member of resolve( + inherited.expression.text, + nextSeen, + )) { + members.add(member); + } } } } - ts.forEachChild(node, visit); + + return members; }; - visit(source); - return members; + + return [...resolve(name, new Set())]; } test("Cloudflare declaration matches the Wrangler Durable Object binding", () => { From 59755e49a7233ce038449fa8be6d04bd2bf38076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E8=A7=81=E6=99=93=E7=A9=BA?= Date: Fri, 28 Aug 2026 15:01:19 +0800 Subject: [PATCH 8/8] style(cloudflare): apply Biome formatting --- src/cloudflare-binding.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/cloudflare-binding.test.ts b/src/cloudflare-binding.test.ts index 3ab6056..0130413 100644 --- a/src/cloudflare-binding.test.ts +++ b/src/cloudflare-binding.test.ts @@ -38,10 +38,7 @@ function interfaceMembers(source: ts.SourceFile, name: string): string[] { if (clause.token !== ts.SyntaxKind.ExtendsKeyword) continue; for (const inherited of clause.types) { if (!ts.isIdentifier(inherited.expression)) continue; - for (const member of resolve( - inherited.expression.text, - nextSeen, - )) { + for (const member of resolve(inherited.expression.text, nextSeen)) { members.add(member); } }