@ocpp-debugkit/toolkit 0.2.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 (124) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +14 -0
  3. package/README.md +35 -0
  4. package/dist/cli/commands/inspect.d.ts +8 -0
  5. package/dist/cli/commands/inspect.d.ts.map +1 -0
  6. package/dist/cli/commands/inspect.js +63 -0
  7. package/dist/cli/commands/inspect.js.map +1 -0
  8. package/dist/cli/commands/report.d.ts +9 -0
  9. package/dist/cli/commands/report.d.ts.map +1 -0
  10. package/dist/cli/commands/report.js +54 -0
  11. package/dist/cli/commands/report.js.map +1 -0
  12. package/dist/cli/commands/scenario.d.ts +10 -0
  13. package/dist/cli/commands/scenario.d.ts.map +1 -0
  14. package/dist/cli/commands/scenario.js +104 -0
  15. package/dist/cli/commands/scenario.js.map +1 -0
  16. package/dist/cli/index.d.ts +7 -0
  17. package/dist/cli/index.d.ts.map +1 -0
  18. package/dist/cli/index.js +47 -0
  19. package/dist/cli/index.js.map +1 -0
  20. package/dist/cli/utils.d.ts +13 -0
  21. package/dist/cli/utils.d.ts.map +1 -0
  22. package/dist/cli/utils.js +43 -0
  23. package/dist/cli/utils.js.map +1 -0
  24. package/dist/core/__fixtures__/connector-fault.d.ts +116 -0
  25. package/dist/core/__fixtures__/connector-fault.d.ts.map +1 -0
  26. package/dist/core/__fixtures__/connector-fault.js +231 -0
  27. package/dist/core/__fixtures__/connector-fault.js.map +1 -0
  28. package/dist/core/__fixtures__/failed-auth.d.ts +64 -0
  29. package/dist/core/__fixtures__/failed-auth.d.ts.map +1 -0
  30. package/dist/core/__fixtures__/failed-auth.js +173 -0
  31. package/dist/core/__fixtures__/failed-auth.js.map +1 -0
  32. package/dist/core/__fixtures__/normal-session.d.ts +108 -0
  33. package/dist/core/__fixtures__/normal-session.d.ts.map +1 -0
  34. package/dist/core/__fixtures__/normal-session.js +261 -0
  35. package/dist/core/__fixtures__/normal-session.js.map +1 -0
  36. package/dist/core/detection.d.ts +23 -0
  37. package/dist/core/detection.d.ts.map +1 -0
  38. package/dist/core/detection.js +226 -0
  39. package/dist/core/detection.js.map +1 -0
  40. package/dist/core/fixtures/index.d.ts +298 -0
  41. package/dist/core/fixtures/index.d.ts.map +1 -0
  42. package/dist/core/fixtures/index.js +19 -0
  43. package/dist/core/fixtures/index.js.map +1 -0
  44. package/dist/core/index.d.ts +14 -0
  45. package/dist/core/index.d.ts.map +1 -0
  46. package/dist/core/index.js +22 -0
  47. package/dist/core/index.js.map +1 -0
  48. package/dist/core/normalizer.d.ts +83 -0
  49. package/dist/core/normalizer.d.ts.map +1 -0
  50. package/dist/core/normalizer.js +289 -0
  51. package/dist/core/normalizer.js.map +1 -0
  52. package/dist/core/parser.d.ts +53 -0
  53. package/dist/core/parser.d.ts.map +1 -0
  54. package/dist/core/parser.js +282 -0
  55. package/dist/core/parser.js.map +1 -0
  56. package/dist/core/schemas.d.ts +68 -0
  57. package/dist/core/schemas.d.ts.map +1 -0
  58. package/dist/core/schemas.js +81 -0
  59. package/dist/core/schemas.js.map +1 -0
  60. package/dist/core/summarizer.d.ts +25 -0
  61. package/dist/core/summarizer.d.ts.map +1 -0
  62. package/dist/core/summarizer.js +47 -0
  63. package/dist/core/summarizer.js.map +1 -0
  64. package/dist/core/timeline.d.ts +26 -0
  65. package/dist/core/timeline.d.ts.map +1 -0
  66. package/dist/core/timeline.js +318 -0
  67. package/dist/core/timeline.js.map +1 -0
  68. package/dist/core/types.d.ts +160 -0
  69. package/dist/core/types.d.ts.map +1 -0
  70. package/dist/core/types.js +9 -0
  71. package/dist/core/types.js.map +1 -0
  72. package/dist/core/validator.d.ts +33 -0
  73. package/dist/core/validator.d.ts.map +1 -0
  74. package/dist/core/validator.js +122 -0
  75. package/dist/core/validator.js.map +1 -0
  76. package/dist/index.d.ts +24 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +26 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/react/components.d.ts +50 -0
  81. package/dist/react/components.d.ts.map +1 -0
  82. package/dist/react/components.js +49 -0
  83. package/dist/react/components.js.map +1 -0
  84. package/dist/react/index.d.ts +11 -0
  85. package/dist/react/index.d.ts.map +1 -0
  86. package/dist/react/index.js +10 -0
  87. package/dist/react/index.js.map +1 -0
  88. package/dist/react/types.d.ts +33 -0
  89. package/dist/react/types.d.ts.map +1 -0
  90. package/dist/react/types.js +5 -0
  91. package/dist/react/types.js.map +1 -0
  92. package/dist/replay/engine.d.ts +55 -0
  93. package/dist/replay/engine.d.ts.map +1 -0
  94. package/dist/replay/engine.js +86 -0
  95. package/dist/replay/engine.js.map +1 -0
  96. package/dist/replay/index.d.ts +11 -0
  97. package/dist/replay/index.d.ts.map +1 -0
  98. package/dist/replay/index.js +11 -0
  99. package/dist/replay/index.js.map +1 -0
  100. package/dist/reporter/index.d.ts +6 -0
  101. package/dist/reporter/index.d.ts.map +1 -0
  102. package/dist/reporter/index.js +5 -0
  103. package/dist/reporter/index.js.map +1 -0
  104. package/dist/reporter/markdown.d.ts +20 -0
  105. package/dist/reporter/markdown.d.ts.map +1 -0
  106. package/dist/reporter/markdown.js +181 -0
  107. package/dist/reporter/markdown.js.map +1 -0
  108. package/dist/reporter/types.d.ts +34 -0
  109. package/dist/reporter/types.d.ts.map +1 -0
  110. package/dist/reporter/types.js +9 -0
  111. package/dist/reporter/types.js.map +1 -0
  112. package/dist/scenarios/__scenarios__/station-offline.d.ts +94 -0
  113. package/dist/scenarios/__scenarios__/station-offline.d.ts.map +1 -0
  114. package/dist/scenarios/__scenarios__/station-offline.js +168 -0
  115. package/dist/scenarios/__scenarios__/station-offline.js.map +1 -0
  116. package/dist/scenarios/__scenarios__/unexpected-stop-reason.d.ts +112 -0
  117. package/dist/scenarios/__scenarios__/unexpected-stop-reason.d.ts.map +1 -0
  118. package/dist/scenarios/__scenarios__/unexpected-stop-reason.js +216 -0
  119. package/dist/scenarios/__scenarios__/unexpected-stop-reason.js.map +1 -0
  120. package/dist/scenarios/index.d.ts +21 -0
  121. package/dist/scenarios/index.d.ts.map +1 -0
  122. package/dist/scenarios/index.js +61 -0
  123. package/dist/scenarios/index.js.map +1 -0
  124. package/package.json +110 -0
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Event normalizer — transforms raw trace event inputs into canonical
3
+ * `Event` objects with classified message type, direction, and timestamps.
4
+ *
5
+ * @see ADR-0003 (canonical event model)
6
+ * @see ADR-0004 (message direction)
7
+ * @see ADR-0005 (timestamp normalization)
8
+ */
9
+ // ---------------------------------------------------------------------------
10
+ // Direction inference (ADR-0004)
11
+ // ---------------------------------------------------------------------------
12
+ /**
13
+ * Actions initiated by the Charge Point (CS → CSMS).
14
+ * These are OCPP 1.6 actions sent FROM the station TO the CSMS.
15
+ */
16
+ const CS_TO_CSMS_ACTIONS = new Set([
17
+ 'BootNotification',
18
+ 'Heartbeat',
19
+ 'Authorize',
20
+ 'StartTransaction',
21
+ 'StopTransaction',
22
+ 'StatusNotification',
23
+ 'MeterValues',
24
+ 'DataTransfer',
25
+ 'DiagnosticsStatusNotification',
26
+ 'FirmwareStatusNotification',
27
+ 'SecurityEventNotification',
28
+ 'SignCertificate',
29
+ 'SignedFirmwareStatusNotification',
30
+ 'LogStatusNotification',
31
+ ]);
32
+ /**
33
+ * Actions initiated by the CSMS (CSMS → CS).
34
+ * These are OCPP 1.6 actions sent FROM the CSMS TO the station.
35
+ */
36
+ const CSMS_TO_CS_ACTIONS = new Set([
37
+ 'Reset',
38
+ 'RemoteStartTransaction',
39
+ 'RemoteStopTransaction',
40
+ 'GetConfiguration',
41
+ 'ChangeConfiguration',
42
+ 'SetChargingProfile',
43
+ 'ClearChargingProfile',
44
+ 'ChangeAvailability',
45
+ 'ReserveNow',
46
+ 'CancelReservation',
47
+ 'DataTransfer',
48
+ 'GetLocalListVersion',
49
+ 'SendLocalList',
50
+ 'TriggerMessage',
51
+ 'UnlockConnector',
52
+ 'GetDiagnostics',
53
+ 'UpdateFirmware',
54
+ 'ExtendedTriggerMessage',
55
+ 'GetLog',
56
+ 'SignedUpdateFirmware',
57
+ 'CertificateSigned',
58
+ 'DeleteCertificate',
59
+ 'GetInstalledCertificateIds',
60
+ 'InstallCertificate',
61
+ ]);
62
+ /**
63
+ * Infer the direction of a Call message from its action name (ADR-0004).
64
+ * - If the action is known to be CS→CSMS, return 'CS_TO_CSMS'.
65
+ * - If the action is known to be CSMS→CS, return 'CSMS_TO_CS'.
66
+ * - If the action is not recognized, return 'UNKNOWN'.
67
+ *
68
+ * For CallResult/CallError, the direction is the reverse of the original Call.
69
+ * Since we don't have the original Call's direction here, we infer based on
70
+ * the matched Call's action. For responses without a matched Call, we use
71
+ * 'UNKNOWN'.
72
+ */
73
+ export function inferDirection(messageType, action) {
74
+ if (messageType === 'Call' && action !== null) {
75
+ if (CS_TO_CSMS_ACTIONS.has(action))
76
+ return 'CS_TO_CSMS';
77
+ if (CSMS_TO_CS_ACTIONS.has(action))
78
+ return 'CSMS_TO_CS';
79
+ return 'UNKNOWN';
80
+ }
81
+ // For CallResult/CallError, direction should be the reverse of the Call.
82
+ // We can't know for certain without matching — return UNKNOWN.
83
+ // The parser will resolve this after matching Calls to responses.
84
+ return 'UNKNOWN';
85
+ }
86
+ /**
87
+ * Determine the reverse direction for a response.
88
+ * Call CS→CSMS → Response CSMS→CS, and vice versa.
89
+ */
90
+ export function reverseDirection(dir) {
91
+ switch (dir) {
92
+ case 'CS_TO_CSMS':
93
+ return 'CSMS_TO_CS';
94
+ case 'CSMS_TO_CS':
95
+ return 'CS_TO_CSMS';
96
+ case 'UNKNOWN':
97
+ return 'UNKNOWN';
98
+ }
99
+ }
100
+ // ---------------------------------------------------------------------------
101
+ // Timestamp normalization (ADR-0005)
102
+ // ---------------------------------------------------------------------------
103
+ /**
104
+ * Threshold for distinguishing Unix epoch seconds from milliseconds.
105
+ * Values below 10^12 are treated as seconds; above as milliseconds.
106
+ * (10^12 = year ~33658 in ms, year ~2001 in s)
107
+ */
108
+ const EPOCH_MS_THRESHOLD = 1e12;
109
+ /**
110
+ * Normalize a timestamp to epoch milliseconds.
111
+ *
112
+ * Accepts:
113
+ * - ISO 8601 strings (UTC or with offset)
114
+ * - Unix epoch in milliseconds (number >= 10^12)
115
+ * - Unix epoch in seconds (number < 10^12)
116
+ * - null/undefined → null
117
+ *
118
+ * @returns epoch milliseconds, or null if the timestamp is missing or invalid.
119
+ */
120
+ export function normalizeTimestamp(timestamp) {
121
+ if (timestamp === null || timestamp === undefined) {
122
+ return null;
123
+ }
124
+ if (typeof timestamp === 'number') {
125
+ if (!Number.isFinite(timestamp)) {
126
+ return null;
127
+ }
128
+ // Detect seconds vs milliseconds
129
+ return timestamp < EPOCH_MS_THRESHOLD ? Math.round(timestamp * 1000) : Math.round(timestamp);
130
+ }
131
+ if (typeof timestamp === 'string') {
132
+ const trimmed = timestamp.trim();
133
+ if (trimmed === '') {
134
+ return null;
135
+ }
136
+ // Try parsing as a number first (stringified epoch)
137
+ const asNum = Number(trimmed);
138
+ if (Number.isFinite(asNum)) {
139
+ return asNum < EPOCH_MS_THRESHOLD ? Math.round(asNum * 1000) : Math.round(asNum);
140
+ }
141
+ // Parse as ISO 8601
142
+ const parsed = Date.parse(trimmed);
143
+ if (Number.isNaN(parsed)) {
144
+ return null;
145
+ }
146
+ return parsed;
147
+ }
148
+ return null;
149
+ }
150
+ // ---------------------------------------------------------------------------
151
+ // Message type classification
152
+ // ---------------------------------------------------------------------------
153
+ /**
154
+ * Classify the OCPP message type from the raw message array.
155
+ * - [2, ...] → 'Call'
156
+ * - [3, ...] → 'CallResult'
157
+ * - [4, ...] → 'CallError'
158
+ */
159
+ export function classifyMessageType(message) {
160
+ const typeId = message[0];
161
+ switch (typeId) {
162
+ case 2:
163
+ return 'Call';
164
+ case 3:
165
+ return 'CallResult';
166
+ case 4:
167
+ return 'CallError';
168
+ default:
169
+ // Should not happen — schema validation prevents this
170
+ return 'Call';
171
+ }
172
+ }
173
+ /**
174
+ * Extract the action name from a Call message.
175
+ * Only Call messages have an action (at index 2).
176
+ */
177
+ export function extractAction(message) {
178
+ if (message[0] === 2 && message.length >= 3) {
179
+ const action = message[2];
180
+ return typeof action === 'string' ? action : null;
181
+ }
182
+ return null;
183
+ }
184
+ /**
185
+ * Extract the payload from any message type.
186
+ * - Call: index 3
187
+ * - CallResult: index 2
188
+ * - CallError: index 4 (ErrorDetails)
189
+ */
190
+ export function extractPayload(message) {
191
+ switch (message[0]) {
192
+ case 2:
193
+ return message[3] ?? null;
194
+ case 3:
195
+ return message[2] ?? null;
196
+ case 4:
197
+ return message[4] ?? null;
198
+ default:
199
+ return null;
200
+ }
201
+ }
202
+ /**
203
+ * Extract error code from a CallError message (index 2).
204
+ */
205
+ export function extractErrorCode(message) {
206
+ if (message[0] === 4 && message.length >= 3) {
207
+ const code = message[2];
208
+ return typeof code === 'string' ? code : null;
209
+ }
210
+ return null;
211
+ }
212
+ /**
213
+ * Extract error description from a CallError message (index 3).
214
+ */
215
+ export function extractErrorDescription(message) {
216
+ if (message[0] === 4 && message.length >= 4) {
217
+ const desc = message[3];
218
+ return typeof desc === 'string' ? desc : null;
219
+ }
220
+ return null;
221
+ }
222
+ // ---------------------------------------------------------------------------
223
+ // normalizeEvents()
224
+ // ---------------------------------------------------------------------------
225
+ /**
226
+ * Normalize an array of raw trace event inputs into canonical `Event` objects.
227
+ *
228
+ * This function:
229
+ * 1. Classifies the message type (Call/CallResult/CallError)
230
+ * 2. Extracts action, payload, error fields
231
+ * 3. Normalizes timestamps to epoch milliseconds
232
+ * 4. Resolves direction: uses explicit direction if provided, otherwise
233
+ * infers from action name (for Calls) or from the matched Call (for responses)
234
+ * 5. Generates sequential event IDs
235
+ *
236
+ * Events are NOT reordered (ADR-0005). Out-of-order timestamps are preserved
237
+ * as-is; the caller can detect them after normalization.
238
+ *
239
+ * @see ADR-0003, ADR-0004, ADR-0005
240
+ */
241
+ export function normalizeEvents(inputs) {
242
+ // First pass: create events with best-effort direction
243
+ const events = inputs.map((input, index) => {
244
+ const message = input.message;
245
+ const messageType = classifyMessageType(message);
246
+ const action = extractAction(message);
247
+ // Use explicit direction, or infer from action for Call messages.
248
+ // An explicit direction (including 'UNKNOWN') is respected as-is.
249
+ // Only infer when direction is not provided at all (undefined).
250
+ let direction = input.direction;
251
+ if (direction === undefined && messageType === 'Call' && action !== null) {
252
+ direction = inferDirection(messageType, action);
253
+ }
254
+ if (direction === undefined) {
255
+ direction = 'UNKNOWN';
256
+ }
257
+ return {
258
+ id: `evt-${String(index + 1).padStart(4, '0')}`,
259
+ messageId: message[1],
260
+ timestamp: normalizeTimestamp(input.timestamp),
261
+ direction,
262
+ messageType,
263
+ action,
264
+ payload: extractPayload(message),
265
+ errorCode: extractErrorCode(message),
266
+ errorDescription: extractErrorDescription(message),
267
+ rawMessage: message,
268
+ };
269
+ });
270
+ // Second pass: resolve response directions by matching to their original Calls.
271
+ // Build a map of messageId → Call direction.
272
+ const callDirections = new Map();
273
+ for (const event of events) {
274
+ if (event.messageType === 'Call' && event.direction !== 'UNKNOWN') {
275
+ callDirections.set(event.messageId, event.direction);
276
+ }
277
+ }
278
+ // For CallResult/CallError with UNKNOWN direction, infer from the matched Call
279
+ for (const event of events) {
280
+ if (event.direction === 'UNKNOWN' && event.messageType !== 'Call') {
281
+ const callDir = callDirections.get(event.messageId);
282
+ if (callDir) {
283
+ event.direction = reverseDirection(callDir);
284
+ }
285
+ }
286
+ }
287
+ return events;
288
+ }
289
+ //# sourceMappingURL=normalizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalizer.js","sourceRoot":"","sources":["../../src/core/normalizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Trace parser — accepts untrusted input in JSON Object, JSONL, or bare array
3
+ * format and produces normalized `Event` objects with warnings for malformed
4
+ * entries.
5
+ *
6
+ * Security:
7
+ * - Safe JSON parsing with try/catch
8
+ * - Input size limit (10 MB)
9
+ * - Event count limit (10,000)
10
+ * - Zod schema validation prevents prototype pollution
11
+ * - Malformed individual events are skipped with a `ParseWarning`
12
+ * - Structural errors (invalid JSON, missing events array) fail fast
13
+ *
14
+ * @see ADR-0002 (input trace formats)
15
+ * @see ADR-0007 (malformed trace handling)
16
+ * @see docs/trace-format-spec.md
17
+ */
18
+ import type { ParseResult } from './types.js';
19
+ /** Maximum input size in bytes (10 MB). */
20
+ export declare const MAX_INPUT_SIZE_BYTES: number;
21
+ /** Maximum number of events after parsing. */
22
+ export declare const MAX_EVENT_COUNT = 10000;
23
+ /** Error thrown when input exceeds size limits or has structural problems. */
24
+ export declare class ParseError extends Error {
25
+ constructor(message: string);
26
+ }
27
+ /**
28
+ * Detect the trace format by examining the input string.
29
+ *
30
+ * - JSONL: multiple lines, first non-empty line starts with `{` and parses as JSON
31
+ * - JSON Object: starts with `{`
32
+ * - Bare Array: starts with `[`
33
+ *
34
+ * This function does NOT validate the full content — it just determines
35
+ * which parsing strategy to use.
36
+ */
37
+ export type TraceFormat = 'json-object' | 'jsonl' | 'bare-array';
38
+ /**
39
+ * Parse a trace from a raw string input.
40
+ *
41
+ * Accepts:
42
+ * - JSON Object format (metadata + events array)
43
+ * - JSONL format (one event per line)
44
+ * - Bare array format (array of raw OCPP message arrays)
45
+ *
46
+ * @param input - Raw trace string (untrusted)
47
+ * @returns ParseResult with normalized events and warnings for malformed entries
48
+ * @throws {ParseError} for structural errors (invalid JSON, missing events, size/count limits exceeded)
49
+ *
50
+ * @see ADR-0002, ADR-0007
51
+ */
52
+ export declare function parseTrace(input: string): ParseResult;
53
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,KAAK,EAAS,WAAW,EAAiC,MAAM,YAAY,CAAC;AAMpF,2CAA2C;AAC3C,eAAO,MAAM,oBAAoB,QAAmB,CAAC;AAErD,8CAA8C;AAC9C,eAAO,MAAM,eAAe,QAAS,CAAC;AAMtC,8EAA8E;AAC9E,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B;AAoCD;;;;;;;;;GASG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,OAAO,GAAG,YAAY,CAAC;AAiLjE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CA4DrD"}
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Trace parser — accepts untrusted input in JSON Object, JSONL, or bare array
3
+ * format and produces normalized `Event` objects with warnings for malformed
4
+ * entries.
5
+ *
6
+ * Security:
7
+ * - Safe JSON parsing with try/catch
8
+ * - Input size limit (10 MB)
9
+ * - Event count limit (10,000)
10
+ * - Zod schema validation prevents prototype pollution
11
+ * - Malformed individual events are skipped with a `ParseWarning`
12
+ * - Structural errors (invalid JSON, missing events array) fail fast
13
+ *
14
+ * @see ADR-0002 (input trace formats)
15
+ * @see ADR-0007 (malformed trace handling)
16
+ * @see docs/trace-format-spec.md
17
+ */
18
+ import { bareArraySchema, rawOcppMessageSchema, traceEventInputSchema, traceSchema, } from './schemas.js';
19
+ import { normalizeEvents } from './normalizer.js';
20
+ // ---------------------------------------------------------------------------
21
+ // Limits (ADR-0007, docs/trace-format-spec.md)
22
+ // ---------------------------------------------------------------------------
23
+ /** Maximum input size in bytes (10 MB). */
24
+ export const MAX_INPUT_SIZE_BYTES = 10 * 1024 * 1024;
25
+ /** Maximum number of events after parsing. */
26
+ export const MAX_EVENT_COUNT = 10_000;
27
+ // ---------------------------------------------------------------------------
28
+ // Errors
29
+ // ---------------------------------------------------------------------------
30
+ /** Error thrown when input exceeds size limits or has structural problems. */
31
+ export class ParseError extends Error {
32
+ constructor(message) {
33
+ super(message);
34
+ this.name = 'ParseError';
35
+ }
36
+ }
37
+ // ---------------------------------------------------------------------------
38
+ // Input size validation
39
+ // ---------------------------------------------------------------------------
40
+ /**
41
+ * Validate the input size before any parsing.
42
+ * @throws {ParseError} if the input exceeds the maximum size.
43
+ */
44
+ function validateInputSize(input) {
45
+ const byteLength = Buffer.byteLength(input, 'utf8');
46
+ if (byteLength > MAX_INPUT_SIZE_BYTES) {
47
+ throw new ParseError(`Input size (${byteLength} bytes) exceeds the maximum allowed size ` +
48
+ `(${MAX_INPUT_SIZE_BYTES} bytes).`);
49
+ }
50
+ }
51
+ /**
52
+ * Validate the event count after parsing.
53
+ * @throws {ParseError} if the event count exceeds the maximum.
54
+ */
55
+ function validateEventCount(events) {
56
+ if (events.length > MAX_EVENT_COUNT) {
57
+ throw new ParseError(`Event count (${events.length}) exceeds the maximum allowed count ` + `(${MAX_EVENT_COUNT}).`);
58
+ }
59
+ }
60
+ function detectFormat(input) {
61
+ const trimmed = input.trim();
62
+ if (trimmed.startsWith('{')) {
63
+ // Could be JSON Object format or JSONL starting with an event object.
64
+ // JSONL has multiple lines; a JSON Object is a single JSON value.
65
+ // We check if the trimmed input contains a newline followed by another `{`
66
+ // that is NOT inside a string (simplified check: if the last non-whitespace
67
+ // character is `}`, and there's content after the first `}`... but that's
68
+ // complex. Simpler: try parsing as a single JSON value first, and if that
69
+ // fails, try JSONL.
70
+ return 'json-object';
71
+ }
72
+ if (trimmed.startsWith('[')) {
73
+ return 'bare-array';
74
+ }
75
+ // Default to JSONL for other cases (each line is a JSON object)
76
+ return 'jsonl';
77
+ }
78
+ // ---------------------------------------------------------------------------
79
+ // JSONL parsing
80
+ // ---------------------------------------------------------------------------
81
+ /**
82
+ * Parse JSONL input: one event per line.
83
+ * Blank lines are ignored. Malformed lines produce warnings.
84
+ *
85
+ * @returns array of valid TraceEventInput and warnings for malformed lines.
86
+ */
87
+ function parseJsonl(input) {
88
+ const lines = input.split('\n');
89
+ const events = [];
90
+ const warnings = [];
91
+ for (let i = 0; i < lines.length; i++) {
92
+ const line = lines[i];
93
+ if (line === undefined)
94
+ continue;
95
+ const trimmed = line.trim();
96
+ if (trimmed === '') {
97
+ continue; // Skip blank lines
98
+ }
99
+ try {
100
+ const parsed = JSON.parse(trimmed);
101
+ const result = traceEventInputSchema.safeParse(parsed);
102
+ if (result.success) {
103
+ events.push(result.data);
104
+ }
105
+ else {
106
+ warnings.push({
107
+ index: i,
108
+ message: `Line ${i + 1}: invalid event structure — ${result.error.issues[0]?.message ?? 'unknown error'}`,
109
+ rawInput: trimmed.slice(0, 200),
110
+ });
111
+ }
112
+ }
113
+ catch (e) {
114
+ warnings.push({
115
+ index: i,
116
+ message: `Line ${i + 1}: invalid JSON — ${e instanceof Error ? e.message : 'unknown error'}`,
117
+ rawInput: trimmed.slice(0, 200),
118
+ });
119
+ }
120
+ }
121
+ return { events, warnings };
122
+ }
123
+ // ---------------------------------------------------------------------------
124
+ // Bare array parsing
125
+ // ---------------------------------------------------------------------------
126
+ /**
127
+ * Parse bare array format: `[ [2, "id", "Action", {...}], [3, "id", {...}], ... ]`
128
+ *
129
+ * Each element is a raw OCPP message. Direction is inferred; timestamp is null.
130
+ */
131
+ function parseBareArray(input) {
132
+ const warnings = [];
133
+ try {
134
+ const parsed = JSON.parse(input);
135
+ const result = bareArraySchema.safeParse(parsed);
136
+ if (!result.success) {
137
+ throw new ParseError(`Invalid bare array format — ${result.error.issues[0]?.message ?? 'unknown error'}`);
138
+ }
139
+ // Convert raw messages to TraceEventInput (with null timestamp, no direction)
140
+ const events = result.data.map((message) => ({
141
+ timestamp: null,
142
+ direction: undefined,
143
+ message,
144
+ }));
145
+ return { events, warnings };
146
+ }
147
+ catch (e) {
148
+ if (e instanceof ParseError)
149
+ throw e;
150
+ throw new ParseError(`Invalid JSON in bare array format — ${e instanceof Error ? e.message : 'unknown error'}`);
151
+ }
152
+ }
153
+ // ---------------------------------------------------------------------------
154
+ // JSON Object parsing
155
+ // ---------------------------------------------------------------------------
156
+ /**
157
+ * Parse JSON Object format: `{ "traceId": ..., "metadata": ..., "events": [...] }`
158
+ *
159
+ * Also handles the case where the JSON Object contains an array of raw messages
160
+ * in the `events` field (degenerate — treated as bare messages without timestamp/direction).
161
+ */
162
+ function parseJsonObject(input) {
163
+ let parsed;
164
+ try {
165
+ parsed = JSON.parse(input);
166
+ }
167
+ catch (e) {
168
+ throw new ParseError(`Invalid JSON — ${e instanceof Error ? e.message : 'unknown error'}`);
169
+ }
170
+ // If the parsed value is an array, treat it as a bare array (degenerate JSON Object)
171
+ if (Array.isArray(parsed)) {
172
+ return parseBareArray(input);
173
+ }
174
+ const result = traceSchema.safeParse(parsed);
175
+ if (!result.success) {
176
+ throw new ParseError(`Invalid trace structure — ${result.error.issues[0]?.message ?? 'unknown error'}`);
177
+ }
178
+ const trace = result.data;
179
+ const warnings = [];
180
+ const events = [];
181
+ // Validate each event individually — malformed events are skipped with warnings
182
+ for (let i = 0; i < trace.events.length; i++) {
183
+ const eventInput = trace.events[i];
184
+ if (eventInput === undefined)
185
+ continue;
186
+ // Re-validate the individual message (the schema already validated the
187
+ // overall structure, but we want to catch edge cases in the message array)
188
+ const msgResult = rawOcppMessageSchema.safeParse(eventInput.message);
189
+ if (!msgResult.success) {
190
+ warnings.push({
191
+ index: i,
192
+ message: `Event ${i + 1}: invalid OCPP message — ${msgResult.error.issues[0]?.message ?? 'unknown error'}`,
193
+ });
194
+ continue;
195
+ }
196
+ events.push({
197
+ timestamp: eventInput.timestamp ?? null,
198
+ direction: eventInput.direction,
199
+ message: msgResult.data,
200
+ });
201
+ }
202
+ if (events.length === 0) {
203
+ throw new ParseError('Trace contains no valid events after parsing.');
204
+ }
205
+ return { events, warnings };
206
+ }
207
+ // ---------------------------------------------------------------------------
208
+ // parseTrace()
209
+ // ---------------------------------------------------------------------------
210
+ /**
211
+ * Parse a trace from a raw string input.
212
+ *
213
+ * Accepts:
214
+ * - JSON Object format (metadata + events array)
215
+ * - JSONL format (one event per line)
216
+ * - Bare array format (array of raw OCPP message arrays)
217
+ *
218
+ * @param input - Raw trace string (untrusted)
219
+ * @returns ParseResult with normalized events and warnings for malformed entries
220
+ * @throws {ParseError} for structural errors (invalid JSON, missing events, size/count limits exceeded)
221
+ *
222
+ * @see ADR-0002, ADR-0007
223
+ */
224
+ export function parseTrace(input) {
225
+ // Validate input size
226
+ validateInputSize(input);
227
+ const trimmed = input.trim();
228
+ if (trimmed === '') {
229
+ throw new ParseError('Input is empty.');
230
+ }
231
+ // Detect format and parse accordingly
232
+ const format = detectFormat(trimmed);
233
+ let events;
234
+ let warnings;
235
+ if (format === 'bare-array') {
236
+ const result = parseBareArray(trimmed);
237
+ events = result.events;
238
+ warnings = result.warnings;
239
+ }
240
+ else if (format === 'jsonl') {
241
+ const result = parseJsonl(trimmed);
242
+ events = result.events;
243
+ warnings = result.warnings;
244
+ }
245
+ else {
246
+ // json-object — but it might actually be JSONL if JSON.parse fails
247
+ try {
248
+ const result = parseJsonObject(trimmed);
249
+ events = result.events;
250
+ warnings = result.warnings;
251
+ }
252
+ catch (e) {
253
+ if (e instanceof ParseError) {
254
+ // If JSON Object parsing fails, try JSONL as a fallback
255
+ // (input starts with `{` but might be JSONL with event objects)
256
+ const jsonlResult = parseJsonl(trimmed);
257
+ if (jsonlResult.events.length > 0) {
258
+ events = jsonlResult.events;
259
+ warnings = jsonlResult.warnings;
260
+ }
261
+ else {
262
+ throw e;
263
+ }
264
+ }
265
+ else {
266
+ throw e;
267
+ }
268
+ }
269
+ }
270
+ // Validate event count
271
+ validateEventCount(events);
272
+ if (events.length === 0) {
273
+ throw new ParseError('Trace contains no valid events.');
274
+ }
275
+ // Normalize events into canonical Event objects
276
+ const normalizedEvents = normalizeEvents(events);
277
+ return {
278
+ events: normalizedEvents,
279
+ warnings,
280
+ };
281
+ }
282
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"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"}