@ocpp-debugkit/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +201 -0
  2. package/dist/__fixtures__/connector-fault.d.ts +116 -0
  3. package/dist/__fixtures__/connector-fault.d.ts.map +1 -0
  4. package/dist/__fixtures__/connector-fault.js +231 -0
  5. package/dist/__fixtures__/connector-fault.js.map +1 -0
  6. package/dist/__fixtures__/failed-auth.d.ts +64 -0
  7. package/dist/__fixtures__/failed-auth.d.ts.map +1 -0
  8. package/dist/__fixtures__/failed-auth.js +173 -0
  9. package/dist/__fixtures__/failed-auth.js.map +1 -0
  10. package/dist/__fixtures__/normal-session.d.ts +108 -0
  11. package/dist/__fixtures__/normal-session.d.ts.map +1 -0
  12. package/dist/__fixtures__/normal-session.js +261 -0
  13. package/dist/__fixtures__/normal-session.js.map +1 -0
  14. package/dist/detection.d.ts +23 -0
  15. package/dist/detection.d.ts.map +1 -0
  16. package/dist/detection.js +226 -0
  17. package/dist/detection.js.map +1 -0
  18. package/dist/fixtures/index.d.ts +298 -0
  19. package/dist/fixtures/index.d.ts.map +1 -0
  20. package/dist/fixtures/index.js +19 -0
  21. package/dist/fixtures/index.js.map +1 -0
  22. package/dist/index.d.ts +14 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +22 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/normalizer.d.ts +83 -0
  27. package/dist/normalizer.d.ts.map +1 -0
  28. package/dist/normalizer.js +289 -0
  29. package/dist/normalizer.js.map +1 -0
  30. package/dist/parser.d.ts +53 -0
  31. package/dist/parser.d.ts.map +1 -0
  32. package/dist/parser.js +282 -0
  33. package/dist/parser.js.map +1 -0
  34. package/dist/schemas.d.ts +68 -0
  35. package/dist/schemas.d.ts.map +1 -0
  36. package/dist/schemas.js +81 -0
  37. package/dist/schemas.js.map +1 -0
  38. package/dist/summarizer.d.ts +25 -0
  39. package/dist/summarizer.d.ts.map +1 -0
  40. package/dist/summarizer.js +47 -0
  41. package/dist/summarizer.js.map +1 -0
  42. package/dist/timeline.d.ts +26 -0
  43. package/dist/timeline.d.ts.map +1 -0
  44. package/dist/timeline.js +318 -0
  45. package/dist/timeline.js.map +1 -0
  46. package/dist/types.d.ts +160 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +9 -0
  49. package/dist/types.js.map +1 -0
  50. package/dist/validator.d.ts +33 -0
  51. package/dist/validator.d.ts.map +1 -0
  52. package/dist/validator.js +122 -0
  53. package/dist/validator.js.map +1 -0
  54. package/package.json +61 -0
