Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/package-size-headroom.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@adcp/sdk': patch
---

Trim the published package from 26.86 MB to 24.99 MB packed (8,529 to 8,176 files). Runtime behavior is unchanged.

- The compliance bundles no longer ship their `domains/` directories. Each was a byte-identical copy of `protocols/`, which is what the storyboard loader reads. If you read storyboards from `node_modules/@adcp/sdk/compliance/cache/<version>/domains/<id>/`, read `protocols/<id>/` instead. `index.json` keeps listing both arrays because it is the upstream bundle file.
- The ESM declarations for the generated protocol and registry types (`types/core.generated.d.mts`, `types/tools.generated.d.mts`, `registry/types.generated.d.mts`) now re-export the CommonJS declarations, as `types/schemas.generated.d.mts` already did, instead of shipping a second copy. ESM and CommonJS consumers get the same types.
- The MCP `tools/list` request projections under `dist/lib/schemas-data/<version>/mcp/` are stored as compact JSON. `tools/list` serves the parsed schemas, so the wire output is the same.
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,10 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
# A pull request checks out its merge commit; depth 2 keeps the first
# parent (the merge base) so its package-size measurement can be found.
fetch-depth: 2

- name: Setup Node.js
uses: actions/setup-node@v5
Expand Down Expand Up @@ -309,8 +313,36 @@ jobs:
- name: Guard browser schema portability and tree-shaking budgets
run: npm run test:schemas-browser

# main records each commit's package measurement. A pull request compares
# itself with the record for its exact merge base, so the per-PR growth
# allowance sees only this PR's change. A missing record (the base's main
# run has not finished, or the cache was evicted) skips that comparison;
# the ceilings in scripts/package-size-budget.json still apply.
- name: Resolve package-size merge base
id: size-base
if: github.event_name == 'pull_request'
run: echo "sha=$(git rev-parse HEAD^1)" >> "$GITHUB_OUTPUT"

- name: Restore merge-base package measurement
if: github.event_name == 'pull_request'
uses: actions/cache/restore@v4
with:
path: .context/package-size.json
key: package-size-${{ runner.os }}-${{ steps.size-base.outputs.sha }}

- name: Enforce publish-size budgets
run: npm run check:package-size
env:
PACKAGE_SIZE_BASE_SHA: ${{ steps.size-base.outputs.sha }}
PACKAGE_SIZE_BASELINE: ${{ github.event_name == 'pull_request' && '.context/package-size.json' || '' }}
PACKAGE_SIZE_REPORT: ${{ github.event_name == 'pull_request' && '.context/package-size-head.json' || '.context/package-size.json' }}

- name: Record package measurement for pull requests
if: github.event_name == 'push'
uses: actions/cache/save@v4
with:
path: .context/package-size.json
key: package-size-${{ runner.os }}-${{ github.sha }}

- name: Typecheck reporting storage package
run: npm run typecheck:reporting-storage
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,7 @@
"compliance/cache/3.1.31/**/*",
"compliance/cache/3.2.7/**/*",
"compliance/cache/3.3.0-beta.3/**/*",
"!compliance/cache/*/domains/**/*",
"ADCP_VERSION",
"docs/README.md",
"docs/TYPE-SUMMARY.md",
Expand Down Expand Up @@ -706,7 +707,7 @@
"check:package": "npm run check:runtime-compat && npm run check:packed-artifact && npm run check:publish-protocol-artifacts && npm run typecheck:examples && publint --strict && node --max-old-space-size=8192 ./node_modules/@arethetypeswrong/cli/dist/index.js --pack . --exclude-entrypoints compliance-fixtures/reporting-consumer-status-v1.json compliance-fixtures/principal.yaml compliance-fixtures/reporting-core.yaml compliance-fixtures/canonical-storyboards-provenance.json && npm run check --workspace=@adcp/reporting-storage && node --max-old-space-size=8192 ./node_modules/@arethetypeswrong/cli/dist/index.js --pack packages/reporting-storage",
"check:packed-artifact": "node scripts/check-packed-artifact.mjs && node scripts/check-reporting-consumer-package.mjs && node scripts/check-reporting-storage-package.mjs",
"check:runtime-compat": "node scripts/check-runtime-compat.mjs",
"check:package-size": "node scripts/check-package-size.mjs && node packages/reporting-storage/scripts/check-package.mjs --size",
"check:package-size": "node scripts/check-package-size.mjs",
"check:publish-protocol-artifacts": "node scripts/check-publish-protocol-artifacts.mjs",
"verify:package": "node scripts/verify-package.mjs",
"validate:reporting-gcp": "node packages/reporting-storage/scripts/validate-reporting-gcp.mjs",
Expand Down
65 changes: 36 additions & 29 deletions packages/reporting-storage/scripts/check-package.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Offline checks for the `@adcp/reporting-storage` tarball. Requires a prior `npm run build`.
*
* node scripts/check-package.mjs export map, packed contents and budgets
* node scripts/check-package.mjs --size the budgets only (the root `check:package-size` runs this)
* node scripts/check-package.mjs --size the size ceilings only (the root `check:package-size` checks them too)
*
* The package is built like the SDK (one transpiled module per source module, CommonJS and ESM with both
* declaration flavours), so the checks mirror the SDK's: every export target is packed, nothing from `src/`,
Expand All @@ -19,16 +19,17 @@ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '
// The one example that ships: the integrated production-service walkthrough the guides link to.
const PUBLISHED_EXAMPLE = 'examples/reliable-reporting-service/README.md';

