diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 969f773..37cc623 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,17 +32,24 @@ pnpm build ``` ocpp-debugkit/ ├── packages/ -│ ├── core/ # Data model, parser, normalizer, timeline, failure detection -│ ├── scenarios/ # Predefined trace scenarios for testing -│ ├── reporter/ # Report generators (Markdown, HTML) -│ ├── cli/ # Command-line interface -│ ├── replay/ # Replay engine (v0.2+) -│ └── react/ # Reusable React components (v0.2+) +│ └── toolkit/ # Single npm package @ocpp-debugkit/toolkit +│ └── src/ +│ ├── core/ # Data model, parser, normalizer, timeline, failure detection +│ ├── scenarios/ # Predefined trace scenarios for testing +│ ├── reporter/ # Report generators (Markdown, HTML) +│ ├── replay/ # Replay engine +│ ├── react/ # Reusable React components +│ └── cli/ # Command-line interface (bin: ocpp-debugkit) ├── apps/ │ └── web/ # Single Next.js app (landing, inspector, docs, blog) └── ... ``` +All modules ship in a single package, `@ocpp-debugkit/toolkit`, exposed via +subpath exports (`@ocpp-debugkit/toolkit/core`, `/scenarios`, `/reporter`, +`/replay`, `/react`, `/cli`, `/fixtures`). See +[ADR-0010](./docs/adr/0010-single-package-consolidation.md) for the rationale. + See [`AGENTS.md`](./AGENTS.md) for a detailed overview of the architecture, build commands, and package dependency graph. diff --git a/README.md b/README.md index 0f90a92..a3ab986 100644 --- a/README.md +++ b/README.md @@ -37,29 +37,33 @@ validate behavior against known scenarios. ## Architecture -OCPP DebugKit is a pnpm monorepo with independently versioned packages. +OCPP DebugKit is a pnpm monorepo. All modules ship in a single npm package, +`@ocpp-debugkit/toolkit`, exposed via [subpath exports](https://nodejs.org/api/packages.html#subpath-exports). ``` - core ← everything depends on this - / | \ - scenarios | reporter | replay - \ | / | - cli | - | | - apps/web (single Next.js app) +@ocpp-debugkit/toolkit +├── core ← data model, parser, normalizer, timeline, failure detection +├── scenarios ← predefined trace scenarios (depends on core) +├── reporter ← report generators — Markdown, HTML (depends on core) +├── replay ← replay engine (depends on core) +├── react ← reusable React components (depends on core, scenarios, reporter) +└── cli ← command-line interface (depends on core, scenarios, reporter) + │ + └── apps/web (single Next.js app) ``` -| Package | Description | Version | -|---------|-------------|---------| -| `@ocpp-debugkit/core` | Data model, trace parser, event normalizer, timeline, failure detection | [![npm](https://img.shields.io/npm/v/@ocpp-debugkit/core.svg)](https://www.npmjs.com/package/@ocpp-debugkit/core) | -| `@ocpp-debugkit/scenarios` | Predefined trace scenarios for testing | [![npm](https://img.shields.io/npm/v/@ocpp-debugkit/scenarios.svg)](https://www.npmjs.com/package/@ocpp-debugkit/scenarios) | -| `@ocpp-debugkit/reporter` | Report generators (Markdown) | [![npm](https://img.shields.io/npm/v/@ocpp-debugkit/reporter.svg)](https://www.npmjs.com/package/@ocpp-debugkit/reporter) | -| `@ocpp-debugkit/cli` | Command-line interface | [![npm](https://img.shields.io/npm/v/@ocpp-debugkit/cli.svg)](https://www.npmjs.com/package/@ocpp-debugkit/cli) | -| `@ocpp-debugkit/replay` | Replay engine | _planned (v0.2.0)_ | -| `@ocpp-debugkit/react` | Reusable React components | _planned (v0.2.0)_ | -| `apps/web` | Single Next.js app (landing, inspector, docs) | — | +| Import path | Description | +|-------------|-------------| +| `@ocpp-debugkit/toolkit/core` | Data model, trace parser, event normalizer, timeline, failure detection | +| `@ocpp-debugkit/toolkit/scenarios` | Predefined trace scenarios for testing | +| `@ocpp-debugkit/toolkit/reporter` | Report generators (Markdown) | +| `@ocpp-debugkit/toolkit/replay` | Replay engine | +| `@ocpp-debugkit/toolkit/react` | Reusable React components | +| `@ocpp-debugkit/toolkit/cli` | Programmatic CLI entry (`bin: ocpp-debugkit`) | +| `@ocpp-debugkit/toolkit/fixtures` | Trace fixtures for testing | +| `apps/web` | Single Next.js app (landing, inspector, docs) | -**Build order:** core → scenarios/reporter/replay → cli → app +**Build order:** toolkit (all internal modules in one `tsc` pass) → app ## Quickstart @@ -74,13 +78,19 @@ pnpm build ### CLI -Packages are published to npm under the `@ocpp-debugkit` scope: +Install the single package globally to get the `ocpp-debugkit` binary: ```bash -npm install -g @ocpp-debugkit/cli +npm install -g @ocpp-debugkit/toolkit ocpp-debugkit inspect trace.json ``` +Or use `npx` without installing: + +```bash +npx ocpp-debugkit inspect trace.json +``` + Other commands: ```bash @@ -89,6 +99,17 @@ ocpp-debugkit scenario list ocpp-debugkit scenario run failed-auth ``` +### Programmatic Usage + +```ts +import { parseTrace, detectFailures } from '@ocpp-debugkit/toolkit/core'; +import { scenarios } from '@ocpp-debugkit/toolkit/scenarios'; +import { generateMarkdownReport } from '@ocpp-debugkit/toolkit/reporter'; +``` + +See the [Migration Guide](./docs/migration.md) if you are upgrading from the +old multi-package layout. + ### Web App Visit [ocppdebugkit.com/inspector](https://ocppdebugkit.com/inspector) to diff --git a/docs/adr/0010-single-package-consolidation.md b/docs/adr/0010-single-package-consolidation.md new file mode 100644 index 0000000..2805cf0 --- /dev/null +++ b/docs/adr/0010-single-package-consolidation.md @@ -0,0 +1,154 @@ +# ADR-0010: Single Package Consolidation + +## Status + +Accepted + +## Context + +OCPP DebugKit was originally published as four independent npm packages under +the `@ocpp-debugkit` scope: + +- `@ocpp-debugkit/core` — data model, trace parser, event normalizer, timeline, + failure detection +- `@ocpp-debugkit/scenarios` — predefined trace scenarios for testing +- `@ocpp-debugkit/reporter` — report generators (Markdown) +- `@ocpp-debugkit/cli` — command-line interface + +Two additional packages — `@ocpp-debugkit/replay` (replay engine) and +`@ocpp-debugkit/react` (reusable React components) — were planned for v0.2.0. + +This multi-package layout created several problems: + +1. **Version drift.** Each package was independently versioned. Consumers had + to keep peer versions in sync, and a mismatch between `core` and `scenarios` + could cause subtle runtime failures that were hard to diagnose. + +2. **Cross-package coupling.** `scenarios`, `reporter`, and `cli` all depend on + `core` types. A change to a `core` type required coordinated releases across + all dependent packages, defeating the supposed independence. + +3. **Installation friction.** Consumers needed to install and list multiple + packages: + + ```bash + npm install @ocpp-debugkit/core @ocpp-debugkit/scenarios @ocpp-debugkit/reporter + ``` + +4. **Release overhead.** Each release required changeset coordination across + multiple packages, multiple `npm publish` calls, and CI that had to build + and test the full dependency graph in order. + +5. **Small project, not a library ecosystem.** The packages are tightly coupled + and maintained by a single team. The independence promised by the + multi-package layout was theoretical — in practice, every meaningful change + touched multiple packages simultaneously. + +6. **Internal module boundaries are enough.** The actual source code already + lives in a single `packages/toolkit` directory with subdirectories (`core`, + `scenarios`, `reporter`, `replay`, `react`, `cli`). The npm package + boundaries were a publishing artifact, not an architectural one. + +## Decision + +**Consolidate all four published packages into a single npm package, +`@ocpp-debugkit/toolkit`, exposed via subpath exports.** + +### Package structure + +``` +@ocpp-debugkit/toolkit + exports: + . # umbrella entry (re-exports core + scenarios) + ./core # data model, parser, normalizer, timeline, failure detection + ./scenarios # predefined trace scenarios + ./reporter # report generators (Markdown, HTML) + ./replay # replay engine + ./react # reusable React components + ./cli # programmatic CLI entry + ./fixtures # trace fixtures (moved from core/fixtures) + bin: + ocpp-debugkit # CLI binary +``` + +### Subpath exports + +Consumers import from `@ocpp-debugkit/toolkit/` instead of +`@ocpp-debugkit/`: + +```ts +// Before +import { parseTrace } from '@ocpp-debugkit/core'; +import { scenarios } from '@ocpp-debugkit/scenarios'; +import { generateMarkdownReport } from '@ocpp-debugkit/reporter'; + +// After +import { parseTrace } from '@ocpp-debugkit/toolkit/core'; +import { scenarios } from '@ocpp-debugkit/toolkit/scenarios'; +import { generateMarkdownReport } from '@ocpp-debugkit/toolkit/reporter'; +``` + +### Binary + +The CLI binary name remains `ocpp-debugkit`. Consumers install one package and +get the CLI: + +```bash +npm install -g @ocpp-debugkit/toolkit +ocpp-debugkit inspect trace.json +``` + +For `npx`: + +```bash +npx ocpp-debugkit inspect trace.json +``` + +### Deprecation of old packages + +The four old packages (`@ocpp-debugkit/core`, `@ocpp-debugkit/scenarios`, +`@ocpp-debugkit/reporter`, `@ocpp-debugkit/cli`) remain on npm with a +`deprecated` flag in their latest published versions. They will not receive new +features or bug fixes. A migration guide is provided at +[`docs/migration.md`](../migration.md). + +### Single version + +`@ocpp-debugkit/toolkit` is a single versioned unit. No more peer-dependency +mismatches — one version, one install, one release. + +## Consequences + +### Positive + +- **Simpler installation.** One package to install: `npm install + @ocpp-debugkit/toolkit`. +- **No version drift.** All modules share a single version. Mismatches are + structurally impossible. +- **Faster releases.** One package, one publish, one changeset — instead of + coordinated multi-package releases. +- **Cleaner dependency graph.** Internal modules depend on each other via + TypeScript path aliases, not npm dependencies. The build is a single `tsc` + pass. +- **Better tree-shaking.** Subpath exports let bundlers include only the + modules a consumer actually imports. A consumer using only `core` doesn't pull + in `react` or `cli`. +- **Module boundaries preserved.** The `core` / `scenarios` / `reporter` / + `replay` / `react` / `cli` separation still exists as directories and export + paths — the architectural boundary is intact, only the npm boundary is gone. + +### Negative + +- **Breaking change for existing consumers.** Anyone importing + `@ocpp-debugkit/core` must update to `@ocpp-debugkit/toolkit/core`. The + migration guide and deprecated old packages ease this. +- **Larger single package.** The npm tarball is larger, though consumers only + pay for what they import at runtime via subpath exports and tree-shaking. +- **No independent versioning.** A bug fix to `reporter` bumps the version for + all modules. Given the tight coupling, this is acceptable — a `reporter` fix + often depends on a `core` change anyway. + +### Neutral + +- The old packages stay on npm indefinitely for backward compatibility, but + they are deprecated and frozen. diff --git a/docs/adr/README.md b/docs/adr/README.md index 3505d5a..60a7fd6 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -16,6 +16,7 @@ significant architectural decision, its context, and its consequences. | [ADR-0007](0007-malformed-trace-handling.md) | Malformed Trace Handling | Accepted | | [ADR-0008](0008-browser-local-processing.md) | Browser-Local Processing & Privacy | Accepted | | [ADR-0009](0009-protocol-extensibility.md) | Future Protocol-Version Extensibility | Accepted | +| [ADR-0010](0010-single-package-consolidation.md) | Single Package Consolidation | Accepted | ## Format diff --git a/docs/migration.md b/docs/migration.md new file mode 100644 index 0000000..e25093a --- /dev/null +++ b/docs/migration.md @@ -0,0 +1,238 @@ +# Migration Guide: Single Package Consolidation + +> **Migrating from the old multi-package layout to the unified +> `@ocpp-debugkit/toolkit` package.** + +OCPP DebugKit has consolidated four separate npm packages into a single +package, `@ocpp-debugkit/toolkit`, using subpath exports. This guide walks +through every change you need to make. + +## Summary + +| Old package | New import path | +|-------------|-----------------| +| `@ocpp-debugkit/core` | `@ocpp-debugkit/toolkit/core` | +| `@ocpp-debugkit/scenarios` | `@ocpp-debugkit/toolkit/scenarios` | +| `@ocpp-debugkit/reporter` | `@ocpp-debugkit/toolkit/reporter` | +| `@ocpp-debugkit/cli` | `@ocpp-debugkit/toolkit/cli` (programmatic) or `npx ocpp-debugkit` (CLI) | +| `@ocpp-debugkit/replay` | `@ocpp-debugkit/toolkit/replay` | +| `@ocpp-debugkit/react` | `@ocpp-debugkit/toolkit/react` | +| `@ocpp-debugkit/core/fixtures` | `@ocpp-debugkit/toolkit/fixtures` | + +The old packages remain on npm under the `@ocpp-debugkit` scope, but they are +**deprecated** and will no longer receive updates. New features and bug fixes +ship only in `@ocpp-debugkit/toolkit`. + +## Installation + +### Before + +```bash +npm install @ocpp-debugkit/core @ocpp-debugkit/scenarios @ocpp-debugkit/reporter +``` + +### After + +```bash +npm install @ocpp-debugkit/toolkit +``` + +That single dependency gives you access to every module via subpath exports. + +## Import Migration + +### Core (data model, parser, normalizer, timeline, failure detection) + +**Before:** + +```ts +import { + parseTrace, + normalizeEvents, + buildTimeline, + detectFailures, + type Event, + type Session, +} from '@ocpp-debugkit/core'; +``` + +**After:** + +```ts +import { + parseTrace, + normalizeEvents, + buildTimeline, + detectFailures, + type Event, + type Session, +} from '@ocpp-debugkit/toolkit/core'; +``` + +### Scenarios + +**Before:** + +```ts +import { scenarios, getScenario } from '@ocpp-debugkit/scenarios'; +``` + +**After:** + +```ts +import { scenarios, getScenario } from '@ocpp-debugkit/toolkit/scenarios'; +``` + +### Reporter + +**Before:** + +```ts +import { generateMarkdownReport } from '@ocpp-debugkit/reporter'; +``` + +**After:** + +```ts +import { generateMarkdownReport } from '@ocpp-debugkit/toolkit/reporter'; +``` + +### Replay + +**Before:** + +```ts +import { createReplayEngine } from '@ocpp-debugkit/replay'; +``` + +**After:** + +```ts +import { createReplayEngine } from '@ocpp-debugkit/toolkit/replay'; +``` + +### React Components + +**Before:** + +```ts +import { TimelineView, MessageInspector } from '@ocpp-debugkit/react'; +``` + +**After:** + +```ts +import { TimelineView, MessageInspector } from '@ocpp-debugkit/toolkit/react'; +``` + +## Fixture Imports + +Trace fixtures previously lived under `@ocpp-debugkit/core/fixtures`. They have +moved to `@ocpp-debugkit/toolkit/fixtures`. + +**Before:** + +```ts +import { failedAuthTrace } from '@ocpp-debugkit/core/fixtures'; +``` + +**After:** + +```ts +import { failedAuthTrace } from '@ocpp-debugkit/toolkit/fixtures'; +``` + +## CLI Migration + +### Installed CLI + +**Before:** + +```bash +npm install -g @ocpp-debugkit/cli +ocpp-debugkit inspect trace.json +``` + +**After:** + +```bash +npm install -g @ocpp-debugkit/toolkit +ocpp-debugkit inspect trace.json +``` + +The binary name stays `ocpp-debugkit` — only the npm package name changes. + +### npx (no global install) + +**Before:** + +```bash +npx @ocpp-debugkit/cli inspect trace.json +``` + +**After:** + +```bash +npx ocpp-debugkit inspect trace.json +``` + +`npx ocpp-debugkit` resolves the `bin` entry from `@ocpp-debugkit/toolkit` +automatically. All subcommands (`inspect`, `report`, `scenario list`, +`scenario run`) work identically. + +### Programmatic CLI import + +If you imported the CLI programmatically (e.g., to invoke it from a Node.js +script): + +**Before:** + +```ts +import { runCli } from '@ocpp-debugkit/cli'; +``` + +**After:** + +```ts +import { runCli } from '@ocpp-debugkit/toolkit/cli'; +``` + +## Codemod (Optional) + +A find-and-replace across your codebase handles most migrations: + +```bash +# Import paths +npx replace-in-file '@ocpp-debugkit/core/fixtures' '@ocpp-debugkit/toolkit/fixtures' 'src/**/*.ts' +npx replace-in-file '@ocpp-debugkit/core' '@ocpp-debugkit/toolkit/core' 'src/**/*.ts' +npx replace-in-file '@ocpp-debugkit/scenarios' '@ocpp-debugkit/toolkit/scenarios' 'src/**/*.ts' +npx replace-in-file '@ocpp-debugkit/reporter' '@ocpp-debugkit/toolkit/reporter' 'src/**/*.ts' +npx replace-in-file '@ocpp-debugkit/replay' '@ocpp-debugkit/toolkit/replay' 'src/**/*.ts' +npx replace-in-file '@ocpp-debugkit/react' '@ocpp-debugkit/toolkit/react' 'src/**/*.ts' +npx replace-in-file '@ocpp-debugkit/cli' '@ocpp-debugkit/toolkit/cli' 'src/**/*.ts' + +# CLI invocations +npx replace-in-file 'npx @ocpp-debugkit/cli' 'npx ocpp-debugkit' 'src/**/*.ts' +``` + +> **Order matters.** Replace `/fixtures` first so it doesn't get swallowed by +> the broader `/core` replacement. + +After running, update your `package.json` dependencies — remove the old +`@ocpp-debugkit/*` entries and add `@ocpp-debugkit/toolkit`. + +## Deprecation Policy + +The four old packages (`@ocpp-debugkit/core`, `@ocpp-debugkit/scenarios`, +`@ocpp-debugkit/reporter`, `@ocpp-debugkit/cli`) remain on npm so existing +installs don't break. Their latest versions carry a `deprecated` flag pointing +to this guide. They will **not** receive new features or bug fixes. + +We recommend migrating to `@ocpp-debugkit/toolkit` at your earliest +convenience. + +## Questions + +- Open a [GitHub Issue](https://github.com/ocpp-debugkit/ocpp-debugkit/issues) +- Read the [ADR](./adr/0010-single-package-consolidation.md) for the rationale + behind this consolidation