@descryy/runtime-identity-grounding 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/element-identity.d.ts +41 -78
- package/dist/element-identity.d.ts.map +1 -1
- package/dist/element-identity.js +59 -64
- package/dist/element-identity.js.map +1 -1
- package/dist/fiber-probe.d.ts +25 -45
- package/dist/fiber-probe.d.ts.map +1 -1
- package/dist/fiber-probe.js +45 -84
- package/dist/fiber-probe.js.map +1 -1
- package/dist/graph-join.d.ts +18 -49
- package/dist/graph-join.d.ts.map +1 -1
- package/dist/graph-join.js +17 -42
- package/dist/graph-join.js.map +1 -1
- package/dist/identity-grounder.d.ts +12 -31
- package/dist/identity-grounder.d.ts.map +1 -1
- package/dist/identity-grounder.js +13 -26
- package/dist/identity-grounder.js.map +1 -1
- package/dist/identity-grounding.d.ts +20 -39
- package/dist/identity-grounding.d.ts.map +1 -1
- package/dist/identity-grounding.js +27 -44
- package/dist/identity-grounding.js.map +1 -1
- package/dist/index.d.ts +7 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/owner-stack.d.ts +36 -65
- package/dist/owner-stack.d.ts.map +1 -1
- package/dist/owner-stack.js +33 -62
- package/dist/owner-stack.js.map +1 -1
- package/dist/vue-identity-grounder.d.ts +23 -0
- package/dist/vue-identity-grounder.d.ts.map +1 -0
- package/dist/vue-identity-grounder.js +28 -0
- package/dist/vue-identity-grounder.js.map +1 -0
- package/dist/vue-identity-grounding.d.ts +16 -0
- package/dist/vue-identity-grounding.d.ts.map +1 -0
- package/dist/vue-identity-grounding.js +110 -0
- package/dist/vue-identity-grounding.js.map +1 -0
- package/dist/vue-probe.d.ts +49 -0
- package/dist/vue-probe.d.ts.map +1 -0
- package/dist/vue-probe.js +95 -0
- package/dist/vue-probe.js.map +1 -0
- package/package.json +7 -7
package/dist/fiber-probe.js
CHANGED
|
@@ -2,58 +2,38 @@
|
|
|
2
2
|
* The page-side half: reads React's fiber bookkeeping off a real DOM node
|
|
3
3
|
* and returns **raw facts only**.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Read-only, unlike `frontend-initiator-capture.ts` which concedes it
|
|
6
|
+
* wraps `window.fetch`. This module defines one function on `window` and
|
|
7
|
+
* reads properties React already put on DOM nodes and fiber objects —
|
|
8
|
+
* nothing wrapped, nothing patched, no application code path changes shape
|
|
9
|
+
* (same observation-only guarantee `Collector` states for attach mode).
|
|
6
10
|
*
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* objects. Nothing is wrapped, nothing is patched, no application code path
|
|
14
|
-
* changes shape because Descry is attached. That is the same
|
|
15
|
-
* observation-only guarantee `Collector` states for attach mode
|
|
16
|
-
* (`ATTACH_MODE_SCOPE_DISCLOSURE`), and it holds here without needing an
|
|
17
|
-
* exception.
|
|
11
|
+
* Injected via `page.addInitScript` with a string body, the same mechanism
|
|
12
|
+
* `frontend-initiator-capture.ts` uses — no transpilation step needed. A
|
|
13
|
+
* string rather than a typed function because this repo's
|
|
14
|
+
* `tsconfig.base.json` has no DOM library, so `document`/`window` don't
|
|
15
|
+
* exist as types here; it keeps the "runs here" vs "runs there" boundary
|
|
16
|
+
* visible.
|
|
18
17
|
*
|
|
19
|
-
*
|
|
18
|
+
* `addInitScript` doesn't reach an already-loaded document — call
|
|
19
|
+
* `install()` before navigating, or a page reports `probe-not-installed`.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* function because this repo's `tsconfig.base.json` compiles with `lib:
|
|
26
|
-
* ["ES2023"]` and no DOM library at all, so `document` and `window` do not
|
|
27
|
-
* exist as types in this package. Writing the page code as a string is not
|
|
28
|
-
* a shortcut around that; it is the same choice the sibling module made,
|
|
29
|
-
* and it keeps the boundary between "runs here" and "runs there" visible.
|
|
30
|
-
*
|
|
31
|
-
* `addInitScript` does not reach a document that has already loaded. Call
|
|
32
|
-
* `install()` before navigating, like every other collector in
|
|
33
|
-
* `@descryy/runtime-browser` — a page navigated first reports
|
|
34
|
-
* `probe-not-installed`, by name, rather than silently returning nothing.
|
|
35
|
-
*
|
|
36
|
-
* ## Raw facts only — no decisions
|
|
37
|
-
*
|
|
38
|
-
* Everything this returns is a JSON-serialisable transcript of what was on
|
|
39
|
-
* the fiber. Deciding what it *means* (is this a production build? does
|
|
40
|
-
* this owner stack point at authored source?) happens in Node, in
|
|
41
|
-
* `identity-grounding.ts`, where it can be unit-tested without a browser
|
|
42
|
-
* and where the source-map machinery this repo already owns is reachable.
|
|
43
|
-
* The page-side script cannot resolve a source map and must not try.
|
|
21
|
+
* Raw facts only, no decisions: everything returned is a JSON-serialisable
|
|
22
|
+
* transcript. Deciding what it *means* happens in Node
|
|
23
|
+
* (`identity-grounding.ts`), unit-testable without a browser. The
|
|
24
|
+
* page-side script cannot resolve a source map and must not try.
|
|
44
25
|
*/
|
|
45
26
|
/** The single global this installs. One name, one function, no other footprint on the page. */
|
|
46
27
|
export const IDENTITY_GROUNDING_BINDING = "__descryIdentityGrounding";
|
|
47
28
|
/**
|
|
48
29
|
* The two key prefixes React has used to hang a fiber off a host DOM node:
|
|
49
|
-
* `__reactFiber$` since React 17, `__reactInternalInstance$` before
|
|
50
|
-
*
|
|
51
|
-
*
|
|
30
|
+
* `__reactFiber$` since React 17, `__reactInternalInstance$` before. Both
|
|
31
|
+
* checked because both are cheap and a wrong "not React" on a React 16 page
|
|
32
|
+
* would be a silent, permanent blind spot.
|
|
52
33
|
*
|
|
53
|
-
* Measured present as `__reactFiber$<random>` on React 18.3.1 and 19.2.8
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* here rather than implied by the code.
|
|
34
|
+
* Measured present as `__reactFiber$<random>` on React 18.3.1 and 19.2.8;
|
|
35
|
+
* `__reactInternalInstance$` matches React 16's documented shape but is
|
|
36
|
+
* NOT covered by this repo's fixtures.
|
|
57
37
|
*/
|
|
58
38
|
export const FIBER_KEY_PREFIXES = ["__reactFiber$", "__reactInternalInstance$"];
|
|
59
39
|
export function createIdentityGroundingProbe() {
|
|
@@ -67,22 +47,15 @@ export function createIdentityGroundingProbe() {
|
|
|
67
47
|
};
|
|
68
48
|
}
|
|
69
49
|
/**
|
|
70
|
-
* The call side, also a string —
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
* alongside a string body returned `undefined` here rather than calling the
|
|
76
|
-
* function expression with it. A self-invoking expression has one
|
|
77
|
-
* unambiguous meaning in both directions, and `JSON.stringify` on the
|
|
78
|
-
* selector is the same escaping this file already uses for the binding
|
|
79
|
-
* name, so a selector containing quotes cannot break out of the string.
|
|
50
|
+
* The call side, also a string — **self-invoking**, with the selector
|
|
51
|
+
* serialised into it rather than passed as an `evaluate` argument. Measured,
|
|
52
|
+
* not stylistic: a separate `arg` alongside a string body returned
|
|
53
|
+
* `undefined` here instead of calling the expression with it.
|
|
54
|
+
* `JSON.stringify` on the selector prevents a quote from breaking out.
|
|
80
55
|
*
|
|
81
|
-
* The `probe-not-installed` branch lives here
|
|
82
|
-
* script
|
|
83
|
-
*
|
|
84
|
-
* and drawing it is what keeps "Descry was not attached to this document"
|
|
85
|
-
* from being reported as "this page is not React".
|
|
56
|
+
* The `probe-not-installed` branch lives here, not in the injected script —
|
|
57
|
+
* a script that never ran can't report that it never ran. This is the only
|
|
58
|
+
* place that distinction can be drawn.
|
|
86
59
|
*/
|
|
87
60
|
function probeCallSource(selector) {
|
|
88
61
|
return `(() => {
|
|
@@ -93,34 +66,23 @@ function probeCallSource(selector) {
|
|
|
93
66
|
return grounding.probe(${JSON.stringify(selector)});
|
|
94
67
|
})()`;
|
|
95
68
|
}
|
|
96
|
-
/** Cap on the key list carried by a `no-fiber` result
|
|
69
|
+
/** Cap on the key list carried by a `no-fiber` result — a pathological element shouldn't become an unbounded payload. */
|
|
97
70
|
const MAX_REPORTED_OWN_KEYS = 32;
|
|
98
71
|
/**
|
|
99
72
|
* The injected reader.
|
|
100
73
|
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* React does not fail loudly — it silently classifies a real component as
|
|
110
|
-
* "not a component" and the answer degrades to a refusal nobody can
|
|
111
|
-
* explain.
|
|
112
|
-
*
|
|
113
|
-
* `fiber.type` is far more stable and is directly observable: a string is a
|
|
114
|
-
* host element, a function is a function or class component, an object with
|
|
115
|
-
* a `render` is a `forwardRef`, an object with a `type` is a `memo`. That
|
|
116
|
-
* is what is used. `tag` is still reported, verbatim, for audit.
|
|
117
|
-
*
|
|
118
|
-
* ## Everything degrades to null, nothing throws
|
|
74
|
+
* Component detection reads the *type shape*, not `fiber.tag` — the
|
|
75
|
+
* obvious numeric-tag table (`0 = FunctionComponent`, ...) is a private
|
|
76
|
+
* React implementation detail with no cross-major guarantee, and a table
|
|
77
|
+
* wrong on some future React silently misclassifies a component as "not a
|
|
78
|
+
* component" rather than failing loudly. `fiber.type` is stable and
|
|
79
|
+
* observable instead: a string is a host element, a function a
|
|
80
|
+
* function/class component, an object with `render` a `forwardRef`, an
|
|
81
|
+
* object with `type` a `memo`. `tag` is still reported verbatim for audit.
|
|
119
82
|
*
|
|
120
|
-
*
|
|
121
|
-
* whole probe body is wrapped so
|
|
122
|
-
*
|
|
123
|
-
* then have to survive.
|
|
83
|
+
* Everything degrades to null, nothing throws — an unexpected shape yields
|
|
84
|
+
* `null`, and the whole probe body is wrapped so a read-only observation
|
|
85
|
+
* can't become a page error the app has to survive.
|
|
124
86
|
*/
|
|
125
87
|
function probeScriptSource() {
|
|
126
88
|
return `(() => {
|
|
@@ -214,9 +176,8 @@ function probeScriptSource() {
|
|
|
214
176
|
try {
|
|
215
177
|
element = document.querySelector(selector);
|
|
216
178
|
} catch (_error) {
|
|
217
|
-
// An invalid selector is the caller's mistake,
|
|
218
|
-
//
|
|
219
|
-
// what actually happened here.
|
|
179
|
+
// An invalid selector is the caller's mistake, not a statement
|
|
180
|
+
// about the page — reported as "matched nothing".
|
|
220
181
|
return { status: "element-not-found", selector: selector };
|
|
221
182
|
}
|
|
222
183
|
if (element === null) return { status: "element-not-found", selector: selector };
|
package/dist/fiber-probe.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fiber-probe.js","sourceRoot":"","sources":["../src/fiber-probe.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fiber-probe.js","sourceRoot":"","sources":["../src/fiber-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAMH,+FAA+F;AAC/F,MAAM,CAAC,MAAM,0BAA0B,GAAG,2BAA2B,CAAC;AAEtE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,eAAe,EAAE,0BAA0B,CAAU,CAAC;AAuDzF,MAAM,UAAU,4BAA4B;IAC1C,OAAO;QACL,KAAK,CAAC,OAAO,CAAC,IAAU;YACtB,MAAM,IAAI,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,KAAK,CAAC,IAAU,EAAE,QAAgB;YAChC,OAAO,IAAI,CAAC,QAAQ,CAAgB,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;QACjE,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,eAAe,CAAC,QAAgB;IACvC,OAAO;6BACoB,IAAI,CAAC,SAAS,CAAC,0BAA0B,CAAC;;;;2BAI5C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;KAC9C,CAAC;AACN,CAAC;AAED,yHAAyH;AACzH,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAEjC;;;;;;;;;;;;;;;GAeG;AACH,SAAS,iBAAiB;IACxB,OAAO;+BACsB,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAoFtD,IAAI,CAAC,SAAS,CAAC,0BAA0B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;mDA4BF,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2BlE,CAAC;AACP,CAAC"}
|
package/dist/graph-join.d.ts
CHANGED
|
@@ -1,61 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The join to `descry-core`'s graph —
|
|
3
|
-
* resolver.
|
|
2
|
+
* The join to `descry-core`'s graph — a **hand-off**, not a second
|
|
3
|
+
* resolver. `resolveSymbolNode` already does the whole job of turning
|
|
4
|
+
* `{ file, symbolName, line }` into a `FUNCTION`/`CLASS` node — refusing
|
|
5
|
+
* ambiguity, checking the line against the node's range, translating path
|
|
6
|
+
* languages, requiring `repo` since there's no honest default. This
|
|
7
|
+
* function's entire contract: hand it exactly that input, or hand it
|
|
8
|
+
* nothing.
|
|
4
9
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* function must not duplicate: refusing ambiguity instead of ranking
|
|
9
|
-
* candidates, checking the claimed line against the node's own range and
|
|
10
|
-
* reporting `line-mismatch` distinctly, translating between the absolute /
|
|
11
|
-
* repo-relative / relative-to-launch-cwd path languages, and requiring
|
|
12
|
-
* `repo` because `FUNCTION` is repo-scoped and there is no honest default.
|
|
13
|
-
* A copy of any of that here would be a copy that drifts.
|
|
10
|
+
* No new node type, no new edge type — resolves to a `FUNCTION`/`CLASS`
|
|
11
|
+
* node an adapter already produced. `descry-core`'s frozen 15/15 vocabulary
|
|
12
|
+
* is untouched.
|
|
14
13
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* already produced — `descry-core`'s frozen 15 node types and 15 edge types
|
|
22
|
-
* are untouched. There is no `COMPONENT_INSTANCE`, no `RENDERS` edge, and
|
|
23
|
-
* nothing here asks for one. (`COMPONENT` is already one of the 15, and a
|
|
24
|
-
* React component that an adapter emitted as one is found by the same
|
|
25
|
-
* name+file lookup.)
|
|
26
|
-
*
|
|
27
|
-
* ## Why a compiled location is withheld rather than passed through
|
|
28
|
-
*
|
|
29
|
-
* `resolveSymbolNode` would take a bundle path quite happily and report
|
|
30
|
-
* `not-found` for it, which reads to a consumer as *"that component is not
|
|
31
|
-
* in the graph"* — the exact misleading refusal `symbol.ts`'s own header
|
|
32
|
-
* describes and fixed for absolute paths. A React 19 answer with
|
|
33
|
-
* `authoredSource: false` names `dist/dev.js`, a file no adapter ever
|
|
34
|
-
* indexed and never will. Withholding it keeps the honest statement —
|
|
35
|
-
* *"we know the component, we could not reach authored source"* — inside
|
|
36
|
-
* `ElementIdentity`, where the capability status explains it, instead of
|
|
37
|
-
* laundering it into a graph miss.
|
|
14
|
+
* A compiled location is withheld rather than passed through:
|
|
15
|
+
* `resolveSymbolNode` would report `not-found` for a bundle path, reading
|
|
16
|
+
* as "not in the graph" — the exact misleading refusal `symbol.ts` fixed
|
|
17
|
+
* for absolute paths. Withholding it keeps the honest statement ("we know
|
|
18
|
+
* the component, couldn't reach authored source") inside `ElementIdentity`,
|
|
19
|
+
* not laundered into a graph miss.
|
|
38
20
|
*/
|
|
39
21
|
import type { ElementIdentity } from "./element-identity.ts";
|
|
40
|
-
/**
|
|
41
|
-
* Structurally `resolveSymbolNode`'s own `location` parameter. Deliberately
|
|
42
|
-
* declared with `line` optional rather than nullable, because that is the
|
|
43
|
-
* shape that function accepts; `graph-join.test.ts` asserts the
|
|
44
|
-
* compatibility against the real signature at compile time, so a change on
|
|
45
|
-
* either side breaks the build rather than being discovered at runtime.
|
|
46
|
-
*/
|
|
22
|
+
/** Structurally `resolveSymbolNode`'s own `location` parameter — `line` optional, not nullable, matching that function's shape. `graph-join.test.ts` asserts the compatibility at compile time. */
|
|
47
23
|
export interface GraphSymbolLocation {
|
|
48
24
|
readonly file: string;
|
|
49
25
|
readonly symbolName: string;
|
|
50
26
|
readonly line?: number;
|
|
51
27
|
}
|
|
52
|
-
/**
|
|
53
|
-
* The graph lookup this identity supports, or `null` when it supports none.
|
|
54
|
-
*
|
|
55
|
-
* `null` for every outcome except a `grounded` one that reached authored
|
|
56
|
-
* source with a real file — including `component-only`, which knows the
|
|
57
|
-
* component's name and nothing about where it lives, and including a
|
|
58
|
-
* `grounded` answer whose location is compiled output.
|
|
59
|
-
*/
|
|
28
|
+
/** The graph lookup this identity supports, or `null` when it supports none — only a `grounded` outcome with authored source and a real file. */
|
|
60
29
|
export declare function symbolLocationForGraph(identity: ElementIdentity): GraphSymbolLocation | null;
|
|
61
30
|
//# sourceMappingURL=graph-join.d.ts.map
|
package/dist/graph-join.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-join.d.ts","sourceRoot":"","sources":["../src/graph-join.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"graph-join.d.ts","sourceRoot":"","sources":["../src/graph-join.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,mMAAmM;AACnM,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,iJAAiJ;AACjJ,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,eAAe,GAAG,mBAAmB,GAAG,IAAI,CAU5F"}
|
package/dist/graph-join.js
CHANGED
|
@@ -1,49 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The join to `descry-core`'s graph —
|
|
3
|
-
* resolver.
|
|
2
|
+
* The join to `descry-core`'s graph — a **hand-off**, not a second
|
|
3
|
+
* resolver. `resolveSymbolNode` already does the whole job of turning
|
|
4
|
+
* `{ file, symbolName, line }` into a `FUNCTION`/`CLASS` node — refusing
|
|
5
|
+
* ambiguity, checking the line against the node's range, translating path
|
|
6
|
+
* languages, requiring `repo` since there's no honest default. This
|
|
7
|
+
* function's entire contract: hand it exactly that input, or hand it
|
|
8
|
+
* nothing.
|
|
4
9
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* function must not duplicate: refusing ambiguity instead of ranking
|
|
9
|
-
* candidates, checking the claimed line against the node's own range and
|
|
10
|
-
* reporting `line-mismatch` distinctly, translating between the absolute /
|
|
11
|
-
* repo-relative / relative-to-launch-cwd path languages, and requiring
|
|
12
|
-
* `repo` because `FUNCTION` is repo-scoped and there is no honest default.
|
|
13
|
-
* A copy of any of that here would be a copy that drifts.
|
|
10
|
+
* No new node type, no new edge type — resolves to a `FUNCTION`/`CLASS`
|
|
11
|
+
* node an adapter already produced. `descry-core`'s frozen 15/15 vocabulary
|
|
12
|
+
* is untouched.
|
|
14
13
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* already produced — `descry-core`'s frozen 15 node types and 15 edge types
|
|
22
|
-
* are untouched. There is no `COMPONENT_INSTANCE`, no `RENDERS` edge, and
|
|
23
|
-
* nothing here asks for one. (`COMPONENT` is already one of the 15, and a
|
|
24
|
-
* React component that an adapter emitted as one is found by the same
|
|
25
|
-
* name+file lookup.)
|
|
26
|
-
*
|
|
27
|
-
* ## Why a compiled location is withheld rather than passed through
|
|
28
|
-
*
|
|
29
|
-
* `resolveSymbolNode` would take a bundle path quite happily and report
|
|
30
|
-
* `not-found` for it, which reads to a consumer as *"that component is not
|
|
31
|
-
* in the graph"* — the exact misleading refusal `symbol.ts`'s own header
|
|
32
|
-
* describes and fixed for absolute paths. A React 19 answer with
|
|
33
|
-
* `authoredSource: false` names `dist/dev.js`, a file no adapter ever
|
|
34
|
-
* indexed and never will. Withholding it keeps the honest statement —
|
|
35
|
-
* *"we know the component, we could not reach authored source"* — inside
|
|
36
|
-
* `ElementIdentity`, where the capability status explains it, instead of
|
|
37
|
-
* laundering it into a graph miss.
|
|
38
|
-
*/
|
|
39
|
-
/**
|
|
40
|
-
* The graph lookup this identity supports, or `null` when it supports none.
|
|
41
|
-
*
|
|
42
|
-
* `null` for every outcome except a `grounded` one that reached authored
|
|
43
|
-
* source with a real file — including `component-only`, which knows the
|
|
44
|
-
* component's name and nothing about where it lives, and including a
|
|
45
|
-
* `grounded` answer whose location is compiled output.
|
|
14
|
+
* A compiled location is withheld rather than passed through:
|
|
15
|
+
* `resolveSymbolNode` would report `not-found` for a bundle path, reading
|
|
16
|
+
* as "not in the graph" — the exact misleading refusal `symbol.ts` fixed
|
|
17
|
+
* for absolute paths. Withholding it keeps the honest statement ("we know
|
|
18
|
+
* the component, couldn't reach authored source") inside `ElementIdentity`,
|
|
19
|
+
* not laundered into a graph miss.
|
|
46
20
|
*/
|
|
21
|
+
/** The graph lookup this identity supports, or `null` when it supports none — only a `grounded` outcome with authored source and a real file. */
|
|
47
22
|
export function symbolLocationForGraph(identity) {
|
|
48
23
|
if (identity.outcome !== "grounded")
|
|
49
24
|
return null;
|
package/dist/graph-join.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-join.js","sourceRoot":"","sources":["../src/graph-join.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"graph-join.js","sourceRoot":"","sources":["../src/graph-join.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAWH,iJAAiJ;AACjJ,MAAM,UAAU,sBAAsB,CAAC,QAAyB;IAC9D,IAAI,QAAQ,CAAC,OAAO,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,CAAC,QAAQ,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IAE1C,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC;IAC/C,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE/B,OAAO,IAAI,KAAK,IAAI;QAClB,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE;QAC/C,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;AAC1D,CAAC"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The composed, page-driving surface — install once, then ask about a
|
|
3
|
-
* selector.
|
|
4
|
-
*
|
|
5
|
-
* Everything hard here is a composition of parts this repo already owns,
|
|
6
|
-
* deliberately:
|
|
3
|
+
* selector. Everything hard here is a composition of parts this repo
|
|
4
|
+
* already owns:
|
|
7
5
|
*
|
|
8
6
|
* | step | owner |
|
|
9
7
|
* | --- | --- |
|
|
@@ -14,22 +12,15 @@
|
|
|
14
12
|
* | source map, staleness, `reliability` | `createNodeSourceLocationResolver` (same) |
|
|
15
13
|
* | decide what may be claimed | `identity-grounding.ts` (this package) |
|
|
16
14
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* or a second URL-rewriting rule here would each be a copy that holds in
|
|
20
|
-
* one place — this repo has measured that drift and says so in
|
|
21
|
-
* `graph-correlator/src/symbol.ts` and `fixture-apps/roots.ts` alike.
|
|
22
|
-
*
|
|
23
|
-
* ## `resolveSourceRoot` is what makes the React 19 path work at all
|
|
15
|
+
* Only the fiber read and the decision table are genuinely new here — a
|
|
16
|
+
* second copy of any of the rest would be a copy that drifts.
|
|
24
17
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* the
|
|
31
|
-
* still names a position, and the answer comes back with
|
|
32
|
-
* `authoredSource: false` and a `degraded` capability rather than a
|
|
18
|
+
* `resolveSourceRoot` is what makes the React 19 path work: a React 19
|
|
19
|
+
* owner stack names the bundle by browser URL
|
|
20
|
+
* (`http://127.0.0.1:41369/dev.js:21714:62`), but source maps resolve from
|
|
21
|
+
* disk. Without a resolver (`CollectorContext.resolveSourceRoot`,
|
|
22
|
+
* RT-023/RT-029), the path degrades honestly — the stack still parses, but
|
|
23
|
+
* the answer comes back `authoredSource: false` and `degraded`, never a
|
|
33
24
|
* fabricated authored file. React 18 needs none of this — its location is
|
|
34
25
|
* already authored, on the fiber.
|
|
35
26
|
*/
|
|
@@ -37,21 +28,11 @@ import type { SourceRootResolver } from "@descryy/runtime-contracts";
|
|
|
37
28
|
import type { Page } from "playwright-core";
|
|
38
29
|
import type { ElementIdentity } from "./element-identity.ts";
|
|
39
30
|
export interface IdentityGrounderOptions {
|
|
40
|
-
/**
|
|
41
|
-
* Joins a browser origin to the on-disk directory it is served from, so a
|
|
42
|
-
* React 19 owner stack's compiled frames can be mapped back to authored
|
|
43
|
-
* source. Absent is a supported configuration, not a misconfiguration —
|
|
44
|
-
* see this module's header.
|
|
45
|
-
*/
|
|
31
|
+
/** Joins a browser origin to the on-disk directory it's served from, so React 19's compiled frames map back to authored source. Absent is supported, not a misconfiguration. */
|
|
46
32
|
readonly resolveSourceRoot?: SourceRootResolver;
|
|
47
33
|
}
|
|
48
34
|
export interface IdentityGrounder {
|
|
49
|
-
/**
|
|
50
|
-
* Installs the page-side reader into every document this page loads from
|
|
51
|
-
* this point forward. **Call before navigating** — `page.addInitScript`
|
|
52
|
-
* does not reach a document that is already loaded, and a page navigated
|
|
53
|
-
* first reports `probe-not-installed` by name.
|
|
54
|
-
*/
|
|
35
|
+
/** Installs the page-side reader into every document this page loads from now on. Call before navigating — a page navigated first reports `probe-not-installed`. */
|
|
55
36
|
install(page: Page): Promise<void>;
|
|
56
37
|
/** Resolves one on-screen element to the component that produced it, and to that component's file and line where those can be established. Never throws for a routine unavailability; refuses by name instead. */
|
|
57
38
|
ground(page: Page, selector: string): Promise<ElementIdentity>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity-grounder.d.ts","sourceRoot":"","sources":["../src/identity-grounder.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"identity-grounder.d.ts","sourceRoot":"","sources":["../src/identity-grounder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAc,MAAM,4BAA4B,CAAC;AAGjF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAI7D,MAAM,WAAW,uBAAuB;IACtC,gLAAgL;IAChL,QAAQ,CAAC,iBAAiB,CAAC,EAAE,kBAAkB,CAAC;CACjD;AAED,MAAM,WAAW,gBAAgB;IAC/B,oKAAoK;IACpK,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,kNAAkN;IAClN,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CAChE;AAED,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,gBAAgB,CAqB9F"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The composed, page-driving surface — install once, then ask about a
|
|
3
|
-
* selector.
|
|
4
|
-
*
|
|
5
|
-
* Everything hard here is a composition of parts this repo already owns,
|
|
6
|
-
* deliberately:
|
|
3
|
+
* selector. Everything hard here is a composition of parts this repo
|
|
4
|
+
* already owns:
|
|
7
5
|
*
|
|
8
6
|
* | step | owner |
|
|
9
7
|
* | --- | --- |
|
|
@@ -14,22 +12,15 @@
|
|
|
14
12
|
* | source map, staleness, `reliability` | `createNodeSourceLocationResolver` (same) |
|
|
15
13
|
* | decide what may be claimed | `identity-grounding.ts` (this package) |
|
|
16
14
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* or a second URL-rewriting rule here would each be a copy that holds in
|
|
20
|
-
* one place — this repo has measured that drift and says so in
|
|
21
|
-
* `graph-correlator/src/symbol.ts` and `fixture-apps/roots.ts` alike.
|
|
22
|
-
*
|
|
23
|
-
* ## `resolveSourceRoot` is what makes the React 19 path work at all
|
|
15
|
+
* Only the fiber read and the decision table are genuinely new here — a
|
|
16
|
+
* second copy of any of the rest would be a copy that drifts.
|
|
24
17
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* the
|
|
31
|
-
* still names a position, and the answer comes back with
|
|
32
|
-
* `authoredSource: false` and a `degraded` capability rather than a
|
|
18
|
+
* `resolveSourceRoot` is what makes the React 19 path work: a React 19
|
|
19
|
+
* owner stack names the bundle by browser URL
|
|
20
|
+
* (`http://127.0.0.1:41369/dev.js:21714:62`), but source maps resolve from
|
|
21
|
+
* disk. Without a resolver (`CollectorContext.resolveSourceRoot`,
|
|
22
|
+
* RT-023/RT-029), the path degrades honestly — the stack still parses, but
|
|
23
|
+
* the answer comes back `authoredSource: false` and `degraded`, never a
|
|
33
24
|
* fabricated authored file. React 18 needs none of this — its location is
|
|
34
25
|
* already authored, on the fiber.
|
|
35
26
|
*/
|
|
@@ -41,13 +32,9 @@ export function createIdentityGrounder(options = {}) {
|
|
|
41
32
|
const probe = createIdentityGroundingProbe();
|
|
42
33
|
const parser = createV8StackTraceParser(createNodeSourceLocationResolver());
|
|
43
34
|
const resolveOwnerStack = (rawStackText) => {
|
|
44
|
-
// Rewritten before parsing, not after
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
// location, and rewriting the text first lets all of that apply
|
|
48
|
-
// unchanged. An unmapped URL is left exactly as the browser reported
|
|
49
|
-
// it, which then resolves as a compiled location rather than a
|
|
50
|
-
// fabricated file.
|
|
35
|
+
// Rewritten before parsing, not after, so the parser/resolver's
|
|
36
|
+
// existing path handling applies unchanged. An unmapped URL is left as
|
|
37
|
+
// the browser reported it, resolving as compiled rather than fabricated.
|
|
51
38
|
const rewritten = rewriteScriptUrls(rawStackText, options.resolveSourceRoot);
|
|
52
39
|
return parser.parse(rewritten.text);
|
|
53
40
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity-grounder.js","sourceRoot":"","sources":["../src/identity-grounder.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"identity-grounder.js","sourceRoot":"","sources":["../src/identity-grounder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,gCAAgC,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAIjH,OAAO,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,eAAe,EAA2B,MAAM,yBAAyB,CAAC;AAcnF,MAAM,UAAU,sBAAsB,CAAC,UAAmC,EAAE;IAC1E,MAAM,KAAK,GAAG,4BAA4B,EAAE,CAAC;IAC7C,MAAM,MAAM,GAAG,wBAAwB,CAAC,gCAAgC,EAAE,CAAC,CAAC;IAE5E,MAAM,iBAAiB,GAAuB,CAAC,YAAoB,EAA8B,EAAE;QACjG,gEAAgE;QAChE,uEAAuE;QACvE,yEAAyE;QACzE,MAAM,SAAS,GAAG,iBAAiB,CAAC,YAAY,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAC7E,OAAO,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC,CAAC;IAEF,OAAO;QACL,OAAO,CAAC,IAAU;YAChB,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,IAAU,EAAE,QAAgB;YACvC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC9C,OAAO,eAAe,CAAC,GAAG,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC;QAC3D,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,53 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The decision layer: raw fiber facts in, one `ElementIdentity` out.
|
|
3
3
|
*
|
|
4
|
-
* Pure with respect to the browser —
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* injected as `OwnerStackResolver`. That split is what lets every refusal
|
|
9
|
-
* branch below be exercised as a plain unit test, with no Chromium and no
|
|
10
|
-
* fixture app, while the fixture apps prove the two mechanisms end to end.
|
|
4
|
+
* Pure with respect to the browser — never touches a `Page`. The one piece
|
|
5
|
+
* of machinery it can't own (turning a React 19 owner stack into a resolved
|
|
6
|
+
* `StackTrace`) is injected as `OwnerStackResolver`, so every refusal
|
|
7
|
+
* branch below is a plain unit test, no Chromium needed.
|
|
11
8
|
*
|
|
12
|
-
*
|
|
9
|
+
* What this cannot do, decided here: a production React build (no
|
|
10
|
+
* `_debug*` survives, refused as `react-debug-fields-absent`); anything
|
|
11
|
+
* that isn't React (no fiber key — a scope boundary, not a gap, refused as
|
|
12
|
+
* "not React" rather than "unknown"); a React 19 bundle with no source map
|
|
13
|
+
* (reported with `authoredSource: false` and `degraded`, never dressed up);
|
|
14
|
+
* an anonymous component (refused — no symbol to look up, no name to act on).
|
|
13
15
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* - **A React 19 bundle with no source map.** The owner stack still names a
|
|
21
|
-
* real position, in compiled output. Reported with
|
|
22
|
-
* `authoredSource: false` and a `degraded` capability, never dressed up
|
|
23
|
-
* as the file a developer wrote.
|
|
24
|
-
* - **An anonymous component.** Refused: there is no symbol for
|
|
25
|
-
* `resolveSymbolNode` to look up and no name for a reader to act on.
|
|
26
|
-
*
|
|
27
|
-
* ## Owner versus renderer
|
|
28
|
-
*
|
|
29
|
-
* `component` is read from `_debugOwner` — the component whose render
|
|
30
|
-
* *created* this element — because that is the component the source
|
|
31
|
-
* location belongs to. `renderedBy` is the nearest component in the fiber
|
|
32
|
-
* `return` chain, which is where the element ended up. They differ whenever
|
|
33
|
-
* an element is created in one component and passed to another as
|
|
34
|
-
* `children`; the fixture app renders that case deliberately. Both are
|
|
35
|
-
* reported and neither is reconciled into the other.
|
|
16
|
+
* `component` is read from `_debugOwner` — whose render *created* the
|
|
17
|
+
* element, matching the source location. `renderedBy` is the nearest
|
|
18
|
+
* component in the `return` chain — where it ended up. They differ when an
|
|
19
|
+
* element is created in one component and passed to another as `children`
|
|
20
|
+
* (the fixture app renders this on purpose); both are reported, neither
|
|
21
|
+
* reconciled.
|
|
36
22
|
*/
|
|
37
23
|
import { type StackTrace } from "@descryy/runtime-contracts";
|
|
38
24
|
import { type ElementIdentity } from "./element-identity.ts";
|
|
39
25
|
import type { RawFiberProbe } from "./fiber-probe.ts";
|
|
40
26
|
/**
|
|
41
27
|
* Turns React 19's raw `_debugStack` text into a resolved `StackTrace`, or
|
|
42
|
-
* `null` when
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* must not re-own: `@descryy/runtime-browser`'s `rewriteScriptUrls` (browser
|
|
47
|
-
* URL to on-disk path), and `@descryy/runtime-adapter-typescript`'s
|
|
48
|
-
* `createV8StackTraceParser` plus `createNodeSourceLocationResolver`
|
|
49
|
-
* (parsing, source-map resolution and the `reliability` classification —
|
|
50
|
-
* including staleness detection). `identity-grounder.ts` wires them.
|
|
28
|
+
* `null` when it's not a V8 stack at all. Injected rather than constructed
|
|
29
|
+
* here, since the real implementation composes three things this package
|
|
30
|
+
* must not re-own: `rewriteScriptUrls`, `createV8StackTraceParser`, and
|
|
31
|
+
* `createNodeSourceLocationResolver`. `identity-grounder.ts` wires them.
|
|
51
32
|
*/
|
|
52
33
|
export type OwnerStackResolver = (rawStackText: string) => Promise<StackTrace | null>;
|
|
53
34
|
export declare function groundFromProbe(probe: RawFiberProbe, selector: string, resolveOwnerStack: OwnerStackResolver | null): Promise<ElementIdentity>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity-grounding.d.ts","sourceRoot":"","sources":["../src/identity-grounding.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"identity-grounding.d.ts","sourceRoot":"","sources":["../src/identity-grounding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAA6C,KAAK,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAExG,OAAO,EAEL,KAAK,eAAe,EAGrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAA0B,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAG9E;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;AAOtF,wBAAsB,eAAe,CACnC,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,kBAAkB,GAAG,IAAI,GAC3C,OAAO,CAAC,eAAe,CAAC,CAyN1B"}
|