@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,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared `wc.debugger` (CDP) session broker for render-host guest WebContents.
|
|
3
|
+
*
|
|
4
|
+
* ── Why this exists ─────────────────────────────────────────────────────────
|
|
5
|
+
* `webContents.debugger` is exclusive per wc (only one `attach()` owner at a
|
|
6
|
+
* time). Four independent modules — safe-area, elements-forward, render-inspect
|
|
7
|
+
* and network-forward — each hand-roll the same "reuse if already attached,
|
|
8
|
+
* self-attach only if nobody has, track what I self-attached so I only detach
|
|
9
|
+
* my own" bookkeeping, and each installs its OWN `wc.debugger.on('message', …)`
|
|
10
|
+
* listener. That duplication caused two real bugs:
|
|
11
|
+
*
|
|
12
|
+
* 1. network-forward's `attachRenderGuest` runs ONCE per guest (at webview
|
|
13
|
+
* creation). If some OTHER module later detaches the shared session it
|
|
14
|
+
* happened to self-attach, network-forward's capture dies permanently —
|
|
15
|
+
* nothing re-attaches it (unlike safe-area/elements-forward/render-inspect,
|
|
16
|
+
* which lazily re-`ensure` the debugger on every use and so self-heal).
|
|
17
|
+
* 2. On the simulator wc, two modules each do "detach if attached" with no
|
|
18
|
+
* notion of the other — whichever runs last steals the other's session.
|
|
19
|
+
*
|
|
20
|
+
* This broker is the single owner of "who attached, who may detach": callers
|
|
21
|
+
* `acquire(wc)` a lease instead of touching `wc.debugger` directly. A session's
|
|
22
|
+
* lifetime tracks the wc, not any one lease — the last lease releasing does
|
|
23
|
+
* NOT detach (another consumer may `acquire` again at any time); only the
|
|
24
|
+
* broker's own top-level `dispose()` detaches sessions IT self-attached. An
|
|
25
|
+
* external detach (another owner, or a real Chrome DevTools window stealing the
|
|
26
|
+
* session) notifies every lease's `onDetach` and drops the session's
|
|
27
|
+
* bookkeeping so the NEXT `acquire()` attaches from scratch — closing bug #1
|
|
28
|
+
* structurally instead of requiring every consumer to remember to re-ensure.
|
|
29
|
+
*/
|
|
30
|
+
import type { WebContents } from 'electron';
|
|
31
|
+
import type { ConnectionRegistry, Disposable } from '@dimina-kit/electron-deck/main';
|
|
32
|
+
export interface CdpSessionLease {
|
|
33
|
+
/** Send one CDP command on this wc's session. Rejects if the session/wc is gone. */
|
|
34
|
+
send(method: string, params?: object): Promise<unknown>;
|
|
35
|
+
/**
|
|
36
|
+
* Subscribe to every CDP `message` event this session receives. Multiple
|
|
37
|
+
* leases (from the same or different `acquire()` calls) share ONE real
|
|
38
|
+
* `wc.debugger.on('message', …)` listener, fanned out to every subscriber.
|
|
39
|
+
*/
|
|
40
|
+
onMessage(cb: (method: string, params: unknown) => void): Disposable;
|
|
41
|
+
/**
|
|
42
|
+
* Subscribe to this session becoming unusable for any reason OTHER than the
|
|
43
|
+
* broker's own top-level `dispose()`: an external detach (another owner
|
|
44
|
+
* releasing it, or a real Chrome DevTools window stealing it) OR the wc
|
|
45
|
+
* itself being destroyed. Either way the broker has already dropped its
|
|
46
|
+
* bookkeeping for this session by the time this fires — a consumer that
|
|
47
|
+
* caches its lease should drop the cache entry here so its NEXT `acquire()`
|
|
48
|
+
* gets a fresh one instead of operating on a dead lease. The broker's own
|
|
49
|
+
* `dispose()` detaching a session it self-attached does NOT fire this: that
|
|
50
|
+
* is an intentional, expected teardown, not a surprise the caller needs to
|
|
51
|
+
* react to.
|
|
52
|
+
*/
|
|
53
|
+
onDetach(cb: () => void): Disposable;
|
|
54
|
+
/**
|
|
55
|
+
* Enable DOM + CSS + Overlay (the render-inspection domains) once per
|
|
56
|
+
* session, in dependency order (`Overlay.enable` must follow `DOM.enable`'s
|
|
57
|
+
* resolution — Chromium rejects it otherwise; `CSS.enable` has no such
|
|
58
|
+
* dependency). Memoized PER SESSION (not per lease): concurrent callers on
|
|
59
|
+
* the same wc share one in-flight/completed handshake. Invalidated on any
|
|
60
|
+
* detach (self or external) so a later session re-runs it fresh.
|
|
61
|
+
*/
|
|
62
|
+
ensureRenderDomains(): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Release every subscription THIS lease registered via `onMessage`/
|
|
65
|
+
* `onDetach`. Idempotent. Never detaches the underlying session — that
|
|
66
|
+
* follows the wc's lifetime, not any one lease's.
|
|
67
|
+
*/
|
|
68
|
+
dispose(): void;
|
|
69
|
+
}
|
|
70
|
+
export interface CdpSessionBroker {
|
|
71
|
+
/**
|
|
72
|
+
* Get-or-create a lease for `wc`'s debugger session. Returns `null` when the
|
|
73
|
+
* wc is already destroyed, or when the debugger is exclusively held
|
|
74
|
+
* elsewhere and unavailable to attach (e.g. a real Chrome DevTools window).
|
|
75
|
+
*/
|
|
76
|
+
acquire(wc: WebContents): CdpSessionLease | null;
|
|
77
|
+
/**
|
|
78
|
+
* Project-level teardown: detach every session this broker itself
|
|
79
|
+
* self-attached (never one it merely reused). Sessions owned by someone
|
|
80
|
+
* else are left untouched.
|
|
81
|
+
*/
|
|
82
|
+
dispose(): void;
|
|
83
|
+
}
|
|
84
|
+
export declare function createCdpSessionBroker(opts?: {
|
|
85
|
+
connections?: ConnectionRegistry;
|
|
86
|
+
}): CdpSessionBroker;
|
|
87
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
export function createCdpSessionBroker(opts = {}) {
|
|
2
|
+
const sessions = new Map();
|
|
3
|
+
function removeDebuggerListeners(session) {
|
|
4
|
+
try {
|
|
5
|
+
session.wc.debugger.removeListener('message', session.onDbgMessage);
|
|
6
|
+
}
|
|
7
|
+
catch { /* wc gone */ }
|
|
8
|
+
try {
|
|
9
|
+
session.wc.debugger.removeListener('detach', session.onDbgDetach);
|
|
10
|
+
}
|
|
11
|
+
catch { /* wc gone */ }
|
|
12
|
+
}
|
|
13
|
+
function notifyDetach(session) {
|
|
14
|
+
for (const cb of [...session.detachSubs]) {
|
|
15
|
+
try {
|
|
16
|
+
cb();
|
|
17
|
+
}
|
|
18
|
+
catch { /* subscriber error is not our problem */ }
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function ensureSession(wc) {
|
|
22
|
+
const existing = sessions.get(wc);
|
|
23
|
+
if (existing)
|
|
24
|
+
return existing;
|
|
25
|
+
let selfAttached = false;
|
|
26
|
+
try {
|
|
27
|
+
if (!wc.debugger.isAttached()) {
|
|
28
|
+
wc.debugger.attach('1.3');
|
|
29
|
+
selfAttached = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Exclusively held elsewhere (e.g. a real Chrome DevTools window) and
|
|
34
|
+
// refused to share — degrade to "unavailable", same as every existing
|
|
35
|
+
// per-module implementation this broker replaces.
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const session = {
|
|
39
|
+
wc,
|
|
40
|
+
selfAttached,
|
|
41
|
+
selfDetaching: false,
|
|
42
|
+
messageSubs: new Set(),
|
|
43
|
+
detachSubs: new Set(),
|
|
44
|
+
enablePromise: null,
|
|
45
|
+
onDbgMessage: (...args) => {
|
|
46
|
+
const [, method, params] = args;
|
|
47
|
+
for (const cb of [...session.messageSubs])
|
|
48
|
+
cb(method, params);
|
|
49
|
+
},
|
|
50
|
+
onDbgDetach: () => {
|
|
51
|
+
const wasSelfInitiated = session.selfDetaching;
|
|
52
|
+
session.selfDetaching = false;
|
|
53
|
+
session.enablePromise = null;
|
|
54
|
+
sessions.delete(wc);
|
|
55
|
+
removeDebuggerListeners(session);
|
|
56
|
+
try {
|
|
57
|
+
session.destroyedSub?.dispose();
|
|
58
|
+
}
|
|
59
|
+
catch { /* already gone */ }
|
|
60
|
+
if (!wasSelfInitiated)
|
|
61
|
+
notifyDetach(session);
|
|
62
|
+
},
|
|
63
|
+
onWcDestroyed: () => {
|
|
64
|
+
sessions.delete(wc);
|
|
65
|
+
removeDebuggerListeners(session);
|
|
66
|
+
// Deliberately does NOT call wc.debugger.detach(), even for a
|
|
67
|
+
// self-attached session: a destroyed wc's debugger is torn down by
|
|
68
|
+
// Electron itself, there is nothing left for us to usefully detach,
|
|
69
|
+
// and attempting it is an unnecessary risk (the underlying native
|
|
70
|
+
// objects may already be gone). Dropping our bookkeeping is enough.
|
|
71
|
+
// Not a broker-initiated detach — same "your lease is dead, re-acquire
|
|
72
|
+
// next time" signal as an external debugger detach, just for a
|
|
73
|
+
// different reason (the wc itself is gone, not merely the session).
|
|
74
|
+
notifyDetach(session);
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
wc.debugger.on('message', session.onDbgMessage);
|
|
78
|
+
wc.debugger.on('detach', session.onDbgDetach);
|
|
79
|
+
if (opts.connections) {
|
|
80
|
+
session.destroyedSub = opts.connections.acquire(wc).on('closed', session.onWcDestroyed);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
try {
|
|
84
|
+
wc.once('destroyed', session.onWcDestroyed);
|
|
85
|
+
}
|
|
86
|
+
catch { /* fake/minimal wc */ }
|
|
87
|
+
}
|
|
88
|
+
sessions.set(wc, session);
|
|
89
|
+
return session;
|
|
90
|
+
}
|
|
91
|
+
function ensureRenderDomains(session) {
|
|
92
|
+
if (session.enablePromise)
|
|
93
|
+
return session.enablePromise;
|
|
94
|
+
session.wc.debugger.sendCommand('CSS.enable').catch(() => { });
|
|
95
|
+
const p = session.wc.debugger
|
|
96
|
+
.sendCommand('DOM.enable')
|
|
97
|
+
.then(() => session.wc.debugger.sendCommand('Overlay.enable'))
|
|
98
|
+
.then(() => undefined)
|
|
99
|
+
.catch(() => {
|
|
100
|
+
// Guest mid-teardown or domain unavailable — drop the memo so a later
|
|
101
|
+
// call (e.g. after the session recovers) can retry instead of being
|
|
102
|
+
// stuck on a permanently-failed handshake.
|
|
103
|
+
session.enablePromise = null;
|
|
104
|
+
});
|
|
105
|
+
session.enablePromise = p;
|
|
106
|
+
return p;
|
|
107
|
+
}
|
|
108
|
+
function createLease(session) {
|
|
109
|
+
const ownMessageSubs = new Set();
|
|
110
|
+
const ownDetachSubs = new Set();
|
|
111
|
+
return {
|
|
112
|
+
// Echo the caller's exact arity through to sendCommand — a caller that
|
|
113
|
+
// omits params (many CDP commands take none, e.g. 'Network.enable')
|
|
114
|
+
// gets the identical call Electron's own API expects, not a synthetic
|
|
115
|
+
// `{}` second argument.
|
|
116
|
+
send: (method, params) => params === undefined
|
|
117
|
+
? session.wc.debugger.sendCommand(method)
|
|
118
|
+
: session.wc.debugger.sendCommand(method, params),
|
|
119
|
+
onMessage: (cb) => {
|
|
120
|
+
session.messageSubs.add(cb);
|
|
121
|
+
ownMessageSubs.add(cb);
|
|
122
|
+
return { dispose: () => { session.messageSubs.delete(cb); ownMessageSubs.delete(cb); } };
|
|
123
|
+
},
|
|
124
|
+
onDetach: (cb) => {
|
|
125
|
+
session.detachSubs.add(cb);
|
|
126
|
+
ownDetachSubs.add(cb);
|
|
127
|
+
return { dispose: () => { session.detachSubs.delete(cb); ownDetachSubs.delete(cb); } };
|
|
128
|
+
},
|
|
129
|
+
ensureRenderDomains: () => ensureRenderDomains(session),
|
|
130
|
+
dispose: () => {
|
|
131
|
+
for (const cb of ownMessageSubs)
|
|
132
|
+
session.messageSubs.delete(cb);
|
|
133
|
+
for (const cb of ownDetachSubs)
|
|
134
|
+
session.detachSubs.delete(cb);
|
|
135
|
+
ownMessageSubs.clear();
|
|
136
|
+
ownDetachSubs.clear();
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
acquire(wc) {
|
|
142
|
+
if (wc.isDestroyed())
|
|
143
|
+
return null;
|
|
144
|
+
const session = ensureSession(wc);
|
|
145
|
+
if (!session)
|
|
146
|
+
return null;
|
|
147
|
+
return createLease(session);
|
|
148
|
+
},
|
|
149
|
+
dispose() {
|
|
150
|
+
for (const session of [...sessions.values()]) {
|
|
151
|
+
if (session.selfAttached) {
|
|
152
|
+
session.selfDetaching = true;
|
|
153
|
+
try {
|
|
154
|
+
if (!session.wc.isDestroyed() && session.wc.debugger.isAttached()) {
|
|
155
|
+
session.wc.debugger.detach();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch { /* already detached / destroyed */ }
|
|
159
|
+
}
|
|
160
|
+
// Whether detach ran above (which already self-cleans via onDbgDetach)
|
|
161
|
+
// or this session was externally-owned (never touched), make sure
|
|
162
|
+
// broker-side bookkeeping is gone either way.
|
|
163
|
+
sessions.delete(session.wc);
|
|
164
|
+
removeDebuggerListeners(session);
|
|
165
|
+
try {
|
|
166
|
+
session.destroyedSub?.dispose();
|
|
167
|
+
}
|
|
168
|
+
catch { /* already gone */ }
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1,8 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Elements-panel forwarding — reflect the ACTIVE RENDER GUEST's live DOM tree in
|
|
3
|
+
* the right-panel Chrome DevTools front-end, which natively inspects the
|
|
4
|
+
* service-host (logic layer).
|
|
5
|
+
*
|
|
6
|
+
* ── Mechanism (no preload) ───────────────────────────────────────────────────
|
|
7
|
+
* The DevTools front-end is a `devtools://` page with NO dimina preload, so we
|
|
8
|
+
* drive it through the same two-way poll bridge the network-forward path uses:
|
|
9
|
+
* • front-end → main : we wrap `InspectorFrontendHost.sendMessageToBackend` in
|
|
10
|
+
* the front-end realm — the ONE outbound CDP gate every injected-panel
|
|
11
|
+
* feature routes through (`routeOutboundCommand` is the single decision
|
|
12
|
+
* table). Commands whose method is in the RENDER domain set
|
|
13
|
+
* (DOM/CSS/Overlay/DOMSnapshot/DOMDebugger), plus `Network.getResponseBody`
|
|
14
|
+
* / `Network.getRequestPostData` for `dimina:sim:` virtual requestIds
|
|
15
|
+
* (which only the network forwarder's prefetch cache can answer — the
|
|
16
|
+
* natively-inspected service host has never heard of them), are NOT passed
|
|
17
|
+
* to the original embedder channel — they're pushed onto
|
|
18
|
+
* `globalThis.__diminaElementsOutbound` tagged with their route and main
|
|
19
|
+
* drains that array (splice) on a poll. EVERY OTHER method
|
|
20
|
+
* (Runtime/Console/Page/Target/Emulation/…) calls through to the original, so
|
|
21
|
+
* the service-host inspection (Console, Sources) and crucially the safe-area
|
|
22
|
+
* `Emulation.setSafeAreaInsetsOverride` are untouched.
|
|
23
|
+
* • main → front-end : we re-inject responses + render-side EVENTS via
|
|
24
|
+
* `window.DevToolsAPI.dispatchMessage(json)` (chunked for large payloads —
|
|
25
|
+
* `DOM.getDocument` can be big — mirroring network-forward/index.ts).
|
|
26
|
+
*
|
|
27
|
+
* ── Render-guest CDP session (via the shared broker) ─────────────────────────
|
|
28
|
+
* `webContents.debugger` is single-owner per wc, so this and every other
|
|
29
|
+
* feature that needs a render guest's session (safe-area, render-inspect,
|
|
30
|
+
* network-forward) `acquire()` a lease from the shared `CdpSessionBroker`
|
|
31
|
+
* (see cdp-session/index.ts) instead of each hand-rolling its own attach/
|
|
32
|
+
* reuse/detach bookkeeping — that duplication used to mean whichever module
|
|
33
|
+
* happened to attach first was the de facto owner, and any other module's
|
|
34
|
+
* `detach()` could steal the session out from under the others. The broker is
|
|
35
|
+
* the single owner of "who attached, who may detach"; `DOM.enable`/
|
|
36
|
+
* `CSS.enable`/`Overlay.enable` never touch the safe-area `Emulation`
|
|
37
|
+
* override, so sharing a session this way is purely additive.
|
|
38
|
+
*
|
|
39
|
+
* ── Staleness (active-guest, NOT a generation counter) ───────────────────────
|
|
40
|
+
* A response/event is honoured only while its originating guest is STILL the
|
|
41
|
+
* active render guest — resolved fresh from the bridge per check (`isActiveWcId`),
|
|
42
|
+
* not snapshotted. So a late response or stray render EVENT from a guest that is
|
|
43
|
+
* no longer active is dropped (its in-flight command id is settled with an error
|
|
44
|
+
* so the front-end never leaks a pending request, and stale nodes never bleed into
|
|
45
|
+
* the new tree); and switching away and BACK to a previously-wired guest RESUMES
|
|
46
|
+
* its forwarding (a snapshot would strand it).
|
|
47
|
+
*
|
|
48
|
+
* ── Degradation ──────────────────────────────────────────────────────────────
|
|
49
|
+
* Hook unavailable / `DevToolsAPI` missing / no active guest → routing is simply
|
|
50
|
+
* inert; the Elements panel falls back to the front-end's native service-host
|
|
51
|
+
* DOM (the prior behaviour). Everything is try/catch + feature-detect + bounded
|
|
52
|
+
* polling: it never throws, never blocks, never disturbs Console/Network/safe-area.
|
|
53
|
+
*
|
|
54
|
+
* This is a production feature (no env gate, default on for the native simulator).
|
|
55
|
+
* The routing table (below) is self-contained; the front-end dispatch transport
|
|
56
|
+
* (`buildChunkedDispatchScript` + its size constants) is shared with
|
|
57
|
+
* network-forward via `../network-forward/frontend-dispatch.js` so the two
|
|
58
|
+
* can never drift on the chunk-continuation protocol.
|
|
59
|
+
*/
|
|
1
60
|
import type { WebContents } from 'electron';
|
|
2
61
|
import type { ConnectionRegistry } from '@dimina-kit/electron-deck/main';
|
|
3
62
|
import type { BridgeRouterHandle } from '../../ipc/bridge-router.js';
|
|
4
|
-
|
|
5
|
-
|
|
63
|
+
import { type NetworkBodyProvider } from '../network-forward/index.js';
|
|
64
|
+
import { type CdpSessionBroker } from '../cdp-session/index.js';
|
|
65
|
+
/**
|
|
66
|
+
* Which target a front-end CDP command is routed to.
|
|
67
|
+
* render — the active render guest's debugger (the Elements tree).
|
|
68
|
+
* network — the network forwarder's prefetch cache (body/post-data lookups
|
|
69
|
+
* for `dimina:sim:` virtual requestIds that only exist there).
|
|
70
|
+
* service — the original embedder channel (the service host the front-end
|
|
71
|
+
* natively inspects).
|
|
72
|
+
*/
|
|
73
|
+
export type CdpRoute = 'render' | 'network' | 'service';
|
|
74
|
+
/**
|
|
75
|
+
* CDP domains that target the RENDER GUEST'S document tree. A command in one of
|
|
76
|
+
* these is intercepted and sent to the active render guest's debugger instead of
|
|
77
|
+
* the service host the front-end nominally inspects.
|
|
78
|
+
*/
|
|
79
|
+
export declare const RENDER_DOMAIN_PREFIXES: readonly string[];
|
|
6
80
|
/**
|
|
7
81
|
* Decide where a front-end CDP `method` is routed.
|
|
8
82
|
*
|
|
@@ -20,12 +94,33 @@ export type CdpRoute = 'render' | 'service';
|
|
|
20
94
|
export declare function routeByDomain(method: string): CdpRoute;
|
|
21
95
|
/** True for an event method we re-inject from the render guest into the panel. */
|
|
22
96
|
export declare function isRenderEventMethod(method: string): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* The Network commands answered from the network forwarder's prefetch cache
|
|
99
|
+
* when they target a virtual requestId. Only these two: they're the panel's
|
|
100
|
+
* body/post-data round-trips. Every other Network.* stays on the service path
|
|
101
|
+
* (a virtual id there errors exactly like an unknown id would — harmless).
|
|
102
|
+
*/
|
|
103
|
+
export declare const NETWORK_BODY_METHODS: readonly string[];
|
|
104
|
+
/**
|
|
105
|
+
* Full outbound routing decision — the SINGLE authority for where a front-end
|
|
106
|
+
* CDP command goes. `routeByDomain` covers the method-only render split; this
|
|
107
|
+
* adds the params-dependent network split. The hook script inlines an
|
|
108
|
+
* equivalent test driven by the same literals, so the two cannot drift.
|
|
109
|
+
*
|
|
110
|
+
* A non-string / missing requestId routes to 'service': only the
|
|
111
|
+
* `dimina:sim:` namespace is ours to answer, and the real backend is the
|
|
112
|
+
* correct authority for its own ids.
|
|
113
|
+
*/
|
|
114
|
+
export declare function routeOutboundCommand(method: string, params: unknown): CdpRoute;
|
|
23
115
|
/**
|
|
24
116
|
* The JS injected into the DevTools front-end realm. Idempotent (sentinel guard).
|
|
25
|
-
* Wraps `InspectorFrontendHost.sendMessageToBackend
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
117
|
+
* Wraps `InspectorFrontendHost.sendMessageToBackend` — the ONE outbound CDP
|
|
118
|
+
* gate for every command the front-end emits. A command that routes 'render'
|
|
119
|
+
* or 'network' (same decision table as {@link routeOutboundCommand}) is pushed
|
|
120
|
+
* onto `globalThis.__diminaElementsOutbound` tagged with its route and NOT
|
|
121
|
+
* forwarded to the original embedder channel (main answers it — from the
|
|
122
|
+
* render guest or the network prefetch cache respectively); every other
|
|
123
|
+
* command calls through to the original (service-host path).
|
|
29
124
|
*
|
|
30
125
|
* Returns `'installed'` / `'already'` on success, `'partial'` while the embedder
|
|
31
126
|
* global is not yet present (so the caller retries), `'error:…'` on a real fault.
|
|
@@ -43,19 +138,41 @@ export interface ElementsForwardDeps {
|
|
|
43
138
|
*/
|
|
44
139
|
appId?: string;
|
|
45
140
|
/**
|
|
46
|
-
* Optional connection registry. When present,
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* `
|
|
51
|
-
*
|
|
141
|
+
* Optional connection registry. When present, the devtools front-end wc's
|
|
142
|
+
* own `stop` teardown is routed through `connections.acquire(wc).own(cleanup)`
|
|
143
|
+
* so it fires deterministically on wc destroy / connection reset — replacing
|
|
144
|
+
* the bespoke `wc.once('destroyed', cleanup)` hook. Optional so existing
|
|
145
|
+
* callers compile unchanged; absent → the `once('destroyed')` fallback is
|
|
146
|
+
* used. Also threaded into the PRIVATE fallback broker (see `broker` below)
|
|
147
|
+
* when no shared broker is supplied, so that broker's own render-guest
|
|
148
|
+
* wc-destroy tracking is connection-routed too.
|
|
52
149
|
*/
|
|
53
150
|
connections?: ConnectionRegistry;
|
|
151
|
+
/**
|
|
152
|
+
* Answers intercepted `Network.getResponseBody` / `Network.getRequestPostData`
|
|
153
|
+
* lookups for `dimina:sim:` virtual requestIds (the network forwarder's
|
|
154
|
+
* prefetch cache). Absent → those commands settle with the standard CDP
|
|
155
|
+
* not-found error, the same answer the mis-routed service-host backend gave.
|
|
156
|
+
*/
|
|
157
|
+
network?: NetworkBodyProvider;
|
|
158
|
+
/**
|
|
159
|
+
* Shared CDP session broker (see cdp-session/index.ts) that owns every
|
|
160
|
+
* render-guest debugger session's attach/detach lifecycle — safe-area,
|
|
161
|
+
* render-inspect and network-forward acquire leases from the same instance.
|
|
162
|
+
* Absent → a private broker is created and owned for this call's lifetime
|
|
163
|
+
* (torn down on `stop()`), so existing standalone callers/tests compile and
|
|
164
|
+
* behave unchanged, just without cross-module session sharing.
|
|
165
|
+
*/
|
|
166
|
+
broker?: CdpSessionBroker;
|
|
54
167
|
}
|
|
55
168
|
/**
|
|
56
|
-
* Install Elements forwarding on a DevTools front-end host wc. Returns a
|
|
57
|
-
* (`stop`) that clears timers, unsubscribes render events,
|
|
58
|
-
*
|
|
169
|
+
* Install Elements forwarding on a DevTools front-end host wc. Returns a
|
|
170
|
+
* disposer (`stop`) that clears timers, unsubscribes render events, releases
|
|
171
|
+
* every broker lease this call acquired, and — only when no `deps.broker` was
|
|
172
|
+
* supplied (this call owns its private broker) — disposes that broker too
|
|
173
|
+
* (which detaches ONLY the sessions it self-attached). When `deps.broker` IS
|
|
174
|
+
* supplied (the shared, app-wide instance), `stop()` never disposes it: other
|
|
175
|
+
* consumers may still be using it.
|
|
59
176
|
*
|
|
60
177
|
* Best-effort + defensive throughout: a destroyed wc ends the feature; every
|
|
61
178
|
* executeJavaScript / sendCommand is wrapped so a torn-down guest never throws
|