@dimina-kit/devtools 0.4.0-dev.20260717120050 → 0.4.0-dev.20260718085557
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/main/app/app.js +3 -1
- package/dist/main/index.bundle.js +7611 -7304
- package/dist/main/services/cdp-session/index.d.ts +87 -0
- package/dist/main/services/cdp-session/index.js +173 -0
- package/dist/main/services/elements-forward/index.d.ts +132 -15
- package/dist/main/services/elements-forward/index.js +162 -229
- package/dist/main/services/network-forward/body-cache.d.ts +70 -0
- package/dist/main/services/network-forward/body-cache.js +175 -0
- package/dist/main/services/network-forward/frontend-dispatch.d.ts +27 -0
- package/dist/main/services/network-forward/frontend-dispatch.js +42 -0
- package/dist/main/services/network-forward/index.d.ts +80 -9
- package/dist/main/services/network-forward/index.js +419 -149
- package/dist/main/services/render-inspect/index.d.ts +10 -0
- package/dist/main/services/render-inspect/index.js +17 -98
- package/dist/main/services/safe-area/index.d.ts +4 -1
- package/dist/main/services/safe-area/index.js +62 -34
- package/dist/main/services/simulator-storage/index.d.ts +22 -4
- package/dist/main/services/simulator-storage/index.js +51 -64
- package/dist/main/services/views/native-simulator-devtools-host.js +12 -1
- package/dist/main/services/views/native-simulator-view.js +6 -0
- package/dist/main/services/views/view-manager.d.ts +9 -0
- package/dist/main/services/views/view-manager.js +1 -1
- package/dist/main/services/workbench-context.d.ts +9 -0
- package/dist/main/services/workbench-context.js +3 -0
- package/package.json +5 -5
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PrefetchCache — a bounded, TTL'd "prime now / read later" promise cache.
|
|
3
|
+
*
|
|
4
|
+
* The network forwarder prefetches `Network.getResponseBody` /
|
|
5
|
+
* `Network.getRequestPostData` from the simulator's CDP session the moment a
|
|
6
|
+
* request finishes (the renderer may evict the resource soon after), keyed by
|
|
7
|
+
* the namespaced virtual requestId. A later Response-tab click resolves from
|
|
8
|
+
* here instead of re-issuing a debugger round-trip against a session that may
|
|
9
|
+
* have moved on.
|
|
10
|
+
*
|
|
11
|
+
* Contract:
|
|
12
|
+
* - `prime(id, fetch)` is idempotent per id: while an entry is pending or a
|
|
13
|
+
* settled entry is still live, later primes are ignored.
|
|
14
|
+
* - A fetch rejection — or a resolved value whose `sizeOf` exceeds
|
|
15
|
+
* `perEntryMaxChars` — becomes an ERROR SENTINEL: the id stays known but
|
|
16
|
+
* every lookup rejects with the canonical not-found message (the same
|
|
17
|
+
* answer a real CDP backend gives for an unknown requestId, so the
|
|
18
|
+
* front-end renders its normal failure state).
|
|
19
|
+
* - `lookup(id)` resolves the cached value, awaits a still-pending fetch (a
|
|
20
|
+
* panel click can land before the prefetch settles), and rejects
|
|
21
|
+
* not-found for unknown / expired / evicted / sentinel entries.
|
|
22
|
+
* - Bounds apply to SETTLED entries only: LRU by settle/lookup recency up to
|
|
23
|
+
* `maxEntries`, plus a `maxTotalChars` budget over `sizeOf`. A pending
|
|
24
|
+
* entry counts 0 and is never evicted — evicting an in-flight prefetch
|
|
25
|
+
* would strand its waiters.
|
|
26
|
+
* - TTL is anchored to the SETTLE time (not the prime() call time) and is
|
|
27
|
+
* enforced lazily on the next prime/lookup.
|
|
28
|
+
*/
|
|
29
|
+
const NOT_FOUND = 'No resource with given identifier found';
|
|
30
|
+
/**
|
|
31
|
+
* Default per-entry size ceiling (chars). Exported so callers that need to
|
|
32
|
+
* pre-screen a fetch BEFORE issuing it (e.g. skipping a CDP round-trip for a
|
|
33
|
+
* response already known to be oversized) reference the exact same number
|
|
34
|
+
* `PrefetchCache`'s own default enforces — one source of truth, not two
|
|
35
|
+
* independently-configured limits that could silently drift apart.
|
|
36
|
+
*/
|
|
37
|
+
export const DEFAULT_PER_ENTRY_MAX_CHARS = 16 * 1024 * 1024;
|
|
38
|
+
export class PrefetchCache {
|
|
39
|
+
sizeOf;
|
|
40
|
+
map = new Map();
|
|
41
|
+
maxEntries;
|
|
42
|
+
maxTotalChars;
|
|
43
|
+
perEntryMaxChars;
|
|
44
|
+
ttlMs;
|
|
45
|
+
now;
|
|
46
|
+
constructor(sizeOf, opts = {}) {
|
|
47
|
+
this.sizeOf = sizeOf;
|
|
48
|
+
this.maxEntries = opts.maxEntries ?? 256;
|
|
49
|
+
this.maxTotalChars = opts.maxTotalChars ?? 64 * 1024 * 1024;
|
|
50
|
+
this.perEntryMaxChars = opts.perEntryMaxChars ?? DEFAULT_PER_ENTRY_MAX_CHARS;
|
|
51
|
+
this.ttlMs = opts.ttlMs ?? 5 * 60_000;
|
|
52
|
+
this.now = opts.now ?? (() => Date.now());
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Returns `true` when this call actually started a new fetch, `false` when
|
|
56
|
+
* it was a no-op (idempotent re-prime of an id that's already pending or
|
|
57
|
+
* still live). Callers that admission-gate priming (a concurrency cap) need
|
|
58
|
+
* this to know whether they actually consumed a slot — incrementing a
|
|
59
|
+
* counter unconditionally would leak a slot on every no-op re-prime.
|
|
60
|
+
*/
|
|
61
|
+
prime(id, fetch) {
|
|
62
|
+
this.sweepExpired();
|
|
63
|
+
const existing = this.map.get(id);
|
|
64
|
+
if (existing && (existing.pending || !this.isExpired(existing)))
|
|
65
|
+
return false;
|
|
66
|
+
if (existing)
|
|
67
|
+
this.map.delete(id);
|
|
68
|
+
// A synchronously-throwing fetch (destroyed webContents) is a rejection.
|
|
69
|
+
let fetched;
|
|
70
|
+
try {
|
|
71
|
+
fetched = fetch();
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
fetched = Promise.reject(err instanceof Error ? err : new Error(String(err)));
|
|
75
|
+
}
|
|
76
|
+
const entry = {
|
|
77
|
+
promise: fetched,
|
|
78
|
+
pending: true,
|
|
79
|
+
failed: false,
|
|
80
|
+
value: null,
|
|
81
|
+
size: 0,
|
|
82
|
+
settledAt: 0,
|
|
83
|
+
};
|
|
84
|
+
entry.promise = fetched.then((v) => {
|
|
85
|
+
entry.pending = false;
|
|
86
|
+
entry.settledAt = this.now();
|
|
87
|
+
const size = this.sizeOf(v);
|
|
88
|
+
if (size > this.perEntryMaxChars) {
|
|
89
|
+
entry.failed = true;
|
|
90
|
+
throw new Error(NOT_FOUND);
|
|
91
|
+
}
|
|
92
|
+
entry.value = v;
|
|
93
|
+
entry.size = size;
|
|
94
|
+
// Refresh recency at settle time (identity-checked: a clear() while
|
|
95
|
+
// pending must not resurrect the entry) and enforce the bounds now
|
|
96
|
+
// that this entry's real size is known.
|
|
97
|
+
if (this.map.get(id) === entry) {
|
|
98
|
+
this.map.delete(id);
|
|
99
|
+
this.map.set(id, entry);
|
|
100
|
+
this.evict();
|
|
101
|
+
}
|
|
102
|
+
return v;
|
|
103
|
+
}, () => {
|
|
104
|
+
entry.pending = false;
|
|
105
|
+
entry.failed = true;
|
|
106
|
+
entry.settledAt = this.now();
|
|
107
|
+
throw new Error(NOT_FOUND);
|
|
108
|
+
});
|
|
109
|
+
// A never-looked-up sentinel must not surface as an unhandled rejection.
|
|
110
|
+
entry.promise.catch(() => { });
|
|
111
|
+
this.map.set(id, entry);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
lookup(id) {
|
|
115
|
+
this.sweepExpired();
|
|
116
|
+
const e = this.map.get(id);
|
|
117
|
+
if (!e)
|
|
118
|
+
return Promise.reject(new Error(NOT_FOUND));
|
|
119
|
+
// A pending entry's normalized promise already carries the outcome the
|
|
120
|
+
// waiter needs (value, sentinel, or size overflow) — hand it out directly
|
|
121
|
+
// so the answer never races the map bookkeeping.
|
|
122
|
+
if (e.pending)
|
|
123
|
+
return e.promise;
|
|
124
|
+
if (e.failed || this.isExpired(e)) {
|
|
125
|
+
if (!e.failed)
|
|
126
|
+
this.map.delete(id);
|
|
127
|
+
return Promise.reject(new Error(NOT_FOUND));
|
|
128
|
+
}
|
|
129
|
+
const v = e.value;
|
|
130
|
+
if (v === null)
|
|
131
|
+
return Promise.reject(new Error(NOT_FOUND));
|
|
132
|
+
// A hit refreshes LRU recency.
|
|
133
|
+
this.map.delete(id);
|
|
134
|
+
this.map.set(id, e);
|
|
135
|
+
return Promise.resolve(v);
|
|
136
|
+
}
|
|
137
|
+
clear() {
|
|
138
|
+
this.map.clear();
|
|
139
|
+
}
|
|
140
|
+
get size() {
|
|
141
|
+
return this.map.size;
|
|
142
|
+
}
|
|
143
|
+
isExpired(e) {
|
|
144
|
+
return !e.pending && this.now() - e.settledAt > this.ttlMs;
|
|
145
|
+
}
|
|
146
|
+
sweepExpired() {
|
|
147
|
+
for (const [k, e] of this.map) {
|
|
148
|
+
if (this.isExpired(e))
|
|
149
|
+
this.map.delete(k);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** Evict oldest SETTLED entries until both bounds hold; pending are exempt. */
|
|
153
|
+
evict() {
|
|
154
|
+
let settled = 0;
|
|
155
|
+
let total = 0;
|
|
156
|
+
for (const e of this.map.values()) {
|
|
157
|
+
if (!e.pending) {
|
|
158
|
+
settled++;
|
|
159
|
+
total += e.size;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (settled <= this.maxEntries && total <= this.maxTotalChars)
|
|
163
|
+
return;
|
|
164
|
+
for (const [k, e] of this.map) {
|
|
165
|
+
if (settled <= this.maxEntries && total <= this.maxTotalChars)
|
|
166
|
+
break;
|
|
167
|
+
if (e.pending)
|
|
168
|
+
continue;
|
|
169
|
+
this.map.delete(k);
|
|
170
|
+
settled--;
|
|
171
|
+
total -= e.size;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=body-cache.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared `executeJavaScript` builders for pushing raw CDP messages into the
|
|
3
|
+
* embedded Chrome DevTools front-end via `window.DevToolsAPI.dispatchMessage`
|
|
4
|
+
* / `dispatchMessageChunk`. Both network-forward (Network tab injection) and
|
|
5
|
+
* elements-forward (Elements tab / render-event re-injection) need the exact
|
|
6
|
+
* same transport contract; a single copy means the two can never drift on the
|
|
7
|
+
* chunk-continuation protocol.
|
|
8
|
+
*/
|
|
9
|
+
/** Probe the front-end realm exposes `DevToolsAPI.dispatchMessage`. */
|
|
10
|
+
export declare const PROBE_DEVTOOLS_API = "(window.DevToolsAPI && typeof window.DevToolsAPI.dispatchMessage === 'function')";
|
|
11
|
+
/** A single dispatch payload may not exceed this many UTF-16 chars; chunk above. */
|
|
12
|
+
export declare const MAX_SINGLE_DISPATCH_CHARS = 1000000;
|
|
13
|
+
export declare const CHUNK_CHARS: number;
|
|
14
|
+
/**
|
|
15
|
+
* Build the `executeJavaScript` source for a chunked dispatch of one large CDP
|
|
16
|
+
* message — DevTools' own transport caps a single `dispatchMessage` payload, so
|
|
17
|
+
* the front-end exposes `dispatchMessageChunk(messageChunk, messageSize)` where
|
|
18
|
+
* the FIRST chunk carries the total size and EVERY SUBSEQUENT chunk is called
|
|
19
|
+
* with the chunk ONLY (second arg omitted). This matches Chromium's
|
|
20
|
+
* `devtools_ui_bindings.cc` DispatchProtocolMessage, whose front-end treats a
|
|
21
|
+
* call with a second argument as the start of a new message and a call without
|
|
22
|
+
* one as a continuation. Passing 0 (the previous behaviour) risked the
|
|
23
|
+
* front-end mis-reading a continuation as a fresh 0-size message. Returns false
|
|
24
|
+
* when the API isn't available.
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildChunkedDispatchScript(chunks: string[], totalSize: number): string;
|
|
27
|
+
//# sourceMappingURL=frontend-dispatch.d.ts.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared `executeJavaScript` builders for pushing raw CDP messages into the
|
|
3
|
+
* embedded Chrome DevTools front-end via `window.DevToolsAPI.dispatchMessage`
|
|
4
|
+
* / `dispatchMessageChunk`. Both network-forward (Network tab injection) and
|
|
5
|
+
* elements-forward (Elements tab / render-event re-injection) need the exact
|
|
6
|
+
* same transport contract; a single copy means the two can never drift on the
|
|
7
|
+
* chunk-continuation protocol.
|
|
8
|
+
*/
|
|
9
|
+
/** Probe the front-end realm exposes `DevToolsAPI.dispatchMessage`. */
|
|
10
|
+
export const PROBE_DEVTOOLS_API = `(window.DevToolsAPI && typeof window.DevToolsAPI.dispatchMessage === 'function')`;
|
|
11
|
+
/** A single dispatch payload may not exceed this many UTF-16 chars; chunk above. */
|
|
12
|
+
export const MAX_SINGLE_DISPATCH_CHARS = 1_000_000;
|
|
13
|
+
export const CHUNK_CHARS = 256 * 1024;
|
|
14
|
+
/**
|
|
15
|
+
* Build the `executeJavaScript` source for a chunked dispatch of one large CDP
|
|
16
|
+
* message — DevTools' own transport caps a single `dispatchMessage` payload, so
|
|
17
|
+
* the front-end exposes `dispatchMessageChunk(messageChunk, messageSize)` where
|
|
18
|
+
* the FIRST chunk carries the total size and EVERY SUBSEQUENT chunk is called
|
|
19
|
+
* with the chunk ONLY (second arg omitted). This matches Chromium's
|
|
20
|
+
* `devtools_ui_bindings.cc` DispatchProtocolMessage, whose front-end treats a
|
|
21
|
+
* call with a second argument as the start of a new message and a call without
|
|
22
|
+
* one as a continuation. Passing 0 (the previous behaviour) risked the
|
|
23
|
+
* front-end mis-reading a continuation as a fresh 0-size message. Returns false
|
|
24
|
+
* when the API isn't available.
|
|
25
|
+
*/
|
|
26
|
+
export function buildChunkedDispatchScript(chunks, totalSize) {
|
|
27
|
+
const arr = JSON.stringify(chunks);
|
|
28
|
+
return `(()=>{try{`
|
|
29
|
+
+ `if(!(window.DevToolsAPI&&typeof window.DevToolsAPI.dispatchMessageChunk==='function'))return false;`
|
|
30
|
+
+ `const cs=JSON.parse(${JSON.stringify(arr)});`
|
|
31
|
+
+ `for(let i=0;i<cs.length;i++){`
|
|
32
|
+
+ `try{`
|
|
33
|
+
// First chunk: (chunk, totalSize). Subsequent chunks: (chunk) — second arg
|
|
34
|
+
// omitted, NOT 0, per Chromium's continuation contract.
|
|
35
|
+
+ `if(i===0){window.DevToolsAPI.dispatchMessageChunk(cs[i], ${totalSize})}`
|
|
36
|
+
+ `else{window.DevToolsAPI.dispatchMessageChunk(cs[i])}`
|
|
37
|
+
+ `}catch(_){}`
|
|
38
|
+
+ `}`
|
|
39
|
+
+ `return true;`
|
|
40
|
+
+ `}catch(_){return false}})()`;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=frontend-dispatch.js.map
|
|
@@ -49,21 +49,59 @@
|
|
|
49
49
|
* ✅ Forwarded to the native Network tab: requestWillBeSent, responseReceived,
|
|
50
50
|
* loadingFinished, loadingFailed (+ requestWillBeSentExtraInfo /
|
|
51
51
|
* responseReceivedExtraInfo when present, for accurate headers/status).
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
52
|
+
* ✅ Response body / preview and request post data: prefetched from the
|
|
53
|
+
* simulator's CDP session at loadingFinished into a bounded cache keyed by
|
|
54
|
+
* the VIRTUAL id (`bodies`, see NetworkBodyProvider). The front-end's
|
|
55
|
+
* `Network.getResponseBody` / `Network.getRequestPostData` round-trips for
|
|
56
|
+
* `dimina:sim:` ids are intercepted by the outbound CDP gate that
|
|
57
|
+
* elements-forward installs on `InspectorFrontendHost.sendMessageToBackend`
|
|
58
|
+
* and answered from that cache — the service-host backend the front-end
|
|
59
|
+
* natively talks to has never heard of these ids.
|
|
60
|
+
* ⏳ TODO: `dataReceived` per-chunk forwarding (skipped to avoid an
|
|
61
|
+
* executeJavaScript per chunk).
|
|
62
|
+
* ✅ Requests issued from inside a render-host `<webview>` guest (page-level
|
|
63
|
+
* resource loads / page `fetch`, tagged `source: 'render'`) — `attachRenderGuest`
|
|
64
|
+
* acquires a lease from the shared `CdpSessionBroker` (cdp-session/index.ts),
|
|
65
|
+
* which is single owner of every render-guest `wc.debugger` session across
|
|
66
|
+
* this forwarder, safe-area, elements-forward and render-inspect. An
|
|
67
|
+
* external detach (another owner releasing the shared session, or a real
|
|
68
|
+
* Chrome DevTools window) self-heals via the lease's `onDetach` — capture
|
|
69
|
+
* re-wires itself even though `attachRenderGuest` is only ever called ONCE
|
|
70
|
+
* per guest (at webview creation).
|
|
61
71
|
* ⚠️ NOT observable by any `webContents.debugger`: a request a host module issues
|
|
62
72
|
* directly from the MAIN process. Those need an explicit `report()` call
|
|
63
73
|
* (exposed below; it uses the console fallback path).
|
|
64
74
|
*/
|
|
65
75
|
import type { WebContents } from 'electron';
|
|
66
76
|
import { type ConnectionRegistry, type Disposable } from '@dimina-kit/electron-deck/main';
|
|
77
|
+
import { type CdpSessionBroker } from '../cdp-session/index.js';
|
|
78
|
+
/**
|
|
79
|
+
* Namespace prefix of every virtual requestId this forwarder injects into the
|
|
80
|
+
* DevTools front-end. SINGLE SOURCE for the literal: the front-end outbound
|
|
81
|
+
* gate (elements-forward) keys its `Network.getResponseBody` /
|
|
82
|
+
* `Network.getRequestPostData` interception on this exact prefix, so the two
|
|
83
|
+
* modules can never drift apart on what counts as "one of ours".
|
|
84
|
+
*/
|
|
85
|
+
export declare const VIRTUAL_REQUEST_ID_PREFIX = "dimina:sim:";
|
|
86
|
+
/** CDP `Network.getResponseBody` result shape (served from the prefetch cache). */
|
|
87
|
+
export interface CdpResponseBody {
|
|
88
|
+
body: string;
|
|
89
|
+
base64Encoded: boolean;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Answers the front-end's body/post-data lookups for virtual requestIds. The
|
|
93
|
+
* outbound CDP gate (elements-forward) consumes this: it intercepts the
|
|
94
|
+
* front-end's `Network.getResponseBody` / `Network.getRequestPostData` for
|
|
95
|
+
* `dimina:sim:` ids (the service-host backend has never heard of them) and
|
|
96
|
+
* replies from here instead. Rejections carry the same not-found message a
|
|
97
|
+
* real CDP backend produces for an unknown requestId.
|
|
98
|
+
*/
|
|
99
|
+
export interface NetworkBodyProvider {
|
|
100
|
+
getResponseBody(requestId: string): Promise<CdpResponseBody>;
|
|
101
|
+
getRequestPostData(requestId: string): Promise<{
|
|
102
|
+
postData: string;
|
|
103
|
+
}>;
|
|
104
|
+
}
|
|
67
105
|
/** Which layer a captured request came from (tags the fallback log line). */
|
|
68
106
|
export type NetworkSource = 'service' | 'render';
|
|
69
107
|
/** A normalized completed network request, used only by the console fallback. */
|
|
@@ -98,6 +136,18 @@ export interface NetworkForwarderBridge {
|
|
|
98
136
|
* `once('destroyed')` fallback is used, so existing callers compile unchanged.
|
|
99
137
|
*/
|
|
100
138
|
connections?: ConnectionRegistry;
|
|
139
|
+
/**
|
|
140
|
+
* Shared CDP session broker (see cdp-session/index.ts) that owns every
|
|
141
|
+
* render-guest AND simulator debugger session's attach/detach lifecycle —
|
|
142
|
+
* safe-area, elements-forward, render-inspect and simulator-storage acquire
|
|
143
|
+
* leases from the same instance. Absent → a private broker is created and
|
|
144
|
+
* owned for this forwarder's lifetime (torn down on `dispose()`), so
|
|
145
|
+
* existing standalone callers/tests compile and behave unchanged, just
|
|
146
|
+
* without cross-module session sharing. Both `attachRenderGuest` and
|
|
147
|
+
* `attachSimulator` go through it — see detachSimulator's docstring for why
|
|
148
|
+
* the simulator path never forces a physical detach either.
|
|
149
|
+
*/
|
|
150
|
+
broker?: CdpSessionBroker;
|
|
101
151
|
}
|
|
102
152
|
export interface NetworkForwarder extends Disposable {
|
|
103
153
|
/**
|
|
@@ -109,6 +159,20 @@ export interface NetworkForwarder extends Disposable {
|
|
|
109
159
|
attachSimulator(wc: WebContents): void;
|
|
110
160
|
/** Detach from the current simulator WCV (without disposing the forwarder). */
|
|
111
161
|
detachSimulator(): void;
|
|
162
|
+
/**
|
|
163
|
+
* Wire a render-host guest wc (pageFrame) for Network capture — page-level
|
|
164
|
+
* resource loads (images/fonts/page fetch) that never touch the simulator's
|
|
165
|
+
* network stack. Idempotent per wc. Acquires a lease from the shared
|
|
166
|
+
* `CdpSessionBroker` (cdp-session/index.ts) — reuses an already-attached
|
|
167
|
+
* session (safe-area / elements-forward / render-inspect may have attached
|
|
168
|
+
* first) or self-attaches when no one has; the broker alone decides who may
|
|
169
|
+
* detach. Self-heals after an external detach (the lease's `onDetach`
|
|
170
|
+
* re-wires automatically) even though this is only ever called ONCE per
|
|
171
|
+
* guest, at webview creation. Events share the simulator capture's
|
|
172
|
+
* virtual-id namespace prefix (distinct epochs keep them collision-free) and
|
|
173
|
+
* the same body prefetch cache.
|
|
174
|
+
*/
|
|
175
|
+
attachRenderGuest(wc: WebContents): void;
|
|
112
176
|
/**
|
|
113
177
|
* Point the forwarder at the WebContents hosting the DevTools FRONT-END (the
|
|
114
178
|
* primary, native-Network-tab sink). Pass null when that view is torn down so
|
|
@@ -120,6 +184,13 @@ export interface NetworkForwarder extends Disposable {
|
|
|
120
184
|
* (e.g. a main-process direct send). Uses the console fallback sink.
|
|
121
185
|
*/
|
|
122
186
|
report(record: NetworkRequestRecord): void;
|
|
187
|
+
/**
|
|
188
|
+
* Body/post-data lookups for the virtual requestIds this forwarder injected,
|
|
189
|
+
* backed by the loadingFinished-time prefetch cache. Keyed by virtual id, so
|
|
190
|
+
* entries stay valid across detach/re-attach (each attach epoch mints
|
|
191
|
+
* non-colliding ids); dispose() drops them all.
|
|
192
|
+
*/
|
|
193
|
+
readonly bodies: NetworkBodyProvider;
|
|
123
194
|
}
|
|
124
195
|
/**
|
|
125
196
|
* CDP events whose `params.requestId` we rewrite into the virtual namespace.
|