@descryy/runtime-browser 0.3.0 → 0.4.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.
package/LICENSE ADDED
@@ -0,0 +1,6 @@
1
+ Copyright (c) Descry
2
+
3
+ All rights reserved. This software is proprietary and confidential.
4
+ No license, express or implied, to reproduce, distribute, modify, or
5
+ create derivative works is granted except as explicitly agreed in
6
+ writing.
@@ -1,18 +1,12 @@
1
1
  /**
2
- * §8's console evidence bucket (level · message · stack if present ·
3
- * timestamp) plus page errors -- uncaught exceptions in the page's own JS,
4
- * captured via Playwright's `pageerror` event. Both ride the same
5
- * `EvidenceSource: "browser-console"` bucket the contracts already name.
2
+ * §8 console evidence (level/message/stack/timestamp) plus page errors --
3
+ * uncaught JS exceptions via Playwright's `pageerror` event. Both use the
4
+ * `EvidenceSource: "browser-console"` bucket.
6
5
  *
7
- * Page-error stack text is preserved verbatim in `payload.stack` (plan §9:
8
- * "the runtime must preserve the original observation") but NOT
9
- * structurally parsed into `StackTrace` frames with resolved
10
- * `SourceLocation`s in V1 -- reflected honestly in `capabilities()`
11
- * (`stackCapture`/`sourceMapping`: unavailable), not silently produced as
12
- * a lesser version. Doing that for real would need mapping the browser's
13
- * `http://` script URLs back to on-disk files via the frontend's static
14
- * file server root, which this collector has no way to know -- a real,
15
- * separate feature, not built here.
6
+ * Page-error stack text is preserved verbatim (§9: preserve the original
7
+ * observation) but without a parser is not structurally parsed into
8
+ * `StackTrace` frames -- reflected honestly in `capabilities()`
9
+ * (`stackCapture`/`sourceMapping`: unavailable), not silently downgraded.
16
10
  */
17
11
  import type { Collector } from "@descryy/runtime-contracts";
18
12
  import type { StackTraceParser } from "@descryy/runtime-backend-observation";
