@descryy/runtime-external-service-observation 0.2.0 → 0.3.1
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.
- package/LICENSE +6 -0
- package/dist/collector-version.d.ts +1 -8
- package/dist/collector-version.d.ts.map +1 -1
- package/dist/collector-version.js +1 -8
- package/dist/collector-version.js.map +1 -1
- package/dist/fetch-instrumentation.d.ts +26 -51
- package/dist/fetch-instrumentation.d.ts.map +1 -1
- package/dist/fetch-instrumentation.js +64 -90
- package/dist/fetch-instrumentation.js.map +1 -1
- package/dist/header-correlation.d.ts +6 -13
- package/dist/header-correlation.d.ts.map +1 -1
- package/dist/header-correlation.js +6 -13
- package/dist/header-correlation.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -8
- package/dist/index.js.map +1 -1
- package/dist/request-collector.d.ts +20 -43
- package/dist/request-collector.d.ts.map +1 -1
- package/dist/request-collector.js +76 -58
- package/dist/request-collector.js.map +1 -1
- package/dist/request-line-parser.d.ts +18 -15
- package/dist/request-line-parser.d.ts.map +1 -1
- package/dist/request-line-parser.js +32 -24
- package/dist/request-line-parser.js.map +1 -1
- package/dist/request-marker.d.ts +22 -35
- package/dist/request-marker.d.ts.map +1 -1
- package/dist/request-marker.js +18 -27
- package/dist/request-marker.js.map +1 -1
- package/dist/service-identity.d.ts +5 -17
- package/dist/service-identity.d.ts.map +1 -1
- package/dist/service-identity.js +5 -17
- package/dist/service-identity.js.map +1 -1
- package/package.json +9 -4
package/LICENSE
ADDED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `Evidence.collectorVersion`'s source for every collector in this package:
|
|
3
|
-
* this package's own `package.json` "version", read from the artifact
|
|
4
|
-
* itself rather than hand-duplicated into a second string that can drift
|
|
5
|
-
* from what actually shipped. Same idea as `nodeVersion` elsewhere in this
|
|
6
|
-
* repo (`process.version`, always known, never probed) applied to a
|
|
7
|
-
* package instead of the Node runtime.
|
|
8
|
-
*/
|
|
1
|
+
/** `Evidence.collectorVersion` for this package's collectors. Read from `package.json`, not hand-duplicated, so it can't drift from what shipped. */
|
|
9
2
|
export declare const COLLECTOR_VERSION: string;
|
|
10
3
|
//# sourceMappingURL=collector-version.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector-version.d.ts","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"collector-version.d.ts","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA,qJAAqJ;AAMrJ,eAAO,MAAM,iBAAiB,EAAE,MAA6E,CAAC"}
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `Evidence.collectorVersion`'s source for every collector in this package:
|
|
3
|
-
* this package's own `package.json` "version", read from the artifact
|
|
4
|
-
* itself rather than hand-duplicated into a second string that can drift
|
|
5
|
-
* from what actually shipped. Same idea as `nodeVersion` elsewhere in this
|
|
6
|
-
* repo (`process.version`, always known, never probed) applied to a
|
|
7
|
-
* package instead of the Node runtime.
|
|
8
|
-
*/
|
|
1
|
+
/** `Evidence.collectorVersion` for this package's collectors. Read from `package.json`, not hand-duplicated, so it can't drift from what shipped. */
|
|
9
2
|
import { createRequire } from "node:module";
|
|
10
3
|
const require = createRequire(import.meta.url);
|
|
11
4
|
export const COLLECTOR_VERSION = require("../package.json").version;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector-version.js","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"collector-version.js","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA,qJAAqJ;AAErJ,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,iBAAiB,GAAY,OAAO,CAAC,iBAAiB,CAAkC,CAAC,OAAO,CAAC"}
|
|
@@ -1,61 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `--import`-loaded preload: patches `globalThis.fetch` before the target
|
|
3
|
-
* application's
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* resolve to the same function. Same singleton-timing argument
|
|
9
|
-
* `sqlite-instrumentation.ts` (`@descryy/runtime-database-observation`,
|
|
10
|
-
* RT-141) already established for `node:sqlite`'s prototype, applied to a
|
|
11
|
-
* different kind of global.
|
|
3
|
+
* application's code runs, so every outbound call through the bare global
|
|
4
|
+
* is observed. Node's global `fetch` is a single mutable binding on
|
|
5
|
+
* `globalThis`, so a preload reassigning it and a later app call resolve to
|
|
6
|
+
* the same function — same singleton-timing argument as
|
|
7
|
+
* `sqlite-instrumentation.ts` (RT-141), applied to a different global.
|
|
12
8
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* comes off the resolved `Response` before any body access, and describing
|
|
17
|
-
* the outbound request (`method`/`url`/headers) is done via the same
|
|
18
|
-
* `Request`/`Headers` normalisation `fetch` itself would do, on a
|
|
19
|
-
* side channel, not by touching the body stream passed to the real call.
|
|
9
|
+
* Read, not write: the wrapper calls the original `fetch` with untouched
|
|
10
|
+
* arguments. Bodies are never read — `status` comes off the resolved
|
|
11
|
+
* `Response` before any body access.
|
|
20
12
|
*
|
|
21
|
-
* Deliberately minimal and import-free, like `sqlite-instrumentation.ts`
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* ids) happens on the collector side, in the observing process, not here —
|
|
26
|
-
* this only captures.
|
|
13
|
+
* Deliberately minimal and import-free, like `sqlite-instrumentation.ts` —
|
|
14
|
+
* runs inside the OBSERVED process, loaded by absolute path via
|
|
15
|
+
* `node --import`, never through this package's normal dependency graph.
|
|
16
|
+
* Interpretation happens on the collector side; this only captures.
|
|
27
17
|
*
|
|
28
|
-
*
|
|
29
|
-
* fact only this process can supply
|
|
30
|
-
* collector it
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* edge", because an edge needs a caller and an endpoint named by ONE
|
|
35
|
-
* observation and this one named only the endpoint. Capturing the stack at
|
|
36
|
-
* the call site is what makes an outbound call able to name its own caller.
|
|
18
|
+
* The call-site stack is captured here and nowhere else — it's the one
|
|
19
|
+
* fact only this process can supply (by the time the marker reaches a
|
|
20
|
+
* collector it's just text on a pipe). Capturing it here is what makes an
|
|
21
|
+
* outbound call able to name its own caller. Raw text, deliberately
|
|
22
|
+
* unparsed — parsing V8's format belongs in the observing process
|
|
23
|
+
* (`@descryy/runtime-adapter-typescript`).
|
|
37
24
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
25
|
+
* Cost: `new Error()` on every outbound call, in a process that opted into
|
|
26
|
+
* observation by loading this preload. `Error.stackTraceLimit` is left as
|
|
27
|
+
* the app set it — raising it would mean writing to the observed process's
|
|
28
|
+
* own config.
|
|
42
29
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* writing to the observed process's own configuration, which the paragraph
|
|
48
|
-
* above forbids.
|
|
49
|
-
*
|
|
50
|
-
* The marker prefix and the captured shape live in `request-marker.ts`, not
|
|
51
|
-
* here: this module has a module-scope effect and nothing that merely needs
|
|
52
|
-
* the vocabulary may be made to import it. See that file for the measurement
|
|
53
|
-
* behind that rule.
|
|
54
|
-
*
|
|
55
|
-
* One line of structured JSON per request, prefixed exactly like
|
|
56
|
-
* `sqlite-instrumentation.ts`'s own `DESCRY_DB_QUERY {json}` convention,
|
|
57
|
-
* itself following the benchmark harness's `BENCH_RESULT {json}` precedent
|
|
58
|
-
* (RT-072): scraping prose measures the prose, so nothing here is prose.
|
|
30
|
+
* Marker prefix and shape live in `request-marker.ts`, not here, since this
|
|
31
|
+
* module has a module-scope effect. One line of structured JSON per
|
|
32
|
+
* request, matching `sqlite-instrumentation.ts`'s `DESCRY_DB_QUERY {json}`
|
|
33
|
+
* convention (RT-072): scraping prose measures the prose.
|
|
59
34
|
*/
|
|
60
35
|
export {};
|
|
61
36
|
//# sourceMappingURL=fetch-instrumentation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-instrumentation.d.ts","sourceRoot":"","sources":["../src/fetch-instrumentation.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fetch-instrumentation.d.ts","sourceRoot":"","sources":["../src/fetch-instrumentation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG"}
|
|
@@ -1,75 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `--import`-loaded preload: patches `globalThis.fetch` before the target
|
|
3
|
-
* application's
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* resolve to the same function. Same singleton-timing argument
|
|
9
|
-
* `sqlite-instrumentation.ts` (`@descryy/runtime-database-observation`,
|
|
10
|
-
* RT-141) already established for `node:sqlite`'s prototype, applied to a
|
|
11
|
-
* different kind of global.
|
|
3
|
+
* application's code runs, so every outbound call through the bare global
|
|
4
|
+
* is observed. Node's global `fetch` is a single mutable binding on
|
|
5
|
+
* `globalThis`, so a preload reassigning it and a later app call resolve to
|
|
6
|
+
* the same function — same singleton-timing argument as
|
|
7
|
+
* `sqlite-instrumentation.ts` (RT-141), applied to a different global.
|
|
12
8
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* comes off the resolved `Response` before any body access, and describing
|
|
17
|
-
* the outbound request (`method`/`url`/headers) is done via the same
|
|
18
|
-
* `Request`/`Headers` normalisation `fetch` itself would do, on a
|
|
19
|
-
* side channel, not by touching the body stream passed to the real call.
|
|
9
|
+
* Read, not write: the wrapper calls the original `fetch` with untouched
|
|
10
|
+
* arguments. Bodies are never read — `status` comes off the resolved
|
|
11
|
+
* `Response` before any body access.
|
|
20
12
|
*
|
|
21
|
-
* Deliberately minimal and import-free, like `sqlite-instrumentation.ts`
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* ids) happens on the collector side, in the observing process, not here —
|
|
26
|
-
* this only captures.
|
|
13
|
+
* Deliberately minimal and import-free, like `sqlite-instrumentation.ts` —
|
|
14
|
+
* runs inside the OBSERVED process, loaded by absolute path via
|
|
15
|
+
* `node --import`, never through this package's normal dependency graph.
|
|
16
|
+
* Interpretation happens on the collector side; this only captures.
|
|
27
17
|
*
|
|
28
|
-
*
|
|
29
|
-
* fact only this process can supply
|
|
30
|
-
* collector it
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* edge", because an edge needs a caller and an endpoint named by ONE
|
|
35
|
-
* observation and this one named only the endpoint. Capturing the stack at
|
|
36
|
-
* the call site is what makes an outbound call able to name its own caller.
|
|
18
|
+
* The call-site stack is captured here and nowhere else — it's the one
|
|
19
|
+
* fact only this process can supply (by the time the marker reaches a
|
|
20
|
+
* collector it's just text on a pipe). Capturing it here is what makes an
|
|
21
|
+
* outbound call able to name its own caller. Raw text, deliberately
|
|
22
|
+
* unparsed — parsing V8's format belongs in the observing process
|
|
23
|
+
* (`@descryy/runtime-adapter-typescript`).
|
|
37
24
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
25
|
+
* Cost: `new Error()` on every outbound call, in a process that opted into
|
|
26
|
+
* observation by loading this preload. `Error.stackTraceLimit` is left as
|
|
27
|
+
* the app set it — raising it would mean writing to the observed process's
|
|
28
|
+
* own config.
|
|
42
29
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* writing to the observed process's own configuration, which the paragraph
|
|
48
|
-
* above forbids.
|
|
49
|
-
*
|
|
50
|
-
* The marker prefix and the captured shape live in `request-marker.ts`, not
|
|
51
|
-
* here: this module has a module-scope effect and nothing that merely needs
|
|
52
|
-
* the vocabulary may be made to import it. See that file for the measurement
|
|
53
|
-
* behind that rule.
|
|
54
|
-
*
|
|
55
|
-
* One line of structured JSON per request, prefixed exactly like
|
|
56
|
-
* `sqlite-instrumentation.ts`'s own `DESCRY_DB_QUERY {json}` convention,
|
|
57
|
-
* itself following the benchmark harness's `BENCH_RESULT {json}` precedent
|
|
58
|
-
* (RT-072): scraping prose measures the prose, so nothing here is prose.
|
|
30
|
+
* Marker prefix and shape live in `request-marker.ts`, not here, since this
|
|
31
|
+
* module has a module-scope effect. One line of structured JSON per
|
|
32
|
+
* request, matching `sqlite-instrumentation.ts`'s `DESCRY_DB_QUERY {json}`
|
|
33
|
+
* convention (RT-072): scraping prose measures the prose.
|
|
59
34
|
*/
|
|
60
|
-
import { REQUEST_MARKER } from "./request-marker.js";
|
|
61
|
-
/** This module's own location, in both shapes a V8 frame
|
|
35
|
+
import { REQUEST_MARKER, FETCH_BINDING_FAILURE_MARKER } from "./request-marker.js";
|
|
36
|
+
/** This module's own location, in both shapes a V8 frame prints it: ESM stringifies a `file://` URL, CJS a plain path. */
|
|
62
37
|
const SELF_URL = import.meta.url;
|
|
63
38
|
const SELF_PATH = SELF_URL.startsWith("file://") ? SELF_URL.slice("file://".length) : SELF_URL;
|
|
64
39
|
/**
|
|
65
|
-
* Frames
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* rather than an error. Matching on `import.meta.url` also survives this
|
|
71
|
-
* module being loaded from `.js` (the compiled preload, how it actually
|
|
72
|
-
* runs) or `.ts` (type stripping, how a test may run it).
|
|
40
|
+
* Frames from this file are dropped **by file, not by count** — a
|
|
41
|
+
* surviving wrapper frame would make every downstream resolution point at
|
|
42
|
+
* the instrumentation instead of the observed code (`primaryFrameIndex` is
|
|
43
|
+
* 0 for every V8 stack this project parses). Matching `import.meta.url`
|
|
44
|
+
* survives this being loaded as `.js` (real) or `.ts` (test).
|
|
73
45
|
*/
|
|
74
46
|
function callSiteStack() {
|
|
75
47
|
const raw = new Error().stack;
|
|
@@ -78,8 +50,8 @@ function callSiteStack() {
|
|
|
78
50
|
const lines = raw.split("\n");
|
|
79
51
|
const header = lines[0] ?? "Error";
|
|
80
52
|
const frames = lines.slice(1).filter((line) => !line.includes(SELF_URL) && !line.includes(SELF_PATH));
|
|
81
|
-
// Nothing but our own frames:
|
|
82
|
-
//
|
|
53
|
+
// Nothing but our own frames: `null` rather than a header line pretending
|
|
54
|
+
// to be a stack.
|
|
83
55
|
if (frames.length === 0)
|
|
84
56
|
return null;
|
|
85
57
|
return [header, ...frames].join("\n");
|
|
@@ -93,12 +65,7 @@ function headersToObject(headers) {
|
|
|
93
65
|
out[name] = value;
|
|
94
66
|
return out;
|
|
95
67
|
}
|
|
96
|
-
/**
|
|
97
|
-
* `url`/`method`/`requestHeaders` off the call's own arguments, without
|
|
98
|
-
* touching the body -- a `Request` object already carries these structured;
|
|
99
|
-
* a `(input, init)` pair is normalised the same way `fetch` itself would,
|
|
100
|
-
* via the real `Headers` constructor rather than hand-parsed.
|
|
101
|
-
*/
|
|
68
|
+
/** `url`/`method`/`requestHeaders` off the call's own arguments, without touching the body. Normalised via the real `Headers` constructor, not hand-parsed. */
|
|
102
69
|
function describeRequest(input, init) {
|
|
103
70
|
if (input instanceof Request) {
|
|
104
71
|
return { url: input.url, method: input.method, requestHeaders: headersToObject(input.headers) };
|
|
@@ -107,31 +74,38 @@ function describeRequest(input, init) {
|
|
|
107
74
|
const method = (init?.method ?? "GET").toUpperCase();
|
|
108
75
|
return { url, method, requestHeaders: headersToObject(new Headers(init?.headers)) };
|
|
109
76
|
}
|
|
110
|
-
// Guards against double-patching if
|
|
111
|
-
//
|
|
112
|
-
// would otherwise wrap an already-wrapped fetch and double-emit. Same
|
|
113
|
-
// guard shape as sqlite-instrumentation.ts's own PATCHED symbol.
|
|
77
|
+
// Guards against double-patching if loaded twice (double-emit otherwise).
|
|
78
|
+
// Same guard shape as sqlite-instrumentation.ts's PATCHED symbol.
|
|
114
79
|
const PATCHED = Symbol.for("descry.external-service-observation.fetch-patched");
|
|
115
80
|
const target = globalThis;
|
|
116
81
|
if (target[PATCHED] !== true) {
|
|
117
82
|
target[PATCHED] = true;
|
|
118
83
|
const original = globalThis.fetch;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
84
|
+
// C-F6: previously unchecked — `original` could be `undefined` (old Node,
|
|
85
|
+
// `--no-experimental-fetch`), and every real call would then throw
|
|
86
|
+
// "original is not a function", indistinguishable from a real network
|
|
87
|
+
// error. Disclosed here instead via a distinct marker line; the wrapper
|
|
88
|
+
// is never installed.
|
|
89
|
+
if (typeof original !== "function") {
|
|
90
|
+
process.stdout.write(`${FETCH_BINDING_FAILURE_MARKER} ${JSON.stringify({ reason: `globalThis.fetch was ${typeof original}, not a function -- no real fetch to instrument` })}\n`);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
globalThis.fetch = async function patchedFetch(input, init) {
|
|
94
|
+
const described = describeRequest(input, init);
|
|
95
|
+
// Captured BEFORE the call: after `await` the app's frames are gone.
|
|
96
|
+
const stack = callSiteStack();
|
|
97
|
+
const start = performance.now();
|
|
98
|
+
try {
|
|
99
|
+
const response = await original(input, init);
|
|
100
|
+
emit({ ...described, status: response.status, durationMs: performance.now() - start, success: true, error: null, stack });
|
|
101
|
+
return response;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
const detail = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
105
|
+
emit({ ...described, status: null, durationMs: performance.now() - start, success: false, error: detail, stack });
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
136
110
|
}
|
|
137
111
|
//# sourceMappingURL=fetch-instrumentation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-instrumentation.js","sourceRoot":"","sources":["../src/fetch-instrumentation.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fetch-instrumentation.js","sourceRoot":"","sources":["../src/fetch-instrumentation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Correlation-id extraction from real HTTP headers —
|
|
3
|
-
*
|
|
4
|
-
* (`@descryhq-wq/runtime-browser`'s `network-correlation.ts`).
|
|
2
|
+
* Correlation-id extraction from real HTTP headers — same mechanism and
|
|
3
|
+
* header names as `@descryy/runtime-browser`'s `network-correlation.ts`.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `fetch`. The function itself is small, pure, and reads a closed,
|
|
11
|
-
* unlikely-to-change set of conventional header names — the case this
|
|
12
|
-
* project's own `symbol.ts` distinguishes from (`toRepoRelative` is
|
|
13
|
-
* *shared* because its two callers must translate identically); these two
|
|
14
|
-
* copies have no such constraint, and importing across a Playwright
|
|
15
|
-
* dependency to avoid ten lines would be the worse coupling.
|
|
5
|
+
* Duplicated on purpose, not imported: `browser` depends on Playwright, a
|
|
6
|
+
* heavy dependency this package has no other reason to carry. The function
|
|
7
|
+
* is small, pure, and reads a closed set of header names — importing across
|
|
8
|
+
* Playwright to avoid ten lines would be the worse coupling.
|
|
16
9
|
*/
|
|
17
10
|
export interface HeaderCorrelationIds {
|
|
18
11
|
readonly traceId: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"header-correlation.d.ts","sourceRoot":"","sources":["../src/header-correlation.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"header-correlation.d.ts","sourceRoot":"","sources":["../src/header-correlation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAUD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,oBAAoB,CAS3G"}
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Correlation-id extraction from real HTTP headers —
|
|
3
|
-
*
|
|
4
|
-
* (`@descryhq-wq/runtime-browser`'s `network-correlation.ts`).
|
|
2
|
+
* Correlation-id extraction from real HTTP headers — same mechanism and
|
|
3
|
+
* header names as `@descryy/runtime-browser`'s `network-correlation.ts`.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `fetch`. The function itself is small, pure, and reads a closed,
|
|
11
|
-
* unlikely-to-change set of conventional header names — the case this
|
|
12
|
-
* project's own `symbol.ts` distinguishes from (`toRepoRelative` is
|
|
13
|
-
* *shared* because its two callers must translate identically); these two
|
|
14
|
-
* copies have no such constraint, and importing across a Playwright
|
|
15
|
-
* dependency to avoid ten lines would be the worse coupling.
|
|
5
|
+
* Duplicated on purpose, not imported: `browser` depends on Playwright, a
|
|
6
|
+
* heavy dependency this package has no other reason to carry. The function
|
|
7
|
+
* is small, pure, and reads a closed set of header names — importing across
|
|
8
|
+
* Playwright to avoid ten lines would be the worse coupling.
|
|
16
9
|
*/
|
|
17
10
|
const TRACEPARENT_PATTERN = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/i;
|
|
18
11
|
function firstHeader(headers, names) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"header-correlation.js","sourceRoot":"","sources":["../src/header-correlation.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"header-correlation.js","sourceRoot":"","sources":["../src/header-correlation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,mBAAmB,GAAG,8DAA8D,CAAC;AAO3F,SAAS,WAAW,CAAC,OAAyC,EAAE,KAAwB;IACtF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,OAAyC;IACnF,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC;IACzE,MAAM,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3C,MAAM,UAAU,GAAG,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE3G,OAAO;QACL,OAAO,EAAE,eAAe,IAAI,UAAU;QACtC,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC;KAChE,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { REQUEST_MARKER, type CapturedRequest } from "./request-marker.ts";
|
|
2
|
-
export { parseRequestLine } from "./request-line-parser.ts";
|
|
1
|
+
export { REQUEST_MARKER, FETCH_BINDING_FAILURE_MARKER, type CapturedRequest } from "./request-marker.ts";
|
|
2
|
+
export { parseRequestLine, parseFetchBindingFailureLine } from "./request-line-parser.ts";
|
|
3
3
|
export { extractServiceIdentity } from "./service-identity.ts";
|
|
4
4
|
export { extractHeaderCorrelationIds, type HeaderCorrelationIds } from "./header-correlation.ts";
|
|
5
5
|
export type { ExternalRequestCollectorOptions } from "./request-collector.ts";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,4BAA4B,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzG,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEjG,YAAY,EAAE,+BAA+B,EAAE,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAE,8BAA8B,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
// Deliberately NOT from `fetch-instrumentation.ts
|
|
2
|
-
// `globalThis.fetch` at module scope
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export { REQUEST_MARKER } from "./request-marker.js";
|
|
8
|
-
export { parseRequestLine } from "./request-line-parser.js";
|
|
1
|
+
// Deliberately NOT from `fetch-instrumentation.ts` — that module patches
|
|
2
|
+
// `globalThis.fetch` at module scope; re-exporting from it would leak the
|
|
3
|
+
// patch into every consumer (`query-marker.ts`'s measured defect). The
|
|
4
|
+
// preload loads by absolute path via `node --import`, never through here.
|
|
5
|
+
export { REQUEST_MARKER, FETCH_BINDING_FAILURE_MARKER } from "./request-marker.js";
|
|
6
|
+
export { parseRequestLine, parseFetchBindingFailureLine } from "./request-line-parser.js";
|
|
9
7
|
export { extractServiceIdentity } from "./service-identity.js";
|
|
10
8
|
export { extractHeaderCorrelationIds } from "./header-correlation.js";
|
|
11
9
|
export { createExternalRequestCollector, FETCH_PRELOAD_MODULE_PATH } from "./request-collector.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,0EAA0E;AAC1E,uEAAuE;AACvE,0EAA0E;AAC1E,OAAO,EAAE,cAAc,EAAE,4BAA4B,EAAwB,MAAM,qBAAqB,CAAC;AACzG,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAA6B,MAAM,yBAAyB,CAAC;AAGjG,OAAO,EAAE,8BAA8B,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -1,57 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `ExternalRequestCollector
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* failure reported as evidence rather than swallowed — but for a different
|
|
8
|
-
* marker on the same stream.
|
|
2
|
+
* `ExternalRequestCollector`: translates `fetch-instrumentation.ts`'s
|
|
3
|
+
* captured requests into `EXTERNAL_REQUEST` Evidence. Same shape as
|
|
4
|
+
* `DatabaseQueryCollector` (RT-141) — `ProcessOutputSource` in, `Evidence`
|
|
5
|
+
* out, failures reported as evidence — for a different marker on the same
|
|
6
|
+
* stream.
|
|
9
7
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* (`service-identity.ts`), and `graphNodeId` is always null — no resolver
|
|
15
|
-
* from a captured hostname to any graph node exists (nothing in the 15
|
|
16
|
-
* canonical node types names an external service). All real §18 rows, left
|
|
17
|
-
* open rather than guessed at, matching `DatabaseQueryCollector`'s own
|
|
18
|
-
* disclosure of the same shape of gap.
|
|
8
|
+
* Does NOT: capture request/response bodies (preload never reads either
|
|
9
|
+
* stream), classify providers beyond hostname (`service-identity.ts`), or
|
|
10
|
+
* set `graphNodeId` (no resolver from a hostname to any of the 15 canonical
|
|
11
|
+
* node types exists). Disclosed gaps, matching `DatabaseQueryCollector`'s own.
|
|
19
12
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* `
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* the preload that writes it runs inside the calling process, so the stack
|
|
26
|
-
* was always available — nobody had captured it. It is captured now
|
|
27
|
-
* (`fetch-instrumentation.ts`), and this collector attaches it.
|
|
28
|
-
*
|
|
29
|
-
* Parsing it is **not** this package's job. V8's `Error.stack` format is one
|
|
30
|
-
* language's, and this collector observes the marker protocol, which is not.
|
|
31
|
-
* So a `StackTraceParser` is an option, supplied by whoever knows which
|
|
32
|
-
* runtime is being observed — `RuntimeAdapter.stackTraceParser` is exactly
|
|
33
|
-
* that value, already on the seam. Omitted, this collector behaves exactly as
|
|
34
|
-
* it did before the capture existed and **says so** in `capabilities()`:
|
|
35
|
-
* `stackCapture: unavailable`, with the reason. A half-wired capability that
|
|
36
|
-
* quietly reports nothing is the failure mode this project's honest-
|
|
37
|
-
* degradation rule exists to prevent.
|
|
13
|
+
* `stackTrace` is parsed via an injected `StackTraceParser` — parsing V8's
|
|
14
|
+
* format is not this package's job, so the observed runtime's own parser
|
|
15
|
+
* (`RuntimeAdapter.stackTraceParser`) is supplied by the caller. Omitted,
|
|
16
|
+
* `capabilities()` reports `stackCapture: unavailable` with the reason
|
|
17
|
+
* rather than silently reporting nothing.
|
|
38
18
|
*/
|
|
39
19
|
import type { Collector } from "@descryy/runtime-contracts";
|
|
40
20
|
import type { ProcessOutputSource, StackTraceParser } from "@descryy/runtime-backend-observation";
|
|
41
|
-
/** Absolute path to the compiled preload, for
|
|
21
|
+
/** Absolute path to the compiled preload, for `node --import <this> <app>`. Never imported directly — loaded by Node in the observed process. */
|
|
42
22
|
export declare const FETCH_PRELOAD_MODULE_PATH: string;
|
|
43
23
|
export interface ExternalRequestCollectorOptions {
|
|
44
24
|
readonly source: ProcessOutputSource;
|
|
45
|
-
/** Which owned system this
|
|
25
|
+
/** Which owned system this evidence should be attributed to. Null when not applicable. */
|
|
46
26
|
readonly service?: string;
|
|
47
27
|
/**
|
|
48
|
-
* The observed runtime's own stack parser
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* Omitted means captured stacks are not parsed and `stackTrace` stays
|
|
53
|
-
* `null`, which `capabilities()` reports as `stackCapture: unavailable`
|
|
54
|
-
* rather than leaving a reader to infer it from an absence.
|
|
28
|
+
* The observed runtime's own stack parser (`RuntimeAdapter.stackTraceParser`)
|
|
29
|
+
* — this package knows no language and must not (IR boundary rule).
|
|
30
|
+
* Omitted means `stackTrace` stays `null`, reported by `capabilities()`
|
|
31
|
+
* as `stackCapture: unavailable` rather than left to infer.
|
|
55
32
|
*/
|
|
56
33
|
readonly stackTraceParser?: StackTraceParser;
|
|
57
34
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-collector.d.ts","sourceRoot":"","sources":["../src/request-collector.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"request-collector.d.ts","sourceRoot":"","sources":["../src/request-collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAA+F,MAAM,4BAA4B,CAAC;AACzJ,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAOlG,iJAAiJ;AACjJ,eAAO,MAAM,yBAAyB,QAAwE,CAAC;AAE/G,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,0FAA0F;IAC1F,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CAC9C;AAgCD,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,+BAA+B,GAAG,SAAS,CAyJlG"}
|