From 98d97cd80348a1c9e460e86c54c2c75835163b1c Mon Sep 17 00:00:00 2001 From: Peter Wielander Date: Sat, 2 May 2026 15:07:28 +0900 Subject: [PATCH 1/3] Split tarball hosting out of docs into its own project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docs project was incidentally hosting preview tarballs because of a prebuild step that ran scripts/pack.ts and dumped *.tgz into docs/public/. Move all of that — pack script, smoke checks, gitignore entries, the .tgz proxy matcher exception — into a new top-level `tarballs/` workspace package that deploys as its own static Vercel project (framework: null, outputDirectory: public). Also fix a long-standing oddity in pack.ts where restoring the package.json after `pnpm pack` dropped the trailing newline because the original was rebuilt with JSON.stringify rather than the source bytes. The new version stores the raw original content and writes it back verbatim. Adds .github/workflows/tarballs-checks.yml that waits for the workflow-tarballs Vercel project and runs the new smoke script. Co-Authored-By: Claude Opus 4.7 (1M context) --- .changeset/split-tarballs-from-docs.md | 2 + .github/workflows/tarballs-checks.yml | 53 ++++++ docs/.gitignore | 2 - docs/package.json | 1 - docs/proxy.ts | 2 +- docs/scripts/check-docs-smoke.mjs | 27 --- pnpm-lock.yaml | 216 ++++++++++++++++++++++ pnpm-workspace.yaml | 1 + tarballs/.gitignore | 6 + tarballs/README.md | 21 +++ tarballs/package.json | 39 ++++ tarballs/scripts/check-tarballs-smoke.mjs | 90 +++++++++ {docs => tarballs}/scripts/pack.ts | 24 ++- tarballs/turbo.json | 9 + tarballs/vercel.json | 7 + 15 files changed, 461 insertions(+), 39 deletions(-) create mode 100644 .changeset/split-tarballs-from-docs.md create mode 100644 .github/workflows/tarballs-checks.yml create mode 100644 tarballs/.gitignore create mode 100644 tarballs/README.md create mode 100644 tarballs/package.json create mode 100644 tarballs/scripts/check-tarballs-smoke.mjs rename {docs => tarballs}/scripts/pack.ts (82%) create mode 100644 tarballs/turbo.json create mode 100644 tarballs/vercel.json diff --git a/.changeset/split-tarballs-from-docs.md b/.changeset/split-tarballs-from-docs.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/split-tarballs-from-docs.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.github/workflows/tarballs-checks.yml b/.github/workflows/tarballs-checks.yml new file mode 100644 index 0000000000..35383316d8 --- /dev/null +++ b/.github/workflows/tarballs-checks.yml @@ -0,0 +1,53 @@ +name: Tarballs Checks + +on: + push: + branches: + - main + tags: + - "!*" + pull_request: + +concurrency: + # Unique group for this workflow and branch + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + tarballs-preview-smoke: + name: Tarballs Preview Smoke Checks + runs-on: ubuntu-latest + timeout-minutes: 10 + env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ vars.TURBO_TEAM }} + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v5 + + - name: Setup Node.js 22.x + uses: actions/setup-node@v4 + with: + node-version: 22.x + cache: "pnpm" + + - name: Install Dependencies + run: pnpm install --frozen-lockfile + + - name: Waiting for the Tarballs Vercel deployment + id: waitForTarballsDeployment + uses: ./.github/actions/wait-for-vercel-project + with: + project-slug: workflow-tarballs + timeout: 1000 + check-interval: 15 + environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }} + + - name: Verify tarball endpoints + run: pnpm --filter tarballs test:smoke + env: + DEPLOYMENT_URL: ${{ steps.waitForTarballsDeployment.outputs.deployment-url }} + VERCEL_AUTOMATION_BYPASS_SECRET: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }} diff --git a/docs/.gitignore b/docs/.gitignore index 0805f529d5..a23daf7601 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -33,6 +33,4 @@ next-env.d.ts # pagefind _pagefind/ -# tarballs -*.tgz .env*.local diff --git a/docs/package.json b/docs/package.json index 3879797b6e..bd0bdda740 100644 --- a/docs/package.json +++ b/docs/package.json @@ -8,7 +8,6 @@ "dev": "next dev --turbo", "start": "next start", "postinstall": "fumadocs-mdx", - "prebuild": "node scripts/pack.ts", "lint": "biome check", "lint:links": "bun ./scripts/lint.ts", "format": "biome format --write", diff --git a/docs/proxy.ts b/docs/proxy.ts index a2b7d5185e..b6be88c65d 100644 --- a/docs/proxy.ts +++ b/docs/proxy.ts @@ -132,7 +132,7 @@ const proxy = (request: NextRequest, context: NextFetchEvent) => { export const config = { // Matcher ignoring `/_next/`, `/api/`, static assets, favicon, sitemap, robots, etc. matcher: [ - '/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|og|.*\\.tgz$|.*\\.svg$|.*\\.zip$).*)', + '/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|og|.*\\.svg$|.*\\.zip$).*)', ], }; diff --git a/docs/scripts/check-docs-smoke.mjs b/docs/scripts/check-docs-smoke.mjs index 14c9f01285..5d1874b36b 100644 --- a/docs/scripts/check-docs-smoke.mjs +++ b/docs/scripts/check-docs-smoke.mjs @@ -229,35 +229,8 @@ const checks = [ name: 'Sitemap', run: () => assertXmlResponse('/sitemap.xml'), }, - { - name: 'Tarball - workflow', - run: () => assertTgzResponse('/workflow.tgz'), - }, - { - name: 'Tarball - workflow-core', - run: () => assertTgzResponse('/workflow-core.tgz'), - }, - { - name: 'Tarball - workflow-next', - run: () => assertTgzResponse('/workflow-next.tgz'), - }, ]; -const GZIP_SIGNATURE = [0x1f, 0x8b]; - -const assertTgzResponse = async (path) => { - const res = await fetch(`${BASE_URL}${path}`, { headers: getHeaders() }); - if (!res.ok) { - throw new Error(`${path} returned ${res.status}`); - } - const buf = new Uint8Array(await res.arrayBuffer()); - for (let i = 0; i < GZIP_SIGNATURE.length; i += 1) { - if (buf[i] !== GZIP_SIGNATURE[i]) { - throw new Error(`${path} did not start with gzip signature bytes`); - } - } -}; - const assertXmlResponse = async (path) => { const res = await fetch(`${BASE_URL}${path}`, { headers: getHeaders() }); if (!res.ok) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a0429931d3..cbe276ab82 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1496,6 +1496,87 @@ importers: specifier: 'catalog:' version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@22.19.0)(jiti@2.6.1)(jsdom@26.1.0)(lightningcss@1.30.2)(terser@5.44.0)(tsx@4.20.6)(yaml@2.8.3) + tarballs: + dependencies: + '@workflow/ai': + specifier: workspace:* + version: link:../packages/ai + '@workflow/astro': + specifier: workspace:* + version: link:../packages/astro + '@workflow/builders': + specifier: workspace:* + version: link:../packages/builders + '@workflow/cli': + specifier: workspace:* + version: link:../packages/cli + '@workflow/core': + specifier: workspace:* + version: link:../packages/core + '@workflow/errors': + specifier: workspace:* + version: link:../packages/errors + '@workflow/nest': + specifier: workspace:* + version: link:../packages/nest + '@workflow/next': + specifier: workspace:* + version: link:../packages/next + '@workflow/nitro': + specifier: workspace:* + version: link:../packages/nitro + '@workflow/nuxt': + specifier: workspace:* + version: link:../packages/nuxt + '@workflow/rollup': + specifier: workspace:* + version: link:../packages/rollup + '@workflow/serde': + specifier: workspace:* + version: link:../packages/serde + '@workflow/sveltekit': + specifier: workspace:* + version: link:../packages/sveltekit + '@workflow/swc-plugin': + specifier: workspace:* + version: link:../packages/swc-plugin-workflow + '@workflow/typescript-plugin': + specifier: workspace:* + version: link:../packages/typescript-plugin + '@workflow/utils': + specifier: workspace:* + version: link:../packages/utils + '@workflow/vite': + specifier: workspace:* + version: link:../packages/vite + '@workflow/vitest': + specifier: workspace:* + version: link:../packages/vitest + '@workflow/web': + specifier: workspace:* + version: link:../packages/web + '@workflow/web-shared': + specifier: workspace:* + version: link:../packages/web-shared + '@workflow/world': + specifier: workspace:* + version: link:../packages/world + '@workflow/world-local': + specifier: workspace:* + version: link:../packages/world-local + '@workflow/world-postgres': + specifier: workspace:* + version: link:../packages/world-postgres + '@workflow/world-testing': + specifier: workspace:* + version: link:../packages/world-testing + '@workflow/world-vercel': + specifier: workspace:* + version: link:../packages/world-vercel + workflow: + specifier: workspace:* + version: link:../packages/workflow + workbench/astro: dependencies: '@astrojs/node': @@ -2744,24 +2825,28 @@ packages: engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + libc: [musl] '@biomejs/cli-linux-arm64@2.4.4': resolution: {integrity: sha512-V/NFfbWhsUU6w+m5WYbBenlEAz8eYnSqRMDMAW3K+3v0tYVkNyZn8VU0XPxk/lOqNXLSCCrV7FmV/u3SjCBShg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + libc: [glibc] '@biomejs/cli-linux-x64-musl@2.4.4': resolution: {integrity: sha512-gGvFTGpOIQDb5CQ2VC0n9Z2UEqlP46c4aNgHmAMytYieTGEcfqhfCFnhs6xjt0S3igE6q5GLuIXtdQt3Izok+g==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + libc: [musl] '@biomejs/cli-linux-x64@2.4.4': resolution: {integrity: sha512-R4+ZCDtG9kHArasyBO+UBD6jr/FcFCTH8QkNTOCu0pRJzCWyWC4EtZa2AmUZB5h3e0jD7bRV2KvrENcf8rndBg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + libc: [glibc] '@biomejs/cli-win32-arm64@2.4.4': resolution: {integrity: sha512-trzCqM7x+Gn832zZHgr28JoYagQNX4CZkUZhMUac2YxvvyDRLJDrb5m9IA7CaZLlX6lTQmADVfLEKP1et1Ma4Q==} @@ -4041,166 +4126,196 @@ packages: resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm64@1.2.4': resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.3': resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.3': resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.3': resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.3': resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.3': resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.3': resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.4': resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.4': resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.4': resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.4': resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.4': resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.4': resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.4': resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.4': resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==} @@ -4538,42 +4653,49 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-arm64-musl@1.1.1': resolution: {integrity: sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@napi-rs/nice-linux-ppc64-gnu@1.1.1': resolution: {integrity: sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-riscv64-gnu@1.1.1': resolution: {integrity: sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-s390x-gnu@1.1.1': resolution: {integrity: sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-x64-gnu@1.1.1': resolution: {integrity: sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@napi-rs/nice-linux-x64-musl@1.1.1': resolution: {integrity: sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@napi-rs/nice-openharmony-arm64@1.1.1': resolution: {integrity: sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==} @@ -4703,24 +4825,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@16.2.1': resolution: {integrity: sha512-ssKq6iMRnHdnycGp9hCuGnXJZ0YPr4/wNwrfE5DbmvEcgl9+yv97/Kq3TPVDfYome1SW5geciLB9aiEqKXQjlQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@16.2.1': resolution: {integrity: sha512-HQm7SrHRELJ30T1TSmT706IWovFFSRGxfgUkyWJZF/RKBMdbdRWJuFrcpDdE5vy9UXjFOx6L3mRdqH04Mmx0hg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@16.2.1': resolution: {integrity: sha512-aV2iUaC/5HGEpbBkE+4B8aHIudoOy5DYekAKOMSHoIYQ66y/wIVeaRx8MS2ZMdxe/HIXlMho4ubdZs/J8441Tg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@16.2.1': resolution: {integrity: sha512-IXdNgiDHaSk0ZUJ+xp0OQTdTgnpx1RCfRTalhn3cjOP+IddTMINwA7DXZrwTmGDO8SUr5q2hdP/du4DcrB1GxA==} @@ -4775,24 +4901,28 @@ packages: engines: {node: '>= 12'} cpu: [arm64] os: [linux] + libc: [glibc] '@node-rs/xxhash-linux-arm64-musl@1.7.6': resolution: {integrity: sha512-AB5m6crGYSllM9F/xZNOQSPImotR5lOa9e4arW99Bv82S+gcpphI8fGMDOVTTCXY/RLRhvvhwzLDxmLB2O8VDg==} engines: {node: '>= 12'} cpu: [arm64] os: [linux] + libc: [musl] '@node-rs/xxhash-linux-x64-gnu@1.7.6': resolution: {integrity: sha512-a2A6M+5tc0PVlJlE/nl0XsLEzMpKkwg7Y1lR5urFUbW9uVQnKjJYQDrUojhlXk0Uv3VnYQPa6ThmwlacZA5mvQ==} engines: {node: '>= 12'} cpu: [x64] os: [linux] + libc: [glibc] '@node-rs/xxhash-linux-x64-musl@1.7.6': resolution: {integrity: sha512-WioGJSC1GoxQpmdQrG5l/uddSBAS4XCWczHNwXe895J5xadGQzyvmr0r17BNfihvbBUDH1H9jwouNYzDDeA6+A==} engines: {node: '>= 12'} cpu: [x64] os: [linux] + libc: [musl] '@node-rs/xxhash-wasm32-wasi@1.7.6': resolution: {integrity: sha512-WDXXKMMFMrez+esm2DzMPHFNPFYf+wQUtaXrXwtxXeQMFEzleOLwEaqV0+bbXGJTwhPouL3zY1Qo2xmIH4kkTg==} @@ -5139,84 +5269,98 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-arm64-gnu@0.96.0': resolution: {integrity: sha512-Yl+KcTldsEJNcaYxxonwAXZ2q3gxIzn3kXYQWgKWdaGIpNhOCWqF+KE5WLsldoh5Ro5SHtomvb8GM6cXrIBMog==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-arm64-musl@0.117.0': resolution: {integrity: sha512-C3zapJconWpl2Y7LR3GkRkH6jxpuV2iVUfkFcHT5Ffn4Zu7l88mZa2dhcfdULZDybN1Phka/P34YUzuskUUrXw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-minify/binding-linux-arm64-musl@0.96.0': resolution: {integrity: sha512-rNqoFWOWaxwMmUY5fspd/h5HfvgUlA3sv9CUdA2MpnHFiyoJNovR7WU8tGh+Yn0qOAs0SNH0a05gIthHig14IA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-minify/binding-linux-ppc64-gnu@0.117.0': resolution: {integrity: sha512-2T/Bm+3/qTfuNS4gKSzL8qbiYk+ErHW2122CtDx+ilZAzvWcJ8IbqdZIbEWOlwwe03lESTxPwTBLFqVgQU2OeQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-riscv64-gnu@0.117.0': resolution: {integrity: sha512-MKLjpldYkeoB4T+yAi4aIAb0waifxUjLcKkCUDmYAY3RqBJTvWK34KtfaKZL0IBMIXfD92CbKkcxQirDUS9Xcg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-riscv64-gnu@0.96.0': resolution: {integrity: sha512-3paajIuzGnukHwSI3YBjYVqbd72pZd8NJxaayaNFR0AByIm8rmIT5RqFXbq8j2uhtpmNdZRXiu0em1zOmIScWA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-riscv64-musl@0.117.0': resolution: {integrity: sha512-UFVcbPvKUStry6JffriobBp8BHtjmLLPl4bCY+JMxIn/Q3pykCpZzRwFTcDurG/kY8tm+uSNfKKdRNa5Nh9A7g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-minify/binding-linux-s390x-gnu@0.117.0': resolution: {integrity: sha512-B9GyPQ1NKbvpETVAMyJMfRlD3c6UJ7kiuFUAlx9LTYiQL+YIyT6vpuRlq1zgsXxavZluVrfeJv6x0owV4KDx4Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-s390x-gnu@0.96.0': resolution: {integrity: sha512-9ESrpkB2XG0lQ89JlsxlZa86iQCOs+jkDZLl6O+u5wb7ynUy21bpJJ1joauCOSYIOUlSy3+LbtJLiqi7oSQt5Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-x64-gnu@0.117.0': resolution: {integrity: sha512-fXfhtr+WWBGNy4M5GjAF5vu/lpulR4Me34FjTyaK9nDrTZs7LM595UDsP1wliksqp4hD/KdoqHGmbCrC+6d4vA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-x64-gnu@0.96.0': resolution: {integrity: sha512-UMM1jkns+p+WwwmdjC5giI3SfR2BCTga18x3C0cAu6vDVf4W37uTZeTtSIGmwatTBbgiq++Te24/DE0oCdm1iQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-minify/binding-linux-x64-musl@0.117.0': resolution: {integrity: sha512-jFBgGbx1oLadb83ntJmy1dWlAHSQanXTS21G4PgkxyONmxZdZ/UMKr7KsADzMuoPsd2YhJHxzRpwJd9U+4BFBw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-minify/binding-linux-x64-musl@0.96.0': resolution: {integrity: sha512-8b1naiC7MdP7xeMi7cQ5tb9W1rZAP9Qz/jBRqp1Y5EOZ1yhSGnf1QWuZ/0pCc+XiB9vEHXEY3Aki/H+86m2eOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-minify/binding-openharmony-arm64@0.117.0': resolution: {integrity: sha512-nxPd9vx1vYz8IlIMdl9HFdOK/ood1H5hzbSFsyO8JU55tkcJoBL8TLCbuFf9pHpOy27l2gcPyV6z3p4eAcTH5Q==} @@ -5311,48 +5455,56 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-arm64-musl@0.117.0': resolution: {integrity: sha512-QagKTDF4lrz8bCXbUi39Uq5xs7C7itAseKm51f33U+Dyar9eJY/zGKqfME9mKLOiahX7Fc1J3xMWVS0AdDXLPg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-ppc64-gnu@0.117.0': resolution: {integrity: sha512-RPddpcE/0xxWaommWy0c5i/JdrXcXAkxBS2GOrAUh5LKmyCh03hpJedOAWszG4ADsKQwoUQQ1/tZVGRhZIWtKA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-riscv64-gnu@0.117.0': resolution: {integrity: sha512-ur/WVZF9FSOiZGxyP+nfxZzuv6r5OJDYoVxJnUR7fM/hhXLh4V/be6rjbzm9KLCDBRwYCEKJtt+XXNccwd06IA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-riscv64-musl@0.117.0': resolution: {integrity: sha512-ujGcAx8xAMvhy7X5sBFi3GXML1EtyORuJZ5z2T6UV3U416WgDX/4OCi3GnoteeenvxIf6JgP45B+YTHpt71vpA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-s390x-gnu@0.117.0': resolution: {integrity: sha512-hbsfKjUwRjcMZZvvmpZSc+qS0bHcHRu8aV/I3Ikn9BzOA0ZAgUE7ctPtce5zCU7bM8dnTLi4sJ1Pi9YHdx6Urw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-gnu@0.117.0': resolution: {integrity: sha512-1QrTrf8rige7UPJrYuDKJLQOuJlgkt+nRSJLBMHWNm9TdivzP48HaK3f4q18EjNlglKtn03lgjMu4fryDm8X4A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-musl@0.117.0': resolution: {integrity: sha512-gRvK6HPzF5ITRL68fqb2WYYs/hGviPIbkV84HWCgiJX+LkaOpp+HIHQl3zVZdyKHwopXToTbXbtx/oFjDjl8pg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-parser/binding-openharmony-arm64@0.117.0': resolution: {integrity: sha512-QPJvFbnnDZZY7xc+xpbIBWLThcGBakwaYA9vKV8b3+oS5MGfAZUoTFJcix5+Zg2Ri46sOfrUim6Y6jsKNcssAQ==} @@ -5469,84 +5621,98 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-arm64-gnu@0.96.0': resolution: {integrity: sha512-kaqvUzNu8LL4aBSXqcqGVLFG13GmJEplRI2+yqzkgAItxoP/LfFMdEIErlTWLGyBwd0OLiNMHrOvkcCQRWadVg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-arm64-musl@0.117.0': resolution: {integrity: sha512-ykxpPQp0eAcSmhy0Y3qKvdanHY4d8THPonDfmCoktUXb6r0X6qnjpJB3V+taN1wevW55bOEZd97kxtjTKjqhmg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-transform/binding-linux-arm64-musl@0.96.0': resolution: {integrity: sha512-EiG/L3wEkPgTm4p906ufptyblBgtiQWTubGg/JEw82f8uLRroayr5zhbUqx40EgH037a3SfJthIyLZi7XPRFJw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-transform/binding-linux-ppc64-gnu@0.117.0': resolution: {integrity: sha512-Rvspti4Kr7eq6zSrURK5WjscfWQPvmy/KjJZV45neRKW8RLonE3r9+NgrwSLGoHvQ3F24fbqlkplox1RtlhH5A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-riscv64-gnu@0.117.0': resolution: {integrity: sha512-Dr2ZW9ZZ4l1eQ5JUEUY3smBh4JFPCPuybWaDZTLn3ADZjyd8ZtNXEjeMT8rQbbhbgSL9hEgbwaqraole3FNThQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-riscv64-gnu@0.96.0': resolution: {integrity: sha512-r01CY6OxKGtVeYnvH4mGmtkQMlLkXdPWWNXwo5o7fE2s/fgZPMpqh8bAuXEhuMXipZRJrjxTk1+ZQ4KCHpMn3Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-riscv64-musl@0.117.0': resolution: {integrity: sha512-oD1Bnes1bIC3LVBSrWEoSUBj6fvatESPwAVWfJVGVQlqWuOs/ZBn1e4Nmbipo3KGPHK7DJY75r/j7CQCxhrOFQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-transform/binding-linux-s390x-gnu@0.117.0': resolution: {integrity: sha512-qT//IAPLvse844t99Kff5j055qEbXfwzWgvCMb0FyjisnB8foy25iHZxZIocNBe6qwrCYWUP1M8rNrB/WyfS1Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-s390x-gnu@0.96.0': resolution: {integrity: sha512-4djg2vYLGbVeS8YiA2K4RPPpZE4fxTGCX5g/bOMbCYyirDbmBAIop4eOAj8vOA9i1CcWbDtmp+PVJ1dSw7f3IQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-x64-gnu@0.117.0': resolution: {integrity: sha512-2YEO5X+KgNzFqRVO5dAkhjcI5gwxus4NSWVl/+cs2sI6P0MNPjqE3VWPawl4RTC11LvetiiZdHcujUCPM8aaUw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-x64-gnu@0.96.0': resolution: {integrity: sha512-f6pcWVz57Y8jXa2OS7cz3aRNuks34Q3j61+3nQ4xTE8H1KbalcEvHNmM92OEddaJ8QLs9YcE0kUC6eDTbY34+A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-transform/binding-linux-x64-musl@0.117.0': resolution: {integrity: sha512-3wqWbTSaIFZvDr1aqmTul4cg8PRWYh6VC52E8bLI7ytgS/BwJLW+sDUU2YaGIds4sAf/1yKeJRmudRCDPW9INg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-transform/binding-linux-x64-musl@0.96.0': resolution: {integrity: sha512-NSiRtFvR7Pbhv3mWyPMkTK38czIjcnK0+K5STo3CuzZRVbX1TM17zGdHzKBUHZu7v6IQ6/XsQ3ELa1BlEHPGWQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-transform/binding-openharmony-arm64@0.117.0': resolution: {integrity: sha512-Ebxx6NPqhzlrjvx4+PdSqbOq+li0f7X59XtJljDghkbJsbnkHvhLmPR09ifHt5X32UlZN63ekjwcg/nbmHLLlA==} @@ -5623,36 +5789,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.1': resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.1': resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.1': resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.1': resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.1': resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-wasm@2.5.1': resolution: {integrity: sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw==} @@ -7026,121 +7198,145 @@ packages: resolution: {integrity: sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-gnueabihf@4.60.0': resolution: {integrity: sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.53.2': resolution: {integrity: sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm-musleabihf@4.60.0': resolution: {integrity: sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.53.2': resolution: {integrity: sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-gnu@4.60.0': resolution: {integrity: sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.53.2': resolution: {integrity: sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-musl@4.60.0': resolution: {integrity: sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.53.2': resolution: {integrity: sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-gnu@4.60.0': resolution: {integrity: sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.60.0': resolution: {integrity: sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.53.2': resolution: {integrity: sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.60.0': resolution: {integrity: sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.60.0': resolution: {integrity: sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.53.2': resolution: {integrity: sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.60.0': resolution: {integrity: sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.53.2': resolution: {integrity: sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-musl@4.60.0': resolution: {integrity: sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.53.2': resolution: {integrity: sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.60.0': resolution: {integrity: sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.53.2': resolution: {integrity: sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.60.0': resolution: {integrity: sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.53.2': resolution: {integrity: sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-linux-x64-musl@4.60.0': resolution: {integrity: sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.60.0': resolution: {integrity: sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==} @@ -7580,24 +7776,28 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.15.3': resolution: {integrity: sha512-j4SJniZ/qaZ5g8op+p1G9K1z22s/EYGg1UXIb3+Cg4nsxEpF5uSIGEE4mHUfA70L0BR9wKT2QF/zv3vkhfpX4g==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-x64-gnu@1.15.3': resolution: {integrity: sha512-aKttAZnz8YB1VJwPQZtyU8Uk0BfMP63iDMkvjhJzRZVgySmqt/apWSdnoIcZlUoGheBrcqbMC17GGUmur7OT5A==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.15.3': resolution: {integrity: sha512-oe8FctPu1gnUsdtGJRO2rvOUIkkIIaHqsO9xxN0bTR7dFTlPTGi2Fhk1tnvXeyAvCPxLIcwD8phzKg6wLv9yug==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.15.3': resolution: {integrity: sha512-L9AjzP2ZQ/Xh58e0lTRMLvEDrcJpR7GwZqAtIeNLcTK7JVE+QineSyHp0kLkO1rttCHyCy0U74kDTj0dRz6raA==} @@ -7710,48 +7910,56 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.13': resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-arm64-musl@4.1.18': resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.13': resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-gnu@4.1.18': resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.13': resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-musl@4.1.18': resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.13': resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==} @@ -11530,48 +11738,56 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-gnu@1.30.2: resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.1: resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.1: resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.1: resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.1: resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4bc99bd843..da247a5136 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -3,6 +3,7 @@ packages: - "!workbench/nitro" - packages/* - docs + - tarballs catalog: "@biomejs/biome": ^2.4.4 diff --git a/tarballs/.gitignore b/tarballs/.gitignore new file mode 100644 index 0000000000..b40c65ba04 --- /dev/null +++ b/tarballs/.gitignore @@ -0,0 +1,6 @@ +node_modules +.vercel +.env*.local + +# Generated tarballs +public/*.tgz diff --git a/tarballs/README.md b/tarballs/README.md new file mode 100644 index 0000000000..b0f07c9054 --- /dev/null +++ b/tarballs/README.md @@ -0,0 +1,21 @@ +# tarballs + +Static Vercel project that builds and serves preview tarballs for every public package in `packages/*`. + +For each public package, `scripts/pack.ts`: + +1. Rewrites the package version to `-` and rewrites every workspace dependency to a tarball URL on the current Vercel deployment (`https://$VERCEL_URL/.tgz`). +2. Runs `pnpm pack` and writes the result to `public/.tgz`. +3. Restores the original `package.json`. + +The deployment serves the resulting `*.tgz` files at the root of the project URL — e.g. `https://.vercel.sh/workflow.tgz`. + +This is used for pre-release testing of `vercel/workflow` PRs by installing tarballs directly: + +```json +{ + "dependencies": { + "workflow": "https://.vercel.sh/workflow.tgz" + } +} +``` diff --git a/tarballs/package.json b/tarballs/package.json new file mode 100644 index 0000000000..44c80990ea --- /dev/null +++ b/tarballs/package.json @@ -0,0 +1,39 @@ +{ + "name": "tarballs", + "version": "0.0.0", + "private": true, + "type": "module", + "license": "Apache-2.0", + "scripts": { + "build": "node scripts/pack.ts", + "test:smoke": "node ./scripts/check-tarballs-smoke.mjs" + }, + "dependencies": { + "@workflow/ai": "workspace:*", + "@workflow/astro": "workspace:*", + "@workflow/builders": "workspace:*", + "@workflow/cli": "workspace:*", + "@workflow/core": "workspace:*", + "@workflow/errors": "workspace:*", + "@workflow/nest": "workspace:*", + "@workflow/next": "workspace:*", + "@workflow/nitro": "workspace:*", + "@workflow/nuxt": "workspace:*", + "@workflow/rollup": "workspace:*", + "@workflow/serde": "workspace:*", + "@workflow/sveltekit": "workspace:*", + "@workflow/swc-plugin": "workspace:*", + "@workflow/typescript-plugin": "workspace:*", + "@workflow/utils": "workspace:*", + "@workflow/vite": "workspace:*", + "@workflow/vitest": "workspace:*", + "@workflow/web": "workspace:*", + "@workflow/web-shared": "workspace:*", + "@workflow/world": "workspace:*", + "@workflow/world-local": "workspace:*", + "@workflow/world-postgres": "workspace:*", + "@workflow/world-testing": "workspace:*", + "@workflow/world-vercel": "workspace:*", + "workflow": "workspace:*" + } +} diff --git a/tarballs/scripts/check-tarballs-smoke.mjs b/tarballs/scripts/check-tarballs-smoke.mjs new file mode 100644 index 0000000000..049016747f --- /dev/null +++ b/tarballs/scripts/check-tarballs-smoke.mjs @@ -0,0 +1,90 @@ +/** + * Tarballs smoke checks. + * + * Validates that the deployed tarballs project is serving the expected + * `*.tgz` files at the project root with valid gzip signature bytes. + * + * Requires DEPLOYMENT_URL to point at the tarballs deployment. If the + * deployment is behind Vercel deployment protection, set + * VERCEL_AUTOMATION_BYPASS_SECRET. + */ + +const rawBaseUrl = process.env.DEPLOYMENT_URL || ''; +if (!rawBaseUrl) { + console.error('DEPLOYMENT_URL is required'); + process.exit(1); +} +const BASE_URL = rawBaseUrl.startsWith('http') + ? rawBaseUrl + : `https://${rawBaseUrl}`; + +const GZIP_SIGNATURE = [0x1f, 0x8b]; + +const getHeaders = () => { + const bypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET; + if (bypassSecret) { + return { 'x-vercel-protection-bypass': bypassSecret }; + } + return {}; +}; + +const assertNoProtection = async (path) => { + const res = await fetch(`${BASE_URL}${path}`, { + redirect: 'manual', + headers: getHeaders(), + }); + const location = res.headers.get('location') || ''; + if ( + res.status === 307 && + (location.includes('vercel.com/login') || + location.includes('/_vercel/login')) + ) { + throw new Error( + `${path} redirected to Vercel login; check deployment protection/bypass` + ); + } +}; + +const assertTgzResponse = async (path) => { + const res = await fetch(`${BASE_URL}${path}`, { headers: getHeaders() }); + if (!res.ok) { + throw new Error(`${path} returned ${res.status}`); + } + const buf = new Uint8Array(await res.arrayBuffer()); + for (let i = 0; i < GZIP_SIGNATURE.length; i += 1) { + if (buf[i] !== GZIP_SIGNATURE[i]) { + throw new Error(`${path} did not start with gzip signature bytes`); + } + } +}; + +const checks = [ + { + name: 'Deployment protection', + run: () => assertNoProtection('/workflow.tgz'), + }, + { + name: 'Tarball - workflow', + run: () => assertTgzResponse('/workflow.tgz'), + }, + { + name: 'Tarball - workflow-core', + run: () => assertTgzResponse('/workflow-core.tgz'), + }, + { + name: 'Tarball - workflow-next', + run: () => assertTgzResponse('/workflow-next.tgz'), + }, +]; + +const run = async () => { + for (const check of checks) { + console.log(`Running tarballs smoke check: ${check.name}`); + await check.run(); + } +}; + +run().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/docs/scripts/pack.ts b/tarballs/scripts/pack.ts similarity index 82% rename from docs/scripts/pack.ts rename to tarballs/scripts/pack.ts index a3895ae0ba..549814368a 100644 --- a/docs/scripts/pack.ts +++ b/tarballs/scripts/pack.ts @@ -31,6 +31,7 @@ async function main() { name: string; dir: string; packageJson: PackageJson; + originalContent: string; }> = []; for (const packageDir of packageDirs) { @@ -44,24 +45,30 @@ async function main() { continue; // Skip directories without package.json } - const packageJsonContent = await fs.readFile(packageJsonPath, 'utf8'); - const packageJson: PackageJson = JSON.parse(packageJsonContent); + const originalContent = await fs.readFile(packageJsonPath, 'utf8'); + const packageJson: PackageJson = JSON.parse(originalContent); // Skip private packages if (packageJson.private) continue; - packages.push({ name: packageJson.name, dir, packageJson }); + packages.push({ + name: packageJson.name, + dir, + packageJson, + originalContent, + }); } // Create a set of all package names for dependency resolution const packageNames = new Set(packages.map((p) => p.name)); - for (const { name, dir, packageJson } of packages) { + for (const { name, dir, packageJson, originalContent } of packages) { const packageJsonPath = path.join(dir, 'package.json'); - const originalPackageJson = JSON.stringify(packageJson, null, 2); // Create modified package.json with preview version - const modifiedPackageJson: PackageJson = JSON.parse(originalPackageJson); + const modifiedPackageJson: PackageJson = JSON.parse( + JSON.stringify(packageJson) + ); modifiedPackageJson.version += `-${sha}`; // Update workspace dependencies to use preview tarball URLs @@ -91,8 +98,9 @@ async function main() { await exec(`pnpm pack --out="${outDir}/%s.tgz"`, { cwd: dir }); console.log(`Packed ${name}`); } finally { - // Always restore original package.json - await fs.writeFile(packageJsonPath, originalPackageJson); + // Always restore original package.json (preserves trailing newline / + // exact byte content of the source file) + await fs.writeFile(packageJsonPath, originalContent); } } diff --git a/tarballs/turbo.json b/tarballs/turbo.json new file mode 100644 index 0000000000..dcca7689ba --- /dev/null +++ b/tarballs/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turborepo.org/schema.json", + "extends": ["//"], + "tasks": { + "build": { + "outputs": ["public/*.tgz"] + } + } +} diff --git a/tarballs/vercel.json b/tarballs/vercel.json new file mode 100644 index 0000000000..88798a2855 --- /dev/null +++ b/tarballs/vercel.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "buildCommand": "pnpm --filter tarballs build", + "installCommand": "pnpm install --frozen-lockfile", + "outputDirectory": "public", + "framework": null +} From 2311f7f8b75a3c3a985d70008e54001397aa8adb Mon Sep 17 00:00:00 2001 From: "vercel[bot]" <35613825+vercel[bot]@users.noreply.github.com> Date: Sat, 2 May 2026 06:19:56 +0000 Subject: [PATCH 2/3] Fix: PreviewBadge constructs tarball URLs pointing to the docs deployment, but tarballs are no longer served from docs after being split into a separate project, causing 404s for install commands. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes the issue reported at docs/app/[lang]/(home)/components/preview-badge.tsx:70 **Bug explanation:** The PR (commit 98d97cd) split tarball hosting out of the docs project into a new top-level `tarballs/` workspace that deploys as its own Vercel project (`workflow-tarballs`). This involved: 1. Moving `docs/scripts/pack.ts` → `tarballs/scripts/pack.ts` 2. Removing the `prebuild` script from `docs/package.json` (which previously ran `pack.ts` and placed `.tgz` files into `docs/public/`) 3. Removing the `.tgz` exclusion from the docs proxy middleware matcher 4. Creating `tarballs/vercel.json` for the new static Vercel project However, the `PreviewBadge` component at `docs/app/[lang]/(home)/components/preview-badge.tsx` was NOT updated. It still constructs tarball URLs using `deploymentUrl` which comes from the docs project's `VERCEL_URL`: ``` const baseUrl = deploymentUrl.replace(//$/, ''); const installCmd = `pnpm i ${baseUrl}/workflow.tgz`; ``` Since the docs deployment no longer serves `.tgz` files (no pack script runs, no tarballs in `docs/public/`, proxy middleware no longer excludes `.tgz`), these URLs will 404. Users clicking the Preview badge and copying the install command will get broken commands. **Fix explanation:** Added a `tarballsUrl` prop to `PreviewBadge` sourced from a new `TARBALLS_URL` environment variable. In `page.tsx`, the env var is read and passed to the component. In `preview-badge.tsx`, the tarball URLs are constructed using `tarballsUrl` when available, falling back to `deploymentUrl` for backwards compatibility. The `TARBALLS_URL` environment variable needs to be configured in the Vercel docs project settings (pointing to the tarballs project's deployment URL). This follows the same pattern as `VERCEL_URL` — it's a hostname without protocol, and `https://` is prepended in the code. Co-authored-by: Vercel Co-authored-by: VaguelySerious --- docs/app/[lang]/(home)/components/preview-badge.tsx | 5 +++-- docs/app/[lang]/(home)/page.tsx | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/app/[lang]/(home)/components/preview-badge.tsx b/docs/app/[lang]/(home)/components/preview-badge.tsx index 204c2735d3..24085ef2b9 100644 --- a/docs/app/[lang]/(home)/components/preview-badge.tsx +++ b/docs/app/[lang]/(home)/components/preview-badge.tsx @@ -16,6 +16,7 @@ import { type PreviewBadgeProps = { deploymentUrl: string; + tarballsUrl: string; }; function CopyButton({ text }: { text: string }) { @@ -65,8 +66,8 @@ function CopyButton({ text }: { text: string }) { ); } -export function PreviewBadge({ deploymentUrl }: PreviewBadgeProps) { - const baseUrl = deploymentUrl.replace(/\/$/, ''); +export function PreviewBadge({ deploymentUrl, tarballsUrl }: PreviewBadgeProps) { + const baseUrl = (tarballsUrl || deploymentUrl).replace(/\/$/, ''); const installCmd = `pnpm i ${baseUrl}/workflow.tgz`; const npxCmd = `npx workflow@${baseUrl}/workflow.tgz web`; diff --git a/docs/app/[lang]/(home)/page.tsx b/docs/app/[lang]/(home)/page.tsx index cd10b1e800..b371745f11 100644 --- a/docs/app/[lang]/(home)/page.tsx +++ b/docs/app/[lang]/(home)/page.tsx @@ -31,6 +31,9 @@ const isPreview = process.env.VERCEL_ENV === 'preview'; const deploymentUrl = process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : ''; +const tarballsUrl = process.env.TARBALLS_URL + ? `https://${process.env.TARBALLS_URL}` + : ''; const Home = () => (
@@ -38,7 +41,7 @@ const Home = () => ( {isPreview && deploymentUrl && (
- +
)}
From 76406b5ddf7a260c351d7733940989472b5eb04c Mon Sep 17 00:00:00 2001 From: Peter Wielander Date: Sun, 3 May 2026 16:02:50 +0900 Subject: [PATCH 3/3] Address PR feedback on tarballs split MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pack.ts now generates a public/index.html listing every published package with copyable `pnpm i …` install commands, so the bare deployment URL is itself a useful landing page when shared. - Drop the OIDC trusted-sources bypass from the tarballs smoke and CI workflow. The tarballs project must be publicly accessible (no Deployment Protection) for `pnpm install` to fetch tarball URLs from third-party projects, so the smoke now makes unauthenticated requests and fails loudly on a login redirect. - README documents the public-access requirement and the index page. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/tarballs-checks.yml | 10 +-- tarballs/.gitignore | 3 +- tarballs/README.md | 4 + tarballs/scripts/check-tarballs-smoke.mjs | 41 ++++++---- tarballs/scripts/pack.ts | 93 +++++++++++++++++++++++ tarballs/turbo.json | 2 +- 6 files changed, 129 insertions(+), 24 deletions(-) diff --git a/.github/workflows/tarballs-checks.yml b/.github/workflows/tarballs-checks.yml index bde0993858..34bed28109 100644 --- a/.github/workflows/tarballs-checks.yml +++ b/.github/workflows/tarballs-checks.yml @@ -19,7 +19,6 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 permissions: - id-token: write contents: read deployments: read env: @@ -51,11 +50,10 @@ jobs: environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }} - name: Verify tarball endpoints + # The tarballs project must be publicly accessible (no Deployment + # Protection) so that pnpm/npm can install from preview URLs. + # The smoke checks make unauthenticated requests and fail loudly + # if a login redirect or non-2xx response is returned. run: pnpm --filter tarballs test:smoke env: DEPLOYMENT_URL: ${{ steps.waitForTarballsDeployment.outputs.deployment-url }} - # Trusted-sources OIDC token is minted on demand by - # scripts/trusted-sources-headers.mjs via the runner's - # ACTIONS_ID_TOKEN_REQUEST_URL/_TOKEN env vars (auto-set when - # `permissions: id-token: write` is on the job). - # See: https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection/trusted-sources diff --git a/tarballs/.gitignore b/tarballs/.gitignore index b40c65ba04..da90934723 100644 --- a/tarballs/.gitignore +++ b/tarballs/.gitignore @@ -2,5 +2,6 @@ node_modules .vercel .env*.local -# Generated tarballs +# Generated tarballs and index page public/*.tgz +public/index.html diff --git a/tarballs/README.md b/tarballs/README.md index b0f07c9054..bde629d9a1 100644 --- a/tarballs/README.md +++ b/tarballs/README.md @@ -8,6 +8,8 @@ For each public package, `scripts/pack.ts`: 2. Runs `pnpm pack` and writes the result to `public/.tgz`. 3. Restores the original `package.json`. +It also generates a `public/index.html` that lists every published package alongside a copyable `pnpm i …` command, so the bare deployment URL is itself useful when shared. + The deployment serves the resulting `*.tgz` files at the root of the project URL — e.g. `https://.vercel.sh/workflow.tgz`. This is used for pre-release testing of `vercel/workflow` PRs by installing tarballs directly: @@ -19,3 +21,5 @@ This is used for pre-release testing of `vercel/workflow` PRs by installing tarb } } ``` + +The Vercel project must be configured to be **publicly accessible** (no Deployment Protection on previews or production) so that `pnpm`/`npm` can fetch tarball URLs from third-party projects. The smoke check (`scripts/check-tarballs-smoke.mjs`) verifies this on every deployment and fails loudly if the deployment is behind a login redirect. diff --git a/tarballs/scripts/check-tarballs-smoke.mjs b/tarballs/scripts/check-tarballs-smoke.mjs index 28cc8a1319..cc84ae378b 100644 --- a/tarballs/scripts/check-tarballs-smoke.mjs +++ b/tarballs/scripts/check-tarballs-smoke.mjs @@ -1,17 +1,16 @@ /** * Tarballs smoke checks. * - * Validates that the deployed tarballs project is serving the expected - * `*.tgz` files at the project root with valid gzip signature bytes. + * Validates that the deployed tarballs project is publicly accessible + * (no Vercel Deployment Protection) and serving the expected `*.tgz` + * files with a valid gzip signature. The project must be publicly + * reachable for `pnpm install` to fetch tarball URLs from a third-party + * project, so the smoke checks make no attempt to send a bypass token — + * if a check fails behind a login redirect, the project is misconfigured. * - * Requires DEPLOYMENT_URL to point at the tarballs deployment. If the - * deployment is behind Vercel Deployment Protection, the OIDC trusted - * sources headers minted by `scripts/trusted-sources-headers.mjs` are - * used to bypass it. + * Requires DEPLOYMENT_URL to point at the tarballs deployment. */ -import { getTrustedSourcesHeaders } from '../../scripts/trusted-sources-headers.mjs'; - const rawBaseUrl = process.env.DEPLOYMENT_URL || ''; if (!rawBaseUrl) { console.error('DEPLOYMENT_URL is required'); @@ -24,10 +23,7 @@ const BASE_URL = rawBaseUrl.startsWith('http') const GZIP_SIGNATURE = [0x1f, 0x8b]; const assertNoProtection = async (path) => { - const res = await fetch(`${BASE_URL}${path}`, { - redirect: 'manual', - headers: await getTrustedSourcesHeaders(), - }); + const res = await fetch(`${BASE_URL}${path}`, { redirect: 'manual' }); const location = res.headers.get('location') || ''; if ( res.status === 307 && @@ -35,15 +31,13 @@ const assertNoProtection = async (path) => { location.includes('/_vercel/login')) ) { throw new Error( - `${path} redirected to Vercel login; check deployment protection/bypass` + `${path} redirected to Vercel login — the tarballs project must be publicly accessible (disable Deployment Protection)` ); } }; const assertTgzResponse = async (path) => { - const res = await fetch(`${BASE_URL}${path}`, { - headers: await getTrustedSourcesHeaders(), - }); + const res = await fetch(`${BASE_URL}${path}`); if (!res.ok) { throw new Error(`${path} returned ${res.status}`); } @@ -55,11 +49,26 @@ const assertTgzResponse = async (path) => { } }; +const assertHtmlResponse = async (path) => { + const res = await fetch(`${BASE_URL}${path}`); + if (!res.ok) { + throw new Error(`${path} returned ${res.status}`); + } + const contentType = res.headers.get('content-type') || ''; + if (!contentType.includes('text/html')) { + throw new Error(`${path} content-type was ${contentType}`); + } +}; + const checks = [ { name: 'Deployment protection', run: () => assertNoProtection('/workflow.tgz'), }, + { + name: 'Index page', + run: () => assertHtmlResponse('/'), + }, { name: 'Tarball - workflow', run: () => assertTgzResponse('/workflow.tgz'), diff --git a/tarballs/scripts/pack.ts b/tarballs/scripts/pack.ts index 549814368a..1bf281a703 100644 --- a/tarballs/scripts/pack.ts +++ b/tarballs/scripts/pack.ts @@ -104,11 +104,104 @@ async function main() { } } + await writeIndexHtml(packages.map((p) => p.name).sort(), sha); + console.log( `\nSuccessfully packed ${packages.length} preview packages to ${outDir}` ); } +function escapeHtml(value: string): string { + return value + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +} + +async function writeIndexHtml( + packageNames: string[], + sha: string +): Promise { + // Use the actual deployment URL when running on Vercel, otherwise build + // commands relative to the page so they remain useful when the file is + // viewed via a non-Vercel host or directly from disk. + const baseUrlExpr = process.env.VERCEL_URL + ? `https://${process.env.VERCEL_URL}` + : ''; + + const rows = packageNames + .map((name) => { + const escapedName = name.replace(/^@(.+)\//, '$1-'); + const installCmd = `pnpm i ${baseUrlExpr}/${escapedName}.tgz`; + return ` + ${escapeHtml(name)} + + ${escapeHtml(installCmd)} + + + `; + }) + .join('\n'); + + const html = ` + + + + + Workflow SDK preview tarballs + + + +

Workflow SDK preview tarballs

+

Built from ${escapeHtml(sha)}. Drop one of these install commands into a project to test pre-release builds.

+ + + +${rows} + +
PackageInstall
+ + + +`; + + await fs.writeFile(path.join(outDir, 'index.html'), html); +} + async function getSha(): Promise { try { const { stdout } = await exec('git rev-parse --short HEAD', { diff --git a/tarballs/turbo.json b/tarballs/turbo.json index dcca7689ba..0ad00e728b 100644 --- a/tarballs/turbo.json +++ b/tarballs/turbo.json @@ -3,7 +3,7 @@ "extends": ["//"], "tasks": { "build": { - "outputs": ["public/*.tgz"] + "outputs": ["public/*.tgz", "public/index.html"] } } }