@descryy/runtime-browser 0.2.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 +6 -0
- package/dist/browser-action-collector.d.ts.map +1 -1
- package/dist/browser-action-collector.js +22 -2
- package/dist/browser-action-collector.js.map +1 -1
- package/dist/browser-console-collector.d.ts +10 -18
- package/dist/browser-console-collector.d.ts.map +1 -1
- package/dist/browser-console-collector.js +24 -47
- package/dist/browser-console-collector.js.map +1 -1
- package/dist/browser-network-collector.d.ts +17 -0
- package/dist/browser-network-collector.d.ts.map +1 -1
- package/dist/browser-network-collector.js +70 -1
- package/dist/browser-network-collector.js.map +1 -1
- package/dist/browser-session.d.ts +46 -78
- package/dist/browser-session.d.ts.map +1 -1
- package/dist/browser-session.js +21 -41
- package/dist/browser-session.js.map +1 -1
- package/dist/collector-version.d.ts +3 -6
- package/dist/collector-version.d.ts.map +1 -1
- package/dist/collector-version.js +3 -6
- package/dist/collector-version.js.map +1 -1
- package/dist/dom-evidence.d.ts +3 -6
- package/dist/dom-evidence.d.ts.map +1 -1
- package/dist/dom-evidence.js +3 -6
- package/dist/dom-evidence.js.map +1 -1
- package/dist/frontend-initiator-capture.d.ts +29 -64
- package/dist/frontend-initiator-capture.d.ts.map +1 -1
- package/dist/frontend-initiator-capture.js +31 -67
- package/dist/frontend-initiator-capture.js.map +1 -1
- package/dist/network-correlation.d.ts +4 -7
- package/dist/network-correlation.d.ts.map +1 -1
- package/dist/network-correlation.js +4 -7
- package/dist/network-correlation.js.map +1 -1
- package/dist/script-url-mapping.d.ts +11 -22
- package/dist/script-url-mapping.d.ts.map +1 -1
- package/dist/script-url-mapping.js +18 -47
- package/dist/script-url-mapping.js.map +1 -1
- package/package.json +9 -4
|
@@ -1,49 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fetch-initiator capture
|
|
3
|
-
*
|
|
4
|
-
*
|
|
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
|
-
*
|
|
8
|
-
* `
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
|
18
|
-
*
|
|
19
|
-
*
|
|
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
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
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
|
|
34
|
-
*
|
|
35
|
-
*
|
|
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
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
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
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
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
|
|
114
|
-
*
|
|
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
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
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
|
|
128
|
-
*
|
|
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
|
|
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
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
|
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
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
|
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
|
|
3
|
-
*
|
|
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
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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,
|
|
25
|
-
*
|
|
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
|
|
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
|
|
3
|
-
*
|
|
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
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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,
|
|
25
|
-
*
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
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
|
-
//
|
|
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":"AAAA
|
|
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
|
+
"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.
|
|
28
|
-
"@descryy/runtime-backend-observation": "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.
|
|
35
|
+
"@descryy/runtime-adapter-typescript": "0.3.0"
|
|
31
36
|
},
|
|
32
37
|
"devDependencies": {
|
|
33
38
|
"@descryy/runtime-controller": "*",
|