@descryy/runtime-evidence-store 0.0.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.
@@ -0,0 +1,511 @@
1
+ /**
2
+ * Evidence store (plan §13; plan §36 gate 9 "evidence persistence").
3
+ * Persistence keyed by executionId, backed by `node:sqlite` — mirrors
4
+ * descry-core's choice (CLAUDE.md: "node:sqlite behind a driver
5
+ * interface") for the same reason: zero native deps, no node-gyp-per-
6
+ * platform distribution problem. A full swappable-driver abstraction
7
+ * (descry-core's `SqlDriver`) is skipped here — one table, no real
8
+ * swap-target in view — but the row-rehydration pattern is kept:
9
+ * `node:sqlite` returns null-prototype row objects, which trips up
10
+ * `JSON.stringify` and structural-equality checks in ways that are easy to
11
+ * miss, so every row is spread into a plain object before use.
12
+ *
13
+ * `node:sqlite` is experimental in this Node version and prints an
14
+ * `ExperimentalWarning`. descry-core's own policy is to suppress that only
15
+ * at a CLI entrypoint, never in library code or tests — this package has
16
+ * no entrypoint of its own, so nothing here suppresses it.
17
+ */
18
+ import { DatabaseSync } from "node:sqlite";
19
+ import { randomUUID } from "node:crypto";
20
+ import { EVIDENCE_SOURCES, REDACTION_STATUSES, RUNTIME_EVENT_TYPES, } from "@descryy/runtime-contracts";
21
+ import { redact } from "./redaction.js";
22
+ import { captureEnvironment, environmentDifferences, } from "./replay.js";
23
+ export class EvidenceStore {
24
+ #db;
25
+ #redactionPolicy;
26
+ #retentionMs;
27
+ constructor(options) {
28
+ this.#redactionPolicy = options.redactionPolicy ?? {};
29
+ this.#retentionMs = options.retentionMs ?? null;
30
+ this.#db = new DatabaseSync(options.path);
31
+ this.#db.exec(`
32
+ CREATE TABLE IF NOT EXISTS evidence (
33
+ evidence_id TEXT PRIMARY KEY,
34
+ execution_id TEXT NOT NULL,
35
+ timestamp TEXT NOT NULL,
36
+ source TEXT NOT NULL,
37
+ service TEXT,
38
+ process TEXT,
39
+ event_type TEXT NOT NULL,
40
+ payload TEXT NOT NULL,
41
+ trace_id TEXT,
42
+ request_id TEXT,
43
+ correlation_id TEXT,
44
+ graph_node_id TEXT,
45
+ source_location TEXT,
46
+ stack_trace TEXT,
47
+ confidence REAL NOT NULL,
48
+ redaction_status TEXT NOT NULL,
49
+ collector_version TEXT NOT NULL
50
+ );
51
+ CREATE INDEX IF NOT EXISTS idx_evidence_execution ON evidence(execution_id);
52
+ -- §24's missing half. Evidence survived a process restart; the
53
+ -- execution that produced it did not -- it lived in
54
+ -- ExecutionController's memory and nowhere on disk, so after a
55
+ -- restart the store held rows keyed by an executionId that no longer
56
+ -- resolved to an application, a commit, or a configuration.
57
+ --
58
+ -- A NEW TABLE, never a new column on the evidence table. An added
59
+ -- table appears under CREATE TABLE IF NOT EXISTS on an existing store
60
+ -- file;
61
+ -- an added column would need a migration this package has no
62
+ -- mechanism for, and inventing one to persist a fingerprint would be
63
+ -- a schema-versioning decision taken sideways.
64
+ CREATE TABLE IF NOT EXISTS executions (
65
+ execution_id TEXT PRIMARY KEY,
66
+ application TEXT NOT NULL,
67
+ repository TEXT NOT NULL,
68
+ commit_sha TEXT NOT NULL,
69
+ recorded_at TEXT NOT NULL,
70
+ configuration TEXT NOT NULL,
71
+ environment TEXT NOT NULL,
72
+ redacted_keys TEXT NOT NULL
73
+ );
74
+ CREATE INDEX IF NOT EXISTS idx_evidence_trace ON evidence(trace_id);
75
+ CREATE INDEX IF NOT EXISTS idx_evidence_request ON evidence(request_id);
76
+ CREATE INDEX IF NOT EXISTS idx_evidence_correlation ON evidence(correlation_id);
77
+ CREATE INDEX IF NOT EXISTS idx_evidence_service ON evidence(service);
78
+ CREATE INDEX IF NOT EXISTS idx_evidence_node ON evidence(graph_node_id);
79
+ CREATE INDEX IF NOT EXISTS idx_evidence_timestamp ON evidence(timestamp);
80
+ -- An expression index, because source_location is stored as JSON
81
+ -- rather than split into columns. Splitting it would be the faster
82
+ -- schema and would also mean migrating every existing store on disk;
83
+ -- the JSON stays authoritative and the index makes the file lookup a
84
+ -- seek instead of a scan.
85
+ CREATE INDEX IF NOT EXISTS idx_evidence_source_file ON evidence(json_extract(source_location, '$.file'));
86
+ `);
87
+ }
88
+ /**
89
+ * The only way to persist evidence. Redaction runs here, unconditionally
90
+ * — `EvidenceInput` has no `redactionStatus` field a caller could set,
91
+ * so there is no way to write a record claiming redaction happened
92
+ * without redact() actually having run. This is the structural
93
+ * guarantee plan §28 asks for: "raw runtime evidence must not
94
+ * automatically become unrestricted AI context."
95
+ */
96
+ write(input) {
97
+ // **Validated at the boundary, not trusted from the type system (§3).**
98
+ // `EvidenceInput` is typed, and inside one compiled program that is
99
+ // enough. It stops being enough the moment a value arrives from anywhere
100
+ // the compiler did not check — a JSON body, a stored row from another
101
+ // version, a hand-written fixture, a collector built against an older
102
+ // contract. §3's own rows are "invalid event rejected" and "unknown event
103
+ // handled explicitly", and a compile-time union answers neither.
104
+ //
105
+ // Throws rather than coerces. A caller writing an event type this build
106
+ // does not know is a bug, and the cheapest moment to say so is before the
107
+ // row exists.
108
+ assertInVocabulary("eventType", input.eventType, RUNTIME_EVENT_TYPES);
109
+ assertInVocabulary("source", input.source, EVIDENCE_SOURCES);
110
+ const { payload, redactionStatus } = redact(input.payload, this.#redactionPolicy);
111
+ const evidence = { ...input, evidenceId: randomUUID(), payload, redactionStatus };
112
+ this.#db
113
+ .prepare(`INSERT INTO evidence (
114
+ evidence_id, execution_id, timestamp, source, service, process, event_type,
115
+ payload, trace_id, request_id, correlation_id, graph_node_id,
116
+ source_location, stack_trace, confidence, redaction_status, collector_version
117
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
118
+ .run(evidence.evidenceId, evidence.executionId, evidence.timestamp, evidence.source, evidence.service, evidence.process, evidence.eventType, JSON.stringify(evidence.payload), evidence.traceId, evidence.requestId, evidence.correlationId, evidence.graphNodeId, evidence.sourceLocation ? JSON.stringify(evidence.sourceLocation) : null, evidence.stackTrace ? JSON.stringify(evidence.stackTrace) : null, evidence.confidence, evidence.redactionStatus, evidence.collectorVersion);
119
+ return evidence;
120
+ }
121
+ /** Every item this execution produced, oldest first — retrievable after the execution has ended, as long as the store is reopened against the same file (plan §36 gate 9). */
122
+ getByExecution(executionId) {
123
+ const rows = this.#db
124
+ .prepare(`SELECT * FROM evidence WHERE execution_id = ? ORDER BY timestamp ASC`)
125
+ .all(executionId);
126
+ return rows.map(rowToEvidence);
127
+ }
128
+ getById(evidenceId) {
129
+ const row = this.#db.prepare(`SELECT * FROM evidence WHERE evidence_id = ?`).get(evidenceId);
130
+ return row ? rowToEvidence(row) : null;
131
+ }
132
+ /**
133
+ * Every row whose enum fields this build cannot interpret (§3).
134
+ *
135
+ * The explicit runtime path for an unknown event. Reads the raw columns
136
+ * without rehydrating, so it works on precisely the store that `query()`
137
+ * refuses — a caller that hits the refusal can call this to learn which
138
+ * rows, which fields and which values, instead of having a throw and no
139
+ * next step.
140
+ *
141
+ * Deliberately reports rather than repairs. Rewriting an unknown
142
+ * `event_type` to something this build knows would be inventing an
143
+ * observation, and deleting the row would destroy evidence that a newer
144
+ * build can read perfectly well.
145
+ */
146
+ integrityCheck() {
147
+ const rows = this.#db
148
+ .prepare(`SELECT evidence_id, source, event_type, redaction_status FROM evidence`)
149
+ .all();
150
+ const issues = [];
151
+ for (const raw of rows) {
152
+ const row = { ...raw };
153
+ for (const [field, value, vocabulary] of [
154
+ ["eventType", row.event_type, RUNTIME_EVENT_TYPES],
155
+ ["source", row.source, EVIDENCE_SOURCES],
156
+ ["redactionStatus", row.redaction_status, REDACTION_STATUSES],
157
+ ]) {
158
+ if (!vocabulary.includes(value)) {
159
+ issues.push({ evidenceId: row.evidence_id, field, value });
160
+ }
161
+ }
162
+ }
163
+ return issues;
164
+ }
165
+ /**
166
+ * Persist the execution behind an `executionId` (§24).
167
+ *
168
+ * **The configuration is redacted on the way in, and that is not an
169
+ * over-application of §20.** Every one of §20's rows is about an evidence
170
+ * payload, but `configuration.services[x].command` is a command line, and
171
+ * a command line is one of the classic places a credential travels:
172
+ * `node server.mjs --api-key=…`. The same `redact()` the evidence write
173
+ * path uses runs here, on the same terms, and `redactedKeys` reports what
174
+ * it caught rather than leaving a caller to guess.
175
+ *
176
+ * Re-recording the same `executionId` replaces the row. An execution is
177
+ * recorded once by the component that owns it; a second record for the
178
+ * same id is a re-run of that recording, not a second execution.
179
+ */
180
+ recordExecution(input) {
181
+ const { payload: configuration, redactedKeys } = redact(input.configuration, this.#redactionPolicy);
182
+ const environment = input.environment ?? captureEnvironment(serviceCommandsOf(configuration));
183
+ const recordedAt = input.recordedAt ?? new Date().toISOString();
184
+ this.#db
185
+ .prepare(`INSERT INTO executions (
186
+ execution_id, application, repository, commit_sha, recorded_at,
187
+ configuration, environment, redacted_keys
188
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
189
+ ON CONFLICT(execution_id) DO UPDATE SET
190
+ application = excluded.application,
191
+ repository = excluded.repository,
192
+ commit_sha = excluded.commit_sha,
193
+ recorded_at = excluded.recorded_at,
194
+ configuration = excluded.configuration,
195
+ environment = excluded.environment,
196
+ redacted_keys = excluded.redacted_keys`)
197
+ .run(input.executionId, input.application, input.repository, input.commit, recordedAt, JSON.stringify(configuration), JSON.stringify(environment), JSON.stringify(redactedKeys));
198
+ return {
199
+ executionId: input.executionId,
200
+ application: input.application,
201
+ repository: input.repository,
202
+ commit: input.commit,
203
+ recordedAt,
204
+ configuration,
205
+ environment,
206
+ redactedKeys,
207
+ };
208
+ }
209
+ getExecution(executionId) {
210
+ const row = this.#db.prepare(`SELECT * FROM executions WHERE execution_id = ?`).get(executionId);
211
+ if (row === undefined)
212
+ return null;
213
+ return {
214
+ executionId: String(row["execution_id"]),
215
+ application: String(row["application"]),
216
+ repository: String(row["repository"]),
217
+ commit: String(row["commit_sha"]),
218
+ recordedAt: String(row["recorded_at"]),
219
+ configuration: JSON.parse(String(row["configuration"])),
220
+ environment: JSON.parse(String(row["environment"])),
221
+ redactedKeys: JSON.parse(String(row["redacted_keys"])),
222
+ };
223
+ }
224
+ /**
225
+ * Replay an execution's evidence (§24).
226
+ *
227
+ * **Replays evidence, not the application.** Nothing is spawned, driven or
228
+ * reissued; this returns what was recorded, in recorded order, so
229
+ * correlation, findings and an evidence package can be re-derived without
230
+ * booting anything. A replay that quietly re-executed would produce a *new*
231
+ * observation while claiming to reproduce an old one.
232
+ *
233
+ * Throws for an unrecorded execution rather than returning an empty
234
+ * replay. Evidence rows can exist for an `executionId` that was never
235
+ * recorded — that is precisely the pre-§24 state — and answering with
236
+ * "here is your replay, minus the execution" would present the gap as a
237
+ * result.
238
+ */
239
+ replay(executionId, currentEnvironment) {
240
+ const execution = this.getExecution(executionId);
241
+ if (execution === null) {
242
+ throw new Error(`replay: no execution recorded for ${JSON.stringify(executionId)}. Evidence may still exist for ` +
243
+ "it — this store held evidence for unrecorded executions before recordExecution existed — but " +
244
+ "a replay without the configuration and environment it ran under is not a replay.");
245
+ }
246
+ const evidence = this.getByExecution(executionId);
247
+ const current = currentEnvironment ?? captureEnvironment(serviceCommandsOf(execution.configuration));
248
+ const warnings = [];
249
+ const differences = environmentDifferences(execution.environment, current);
250
+ if (differences.length > 0) {
251
+ warnings.push({
252
+ kind: "environment-changed",
253
+ detail: `The environment differs from the one this execution was recorded in: ${differences.join("; ")}. ` +
254
+ "Reported, not enforced — whether it matters is a judgement this store has no information to make.",
255
+ });
256
+ }
257
+ if (evidence.length === 0) {
258
+ warnings.push({
259
+ kind: "no-evidence",
260
+ detail: "The execution is recorded but produced no stored evidence. That is a real state (a run that " +
261
+ "observed nothing) and is not the same as an unrecorded execution, which throws.",
262
+ });
263
+ }
264
+ // getByExecution orders by timestamp, so this cannot detect a bad sort —
265
+ // it detects a recorded stream whose own timestamps were never
266
+ // monotonic, which means "recorded order" and "the order things
267
+ // happened" are not the same list and a reader replaying by index is
268
+ // reading a sequence that never occurred.
269
+ for (let i = 1; i < evidence.length; i += 1) {
270
+ if (evidence[i - 1].timestamp === evidence[i].timestamp)
271
+ continue;
272
+ if (evidence[i - 1].timestamp < evidence[i].timestamp)
273
+ continue;
274
+ warnings.push({
275
+ kind: "unordered-timestamps",
276
+ detail: "At least one pair of evidence items is out of timestamp order after sorting, which means the " +
277
+ "recorded timestamps are not a total order. Replay order is by timestamp, so the sequence " +
278
+ "returned here is not necessarily the sequence that occurred.",
279
+ });
280
+ break;
281
+ }
282
+ return { execution, evidence, currentEnvironment: current, warnings };
283
+ }
284
+ /**
285
+ * Record that correlation resolved this evidence to a graph node.
286
+ *
287
+ * **Written because the correlation was never durable, and that made two
288
+ * of the evidence package's four selection tiers inert.** Found by
289
+ * mutation, not by reading: `assembleEvidencePackage`'s tier 2 queries
290
+ * `graphNodeId`, and a mutation that dropped the execution scope from that
291
+ * query changed nothing at all — because in the real pipeline no stored row
292
+ * has a `graphNodeId` to match. `graphNodeId` was set in memory at
293
+ * composition time, on a copy, and thrown away with the array that held it.
294
+ * Every downstream question of the form "what else named this node" was
295
+ * therefore answerable only for evidence some caller happened to still be
296
+ * holding.
297
+ *
298
+ * **Refuses to re-attribute to a different node.** One observation
299
+ * genuinely can name two graph entities (RT-052's backend exception names
300
+ * the endpoint in its text and the function in its stack), and the answer
301
+ * to that is `EvidenceAttribution` passed alongside the evidence — an
302
+ * output of correlation, not a property of the observation. Letting this
303
+ * method overwrite would silently discard the first correlation and leave
304
+ * the store asserting the second as if it were the only one. Idempotent
305
+ * for the same node, so re-running a correlation pass is safe.
306
+ *
307
+ * Throws for an unknown `evidenceId`: a caller attributing evidence this
308
+ * store does not hold has a bug, and writing nothing would hide it.
309
+ */
310
+ attribute(evidenceId, graphNodeId) {
311
+ const existing = this.getById(evidenceId);
312
+ if (existing === null) {
313
+ throw new Error(`attribute: no evidence with id ${JSON.stringify(evidenceId)} in this store`);
314
+ }
315
+ if (existing.graphNodeId !== null && existing.graphNodeId !== graphNodeId) {
316
+ throw new Error(`attribute: evidence ${evidenceId} is already attributed to ${existing.graphNodeId}; refusing to ` +
317
+ `overwrite with ${graphNodeId}. One observation naming two nodes is expressed as an ` +
318
+ "EvidenceAttribution alongside the evidence, not by rewriting the stored one.");
319
+ }
320
+ if (existing.graphNodeId === graphNodeId)
321
+ return;
322
+ this.#db.prepare(`UPDATE evidence SET graph_node_id = ? WHERE evidence_id = ?`).run(graphNodeId, evidenceId);
323
+ }
324
+ /**
325
+ * The general query surface (§19).
326
+ *
327
+ * Before this, the store answered two questions — by id and by execution —
328
+ * and §19 asks for six axes: trace, service, graph node, source location,
329
+ * time, and execution. **Five of the six did not exist**, which is
330
+ * invisible from "evidence persistence works" and was found by auditing
331
+ * the checklist rather than by anything failing.
332
+ *
333
+ * **`executionId` is required and may be explicitly `null`, and that is
334
+ * the load-bearing design choice here.** Every other field is optional.
335
+ * Evidence not leaking between executions is a guarantee this repo
336
+ * enforces elsewhere (`composeFinding` excludes foreign executions with a
337
+ * named reason), and a query is the obvious way to lose it: ask for a
338
+ * trace id and quietly receive a prior run's evidence too. Making the
339
+ * field optional-with-a-default would mean the safe behaviour depends on
340
+ * remembering to pass something, which is how the default gets forgotten
341
+ * exactly once. Passing `null` is a deliberate statement that a
342
+ * cross-execution answer is wanted — the same discipline
343
+ * `resolveSymbolNode` applies to `repo`, where there is no honest default
344
+ * either.
345
+ *
346
+ * Criteria combine with AND. An empty criteria object plus a null
347
+ * execution returns everything, which is a real request (a store dump)
348
+ * and is spelled out rather than reachable by accident.
349
+ */
350
+ query(criteria) {
351
+ const clauses = [];
352
+ const params = [];
353
+ if (criteria.executionId !== null) {
354
+ clauses.push("execution_id = ?");
355
+ params.push(criteria.executionId);
356
+ }
357
+ // Each of these is an exact match, never a LIKE. A prefix or substring
358
+ // match on a trace id or a service name would return evidence about a
359
+ // *different* thing that happens to share a prefix -- RT-031's
360
+ // identity-proxy class, and the last place it belongs is the query
361
+ // layer that everything above reads through.
362
+ for (const [column, value] of [
363
+ ["trace_id", criteria.traceId],
364
+ ["request_id", criteria.requestId],
365
+ ["correlation_id", criteria.correlationId],
366
+ ["service", criteria.service],
367
+ ["source", criteria.source],
368
+ ["event_type", criteria.eventType],
369
+ ["graph_node_id", criteria.graphNodeId],
370
+ ]) {
371
+ if (value === undefined)
372
+ continue;
373
+ clauses.push(`${column} = ?`);
374
+ params.push(value);
375
+ }
376
+ if (criteria.sourceFile !== undefined) {
377
+ clauses.push("json_extract(source_location, '$.file') = ?");
378
+ params.push(criteria.sourceFile);
379
+ }
380
+ if (criteria.sourceLine !== undefined) {
381
+ clauses.push("json_extract(source_location, '$.line') = ?");
382
+ params.push(criteria.sourceLine);
383
+ }
384
+ // ISO-8601 UTC strings sort lexicographically in the same order they
385
+ // sort chronologically, which is why `timestamp` is comparable as TEXT.
386
+ // Inclusive at both ends: a caller asking for a window around a known
387
+ // event should get that event.
388
+ if (criteria.from !== undefined) {
389
+ clauses.push("timestamp >= ?");
390
+ params.push(criteria.from);
391
+ }
392
+ if (criteria.to !== undefined) {
393
+ clauses.push("timestamp <= ?");
394
+ params.push(criteria.to);
395
+ }
396
+ const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
397
+ const limit = criteria.limit !== undefined ? "LIMIT ?" : "";
398
+ if (criteria.limit !== undefined)
399
+ params.push(criteria.limit);
400
+ const rows = this.#db
401
+ .prepare(`SELECT * FROM evidence ${where} ORDER BY timestamp ASC ${limit}`)
402
+ .all(...params);
403
+ return rows.map(rowToEvidence);
404
+ }
405
+ /**
406
+ * Deletes every row whose own `timestamp` is older than `retentionMs`
407
+ * (constructor option) relative to `now` (defaults to the real current
408
+ * time; overridable so a test can purge without a real sleep). Never
409
+ * called automatically -- no timer, no call from `write()` -- a caller
410
+ * decides when retention actually runs. Throws rather than silently
411
+ * no-op-ing if `retentionMs` was never configured: a caller explicitly
412
+ * asking to purge with no policy in place is a configuration mistake
413
+ * worth surfacing, not masking.
414
+ */
415
+ purgeExpired(now = new Date()) {
416
+ if (this.#retentionMs === null) {
417
+ throw new Error("purgeExpired() called but no retentionMs was configured on this EvidenceStore.");
418
+ }
419
+ const cutoff = new Date(now.getTime() - this.#retentionMs).toISOString();
420
+ const result = this.#db.prepare(`DELETE FROM evidence WHERE timestamp < ?`).run(cutoff);
421
+ return Number(result.changes);
422
+ }
423
+ close() {
424
+ this.#db.close();
425
+ }
426
+ }
427
+ /**
428
+ * Throws when a value is outside the vocabulary this build knows.
429
+ *
430
+ * The message names the value **and** the vocabulary, because the two useful
431
+ * conclusions are opposite: an unknown value is either a typo (fix the caller)
432
+ * or a newer contract (this build is the old one), and only seeing both lists
433
+ * distinguishes them.
434
+ */
435
+ function assertInVocabulary(field, value, vocabulary) {
436
+ if (vocabulary.includes(value))
437
+ return;
438
+ throw new Error(`EvidenceStore: ${field} ${JSON.stringify(value)} is not one of ${JSON.stringify(vocabulary)}. ` +
439
+ "Either the caller is wrong, or this store is being written by a build with a newer contract " +
440
+ "than the one reading it — the two need opposite fixes, so neither is assumed.");
441
+ }
442
+ /**
443
+ * Rehydrate a row, refusing one this build cannot interpret.
444
+ *
445
+ * **The previous version blind-cast every enum field** — `row.event_type as
446
+ * Evidence["eventType"]` — which is a `as` that cannot fail and a value that
447
+ * can. A store file written by a build with an extra `RuntimeEventType`, a
448
+ * restored backup, or a hand-edited row produced a fully-typed `Evidence`
449
+ * whose `eventType` no `switch` in this program handles, and nothing anywhere
450
+ * said so. §3's "unknown event handled explicitly" row was open for exactly
451
+ * this, and the handling could not be added upstream because there was no
452
+ * point at which the unknown was ever recognised as unknown.
453
+ *
454
+ * **It throws rather than skipping.** Skipping would return fewer rows while
455
+ * every caller treated the result as complete — the "unsupported silently
456
+ * becomes no failure" shape, applied to a query result, which is the worst
457
+ * place for it: `composeFinding` would compose over a subset and report
458
+ * confidently. `integrityCheck()` exists so a caller facing this can find out
459
+ * how bad it is without the throw being a dead end.
460
+ */
461
+ function rowToEvidence(raw) {
462
+ const row = { ...raw };
463
+ assertInVocabulary("eventType", row.event_type, RUNTIME_EVENT_TYPES);
464
+ assertInVocabulary("source", row.source, EVIDENCE_SOURCES);
465
+ assertInVocabulary("redactionStatus", row.redaction_status, REDACTION_STATUSES);
466
+ return {
467
+ evidenceId: row.evidence_id,
468
+ executionId: row.execution_id,
469
+ timestamp: row.timestamp,
470
+ source: row.source,
471
+ service: row.service,
472
+ process: row.process,
473
+ eventType: row.event_type,
474
+ payload: JSON.parse(row.payload),
475
+ traceId: row.trace_id,
476
+ requestId: row.request_id,
477
+ correlationId: row.correlation_id,
478
+ graphNodeId: row.graph_node_id,
479
+ sourceLocation: row.source_location
480
+ ? JSON.parse(row.source_location)
481
+ : null,
482
+ stackTrace: row.stack_trace ? JSON.parse(row.stack_trace) : null,
483
+ confidence: row.confidence,
484
+ redactionStatus: row.redaction_status,
485
+ collectorVersion: row.collector_version,
486
+ };
487
+ }
488
+ /**
489
+ * `serviceName -> command` out of an `ExecutionConfiguration`-shaped object.
490
+ *
491
+ * Written defensively against `unknown` rather than typed against
492
+ * `ExecutionConfiguration`, because the configuration reaching this store has
493
+ * already been through `redact()` and is no longer that type: a redacted
494
+ * command is the string `[REDACTED]`, which is still a string, but a redacted
495
+ * *services* object could in principle be a marker too. Reading it
496
+ * structurally means a surprising shape yields an empty map rather than a
497
+ * throw inside a persistence call.
498
+ */
499
+ function serviceCommandsOf(configuration) {
500
+ const services = configuration?.services;
501
+ if (services === null || typeof services !== "object")
502
+ return {};
503
+ const commands = {};
504
+ for (const [name, service] of Object.entries(services)) {
505
+ const command = service?.command;
506
+ if (typeof command === "string")
507
+ commands[name] = command;
508
+ }
509
+ return commands;
510
+ }
511
+ //# sourceMappingURL=evidence-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence-store.js","sourceRoot":"","sources":["../src/evidence-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type { RedactionResult, RedactionPolicy } from "./redaction.ts";
2
+ export { redact, collidingKeys, redactCommand } from "./redaction.ts";
3
+ export type { EvidenceStoreOptions, EvidenceInput, EvidenceQuery } from "./evidence-store.ts";
4
+ export { EvidenceStore } from "./evidence-store.ts";
5
+ export { captureEnvironment, environmentDifferences, type EnvironmentFingerprint, type RecordedExecution, type Replay, type ReplayWarning, } from "./replay.ts";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEtE,YAAY,EAAE,oBAAoB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,MAAM,EACX,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { redact, collidingKeys, redactCommand } from "./redaction.js";
2
+ export { EvidenceStore } from "./evidence-store.js";
3
+ export { captureEnvironment, environmentDifferences, } from "./replay.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGtE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EACL,kBAAkB,EAClB,sBAAsB,GAKvB,MAAM,aAAa,CAAC"}