// Measured at 0.0.0: about 408,000 packed bytes, 1,883,000 unpacked, 115 files (28 modules x 4 flavours, the
// manifest, the README and the example). A new module adds four files. Raise a budget deliberately, in the
// change that grows the package.
const MAX_PACKED_BYTES = 450_000;
const MAX_UNPACKED_BYTES = 2_200_000;
// +13 at 0.3: postgresStorage, the versioned migrations and the CLI module (three modules x 4) and
// bin/adcp-reporting-storage.js.
const MAX_FILE_COUNT = 140;
// Size ceilings and the per-PR growth allowance live with the SDK's in the repository's
// scripts/package-size-budget.json, so the root `check:package-size` compares both packages with their merge
// base in one place. A new module adds four files (two runtime formats, two declaration flavours).
const BUDGET_FILE = path.resolve(packageRoot, '..', '..', 'scripts', 'package-size-budget.json');
export const PACKAGE_NAME = '@adcp/reporting-storage';

function pack() {
function ceiling() {
return JSON.parse(readFileSync(BUDGET_FILE, 'utf8')).packages[PACKAGE_NAME].ceiling;
}

export function packReportingStorage() {
const output = execFileSync('npm', ['pack', '--dry-run', '--json', '--ignore-scripts', '--loglevel=error'], {
cwd: packageRoot,
encoding: 'utf8',
Expand All @@ -46,15 +47,15 @@ function pack() {
throw new Error('npm pack did not return package metadata');
}

function checkBudgets(info) {
export function checkReportingStorageBudgets(info) {
const limit = ceiling();
const problems = [];
if (info.size > MAX_PACKED_BYTES)
problems.push(`packed tarball is ${info.size} bytes; budget is ${MAX_PACKED_BYTES}`);
if (info.unpackedSize > MAX_UNPACKED_BYTES) {
problems.push(`unpacked package is ${info.unpackedSize} bytes; budget is ${MAX_UNPACKED_BYTES}`);
if (info.size > limit.packedBytes)
problems.push(`packed tarball is ${info.size} bytes; ceiling is ${limit.packedBytes}`);
if (info.unpackedSize > limit.unpackedBytes) {
problems.push(`unpacked package is ${info.unpackedSize} bytes; ceiling is ${limit.unpackedBytes}`);
}
if (info.entryCount > MAX_FILE_COUNT)
problems.push(`package has ${info.entryCount} files; budget is ${MAX_FILE_COUNT}`);
if (info.entryCount > limit.files) problems.push(`package has ${info.entryCount} files; ceiling is ${limit.files}`);
return problems;
}

Expand Down Expand Up @@ -95,17 +96,23 @@ function checkContents(info) {
return problems;
}

try {
const info = pack();
const problems = [...checkBudgets(info), ...(process.argv.includes('--size') ? [] : checkContents(info))];
if (problems.length > 0) {
for (const problem of problems) console.error(` - ${problem}`);
throw new Error(`${problems.length} package problem(s)`);
const scriptPath = process.argv[1] ? path.resolve(process.argv[1]) : undefined;
if (scriptPath === fileURLToPath(import.meta.url)) {
try {
const info = packReportingStorage();
const problems = [
...checkReportingStorageBudgets(info),
...(process.argv.includes('--size') ? [] : checkContents(info)),
];
if (problems.length > 0) {
for (const problem of problems) console.error(` - ${problem}`);
throw new Error(`${problems.length} package problem(s)`);
}
console.log(
`✅ ${PACKAGE_NAME}: ${info.size} bytes packed, ${info.unpackedSize} unpacked, ${info.entryCount} files`
);
} catch (error) {
console.error(`❌ ${PACKAGE_NAME} package check failed: ${error.message ?? error}`);
process.exitCode = 1;
}
console.log(
`✅ @adcp/reporting-storage: ${info.size} bytes packed, ${info.unpackedSize} unpacked, ${info.entryCount} files`
);
} catch (error) {
console.error(`❌ @adcp/reporting-storage package check failed: ${error.message ?? error}`);
process.exitCode = 1;
}
Loading
Loading