@@ -0,0 +1,318 @@
1
+ /**
2
+ * Session timeline builder — correlates events into logical charging sessions.
3
+ *
4
+ * Session correlation strategy (ADR-0006):
5
+ * 1. Primary: transactionId (from StartTransaction response / StopTransaction)
6
+ * 2. Secondary: connectorId + stationId grouping
7
+ * 3. Events without a transaction are grouped by stationId + connectorId
8
+ *
9
+ * @see ADR-0006
10
+ */
11
+ // ---------------------------------------------------------------------------
12
+ // Helpers
13
+ // ---------------------------------------------------------------------------
14
+ /**
15
+ * Extract transactionId from an event's payload.
16
+ * - StartTransaction response (CallResult): { transactionId, idTagInfo }
17
+ * - StopTransaction request (Call): { transactionId, ... }
18
+ * - MeterValues request (Call): { transactionId, ... }
19
+ */
20
+ function extractTransactionId(event) {
21
+ if (event.messageType === 'Call') {
22
+ if (event.action === 'StartTransaction') {
23
+ // StartTransaction request doesn't have transactionId — the response does.
24
+ return null;
25
+ }
26
+ if (event.action === 'StopTransaction' || event.action === 'MeterValues') {
27
+ const payload = event.payload;
28
+ if (typeof payload?.transactionId === 'number') {
29
+ return payload.transactionId;
30
+ }
31
+ }
32
+ }
33
+ if (event.messageType === 'CallResult') {
34
+ const payload = event.payload;
35
+ if (typeof payload?.transactionId === 'number') {
36
+ return payload.transactionId;
37
+ }
38
+ }
39
+ return null;
40
+ }
41
+ /**
42
+ * Extract connectorId from an event's payload.
43
+ * Present in StatusNotification, StartTransaction, MeterValues.
44
+ */
45
+ function extractConnectorId(event) {
46
+ if (event.messageType !== 'Call' || event.payload === null) {
47
+ return null;
48
+ }
49
+ const payload = event.payload;
50
+ if (typeof payload?.connectorId === 'number') {
51
+ return payload.connectorId;
52
+ }
53
+ return null;
54
+ }
55
+ /**
56
+ * Extract stationId from BootNotification payload.
57
+ */
58
+ function extractStationId(events) {
59
+ for (const event of events) {
60
+ if (event.messageType === 'Call' && event.action === 'BootNotification') {
61
+ const payload = event.payload;
62
+ if (typeof payload?.chargePointSerialNumber === 'string') {
63
+ return payload.chargePointSerialNumber;
64
+ }
65
+ }
66
+ }
67
+ return 'unknown';
68
+ }
69
+ /**
70
+ * Determine if an event indicates a connector fault status.
71
+ */
72
+ function isFaultedStatus(event) {
73
+ if (event.messageType !== 'Call' || event.action !== 'StatusNotification') {
74
+ return false;
75
+ }
76
+ const payload = event.payload;
77
+ return payload?.status === 'Faulted';
78
+ }
79
+ /**
80
+ * Determine if an event indicates the connector is unavailable/offline.
81
+ */
82
+ function isUnavailableStatus(event) {
83
+ if (event.messageType !== 'Call' || event.action !== 'StatusNotification') {
84
+ return false;
85
+ }
86
+ const payload = event.payload;
87
+ return payload?.status === 'Unavailable' || payload?.status === 'Offline';
88
+ }
89
+ // ---------------------------------------------------------------------------
90
+ // buildSessionTimeline()
91
+ // ---------------------------------------------------------------------------
92
+ /**
93
+ * Build session timelines from normalized events.
94
+ *
95
+ * Correlates events into logical charging sessions by:
96
+ * 1. Matching StartTransaction responses to find transactionIds
97
+ * 2. Grouping StopTransaction and MeterValues events by transactionId
98
+ * 3. Grouping StatusNotification events by connectorId + stationId
99
+ * 4. Events without a transaction are assigned to a "no-session" group
100
+ *
101
+ * Sessions are ordered by their first event's timestamp.
102
+ *
103
+ * @see ADR-0006
104
+ */
105
+ export function buildSessionTimeline(events) {
106
+ if (events.length === 0) {
107
+ return [];
108
+ }
109
+ const stationId = extractStationId(events);
110
+ // Step 1: Build a map of messageId → transactionId from StartTransaction responses.
111
+ // The StartTransaction Call (msg-005) gets a response (CallResult) with transactionId.
112
+ // We match by messageId.
113
+ const messageIdToTransactionId = new Map();
114
+ for (const event of events) {
115
+ if (event.messageType === 'CallResult') {
116
+ const txId = extractTransactionId(event);
117
+ if (txId !== null) {
118
+ messageIdToTransactionId.set(event.messageId, txId);
119
+ }
120
+ }
121
+ }
122
+ // Step 2: Build a map of messageId → transactionId for StopTransaction/MeterValues Calls.
123
+ // These Calls contain the transactionId in their payload directly.
124
+ const callMessageIdToTransactionId = new Map();
125
+ for (const event of events) {
126
+ if (event.messageType === 'Call') {
127
+ const txId = extractTransactionId(event);
128
+ if (txId !== null) {
129
+ callMessageIdToTransactionId.set(event.messageId, txId);
130
+ }
131
+ }
132
+ }
133
+ // Step 3: Group events into sessions.
134
+ // A session is identified by a transactionId.
135
+ // Events are assigned to a session if:
136
+ // - They contain that transactionId in their payload (StopTransaction, MeterValues)
137
+ // - They are a StartTransaction Call/CallResult with a matched messageId
138
+ // - They are StatusNotification events for the same connectorId around the same time
139
+ // First, find all StartTransaction Call messages and their corresponding response transactionIds
140
+ const startTxCalls = [];
141
+ for (const event of events) {
142
+ if (event.messageType === 'Call' && event.action === 'StartTransaction') {
143
+ const txId = messageIdToTransactionId.get(event.messageId) ?? null;
144
+ const responseEvent = events.find((e) => e.messageId === event.messageId && e.messageType === 'CallResult') ??
145
+ null;
146
+ startTxCalls.push({ callEvent: event, responseEvent, transactionId: txId });
147
+ }
148
+ }
149
+ // If no transactions found, return a single session with all events
150
+ if (startTxCalls.length === 0) {
151
+ return [createSession('session-0', stationId, events)];
152
+ }
153
+ // Build a map of messageId → transactionId for ALL Call messages that have
154
+ // a transactionId (StopTransaction, MeterValues). Their CallResult responses
155
+ // inherit this transactionId.
156
+ const callMessageIdToTxId = new Map();
157
+ for (const event of events) {
158
+ if (event.messageType === 'Call') {
159
+ const txId = extractTransactionId(event);
160
+ if (txId !== null) {
161
+ callMessageIdToTxId.set(event.messageId, txId);
162
+ }
163
+ // StartTransaction Call — get txId from the response
164
+ if (event.action === 'StartTransaction') {
165
+ const respTxId = messageIdToTransactionId.get(event.messageId);
166
+ if (respTxId !== undefined) {
167
+ callMessageIdToTxId.set(event.messageId, respTxId);
168
+ }
169
+ }
170
+ }
171
+ }
172
+ // Group events by transactionId
173
+ const sessionEventsMap = new Map();
174
+ for (const event of events) {
175
+ let txId = null;
176
+ if (event.messageType === 'Call') {
177
+ // Call: check if this messageId has a known transactionId
178
+ txId = callMessageIdToTxId.get(event.messageId) ?? null;
179
+ if (txId === null) {
180
+ // Try extracting from payload directly
181
+ txId = extractTransactionId(event);
182
+ }
183
+ }
184
+ else if (event.messageType === 'CallResult') {
185
+ // CallResult: check if the matching Call has a transactionId
186
+ txId = callMessageIdToTxId.get(event.messageId) ?? null;
187
+ // Also check if transactionId is directly in the response payload
188
+ if (txId === null) {
189
+ txId = extractTransactionId(event);
190
+ }
191
+ }
192
+ if (txId !== null) {
193
+ const group = sessionEventsMap.get(txId) ?? [];
194
+ group.push(event);
195
+ sessionEventsMap.set(txId, group);
196
+ }
197
+ else {
198
+ // Events without a transaction — assign to null group (will be distributed)
199
+ const group = sessionEventsMap.get(null) ?? [];
200
+ group.push(event);
201
+ sessionEventsMap.set(null, group);
202
+ }
203
+ }
204
+ // Distribute null-group events to sessions by connectorId and time proximity
205
+ const nullEvents = sessionEventsMap.get(null) ?? [];
206
+ sessionEventsMap.delete(null);
207
+ const usedNullEventIds = new Set();
208
+ // Build sessions
209
+ const sessions = [];
210
+ let sessionIndex = 0;
211
+ for (const [txId, txEvents] of sessionEventsMap) {
212
+ // Find connectorId from the StartTransaction Call
213
+ const startTxCall = txEvents.find((e) => e.messageType === 'Call' && e.action === 'StartTransaction');
214
+ const connectorId = startTxCall ? extractConnectorId(startTxCall) : null;
215
+ // Include null-group events that belong to this session's connector
216
+ // and time range, or that are responses to Calls already in the session.
217
+ const txMessageIds = new Set(txEvents.map((e) => e.messageId));
218
+ const sessionStart = txEvents[0]?.timestamp ?? null;
219
+ const sessionEnd = txEvents[txEvents.length - 1]?.timestamp ?? null;
220
+ const relatedNullEvents = nullEvents.filter((e) => {
221
+ // Skip already-used events
222
+ if (usedNullEventIds.has(e.id))
223
+ return false;
224
+ // Include CallResult/CallError that match a Call already in the session
225
+ if (e.messageType !== 'Call' && txMessageIds.has(e.messageId)) {
226
+ return true;
227
+ }
228
+ const eventConnectorId = extractConnectorId(e);
229
+ // Include events with matching connectorId within time range
230
+ if (eventConnectorId !== null && connectorId !== null && eventConnectorId === connectorId) {
231
+ if (sessionStart !== null && sessionEnd !== null && e.timestamp !== null) {
232
+ return e.timestamp >= sessionStart && e.timestamp <= sessionEnd + 60000; // 1 min grace
233
+ }
234
+ return true; // No timestamps — include
235
+ }
236
+ // Include BootNotification events at the start
237
+ if (e.action === 'BootNotification' || e.action === 'Heartbeat') {
238
+ // Only include if this is the first session
239
+ return sessionIndex === 0;
240
+ }
241
+ // Include events without connectorId (like Authorize) within time range
242
+ // (extending before session start to include pre-session events like Authorize)
243
+ if (eventConnectorId === null &&
244
+ e.messageType === 'Call' &&
245
+ e.action !== 'BootNotification' &&
246
+ e.action !== 'Heartbeat') {
247
+ if (sessionStart !== null && sessionEnd !== null && e.timestamp !== null) {
248
+ // Include if within 5 minutes before session start through 1 min after end
249
+ return e.timestamp >= sessionStart - 300000 && e.timestamp <= sessionEnd + 60000;
250
+ }
251
+ }
252
+ return false;
253
+ });
254
+ // Mark these null events as used so they aren't included in other sessions
255
+ for (const e of relatedNullEvents) {
256
+ usedNullEventIds.add(e.id);
257
+ }
258
+ const allEvents = [...txEvents, ...relatedNullEvents].sort((a, b) => {
259
+ // Sort by original event order (ID is sequential)
260
+ return a.id.localeCompare(b.id);
261
+ });
262
+ sessions.push(createSession(`session-${sessionIndex}`, stationId, allEvents, connectorId, txId));
263
+ sessionIndex++;
264
+ }
265
+ // Sort sessions by start time
266
+ sessions.sort((a, b) => {
267
+ if (a.startTime === null)
268
+ return 1;
269
+ if (b.startTime === null)
270
+ return -1;
271
+ return a.startTime - b.startTime;
272
+ });
273
+ // Renumber sessions
274
+ sessions.forEach((s, i) => {
275
+ s.sessionId = `session-${i}`;
276
+ });
277
+ return sessions;
278
+ }
279
+ // ---------------------------------------------------------------------------
280
+ // createSession helper
281
+ // ---------------------------------------------------------------------------
282
+ function createSession(sessionId, stationId, events, connectorId = null, transactionId = null) {
283
+ const timestamps = events.map((e) => e.timestamp).filter((t) => t !== null);
284
+ const startTime = timestamps.length > 0 ? Math.min(...timestamps) : null;
285
+ const endTime = timestamps.length > 0 ? Math.max(...timestamps) : null;
286
+ // Determine session status
287
+ let status = 'active';
288
+ const hasStop = events.some((e) => e.messageType === 'Call' && e.action === 'StopTransaction');
289
+ const hasFaulted = events.some(isFaultedStatus);
290
+ const hasUnavailable = events.some(isUnavailableStatus);
291
+ if (hasStop) {
292
+ status = 'completed';
293
+ }
294
+ else if (hasFaulted || hasUnavailable) {
295
+ status = 'aborted';
296
+ }
297
+ // If we didn't get a transactionId from parameter, try to extract it
298
+ if (transactionId === null) {
299
+ for (const event of events) {
300
+ const txId = extractTransactionId(event);
301
+ if (txId !== null) {
302
+ transactionId = txId;
303
+ break;
304
+ }
305
+ }
306
+ }
307
+ return {
308
+ sessionId,
309
+ stationId,
310
+ connectorId,
311
+ transactionId,
312
+ startTime,
313
+ endTime,
314
+ events,
315
+ status,
316
+ };
317
+ }
318
+ //# sourceMappingURL=timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline.js","sourceRoot":"","sources":["../src/timeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Core type definitions for OCPP DebugKit.
3
+ *
4
+ * These are the proposed canonical types from the M0.5 design phase
5
+ * (ADR-0003 through ADR-0006). They will be fully implemented with Zod
6
+ * schemas in v0.1.0 (Issue #13).
7
+ */
8
+ /**
9
+ * Direction of an OCPP message.
10
+ * @see ADR-0004
11
+ */
12
+ export type Direction = 'CS_TO_CSMS' | 'CSMS_TO_CS' | 'UNKNOWN';
13
+ /**
14
+ * OCPP 1.6 JSON message type.
15
+ * - Call (2): request from one side to the other.
16
+ * - CallResult (3): successful response.
17
+ * - CallError (4): error response.
18
+ */
19
+ export type MessageType = 'Call' | 'CallResult' | 'CallError';
20
+ /**
21
+ * A raw OCPP 1.6 JSON message as it appears on the wire.
22
+ * The shape depends on the message type:
23
+ * - Call: [2, UniqueId, Action, Payload]
24
+ * - CallResult: [3, UniqueId, Payload]
25
+ * - CallError: [4, UniqueId, ErrorCode, ErrorDescription, ErrorDetails]
26
+ */
27
+ export type RawOcppMessage = [number, string, ...unknown[]];
28
+ /**
29
+ * A trace event entry as it appears in a trace file (JSON Object or JSONL).
30
+ * This is the input shape before normalization.
31
+ */
32
+ export interface TraceEventInput {
33
+ /** ISO 8601 string or Unix epoch (ms or s). Optional. */
34
+ timestamp?: string | number | null;
35
+ /** Direction of the message. Inferred if absent. */
36
+ direction?: Direction;
37
+ /** Raw OCPP 1.6 JSON message array. */
38
+ message: RawOcppMessage;
39
+ }
40
+ /**
41
+ * The canonical normalized event used internally by DebugKit.
42
+ * @see ADR-0003
43
+ */
44
+ export interface Event {
45
+ /** Generated unique event ID (sequential, stable within a parse). */
46
+ id: string;
47
+ /** OCPP UniqueId from the message array. */
48
+ messageId: string;
49
+ /** Normalized timestamp in epoch milliseconds. null if missing. */
50
+ timestamp: number | null;
51
+ /** Direction of the message. */
52
+ direction: Direction;
53
+ /** OCPP message type. */
54
+ messageType: MessageType;
55
+ /** OCPP action name (e.g., "BootNotification"). Present only for Call messages. */
56
+ action: string | null;
57
+ /** OCPP payload object. */
58
+ payload: unknown;
59
+ /** Error code, present only for CallError messages. */
60
+ errorCode: string | null;
61
+ /** Error description, present only for CallError messages. */
62
+ errorDescription: string | null;
63
+ /** The original raw OCPP message array, unmodified. */
64
+ rawMessage: RawOcppMessage;
65
+ }
66
+ /**
67
+ * Metadata for a trace file.
68
+ */
69
+ export interface TraceMetadata {
70
+ stationId?: string;
71
+ ocppVersion?: string;
72
+ source?: string;
73
+ description?: string;
74
+ }
75
+ /**
76
+ * The JSON Object trace format.
77
+ * @see ADR-0002, docs/trace-format-spec.md
78
+ */
79
+ export interface Trace {
80
+ traceId?: string;
81
+ metadata?: TraceMetadata;
82
+ events: TraceEventInput[];
83
+ }
84
+ /**
85
+ * A logical charging session derived from trace events.
86
+ * @see ADR-0006
87
+ */
88
+ export interface Session {
89
+ sessionId: string;
90
+ stationId: string;
91
+ connectorId: number | null;
92
+ transactionId: number | null;
93
+ startTime: number | null;
94
+ endTime: number | null;
95
+ events: Event[];
96
+ status: 'active' | 'completed' | 'aborted';
97
+ }
98
+ /**
99
+ * A warning produced during parsing when an individual event is malformed.
100
+ * @see ADR-0007
101
+ */
102
+ export interface ParseWarning {
103
+ index: number;
104
+ message: string;
105
+ rawInput?: string;
106
+ }
107
+ /**
108
+ * Result of parsing a trace.
109
+ */
110
+ export interface ParseResult {
111
+ events: Event[];
112
+ warnings: ParseWarning[];
113
+ }
114
+ /** Severity of a detected failure. */
115
+ export type FailureSeverity = 'critical' | 'warning' | 'info';
116
+ /** Failure rule codes implemented in v0.1. */
117
+ export type FailureCode = 'FAILED_AUTHORIZATION' | 'CONNECTOR_FAULT' | 'STATION_OFFLINE_DURING_SESSION';
118
+ /**
119
+ * A detected failure in a trace.
120
+ */
121
+ export interface Failure {
122
+ /** Failure rule code. */
123
+ code: FailureCode;
124
+ /** Human-readable description. */
125
+ description: string;
126
+ /** Severity level. */
127
+ severity: FailureSeverity;
128
+ /** Event IDs associated with the failure. */
129
+ eventIds: string[];
130
+ /** Suggested next steps for resolution. */
131
+ suggestedSteps: string[];
132
+ }
133
+ /** Summary statistics for a charging session. */
134
+ export interface SessionSummary {
135
+ sessionId: string;
136
+ stationId: string;
137
+ connectorId: number | null;
138
+ transactionId: number | null;
139
+ status: 'active' | 'completed' | 'aborted';
140
+ eventCount: number;
141
+ durationMs: number | null;
142
+ failureCount: number;
143
+ /** Ordered list of actions in the session. */
144
+ actionSequence: string[];
145
+ }
146
+ /** Result of validating a single OCPP message. */
147
+ export interface ValidationResult {
148
+ valid: boolean;
149
+ errors: string[];
150
+ }
151
+ /** A scenario fixture for testing the analysis engine. */
152
+ export interface Scenario {
153
+ name: string;
154
+ description: string;
155
+ /** The trace data to analyze. */
156
+ trace: Trace;
157
+ /** Failure codes expected to be detected. */
158
+ expectedFailures: FailureCode[];
159
+ }
160
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,YAAY,GAAG,SAAS,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,WAAW,CAAC;AAM9D;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;AAE5D;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACnC,oDAAoD;IACpD,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,uCAAuC;IACvC,OAAO,EAAE,cAAc,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,KAAK;IACpB,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gCAAgC;IAChC,SAAS,EAAE,SAAS,CAAC;IACrB,yBAAyB;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,mFAAmF;IACnF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,2BAA2B;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,8DAA8D;IAC9D,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,uDAAuD;IACvD,UAAU,EAAE,cAAc,CAAC;CAC5B;AAMD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,KAAK;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAMD;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;CAC5C;AAMD;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAMD,sCAAsC;AACtC,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAE9D,8CAA8C;AAC9C,MAAM,MAAM,WAAW,GACrB,sBAAsB,GAAG,iBAAiB,GAAG,gCAAgC,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,yBAAyB;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB;IACtB,QAAQ,EAAE,eAAe,CAAC;IAC1B,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2CAA2C;IAC3C,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAMD,iDAAiD;AACjD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAMD,kDAAkD;AAClD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAMD,0DAA0D;AAC1D,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,KAAK,EAAE,KAAK,CAAC;IACb,6CAA6C;IAC7C,gBAAgB,EAAE,WAAW,EAAE,CAAC;CACjC"}
package/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Core type definitions for OCPP DebugKit.
3
+ *
4
+ * These are the proposed canonical types from the M0.5 design phase
5
+ * (ADR-0003 through ADR-0006). They will be fully implemented with Zod
6
+ * schemas in v0.1.0 (Issue #13).
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * OCPP message validator — checks structural compliance of individual messages.
3
+ *
4
+ * Validates that an OCPP 1.6 JSON message conforms to the protocol's
5
+ * structural requirements.
6
+ *
7
+ * @see docs/trace-format-spec.md
8
+ */
9
+ import type { Event, ValidationResult } from './types.js';
10
+ /**
11
+ * Validate a single OCPP message for structural compliance.
12
+ *
13
+ * Checks:
14
+ * - Message array has correct minimum length for its type
15
+ * - MessageTypeId is 2, 3, or 4
16
+ * - UniqueId is a non-empty string
17
+ * - Call messages have a string Action
18
+ * - CallError messages have ErrorCode and ErrorDescription
19
+ * - MessageType field is consistent with raw message's MessageTypeId
20
+ *
21
+ * @param event - The event to validate
22
+ * @param allEvents - Optional: all events in the trace (for Call/Response matching)
23
+ * @returns Validation result with errors array
24
+ */
25
+ export declare function validateMessage(event: Event, allEvents?: Event[]): ValidationResult;
26
+ /**
27
+ * Validate all events in a trace.
28
+ *
29
+ * @param events - All events in the trace
30
+ * @returns Map of event ID to validation result
31
+ */
32
+ export declare function validateMessages(events: Event[]): Map<string, ValidationResult>;
33
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAe,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA+FvE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,gBAAgB,CAcnF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAQ/E"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * OCPP message validator — checks structural compliance of individual messages.
3
+ *
4
+ * Validates that an OCPP 1.6 JSON message conforms to the protocol's
5
+ * structural requirements.
6
+ *
7
+ * @see docs/trace-format-spec.md
8
+ */
9
+ // ---------------------------------------------------------------------------
10
+ // Validation rules
11
+ // ---------------------------------------------------------------------------
12
+ /**
13
+ * Validate the message structure based on its type.
14
+ *
15
+ * Call (2): [2, UniqueId, Action, Payload] — 4+ elements, Action is string
16
+ * CallResult (3): [3, UniqueId, Payload] — 3+ elements
17
+ * CallError (4): [4, UniqueId, ErrorCode, ErrorDescription, ErrorDetails] — 5+ elements
18
+ */
19
+ function validateMessageStructure(event) {
20
+ const errors = [];
21
+ const msg = event.rawMessage;
22
+ const msgType = event.messageType;
23
+ // Check minimum length
24
+ const minLength = msgType === 'Call' ? 4 : msgType === 'CallResult' ? 3 : 5;
25
+ if (msg.length < minLength) {
26
+ errors.push(`${msgType} message must have at least ${minLength} elements (has ${msg.length})`);
27
+ }
28
+ // Check MessageTypeId (index 0)
29
+ if (msg[0] !== 2 && msg[0] !== 3 && msg[0] !== 4) {
30
+ errors.push(`Invalid MessageTypeId: ${msg[0]} (expected 2, 3, or 4)`);
31
+ }
32
+ // Check UniqueId (index 1)
33
+ if (typeof msg[1] !== 'string' || msg[1] === '') {
34
+ errors.push('UniqueId (index 1) must be a non-empty string');
35
+ }
36
+ // Call-specific: Action (index 2) must be a string
37
+ if (msgType === 'Call') {
38
+ if (typeof msg[2] !== 'string' || msg[2] === '') {
39
+ errors.push('Call Action (index 2) must be a non-empty string');
40
+ }
41
+ }
42
+ // CallError-specific: ErrorCode and ErrorDescription
43
+ if (msgType === 'CallError') {
44
+ if (typeof msg[2] !== 'string' || msg[2] === '') {
45
+ errors.push('CallError ErrorCode (index 2) must be a non-empty string');
46
+ }
47
+ if (typeof msg[3] !== 'string') {
48
+ errors.push('CallError ErrorDescription (index 3) must be a string');
49
+ }
50
+ }
51
+ return errors;
52
+ }
53
+ /**
54
+ * Validate that the event's messageType matches the raw message's MessageTypeId.
55
+ */
56
+ function validateTypeConsistency(event) {
57
+ const errors = [];
58
+ const expectedType = event.rawMessage[0] === 2 ? 'Call' : event.rawMessage[0] === 3 ? 'CallResult' : 'CallError';
59
+ if (event.messageType !== expectedType) {
60
+ errors.push(`MessageType mismatch: event says "${event.messageType}" but raw message has MessageTypeId ${event.rawMessage[0]} ("${expectedType}")`);
61
+ }
62
+ return errors;
63
+ }
64
+ /**
65
+ * Validate that CallResult/CallError have a matching Call.
66
+ * This is a soft validation — the function checks if there's a Call with
67
+ * the same messageId in the provided event list.
68
+ */
69
+ function validateResponseHasCall(event, allEvents) {
70
+ const errors = [];
71
+ if (event.messageType === 'CallResult' || event.messageType === 'CallError') {
72
+ const hasCall = allEvents.some((e) => e.messageType === 'Call' && e.messageId === event.messageId);
73
+ if (!hasCall) {
74
+ errors.push(`${event.messageType} with messageId "${event.messageId}" has no matching Call`);
75
+ }
76
+ }
77
+ return errors;
78
+ }
79
+ // ---------------------------------------------------------------------------
80
+ // validateMessage()
81
+ // ---------------------------------------------------------------------------
82
+ /**
83
+ * Validate a single OCPP message for structural compliance.
84
+ *
85
+ * Checks:
86
+ * - Message array has correct minimum length for its type
87
+ * - MessageTypeId is 2, 3, or 4
88
+ * - UniqueId is a non-empty string
89
+ * - Call messages have a string Action
90
+ * - CallError messages have ErrorCode and ErrorDescription
91
+ * - MessageType field is consistent with raw message's MessageTypeId
92
+ *
93
+ * @param event - The event to validate
94
+ * @param allEvents - Optional: all events in the trace (for Call/Response matching)
95
+ * @returns Validation result with errors array
96
+ */
97
+ export function validateMessage(event, allEvents) {
98
+ const errors = [];
99
+ errors.push(...validateMessageStructure(event));
100
+ errors.push(...validateTypeConsistency(event));
101
+ if (allEvents) {
102
+ errors.push(...validateResponseHasCall(event, allEvents));
103
+ }
104
+ return {
105
+ valid: errors.length === 0,
106
+ errors,
107
+ };
108
+ }
109
+ /**
110
+ * Validate all events in a trace.
111
+ *
112
+ * @param events - All events in the trace
113
+ * @returns Map of event ID to validation result
114
+ */
115
+ export function validateMessages(events) {
116
+ const results = new Map();
117
+ for (const event of events) {
118
+ results.set(event.id, validateMessage(event, events));
119
+ }
120
+ return results;
121
+ }
122
+ //# sourceMappingURL=validator.js.map