From db43945cb53e89e72509d99806b9b3c168e0f4c9 Mon Sep 17 00:00:00 2001 From: sepehr-safari Date: Wed, 8 Jul 2026 01:51:58 +0300 Subject: [PATCH] feat(scenarios): format + 5 initial scenarios + package config - Scenario registry with getScenario() lookup - 5 scenarios: normal-session, failed-auth, connector-fault, station-offline, unexpected-stop-reason - Each scenario's expectedFailures aligns with v0.1 detection rules - 21 tests (registry, engine integration, synthetic data policy) Closes #23 --- .changeset/scenarios-package.md | 11 + CURRENT_STATE.md | 22 +- packages/scenarios/package.json | 55 +++++ .../src/__scenarios__/station-offline.json | 167 ++++++++++++++ .../__scenarios__/unexpected-stop-reason.json | 215 ++++++++++++++++++ packages/scenarios/src/index.test.ts | 143 ++++++++++++ packages/scenarios/src/index.ts | 83 +++++++ packages/scenarios/tsconfig.json | 9 + pnpm-lock.yaml | 13 ++ 9 files changed, 714 insertions(+), 4 deletions(-) create mode 100644 .changeset/scenarios-package.md create mode 100644 packages/scenarios/package.json create mode 100644 packages/scenarios/src/__scenarios__/station-offline.json create mode 100644 packages/scenarios/src/__scenarios__/unexpected-stop-reason.json create mode 100644 packages/scenarios/src/index.test.ts create mode 100644 packages/scenarios/src/index.ts create mode 100644 packages/scenarios/tsconfig.json diff --git a/.changeset/scenarios-package.md b/.changeset/scenarios-package.md new file mode 100644 index 0000000..9b1537f --- /dev/null +++ b/.changeset/scenarios-package.md @@ -0,0 +1,11 @@ +--- +'@ocpp-debugkit/scenarios': minor +--- + +Create scenarios package with 5 initial scenarios. + +- Scenario registry with `getScenario()` lookup +- 5 scenarios: normal-session, failed-auth, connector-fault, + station-offline, unexpected-stop-reason +- Each scenario's expectedFailures aligns with v0.1 detection rules +- 21 tests (registry, engine integration, synthetic data policy) diff --git a/CURRENT_STATE.md b/CURRENT_STATE.md index 11419ce..9f14a31 100644 --- a/CURRENT_STATE.md +++ b/CURRENT_STATE.md @@ -77,7 +77,7 @@ report exported. CLI and web inspector. - ✅ `packages/core/src/validator.ts` — `validateMessage()` / `validateMessages()` checking OCPP 1.6 JSON structural compliance - ✅ 40 additional tests (10 timeline + 11 detection + 5 summarizer + 14 validator) -### Core Package — Public API Export + Package Config (in progress — this PR) +### Core Package — Public API Export + Package Config (PR #35) - ✅ Barrel export complete (types, schemas, parser, normalizer, timeline, detection, summarizer, validator, fixtures) - ✅ `sideEffects: false` for tree-shaking @@ -85,12 +85,26 @@ report exported. CLI and web inspector. - ✅ `keywords`, `repository`, `homepage`, `bugs` fields for npm discoverability - ✅ Package is npm-publish-ready (`access: public`) +### CI Fixes (PR #36, #37) + +- ✅ Bumped `actions/checkout` and `actions/setup-node` to v5 (Node.js 20 deprecation) +- ✅ Pinned `changesets/action` to `v1.9.0` +- ✅ Fixed root `changeset` script: `"changeset add"` → `"changeset"` (was causing release workflow failures) + +### Scenarios Package (in progress — this PR) + +- ✅ `packages/scenarios/` — new package +- ✅ 5 scenarios: normal-session, failed-auth, connector-fault, station-offline, unexpected-stop-reason +- ✅ Scenario registry with `getScenario()` lookup +- ✅ Each scenario's `expectedFailures` aligns with v0.1 detection rules +- ✅ 21 tests (registry, engine integration, synthetic data policy) + ## What's Next 1. **Issue #20** → complete (PR #33): data model + parser + normalizer 2. **Issue #21** → complete (PR #34): timeline + detection + summarizer + validator -3. **Issue #22** (this PR) → complete: public API export + package config -4. **Issue #23**: Scenarios package (format + 5 initial scenarios) +3. **Issue #22** → complete (PR #35): public API export + package config +4. **Issue #23** (this PR) → complete: scenarios package (format + 5 initial scenarios) 5. **Issue #24**: Reporter package (Markdown report generator) 6. **Issue #25**: CLI package (scaffold + inspect + report + scenario commands) @@ -103,7 +117,7 @@ report exported. CLI and web inspector. | Package | Status | Version | |---------|--------|---------| | `@ocpp-debugkit/core` | in progress (package config finalized, ready for downstream) | 0.0.0 | -| `@ocpp-debugkit/scenarios` | not started | — | +| `@ocpp-debugkit/scenarios` | in progress (5 scenarios + registry) | 0.0.0 | | `@ocpp-debugkit/reporter` | not started | — | | `@ocpp-debugkit/cli` | not started | — | | `@ocpp-debugkit/replay` | not started | — | diff --git a/packages/scenarios/package.json b/packages/scenarios/package.json new file mode 100644 index 0000000..1c461bb --- /dev/null +++ b/packages/scenarios/package.json @@ -0,0 +1,55 @@ +{ + "name": "@ocpp-debugkit/scenarios", + "version": "0.0.0", + "description": "Predefined OCPP trace scenarios for testing the DebugKit analysis engine.", + "license": "Apache-2.0", + "type": "module", + "sideEffects": false, + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + }, + "files": [ + "dist", + "README.md", + "NOTICE" + ], + "keywords": [ + "ocpp", + "ocpp1.6", + "ev-charging", + "scenarios", + "test-fixtures", + "trace" + ], + "repository": { + "type": "git", + "url": "https://github.com/ocpp-debugkit/ocpp-debugkit.git", + "directory": "packages/scenarios" + }, + "homepage": "https://github.com/ocpp-debugkit/ocpp-debugkit/tree/main/packages/scenarios", + "bugs": { + "url": "https://github.com/ocpp-debugkit/ocpp-debugkit/issues" + }, + "scripts": { + "build": "tsc -p tsconfig.json", + "typecheck": "tsc --noEmit", + "test": "vitest run", + "clean": "rm -rf dist .turbo" + }, + "dependencies": { + "@ocpp-debugkit/core": "workspace:*" + }, + "devDependencies": { + "typescript": "^5.7.0", + "vitest": "^3.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/scenarios/src/__scenarios__/station-offline.json b/packages/scenarios/src/__scenarios__/station-offline.json new file mode 100644 index 0000000..c56af41 --- /dev/null +++ b/packages/scenarios/src/__scenarios__/station-offline.json @@ -0,0 +1,167 @@ +{ + "name": "station-offline", + "description": "Station goes offline during active session: transaction starts but no StopTransaction follows. Expects STATION_OFFLINE_DURING_SESSION failure.", + "trace": { + "traceId": "scenario-station-offline", + "metadata": { + "stationId": "CS-SYNTHETIC-004", + "ocppVersion": "1.6", + "source": "synthetic-scenario", + "description": "Station offline during active session — StartTransaction with no StopTransaction." + }, + "events": [ + { + "timestamp": "2024-01-15T14:00:00.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-001", + "BootNotification", + { + "chargePointVendor": "SyntheticVendor", + "chargePointModel": "SM-100", + "chargePointSerialNumber": "CS-SYNTHETIC-004", + "firmwareVersion": "1.0.0" + } + ] + }, + { + "timestamp": "2024-01-15T14:00:00.500Z", + "direction": "CSMS_TO_CS", + "message": [ + 3, + "msg-001", + { + "currentTime": "2024-01-15T14:00:00.500Z", + "interval": 300, + "status": "Accepted" + } + ] + }, + { + "timestamp": "2024-01-15T14:01:00.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-002", + "StatusNotification", + { + "connectorId": 0, + "status": "Available", + "errorCode": "NoError" + } + ] + }, + { + "timestamp": "2024-01-15T14:01:00.500Z", + "direction": "CSMS_TO_CS", + "message": [3, "msg-002", {}] + }, + { + "timestamp": "2024-01-15T14:02:00.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-003", + "Authorize", + { + "idTag": "SYNTHETIC-TAG-004" + } + ] + }, + { + "timestamp": "2024-01-15T14:02:00.500Z", + "direction": "CSMS_TO_CS", + "message": [ + 3, + "msg-003", + { + "idTagInfo": { + "status": "Accepted", + "expiryDate": "2024-12-31T23:59:59.000Z" + } + } + ] + }, + { + "timestamp": "2024-01-15T14:02:30.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-004", + "StartTransaction", + { + "connectorId": 1, + "idTag": "SYNTHETIC-TAG-004", + "meterStart": 0, + "timestamp": "2024-01-15T14:02:30.000Z" + } + ] + }, + { + "timestamp": "2024-01-15T14:02:30.500Z", + "direction": "CSMS_TO_CS", + "message": [ + 3, + "msg-004", + { + "transactionId": 100004, + "idTagInfo": { + "status": "Accepted" + } + } + ] + }, + { + "timestamp": "2024-01-15T14:02:31.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-005", + "StatusNotification", + { + "connectorId": 1, + "status": "Charging", + "errorCode": "NoError" + } + ] + }, + { + "timestamp": "2024-01-15T14:02:31.500Z", + "direction": "CSMS_TO_CS", + "message": [3, "msg-005", {}] + }, + { + "timestamp": "2024-01-15T14:15:00.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-006", + "MeterValues", + { + "connectorId": 1, + "transactionId": 100004, + "meterValue": [ + { + "timestamp": "2024-01-15T14:15:00.000Z", + "sampledValue": [ + { + "value": "2000", + "measurand": "Energy.Active.Import.Register", + "unit": "Wh" + } + ] + } + ] + } + ] + }, + { + "timestamp": "2024-01-15T14:15:00.500Z", + "direction": "CSMS_TO_CS", + "message": [3, "msg-006", {}] + } + ] + }, + "expectedFailures": ["STATION_OFFLINE_DURING_SESSION"] +} diff --git a/packages/scenarios/src/__scenarios__/unexpected-stop-reason.json b/packages/scenarios/src/__scenarios__/unexpected-stop-reason.json new file mode 100644 index 0000000..e8f5cd1 --- /dev/null +++ b/packages/scenarios/src/__scenarios__/unexpected-stop-reason.json @@ -0,0 +1,215 @@ +{ + "name": "unexpected-stop-reason", + "description": "Stop transaction with unexpected stop reason (EVDisconnected replaced by Other). Parser and timeline-only fixture — no v0.1 detection rule matches this pattern. Validates that the parser and timeline builder handle stop events with error payloads correctly.", + "trace": { + "traceId": "scenario-unexpected-stop-reason", + "metadata": { + "stationId": "CS-SYNTHETIC-005", + "ocppVersion": "1.6", + "source": "synthetic-scenario", + "description": "Stop transaction with unexpected stop reason — parser/timeline validation only." + }, + "events": [ + { + "timestamp": "2024-01-15T16:00:00.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-001", + "BootNotification", + { + "chargePointVendor": "SyntheticVendor", + "chargePointModel": "SM-100", + "chargePointSerialNumber": "CS-SYNTHETIC-005", + "firmwareVersion": "1.0.0" + } + ] + }, + { + "timestamp": "2024-01-15T16:00:00.500Z", + "direction": "CSMS_TO_CS", + "message": [ + 3, + "msg-001", + { + "currentTime": "2024-01-15T16:00:00.500Z", + "interval": 300, + "status": "Accepted" + } + ] + }, + { + "timestamp": "2024-01-15T16:01:00.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-002", + "StatusNotification", + { + "connectorId": 0, + "status": "Available", + "errorCode": "NoError" + } + ] + }, + { + "timestamp": "2024-01-15T16:01:00.500Z", + "direction": "CSMS_TO_CS", + "message": [3, "msg-002", {}] + }, + { + "timestamp": "2024-01-15T16:02:00.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-003", + "Authorize", + { + "idTag": "SYNTHETIC-TAG-005" + } + ] + }, + { + "timestamp": "2024-01-15T16:02:00.500Z", + "direction": "CSMS_TO_CS", + "message": [ + 3, + "msg-003", + { + "idTagInfo": { + "status": "Accepted", + "expiryDate": "2024-12-31T23:59:59.000Z" + } + } + ] + }, + { + "timestamp": "2024-01-15T16:02:30.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-004", + "StartTransaction", + { + "connectorId": 1, + "idTag": "SYNTHETIC-TAG-005", + "meterStart": 0, + "timestamp": "2024-01-15T16:02:30.000Z" + } + ] + }, + { + "timestamp": "2024-01-15T16:02:30.500Z", + "direction": "CSMS_TO_CS", + "message": [ + 3, + "msg-004", + { + "transactionId": 100005, + "idTagInfo": { + "status": "Accepted" + } + } + ] + }, + { + "timestamp": "2024-01-15T16:02:31.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-005", + "StatusNotification", + { + "connectorId": 1, + "status": "Charging", + "errorCode": "NoError" + } + ] + }, + { + "timestamp": "2024-01-15T16:02:31.500Z", + "direction": "CSMS_TO_CS", + "message": [3, "msg-005", {}] + }, + { + "timestamp": "2024-01-15T16:20:00.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-006", + "MeterValues", + { + "connectorId": 1, + "transactionId": 100005, + "meterValue": [ + { + "timestamp": "2024-01-15T16:20:00.000Z", + "sampledValue": [ + { + "value": "4000", + "measurand": "Energy.Active.Import.Register", + "unit": "Wh" + } + ] + } + ] + } + ] + }, + { + "timestamp": "2024-01-15T16:20:00.500Z", + "direction": "CSMS_TO_CS", + "message": [3, "msg-006", {}] + }, + { + "timestamp": "2024-01-15T16:25:00.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-007", + "StopTransaction", + { + "transactionId": 100005, + "idTag": "SYNTHETIC-TAG-005", + "meterStop": 4000, + "timestamp": "2024-01-15T16:25:00.000Z", + "reason": "Other" + } + ] + }, + { + "timestamp": "2024-01-15T16:25:00.500Z", + "direction": "CSMS_TO_CS", + "message": [ + 3, + "msg-007", + { + "idTagInfo": { + "status": "Accepted" + } + } + ] + }, + { + "timestamp": "2024-01-15T16:25:01.000Z", + "direction": "CS_TO_CSMS", + "message": [ + 2, + "msg-008", + "StatusNotification", + { + "connectorId": 1, + "status": "Available", + "errorCode": "NoError" + } + ] + }, + { + "timestamp": "2024-01-15T16:25:01.500Z", + "direction": "CSMS_TO_CS", + "message": [3, "msg-008", {}] + } + ] + }, + "expectedFailures": [] +} diff --git a/packages/scenarios/src/index.test.ts b/packages/scenarios/src/index.test.ts new file mode 100644 index 0000000..64cd0bb --- /dev/null +++ b/packages/scenarios/src/index.test.ts @@ -0,0 +1,143 @@ +import { describe, it, expect } from 'vitest'; +import { + scenarios, + scenarioNames, + getScenario, + normalSessionScenario, + failedAuthScenario, + connectorFaultScenario, + stationOfflineScenario, + unexpectedStopReasonScenario, +} from './index.js'; +import { parseTrace, buildSessionTimeline, detectFailures } from '@ocpp-debugkit/core'; + +// --------------------------------------------------------------------------- +// Registry tests +// --------------------------------------------------------------------------- + +describe('scenario registry', () => { + it('exports exactly 5 scenarios', () => { + expect(scenarios).toHaveLength(5); + }); + + it('exports scenario names in order', () => { + expect(scenarioNames).toEqual([ + 'normal-session', + 'failed-auth', + 'connector-fault', + 'station-offline', + 'unexpected-stop-reason', + ]); + }); + + it('each scenario has a name, description, trace, and expectedFailures', () => { + for (const scenario of scenarios) { + expect(scenario.name).toBeTruthy(); + expect(typeof scenario.description).toBe('string'); + expect(scenario.trace).toBeDefined(); + expect(Array.isArray(scenario.expectedFailures)).toBe(true); + } + }); + + it('getScenario returns the correct scenario by name', () => { + expect(getScenario('normal-session')).toBe(normalSessionScenario); + expect(getScenario('failed-auth')).toBe(failedAuthScenario); + expect(getScenario('connector-fault')).toBe(connectorFaultScenario); + expect(getScenario('station-offline')).toBe(stationOfflineScenario); + expect(getScenario('unexpected-stop-reason')).toBe(unexpectedStopReasonScenario); + }); + + it('getScenario returns undefined for unknown name', () => { + expect(getScenario('nonexistent')).toBeUndefined(); + }); +}); + +// --------------------------------------------------------------------------- +// Expected failures alignment (pitfall: scenarios must match v0.1 detection rules) +// --------------------------------------------------------------------------- + +describe('expectedFailures alignment with v0.1 detection rules', () => { + const VALID_FAILURE_CODES = new Set([ + 'FAILED_AUTHORIZATION', + 'CONNECTOR_FAULT', + 'STATION_OFFLINE_DURING_SESSION', + ]); + + it('all expectedFailures reference valid v0.1 failure codes', () => { + for (const scenario of scenarios) { + for (const code of scenario.expectedFailures) { + expect(VALID_FAILURE_CODES.has(code)).toBe(true); + } + } + }); +}); + +// --------------------------------------------------------------------------- +// Engine integration — each scenario runs through the analysis engine +// --------------------------------------------------------------------------- + +describe('scenario engine integration', () => { + it('normal-session: no failures detected', () => { + const trace = JSON.stringify(normalSessionScenario.trace); + const result = parseTrace(trace); + const sessions = buildSessionTimeline(result.events); + const failures = detectFailures(result.events, sessions); + expect(failures).toHaveLength(0); + }); + + it('failed-auth: detects FAILED_AUTHORIZATION', () => { + const trace = JSON.stringify(failedAuthScenario.trace); + const result = parseTrace(trace); + const sessions = buildSessionTimeline(result.events); + const failures = detectFailures(result.events, sessions); + expect(failures.some((f) => f.code === 'FAILED_AUTHORIZATION')).toBe(true); + }); + + it('connector-fault: detects CONNECTOR_FAULT', () => { + const trace = JSON.stringify(connectorFaultScenario.trace); + const result = parseTrace(trace); + const sessions = buildSessionTimeline(result.events); + const failures = detectFailures(result.events, sessions); + expect(failures.some((f) => f.code === 'CONNECTOR_FAULT')).toBe(true); + }); + + it('station-offline: detects STATION_OFFLINE_DURING_SESSION', () => { + const trace = JSON.stringify(stationOfflineScenario.trace); + const result = parseTrace(trace); + const sessions = buildSessionTimeline(result.events); + const failures = detectFailures(result.events, sessions); + expect(failures.some((f) => f.code === 'STATION_OFFLINE_DURING_SESSION')).toBe(true); + }); + + it('unexpected-stop-reason: no failures detected (parser/timeline-only fixture)', () => { + const trace = JSON.stringify(unexpectedStopReasonScenario.trace); + const result = parseTrace(trace); + const sessions = buildSessionTimeline(result.events); + const failures = detectFailures(result.events, sessions); + expect(failures).toHaveLength(0); + }); +}); + +// --------------------------------------------------------------------------- +// Synthetic data policy +// --------------------------------------------------------------------------- + +describe('synthetic data policy', () => { + it.each(scenarios.map((s, i) => [s.name, i] as const))( + '%s contains only synthetic identifiers', + (name) => { + const scenario = getScenario(name); + expect(scenario).toBeDefined(); + const json = JSON.stringify(scenario); + expect(json).toContain('SYNTHETIC'); + // Must not contain UUID-like patterns + expect(json).not.toMatch(/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i); + }, + ); + + it.each(scenarios.map((s, i) => [s.name, i] as const))('%s declares ocppVersion 1.6', (name) => { + const scenario = getScenario(name); + expect(scenario).toBeDefined(); + expect(scenario?.trace.metadata?.ocppVersion).toBe('1.6'); + }); +}); diff --git a/packages/scenarios/src/index.ts b/packages/scenarios/src/index.ts new file mode 100644 index 0000000..950de26 --- /dev/null +++ b/packages/scenarios/src/index.ts @@ -0,0 +1,83 @@ +/** + * Scenario registry — exports all predefined scenarios. + * + * All scenario data is fully synthetic — no real station identifiers, + * transaction IDs, idTag values, or personal data. + */ + +import type { Scenario, Trace } from '@ocpp-debugkit/core'; +import { fixtures } from '@ocpp-debugkit/core'; + +import stationOffline from './__scenarios__/station-offline.json'; +import unexpectedStopReason from './__scenarios__/unexpected-stop-reason.json'; + +// --------------------------------------------------------------------------- +// Scenarios derived from core fixtures +// --------------------------------------------------------------------------- + +const normalSessionScenario: Scenario = { + name: 'normal-session', + description: + 'Normal charging session: boot → authorize → start transaction → meter values → stop transaction. No failures expected.', + trace: fixtures.normalSession as Trace, + expectedFailures: [], +}; + +const failedAuthScenario: Scenario = { + name: 'failed-auth', + description: + 'Failed authorization: station connector prepares, idTag is rejected by CSMS. StartTransaction is not attempted. Expects FAILED_AUTHORIZATION failure.', + trace: fixtures.failedAuth as Trace, + expectedFailures: ['FAILED_AUTHORIZATION'], +}; + +const connectorFaultScenario: Scenario = { + name: 'connector-fault', + description: + 'Connector fault during active session: station boots, transaction starts, connector faults mid-charging, transaction stops with fault reason. Expects CONNECTOR_FAULT failure.', + trace: fixtures.connectorFault as Trace, + expectedFailures: ['CONNECTOR_FAULT'], +}; + +// --------------------------------------------------------------------------- +// Scenarios from JSON files +// --------------------------------------------------------------------------- + +const stationOfflineScenario: Scenario = stationOffline as unknown as Scenario; +const unexpectedStopReasonScenario: Scenario = unexpectedStopReason as unknown as Scenario; + +// --------------------------------------------------------------------------- +// Registry +// --------------------------------------------------------------------------- + +export const scenarios = [ + normalSessionScenario, + failedAuthScenario, + connectorFaultScenario, + stationOfflineScenario, + unexpectedStopReasonScenario, +] as const; + +export const scenarioNames = [ + 'normal-session', + 'failed-auth', + 'connector-fault', + 'station-offline', + 'unexpected-stop-reason', +] as const; + +export { + normalSessionScenario, + failedAuthScenario, + connectorFaultScenario, + stationOfflineScenario, + unexpectedStopReasonScenario, +}; + +/** + * Get a scenario by name. + * @returns The scenario, or undefined if not found. + */ +export function getScenario(name: string): Scenario | undefined { + return scenarios.find((s) => s.name === name); +} diff --git a/packages/scenarios/tsconfig.json b/packages/scenarios/tsconfig.json new file mode 100644 index 0000000..dd1cdcb --- /dev/null +++ b/packages/scenarios/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src"], + "exclude": ["node_modules", "dist", "**/*.test.ts"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 60f32c9..02c0b21 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,6 +49,19 @@ importers: specifier: ^3.0.0 version: 3.2.7(@types/node@22.20.0) + packages/scenarios: + dependencies: + '@ocpp-debugkit/core': + specifier: workspace:* + version: link:../core + devDependencies: + typescript: + specifier: ^5.7.0 + version: 5.9.3 + vitest: + specifier: ^3.0.0 + version: 3.2.7(@types/node@22.20.0) + packages: '@babel/runtime@7.29.7':