@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.
@@ -1,47 +1,27 @@
1
1
  /**
2
- * `ExternalRequestCollector` (plan §18 / checklist §18): translates
3
- * `fetch-instrumentation.ts`'s captured requests into `EXTERNAL_REQUEST`
4
- * Evidence. Same shape as `DatabaseQueryCollector`
5
- * (`@descryy/runtime-database-observation`, RT-141) deliberately — a
6
- * `ProcessOutputSource` in, `Evidence` out, streaming-first, a collector
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
- * **What this collector does not do, named rather than silently absent:**
11
- * no request/response body capture (the preload never reads either stream —
12
- * see `fetch-instrumentation.ts`'s own "read, not write" note), no
13
- * provider classification beyond a request's own hostname
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
- * ## The call-site stack, and why the parser is injected
21
- *
22
- * `stackTrace` used to be hard-null here, and `observe_runtime`'s own header
23
- * gave the reason: *"it parses a log line the application printed and a
24
- * printed line carries no stack."* The line is this package's own marker and
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 { fileURLToPath } from "node:url";
40
- import { parseRequestLine } from "./request-line-parser.js";
20
+ import { parseRequestLine, parseFetchBindingFailureLine } from "./request-line-parser.js";
41
21
  import { extractServiceIdentity } from "./service-identity.js";
42
22
  import { extractHeaderCorrelationIds } from "./header-correlation.js";
43
23
  import { COLLECTOR_VERSION } from "./collector-version.js";
44
- /** Absolute path to the compiled preload, for a caller building `node --import <this> <app>`. Never imported directly -- loaded by Node itself, in the observed process, before that process's own code runs. */
24
+ /** Absolute path to the compiled preload, for `node --import <this> <app>`. Never imported directly — loaded by Node in the observed process. */
45
25
  export const FETCH_PRELOAD_MODULE_PATH = fileURLToPath(new URL("./fetch-instrumentation.js", import.meta.url));
46
26
  const EVENT_TYPE = "EXTERNAL_REQUEST";
