@descryy/mcp 0.4.0 → 0.6.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/dist/bin/descry-mcp.js +16 -2
- package/dist/bin/descry-mcp.js.map +1 -1
- package/dist/browser/driver.d.ts +105 -6
- package/dist/browser/driver.d.ts.map +1 -1
- package/dist/browser/driver.js +17 -3
- package/dist/browser/driver.js.map +1 -1
- package/dist/browser/evidence.d.ts +11 -0
- package/dist/browser/evidence.d.ts.map +1 -1
- package/dist/browser/evidence.js +64 -8
- package/dist/browser/evidence.js.map +1 -1
- package/dist/browser/fake-driver.d.ts +8 -0
- package/dist/browser/fake-driver.d.ts.map +1 -1
- package/dist/browser/fake-driver.js +26 -3
- package/dist/browser/fake-driver.js.map +1 -1
- package/dist/browser/playwright-driver.d.ts +68 -14
- package/dist/browser/playwright-driver.d.ts.map +1 -1
- package/dist/browser/playwright-driver.js +318 -38
- package/dist/browser/playwright-driver.js.map +1 -1
- package/dist/browser/provider.d.ts +10 -4
- package/dist/browser/provider.d.ts.map +1 -1
- package/dist/browser/provider.js +10 -4
- package/dist/browser/provider.js.map +1 -1
- package/dist/browser/scenario-runner.d.ts +9 -0
- package/dist/browser/scenario-runner.d.ts.map +1 -1
- package/dist/browser/scenario-runner.js +32 -2
- package/dist/browser/scenario-runner.js.map +1 -1
- package/dist/browser/tool-support.js +1 -1
- package/dist/browser/tool-support.js.map +1 -1
- package/dist/cancellation.d.ts +55 -0
- package/dist/cancellation.d.ts.map +1 -0
- package/dist/cancellation.js +76 -0
- package/dist/cancellation.js.map +1 -0
- package/dist/capped.d.ts +41 -0
- package/dist/capped.d.ts.map +1 -0
- package/dist/capped.js +35 -0
- package/dist/capped.js.map +1 -0
- package/dist/registry.d.ts +20 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +71 -4
- package/dist/registry.js.map +1 -1
- package/dist/render.d.ts +92 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +250 -5
- package/dist/render.js.map +1 -1
- package/dist/runtime-registry.d.ts +19 -1
- package/dist/runtime-registry.d.ts.map +1 -1
- package/dist/runtime-registry.js +88 -4
- package/dist/runtime-registry.js.map +1 -1
- package/dist/server.d.ts +19 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +135 -11
- package/dist/server.js.map +1 -1
- package/dist/session.d.ts +22 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +27 -1
- package/dist/session.js.map +1 -1
- package/dist/tools/analyze.d.ts +23 -3
- package/dist/tools/analyze.d.ts.map +1 -1
- package/dist/tools/analyze.js +35 -3
- package/dist/tools/analyze.js.map +1 -1
- package/dist/tools/browser-click.d.ts.map +1 -1
- package/dist/tools/browser-click.js +14 -0
- package/dist/tools/browser-click.js.map +1 -1
- package/dist/tools/browser-fill.d.ts.map +1 -1
- package/dist/tools/browser-fill.js +14 -0
- package/dist/tools/browser-fill.js.map +1 -1
- package/dist/tools/browser-navigate.d.ts.map +1 -1
- package/dist/tools/browser-navigate.js +14 -0
- package/dist/tools/browser-navigate.js.map +1 -1
- package/dist/tools/browser-run-scenario.d.ts.map +1 -1
- package/dist/tools/browser-run-scenario.js +12 -3
- package/dist/tools/browser-run-scenario.js.map +1 -1
- package/dist/tools/browser-save-scenario.d.ts.map +1 -1
- package/dist/tools/browser-save-scenario.js +109 -3
- package/dist/tools/browser-save-scenario.js.map +1 -1
- package/dist/tools/browser-start-session.d.ts.map +1 -1
- package/dist/tools/browser-start-session.js +43 -0
- package/dist/tools/browser-start-session.js.map +1 -1
- package/dist/tools/browser-type.d.ts.map +1 -1
- package/dist/tools/browser-type.js +14 -0
- package/dist/tools/browser-type.js.map +1 -1
- package/dist/tools/contracts.d.ts +41 -10
- package/dist/tools/contracts.d.ts.map +1 -1
- package/dist/tools/contracts.js +117 -17
- package/dist/tools/contracts.js.map +1 -1
- package/dist/tools/cross-pr.d.ts +39 -10
- package/dist/tools/cross-pr.d.ts.map +1 -1
- package/dist/tools/cross-pr.js +113 -29
- package/dist/tools/cross-pr.js.map +1 -1
- package/dist/tools/git-diff.d.ts.map +1 -1
- package/dist/tools/git-diff.js +30 -2
- package/dist/tools/git-diff.js.map +1 -1
- package/dist/tools/impact.d.ts.map +1 -1
- package/dist/tools/impact.js +50 -2
- package/dist/tools/impact.js.map +1 -1
- package/dist/tools/observe-runtime.d.ts.map +1 -1
- package/dist/tools/observe-runtime.js +84 -4
- package/dist/tools/observe-runtime.js.map +1 -1
- package/dist/tools/observe-tests.d.ts +12 -0
- package/dist/tools/observe-tests.d.ts.map +1 -1
- package/dist/tools/observe-tests.js +92 -8
- package/dist/tools/observe-tests.js.map +1 -1
- package/dist/tools/pre-push.d.ts +40 -7
- package/dist/tools/pre-push.d.ts.map +1 -1
- package/dist/tools/pre-push.js +65 -23
- package/dist/tools/pre-push.js.map +1 -1
- package/dist/tools/scope.d.ts.map +1 -1
- package/dist/tools/scope.js +20 -4
- package/dist/tools/scope.js.map +1 -1
- package/dist/tools/validate.d.ts +40 -1
- package/dist/tools/validate.d.ts.map +1 -1
- package/dist/tools/validate.js +150 -27
- package/dist/tools/validate.js.map +1 -1
- package/dist/tools/verification-status.d.ts.map +1 -1
- package/dist/tools/verification-status.js +3 -3
- package/dist/tools/verification-status.js.map +1 -1
- package/dist/transport.d.ts +12 -1
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +30 -16
- package/dist/transport.js.map +1 -1
- package/package.json +22 -13
package/dist/bin/descry-mcp.js
CHANGED
|
@@ -17,9 +17,10 @@
|
|
|
17
17
|
import process from "node:process";
|
|
18
18
|
import { createRequire } from "node:module";
|
|
19
19
|
import { resolve } from "node:path";
|
|
20
|
-
import { createMcpServer } from "../server.js";
|
|
20
|
+
import { createMcpServer, isOutOfBand } from "../server.js";
|
|
21
21
|
import { Session } from "../session.js";
|
|
22
22
|
import { serveStdio } from "../transport.js";
|
|
23
|
+
import { createPlaywrightBrowserDriver } from "../browser/playwright-driver.js";
|
|
23
24
|
/**
|
|
24
25
|
* The version this build actually is, read from the installed package rather
|
|
25
26
|
* than written here.
|
|
@@ -57,9 +58,22 @@ async function main() {
|
|
|
57
58
|
}
|
|
58
59
|
const repoPath = resolve(args[0] ?? process.cwd());
|
|
59
60
|
const session = await Session.open({ repoPath });
|
|
61
|
+
// The nine browser_* tools ask `session.browserBackend()` for a driver
|
|
62
|
+
// factory and get `BROWSER_BACKEND_NOT_INSTALLED` unless one is installed
|
|
63
|
+
// here — `Session` itself never defaults `#browserDriverFactory` away from
|
|
64
|
+
// null. Without this line the tools refuse unconditionally in every real
|
|
65
|
+
// MCP host regardless of what is installed: declaring the dependency in
|
|
66
|
+
// package.json makes `@descryy/runtime-browser` resolvable, not reachable.
|
|
67
|
+
// `createPlaywrightBrowserDriver` itself still turns a missing package, a
|
|
68
|
+
// failed import or a missing Chromium binary into a named refusal rather
|
|
69
|
+
// than a crash — this wiring does not change that.
|
|
70
|
+
session.useBrowserDriverFactory((options) => createPlaywrightBrowserDriver(options));
|
|
60
71
|
const server = createMcpServer({ session, name: "descry", version: VERSION });
|
|
61
72
|
try {
|
|
62
|
-
await serveStdio({ stdin: process.stdin, stdout: process.stdout, stderr: process.stderr }, (line, transport) => server.dispatch(line, transport)
|
|
73
|
+
await serveStdio({ stdin: process.stdin, stdout: process.stdout, stderr: process.stderr }, (line, transport) => server.dispatch(line, transport),
|
|
74
|
+
// Without this, `notifications/cancelled` waits in the ordered queue
|
|
75
|
+
// behind the very call it cancels and can never do anything.
|
|
76
|
+
{ isOutOfBand });
|
|
63
77
|
return 0;
|
|
64
78
|
}
|
|
65
79
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"descry-mcp.js","sourceRoot":"","sources":["../../src/bin/descry-mcp.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"descry-mcp.js","sourceRoot":"","sources":["../../src/bin/descry-mcp.ts"],"names":[],"mappings":"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"}
|
package/dist/browser/driver.d.ts
CHANGED
|
@@ -47,8 +47,21 @@ export interface SnapshotElement {
|
|
|
47
47
|
* read by a human, **not** so a caller can act on it: every verb takes a
|
|
48
48
|
* `ref`, never a selector, because a ref ties the action to a snapshot the
|
|
49
49
|
* agent actually saw and a selector does not.
|
|
50
|
+
*
|
|
51
|
+
* Also what a scenario stores to find the element again in a *later*
|
|
52
|
+
* session (`scenario-resolve.ts`), which is the property that actually
|
|
53
|
+
* needs it to be durable — a value scoped to this one snapshot would defeat
|
|
54
|
+
* that the moment the generation counter moved on.
|
|
55
|
+
*
|
|
56
|
+
* **Null when no candidate resolves to exactly one element on the page.**
|
|
57
|
+
* A driver must never fabricate a selector that might not match, or might
|
|
58
|
+
* match the wrong thing — that is precision over recall (rule 2) applied
|
|
59
|
+
* here: an honest null beats a value that looks like a selector and isn't
|
|
60
|
+
* one. `browser_save_scenario` refuses to save a step naming such an
|
|
61
|
+
* element, by name, rather than writing a scenario doomed to fail at
|
|
62
|
+
* replay.
|
|
50
63
|
*/
|
|
51
|
-
readonly selector: string;
|
|
64
|
+
readonly selector: string | null;
|
|
52
65
|
}
|
|
53
66
|
export interface PageSnapshot {
|
|
54
67
|
readonly url: string;
|
|
@@ -86,24 +99,80 @@ export interface ObservedAction {
|
|
|
86
99
|
readonly url: string;
|
|
87
100
|
readonly at: string;
|
|
88
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* What `rewriteScriptUrls` did with one script URL in a stack.
|
|
104
|
+
*
|
|
105
|
+
* Per URL rather than a summary, because partial mapping is the steady state:
|
|
106
|
+
* an application's own bundle maps, its CDN dependency does not, and a
|
|
107
|
+
* browser extension's frame never will. Collapsing that into a count would
|
|
108
|
+
* report a shortfall where there is a boundary, and would leave a caller
|
|
109
|
+
* unable to tell a misconfigured `documentRoot` from a third-party script it
|
|
110
|
+
* should ignore.
|
|
111
|
+
*/
|
|
112
|
+
export interface ScriptUrlOutcome {
|
|
113
|
+
/** The URL as it appeared in the stack, `:line:column` suffix included. */
|
|
114
|
+
readonly url: string;
|
|
115
|
+
/** The on-disk file it was rewritten to, or null when it was left as a URL. */
|
|
116
|
+
readonly mapped: string | null;
|
|
117
|
+
/** Why it was left alone. Null exactly when `mapped` is set. */
|
|
118
|
+
readonly reason: string | null;
|
|
119
|
+
}
|
|
89
120
|
export interface ObservedConsoleError {
|
|
90
121
|
readonly text: string;
|
|
91
122
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
123
|
+
* The stack, rendered from parsed frames, or null.
|
|
124
|
+
*
|
|
125
|
+
* Already rewritten to real files and lines where that was possible:
|
|
126
|
+
* `rewriteScriptUrls` runs inside the runtime collector, on the stack text
|
|
127
|
+
* *before* the parser sees it, using the `resolveSourceRoot` the driver put
|
|
128
|
+
* on the collector context. What survives as an `http://` URL here is a
|
|
129
|
+
* frame that genuinely did not map, and `scriptUrlMapping` says why.
|
|
96
130
|
*/
|
|
97
131
|
readonly stackText: string | null;
|
|
132
|
+
/**
|
|
133
|
+
* Per-URL mapping outcomes from the collector, empty when it attempted no
|
|
134
|
+
* mapping. **Empty is not "nothing mapped"** — it is "no rewrite ran",
|
|
135
|
+
* which happens with no stack parser configured, and the two must not be
|
|
136
|
+
* reported alike.
|
|
137
|
+
*/
|
|
138
|
+
readonly scriptUrlMapping: readonly ScriptUrlOutcome[];
|
|
98
139
|
readonly at: string;
|
|
99
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* How a request's lifecycle actually ended, when the collector can tell.
|
|
143
|
+
*
|
|
144
|
+
* `status: null` used to carry two different facts at once: "this will never
|
|
145
|
+
* answer" and "it has not answered *yet*". `"pending"` splits the second one
|
|
146
|
+
* back out — a request still in flight when the observation window closed is
|
|
147
|
+
* neither a success nor a failure, and folding it into either taught a false
|
|
148
|
+
* positive on a perfectly healthy, still-loading page.
|
|
149
|
+
*
|
|
150
|
+
* - `"answered"` — a real status came back, carried in `status`.
|
|
151
|
+
* - `"unanswered"` — a real failure: Playwright's own `requestfailed` fired,
|
|
152
|
+
* or the page closed with this request outstanding.
|
|
153
|
+
* - `"pending"` — still in flight when the drain happened. Not a verdict
|
|
154
|
+
* either way; reported under its own key rather than as a failure.
|
|
155
|
+
*/
|
|
156
|
+
export type RequestOutcome = "answered" | "unanswered" | "pending";
|
|
100
157
|
export interface ObservedRequest {
|
|
101
158
|
readonly method: string;
|
|
102
159
|
readonly url: string;
|
|
103
160
|
/** Null when the request produced no response at all, which is a different fact from a 500. */
|
|
104
161
|
readonly status: number | null;
|
|
162
|
+
/**
|
|
163
|
+
* How this request's lifecycle ended, when the collector reports it.
|
|
164
|
+
*
|
|
165
|
+
* Optional on purpose: the field is `descry-runtime`'s browser collector to
|
|
166
|
+
* populate (a separate lane's work), and this port must not assume that
|
|
167
|
+
* build is running. Absent means no outcome information at all — see
|
|
168
|
+
* `isFailedRequest`, which degrades to its pre-existing status-only rule
|
|
169
|
+
* rather than mis-reading an older build's silence as a new fact.
|
|
170
|
+
*/
|
|
171
|
+
readonly outcome?: RequestOutcome;
|
|
105
172
|
/** The `fetch()` call site as raw text, when the initiator capture claimed one. Null is honest absence. */
|
|
106
173
|
readonly stackText: string | null;
|
|
174
|
+
/** Per-URL mapping outcomes for that call site. See `ScriptUrlOutcome`. */
|
|
175
|
+
readonly scriptUrlMapping: readonly ScriptUrlOutcome[];
|
|
107
176
|
/**
|
|
108
177
|
* The same call site, parsed into frames with real file paths.
|
|
109
178
|
*
|
|
@@ -116,7 +185,17 @@ export interface ObservedRequest {
|
|
|
116
185
|
readonly stackTrace: StackTrace | null;
|
|
117
186
|
readonly at: string;
|
|
118
187
|
}
|
|
119
|
-
/**
|
|
188
|
+
/**
|
|
189
|
+
* A request that did not succeed. Mechanical, not a judgement.
|
|
190
|
+
*
|
|
191
|
+
* With no `outcome` reported (an older `descry-runtime` build), this keeps
|
|
192
|
+
* the original rule exactly: no response at all, or a 4xx/5xx status. With an
|
|
193
|
+
* `outcome`, `"pending"` is deliberately excluded — a request still in flight
|
|
194
|
+
* when the window closed is not evidence of anything — and `"unanswered"` is
|
|
195
|
+
* always a failure regardless of `status`, since Playwright's own
|
|
196
|
+
* `requestfailed` (or a page closing mid-request) is a stronger signal than
|
|
197
|
+
* an absent status by itself.
|
|
198
|
+
*/
|
|
120
199
|
export declare function isFailedRequest(request: ObservedRequest): boolean;
|
|
121
200
|
/** Everything witnessed since the last drain. Raw — see this file's header. */
|
|
122
201
|
export interface BrowserObservation {
|
|
@@ -131,6 +210,26 @@ export interface BrowserObservation {
|
|
|
131
210
|
* The reply narrows to failures for readability; the correlation does not.
|
|
132
211
|
*/
|
|
133
212
|
readonly requests: readonly ObservedRequest[];
|
|
213
|
+
/**
|
|
214
|
+
* Actions whose network activity had not finished when the driver stopped
|
|
215
|
+
* waiting.
|
|
216
|
+
*
|
|
217
|
+
* This exists because the alternative is the failure this surface is built
|
|
218
|
+
* to prevent. An action returns after a bounded wait; if a request it
|
|
219
|
+
* caused is still in flight at that bound, its evidence lands after the
|
|
220
|
+
* drain and is simply not in the reply — and a reply missing evidence looks
|
|
221
|
+
* exactly like a reply from a page that produced none. One is "nothing
|
|
222
|
+
* happened", the other is "I stopped looking", and rule 7 does not permit
|
|
223
|
+
* them to render the same. Anything in here means the observation for that
|
|
224
|
+
* action is incomplete and says so.
|
|
225
|
+
*/
|
|
226
|
+
readonly unsettled: readonly UnsettledAction[];
|
|
227
|
+
}
|
|
228
|
+
export interface UnsettledAction {
|
|
229
|
+
readonly action: ObservedAction["action"];
|
|
230
|
+
readonly ref: string | null;
|
|
231
|
+
/** How long the driver waited before giving up, in ms. */
|
|
232
|
+
readonly waitedMs: number;
|
|
134
233
|
}
|
|
135
234
|
export declare const EMPTY_OBSERVATION: BrowserObservation;
|
|
136
235
|
export interface BrowserLaunchOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/browser/driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE7D,sFAAsF;AACtF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/browser/driver.ts"],"names":[],"mappings":"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"}
|
package/dist/browser/driver.js
CHANGED
|
@@ -36,11 +36,25 @@
|
|
|
36
36
|
* Rule 1 holds here as everywhere — nothing in this file names a language, a
|
|
37
37
|
* framework, or a file extension.
|
|
38
38
|
*/
|
|
39
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* A request that did not succeed. Mechanical, not a judgement.
|
|
41
|
+
*
|
|
42
|
+
* With no `outcome` reported (an older `descry-runtime` build), this keeps
|
|
43
|
+
* the original rule exactly: no response at all, or a 4xx/5xx status. With an
|
|
44
|
+
* `outcome`, `"pending"` is deliberately excluded — a request still in flight
|
|
45
|
+
* when the window closed is not evidence of anything — and `"unanswered"` is
|
|
46
|
+
* always a failure regardless of `status`, since Playwright's own
|
|
47
|
+
* `requestfailed` (or a page closing mid-request) is a stronger signal than
|
|
48
|
+
* an absent status by itself.
|
|
49
|
+
*/
|
|
40
50
|
export function isFailedRequest(request) {
|
|
41
|
-
|
|
51
|
+
if (request.outcome === undefined)
|
|
52
|
+
return request.status === null || request.status >= 400;
|
|
53
|
+
if (request.outcome === "pending")
|
|
54
|
+
return false;
|
|
55
|
+
return request.outcome === "unanswered" || (request.status !== null && request.status >= 400);
|
|
42
56
|
}
|
|
43
|
-
export const EMPTY_OBSERVATION = { actions: [], consoleErrors: [], requests: [] };
|
|
57
|
+
export const EMPTY_OBSERVATION = { actions: [], consoleErrors: [], requests: [], unsettled: [] };
|
|
44
58
|
/** The browser died. Distinct from a closed session: a crash invalidates the id rather than ending it cleanly. */
|
|
45
59
|
export class BrowserSessionCrashedError extends Error {
|
|
46
60
|
sessionId;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../src/browser/driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;
|
|
1
|
+
{"version":3,"file":"driver.js","sourceRoot":"","sources":["../../src/browser/driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAgKH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAAC,OAAwB;IACtD,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC;IAC3F,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAChD,OAAO,OAAO,CAAC,OAAO,KAAK,YAAY,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC;AAChG,CAAC;AAsCD,MAAM,CAAC,MAAM,iBAAiB,GAAuB,EAAE,OAAO,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;AA0BrH,kHAAkH;AAClH,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAC1C,SAAS,CAAS;IAE3B,YAAY,SAAiB;QAC3B,KAAK,CACH,mBAAmB,SAAS,yEAAyE;YACnG,gGAAgG;YAChG,+EAA+E,CAClF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;QACzC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/C,YAAY,GAAW;QACrB,KAAK,CACH,IAAI,GAAG,+FAA+F;YACpG,kFAAkF,CACrF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF"}
|
|
@@ -29,9 +29,20 @@ export interface BrowserEvidenceReport {
|
|
|
29
29
|
* frontend action reached a backend route.
|
|
30
30
|
*/
|
|
31
31
|
readonly failedRequests: readonly ObservedRequest[];
|
|
32
|
+
/**
|
|
33
|
+
* Requests still in flight when the observation window closed.
|
|
34
|
+
*
|
|
35
|
+
* Not a failure and not a success — `isFailedRequest` deliberately excludes
|
|
36
|
+
* these. Reported under its own key rather than silently absent, because a
|
|
37
|
+
* healthy request that simply had not answered yet must not read the same
|
|
38
|
+
* as a page that issued nothing.
|
|
39
|
+
*/
|
|
40
|
+
readonly pendingRequests: readonly ObservedRequest[];
|
|
32
41
|
/** How many requests the page issued in total, so the list above is read as a subset and not as all of it. */
|
|
33
42
|
readonly totalRequests: number;
|
|
34
43
|
readonly actions: BrowserObservation["actions"];
|
|
44
|
+
/** Actions the driver stopped waiting on. Empty on every ordinary reply. */
|
|
45
|
+
readonly unsettled: BrowserObservation["unsettled"];
|
|
35
46
|
}
|
|
36
47
|
export declare function evidenceReport(observation: BrowserObservation): BrowserEvidenceReport;
|
|
37
48
|
export declare function isEmpty(report: BrowserEvidenceReport): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../../src/browser/evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAmB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7F,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,aAAa,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAC5D;;;;;;;;;OASG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,eAAe,EAAE,CAAC;IACpD,8GAA8G;IAC9G,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../../src/browser/evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAmB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAE7F,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,aAAa,EAAE,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAC5D;;;;;;;;;OASG;IACH,QAAQ,CAAC,cAAc,EAAE,SAAS,eAAe,EAAE,CAAC;IACpD;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,EAAE,SAAS,eAAe,EAAE,CAAC;IACrD,8GAA8G;IAC9G,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAChD,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAC;CACrD;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,kBAAkB,GAAG,qBAAqB,CASrF;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAE9D;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAmCrE"}
|
package/dist/browser/evidence.js
CHANGED
|
@@ -20,12 +20,14 @@ export function evidenceReport(observation) {
|
|
|
20
20
|
return {
|
|
21
21
|
consoleErrors: observation.consoleErrors,
|
|
22
22
|
failedRequests: observation.requests.filter(isFailedRequest),
|
|
23
|
+
pendingRequests: observation.requests.filter((request) => request.outcome === "pending"),
|
|
23
24
|
totalRequests: observation.requests.length,
|
|
24
25
|
actions: observation.actions,
|
|
26
|
+
unsettled: observation.unsettled,
|
|
25
27
|
};
|
|
26
28
|
}
|
|
27
29
|
export function isEmpty(report) {
|
|
28
|
-
return report.consoleErrors.length === 0 && report.failedRequests.length === 0;
|
|
30
|
+
return report.consoleErrors.length === 0 && report.failedRequests.length === 0 && report.pendingRequests.length === 0;
|
|
29
31
|
}
|
|
30
32
|
/**
|
|
31
33
|
* The notes any reply carrying evidence must include.
|
|
@@ -36,20 +38,74 @@ export function isEmpty(report) {
|
|
|
36
38
|
* how a real disclosure stops being read.
|
|
37
39
|
*/
|
|
38
40
|
export function evidenceNotes(report) {
|
|
41
|
+
// Checked before the emptiness gate, deliberately. An action whose network
|
|
42
|
+
// never settled produces a report that can be *empty in every other
|
|
43
|
+
// respect*, and staying silent about it is the one thing this note exists
|
|
44
|
+
// to prevent: the reply would then be indistinguishable from a clean one.
|
|
45
|
+
const unsettledNotes = report.unsettled.map((item) => `The "${item.action}" action${item.ref === null ? "" : ` on ${item.ref}`} was still causing network ` +
|
|
46
|
+
`activity when Descry stopped waiting, after ${item.waitedMs}ms. Evidence for anything that finished ` +
|
|
47
|
+
"after that point is not in this reply — this is an incomplete observation of that action, not a " +
|
|
48
|
+
"clean one.");
|
|
49
|
+
// Checked before the emptiness gate too, and for the same reason as
|
|
50
|
+
// `unsettledNotes`: a request that is merely still in flight is not a
|
|
51
|
+
// failure and must not be silently folded into a report that then reads as
|
|
52
|
+
// clean when it is really "the window closed before this one finished."
|
|
53
|
+
const pendingNotes = report.pendingRequests.map((request) => `${request.method} ${request.url} was still in flight when the observation window closed. That is not ` +
|
|
54
|
+
"evidence it will fail — the request simply had not answered yet.");
|
|
39
55
|
if (isEmpty(report))
|
|
40
|
-
return [];
|
|
56
|
+
return [...unsettledNotes, ...pendingNotes];
|
|
41
57
|
const notes = [
|
|
58
|
+
...unsettledNotes,
|
|
59
|
+
...pendingNotes,
|
|
42
60
|
`${report.consoleErrors.length} console error(s) and ${report.failedRequests.length} failed request(s) ` +
|
|
43
61
|
"were observed in the browser during this call. They are reported raw and have not been triaged — " +
|
|
44
62
|
"Descry is not claiming any of them is a bug, only that the page produced them. Deciding which " +
|
|
45
63
|
"matter is the calling agent's job.",
|
|
46
64
|
];
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
65
|
+
return [...notes, ...scriptUrlNotes(report)];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* What the source-root mapping actually managed, per URL.
|
|
69
|
+
*
|
|
70
|
+
* This replaced a heuristic that sniffed rendered stack text for the
|
|
71
|
+
* substring `http` and reported a count. Two things were wrong with it. It
|
|
72
|
+
* guessed at an answer the collector had already computed exactly — and its
|
|
73
|
+
* guess was broken besides, since it also required the text to not start with
|
|
74
|
+
* `/`, which a rendering that begins `> at fn (…)` never does. And it
|
|
75
|
+
* described the mapping as un-wired, which stopped being true once
|
|
76
|
+
* `browser_start_session` began building a `resolveSourceRoot` for every
|
|
77
|
+
* session: the rewrite runs inside the runtime collector, on the stack text
|
|
78
|
+
* before the parser reads it.
|
|
79
|
+
*
|
|
80
|
+
* What remains worth disclosing is narrower and real: **which** URLs did not
|
|
81
|
+
* map, and why. Partial coverage is the normal case — an application's own
|
|
82
|
+
* bundle maps and its CDN dependency does not — so the note leads with the
|
|
83
|
+
* coverage and then names each miss with the collector's own reason. A caller
|
|
84
|
+
* can then tell a misconfigured document root from a third-party script that
|
|
85
|
+
* was never going to map.
|
|
86
|
+
*/
|
|
87
|
+
function scriptUrlNotes(report) {
|
|
88
|
+
const outcomes = [...report.consoleErrors, ...report.failedRequests].flatMap((item) => item.scriptUrlMapping);
|
|
89
|
+
// No outcomes means no rewrite was attempted — no stack parser, or no stack
|
|
90
|
+
// at all. That is not a mapping shortfall and must not be reported as one.
|
|
91
|
+
if (outcomes.length === 0)
|
|
92
|
+
return [];
|
|
93
|
+
const unmapped = outcomes.filter((outcome) => outcome.mapped === null);
|
|
94
|
+
if (unmapped.length === 0)
|
|
95
|
+
return [];
|
|
96
|
+
// De-duplicated: one script referenced from ten frames is one unmapped
|
|
97
|
+
// script, and listing it ten times would overstate the shortfall.
|
|
98
|
+
const byUrl = new Map();
|
|
99
|
+
for (const outcome of unmapped) {
|
|
100
|
+
if (!byUrl.has(outcome.url))
|
|
101
|
+
byUrl.set(outcome.url, outcome.reason ?? "no reason given");
|
|
52
102
|
}
|
|
53
|
-
|
|
103
|
+
const distinct = new Set(outcomes.map((outcome) => outcome.url));
|
|
104
|
+
return [
|
|
105
|
+
`${distinct.size - byUrl.size} of ${distinct.size} script URL(s) in these stacks were mapped back to ` +
|
|
106
|
+
"repository files. The rest are reported as the URLs the browser gave, not as a guessed file — a stack " +
|
|
107
|
+
"frame pointing at the wrong line is worse than one that admits it is a URL:\n" +
|
|
108
|
+
[...byUrl].map(([url, reason]) => ` ${url} — ${reason}`).join("\n"),
|
|
109
|
+
];
|
|
54
110
|
}
|
|
55
111
|
//# sourceMappingURL=evidence.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/browser/evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,eAAe,EAAiD,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/browser/evidence.ts"],"names":[],"mappings":"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"}
|
|
@@ -41,6 +41,8 @@ export interface FakeBrowserDriver extends BrowserDriver {
|
|
|
41
41
|
readonly status: number | null;
|
|
42
42
|
readonly stackText: string | null;
|
|
43
43
|
readonly stackTrace?: ObservedRequest["stackTrace"];
|
|
44
|
+
/** Omit to leave this request's outcome unreported, the way an older `descry-runtime` build would. */
|
|
45
|
+
readonly outcome?: ObservedRequest["outcome"];
|
|
44
46
|
}): void;
|
|
45
47
|
/** Sugar for `emitRequest` with a failing status. */
|
|
46
48
|
emitFailedRequest(sessionId: string, request: {
|
|
@@ -49,6 +51,12 @@ export interface FakeBrowserDriver extends BrowserDriver {
|
|
|
49
51
|
readonly status: number | null;
|
|
50
52
|
readonly stackText: string | null;
|
|
51
53
|
}): void;
|
|
54
|
+
/** Sugar for `emitRequest` still in flight when the window closed — `outcome: "pending"`, `status: null`. */
|
|
55
|
+
emitPendingRequest(sessionId: string, request: {
|
|
56
|
+
readonly method: string;
|
|
57
|
+
readonly url: string;
|
|
58
|
+
readonly stackText: string | null;
|
|
59
|
+
}): void;
|
|
52
60
|
/** Kill the browser behind a session, the way a real crash does — usable goes false, the id stays invalid. */
|
|
53
61
|
crash(sessionId: string): void;
|
|
54
62
|
/** Every session this driver has opened and not closed. What the registry's orphan-cleanup tests assert against. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-driver.d.ts","sourceRoot":"","sources":["../../src/browser/fake-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAGL,KAAK,aAAa,EAOlB,KAAK,eAAe,EAGrB,MAAM,aAAa,CAAC;AAErB,mFAAmF;AACnF,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3G;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,0JAA0J;IAC1J,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3C,kFAAkF;IAClF,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/G,iGAAiG;IACjG,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;QACP,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"fake-driver.d.ts","sourceRoot":"","sources":["../../src/browser/fake-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAGL,KAAK,aAAa,EAOlB,KAAK,eAAe,EAGrB,MAAM,aAAa,CAAC;AAErB,mFAAmF;AACnF,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3G;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,0JAA0J;IAC1J,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3C,kFAAkF;IAClF,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC/G,iGAAiG;IACjG,WAAW,CACT,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;QACP,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAC;QACpD,sGAAsG;QACtG,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC;KAC/C,GACA,IAAI,CAAC;IACR,qDAAqD;IACrD,iBAAiB,CACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAC5H,IAAI,CAAC;IACR,6GAA6G;IAC7G,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3I,8GAA8G;IAC9G,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,oHAAoH;IACpH,cAAc,IAAI,SAAS,MAAM,EAAE,CAAC;CACrC;AAeD,wBAAgB,uBAAuB,IAAI,iBAAiB,CA6K3D"}
|
|
@@ -35,6 +35,8 @@ export function createFakeBrowserDriver() {
|
|
|
35
35
|
actions: state.buffer.actions,
|
|
36
36
|
consoleErrors: state.buffer.consoleErrors,
|
|
37
37
|
requests: state.buffer.requests,
|
|
38
|
+
// The fake page has no network, so nothing can be left in flight.
|
|
39
|
+
unsettled: [],
|
|
38
40
|
};
|
|
39
41
|
state.buffer.actions = [];
|
|
40
42
|
state.buffer.consoleErrors = [];
|
|
@@ -142,13 +144,34 @@ export function createFakeBrowserDriver() {
|
|
|
142
144
|
chromiumMissing = { remedy };
|
|
143
145
|
},
|
|
144
146
|
emitConsoleError(sessionId, error) {
|
|
145
|
-
stateOf(sessionId).buffer.consoleErrors.push({ ...error, at: new Date().toISOString() });
|
|
147
|
+
stateOf(sessionId).buffer.consoleErrors.push({ scriptUrlMapping: [], ...error, at: new Date().toISOString() });
|
|
146
148
|
},
|
|
147
149
|
emitRequest(sessionId, request) {
|
|
148
|
-
|
|
150
|
+
// `outcome` is destructured out and re-added only when present:
|
|
151
|
+
// `exactOptionalPropertyTypes` treats a spread of an optional field as
|
|
152
|
+
// `T | undefined`, which `ObservedRequest`'s own `outcome?:` does not
|
|
153
|
+
// accept — the key must be omitted, never present as `undefined`.
|
|
154
|
+
const { outcome, ...rest } = request;
|
|
155
|
+
stateOf(sessionId).buffer.requests.push({
|
|
156
|
+
stackTrace: null,
|
|
157
|
+
scriptUrlMapping: [],
|
|
158
|
+
...rest,
|
|
159
|
+
...(outcome === undefined ? {} : { outcome }),
|
|
160
|
+
at: new Date().toISOString(),
|
|
161
|
+
});
|
|
149
162
|
},
|
|
150
163
|
emitFailedRequest(sessionId, request) {
|
|
151
|
-
stateOf(sessionId).buffer.requests.push({ ...request, stackTrace: null, at: new Date().toISOString() });
|
|
164
|
+
stateOf(sessionId).buffer.requests.push({ scriptUrlMapping: [], ...request, stackTrace: null, at: new Date().toISOString() });
|
|
165
|
+
},
|
|
166
|
+
emitPendingRequest(sessionId, request) {
|
|
167
|
+
stateOf(sessionId).buffer.requests.push({
|
|
168
|
+
scriptUrlMapping: [],
|
|
169
|
+
stackTrace: null,
|
|
170
|
+
...request,
|
|
171
|
+
status: null,
|
|
172
|
+
outcome: "pending",
|
|
173
|
+
at: new Date().toISOString(),
|
|
174
|
+
});
|
|
152
175
|
},
|
|
153
176
|
crash(sessionId) {
|
|
154
177
|
stateOf(sessionId).crashed = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-driver.js","sourceRoot":"","sources":["../../src/browser/fake-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EACL,0BAA0B,EAC1B,sBAAsB,GAWvB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"fake-driver.js","sourceRoot":"","sources":["../../src/browser/fake-driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The real `BrowserDriver`, over `@descryy/runtime-browser`.
|
|
3
3
|
*
|
|
4
|
-
* ## Why the import is dynamic
|
|
4
|
+
* ## Why the import is still dynamic
|
|
5
5
|
*
|
|
6
|
-
* `@descryy/runtime-browser` is
|
|
7
|
-
* (`mcp-browser-tools.md` §3.1 — the
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
6
|
+
* `@descryy/runtime-browser` is now a declared dependency of `@descryy/mcp`
|
|
7
|
+
* (`mcp-browser-tools.md` §3.1's publish landed) — so the reason this module
|
|
8
|
+
* used to give for a call-time specifier import, "not on the registry yet,"
|
|
9
|
+
* no longer holds. It stays dynamic anyway, for a reason that outgrew that
|
|
10
|
+
* one: `loadRuntimeModule` (`PlaywrightDriverOptions`, below) is a real
|
|
11
|
+
* injection seam that `browser-action-settle.test.ts` uses today to drive
|
|
12
|
+
* this file's settle logic against a fake module shaped like this one,
|
|
13
|
+
* deterministically, with no real browser involved. A static
|
|
14
|
+
* `import … from "@descryy/runtime-browser"` at the top of this file would
|
|
15
|
+
* remove that seam along with the indirection, and nothing here needs
|
|
16
|
+
* removing it — the package being on the registry made the *dependency*
|
|
17
|
+
* declarable, not the import path mandatory. Absence (package missing,
|
|
18
|
+
* import throws, or Chromium missing) is still a **named refusal with a
|
|
19
|
+
* remedy**, exactly as before — see `provider.ts`.
|
|
17
20
|
*
|
|
18
21
|
* ## What this adds over the runtime package, and what it deliberately does not
|
|
19
22
|
*
|
|
@@ -38,9 +41,9 @@
|
|
|
38
41
|
* the same reason. Without one, requests are still observed and no caller
|
|
39
42
|
* edge is written; the reply says so.
|
|
40
43
|
*/
|
|
41
|
-
import type { ServiceRootLookup } from "@descryy/runtime-contracts";
|
|
44
|
+
import type { StackTrace, ServiceRootLookup } from "@descryy/runtime-contracts";
|
|
42
45
|
import type { StackTraceParser } from "@descryy/runtime-backend-observation";
|
|
43
|
-
import type { BrowserDriver } from "./driver.ts";
|
|
46
|
+
import type { BrowserDriver, BrowserObservation, ObservedAction, UnsettledAction } from "./driver.ts";
|
|
44
47
|
export interface PlaywrightDriverOptions {
|
|
45
48
|
/**
|
|
46
49
|
* Turns a raw browser stack into resolved frames. Supplied by the caller;
|
|
@@ -55,11 +58,62 @@ export interface PlaywrightDriverOptions {
|
|
|
55
58
|
readonly resolveSourceRoot?: SourceRootResolver;
|
|
56
59
|
/** Which service the evidence is attributed to. */
|
|
57
60
|
readonly service?: string;
|
|
61
|
+
/**
|
|
62
|
+
* How the runtime browser module is loaded. Defaults to importing
|
|
63
|
+
* `@descryy/runtime-browser` by specifier.
|
|
64
|
+
*
|
|
65
|
+
* It exists because the settle logic below is timing-dependent and this
|
|
66
|
+
* build has no browser backend to run it against — the conformance test
|
|
67
|
+
* that would exercise it skips on every machine without
|
|
68
|
+
* `@descryy/runtime-browser` and Chromium. A driver-level fake page is the
|
|
69
|
+
* only way that logic is executable at all here — and a sleep that dropped
|
|
70
|
+
* evidence shipped in this file with no executable test over it at all,
|
|
71
|
+
* which is the argument for the seam rather than against it.
|
|
72
|
+
*
|
|
73
|
+
* Keep it. Ruled on when it was introduced: exporting `openSession` instead
|
|
74
|
+
* would widen the public surface to an internal lifecycle, where this
|
|
75
|
+
* narrows to one injection point with a stated purpose.
|
|
76
|
+
*/
|
|
77
|
+
readonly loadRuntimeModule?: () => Promise<unknown>;
|
|
58
78
|
}
|
|
59
79
|
type SourceRootResolver = (origin: string) => ServiceRootLookup;
|
|
60
80
|
export declare class BrowserBackendMissingError extends Error {
|
|
61
81
|
constructor(cause: unknown);
|
|
62
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* An `Evidence`-shaped record, as the collectors emit it.
|
|
85
|
+
*
|
|
86
|
+
* Typed structurally rather than imported wholesale because only four fields
|
|
87
|
+
* are read: everything else the collectors attach travels to nobody here.
|
|
88
|
+
*/
|
|
89
|
+
/**
|
|
90
|
+
* Exported for `browser-request-outcome-mapping.test.ts`, which drives
|
|
91
|
+
* `collect()` directly with synthetic evidence records — the real
|
|
92
|
+
* evidence-to-`ObservedRequest` mapping, not the fake driver's fixtures. That
|
|
93
|
+
* test is the regression test for B3: the fake driver lets a fixture declare
|
|
94
|
+
* `outcome` directly, which let this mapping function ship never populating
|
|
95
|
+
* the field at all while every test still passed.
|
|
96
|
+
*/
|
|
97
|
+
export interface EmittedEvidence {
|
|
98
|
+
readonly eventType: string;
|
|
99
|
+
readonly payload: Record<string, unknown>;
|
|
100
|
+
readonly stackTrace: StackTrace | null;
|
|
101
|
+
readonly requestId: string | null;
|
|
102
|
+
readonly timestamp: string;
|
|
103
|
+
}
|
|
63
104
|
export declare function createPlaywrightBrowserDriver(options?: PlaywrightDriverOptions): Promise<BrowserDriver>;
|
|
105
|
+
/**
|
|
106
|
+
* Turn what the collectors emitted into the port's vocabulary.
|
|
107
|
+
*
|
|
108
|
+
* The request/response join is on `requestId`, because a `NETWORK_REQUEST`
|
|
109
|
+
* carries the method, the URL and the call-site stack while only the matching
|
|
110
|
+
* `NETWORK_RESPONSE` knows the status. A request with no response is kept with
|
|
111
|
+
* `status: null` — "never answered" is a different fact from a 500, and the
|
|
112
|
+
* port says so.
|
|
113
|
+
*
|
|
114
|
+
* Exported for `browser-request-outcome-mapping.test.ts` — see
|
|
115
|
+
* `EmittedEvidence`'s doc comment for why.
|
|
116
|
+
*/
|
|
117
|
+
export declare function collect(emitted: readonly EmittedEvidence[], actions: readonly ObservedAction[], unsettled: readonly UnsettledAction[]): BrowserObservation;
|
|
64
118
|
export {};
|
|
65
119
|
//# sourceMappingURL=playwright-driver.d.ts.map
|