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
12 changes: 10 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ jobs:
run: npm run lint

- name: Format check
run: npm run format:check || true
run: npm run format:check

- name: Type check
run: npm run typecheck

- name: Build
run: npm run build

test:
Expand Down Expand Up @@ -81,6 +84,11 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Run npm audit
# Blocking: anything that ships to consumers must be clean.
- name: Audit production dependencies
run: npm audit --omit=dev --audit-level=high

# Informational: dev-only advisories should be tracked but not block CI.
- name: Audit all dependencies
run: npm audit --audit-level=high
continue-on-error: true
4 changes: 4 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ jobs:
- name: Install dependencies
run: npm ci

# The committed src/schemas.generated.ts is the source of truth and is
# built/published as-is (no network fetch at publish time). `npm test`
# asserts BUNDLED_SPEC_VERSION matches package.json's xarfSpec.version
# (see tests/bundle.test.ts), so a stale bundle fails here, offline.
- name: Run tests
run: npm test

Expand Down
10 changes: 10 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Build output
dist/
coverage/

# Auto-generated (intentionally minified) bundled schemas
src/schemas.generated.ts

# Fetched schemas (gitignored, but excluded here for completeness)
schemas/
.xarf-temp/
43 changes: 41 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,52 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Security

- **Removed the `postinstall` schema fetch.** The package no longer runs a
network download on install, which previously failed `npm install` in
offline/air-gapped/proxied environments and was an install-time supply-chain
surface. Schemas are now bundled into the package at build time.
- **Patched `fast-uri`** (the only runtime-tree advisory) via an `ajv` bump and
a dependency override; the production dependency tree now audits clean.
- **Hardened `scripts/fetch-schemas.js`** (a maintainer-only tool): host
allowlist, redirect-depth cap, and download size cap.
- Added an optional `maxInputBytes` guard to `parse()` to bound untrusted input.

### Added

- `BUNDLED_SPEC_VERSION` export — the xarf-spec version bundled into the build.
- `VERSION` export now derived from `package.json` (no longer hardcoded).
- Dual **ESM + CommonJS** build with an `exports` map and type declarations.

### Changed

- Schemas are read from an in-memory bundle (`src/schemas.generated.ts`,
produced by `scripts/generate-schemas.js`) instead of from the filesystem at
runtime. This removes the `findSchemasDir()` discovery logic and makes the
library work in bundled, serverless, and edge environments.
- `tar` moved from runtime `dependencies` to `devDependencies`.
- Minimum Node version raised to `>=18`.

### Removed

- Dead, unreachable recursive `$ref` loader in `SchemaValidator`.

### Fixed

- Documentation: `parse()`/`createReport()` `strict` mode does **not** throw —
it reports warnings and `x-recommended` fields as errors in the returned
result. The README and JSDoc previously claimed it threw.

## [1.0.0] - 2025-11-30

### Breaking Changes

- **Category Correction**: Removed "other" category to align with XARF v4.0.0 specification
- XARF spec defines exactly 7 categories (not 8)
- Unknown v3 report types now map to `content` category with type `unclassified`
- Unknown v3 report types now throw `XARFParseError` listing the supported types
- Migration: Replace any usage of `category: 'other'` with `category: 'content'`

### Added
Expand All @@ -27,7 +66,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- **Version**: Updated from v1.0.0-alpha.2 to v1.0.0 (production release)
- **Category Validation**: Stricter validation for all 7 official categories
- **v3 Legacy Mapping**: Unknown v3 types now map to `content/unclassified` instead of `other/unclassified`
- **v3 Legacy Mapping**: Unknown v3 types now throw `XARFParseError` (the removed `other/unclassified` fallback no longer exists)
- **Documentation**: Updated all references from 8 to 7 categories

### Fixed
Expand Down
20 changes: 14 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,11 @@ const { report, errors, warnings, info } = parse(jsonData, options?);
**Parameters:**

- `jsonData: string | Record<string, unknown>` — JSON string or object containing a XARF report
- `options.strict?: boolean` — Throw `XARFValidationError` on validation failures (default: `false`)
- `options.strict?: boolean` — Treat warnings (e.g. unknown fields) and `x-recommended` fields as errors (default: `false`)
- `options.showMissingOptional?: boolean` — Include info about missing optional fields (default: `false`)

> `parse()` does not throw on validation failures — inspect the returned `errors` array. It only throws `XARFParseError` when `jsonData` is a malformed JSON string.

**Returns `ParseResult`:**

- `report: XARFReport` — The parsed report, typed by category
Expand All @@ -135,9 +137,11 @@ const { report, errors, warnings } = createReport(input, options?);
**Parameters:**

- `input: ReportInput` — Report data. A discriminated union on `category` that narrows type-safe fields per category (e.g., `MessagingReportInput`, `ConnectionReportInput`, etc.)
- `options.strict?: boolean` — Throw on validation failures (default: `false`)
- `options.strict?: boolean` — Treat warnings and `x-recommended` fields as errors (default: `false`)
- `options.showMissingOptional?: boolean` — Include info about missing optional fields (default: `false`)

> Like `parse()`, `createReport()` does not throw on validation failures — the report is always returned alongside any `errors`.

**Returns `CreateReportResult`:**

- `report: XARFReport` — The generated report
Expand Down Expand Up @@ -237,23 +241,27 @@ Unknown v3 report types cause a parse error listing the supported types. See [MI

## Schema Management

This library validates against the official [xarf-spec](https://github.com/xarf/xarf-spec) JSON schemas. Schemas are fetched automatically on `npm install` based on the version configured in `package.json`:
This library validates against the official [xarf-spec](https://github.com/xarf/xarf-spec) JSON schemas. The schemas are **bundled into the package** at build time, so installation requires no network access and the library works in any environment (Node, bundlers, serverless, edge) with zero filesystem dependency. The bundled spec version is exposed as `BUNDLED_SPEC_VERSION`.

The schema version is configured in `package.json`:

```json
"xarfSpec": {
"version": "v4.2.0"
}
```

For **maintainers**, updating to a newer spec version is a two-step, network-only-at-build-time process:

```bash
# Check if a newer version of xarf-spec is available
npm run check-schema-updates

# Re-fetch schemas (e.g., if missing or to force a refresh)
npm run fetch-schemas
# Bump "xarfSpec.version" in package.json, then refresh the bundled schemas:
npm run sync-schemas # fetch-schemas + generate-schemas (regenerates src/schemas.generated.ts)
```

To update to a newer spec version, change the version in `package.json` and run `npm install`.
Consumers never run these scripts — they receive the pre-bundled schemas with the published package.

## Development

Expand Down
12 changes: 7 additions & 5 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ module.exports = {
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
'!src/index.ts'
'!src/index.ts',
// Generated data module (inlined JSON schemas), not logic to test.
'!src/schemas.generated.ts'
],
coverageThreshold: {
global: {
branches: 71,
functions: 80,
lines: 77,
statements: 77
branches: 78,
functions: 90,
lines: 88,
statements: 88
}
},
coverageDirectory: 'coverage',
Expand Down
Loading
Loading