47
27
  function computeCapabilities(hasStackParser) {
@@ -52,15 +32,12 @@ function computeCapabilities(hasStackParser) {
52
32
  consoleObservation: status,
53
33
  networkObservation: status,
54
34
  backendLogAccess: status,
55
- // Real HTTP headers, structurally read (Headers/Request, not text
56
- // parsed) -- the same mechanism and the same claim strength
57
- // BrowserNetworkCollector already makes for its own captured requests.
35
+ // Real HTTP headers, structurally read (Headers/Request), same claim
36
+ // strength BrowserNetworkCollector makes for its own captured requests.
58
37
  distributedTrace: { availability: "available", reason: null },
59
38
  sourceMapping: status,
60
- // Real: the preload captures the application's own stack at the fetch
61
- // call site, in the observed process, before the call leaves it. Claimed
62
- // only when a parser was actually supplied to turn it into frames --
63
- // capturing text nothing can read is not a capability.
39
+ // Claimed only when a parser was actually supplied — capturing text
40
+ // nothing can read is not a capability.
64
41
  stackCapture: hasStackParser
65
42
  ? { availability: "available", reason: null }
66
43
  : {
@@ -77,24 +54,23 @@ export function createExternalRequestCollector(options) {
77
54
  const capabilities = computeCapabilities(options.stackTraceParser !== undefined);
78
55
  let consumeLoopDone;
79
56
  let consumptionFailure = null;
80
- /**
81
- * `null` for every honest reason it can be: nothing captured, no parser
82
- * supplied, or a parser that refused the text outright. A parser's `null`
83
- * is its own contract ("not recognizable as this parser's format, never a
84
- * best-effort guess") and is passed through rather than softened.
85
- */
57
+ // C-F6: set once FETCH_BINDING_FAILURE_MARKER is seen — the preload found
58
+ // no real `globalThis.fetch`, so no call was ever observed. Before this,
59
+ // capabilities() kept reporting "available" regardless.
60
+ let bindingFailure = null;
61
+ /** `null` for nothing captured, no parser, or a parser that refused the text — passed through rather than softened. */
86
62
  async function parseStack(request) {
87
63
  if (request.stack === null || options.stackTraceParser === undefined)
88
64
  return null;
89
65
  return await options.stackTraceParser.parse(request.stack);
90
66
  }
91
- async function emitCapturedRequest(request, context) {
67
+ async function emitCapturedRequest(request, context, preExisting) {
92
68
  const { traceId, requestId } = extractHeaderCorrelationIds(request.requestHeaders);
93
69
  const stackTrace = await parseStack(request);
94
70
  context.emit({
95
71
  timestamp: new Date().toISOString(),
96
72
  source: "backend-process",
97
- service: options.service ?? null,
73
+ service: options.source.serviceName ?? options.service ?? null,
98
74
  process: options.source.processId,
99
75
  eventType: EVENT_TYPE,
100
76
  payload: {
@@ -110,23 +86,54 @@ export function createExternalRequestCollector(options) {
110
86
  traceId,
111
87
  requestId,
112
88
  correlationId: null,
113
- // No resolver from a captured hostname to a graph node exists --
114
- // none of the 15 canonical node types names an external service.
89
+ // No resolver from a hostname to a graph node exists — none of the
90
+ // 15 canonical node types names an external service.
115
91
  graphNodeId: null,
116
92
  sourceLocation: null,
117
93
  stackTrace,
118
- // The observation itself (a real captured call, real timing, real
119
- // status/failure) is not probabilistic.
120
- confidence: 1,
94
+ confidence: 1, // a real captured call, real timing — not probabilistic
95
+ redactionStatus: "pending-redaction",
96
+ collectorVersion: COLLECTOR_VERSION,
97
+ // RT-N3: this capture came from a line the source itself marked as
98
+ // pre-existing (e.g. an attach-mode target's log content from before
99
+ // attach) -- see `ProcessOutputLine.preExisting`.
100
+ ...(preExisting ? { preExisting: true } : {}),
101
+ });
102
+ }
103
+ function emitBindingFailure(reason, context) {
104
+ bindingFailure = reason;
105
+ context.emit({
106
+ timestamp: new Date().toISOString(),
107
+ source: "backend-process",
108
+ service: options.source.serviceName ?? options.service ?? null,
109
+ process: options.source.processId,
110
+ eventType: "COLLECTOR_ERROR",
111
+ payload: {
112
+ raw: `external request collector for process "${options.source.processId}": the fetch preload could not bind -- ${reason}. No outbound call in this process can be observed.`,
113
+ collectorId: `external-request-collector:${options.source.processId}`,
114
+ error: reason,
115
+ },
116
+ traceId: null,
117
+ requestId: null,
118
+ correlationId: null,
119
+ graphNodeId: null,
120
+ sourceLocation: null,
121
+ stackTrace: null,
122
+ confidence: 1, // our own failure to bind, not an inference about the app
121
123
  redactionStatus: "pending-redaction",
122
124
  collectorVersion: COLLECTOR_VERSION,
123
125
  });
124
126
  }
125
127
  async function consume(context) {
126
128
  for await (const line of options.source.lines) {
129
+ const binding = parseFetchBindingFailureLine(line.text);
130
+ if (binding !== null) {
131
+ emitBindingFailure(binding.reason, context);
132
+ continue;
133
+ }
127
134
  const request = parseRequestLine(line.text);
128
135
  if (request !== null)
129
- await emitCapturedRequest(request, context);
136
+ await emitCapturedRequest(request, context, line.preExisting === true);
130
137
  }
131
138
  }
132
139
  return {
@@ -139,7 +146,7 @@ export function createExternalRequestCollector(options) {
139
146
  context.emit({
140
147
  timestamp: new Date().toISOString(),
141
148
  source: "backend-process",
142
- service: options.service ?? null,
149
+ service: options.source.serviceName ?? options.service ?? null,
143
150
  process: options.source.processId,
144
151
  eventType: "COLLECTOR_ERROR",
145
152
  payload: {
@@ -168,6 +175,17 @@ export function createExternalRequestCollector(options) {
168
175
  await consumeLoopDone;
169
176
  },
170
177
  capabilities() {
178
+ // Binding failure takes priority — externalServiceObservation was
179
+ // never real for this process, worse than "stopped early" below.
180
+ if (bindingFailure !== null) {
181
+ return {
182
+ ...capabilities,
183
+ externalServiceObservation: {
184
+ availability: "unavailable",
185
+ reason: `the fetch preload never bound a real globalThis.fetch (${bindingFailure}) -- no outbound call in this process was observed.`,
186
+ },
187
+ };
188
+ }
171
189
  if (consumptionFailure === null)
172
190
  return capabilities;
173
191
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"request-collector.js","sourceRoot":"","sources":["../src/request-collector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request-collector.js","sourceRoot":"","sources":["../src/request-collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,OAAO,EAAE,gBAAgB,EAAE,4BAA4B,EAAwB,MAAM,0BAA0B,CAAC;AAChH,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,iJAAiJ;AACjJ,MAAM,CAAC,MAAM,yBAAyB,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,4BAA4B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAe/G,MAAM,UAAU,GAAqB,kBAAkB,CAAC;AAExD,SAAS,mBAAmB,CAAC,cAAuB;IAClD,MAAM,MAAM,GAAG,iEAAiE,CAAC;IACjF,MAAM,MAAM,GAAG,EAAE,YAAY,EAAE,aAAsB,EAAE,MAAM,EAAE,CAAC;IAChE,OAAO;QACL,cAAc,EAAE,MAAM;QACtB,kBAAkB,EAAE,MAAM;QAC1B,kBAAkB,EAAE,MAAM;QAC1B,gBAAgB,EAAE,MAAM;QACxB,qEAAqE;QACrE,wEAAwE;QACxE,gBAAgB,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE;QAC7D,aAAa,EAAE,MAAM;QACrB,oEAAoE;QACpE,wCAAwC;QACxC,YAAY,EAAE,cAAc;YAC1B,CAAC,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE;YAC7C,CAAC,CAAC;gBACE,YAAY,EAAE,aAAa;gBAC3B,MAAM,EACJ,wGAAwG;oBACxG,mHAAmH;aACtH;QACL,gBAAgB,EAAE,MAAM;QACxB,mBAAmB,EAAE,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,uHAAuH,EAAE;QACrL,0BAA0B,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE;KACxE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,OAAwC;IACrF,MAAM,YAAY,GAAG,mBAAmB,CAAC,OAAO,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC;IACjF,IAAI,eAA0C,CAAC;IAC/C,IAAI,kBAAkB,GAAkB,IAAI,CAAC;IAC7C,0EAA0E;IAC1E,yEAAyE;IACzE,wDAAwD;IACxD,IAAI,cAAc,GAAkB,IAAI,CAAC;IAEzC,uHAAuH;IACvH,KAAK,UAAU,UAAU,CAAC,OAAwB;QAChD,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,CAAC,gBAAgB,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QAClF,OAAO,MAAM,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,UAAU,mBAAmB,CAAC,OAAwB,EAAE,OAAyB,EAAE,WAAoB;QAC1G,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,2BAA2B,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACnF,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC;YACX,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,MAAM,EAAE,iBAAiB;YACzB,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC,OAAO,IAAI,IAAI;YAC9D,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS;YACjC,SAAS,EAAE,UAAU;YACrB,OAAO,EAAE;gBACP,GAAG,EAAE,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE;gBACvC,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,OAAO,EAAE,sBAAsB,CAAC,OAAO,CAAC,GAAG,CAAC;gBAC5C,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,KAAK,EAAE,OAAO,CAAC,KAAK;aACrB;YACD,OAAO;YACP,SAAS;YACT,aAAa,EAAE,IAAI;YACnB,mEAAmE;YACnE,qDAAqD;YACrD,WAAW,EAAE,IAAI;YACjB,cAAc,EAAE,IAAI;YACpB,UAAU;YACV,UAAU,EAAE,CAAC,EAAE,wDAAwD;YACvE,eAAe,EAAE,mBAAmB;YACpC,gBAAgB,EAAE,iBAAiB;YACnC,mEAAmE;YACnE,qEAAqE;YACrE,kDAAkD;YAClD,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9C,CAAC,CAAC;IACL,CAAC;IAED,SAAS,kBAAkB,CAAC,MAAc,EAAE,OAAyB;QACnE,cAAc,GAAG,MAAM,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC;YACX,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,MAAM,EAAE,iBAAiB;YACzB,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC,OAAO,IAAI,IAAI;YAC9D,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS;YACjC,SAAS,EAAE,iBAAiB;YAC5B,OAAO,EAAE;gBACP,GAAG,EAAE,2CAA2C,OAAO,CAAC,MAAM,CAAC,SAAS,0CAA0C,MAAM,qDAAqD;gBAC7K,WAAW,EAAE,8BAA8B,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE;gBACrE,KAAK,EAAE,MAAM;aACd;YACD,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,IAAI;YACf,aAAa,EAAE,IAAI;YACnB,WAAW,EAAE,IAAI;YACjB,cAAc,EAAE,IAAI;YACpB,UAAU,EAAE,IAAI;YAChB,UAAU,EAAE,CAAC,EAAE,0DAA0D;YACzE,eAAe,EAAE,mBAAmB;YACpC,gBAAgB,EAAE,iBAAiB;SACpC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,UAAU,OAAO,CAAC,OAAyB;QAC9C,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC9C,MAAM,OAAO,GAAG,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,kBAAkB,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAC5C,SAAS;YACX,CAAC;YACD,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,OAAO,KAAK,IAAI;gBAAE,MAAM,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;IAED,OAAO;QACL,WAAW,EAAE,8BAA8B,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE;QAErE,KAAK,CAAC,OAAyB;YAC7B,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBAC1D,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC1F,kBAAkB,GAAG,MAAM,CAAC;gBAC5B,IAAI,CAAC;oBACH,OAAO,CAAC,IAAI,CAAC;wBACX,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;wBACnC,MAAM,EAAE,iBAAiB;wBACzB,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC,OAAO,IAAI,IAAI;wBAC9D,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS;wBACjC,SAAS,EAAE,iBAAiB;wBAC5B,OAAO,EAAE;4BACP,GAAG,EAAE,2CAA2C,OAAO,CAAC,MAAM,CAAC,SAAS,uCAAuC,MAAM,EAAE;4BACvH,WAAW,EAAE,8BAA8B,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE;4BACrE,KAAK,EAAE,MAAM;yBACd;wBACD,OAAO,EAAE,IAAI;wBACb,SAAS,EAAE,IAAI;wBACf,aAAa,EAAE,IAAI;wBACnB,WAAW,EAAE,IAAI;wBACjB,cAAc,EAAE,IAAI;wBACpB,UAAU,EAAE,IAAI;wBAChB,UAAU,EAAE,CAAC;wBACb,eAAe,EAAE,mBAAmB;wBACpC,gBAAgB,EAAE,iBAAiB;qBACpC,CAAC,CAAC;gBACL,CAAC;gBAAC,OAAO,SAAkB,EAAE,CAAC;oBAC5B,OAAO,CAAC,KAAK,CACX,+BAA+B,OAAO,CAAC,MAAM,CAAC,SAAS,yBAAyB,MAAM,2CAA2C,MAAM,CAAC,SAAS,CAAC,EAAE,CACrJ,CAAC;gBACJ,CAAC;YACH,CAAC,CAAC,CAAC;YACH,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;QAED,KAAK,CAAC,IAAI;YACR,MAAM,eAAe,CAAC;QACxB,CAAC;QAED,YAAY;YACV,kEAAkE;YAClE,iEAAiE;YACjE,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;gBAC5B,OAAO;oBACL,GAAG,YAAY;oBACf,0BAA0B,EAAE;wBAC1B,YAAY,EAAE,aAAa;wBAC3B,MAAM,EAAE,0DAA0D,cAAc,qDAAqD;qBACtI;iBACF,CAAC;YACJ,CAAC;YACD,IAAI,kBAAkB,KAAK,IAAI;gBAAE,OAAO,YAAY,CAAC;YACrD,OAAO;gBACL,GAAG,YAAY;gBACf,gBAAgB,EAAE;oBAChB,YAAY,EAAE,aAAa;oBAC3B,MAAM,EAAE,6CAA6C,kBAAkB,gDAAgD;iBACxH;aACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,22 +1,25 @@
1
1
  /**
2
- * Reads one process-output line for the `REQUEST_MARKER` prefix.
3
- *
4
- * The marker comes from `request-marker.ts`, never from
5
- * `fetch-instrumentation.ts` — importing the emitter to get a string would
6
- * patch the parsing process's own `globalThis.fetch`. See `request-marker.ts`
7
- * for the measurement. Everything else — the application's own real
8
- * stdout/stderr — is not this parser's concern and is left alone; an
9
- * external-request collector does not also try to be a log collector.
2
+ * Reads one process-output line for the `REQUEST_MARKER` prefix. The
3
+ * marker comes from `request-marker.ts`, never `fetch-instrumentation.ts`
4
+ * — importing the emitter would patch the parsing process's own fetch.
5
+ * Everything else (the app's real stdout/stderr) is left alone.
10
6
  */
11
- import { REQUEST_MARKER, type CapturedRequest } from "./request-marker.ts";
7
+ import { REQUEST_MARKER, FETCH_BINDING_FAILURE_MARKER, type CapturedRequest } from "./request-marker.ts";
12
8
  /**
13
- * `null` for a non-matching line (ordinary application output) AND for a
14
- * line that starts with the marker but fails to parse as one of this
15
- * package's own captured requests — a malformed marker line is refused,
16
- * never guessed at, the same distinction `parseQueryLine`
17
- * (`@descryy/runtime-database-observation`) makes.
9
+ * `null` for a non-matching line AND for a marker-prefixed line that fails
10
+ * to parse — malformed is refused, never guessed at, same as
11
+ * `parseQueryLine` (`@descryy/runtime-database-observation`).
18
12
  */
19
13
  export declare function parseRequestLine(line: string): CapturedRequest | null;
14
+ /**
15
+ * C-F6: recognises the preload's disclosure that it found no real
16
+ * `globalThis.fetch`. `null` for every other line. A malformed line past
17
+ * the marker prefix still counts as a binding failure (the marker itself is
18
+ * the fact that matters) with a generic reason substituted.
19
+ */
20
+ export declare function parseFetchBindingFailureLine(line: string): {
21
+ readonly reason: string;
22
+ } | null;
20
23
  export type { CapturedRequest };
21
- export { REQUEST_MARKER };
24
+ export { REQUEST_MARKER, FETCH_BINDING_FAILURE_MARKER };
22
25
  //# sourceMappingURL=request-line-parser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"request-line-parser.d.ts","sourceRoot":"","sources":["../src/request-line-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAsB3E;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAcrE;AAED,YAAY,EAAE,eAAe,EAAE,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"request-line-parser.d.ts","sourceRoot":"","sources":["../src/request-line-parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,4BAA4B,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAmBzG;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAarE;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAS7F;AAED,YAAY,EAAE,eAAe,EAAE,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,4BAA4B,EAAE,CAAC"}
@@ -1,14 +1,10 @@
1
1
  /**
2
- * Reads one process-output line for the `REQUEST_MARKER` prefix.
3
- *
4
- * The marker comes from `request-marker.ts`, never from
5
- * `fetch-instrumentation.ts` — importing the emitter to get a string would
6
- * patch the parsing process's own `globalThis.fetch`. See `request-marker.ts`
7
- * for the measurement. Everything else — the application's own real
8
- * stdout/stderr — is not this parser's concern and is left alone; an
9
- * external-request collector does not also try to be a log collector.
2
+ * Reads one process-output line for the `REQUEST_MARKER` prefix. The
3
+ * marker comes from `request-marker.ts`, never `fetch-instrumentation.ts`
4
+ * — importing the emitter would patch the parsing process's own fetch.
5
+ * Everything else (the app's real stdout/stderr) is left alone.
10
6
  */
11
- import { REQUEST_MARKER } from "./request-marker.js";
7
+ import { REQUEST_MARKER, FETCH_BINDING_FAILURE_MARKER } from "./request-marker.js";
12
8
  function isCapturedRequest(value) {
13
9
  if (typeof value !== "object" || value === null)
14
10
  return false;
@@ -23,22 +19,17 @@ function isCapturedRequest(value) {
23
19
  return false;
24
20
  if (typeof v.requestHeaders !== "object" || v.requestHeaders === null)
25
21
  return false;
26
- // `stack` is the one field allowed to be absent. A marker line written by a
27
- // preload from before call-site capture existed is a well-formed line that
28
- // genuinely carries no stack -- normalised to `null` below, which is what
29
- // "no stack was captured" already means everywhere downstream. Anything
30
- // present but not a string is malformed and refused, same as every other
31
- // field here.
22
+ // `stack` is the one field allowed to be absent (a pre-capture marker
23
+ // line genuinely carries none) — normalised to `null` below. Present but
24
+ // not a string is malformed and refused like every other field.
32
25
  if (v.stack !== undefined && v.stack !== null && typeof v.stack !== "string")
33
26
  return false;
34
27
  return Object.values(v.requestHeaders).every((value) => typeof value === "string");
35
28
  }
36
29
  /**
37
- * `null` for a non-matching line (ordinary application output) AND for a
38
- * line that starts with the marker but fails to parse as one of this
39
- * package's own captured requests — a malformed marker line is refused,
40
- * never guessed at, the same distinction `parseQueryLine`
41
- * (`@descryy/runtime-database-observation`) makes.
30
+ * `null` for a non-matching line AND for a marker-prefixed line that fails
31
+ * to parse — malformed is refused, never guessed at, same as
32
+ * `parseQueryLine` (`@descryy/runtime-database-observation`).
42
33
  */
43
34
  export function parseRequestLine(line) {
44
35
  if (!line.startsWith(`${REQUEST_MARKER} `))
@@ -53,10 +44,27 @@ export function parseRequestLine(line) {
53
44
  }
54
45
  if (!isCapturedRequest(parsed))
55
46
  return null;
56
- // Absent `stack` becomes an explicit `null` so no consumer has to
57
- // distinguish "the field was missing" from "nothing was captured" -- they
58
- // are the same fact and only one of them is representable downstream.
47
+ // Absent `stack` becomes explicit `null` — "missing" and "not captured"
48
+ // are the same fact downstream.
59
49
  return { ...parsed, stack: parsed.stack ?? null };
60
50
  }
61
- export { REQUEST_MARKER };
51
+ /**
52
+ * C-F6: recognises the preload's disclosure that it found no real
53
+ * `globalThis.fetch`. `null` for every other line. A malformed line past
54
+ * the marker prefix still counts as a binding failure (the marker itself is
55
+ * the fact that matters) with a generic reason substituted.
56
+ */
57
+ export function parseFetchBindingFailureLine(line) {
58
+ if (!line.startsWith(`${FETCH_BINDING_FAILURE_MARKER} `))
59
+ return null;
60
+ const json = line.slice(FETCH_BINDING_FAILURE_MARKER.length + 1);
61
+ try {
62
+ const parsed = JSON.parse(json);
63
+ return { reason: typeof parsed.reason === "string" ? parsed.reason : "no real globalThis.fetch was found to instrument" };
64
+ }
65
+ catch {
66
+ return { reason: "no real globalThis.fetch was found to instrument" };
67
+ }
68
+ }
69
+ export { REQUEST_MARKER, FETCH_BINDING_FAILURE_MARKER };
62
70
  //# sourceMappingURL=request-line-parser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"request-line-parser.js","sourceRoot":"","sources":["../src/request-line-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,cAAc,EAAwB,MAAM,qBAAqB,CAAC;AAI3E,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,KAAgC,CAAC;IAC3C,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5E,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACrF,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACpE,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClE,IAAI,OAAO,CAAC,CAAC,cAAc,KAAK,QAAQ,IAAI,CAAC,CAAC,cAAc,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACpF,4EAA4E;IAC5E,2EAA2E;IAC3E,0EAA0E;IAC1E,wEAAwE;IACxE,yEAAyE;IACzE,cAAc;IACd,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC3F,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,cAAyC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;AAChH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,cAAc,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,kEAAkE;IAClE,0EAA0E;IAC1E,sEAAsE;IACtE,OAAO,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;AACpD,CAAC;AAGD,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"request-line-parser.js","sourceRoot":"","sources":["../src/request-line-parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,4BAA4B,EAAwB,MAAM,qBAAqB,CAAC;AAIzG,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,KAAgC,CAAC;IAC3C,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5E,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACrF,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACpE,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClE,IAAI,OAAO,CAAC,CAAC,cAAc,KAAK,QAAQ,IAAI,CAAC,CAAC,cAAc,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACpF,sEAAsE;IACtE,yEAAyE;IACzE,gEAAgE;IAChE,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC3F,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,cAAyC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;AAChH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,cAAc,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5C,wEAAwE;IACxE,gCAAgC;IAChC,OAAO,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,IAAY;IACvD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,4BAA4B,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACtE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,4BAA4B,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACjE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAyB,CAAC;QACxD,OAAO,EAAE,MAAM,EAAE,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,kDAAkD,EAAE,CAAC;IAC5H,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,kDAAkD,EAAE,CAAC;IACxE,CAAC;AACH,CAAC;AAGD,OAAO,EAAE,cAAc,EAAE,4BAA4B,EAAE,CAAC"}
@@ -1,50 +1,37 @@
1
1
  /**
2
- * The wire vocabulary shared by the two halves of external-service
3
- * observation: the marker prefix and the shape that follows it.
4
- *
5
- * This module exists to be **free of side effects**, and that is its entire
6
- * job. `fetch-instrumentation.ts` — the other holder of these names until now
7
- * — replaces `globalThis.fetch` at module scope and writes to stdout, which
8
- * is right for a `--import` preload inside an observed process and wrong
9
- * everywhere else. `request-line-parser.ts` needed nothing from it but the
10
- * string `"DESCRY_EXTERNAL_REQUEST"`, and importing a string is still
11
- * importing a module: the patch and the stdout writer came along, through the
12
- * package index, into every consumer.
13
- *
14
- * **This is `query-marker.ts`'s defect, one package over, and it was still
15
- * open.** `@descryy/runtime-database-observation` found the identical shape,
16
- * measured it into `@descryy/mcp`'s JSON-RPC transport — 14,906 marker lines
17
- * in one `analyze` call — and carved the vocabulary out. Nothing did the same
18
- * here, and nothing noticed, because nothing outside this repository imports
19
- * this package yet. `observe_runtime` consuming this collector is precisely
20
- * the change that would have noticed.
21
- *
22
- * So: the emitter imports the vocabulary, the parser imports the vocabulary,
23
- * and neither imports the other. Anything added here must stay a constant or
24
- * a type. A function with a module-scope effect would rebuild the same trap
25
- * one file over.
2
+ * The wire vocabulary shared by both halves of external-service observation:
3
+ * marker prefix + shape. Must stay free of side effects — a function with a
4
+ * module-scope effect (like `fetch-instrumentation.ts`'s fetch patch) would
5
+ * leak into every consumer that only needs the vocabulary. This is
6
+ * `query-marker.ts`'s defect (measured: 14,906 marker lines through
7
+ * `@descryy/mcp`'s JSON-RPC transport in one `analyze` call), carved out
8
+ * here before anything hit it the same way.
26
9
  */
27
10
  export declare const REQUEST_MARKER = "DESCRY_EXTERNAL_REQUEST";
11
+ /**
12
+ * C-F6: written once, by `fetch-instrumentation.ts`, when `globalThis.fetch`
13
+ * wasn't a real function at preload time — a distinct line from
14
+ * `REQUEST_MARKER`, since nothing was actually observed. Without this, a
15
+ * missing real `fetch` would surface as an ordinary failure indistinguishable
16
+ * from a real network error, and `capabilities()` would claim "available"
17
+ * when zero calls were ever seen.
18
+ */
19
+ export declare const FETCH_BINDING_FAILURE_MARKER = "DESCRY_EXTERNAL_REQUEST_FETCH_BINDING_FAILED";
28
20
  export interface CapturedRequest {
29
21
  readonly url: string;
30
22
  readonly method: string;
31
23
  readonly requestHeaders: Readonly<Record<string, string>>;
32
- /** `null` only when `success` is `false` -- the call never resolved to a response at all. */
24
+ /** `null` only when `success` is `false` — the call never resolved to a response. */
33
25
  readonly status: number | null;
34
26
  readonly durationMs: number;
35
- /** `true` iff `fetch` resolved rather than threw. An HTTP error status (4xx/5xx) is still `success: true` -- fetch itself does not reject on one. */
27
+ /** `true` iff `fetch` resolved rather than threw. A 4xx/5xx status is still `success: true` — fetch doesn't reject on one. */
36
28
  readonly success: boolean;
37
29
  readonly error: string | null;
38
30
  /**
39
- * The **application's** own stack at the moment it called `fetch`, raw and
40
- * unparsed, with the preload's own wrapper frames removed. `null` when the
41
- * runtime produced no stack at all, or when nothing but the preload's own
42
- * frames was in it.
43
- *
44
- * Raw text on purpose: parsing V8's format is
45
- * `@descryy/runtime-adapter-typescript`'s job and belongs in the observing
46
- * process, the same read-here/interpret-there split every marker in this
47
- * repository already uses.
31
+ * The application's own stack at the `fetch` call, raw and unparsed, with
32
+ * the preload's wrapper frames removed. `null` if the runtime produced no
33
+ * stack. Raw text on purpose — parsing V8's format belongs in the
34
+ * observing process (`@descryy/runtime-adapter-typescript`), not here.
48
35
  */
49
36
  readonly stack: string | null;
50
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"request-marker.d.ts","sourceRoot":"","sources":["../src/request-marker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAOH,eAAO,MAAM,cAAc,4BAA8C,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,6FAA6F;IAC7F,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qJAAqJ;IACrJ,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B"}
1
+ {"version":3,"file":"request-marker.d.ts","sourceRoot":"","sources":["../src/request-marker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,eAAO,MAAM,cAAc,4BAA8C,CAAC;AAE1E;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,iDAAmE,CAAC;AAE7G,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,qFAAqF;IACrF,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,8HAA8H;IAC9H,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B"}
@@ -1,32 +1,23 @@
1
1
  /**
2
- * The wire vocabulary shared by the two halves of external-service
3
- * observation: the marker prefix and the shape that follows it.
4
- *
5
- * This module exists to be **free of side effects**, and that is its entire
6
- * job. `fetch-instrumentation.ts` — the other holder of these names until now
7
- * — replaces `globalThis.fetch` at module scope and writes to stdout, which
8
- * is right for a `--import` preload inside an observed process and wrong
9
- * everywhere else. `request-line-parser.ts` needed nothing from it but the
10
- * string `"DESCRY_EXTERNAL_REQUEST"`, and importing a string is still
11
- * importing a module: the patch and the stdout writer came along, through the
12
- * package index, into every consumer.
13
- *
14
- * **This is `query-marker.ts`'s defect, one package over, and it was still
15
- * open.** `@descryy/runtime-database-observation` found the identical shape,
16
- * measured it into `@descryy/mcp`'s JSON-RPC transport — 14,906 marker lines
17
- * in one `analyze` call — and carved the vocabulary out. Nothing did the same
18
- * here, and nothing noticed, because nothing outside this repository imports
19
- * this package yet. `observe_runtime` consuming this collector is precisely
20
- * the change that would have noticed.
21
- *
22
- * So: the emitter imports the vocabulary, the parser imports the vocabulary,
23
- * and neither imports the other. Anything added here must stay a constant or
24
- * a type. A function with a module-scope effect would rebuild the same trap
25
- * one file over.
2
+ * The wire vocabulary shared by both halves of external-service observation:
3
+ * marker prefix + shape. Must stay free of side effects — a function with a
4
+ * module-scope effect (like `fetch-instrumentation.ts`'s fetch patch) would
5
+ * leak into every consumer that only needs the vocabulary. This is
6
+ * `query-marker.ts`'s defect (measured: 14,906 marker lines through
7
+ * `@descryy/mcp`'s JSON-RPC transport in one `analyze` call), carved out
8
+ * here before anything hit it the same way.
26
9
  */
27
10
  import { RESERVED_MARKER_PREFIX } from "@descryy/runtime-contracts";
28
- // Derived, not spelled again: `RESERVED_MARKER_PREFIX` is what the
29
- // backend log collector skips on, so a marker that did not use it would
30
- // come back as the application's own log output.
11
+ // Derived from `RESERVED_MARKER_PREFIX`, which the backend log collector
12
+ // skips on — a marker not using it would look like app log output.
31
13
  export const REQUEST_MARKER = `${RESERVED_MARKER_PREFIX}EXTERNAL_REQUEST`;
14
+ /**
15
+ * C-F6: written once, by `fetch-instrumentation.ts`, when `globalThis.fetch`
16
+ * wasn't a real function at preload time — a distinct line from
17
+ * `REQUEST_MARKER`, since nothing was actually observed. Without this, a
18
+ * missing real `fetch` would surface as an ordinary failure indistinguishable
19
+ * from a real network error, and `capabilities()` would claim "available"
20
+ * when zero calls were ever seen.
21
+ */
22
+ export const FETCH_BINDING_FAILURE_MARKER = `${RESERVED_MARKER_PREFIX}EXTERNAL_REQUEST_FETCH_BINDING_FAILED`;
32
23
  //# sourceMappingURL=request-marker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"request-marker.js","sourceRoot":"","sources":["../src/request-marker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEpE,mEAAmE;AACnE,wEAAwE;AACxE,iDAAiD;AACjD,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,sBAAsB,kBAAkB,CAAC"}
1
+ {"version":3,"file":"request-marker.js","sourceRoot":"","sources":["../src/request-marker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEpE,yEAAyE;AACzE,mEAAmE;AACnE,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,sBAAsB,kBAAkB,CAAC;AAE1E;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,sBAAsB,uCAAuC,CAAC"}
@@ -1,21 +1,9 @@
1
1
  /**
2
- * A captured request's "service identity" — the checklist's §18 own
3
- * `service identity` row — is its URL's hostname, and nothing more.
4
- *
5
- * **Declared, never inferred.** This does not attempt to recognise "this
6
- * hostname is Stripe" or classify a call into `authentication provider` /
7
- * `payment provider` / etc. (§18's own "Potential integrations" list) —
8
- * that would be a lookup table of well-known hosts this project has no
9
- * source of truth for, guessed rather than read off anything the
10
- * application declared. The hostname is a real, observed fact; a provider
11
- * label would not be. If a consumer wants a friendlier name for a known
12
- * host, that is a later, disclosed classification step layered on top of
13
- * this, not something this function silently does.
14
- *
15
- * `null` for a URL that does not parse — refused rather than guessed, the
16
- * same shape `extractTargetTable`
17
- * (`@descryy/runtime-database-observation`) refuses a SQL statement it does
18
- * not recognise.
2
+ * A captured request's "service identity" is its URL's hostname, nothing
3
+ * more. Never classified into "Stripe" / "payment provider" etc — no
4
+ * source of truth for that, and a guessed label isn't an observed fact.
5
+ * `null` for a URL that doesn't parse — refused rather than guessed, same
6
+ * as `extractTargetTable` (`@descryy/runtime-database-observation`).
19
7
  */
20
8
  export declare function extractServiceIdentity(url: string): string | null;
21
9
  //# sourceMappingURL=service-identity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"service-identity.d.ts","sourceRoot":"","sources":["../src/service-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMjE"}
1
+ {"version":3,"file":"service-identity.d.ts","sourceRoot":"","sources":["../src/service-identity.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMjE"}
@@ -1,21 +1,9 @@
1
1
  /**
2
- * A captured request's "service identity" — the checklist's §18 own
3
- * `service identity` row — is its URL's hostname, and nothing more.
4
- *
5
- * **Declared, never inferred.** This does not attempt to recognise "this
6
- * hostname is Stripe" or classify a call into `authentication provider` /
7
- * `payment provider` / etc. (§18's own "Potential integrations" list) —
8
- * that would be a lookup table of well-known hosts this project has no
9
- * source of truth for, guessed rather than read off anything the
10
- * application declared. The hostname is a real, observed fact; a provider
11
- * label would not be. If a consumer wants a friendlier name for a known
12
- * host, that is a later, disclosed classification step layered on top of
13
- * this, not something this function silently does.
14
- *
15
- * `null` for a URL that does not parse — refused rather than guessed, the
16
- * same shape `extractTargetTable`
17
- * (`@descryy/runtime-database-observation`) refuses a SQL statement it does
18
- * not recognise.
2
+ * A captured request's "service identity" is its URL's hostname, nothing
3
+ * more. Never classified into "Stripe" / "payment provider" etc — no
4
+ * source of truth for that, and a guessed label isn't an observed fact.
5
+ * `null` for a URL that doesn't parse — refused rather than guessed, same
6
+ * as `extractTargetTable` (`@descryy/runtime-database-observation`).
19
7
  */
20
8
  export function extractServiceIdentity(url) {
21
9
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"service-identity.js","sourceRoot":"","sources":["../src/service-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAW;IAChD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"service-identity.js","sourceRoot":"","sources":["../src/service-identity.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAW;IAChD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "@descryy/runtime-external-service-observation",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
- "description": "External service observation (plan \u00a718, checklist \u00a718): real EXTERNAL_REQUEST capture via client instrumentation, never parsed application logs. Client #1 is the global fetch.",
5
+ "description": "External service observation (plan §18, checklist §18): real EXTERNAL_REQUEST capture via client instrumentation, never parsed application logs. Client #1 is the global fetch.",
6
6
  "license": "UNLICENSED",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/descryhq-wq/descry-runtime.git",
10
+ "directory": "packages/external-service-observation"
11
+ },
7
12
  "engines": {
8
13
  "node": ">=22.5"
9
14
  },
@@ -24,8 +29,8 @@
24
29
  "build": "tsc -b"
25
30
  },
26
31
  "dependencies": {
27
- "@descryy/runtime-contracts": "0.2.0",
28
- "@descryy/runtime-backend-observation": "0.2.0"
32
+ "@descryy/runtime-contracts": "0.3.1",
33
+ "@descryy/runtime-backend-observation": "0.3.1"
29
34
  },
30
35
  "devDependencies": {
31
36
  "@descryy/runtime-controller": "*",