diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 5518483d2..f4d9cb921 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -23,6 +23,22 @@ jobs: with: cache: npm node-version-file: '.nvmrc' + registry-url: 'https://registry.npmjs.org' + + # Ensure npm 11.5.1 or later is installed + - name: Update npm + run: npm install -g npm@latest + + - name: Install dependencies + run: npm ci + + - name: Build and bundle + run: npm run bundle + env: + NODE_ENV: 'production' - name: Verify server.json run: npm run verify-server-json-version + + - name: Verify npm package + run: npm run verify-npm-package diff --git a/package.json b/package.json index a55107464..5bcfd2ef5 100644 --- a/package.json +++ b/package.json @@ -22,12 +22,12 @@ "test:update-snapshots": "npm run build && node scripts/test.mjs --test-update-snapshots", "prepare": "node --experimental-strip-types scripts/prepare.ts", "verify-server-json-version": "node --experimental-strip-types scripts/verify-server-json-version.ts", + "verify-npm-package": "node scripts/verify-npm-package.mjs", "eval": "npm run build && CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS=true node --experimental-strip-types scripts/eval_gemini.ts", "count-tokens": "node --experimental-strip-types scripts/count_tokens.ts" }, "files": [ "build/src", - "build/node_modules", "LICENSE", "!*.tsbuildinfo" ], diff --git a/scripts/verify-npm-package.mjs b/scripts/verify-npm-package.mjs new file mode 100644 index 000000000..44c74663e --- /dev/null +++ b/scripts/verify-npm-package.mjs @@ -0,0 +1,41 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {execSync} from 'node:child_process'; + +// Checks that the select build files are present using `npm publish --dry-run`. +function verifyPackageContents() { + try { + const output = execSync('npm publish --dry-run --json --silent', { + encoding: 'utf8', + }); + // skip non-JSON output from prepare. + const data = JSON.parse(output.substring(output.indexOf('{'))); + const files = data.files.map(f => f.path); + // Check some important files. + const requiredPaths = [ + 'build/src/index.js', + 'build/src/third_party/index.js', + ]; + for (const requiredPath of requiredPaths) { + const hasBuildFolder = files.some(path => path.startsWith(requiredPath)); + if (!hasBuildFolder) { + console.error( + `Assertion Failed: "${requiredPath}" not found in tarball.`, + ); + process.exit(1); + } + } + console.log( + `npm publish --dry-run contained ${JSON.stringify(requiredPaths)}`, + ); + } catch (err) { + console.error('failed to parse npm publish output', err); + process.exit(1); + } +} + +verifyPackageContents();