@@ -21,11 +15,9 @@ export interface BrowserConsoleCollectorOptions {
21
15
  readonly session: BrowserSession;
22
16
  readonly service?: string;
23
17
  /**
24
- * Injected, never constructed here — a browser page runs JavaScript, but
25
- * this package stays language-neutral the same way `LogCollector` does:
26
- * whoever wires the collector supplies the parser for the runtime it is
27
- * actually watching. Omit it and page-error stacks are preserved as text
28
- * exactly as before, with `capabilities()` saying so.
18
+ * Injected, never constructed here -- stays language-neutral like
19
+ * `LogCollector`. Omit it and stacks are preserved as text, with
20
+ * `capabilities()` saying so.
29
21
  */
30
22
  readonly stackTraceParser?: StackTraceParser;
31
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"browser-console-collector.d.ts","sourceRoot":"","sources":["../src/browser-console-collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAqF,MAAM,4BAA4B,CAAC;AAG/I,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAE7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAI3D,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CAC9C;AAmDD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,8BAA8B,GAAG,SAAS,CA8HhG"}
1
+ {"version":3,"file":"browser-console-collector.d.ts","sourceRoot":"","sources":["../src/browser-console-collector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAqF,MAAM,4BAA4B,CAAC;AAG/I,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAE7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAI3D,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CAC9C;AAgDD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,8BAA8B,GAAG,SAAS,CAgHhG"}
@@ -1,18 +1,12 @@
1
1
  /**
2
- * §8's console evidence bucket (level · message · stack if present ·
3
- * timestamp) plus page errors -- uncaught exceptions in the page's own JS,
4
- * captured via Playwright's `pageerror` event. Both ride the same
5
- * `EvidenceSource: "browser-console"` bucket the contracts already name.
2
+ * §8 console evidence (level/message/stack/timestamp) plus page errors --
3
+ * uncaught JS exceptions via Playwright's `pageerror` event. Both use the
4
+ * `EvidenceSource: "browser-console"` bucket.
6
5
  *
7
- * Page-error stack text is preserved verbatim in `payload.stack` (plan §9:
8
- * "the runtime must preserve the original observation") but NOT
9
- * structurally parsed into `StackTrace` frames with resolved
10
- * `SourceLocation`s in V1 -- reflected honestly in `capabilities()`
11
- * (`stackCapture`/`sourceMapping`: unavailable), not silently produced as
12
- * a lesser version. Doing that for real would need mapping the browser's
13
- * `http://` script URLs back to on-disk files via the frontend's static
14
- * file server root, which this collector has no way to know -- a real,
15
- * separate feature, not built here.
6
+ * Page-error stack text is preserved verbatim (§9: preserve the original
7
+ * observation) but without a parser is not structurally parsed into
8
+ * `StackTrace` frames -- reflected honestly in `capabilities()`
9
+ * (`stackCapture`/`sourceMapping`: unavailable), not silently downgraded.
16
10
  */
17
11
  import { primaryFrameLocation } from "@descryy/runtime-contracts";
18
12
  import { extractCorrelationIds } from "@descryy/runtime-backend-observation";
@@ -43,15 +37,12 @@ const CAPABILITIES = {
43
37
  externalServiceObservation: notThisCollectorsJob("external service observation"),
44
38
  };
45
39
  /**
46
- * RT-023 landed: with a parser injected and `CollectorContext.resolveSourceRoot`
47
- * present, page-error stacks are parsed and their `http://` script URLs are
48
- * rewritten to on-disk paths.
40
+ * RT-023: with a parser injected and `resolveSourceRoot` present,
41
+ * page-error stacks are parsed and script URLs rewritten to on-disk paths.
49
42
  *
50
- * `sourceMapping` stays **degraded**, not available, and the distinction is
51
- * load-bearing: the origin-to-root lookup proves the origin maps to a
52
- * configured directory, not that the file the browser executed came from
53
- * the checkout in it (`declaredCwd` is named for exactly that). A script
54
- * this execution did not serve — a CDN, an extension — is left as a URL.
43
+ * `sourceMapping` stays degraded, not available: the lookup proves the
44
+ * origin maps to a configured directory, not that the executed file came
45
+ * from that checkout. A script this execution didn't serve is left as URL.
55
46
  */
56
47
  const CAPABILITIES_WITH_STACKS = {
57
48
  ...CAPABILITIES,
@@ -73,15 +64,11 @@ export function createBrowserConsoleCollector(options) {
73
64
  /**
74
65
  * In-flight `onPageError` handlers.
75
66
  *
76
- * Parsing a stack is asynchronous, and Playwright's `pageerror` listener
77
- * is not — so the handler starts work and returns, and `stop()` used to
78
- * clear `emit` out from under it. Any page error whose parse had not
79
- * finished was **silently deleted**: `emit?.()` on an undefined `emit` is
80
- * a no-op, and nothing recorded that an observation had been dropped.
81
- * `stop()` is called at the end of every execution, which is precisely
82
- * when a page's last error arrives, so this was not a rare window.
83
- *
84
- * `stop()` now drains this set before clearing `emit`.
67
+ * Parsing is async but Playwright's `pageerror` listener isn't, so
68
+ * `stop()` used to clear `emit` while a parse was still running --
69
+ * `emit?.()` on undefined is a silent no-op, dropping the page's last
70
+ * error every time (stop() runs right when it arrives). `stop()` now
71
+ * drains this set first.
85
72
  */
86
73
  const inFlight = new Set();
87
74
  function onConsole(msg) {
@@ -122,23 +109,18 @@ export function createBrowserConsoleCollector(options) {
122
109
  eventType: "EXCEPTION",
123
110
  payload: {
124
111
  message: error.message,
125
- // The browser's own text, always, whatever the mapping did to it
126
- // (plan §9: preserve the original observation).
112
+ // raw browser text, unchanged by the mapping (§9: preserve the original observation).
127
113
  stack: rawStack,
128
114
  browserSessionId: session.sessionId,
129
- // Per-URL outcomes rather than a boolean: "three scripts, two
130
- // mapped, one is a CDN" is a coverage statement, and collapsing
131
- // it would imply the unmapped one simply was not there.
115
+ // per-URL outcomes, not a boolean -- collapsing would hide the partially-mapped case.
132
116
  ...(mapping !== null ? { scriptUrlMapping: mapping.outcomes } : {}),
133
117
  },
134
118
  traceId: null,
135
119
  requestId: null,
136
120
  correlationId: null,
137
121
  graphNodeId: null,
138
- // Was its own `frames[0]` copy of a rule `backend-observation` had
139
- // already moved onto `primaryFrameIndex` (RT-083). The two agreed
140
- // only because V8 reports index 0 — a coincidence, not a shared
141
- // rule. The full chain is in stackTrace either way.
122
+ // backend-observation moved to primaryFrameIndex (RT-083); frames[0] agreement was
123
+ // coincidence (V8 reports index 0), not a shared rule. Full chain is in stackTrace either way.
142
124
  sourceLocation: primaryFrameLocation(stackTrace),
143
125
  stackTrace,
144
126
  confidence: 1,
@@ -157,9 +139,7 @@ export function createBrowserConsoleCollector(options) {
157
139
  }
158
140
  emit = context.emit;
159
141
  resolveSourceRoot = context.resolveSourceRoot;
160
- // Both halves or neither: a parser with no way to map URLs would
161
- // produce frames pointing at http:// locations nothing can open, and
162
- // a mapper with no parser has nothing to map.
142
+ // both halves or neither: a parser without a mapper points at http:// nothing can open, and a mapper without a parser has nothing to map.
163
143
  stacksParsed = options.stackTraceParser !== undefined && context.resolveSourceRoot !== undefined;
164
144
  page.on("console", onConsole);
165
145
  page.on("pageerror", onPageError);
@@ -169,11 +149,8 @@ export function createBrowserConsoleCollector(options) {
169
149
  // Listeners off first, so nothing new joins the set while it drains.
170
150
  page.off("console", onConsole);
171
151
  page.off("pageerror", onPageError);
172
- // Then drain, THEN clear `emit` — in that order. Clearing first is
173
- // what silently deleted the last page error of every execution.
174
- // `allSettled`: a handler that threw has already failed on its own
175
- // terms, and stop() refusing to complete because of it would take the
176
- // rest of the run's evidence down with it.
152
+ // drain then clear emit -- clearing first silently dropped the last page error.
153
+ // allSettled: a handler that threw already failed on its own terms and shouldn't block the rest.
177
154
  await Promise.allSettled([...inFlight]);
178
155
  emit = undefined;
179
156
  },
@@ -1 +1 @@
1
- {"version":3,"file":"browser-console-collector.js","sourceRoot":"","sources":["../src/browser-console-collector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser-console-collector.js","sourceRoot":"","sources":["../src/browser-console-collector.ts"],"names":[],"mappings":"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"}
@@ -1,35 +1,21 @@
1
1
  /**
2
- * §7's launch / isolated context / page creation, as a thin wrapper over
3
- * Playwright (see `documents/decisions-inbox/PROPOSAL-B-playwright-for-
4
- * browser-runtime.md` for why Playwright over raw CDP). One
5
- * `BrowserSession` = one Playwright `BrowserContext` (Playwright's own
6
- * isolation unit -- separate cookies/storage/cache per context) plus its
7
- * one page, which is what plan §7's "isolated context/session · page
8
- * creation" already asks for; nothing here re-derives isolation Playwright
9
- * already gives structurally.
2
+ * §7 launch/isolated-context/page creation, a thin wrapper over Playwright
3
+ * (see PROPOSAL-B-playwright-for-browser-runtime.md for why Playwright over
4
+ * raw CDP). One `BrowserSession` = one Playwright `BrowserContext` (its own
5
+ * isolation unit) plus its one page.
10
6
  *
11
- * Deliberately does NOT itself turn browser-session launch into Evidence.
12
- * `BrowserSessionHandle` (`execution.ts`) already carries `sessionId` /
13
- * `targetUrl` / `startedAt` / `endedAt` structurally on `Execution`, the
14
- * same relationship `ProcessHandle` has to process lifecycle --
15
- * `backend-observation/collector.ts` declared that an equivalent non-goal
16
- * for `ProcessCollector`, for the identical reason: whether session
17
- * lifecycle becomes Evidence at all is an orchestration-layer question,
18
- * not this seam's. Both non-goals now have an answer, in each package's
19
- * own collector — `createProcessCollector` (`@descryy/runtime-controller`)
20
- * and `BrowserActionCollector.start()` (`browser-action-collector.ts`,
21
- * PAGE_CREATED) — never here. `startedAt` is captured below only so that
22
- * answer has a real creation timestamp to report rather than "whenever a
23
- * collector got around to starting."
7
+ * Deliberately does NOT turn session launch into Evidence -- that's a
8
+ * collector's job (`createProcessCollector` for process lifecycle;
9
+ * `BrowserActionCollector.start()`'s PAGE_CREATED for this), never this
10
+ * module's. `startedAt` is captured below only so that answer has a real
11
+ * creation timestamp to report.
24
12
  */
25
13
  import { type Page } from "playwright-core";
26
14
  import type { BrowserConfiguration } from "@descryy/runtime-contracts";
27
15
  /**
28
- * RT-068: this used to be its own interface, declared independently of
29
- * `ExecutionConfiguration.browser`. Two shapes with the same one field would
30
- * have been exactly the "parallel copy that could drift" this codebase
31
- * already refuses elsewhere (see `InstrumentedExecutionInput.execution`'s
32
- * own comment) -- so this is the contracts type, not a look-alike of it.
16
+ * RT-068: this is the contracts type (`BrowserConfiguration`), not a
17
+ * look-alike declared independently of `ExecutionConfiguration.browser` --
18
+ * two shapes with the same field would drift.
33
19
  */
34
20
  export type BrowserSessionOptions = BrowserConfiguration;
35
21
  export interface BrowserSession {
@@ -39,64 +25,47 @@ export interface BrowserSession {
39
25
  readonly startedAt: string;
40
26
  /**
41
27
  * False once the page has crashed or closed. Every collector's `start()`
42
- * consults this before reporting `{available: true}` -- `page.isClosed()`
43
- * alone is not sufficient: verified directly that it still reports
44
- * `false` after a real `chrome://crash`, so a collector checking only
45
- * `isClosed()` would report itself available against a page that can no
46
- * longer run a single action. The `'crash'` event is the only signal
47
- * that actually fires for that case, so it's tracked here once, for
48
- * every collector sharing this session, rather than each collector
49
- * re-attaching its own listener.
28
+ * checks this before reporting available -- `page.isClosed()` alone
29
+ * isn't enough: verified that it still returns false after a real
30
+ * `chrome://crash`. Tracked once here via the `'crash'` event, shared
31
+ * across every collector on this session.
50
32
  */
51
33
  isUsable(): boolean;
52
34
  close(): Promise<void>;
53
35
  /**
54
- * The finished `recordVideo` file's bytes, or `null` when this session was
55
- * never launched with `recordVideo: true`.
36
+ * The finished `recordVideo` file's bytes, or `null` if this session
37
+ * wasn't launched with `recordVideo: true`.
56
38
  *
57
- * **Still deliberately not Evidence** -- same non-goal this file's own
58
- * header already states for session launch, applied to session teardown:
59
- * turning a raw fact into Evidence is a collector's job
60
- * (`BrowserActionCollector.captureVideo()`), never this module's.
39
+ * Not Evidence -- same non-goal as session launch above; that's a
40
+ * collector's job (`BrowserActionCollector.captureVideo()`).
61
41
  *
62
- * **Must be called after `close()` has resolved.** Playwright's own
63
- * contract for `Video.path()` is that it does not resolve until the
64
- * browser context that recorded it has closed -- calling this first would
65
- * hang waiting for a close that this method does not itself trigger, so it
66
- * throws immediately instead of hanging on a caller's mistake.
42
+ * Must be called after `close()` resolves: `Video.path()` doesn't
43
+ * resolve until the context has closed, and this method doesn't trigger
44
+ * that close itself, so it throws immediately rather than hanging.
67
45
  *
68
- * Reads the file fully into memory and removes the temp directory it was
69
- * written to -- the same "whole file in memory" tradeoff `screenshot()`
70
- * already makes at a smaller scale (this module's sibling,
71
- * `browser-action-collector.ts`), and once the bytes are safely returned
72
- * here the on-disk copy has no further purpose.
46
+ * Reads the whole file into memory and removes the temp dir -- same
47
+ * tradeoff `screenshot()` makes at a smaller scale.
73
48
  */
74
49
  finishedVideo(): Promise<Uint8Array | null>;
75
50
  }
76
51
  /**
77
- * Why this exists, and why it is not a `throw`.
52
+ * Why this exists, and why it's not a throw.
78
53
  *
79
- * This package depends on `playwright-core`, not `playwright`. The two ship
80
- * the same driver; only `playwright` carries a postinstall that downloads
81
- * Chromium. That postinstall is transitive, so every install of a package
82
- * that has this one anywhere in its closure -- `@descryy/mcp`, whose users
83
- * overwhelmingly never call a browser tool -- paid several hundred megabytes
84
- * for a browser it would never launch. `playwright-core` removes the download
85
- * and, with it, the guarantee that a browser is present at all.
54
+ * This package depends on `playwright-core`, not `playwright` -- only
55
+ * `playwright`'s postinstall downloads Chromium, and that cost is
56
+ * transitive to everything depending on this package (e.g. `@descryy/mcp`,
57
+ * whose users mostly never call a browser tool): several hundred megabytes
58
+ * for a browser never launched. `playwright-core` drops the download and
59
+ * the guarantee a browser is present.
86
60
  *
87
- * So absence is now a normal, expected state rather than a broken install,
88
- * and it gets the shape this codebase already gives an expected inability:
89
- * `ServiceRootLookup`'s `{ found: false, refusal, message }` (contracts,
90
- * `source-root.ts`). One field is added to it -- `remedy` -- because the
91
- * caller mapping this onto a user-visible refusal must be able to print the
92
- * exact command rather than paraphrase it, and a remedy buried in prose is a
93
- * remedy the caller has to parse back out.
61
+ * So absence is a normal state, shaped like this codebase's other expected
62
+ * inabilities (`ServiceRootLookup`'s `{ found: false, refusal, message }`),
63
+ * plus a `remedy` field so a caller can print the exact fix rather than
64
+ * paraphrase it.
94
65
  *
95
- * The check is `existsSync` on the path `playwright-core` itself computes.
96
- * `chromium.executablePath()` does not verify existence -- it returns the
97
- * path this build *would* use, resolved against `PLAYWRIGHT_BROWSERS_PATH`
98
- * when that is set -- so the check and the launch below are handed the same
99
- * string, and cannot disagree about which binary was meant.
66
+ * Checked via `existsSync` on the path `playwright-core` itself computes --
67
+ * `chromium.executablePath()` doesn't verify existence, it returns the path
68
+ * this build would use, so the check and the launch below can't disagree.
100
69
  */
101
70
  export interface ChromiumUnavailable {
102
71
  readonly refusal: "chromiumNotInstalled";
@@ -120,10 +89,9 @@ export type BrowserSessionLaunch = {
120
89
  } & ChromiumUnavailable);
121
90
  export declare const CHROMIUM_INSTALL_REMEDY = "npx playwright install chromium";
122
91
  /**
123
- * Resolved at launch time, deliberately not at import time. A module-level
124
- * check would make merely importing this package fail on a machine with no
125
- * browser -- including for a consumer that imports it only to read a type,
126
- * which is the exact cost `playwright-core` was adopted to remove.
92
+ * Resolved at launch time, not import time -- a module-level check would
93
+ * fail merely importing this package on a machine with no browser, the
94
+ * exact cost `playwright-core` was adopted to remove.
127
95
  */
128
96
  export declare function resolveChromiumExecutable(): ChromiumAvailability;
129
97
  /** Thrown by `launchBrowserSession` when `resolveChromiumExecutable()` refuses. Carries the refusal whole, so a caller that catches rather than branching still gets the remedy. */
@@ -134,10 +102,10 @@ export declare class BrowserUnavailableError extends Error {
134
102
  constructor(unavailable: ChromiumUnavailable);
135
103
  }
136
104
  /**
137
- * The refusal-returning launch. Prefer this wherever a missing browser is a
138
- * reportable outcome rather than a bug -- an MCP tool mapping it onto its own
139
- * `refused` state, for instance. `launchBrowserSession` below is the same
140
- * call for callers that would only rethrow.
105
+ * Refusal-returning launch. Prefer this where a missing browser is a
106
+ * reportable outcome, not a bug (e.g. an MCP tool's `refused` state).
107
+ * `launchBrowserSession` below is the same call for callers that would
108
+ * only rethrow.
141
109
  */
142
110
  export declare function launchBrowserSessionOrRefuse(options?: BrowserSessionOptions): Promise<BrowserSessionLaunch>;
143
111
  export declare function launchBrowserSession(options?: BrowserSessionOptions): Promise<BrowserSession>;
@@ -1 +1 @@
1
- {"version":3,"file":"browser-session.d.ts","sourceRoot":"","sources":["../src/browser-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAA+C,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAMzF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,GAAG,oBAAoB,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,2JAA2J;IAC3J,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,QAAQ,IAAI,OAAO,CAAC;IACpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,aAAa,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gIAAgI;IAChI,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACzC;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAC7D,CAAC;IAAE,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAA;CAAE,GAAG,mBAAmB,CAAC,CAAC;AAE1D,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC7D,CAAC;IAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAA;CAAE,GAAG,mBAAmB,CAAC,CAAC;AAEzD,eAAO,MAAM,uBAAuB,oCAAoC,CAAC;AAEzE;;;;;GAKG;AACH,wBAAgB,yBAAyB,IAAI,oBAAoB,CAYhE;AAED,oLAAoL;AACpL,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;gBAE5B,WAAW,EAAE,mBAAmB;CAO7C;AAED;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAAC,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAOrH;AAED,wBAAsB,oBAAoB,CAAC,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,cAAc,CAAC,CAOvG"}
1
+ {"version":3,"file":"browser-session.d.ts","sourceRoot":"","sources":["../src/browser-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAA+C,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAMzF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,oBAAoB,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,2JAA2J;IAC3J,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,QAAQ,IAAI,OAAO,CAAC;IACpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB;;;;;;;;;;;;;OAaG;IACH,aAAa,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gIAAgI;IAChI,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACzC;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAC7D,CAAC;IAAE,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAA;CAAE,GAAG,mBAAmB,CAAC,CAAC;AAE1D,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;CAAE,GAC7D,CAAC;IAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAA;CAAE,GAAG,mBAAmB,CAAC,CAAC;AAEzD,eAAO,MAAM,uBAAuB,oCAAoC,CAAC;AAEzE;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,oBAAoB,CAYhE;AAED,oLAAoL;AACpL,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;gBAE5B,WAAW,EAAE,mBAAmB;CAO7C;AAED;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAAC,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAOrH;AAED,wBAAsB,oBAAoB,CAAC,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,cAAc,CAAC,CAOvG"}
@@ -1,26 +1,14 @@
1
1
  /**
2
- * §7's launch / isolated context / page creation, as a thin wrapper over
3
- * Playwright (see `documents/decisions-inbox/PROPOSAL-B-playwright-for-
4
- * browser-runtime.md` for why Playwright over raw CDP). One
5
- * `BrowserSession` = one Playwright `BrowserContext` (Playwright's own
6
- * isolation unit -- separate cookies/storage/cache per context) plus its
7
- * one page, which is what plan §7's "isolated context/session · page
8
- * creation" already asks for; nothing here re-derives isolation Playwright
9
- * already gives structurally.
2
+ * §7 launch/isolated-context/page creation, a thin wrapper over Playwright
3
+ * (see PROPOSAL-B-playwright-for-browser-runtime.md for why Playwright over
4
+ * raw CDP). One `BrowserSession` = one Playwright `BrowserContext` (its own
5
+ * isolation unit) plus its one page.
10
6
  *
11
- * Deliberately does NOT itself turn browser-session launch into Evidence.
12
- * `BrowserSessionHandle` (`execution.ts`) already carries `sessionId` /
13
- * `targetUrl` / `startedAt` / `endedAt` structurally on `Execution`, the
14
- * same relationship `ProcessHandle` has to process lifecycle --
15
- * `backend-observation/collector.ts` declared that an equivalent non-goal
16
- * for `ProcessCollector`, for the identical reason: whether session
17
- * lifecycle becomes Evidence at all is an orchestration-layer question,
18
- * not this seam's. Both non-goals now have an answer, in each package's
19
- * own collector — `createProcessCollector` (`@descryy/runtime-controller`)
20
- * and `BrowserActionCollector.start()` (`browser-action-collector.ts`,
21
- * PAGE_CREATED) — never here. `startedAt` is captured below only so that
22
- * answer has a real creation timestamp to report rather than "whenever a
23
- * collector got around to starting."
7
+ * Deliberately does NOT turn session launch into Evidence -- that's a
8
+ * collector's job (`createProcessCollector` for process lifecycle;
9
+ * `BrowserActionCollector.start()`'s PAGE_CREATED for this), never this
10
+ * module's. `startedAt` is captured below only so that answer has a real
11
+ * creation timestamp to report.
24
12
  */
25
13
  import { chromium } from "playwright-core";
26
14
  import { randomUUID } from "node:crypto";
@@ -30,10 +18,9 @@ import { tmpdir } from "node:os";
30
18
  import { join } from "node:path";
31
19
  export const CHROMIUM_INSTALL_REMEDY = "npx playwright install chromium";
32
20
  /**
33
- * Resolved at launch time, deliberately not at import time. A module-level
34
- * check would make merely importing this package fail on a machine with no
35
- * browser -- including for a consumer that imports it only to read a type,
36
- * which is the exact cost `playwright-core` was adopted to remove.
21
+ * Resolved at launch time, not import time -- a module-level check would
22
+ * fail merely importing this package on a machine with no browser, the
23
+ * exact cost `playwright-core` was adopted to remove.
37
24
  */
38
25
  export function resolveChromiumExecutable() {
39
26
  const executablePath = chromium.executablePath();
@@ -62,10 +49,10 @@ export class BrowserUnavailableError extends Error {
62
49
  }
63
50
  }
64
51
  /**
65
- * The refusal-returning launch. Prefer this wherever a missing browser is a
66
- * reportable outcome rather than a bug -- an MCP tool mapping it onto its own
67
- * `refused` state, for instance. `launchBrowserSession` below is the same
68
- * call for callers that would only rethrow.
52
+ * Refusal-returning launch. Prefer this where a missing browser is a
53
+ * reportable outcome, not a bug (e.g. an MCP tool's `refused` state).
54
+ * `launchBrowserSession` below is the same call for callers that would
55
+ * only rethrow.
69
56
  */
70
57
  export async function launchBrowserSessionOrRefuse(options = {}) {
71
58
  const chromiumBinary = resolveChromiumExecutable();
@@ -86,11 +73,8 @@ export async function launchBrowserSession(options = {}) {
86
73
  async function launchWithExecutable(options, executablePath) {
87
74
  const browser = await chromium.launch({ headless: options.headless ?? true, executablePath });
88
75
  const sessionId = randomUUID();
89
- // A session-scoped temp dir, never a caller-supplied path -- see
90
- // `BrowserConfiguration.recordVideo`'s own comment on why only the toggle
91
- // is exposed. Created before newContext() because Playwright's
92
- // `recordVideo.dir` must already exist and be known at context-creation
93
- // time; there is no way to attach recording after the fact.
76
+ // session-scoped temp dir, never caller-supplied (see BrowserConfiguration.recordVideo).
77
+ // created before newContext(): Playwright's recordVideo.dir must exist and be known at context-creation time.
94
78
  const videoDir = options.recordVideo === true ? await mkdtemp(join(tmpdir(), `descry-video-${sessionId}-`)) : null;
95
79
  const context = await browser.newContext(videoDir !== null ? { recordVideo: { dir: videoDir } } : {});
96
80
  const page = await context.newPage();
@@ -117,17 +101,13 @@ async function launchWithExecutable(options, executablePath) {
117
101
  "method does not itself perform). Call session.close() first.");
118
102
  }
119
103
  const video = page.video();
120
- // Should not happen given videoDir !== null above (recordVideo was
121
- // requested, so Playwright always attaches a Video to a page created
122
- // under that context) -- guarded rather than asserted with `!`,
123
- // because a null here would otherwise surface as a confusing crash
124
- // inside readFile(undefined) instead of a clear "nothing to return."
104
+ // shouldn't happen (recordVideo requested implies Playwright attaches a Video) -- guarded rather
105
+ // than asserted with `!`, since a null here would otherwise surface as a confusing crash.
125
106
  if (video === null)
126
107
  return null;
127
108
  const videoFilePath = await video.path();
128
109
  const bytes = await readFile(videoFilePath);
129
- // Best-effort: the bytes are already safely captured above, so a
130
- // cleanup failure here (e.g. already removed) must not fail the call.
110
+ // best-effort: bytes are already captured, so a cleanup failure here must not fail the call.
131
111
  await rm(videoDir, { recursive: true, force: true }).catch(() => { });
132
112
  return bytes;
133
113
  },
@@ -1 +1 @@
1
- {"version":3,"file":"browser-session.js","sourceRoot":"","sources":["../src/browser-session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser-session.js","sourceRoot":"","sources":["../src/browser-session.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,7 @@
1
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.
2
+ * `Evidence.collectorVersion` source: reads this package's own package.json
3
+ * "version" instead of a hand-duplicated string that can drift. Same idea
4
+ * as `nodeVersion` using `process.version`.
8
5
  */
9
6
  export declare const COLLECTOR_VERSION: string;
10
7
  //# 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;;;;;;;GAOG;AAMH,eAAO,MAAM,iBAAiB,EAAE,MAA6E,CAAC"}
1
+ {"version":3,"file":"collector-version.d.ts","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,eAAO,MAAM,iBAAiB,EAAE,MAA6E,CAAC"}
@@ -1,10 +1,7 @@
1
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.
2
+ * `Evidence.collectorVersion` source: reads this package's own package.json
3
+ * "version" instead of a hand-duplicated string that can drift. Same idea
4
+ * as `nodeVersion` using `process.version`.
8
5
  */
9
6
  import { createRequire } from "node:module";
10
7
  const require = createRequire(import.meta.url);
@@ -1 +1 @@
1
- {"version":3,"file":"collector-version.js","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,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
+ {"version":3,"file":"collector-version.js","sourceRoot":"","sources":["../src/collector-version.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,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,10 +1,7 @@
1
1
  /**
2
- * §8's DOM evidence bucket: "relevant element · selector/locator · text/
3
- * value when safe · accessibility information when useful." Captured
4
- * alongside an action (click/type/wait) rather than as its own streamed
5
- * event type -- the frozen `RuntimeEventType` vocabulary has no dedicated
6
- * DOM-snapshot type, and a DOM fact is naturally "what did the element
7
- * this action touched look like," not an independent stream.
2
+ * DOM evidence for an action (§8): element/selector/text/value/a11y info.
3
+ * Captured alongside the action, not as its own event type -- no dedicated
4
+ * DOM-snapshot type exists in `RuntimeEventType`.
8
5
  */
9
6
  import type { Page } from "playwright-core";
10
7
  export interface DomElementSnapshot {
@@ -1 +1 @@
1
- {"version":3,"file":"dom-evidence.d.ts","sourceRoot":"","sources":["../src/dom-evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,8FAA8F;IAC9F,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/C;AAWD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAetG"}
1
+ {"version":3,"file":"dom-evidence.d.ts","sourceRoot":"","sources":["../src/dom-evidence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,8FAA8F;IAC9F,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/C;AAWD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAetG"}
@@ -1,10 +1,7 @@
1
1
  /**
2
- * §8's DOM evidence bucket: "relevant element · selector/locator · text/
3
- * value when safe · accessibility information when useful." Captured
4
- * alongside an action (click/type/wait) rather than as its own streamed
5
- * event type -- the frozen `RuntimeEventType` vocabulary has no dedicated
6
- * DOM-snapshot type, and a DOM fact is naturally "what did the element
7
- * this action touched look like," not an independent stream.
2
+ * DOM evidence for an action (§8): element/selector/text/value/a11y info.
3
+ * Captured alongside the action, not as its own event type -- no dedicated
4
+ * DOM-snapshot type exists in `RuntimeEventType`.
8
5
  */
9
6
  const VALUE_BEARING_TAGS = new Set(["input", "textarea", "select"]);
10
7
  async function safeValue(locator, tagName) {
@@ -1 +1 @@
1
- {"version":3,"file":"dom-evidence.js","sourceRoot":"","sources":["../src/dom-evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAcH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEpE,KAAK,UAAU,SAAS,CAAC,OAAgB,EAAE,OAAsB;IAC/D,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACtE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACvE,IAAI,SAAS,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAAU,EAAE,QAAgB;IACvE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;IAC/C,MAAM,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC;IAC3F,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC3F,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,qBAAqB,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC7D,OAAO,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;QACvC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;QAC3B,OAAO,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;KACzC,CAAC,CAAC;IAEH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC;AACnE,CAAC"}
1
+ {"version":3,"file":"dom-evidence.js","sourceRoot":"","sources":["../src/dom-evidence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEpE,KAAK,UAAU,SAAS,CAAC,OAAgB,EAAE,OAAsB;IAC/D,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACtE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACvE,IAAI,SAAS,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAAU,EAAE,QAAgB;IACvE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;IAC/C,MAAM,OAAO,GAAG,CAAC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC;IAC3F,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC3F,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,qBAAqB,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC7D,OAAO,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;QACvC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;QAC3B,OAAO,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;KACzC,CAAC,CAAC;IAEH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC;AACnE,CAAC"}
@@ -1,87 +1,52 @@
1
1
  /**
2
- * Fetch-initiator capture — the page-side half of resolving *which*
3
- * frontend function issued an observed request, not merely which functions
4
- * the graph says are capable of it (`resolveFrontendCallers`'s own
5
- * structural limit, `@descryy/runtime-graph-correlator`).
2
+ * Fetch-initiator capture: page-side half of resolving which frontend
3
+ * function issued an observed request (structural capability alone is
4
+ * `resolveFrontendCallers`'s job, in `@descryy/runtime-graph-correlator`).
6
5
  *
7
- * **This is a write, not a read**, in the sense
8
- * `PROPOSAL-code-injection-into-observed-processes.md` asks every injection
9
- * mechanism to state for itself: the wrapped `fetch()` adds a real header
10
- * (`x-descry-initiator-id`) to a real outgoing request. That line does not
11
- * run when Descry is not attached — a same-origin request can pick up a
12
- * fresh CORS preflight it would not otherwise have had. That side effect is
13
- * the one `PROPOSAL-observed-frontend-caller-needs-initiator-capture.md`
14
- * asked a human to sign off on before this was built; nothing here reopens
15
- * that call.
6
+ * This is a write, not a read: the wrapped fetch() adds a real header
7
+ * (`x-descry-initiator-id`) to a real outgoing request, which can trigger a
8
+ * fresh CORS preflight on a same-origin request. Signed off in
9
+ * `PROPOSAL-observed-frontend-caller-needs-initiator-capture.md`.
16
10
  *
17
- * The call-site stack itself never travels over the wire that carries the
18
- * application's own traffic — only a short, opaque per-call id does, as the
19
- * header value. The stack text instead travels over Playwright's own CDP
20
- * binding channel (`page.exposeFunction`), straight to `take()` below,
21
- * keyed by that same id.
11
+ * The call-site stack never travels with application traffic -- only an
12
+ * opaque per-call id does, as the header value. The stack text travels
13
+ * over Playwright's CDP binding (`page.exposeFunction`) to `take()` below.
22
14
  *
23
- * **Why the real `fetch()` is held until the exposed call returns.** Firing
24
- * the buffering call and the real request concurrently would make
25
- * correctness depend on which of two independent async channels — the CDP
26
- * binding call, and Chromium's own network stack — happens to land at this
27
- * process first. That is exactly the kind of timing assumption §27's
28
- * "similarity must never be treated as causality" rules out. Awaiting the
29
- * binding call before dispatching `fetch` makes the ordering true by
30
- * construction instead: the real request cannot be sent until this module
31
- * has already buffered the stack it will be looked up by.
15
+ * The real fetch() is held until the exposed call returns, so ordering is
16
+ * true by construction rather than a race between the CDP binding and
17
+ * Chromium's network stack (§27: never treat timing as causality).
32
18
  *
33
- * Chromium only — `page.addInitScript` + `page.exposeFunction` is the
34
- * mechanism, and no non-CDP-based engine here exposes an equivalent pair.
35
- * `fetch()` only, not `XMLHttpRequest`. Both boundaries are the scope
36
- * `PROPOSAL-observed-frontend-caller-needs-initiator-capture.md` drew, not
37
- * an oversight of this module.
19
+ * Chromium only (`page.addInitScript`/`page.exposeFunction`), fetch() only
20
+ * (not XMLHttpRequest) -- scope drawn by the proposal above, not an
21
+ * oversight.
38
22
  */
39
23
  import type { Page } from "playwright-core";
40
24
  export declare const INITIATOR_HEADER_NAME = "x-descry-initiator-id";
41
25
  export interface FrontendInitiatorCapture {
42
26
  /**
43
- * Wraps `window.fetch` in every document this page loads from this point
44
- * forward — `page.addInitScript`'s own contract: it does not retroactively
45
- * reach a document already loaded. Call before navigating to whatever the
46
- * caller wants covered, exactly like `BrowserConsoleCollector`'s own
47
- * `page.on(...)` registration ordering.
27
+ * Wraps window.fetch in every document from this point forward --
28
+ * addInitScript doesn't reach an already-loaded document. Call before
29
+ * navigating, same ordering as BrowserConsoleCollector's page.on(...).
48
30
  */
49
31
  install(page: Page): Promise<void>;
50
32
  /**
51
- * Pops the buffered raw `Error.stack` text captured for `id`, or
52
- * `undefined` — the header never reached this collector, the id was never
53
- * issued by this capture (a stale id, a different page), or the buffer
54
- * evicted it under `MAX_BUFFERED_STACKS`. Popped rather than peeked: a
55
- * captured stack is consumed by the one request it was captured for, and
56
- * leaving it behind would let a second, unrelated lookup of a reused id
57
- * (impossible by construction here, but not worth relying on) read
58
- * another request's call site.
33
+ * Pops the buffered stack for `id`, or undefined if never captured or
34
+ * evicted. Popped not peeked: a captured stack belongs to one request.
59
35
  */
60
36
  take(id: string): string | undefined;
61
37
  }
62
38
  export declare function createFrontendInitiatorCapture(): FrontendInitiatorCapture;
63
39
  /**
64
- * Strips `descryFetch`'s own frame from a raw V8 stack, so the remaining
65
- * text's first frame is the real call site rather than this module's own
66
- * wrapper.
40
+ * Strips descryFetch's own frame from a raw V8 stack so the first
41
+ * remaining frame is the real call site.
67
42
  *
68
- * **Why this can be a fixed "drop the first frame line" rule rather than a
69
- * search for a named function.** `new Error().stack` is captured
70
- * synchronously, as the wrapper's first statement — before the `await`-
71
- * shaped `.then(dispatch)` chain below it ever runs. V8's stack is built
72
- * from the synchronous call chain live at capture time, so the innermost
73
- * frame is deterministically `descryFetch` itself, every time, regardless
74
- * of what called it. Stripping by *position* (first frame line) rather than
75
- * by *name* also survives minification of this wrapper's own name, which a
76
- * name-based strip would not.
43
+ * Works as a fixed "drop first line" rule rather than a name search:
44
+ * Error().stack is captured synchronously as the wrapper's first statement,
45
+ * so the innermost frame is always descryFetch regardless of caller --
46
+ * stripping by position also survives minification of the wrapper's name.
77
47
  *
78
- * Applied to raw text, before parsing — same reasoning
79
- * `rewriteScriptUrls`'s own doc gives for rewriting before rather than
80
- * after: `createV8StackTraceParser` already treats frame 0 of whatever it
81
- * receives as `primaryFrameIndex`, so removing the wrapper's line here
82
- * means the parser's existing, already-tested convention does the right
83
- * thing unmodified, instead of teaching every consumer a second index to
84
- * skip.
48
+ * Applied to raw text before parsing, so createV8StackTraceParser's
49
+ * existing primaryFrameIndex convention (frame 0) just works.
85
50
  */
86
51
  export declare function stripInitiatorWrapperFrame(rawStackText: string): string;
87
52
  //# sourceMappingURL=frontend-initiator-capture.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"frontend-initiator-capture.d.ts","sourceRoot":"","sources":["../src/frontend-initiator-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAc7D,MAAM,WAAW,wBAAwB;IACvC;;;;;;OAMG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC;;;;;;;;;OASG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,wBAAgB,8BAA8B,IAAI,wBAAwB,CAsBzE;AA4CD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAKvE"}
1
+ {"version":3,"file":"frontend-initiator-capture.d.ts","sourceRoot":"","sources":["../src/frontend-initiator-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAW7D,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC;;;OAGG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,wBAAgB,8BAA8B,IAAI,wBAAwB,CAsBzE;AAsCD;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAKvE"}
@@ -1,49 +1,30 @@
1
1
  /**
2
- * Fetch-initiator capture — the page-side half of resolving *which*
3
- * frontend function issued an observed request, not merely which functions
4
- * the graph says are capable of it (`resolveFrontendCallers`'s own
5
- * structural limit, `@descryy/runtime-graph-correlator`).
2
+ * Fetch-initiator capture: page-side half of resolving which frontend
3
+ * function issued an observed request (structural capability alone is
4
+ * `resolveFrontendCallers`'s job, in `@descryy/runtime-graph-correlator`).
6
5
  *
7
- * **This is a write, not a read**, in the sense
8
- * `PROPOSAL-code-injection-into-observed-processes.md` asks every injection
9
- * mechanism to state for itself: the wrapped `fetch()` adds a real header
10
- * (`x-descry-initiator-id`) to a real outgoing request. That line does not
11
- * run when Descry is not attached — a same-origin request can pick up a
12
- * fresh CORS preflight it would not otherwise have had. That side effect is
13
- * the one `PROPOSAL-observed-frontend-caller-needs-initiator-capture.md`
14
- * asked a human to sign off on before this was built; nothing here reopens
15
- * that call.
6
+ * This is a write, not a read: the wrapped fetch() adds a real header
7
+ * (`x-descry-initiator-id`) to a real outgoing request, which can trigger a
8
+ * fresh CORS preflight on a same-origin request. Signed off in
9
+ * `PROPOSAL-observed-frontend-caller-needs-initiator-capture.md`.
16
10
  *
17
- * The call-site stack itself never travels over the wire that carries the
18
- * application's own traffic — only a short, opaque per-call id does, as the
19
- * header value. The stack text instead travels over Playwright's own CDP
20
- * binding channel (`page.exposeFunction`), straight to `take()` below,
21
- * keyed by that same id.
11
+ * The call-site stack never travels with application traffic -- only an
12
+ * opaque per-call id does, as the header value. The stack text travels
13
+ * over Playwright's CDP binding (`page.exposeFunction`) to `take()` below.
22
14
  *
23
- * **Why the real `fetch()` is held until the exposed call returns.** Firing
24
- * the buffering call and the real request concurrently would make
25
- * correctness depend on which of two independent async channels — the CDP
26
- * binding call, and Chromium's own network stack — happens to land at this
27
- * process first. That is exactly the kind of timing assumption §27's
28
- * "similarity must never be treated as causality" rules out. Awaiting the
29
- * binding call before dispatching `fetch` makes the ordering true by
30
- * construction instead: the real request cannot be sent until this module
31
- * has already buffered the stack it will be looked up by.
15
+ * The real fetch() is held until the exposed call returns, so ordering is
16
+ * true by construction rather than a race between the CDP binding and
17
+ * Chromium's network stack (§27: never treat timing as causality).
32
18
  *
33
- * Chromium only — `page.addInitScript` + `page.exposeFunction` is the
34
- * mechanism, and no non-CDP-based engine here exposes an equivalent pair.
35
- * `fetch()` only, not `XMLHttpRequest`. Both boundaries are the scope
36
- * `PROPOSAL-observed-frontend-caller-needs-initiator-capture.md` drew, not
37
- * an oversight of this module.
19
+ * Chromium only (`page.addInitScript`/`page.exposeFunction`), fetch() only
20
+ * (not XMLHttpRequest) -- scope drawn by the proposal above, not an
21
+ * oversight.
38
22
  */
39
23
  export const INITIATOR_HEADER_NAME = "x-descry-initiator-id";
40
24
  /**
41
- * Bound on stacks buffered but never claimed. Without it, every request
42
- * whose id is never looked up — the header stripped in transit, a page that
43
- * never triggers a matching `onRequest` at all — would grow this map for
44
- * the entire life of the page. FIFO eviction via `Map`'s own insertion
45
- * order; a stack this old was never going to be claimed by the time
46
- * something newer needs the room.
25
+ * Cap on stacks buffered but never claimed (stripped header, no matching
26
+ * request) -- otherwise this map grows for the page's whole life. FIFO
27
+ * eviction via Map's own insertion order.
47
28
  */
48
29
  const MAX_BUFFERED_STACKS = 2000;
49
30
  const CAPTURE_BINDING_NAME = "__descryCaptureInitiatorStack";
@@ -70,16 +51,10 @@ export function createFrontendInitiatorCapture() {
70
51
  };
71
52
  }
72
53
  /**
73
- * The injected wrapper, as a plain string — `page.addInitScript`'s
74
- * string form, so this never needs its own transpilation step and runs
75
- * exactly as written in the page's own JS engine, not this process's.
76
- *
77
- * Every call site outcome degrades to "no id header" or "no functionName"
78
- * rather than throwing: `bind(...)` is wrapped in its own `.catch`, and a
79
- * `fetch()` whose `input` is neither a string, `URL`, nor `Request` still
80
- * reaches `originalFetch` unmodified so the native `TypeError` a caller
81
- * would have gotten anyway is the one they still get — this wrapper adds a
82
- * header, it does not change what counts as a valid `fetch()` call.
54
+ * Injected wrapper as a plain string (addInitScript's string form; runs
55
+ * unmodified in the page's own JS engine). Failures degrade silently:
56
+ * bind() is wrapped in .catch, and a non-string/URL/Request fetch input
57
+ * still reaches originalFetch unmodified, so callers get their normal error.
83
58
  */
84
59
  function initScriptSource() {
85
60
  return `(() => {
@@ -110,27 +85,16 @@ function initScriptSource() {
110
85
  }
111
86
  const FRAME_LINE = /^\s*at\s/;
112
87
  /**
113
- * Strips `descryFetch`'s own frame from a raw V8 stack, so the remaining
114
- * text's first frame is the real call site rather than this module's own
115
- * wrapper.
88
+ * Strips descryFetch's own frame from a raw V8 stack so the first
89
+ * remaining frame is the real call site.
116
90
  *
117
- * **Why this can be a fixed "drop the first frame line" rule rather than a
118
- * search for a named function.** `new Error().stack` is captured
119
- * synchronously, as the wrapper's first statement — before the `await`-
120
- * shaped `.then(dispatch)` chain below it ever runs. V8's stack is built
121
- * from the synchronous call chain live at capture time, so the innermost
122
- * frame is deterministically `descryFetch` itself, every time, regardless
123
- * of what called it. Stripping by *position* (first frame line) rather than
124
- * by *name* also survives minification of this wrapper's own name, which a
125
- * name-based strip would not.
91
+ * Works as a fixed "drop first line" rule rather than a name search:
92
+ * Error().stack is captured synchronously as the wrapper's first statement,
93
+ * so the innermost frame is always descryFetch regardless of caller --
94
+ * stripping by position also survives minification of the wrapper's name.
126
95
  *
127
- * Applied to raw text, before parsing — same reasoning
128
- * `rewriteScriptUrls`'s own doc gives for rewriting before rather than
129
- * after: `createV8StackTraceParser` already treats frame 0 of whatever it
130
- * receives as `primaryFrameIndex`, so removing the wrapper's line here
131
- * means the parser's existing, already-tested convention does the right
132
- * thing unmodified, instead of teaching every consumer a second index to
133
- * skip.
96
+ * Applied to raw text before parsing, so createV8StackTraceParser's
97
+ * existing primaryFrameIndex convention (frame 0) just works.
134
98
  */
135
99
  export function stripInitiatorWrapperFrame(rawStackText) {
136
100
  const lines = rawStackText.split(/\r\n|\r|\n/);
@@ -1 +1 @@
1
- {"version":3,"file":"frontend-initiator-capture.js","sourceRoot":"","sources":["../src/frontend-initiator-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAIH,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAE7D;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC,MAAM,oBAAoB,GAAG,+BAA+B,CAAC;AAwB7D,MAAM,UAAU,8BAA8B;IAC5C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE3C,SAAS,MAAM,CAAC,EAAU,EAAE,SAAiB;QAC3C,IAAI,QAAQ,CAAC,IAAI,IAAI,mBAAmB,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAC5C,IAAI,MAAM,KAAK,SAAS;gBAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACpD,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,IAAU;YACtB,MAAM,IAAI,CAAC,cAAc,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;YACxD,MAAM,IAAI,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,CAAC,EAAU;YACb,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACpB,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,gBAAgB;IACvB,OAAO;;;0BAGiB,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;;;;;;;;;;;sBAaxC,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC;;;;;;;;QAQnD,CAAC;AACT,CAAC;AAED,MAAM,UAAU,GAAG,UAAU,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,0BAA0B,CAAC,YAAoB;IAC7D,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACpE,IAAI,UAAU,KAAK,CAAC,CAAC;QAAE,OAAO,YAAY,CAAC;IAC3C,OAAO,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpF,CAAC"}
1
+ {"version":3,"file":"frontend-initiator-capture.js","sourceRoot":"","sources":["../src/frontend-initiator-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAE7D;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC,MAAM,oBAAoB,GAAG,+BAA+B,CAAC;AAgB7D,MAAM,UAAU,8BAA8B;IAC5C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE3C,SAAS,MAAM,CAAC,EAAU,EAAE,SAAiB;QAC3C,IAAI,QAAQ,CAAC,IAAI,IAAI,mBAAmB,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAC5C,IAAI,MAAM,KAAK,SAAS;gBAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACpD,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,IAAU;YACtB,MAAM,IAAI,CAAC,cAAc,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;YACxD,MAAM,IAAI,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,CAAC,EAAU;YACb,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACpB,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB;IACvB,OAAO;;;0BAGiB,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC;;;;;;;;;;;;;sBAaxC,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC;;;;;;;;QAQnD,CAAC;AACT,CAAC;AAED,MAAM,UAAU,GAAG,UAAU,CAAC;AAE9B;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,0BAA0B,CAAC,YAAoB;IAC7D,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACpE,IAAI,UAAU,KAAK,CAAC,CAAC;QAAE,OAAO,YAAY,CAAC;IAC3C,OAAO,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpF,CAAC"}
@@ -1,11 +1,8 @@
1
1
  /**
2
- * Correlation-id extraction from real HTTP headers (structured access, not
3
- * text regex) -- covers the top three levels of plan §10's six-level
4
- * preference order: trace ID, request ID, W3C trace context. Direct header
5
- * access makes the W3C case cheap here in a way it wasn't for
6
- * `backend-observation`'s `extractCorrelationIds`, which only ever sees
7
- * unstructured log text and explicitly cuts W3C parsing as a documented
8
- * V1 gap -- this collector doesn't need that same cut.
2
+ * Correlation-id extraction from HTTP headers -- top three of §10's six
3
+ * levels (trace ID, request ID, W3C trace context). Structured header
4
+ * access makes W3C parsing cheap here, unlike `backend-observation`'s
5
+ * `extractCorrelationIds` (log-text only, documents W3C as a V1 gap).
9
6
  */
10
7
  export interface HeaderCorrelationIds {
11
8
  readonly traceId: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"network-correlation.d.ts","sourceRoot":"","sources":["../src/network-correlation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,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
+ {"version":3,"file":"network-correlation.d.ts","sourceRoot":"","sources":["../src/network-correlation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,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,11 +1,8 @@
1
1
  /**
2
- * Correlation-id extraction from real HTTP headers (structured access, not
3
- * text regex) -- covers the top three levels of plan §10's six-level
4
- * preference order: trace ID, request ID, W3C trace context. Direct header
5
- * access makes the W3C case cheap here in a way it wasn't for
6
- * `backend-observation`'s `extractCorrelationIds`, which only ever sees
7
- * unstructured log text and explicitly cuts W3C parsing as a documented
8
- * V1 gap -- this collector doesn't need that same cut.
2
+ * Correlation-id extraction from HTTP headers -- top three of §10's six
3
+ * levels (trace ID, request ID, W3C trace context). Structured header
4
+ * access makes W3C parsing cheap here, unlike `backend-observation`'s
5
+ * `extractCorrelationIds` (log-text only, documents W3C as a V1 gap).
9
6
  */
10
7
  // W3C Trace Context: "00-<32 hex trace-id>-<16 hex parent-id>-<2 hex flags>".
11
8
  const TRACEPARENT_PATTERN = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/i;
@@ -1 +1 @@
1
- {"version":3,"file":"network-correlation.js","sourceRoot":"","sources":["../src/network-correlation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,8EAA8E;AAC9E,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"}
1
+ {"version":3,"file":"network-correlation.js","sourceRoot":"","sources":["../src/network-correlation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8EAA8E;AAC9E,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"}
@@ -1,29 +1,18 @@
1
1
  /**
2
- * RT-023's collector half: rewriting a browser script URL to the on-disk
3
- * file it was served from, so a page-error stack can be parsed into real
4
- * `SourceLocation`s instead of preserved as text.
2
+ * RT-023 collector half: rewrites a script URL to its on-disk file so a
3
+ * page-error stack parses into real `SourceLocation`s instead of text.
5
4
  *
6
- * **The rewrite happens on the stack text, before parsing, deliberately.**
7
- * A `StackTraceParser` and its `SourceLocationResolver` already know how to
8
- * turn `at f (/abs/path.js:12:5)` into a resolved location — including
9
- * source-map handling and staleness detection, which took real work to get
10
- * right. Rewriting the URL first lets all of that apply unchanged, where
11
- * post-processing parsed frames would mean reimplementing it here and
12
- * keeping two copies honest.
5
+ * Rewrite happens on the stack text before parsing, so the existing
6
+ * `StackTraceParser`/`SourceLocationResolver` (source maps, staleness)
7
+ * apply unchanged rather than being reimplemented here.
13
8
  *
14
- * **What this can and cannot claim.** `CollectorContext.resolveSourceRoot`
15
- * answers "which service's declared root does this origin belong to", and
16
- * `ConfiguredServiceRoot.declaredCwd` is named for what it is: configured,
17
- * not verified. So a successful rewrite proves the origin maps to a
18
- * directory — **not** that the file the browser executed came from the
19
- * checkout in it. The downstream resolver's own existence check is the real
20
- * refusal point, and an unmapped or non-existent path degrades to the URL
21
- * itself rather than to a fabricated file. That is RT-031's class again:
22
- * a match on an observable proxy is not proof of the underlying identity.
9
+ * A successful rewrite proves the origin maps to a directory, not that the
10
+ * executed file came from that checkout (`declaredCwd` is configured, not
11
+ * verified) -- the downstream resolver's existence check is the real
12
+ * refusal point. RT-031's class: a match on a proxy isn't proof of identity.
23
13
  *
24
- * Nothing is rewritten when the resolver refuses, when it is absent, or
25
- * when the URL is not one this execution spawned — a CDN script, a browser
26
- * extension, `about:blank`. Those are routine, not failures.
14
+ * Nothing is rewritten when the resolver refuses, is absent, or the URL
15
+ * wasn't spawned by this execution (CDN script, extension, `about:blank`).
27
16
  */
28
17
  import type { ServiceRootLookup } from "@descryy/runtime-contracts";
29
18
  export type SourceRootResolver = (origin: string) => ServiceRootLookup;
@@ -1 +1 @@
1
- {"version":3,"file":"script-url-mapping.d.ts","sourceRoot":"","sources":["../src/script-url-mapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,iBAAiB,CAAC;AAKvE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4GAA4G;IAC5G,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;CACxH;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE,kBAAkB,GAAG,SAAS,GAAG,gBAAgB,CAoExH"}
1
+ {"version":3,"file":"script-url-mapping.d.ts","sourceRoot":"","sources":["../src/script-url-mapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEpE,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,iBAAiB,CAAC;AAKvE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4GAA4G;IAC5G,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;CACxH;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE,kBAAkB,GAAG,SAAS,GAAG,gBAAgB,CAkDxH"}
@@ -1,29 +1,18 @@
1
1
  /**
2
- * RT-023's collector half: rewriting a browser script URL to the on-disk
3
- * file it was served from, so a page-error stack can be parsed into real
4
- * `SourceLocation`s instead of preserved as text.
2
+ * RT-023 collector half: rewrites a script URL to its on-disk file so a
3
+ * page-error stack parses into real `SourceLocation`s instead of text.
5
4
  *
6
- * **The rewrite happens on the stack text, before parsing, deliberately.**
7
- * A `StackTraceParser` and its `SourceLocationResolver` already know how to
8
- * turn `at f (/abs/path.js:12:5)` into a resolved location — including
9
- * source-map handling and staleness detection, which took real work to get
10
- * right. Rewriting the URL first lets all of that apply unchanged, where
11
- * post-processing parsed frames would mean reimplementing it here and
12
- * keeping two copies honest.
5
+ * Rewrite happens on the stack text before parsing, so the existing
6
+ * `StackTraceParser`/`SourceLocationResolver` (source maps, staleness)
7
+ * apply unchanged rather than being reimplemented here.
13
8
  *
14
- * **What this can and cannot claim.** `CollectorContext.resolveSourceRoot`
15
- * answers "which service's declared root does this origin belong to", and
16
- * `ConfiguredServiceRoot.declaredCwd` is named for what it is: configured,
17
- * not verified. So a successful rewrite proves the origin maps to a
18
- * directory — **not** that the file the browser executed came from the
19
- * checkout in it. The downstream resolver's own existence check is the real
20
- * refusal point, and an unmapped or non-existent path degrades to the URL
21
- * itself rather than to a fabricated file. That is RT-031's class again:
22
- * a match on an observable proxy is not proof of the underlying identity.
9
+ * A successful rewrite proves the origin maps to a directory, not that the
10
+ * executed file came from that checkout (`declaredCwd` is configured, not
11
+ * verified) -- the downstream resolver's existence check is the real
12
+ * refusal point. RT-031's class: a match on a proxy isn't proof of identity.
23
13
  *
24
- * Nothing is rewritten when the resolver refuses, when it is absent, or
25
- * when the URL is not one this execution spawned — a CDN script, a browser
26
- * extension, `about:blank`. Those are routine, not failures.
14
+ * Nothing is rewritten when the resolver refuses, is absent, or the URL
15
+ * wasn't spawned by this execution (CDN script, extension, `about:blank`).
27
16
  */
28
17
  import { statSync } from "node:fs";
29
18
  import { join } from "node:path";
@@ -35,9 +24,7 @@ export function rewriteScriptUrls(stackText, resolveSourceRoot) {
35
24
  }
36
25
  const outcomes = [];
37
26
  const text = stackText.replace(SCRIPT_URL, (match) => {
38
- // Strip the stack's own `:line:column` suffix before treating the rest
39
- // as a URL — `new URL()` would otherwise parse `:12` as part of the
40
- // path and produce a file that never existed.
27
+ // strip the stack's ":line:column" suffix first -- new URL() would parse ":12" as part of the path.
41
28
  const suffix = /:(\d+):(\d+)$/.exec(match);
42
29
  const urlText = suffix === null ? match : match.slice(0, match.length - suffix[0].length);
43
30
  let url;
@@ -53,24 +40,12 @@ export function rewriteScriptUrls(stackText, resolveSourceRoot) {
53
40
  outcomes.push({ url: match, mapped: null, reason: lookup.message });
54
41
  return match;
55
42
  }
56
- // `url.pathname` is always absolute; `join` would otherwise treat a
57
- // leading slash as a fresh root and discard the service's own cwd.
43
+ // url.pathname is always absolute; join would otherwise treat the leading slash as a fresh root and drop declaredCwd.
58
44
  const candidate = join(lookup.root.declaredCwd, url.pathname.replace(/^\/+/, ""));
59
- // **`isFile()`, not `existsSync` — and the difference is not pedantry.**
60
- // An inline `<script>` on a page served at `/` produces frames V8 names
61
- // after the *document* URL, whose pathname is `/` and nothing else. That
62
- // joins to `declaredCwd` itself: a real directory, so `existsSync` said
63
- // yes and this function rewrote a stack frame to a directory no browser
64
- // ever executed. The downstream `SourceLocationResolver` then reached
65
- // `readFileSync(directory)`, threw `EISDIR`, and the whole
66
- // `NETWORK_REQUEST` row was lost with it — an observation discarded to
67
- // protect a nullable field. `statSync` answers the question that was
68
- // always being asked (is there a FILE here?) rather than the weaker one
69
- // that happened to be cheap.
70
- //
71
- // `statSync` throws on a missing path where `existsSync` returned false,
72
- // so the absence case is caught rather than propagated: both branches end
73
- // in the same refusal, with the reason naming which one it was.
45
+ // isFile(), not existsSync: an inline <script> on a page served at "/" resolves to declaredCwd
46
+ // itself -- a real directory, so existsSync said yes and readFileSync(directory) threw EISDIR,
47
+ // dropping the whole NETWORK_REQUEST row. statSync also catches the missing-path case, so both
48
+ // branches end in the same refusal, with the reason naming which one it was.
74
49
  let isFile;
75
50
  try {
76
51
  isFile = statSync(candidate).isFile();
@@ -80,11 +55,7 @@ export function rewriteScriptUrls(stackText, resolveSourceRoot) {
80
55
  return match;
81
56
  }
82
57
  if (!isFile) {
83
- // The origin maps to a root and the pathname points at something that
84
- // is not a file in it — a directory (the `/` case above), a socket, a
85
- // device. Reported rather than rewritten: a path that is not a source
86
- // file is worse than the URL, which at least says truthfully where the
87
- // browser got it.
58
+ // not a file (dir/socket/device) -- reported rather than rewritten, since that's worse than the honest URL.
88
59
  outcomes.push({ url: match, mapped: null, reason: `resolved to "${candidate}", which is not a file on disk` });
89
60
  return match;
90
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"script-url-mapping.js","sourceRoot":"","sources":["../src/script-url-mapping.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"script-url-mapping.js","sourceRoot":"","sources":["../src/script-url-mapping.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "@descryy/runtime-browser",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Browser runtime: launch, isolated context, navigation, click/type/wait, DOM inspection, screenshots, console/page-error/network capture, all through the Collector contract (plan \u00a77/\u00a78). See documents/decisions-inbox/PROPOSAL-B-playwright-for-browser-runtime.md for the Playwright-vs-CDP call.",
6
6
  "license": "UNLICENSED",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/descryhq-wq/descry-runtime.git",
10
+ "directory": "packages/browser"
11
+ },
7
12
  "engines": {
8
13
  "node": ">=22.5"
9
14
  },
@@ -24,10 +29,10 @@
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.0",
33
+ "@descryy/runtime-backend-observation": "0.3.0",
29
34
  "playwright-core": "^1.62.1",
30
- "@descryy/runtime-adapter-typescript": "0.2.0"
35
+ "@descryy/runtime-adapter-typescript": "0.3.0"
31
36
  },
32
37
  "devDependencies": {
33
38
  "@descryy/runtime-controller": "*",