@descryy/runtime-remote-log-ingestion 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,67 @@
1
+ /**
2
+ * Correlation between a captured browser/proxy request and an ingested
3
+ * remote log line (DEC-271's remote side). Follows the same pattern
4
+ * `backend-observation/correlator.ts`'s `correlateBackendEvidence` already
5
+ * establishes -- prefer a real shared identifier, never fall back to timing
6
+ * on its own -- rather than inventing a second correlation shape.
7
+ *
8
+ * Reuses `@descryy/runtime-contracts`' `Correlation`/`createCorrelation`
9
+ * directly: `method` is drawn from the same closed `CorrelationMethod`
10
+ * union everywhere else in this repo uses, so `isConfirmed` is derived the
11
+ * same way (`isStructuralCorrelation` -- true for `trace-id`/`request-id`,
12
+ * false for `timing-context-fallback`) and a reader who already knows that
13
+ * contract does not have to learn a second one for the remote case.
14
+ */
15
+ import type { Correlation } from "@descryy/runtime-contracts";
16
+ import type { IngestedLogLine } from "./log-line.ts";
17
+ /**
18
+ * A captured browser/proxy request, reduced to the fields correlation
19
+ * needs. `timestamp` and `path` are always available -- every captured
20
+ * request has both; `traceId`/`requestId` are populated only when the
21
+ * capturing side actually found them (real headers, W3C `traceparent` --
22
+ * see `external-service-observation/header-correlation.ts`), null
23
+ * otherwise. `id` is caller-assigned (an `Evidence.evidenceId`, typically)
24
+ * -- this module never generates one, mirroring
25
+ * `correlateBackendEvidence`'s use of pre-existing `evidenceId`s rather
26
+ * than minting its own.
27
+ */
28
+ export interface CapturedRequestRef {
29
+ readonly id: string;
30
+ readonly executionId: string;
31
+ readonly timestamp: string;
32
+ readonly path: string;
33
+ readonly traceId: string | null;
34
+ readonly requestId: string | null;
35
+ }
36
+ export interface CorrelateOptions {
37
+ /**
38
+ * Widest gap between the request's and the line's timestamp still
39
+ * considered for a timestamp+path match, in milliseconds. Default 5000 --
40
+ * generous enough for real network and log-flush latency between a
41
+ * request landing and its log line appearing, narrow enough not to pair
42
+ * unrelated activity in a busy log.
43
+ */
44
+ readonly windowMs?: number;
45
+ }
46
+ /**
47
+ * Best-effort correlation between one captured request and one ingested log
48
+ * line, in DEC-271's stated preference order:
49
+ *
50
+ * 1. a shared trace id (`method: "trace-id"`, confidence 1) -- the same
51
+ * rule and confidence `correlateBackendEvidence` uses for the local case.
52
+ * 2. a shared request id (`method: "request-id"`, confidence 1).
53
+ * 3. the request's timestamp within `windowMs` of the line's **and** the
54
+ * request's `path` appearing in the line's (already-redacted) text --
55
+ * `method: "timing-context-fallback"`, confidence
56
+ * `TIMESTAMP_PATH_CONFIDENCE`, `isConfirmed: false`. Both signals are
57
+ * required together; timestamp proximity alone is not treated as
58
+ * evidence of anything, per DEC-271's warning against inferring from
59
+ * timing on its own.
60
+ *
61
+ * Returns `null` -- DEC-271's "not observable here" for this one
62
+ * request/line pair -- when none of the above hold: no shared identifier,
63
+ * and either the line carries no parseable timestamp or the path/window
64
+ * test fails. Never fabricates a match to fill the gap.
65
+ */
66
+ export declare function correlateLogLine(request: CapturedRequestRef, line: IngestedLogLine, options?: CorrelateOptions): Correlation | null;
67
+ //# sourceMappingURL=correlator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlator.d.ts","sourceRoot":"","sources":["../src/correlator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAG9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAmBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,GAAE,gBAAqB,GAAG,WAAW,GAAG,IAAI,CAqCvI"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Correlation between a captured browser/proxy request and an ingested
3
+ * remote log line (DEC-271's remote side). Follows the same pattern
4
+ * `backend-observation/correlator.ts`'s `correlateBackendEvidence` already
5
+ * establishes -- prefer a real shared identifier, never fall back to timing
6
+ * on its own -- rather than inventing a second correlation shape.
7
+ *
8
+ * Reuses `@descryy/runtime-contracts`' `Correlation`/`createCorrelation`
9
+ * directly: `method` is drawn from the same closed `CorrelationMethod`
10
+ * union everywhere else in this repo uses, so `isConfirmed` is derived the
11
+ * same way (`isStructuralCorrelation` -- true for `trace-id`/`request-id`,
12
+ * false for `timing-context-fallback`) and a reader who already knows that
13
+ * contract does not have to learn a second one for the remote case.
14
+ */
15
+ import { randomUUID } from "node:crypto";
16
+ import { createCorrelation } from "@descryy/runtime-contracts";
17
+ const DEFAULT_WINDOW_MS = 5000;
18
+ /**
19
+ * Confidence assigned to every `"timing-context-fallback"` match. Fixed
20
+ * rather than scaled by how close the two timestamps are -- DEC-271 asks
21
+ * for an honestly-stated tier, not a manufactured precision this signal
22
+ * doesn't actually have: there is no identifier behind it, only two
23
+ * independent weak cues (a clock and a substring search), so one
24
+ * deliberately-below-"confirmed" number stands for the whole tier rather
25
+ * than implying a false gradation within it. The structural distinction
26
+ * from a confirmed match (`isConfirmed: false`, via `isStructuralCorrelation`)
27
+ * is what actually matters; this number exists only so two
28
+ * `Correlation`s are never rendered as equally certain by a reader who
29
+ * looks at `confidence` alone.
30
+ */
31
+ const TIMESTAMP_PATH_CONFIDENCE = 0.4;
32
+ /**
33
+ * Best-effort correlation between one captured request and one ingested log
34
+ * line, in DEC-271's stated preference order:
35
+ *
36
+ * 1. a shared trace id (`method: "trace-id"`, confidence 1) -- the same
37
+ * rule and confidence `correlateBackendEvidence` uses for the local case.
38
+ * 2. a shared request id (`method: "request-id"`, confidence 1).
39
+ * 3. the request's timestamp within `windowMs` of the line's **and** the
40
+ * request's `path` appearing in the line's (already-redacted) text --
41
+ * `method: "timing-context-fallback"`, confidence
42
+ * `TIMESTAMP_PATH_CONFIDENCE`, `isConfirmed: false`. Both signals are
43
+ * required together; timestamp proximity alone is not treated as
44
+ * evidence of anything, per DEC-271's warning against inferring from
45
+ * timing on its own.
46
+ *
47
+ * Returns `null` -- DEC-271's "not observable here" for this one
48
+ * request/line pair -- when none of the above hold: no shared identifier,
49
+ * and either the line carries no parseable timestamp or the path/window
50
+ * test fails. Never fabricates a match to fill the gap.
51
+ */
52
+ export function correlateLogLine(request, line, options = {}) {
53
+ if (request.traceId !== null && request.traceId === line.traceId) {
54
+ return createCorrelation({
55
+ correlationId: randomUUID(),
56
+ executionId: request.executionId,
57
+ method: "trace-id",
58
+ confidence: 1,
59
+ evidenceIds: [request.id, line.lineId],
60
+ });
61
+ }
62
+ if (request.requestId !== null && request.requestId === line.requestId) {
63
+ return createCorrelation({
64
+ correlationId: randomUUID(),
65
+ executionId: request.executionId,
66
+ method: "request-id",
67
+ confidence: 1,
68
+ evidenceIds: [request.id, line.lineId],
69
+ });
70
+ }
71
+ // No clock on this line to window against -- not a weaker match, no
72
+ // match at all. Claiming one would be a guess this module refuses.
73
+ if (line.timestamp === null)
74
+ return null;
75
+ const windowMs = options.windowMs ?? DEFAULT_WINDOW_MS;
76
+ const deltaMs = Math.abs(new Date(request.timestamp).getTime() - new Date(line.timestamp).getTime());
77
+ if (deltaMs > windowMs)
78
+ return null;
79
+ if (!line.raw.includes(request.path))
80
+ return null;
81
+ return createCorrelation({
82
+ correlationId: randomUUID(),
83
+ executionId: request.executionId,
84
+ method: "timing-context-fallback",
85
+ confidence: TIMESTAMP_PATH_CONFIDENCE,
86
+ evidenceIds: [request.id, line.lineId],
87
+ });
88
+ }
89
+ //# sourceMappingURL=correlator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlator.js","sourceRoot":"","sources":["../src/correlator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAmC/D,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAE/B;;;;;;;;;;;;GAYG;AACH,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAEtC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAA2B,EAAE,IAAqB,EAAE,UAA4B,EAAE;IACjH,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;QACjE,OAAO,iBAAiB,CAAC;YACvB,aAAa,EAAE,UAAU,EAAE;YAC3B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,MAAM,EAAE,UAAU;YAClB,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC;SACvC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,KAAK,IAAI,IAAI,OAAO,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;QACvE,OAAO,iBAAiB,CAAC;YACvB,aAAa,EAAE,UAAU,EAAE;YAC3B,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,MAAM,EAAE,YAAY;YACpB,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC;SACvC,CAAC,CAAC;IACL,CAAC;IAED,oEAAoE;IACpE,mEAAmE;IACnE,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEzC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;IACvD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACrG,IAAI,OAAO,GAAG,QAAQ;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAElD,OAAO,iBAAiB,CAAC;QACvB,aAAa,EAAE,UAAU,EAAE;QAC3B,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,MAAM,EAAE,yBAAyB;QACjC,UAAU,EAAE,yBAAyB;QACrC,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC;KACvC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Concrete adapter #1 for DEC-271's remote side: a log **file** the user
3
+ * points us at.
4
+ *
5
+ * **Chosen over a command-stdout adapter** (`RemoteLogLocation`'s other
6
+ * named-and-typed option) because it is the simpler case to build correctly
7
+ * and verify in this pass: deterministic content on disk, no child-process
8
+ * lifecycle, no question of how a running command's stdout encoding or
9
+ * buffering interacts with line splitting. A command adapter is the natural
10
+ * next one -- it would reuse `buildIngestedLogLine` unchanged and differ
11
+ * only in where the lines come from -- not built this pass.
12
+ *
13
+ * **One-shot, not a continuous tail.** This reads the file's contents as of
14
+ * the call; it does not follow appended writes. Stated rather than silently
15
+ * partial, per this repo's "honest degradation" rule: a caller that needs
16
+ * live tailing does not get it from this function today.
17
+ */
18
+ import type { RedactionPolicy } from "@descryy/runtime-evidence-store";
19
+ import { type IngestedLogLine } from "./log-line.ts";
20
+ import type { RemoteLogSourceConfig } from "./log-source-config.ts";
21
+ export interface FileLogSourceConfig extends RemoteLogSourceConfig {
22
+ readonly location: {
23
+ readonly kind: "file";
24
+ readonly path: string;
25
+ };
26
+ }
27
+ export interface FileLogAdapterOptions {
28
+ readonly config: FileLogSourceConfig;
29
+ readonly redactionPolicy?: RedactionPolicy;
30
+ }
31
+ /**
32
+ * Reads `config.location.path` and returns one `IngestedLogLine` per
33
+ * non-empty line, in file order. Every line has already been through
34
+ * `redact()` by the time it is returned -- see `log-line.ts`.
35
+ *
36
+ * A file that cannot be read (missing, permission denied) throws with the
37
+ * path and the underlying error in the message -- "not observable here" for
38
+ * this source, surfaced as a rejection a caller must handle, not a silent
39
+ * empty result indistinguishable from an empty log.
40
+ */
41
+ export declare function ingestFileLog(options: FileLogAdapterOptions): Promise<readonly IngestedLogLine[]>;
42
+ //# sourceMappingURL=file-log-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-log-adapter.d.ts","sourceRoot":"","sources":["../src/file-log-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEvE,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAChE,QAAQ,CAAC,QAAQ,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACrE;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC;CAC5C;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC,CAcvG"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Concrete adapter #1 for DEC-271's remote side: a log **file** the user
3
+ * points us at.
4
+ *
5
+ * **Chosen over a command-stdout adapter** (`RemoteLogLocation`'s other
6
+ * named-and-typed option) because it is the simpler case to build correctly
7
+ * and verify in this pass: deterministic content on disk, no child-process
8
+ * lifecycle, no question of how a running command's stdout encoding or
9
+ * buffering interacts with line splitting. A command adapter is the natural
10
+ * next one -- it would reuse `buildIngestedLogLine` unchanged and differ
11
+ * only in where the lines come from -- not built this pass.
12
+ *
13
+ * **One-shot, not a continuous tail.** This reads the file's contents as of
14
+ * the call; it does not follow appended writes. Stated rather than silently
15
+ * partial, per this repo's "honest degradation" rule: a caller that needs
16
+ * live tailing does not get it from this function today.
17
+ */
18
+ import { readFile } from "node:fs/promises";
19
+ import { buildIngestedLogLine } from "./log-line.js";
20
+ /**
21
+ * Reads `config.location.path` and returns one `IngestedLogLine` per
22
+ * non-empty line, in file order. Every line has already been through
23
+ * `redact()` by the time it is returned -- see `log-line.ts`.
24
+ *
25
+ * A file that cannot be read (missing, permission denied) throws with the
26
+ * path and the underlying error in the message -- "not observable here" for
27
+ * this source, surfaced as a rejection a caller must handle, not a silent
28
+ * empty result indistinguishable from an empty log.
29
+ */
30
+ export async function ingestFileLog(options) {
31
+ const { config, redactionPolicy } = options;
32
+ let content;
33
+ try {
34
+ content = await readFile(config.location.path, "utf8");
35
+ }
36
+ catch (error) {
37
+ const detail = error instanceof Error ? error.message : String(error);
38
+ throw new Error(`remote-log-ingestion: could not read log file "${config.location.path}": ${detail}`);
39
+ }
40
+ return content
41
+ .split(/\r?\n/)
42
+ .filter((line) => line.length > 0)
43
+ .map((line) => buildIngestedLogLine(line, config, redactionPolicy));
44
+ }
45
+ //# sourceMappingURL=file-log-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-log-adapter.js","sourceRoot":"","sources":["../src/file-log-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EAAE,oBAAoB,EAAwB,MAAM,eAAe,CAAC;AAY3E;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAA8B;IAChE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;IAC5C,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,kDAAkD,MAAM,CAAC,QAAQ,CAAC,IAAI,MAAM,MAAM,EAAE,CAAC,CAAC;IACxG,CAAC;IAED,OAAO,OAAO;SACX,KAAK,CAAC,OAAO,CAAC;SACd,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;SACjC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;AACxE,CAAC"}
@@ -0,0 +1,9 @@
1
+ export type { RemoteLogLocation, RemoteLogFormat, RemoteLogSourceConfig } from "./log-source-config.ts";
2
+ export { REMOTE_LOG_FORMATS } from "./log-source-config.ts";
3
+ export type { IngestedLogLine } from "./log-line.ts";
4
+ export { buildIngestedLogLine } from "./log-line.ts";
5
+ export type { FileLogSourceConfig, FileLogAdapterOptions } from "./file-log-adapter.ts";
6
+ export { ingestFileLog } from "./file-log-adapter.ts";
7
+ export type { CapturedRequestRef, CorrelateOptions } from "./correlator.ts";
8
+ export { correlateLogLine } from "./correlator.ts";
9
+ //# 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,iBAAiB,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACxG,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,YAAY,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { REMOTE_LOG_FORMATS } from "./log-source-config.js";
2
+ export { buildIngestedLogLine } from "./log-line.js";
3
+ export { ingestFileLog } from "./file-log-adapter.js";
4
+ export { correlateLogLine } from "./correlator.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAG5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAGrD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * One ingested log line, redacted before it is ever handed back to a
3
+ * caller (DEC-271: "log content is redacted before it reaches the model,
4
+ * not just before display -- the exposure is the read, not the render").
5
+ *
6
+ * Reuses `@descryy/runtime-evidence-store`'s `redact()` rather than
7
+ * reimplementing key-name/body/PII/command scanning -- the same reuse
8
+ * discipline `database-observation`'s and `browser`'s collectors already
9
+ * follow for evidence payloads. `redact()`'s own body-bearing-key
10
+ * convention (`raw`, documented there as the `LogCollector`'s payload key
11
+ * for captured text) is reused verbatim: every line is wrapped as
12
+ * `{ raw: line }` before redaction, so a JSON-shaped line gets `redact()`'s
13
+ * full key-name + text-scan treatment (parsed, walked, redacted key by
14
+ * key), and a plain-text line gets its text scanned for emails, card
15
+ * numbers and long tokens -- the same two paths `redactBodyString` already
16
+ * implements, not a new one.
17
+ */
18
+ import type { RedactionStatus } from "@descryy/runtime-contracts";
19
+ import { type RedactionPolicy } from "@descryy/runtime-evidence-store";
20
+ import type { RemoteLogSourceConfig } from "./log-source-config.ts";
21
+ export interface IngestedLogLine {
22
+ readonly lineId: string;
23
+ /** ISO 8601, or null when no timestamp could be read from the line -- a real absence, not a parse failure hidden as "now". */
24
+ readonly timestamp: string | null;
25
+ /** Post-redaction text. There is no path out of `buildIngestedLogLine` that returns pre-redaction content. */
26
+ readonly raw: string;
27
+ readonly traceId: string | null;
28
+ readonly requestId: string | null;
29
+ readonly redactionStatus: RedactionStatus;
30
+ }
31
+ /**
32
+ * Builds one `IngestedLogLine` from one raw text line plus the user's
33
+ * declared `RemoteLogSourceConfig`.
34
+ *
35
+ * Identifier extraction always runs against the **pre-redaction** text --
36
+ * a trace/request id is evidence metadata, not payload content, the same
37
+ * distinction `Evidence.traceId`/`requestId` draw by living outside
38
+ * `Evidence.payload` and therefore outside `redact()`'s reach entirely.
39
+ * Extracting after redaction would try to read an id out of a line that
40
+ * may already read `[REDACTED]` where the id was.
41
+ *
42
+ * Priority, weakest signal overridden by the strongest available, per
43
+ * DEC-271's "ask, don't guess": `extractCorrelationIds`'s generic
44
+ * `trace_id=`/`traceparent`/`request_id=` heuristic runs first as a
45
+ * baseline; a JSON line's own `requestId`/`request_id` field overrides it
46
+ * when present; and the user's declared `traceIdField`, when it names a
47
+ * real value on this line, wins over both -- it is the one signal the user
48
+ * actually told us about rather than one this module inferred.
49
+ */
50
+ export declare function buildIngestedLogLine(rawLine: string, config: Pick<RemoteLogSourceConfig, "format" | "traceIdField">, redactionPolicy?: RedactionPolicy): IngestedLogLine;
51
+ //# sourceMappingURL=log-line.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-line.d.ts","sourceRoot":"","sources":["../src/log-line.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAU,KAAK,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAG/E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8HAA8H;IAC9H,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,8GAA8G;IAC9G,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC3C;AAkCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,IAAI,CAAC,qBAAqB,EAAE,QAAQ,GAAG,cAAc,CAAC,EAC9D,eAAe,GAAE,eAAoB,GACpC,eAAe,CAoCjB"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * One ingested log line, redacted before it is ever handed back to a
3
+ * caller (DEC-271: "log content is redacted before it reaches the model,
4
+ * not just before display -- the exposure is the read, not the render").
5
+ *
6
+ * Reuses `@descryy/runtime-evidence-store`'s `redact()` rather than
7
+ * reimplementing key-name/body/PII/command scanning -- the same reuse
8
+ * discipline `database-observation`'s and `browser`'s collectors already
9
+ * follow for evidence payloads. `redact()`'s own body-bearing-key
10
+ * convention (`raw`, documented there as the `LogCollector`'s payload key
11
+ * for captured text) is reused verbatim: every line is wrapped as
12
+ * `{ raw: line }` before redaction, so a JSON-shaped line gets `redact()`'s
13
+ * full key-name + text-scan treatment (parsed, walked, redacted key by
14
+ * key), and a plain-text line gets its text scanned for emails, card
15
+ * numbers and long tokens -- the same two paths `redactBodyString` already
16
+ * implements, not a new one.
17
+ */
18
+ import { randomUUID } from "node:crypto";
19
+ import { redact } from "@descryy/runtime-evidence-store";
20
+ import { extractCorrelationIds } from "@descryy/runtime-backend-observation";
21
+ const ISO_TIMESTAMP = /\b\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?\b/;
22
+ function parseTimestamp(text) {
23
+ const match = ISO_TIMESTAMP.exec(text);
24
+ if (match === null)
25
+ return null;
26
+ const parsed = new Date(match[0].replace(" ", "T"));
27
+ return Number.isNaN(parsed.getTime()) ? null : parsed.toISOString();
28
+ }
29
+ function tryParseJsonObject(text) {
30
+ try {
31
+ const parsed = JSON.parse(text);
32
+ return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ function extractJsonField(record, field) {
39
+ const value = record[field];
40
+ return typeof value === "string" && value.length > 0 ? value : null;
41
+ }
42
+ function escapeRegExp(text) {
43
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
44
+ }
45
+ function namedFieldFromText(text, field) {
46
+ const pattern = new RegExp(`\\b${escapeRegExp(field)}["']?\\s*[:=]\\s*["']?([0-9a-zA-Z-]{6,})["']?`, "i");
47
+ return pattern.exec(text)?.[1] ?? null;
48
+ }
49
+ /**
50
+ * Builds one `IngestedLogLine` from one raw text line plus the user's
51
+ * declared `RemoteLogSourceConfig`.
52
+ *
53
+ * Identifier extraction always runs against the **pre-redaction** text --
54
+ * a trace/request id is evidence metadata, not payload content, the same
55
+ * distinction `Evidence.traceId`/`requestId` draw by living outside
56
+ * `Evidence.payload` and therefore outside `redact()`'s reach entirely.
57
+ * Extracting after redaction would try to read an id out of a line that
58
+ * may already read `[REDACTED]` where the id was.
59
+ *
60
+ * Priority, weakest signal overridden by the strongest available, per
61
+ * DEC-271's "ask, don't guess": `extractCorrelationIds`'s generic
62
+ * `trace_id=`/`traceparent`/`request_id=` heuristic runs first as a
63
+ * baseline; a JSON line's own `requestId`/`request_id` field overrides it
64
+ * when present; and the user's declared `traceIdField`, when it names a
65
+ * real value on this line, wins over both -- it is the one signal the user
66
+ * actually told us about rather than one this module inferred.
67
+ */
68
+ export function buildIngestedLogLine(rawLine, config, redactionPolicy = {}) {
69
+ const parsedRecord = config.format === "json-lines" ? tryParseJsonObject(rawLine) : null;
70
+ const generic = extractCorrelationIds(rawLine);
71
+ let traceId = generic.traceId;
72
+ let requestId = generic.requestId;
73
+ let timestamp = parseTimestamp(rawLine);
74
+ if (parsedRecord !== null) {
75
+ const tsField = extractJsonField(parsedRecord, "timestamp") ?? extractJsonField(parsedRecord, "time") ?? extractJsonField(parsedRecord, "@timestamp");
76
+ if (tsField !== null) {
77
+ const parsedDate = new Date(tsField);
78
+ if (!Number.isNaN(parsedDate.getTime()))
79
+ timestamp = parsedDate.toISOString();
80
+ }
81
+ const jsonRequestId = extractJsonField(parsedRecord, "requestId") ?? extractJsonField(parsedRecord, "request_id");
82
+ if (jsonRequestId !== null)
83
+ requestId = jsonRequestId;
84
+ }
85
+ if (config.traceIdField) {
86
+ const named = parsedRecord !== null ? extractJsonField(parsedRecord, config.traceIdField) : namedFieldFromText(rawLine, config.traceIdField);
87
+ if (named !== null)
88
+ traceId = named;
89
+ }
90
+ const { payload, redactionStatus } = redact({ raw: rawLine }, redactionPolicy);
91
+ const redactedRaw = payload.raw;
92
+ return {
93
+ lineId: randomUUID(),
94
+ timestamp,
95
+ raw: redactedRaw,
96
+ traceId,
97
+ requestId,
98
+ redactionStatus,
99
+ };
100
+ }
101
+ //# sourceMappingURL=log-line.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-line.js","sourceRoot":"","sources":["../src/log-line.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The "ask, don't guess" input contract for remote log ingestion (DEC-271).
3
+ *
4
+ * For local/booted execution Descry injects its own proxy and needs to ask
5
+ * the user nothing. For remote environments (staging/preview/production,
6
+ * DEC-266) Descry does not own the infra and cannot inject anything -- the
7
+ * only mechanism left is ingesting whatever the target already has, and
8
+ * DEC-271's own "rejected: one universal mechanism" clause says that target
9
+ * is heterogeneous by nature (Datadog, CloudWatch, plain stdout, full
10
+ * OpenTelemetry, or nothing at all). So setup has to ask: where are the
11
+ * logs, what shape are they in, and is there a field that already carries a
12
+ * trace/request id.
13
+ *
14
+ * This file defines that shape only -- it is filled in by whatever asks the
15
+ * user (a CLI prompt, a UI form, elsewhere), never inferred or defaulted
16
+ * here. The logic that consumes it lives in the adapters
17
+ * (`file-log-adapter.ts` today) and in `correlator.ts`.
18
+ */
19
+ /**
20
+ * What the user says they have. `file` and `command` are both plausible
21
+ * ("here's our log file" / "here's how we tail it") and named so a future
22
+ * adapter for either has an unambiguous slot; `url` covers a log-query API
23
+ * or a signed export link. Only `file` has a concrete adapter this pass --
24
+ * see `file-log-adapter.ts`'s own doc comment for why it was chosen over
25
+ * `command`, and why `url` isn't built at all yet.
26
+ */
27
+ export type RemoteLogLocation = {
28
+ readonly kind: "file";
29
+ readonly path: string;
30
+ } | {
31
+ readonly kind: "command";
32
+ readonly command: string;
33
+ readonly args?: readonly string[];
34
+ } | {
35
+ readonly kind: "url";
36
+ readonly url: string;
37
+ };
38
+ export declare const REMOTE_LOG_FORMATS: readonly ["plain-text", "json-lines"];
39
+ /**
40
+ * The two shapes this pass knows how to read. Not a claim these are the
41
+ * only shapes a real target log ever takes (a named convention such as
42
+ * "Heroku router format" or "Rails tagged logging" is a real future case)
43
+ * -- narrowed to what `buildIngestedLogLine` actually parses, honestly,
44
+ * rather than accepting a value it would silently mishandle.
45
+ */
46
+ export type RemoteLogFormat = (typeof REMOTE_LOG_FORMATS)[number];
47
+ export interface RemoteLogSourceConfig {
48
+ readonly location: RemoteLogLocation;
49
+ readonly format: RemoteLogFormat;
50
+ /**
51
+ * The field the user says already carries a trace/request id -- a JSON
52
+ * key for `"json-lines"`, or a `name=`/`name:` field for `"plain-text"`.
53
+ *
54
+ * `null`/absent when the user doesn't have one (or doesn't know), in
55
+ * which case correlation falls back first to `extractCorrelationIds`'s
56
+ * generic key-shape heuristic and, failing that, to a timestamp+path
57
+ * window -- both weaker than a declared field, and both disclosed via
58
+ * `Correlation.method`/`confidence` on the result, never silently
59
+ * promoted to look as certain as a field the user actually named. This is
60
+ * the same "ask rather than guess" principle DEC-266 applies to target
61
+ * URLs, applied here to trace identity.
62
+ */
63
+ readonly traceIdField?: string | null;
64
+ }
65
+ //# sourceMappingURL=log-source-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-source-config.d.ts","sourceRoot":"","sources":["../src/log-source-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACzF;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,eAAO,MAAM,kBAAkB,uCAAwC,CAAC;AACxE;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The "ask, don't guess" input contract for remote log ingestion (DEC-271).
3
+ *
4
+ * For local/booted execution Descry injects its own proxy and needs to ask
5
+ * the user nothing. For remote environments (staging/preview/production,
6
+ * DEC-266) Descry does not own the infra and cannot inject anything -- the
7
+ * only mechanism left is ingesting whatever the target already has, and
8
+ * DEC-271's own "rejected: one universal mechanism" clause says that target
9
+ * is heterogeneous by nature (Datadog, CloudWatch, plain stdout, full
10
+ * OpenTelemetry, or nothing at all). So setup has to ask: where are the
11
+ * logs, what shape are they in, and is there a field that already carries a
12
+ * trace/request id.
13
+ *
14
+ * This file defines that shape only -- it is filled in by whatever asks the
15
+ * user (a CLI prompt, a UI form, elsewhere), never inferred or defaulted
16
+ * here. The logic that consumes it lives in the adapters
17
+ * (`file-log-adapter.ts` today) and in `correlator.ts`.
18
+ */
19
+ export const REMOTE_LOG_FORMATS = ["plain-text", "json-lines"];
20
+ //# sourceMappingURL=log-source-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-source-config.js","sourceRoot":"","sources":["../src/log-source-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAeH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,YAAY,EAAE,YAAY,CAAU,CAAC"}
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@descryy/runtime-remote-log-ingestion",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "description": "Remote-environment log ingestion (DEC-271): for staging/preview/production, where Descry cannot inject a proxy into infra it doesn't own, ingest whatever the target already has -- logs, and trace ids if a field is declared -- and correlate best-effort against a captured browser/proxy request, with confidence disclosed rather than assumed.",
6
+ "license": "UNLICENSED",
7
+ "engines": {
8
+ "node": ">=22.5"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "publishConfig": {
20
+ "registry": "https://registry.npmjs.org",
21
+ "access": "public"
22
+ },
23
+ "scripts": {
24
+ "build": "tsc -b"
25
+ },
26
+ "dependencies": {
27
+ "@descryy/runtime-contracts": "0.0.0",
28
+ "@descryy/runtime-backend-observation": "0.0.0",
29
+ "@descryy/runtime-evidence-store": "0.0.0"
30
+ }
31
+ }