@dimina-kit/devtools 0.4.0-dev.20260701155140 → 0.4.0-dev.20260702145840
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/max-listeners-diagnostic.js +5 -1
- package/dist/main/index.bundle.js +1532 -1236
- package/dist/main/ipc/bridge-router.d.ts +28 -0
- package/dist/main/ipc/bridge-router.js +175 -50
- package/dist/main/ipc/session-listener-bag.d.ts +41 -0
- package/dist/main/ipc/session-listener-bag.js +40 -0
- package/dist/main/ipc/simulator.js +5 -1
- package/dist/main/services/elements-forward/index.js +19 -0
- package/dist/main/services/network-forward/index.js +13 -0
- package/dist/main/services/views/destroy-child-view.d.ts +9 -0
- package/dist/main/services/views/destroy-child-view.js +23 -0
- package/dist/main/services/views/host-toolbar-view.d.ts +21 -0
- package/dist/main/services/views/host-toolbar-view.js +249 -0
- package/dist/main/services/views/inject-when-ready.d.ts +41 -0
- package/dist/main/services/views/inject-when-ready.js +62 -0
- package/dist/main/services/views/native-simulator-devtools-host.d.ts +26 -0
- package/dist/main/services/views/native-simulator-devtools-host.js +484 -0
- package/dist/main/services/views/native-simulator-view.d.ts +28 -0
- package/dist/main/services/views/native-simulator-view.js +428 -0
- package/dist/main/services/views/overlay-panels-view.d.ts +29 -0
- package/dist/main/services/views/overlay-panels-view.js +150 -0
- package/dist/main/services/views/placement-reconciler.d.ts +73 -0
- package/dist/main/services/views/placement-reconciler.js +120 -0
- package/dist/main/services/views/resolve-project-editor-target.d.ts +13 -0
- package/dist/main/services/views/resolve-project-editor-target.js +33 -0
- package/dist/main/services/views/view-manager.d.ts +20 -16
- package/dist/main/services/views/view-manager.js +66 -1545
- package/dist/main/services/views/workbench-view.d.ts +15 -0
- package/dist/main/services/views/workbench-view.js +170 -0
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/main.cjs +10 -1
- package/dist/preload/windows/main.cjs.map +2 -2
- package/dist/preload/windows/simulator.cjs +6 -0
- package/dist/preload/windows/simulator.cjs.map +2 -2
- package/dist/preload/windows/simulator.js +6 -0
- package/dist/renderer/assets/index-ChF9V4r-.js +49 -0
- package/dist/renderer/assets/{input-Djg2NR4U.js → input-Cjk0wSEh.js} +2 -2
- package/dist/renderer/assets/ipc-transport-D5dKIti1.css +1 -0
- package/dist/renderer/assets/{ipc-transport-Be-AzCub.js → ipc-transport-OZS-KmOW.js} +2 -2
- package/dist/renderer/assets/{popover-eDUh4NYe.js → popover-CQVvOe90.js} +2 -2
- package/dist/renderer/assets/{select-DesFfkVV.js → select-BQDXi5ih.js} +2 -2
- package/dist/renderer/assets/{settings-api-HQ7ZFPWi.js → settings-api-B6x2mhaD.js} +2 -2
- package/dist/renderer/assets/{settings-CRmO7zUG.js → settings-tP3Px2KR.js} +2 -2
- package/dist/renderer/assets/{workbenchSettings-CZBWsliT.js → workbenchSettings-Bim9ol9R.js} +2 -2
- package/dist/renderer/entries/main/index.html +6 -6
- package/dist/renderer/entries/popover/index.html +5 -5
- package/dist/renderer/entries/settings/index.html +5 -5
- package/dist/renderer/entries/workbench-settings/index.html +4 -4
- package/dist/shared/bridge-channels.d.ts +17 -0
- package/dist/shared/bridge-channels.js +9 -0
- package/dist/shared/ipc-channels.d.ts +1 -0
- package/dist/shared/ipc-channels.js +6 -0
- package/dist/shared/ipc-schemas.d.ts +6 -0
- package/dist/shared/ipc-schemas.js +10 -0
- package/dist/simulator/assets/{bridge-channels-BUQ5AbvJ.js → bridge-channels-zhsumfky.js} +2 -2
- package/dist/simulator/assets/{device-shell-CT3LRnTB.js → device-shell-CUl0ILfn.js} +2 -2
- package/dist/simulator/assets/{simulator-BizhGGE3.js → simulator-Dz8iGcgy.js} +5 -5
- package/dist/simulator/assets/{simulator-mini-app-BfNuDF3R.js → simulator-mini-app-Bt639XL_.js} +2 -2
- package/dist/simulator/simulator.html +2 -1
- package/package.json +5 -5
- package/dist/renderer/assets/index-jDrNHghH.js +0 -49
- package/dist/renderer/assets/ipc-transport-C6-KPMqw.css +0 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { PlacementReconciler } from './placement-reconciler.js';
|
|
2
|
+
import type { HostToolbarControl, ViewManagerContext } from './view-manager.js';
|
|
3
|
+
/**
|
|
4
|
+
* A strip above the devtools header that the downstream host loads its own
|
|
5
|
+
* content into and fully controls. Bounds come from a renderer DOM anchor
|
|
6
|
+
* (forward anchor, like the simulator DevTools overlay); its height is dynamic
|
|
7
|
+
* via a reverse size-advertiser the toolbar's own renderer drives.
|
|
8
|
+
*/
|
|
9
|
+
export interface HostToolbarView {
|
|
10
|
+
readonly control: HostToolbarControl;
|
|
11
|
+
setHostToolbarHeight(extent: number): void;
|
|
12
|
+
getHostToolbarHeight(): number;
|
|
13
|
+
getHostToolbarWebContentsId(): number | null;
|
|
14
|
+
/** Teardown for `disposeAll`: sweep the port, destroy the view, release the runtime ref. */
|
|
15
|
+
dispose(): void;
|
|
16
|
+
}
|
|
17
|
+
export declare function createHostToolbarView(ctx: ViewManagerContext, reconciler: PlacementReconciler, deps: {
|
|
18
|
+
/** Re-apply the settings/popover overlays whose height depends on the toolbar strip. */
|
|
19
|
+
reapplyPresentOverlays(): void;
|
|
20
|
+
}): HostToolbarView;
|
|
21
|
+
//# sourceMappingURL=host-toolbar-view.d.ts.map
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { WebContentsView } from 'electron';
|
|
2
|
+
import { handleWindowOpenExternal } from '../../windows/navigation-hardening.js';
|
|
3
|
+
import { HOST_TOOLBAR_RUNTIME_MARKER } from '../../../shared/constants.js';
|
|
4
|
+
import { VIEW_ID, VIEW_LAYER } from '../../../shared/view-ids.js';
|
|
5
|
+
import { acquireHostToolbarSessionRuntime, releaseHostToolbarSessionRuntime, } from './host-toolbar-session-runtime.js';
|
|
6
|
+
import { createHostToolbarPortChannel } from './host-toolbar-port-channel.js';
|
|
7
|
+
import { destroyChildView } from './destroy-child-view.js';
|
|
8
|
+
export function createHostToolbarView(ctx, reconciler, deps) {
|
|
9
|
+
let hostToolbarView = null;
|
|
10
|
+
let hostToolbarPreloadOverride = null;
|
|
11
|
+
let hostToolbarViewAdded = false;
|
|
12
|
+
// Whether THIS manager holds a reference on the shared defaultSession
|
|
13
|
+
// registration of the toolbar-runtime preload (see
|
|
14
|
+
// host-toolbar-session-runtime.ts). Acquired on first toolbar need,
|
|
15
|
+
// released exactly once in dispose — a manager that never used the
|
|
16
|
+
// toolbar must not decrement a ref it never took.
|
|
17
|
+
let hostToolbarRuntimeAcquired = false;
|
|
18
|
+
// Placeholder height authority: 'auto' = advertiser reports forward to the
|
|
19
|
+
// renderer; { fixed } = host-pinned, advertiser reports are dropped.
|
|
20
|
+
let hostToolbarHeightMode = 'auto';
|
|
21
|
+
// Last toolbar height NOTIFIED to the main-window renderer — the replay
|
|
22
|
+
// source behind `getHostToolbarHeight()`. Updated ONLY inside
|
|
23
|
+
// `notifyHostToolbarHeight` so the retained value can never diverge from
|
|
24
|
+
// what the renderer was told (an advertiser report dropped by a `{ fixed }`
|
|
25
|
+
// pin must not pollute it, and a setHeightMode validation reject leaves it
|
|
26
|
+
// untouched).
|
|
27
|
+
let hostToolbarLastHeight = 0;
|
|
28
|
+
// Gated narrow channel to the toolbar PAGE (per-load MessagePort handshake;
|
|
29
|
+
// see host-toolbar-port-channel.ts). Control-level registry — created with
|
|
30
|
+
// the manager so onMessage() works before any toolbar view exists.
|
|
31
|
+
const hostToolbarPort = createHostToolbarPortChannel({
|
|
32
|
+
isCurrent: (wc) => liveHostToolbarWebContents() === wc,
|
|
33
|
+
});
|
|
34
|
+
// The toolbar's webContents lifecycle belongs to the HOST, which may close
|
|
35
|
+
// it out from under us (the documented rebuild path). In real Electron a
|
|
36
|
+
// WebContentsView whose webContents was destroyed can report `webContents`
|
|
37
|
+
// as undefined — not merely a destroyed handle — so every access must
|
|
38
|
+
// tolerate BOTH (observed in the R1 e2e: `.isDestroyed()` on undefined threw
|
|
39
|
+
// inside the control surface after the host closed the wc).
|
|
40
|
+
function liveHostToolbarWebContents() {
|
|
41
|
+
const wc = hostToolbarView?.webContents;
|
|
42
|
+
if (!wc || wc.isDestroyed())
|
|
43
|
+
return null;
|
|
44
|
+
return wc;
|
|
45
|
+
}
|
|
46
|
+
// Lazily create the host-toolbar view. Mirrors `showSettings` for the
|
|
47
|
+
// webPreferences shape and the native simulator for nav hardening +
|
|
48
|
+
// background color (the host may load arbitrary URLs / content). Idempotent.
|
|
49
|
+
function ensureHostToolbarView() {
|
|
50
|
+
if (hostToolbarView && liveHostToolbarWebContents()) {
|
|
51
|
+
return hostToolbarView;
|
|
52
|
+
}
|
|
53
|
+
// Rebuilding after the host destroyed the underlying webContents: detach the
|
|
54
|
+
// dead view from the contentView and reset the added-flag so the new view
|
|
55
|
+
// gets re-mounted (otherwise the `hostToolbarViewAdded` guard would skip the
|
|
56
|
+
// addChildView and the toolbar would silently disappear).
|
|
57
|
+
if (hostToolbarView && hostToolbarViewAdded) {
|
|
58
|
+
try {
|
|
59
|
+
ctx.windows.mainWindow.contentView.removeChildView(hostToolbarView);
|
|
60
|
+
}
|
|
61
|
+
catch { /* already removed */ }
|
|
62
|
+
hostToolbarViewAdded = false;
|
|
63
|
+
}
|
|
64
|
+
// The instance is being replaced — forget its reconciled mount state so the
|
|
65
|
+
// rebuilt view is treated as a fresh attach (not skipped as already-attached).
|
|
66
|
+
reconciler.forgetActual(VIEW_ID.hostToolbar);
|
|
67
|
+
// The framework's height-advertiser runtime is SESSION-resident: register
|
|
68
|
+
// it on session.defaultSession (ref-counted across coexisting managers)
|
|
69
|
+
// BEFORE the view exists, so the very first load already runs it. The
|
|
70
|
+
// toolbar WCV stays on the defaultSession (no partition/session override)
|
|
71
|
+
// — moving it onto its own partition would silently detach it from this
|
|
72
|
+
// registration and height advertising would die with no error.
|
|
73
|
+
if (!hostToolbarRuntimeAcquired) {
|
|
74
|
+
acquireHostToolbarSessionRuntime();
|
|
75
|
+
hostToolbarRuntimeAcquired = true;
|
|
76
|
+
}
|
|
77
|
+
// `webPreferences.preload` is the HOST's alone (setPreloadPath); the
|
|
78
|
+
// built-in advertiser no longer rides it (it would execute twice — the
|
|
79
|
+
// session copy + the webPreferences copy). The additionalArguments marker
|
|
80
|
+
// is what the session runtime's guard keys on to activate here and stay a
|
|
81
|
+
// zero-footprint no-op in every other defaultSession renderer.
|
|
82
|
+
const webPreferences = {
|
|
83
|
+
nodeIntegration: false,
|
|
84
|
+
contextIsolation: true,
|
|
85
|
+
sandbox: false,
|
|
86
|
+
additionalArguments: [HOST_TOOLBAR_RUNTIME_MARKER],
|
|
87
|
+
};
|
|
88
|
+
if (hostToolbarPreloadOverride !== null) {
|
|
89
|
+
webPreferences.preload = hostToolbarPreloadOverride;
|
|
90
|
+
}
|
|
91
|
+
const view = new WebContentsView({ webPreferences });
|
|
92
|
+
hostToolbarView = view;
|
|
93
|
+
// Hook the per-load MessagePort handshake (did-finish-load) + dead-port
|
|
94
|
+
// cleanup (destroyed) on the fresh wc. AFTER the assignment above so the
|
|
95
|
+
// channel's isCurrent guard sees this wc as the live one.
|
|
96
|
+
hostToolbarPort.attach(view.webContents);
|
|
97
|
+
// Paint the surface a neutral color so growing the reserved strip never
|
|
98
|
+
// flashes white before the host content paints (mirrors the native
|
|
99
|
+
// simulator's setBackgroundColor anti-flash).
|
|
100
|
+
try {
|
|
101
|
+
view.setBackgroundColor('#121212');
|
|
102
|
+
}
|
|
103
|
+
catch { /* stub may lack it */ }
|
|
104
|
+
// The host may load arbitrary URLs; route popups + cross-origin in-place
|
|
105
|
+
// navigation to the OS browser (mirror the native simulator hardening).
|
|
106
|
+
try {
|
|
107
|
+
view.webContents.setWindowOpenHandler(({ url }) => handleWindowOpenExternal(url));
|
|
108
|
+
}
|
|
109
|
+
catch { /* stub may lack it */ }
|
|
110
|
+
return view;
|
|
111
|
+
}
|
|
112
|
+
// Single funnel for the height notify: retain-then-push, so the retained
|
|
113
|
+
// value is exactly the last value the renderer was told. Every height
|
|
114
|
+
// notify site MUST go through here — the renderer pulls the retained value
|
|
115
|
+
// on project-view mount to replay a push it missed (the toolbar's
|
|
116
|
+
// size-advertiser deduplicates and never re-reports).
|
|
117
|
+
function notifyHostToolbarHeight(height) {
|
|
118
|
+
hostToolbarLastHeight = height;
|
|
119
|
+
ctx.notify.hostToolbarHeightChanged(height);
|
|
120
|
+
deps.reapplyPresentOverlays();
|
|
121
|
+
}
|
|
122
|
+
function setHostToolbarHeight(extent) {
|
|
123
|
+
// While the host pins a fixed height, drop advertiser reports entirely —
|
|
124
|
+
// the session-resident advertiser is always installed, so forwarding its
|
|
125
|
+
// reports would make the strip oscillate between the pinned and measured
|
|
126
|
+
// heights on every content resize. Dropped reports must not touch the
|
|
127
|
+
// retained value either: retention records what was NOTIFIED, not what
|
|
128
|
+
// was reported.
|
|
129
|
+
if (hostToolbarHeightMode !== 'auto')
|
|
130
|
+
return;
|
|
131
|
+
// Push the reserved height back to the main-window renderer so its
|
|
132
|
+
// placeholder div resizes (closing the dynamic-height loop). The notified
|
|
133
|
+
// height IS retained in main (`getHostToolbarHeight`) so a renderer that
|
|
134
|
+
// mounts later can pull/replay it; the renderer placeholder remains the
|
|
135
|
+
// geometry authority — the forward anchor re-reports bounds from it.
|
|
136
|
+
notifyHostToolbarHeight(extent);
|
|
137
|
+
}
|
|
138
|
+
function hideHostToolbar() {
|
|
139
|
+
reconciler.setBaseDesired(VIEW_ID.hostToolbar, {
|
|
140
|
+
viewId: VIEW_ID.hostToolbar,
|
|
141
|
+
placement: { visible: false },
|
|
142
|
+
layer: VIEW_LAYER.hostToolbar,
|
|
143
|
+
});
|
|
144
|
+
reconciler.reconcileNow();
|
|
145
|
+
// Collapse the renderer placeholder to 0 too. Otherwise its anchor keeps a
|
|
146
|
+
// non-zero reserved height and re-publishes bounds on the next window
|
|
147
|
+
// resize, silently re-adding the view we just hid (unstable hide). Zeroing
|
|
148
|
+
// the height flips the anchor to `present:false` so it stops re-publishing.
|
|
149
|
+
// Through the funnel so the retained value follows to 0 — a renderer
|
|
150
|
+
// mounting after the hide must replay 0, not the stale pre-hide height.
|
|
151
|
+
notifyHostToolbarHeight(0);
|
|
152
|
+
}
|
|
153
|
+
const control = {
|
|
154
|
+
async loadURL(url) {
|
|
155
|
+
const view = ensureHostToolbarView();
|
|
156
|
+
// Invalidate SYNCHRONOUSLY at initiation, before the load is issued:
|
|
157
|
+
// the current document is about to be replaced, so a same-tick send()
|
|
158
|
+
// must report false instead of confirming delivery into it. The channel
|
|
159
|
+
// recovers on the new document's did-finish-load handshake. (Cannot
|
|
160
|
+
// rely on did-start-navigation here — that only covers page-initiated
|
|
161
|
+
// navigations once the load is actually under way.)
|
|
162
|
+
hostToolbarPort.invalidate();
|
|
163
|
+
await view.webContents.loadURL(url);
|
|
164
|
+
},
|
|
165
|
+
async loadFile(filePath) {
|
|
166
|
+
const view = ensureHostToolbarView();
|
|
167
|
+
// Same initiation-invalidates contract as loadURL above.
|
|
168
|
+
hostToolbarPort.invalidate();
|
|
169
|
+
await view.webContents.loadFile(filePath);
|
|
170
|
+
},
|
|
171
|
+
get webContents() {
|
|
172
|
+
return liveHostToolbarWebContents();
|
|
173
|
+
},
|
|
174
|
+
hide() {
|
|
175
|
+
hideHostToolbar();
|
|
176
|
+
},
|
|
177
|
+
setPreloadPath(path) {
|
|
178
|
+
// The HOST's own webPreferences.preload, applied when the view is next
|
|
179
|
+
// (re)created. `null` = no host preload. The framework advertiser is
|
|
180
|
+
// session-resident and unaffected either way (see ensureHostToolbarView).
|
|
181
|
+
hostToolbarPreloadOverride = path;
|
|
182
|
+
},
|
|
183
|
+
setHeightMode(mode) {
|
|
184
|
+
// Validate BEFORE touching any state: a poisoned `{ fixed }` (NaN /
|
|
185
|
+
// ±Infinity / negative) must neither reach the renderer placeholder
|
|
186
|
+
// (`height: NaNpx` corrupts the strip with no error anywhere) nor
|
|
187
|
+
// clobber the standing mode — fail-closed, not fail-corrupt.
|
|
188
|
+
if (mode !== 'auto' && !(Number.isFinite(mode.fixed) && mode.fixed >= 0)) {
|
|
189
|
+
throw new TypeError(`hostToolbar.setHeightMode: fixed height must be a finite, non-negative number (got ${mode.fixed})`);
|
|
190
|
+
}
|
|
191
|
+
hostToolbarHeightMode = mode;
|
|
192
|
+
if (mode !== 'auto') {
|
|
193
|
+
// Pin immediately: a preload-less/static toolbar never advertises, so
|
|
194
|
+
// waiting for the next report would leave the strip at height 0.
|
|
195
|
+
notifyHostToolbarHeight(mode.fixed);
|
|
196
|
+
}
|
|
197
|
+
// Switching back to 'auto' deliberately does NOT synthesize a notify —
|
|
198
|
+
// replaying a stale cached height would flash the old size; the NEXT
|
|
199
|
+
// advertiser report drives the placeholder again. The RETAINED value
|
|
200
|
+
// survives the switch though: a freshly-mounting renderer still needs
|
|
201
|
+
// the pinned height until that next report lands.
|
|
202
|
+
},
|
|
203
|
+
onMessage(channel, handler) {
|
|
204
|
+
return hostToolbarPort.onMessage(channel, handler);
|
|
205
|
+
},
|
|
206
|
+
onReady(handler) {
|
|
207
|
+
return hostToolbarPort.onReady(handler);
|
|
208
|
+
},
|
|
209
|
+
send(channel, payload) {
|
|
210
|
+
return hostToolbarPort.send(channel, payload);
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
reconciler.registerView(VIEW_ID.hostToolbar, {
|
|
214
|
+
getView: () => hostToolbarView,
|
|
215
|
+
ensureView: () => ensureHostToolbarView(),
|
|
216
|
+
setAdded: (added) => { hostToolbarViewAdded = added; },
|
|
217
|
+
ensureLazy: (desired) => {
|
|
218
|
+
if (desired?.placement.visible && !liveHostToolbarWebContents())
|
|
219
|
+
ensureHostToolbarView();
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
function dispose() {
|
|
223
|
+
// Narrow channel first: close the live MessagePort + sweep the onMessage
|
|
224
|
+
// registry, so a send() racing teardown reports false instead of posting
|
|
225
|
+
// into a wc that is about to be closed.
|
|
226
|
+
hostToolbarPort.dispose();
|
|
227
|
+
// Host-controllable toolbar view: removed from the contentView + its
|
|
228
|
+
// WebContents closed (the host's loaded content is torn down on app exit).
|
|
229
|
+
destroyChildView(ctx.windows.mainWindow, hostToolbarView);
|
|
230
|
+
hostToolbarView = null;
|
|
231
|
+
hostToolbarViewAdded = false;
|
|
232
|
+
// Release this manager's reference on the shared defaultSession
|
|
233
|
+
// toolbar-runtime registration (only if it ever acquired one — a manager
|
|
234
|
+
// that never used the toolbar must not drive the shared count to zero).
|
|
235
|
+
// The LAST release unregisters; other coexisting managers keep theirs.
|
|
236
|
+
if (hostToolbarRuntimeAcquired) {
|
|
237
|
+
releaseHostToolbarSessionRuntime();
|
|
238
|
+
hostToolbarRuntimeAcquired = false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
control,
|
|
243
|
+
setHostToolbarHeight,
|
|
244
|
+
getHostToolbarHeight: () => hostToolbarLastHeight,
|
|
245
|
+
getHostToolbarWebContentsId: () => liveHostToolbarWebContents()?.id ?? null,
|
|
246
|
+
dispose,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=host-toolbar-view.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { WebContents } from 'electron';
|
|
2
|
+
/**
|
|
3
|
+
* Deferred executeJavaScript scheduling for a LOADING webContents.
|
|
4
|
+
*
|
|
5
|
+
* `wc.executeJavaScript()` against a loading wc queues one internal
|
|
6
|
+
* `did-stop-loading` waiter PER CALL (Electron defers the eval). Call sites
|
|
7
|
+
* that re-inject on every re-point (open-in-editor glue, tab customization,
|
|
8
|
+
* console default) can fire dozens of times within one front-end load window —
|
|
9
|
+
* piling waiters past the MaxListeners ceiling on the host wc.
|
|
10
|
+
*
|
|
11
|
+
* This injector keeps AT MOST ONE `did-stop-loading` hook per (wc, kind) per
|
|
12
|
+
* load window; repeated schedules within the window only REPLACE the runner
|
|
13
|
+
* (latest-wins — a re-point that swaps the inspected service wc must win over
|
|
14
|
+
* the stale closure). A non-loading wc runs immediately.
|
|
15
|
+
*/
|
|
16
|
+
export interface LoadDeferredInjector {
|
|
17
|
+
(wc: WebContents, kind: string, run: () => void): void;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* THE single settled-predicate for the DevTools front-end host wc — every
|
|
21
|
+
* module that fires `executeJavaScript` at it (deferred injects here, the
|
|
22
|
+
* Elements reconcile tick + pushes, the Network dispatch flush) must consult
|
|
23
|
+
* THIS predicate, never its own `isLoading()` probe.
|
|
24
|
+
*
|
|
25
|
+
* It is AT LEAST as strict as Electron's internal
|
|
26
|
+
* `waitTillCanExecuteJavaScript` gate (`getURL() && !isLoadingMainFrame()`,
|
|
27
|
+
* lib/browser/api/web-contents.ts): whenever this predicate reads settled,
|
|
28
|
+
* Electron executes immediately and queues NO did-stop-loading waiter. A laxer
|
|
29
|
+
* probe (bare `isLoading()`) opens a divergence window where the caller
|
|
30
|
+
* believes the wc is idle while Electron still queues one waiter per call,
|
|
31
|
+
* piling toward the MaxListeners ceiling. Two DELIBERATE extra strictures on
|
|
32
|
+
* top of Electron's gate:
|
|
33
|
+
* - `about:blank` reads unsettled — it satisfies Electron's check, but a
|
|
34
|
+
* script run against it is wiped by the upcoming real navigation;
|
|
35
|
+
* - probes are reflective (try/catch, isLoading fallback): a partial test wc
|
|
36
|
+
* degrades to "unsettled", mirroring the surrounding modules'
|
|
37
|
+
* degrade-silently convention.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isFrontendSettled(wc: WebContents): boolean;
|
|
40
|
+
export declare function createLoadDeferredInjector(): LoadDeferredInjector;
|
|
41
|
+
//# sourceMappingURL=inject-when-ready.d.ts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE single settled-predicate for the DevTools front-end host wc — every
|
|
3
|
+
* module that fires `executeJavaScript` at it (deferred injects here, the
|
|
4
|
+
* Elements reconcile tick + pushes, the Network dispatch flush) must consult
|
|
5
|
+
* THIS predicate, never its own `isLoading()` probe.
|
|
6
|
+
*
|
|
7
|
+
* It is AT LEAST as strict as Electron's internal
|
|
8
|
+
* `waitTillCanExecuteJavaScript` gate (`getURL() && !isLoadingMainFrame()`,
|
|
9
|
+
* lib/browser/api/web-contents.ts): whenever this predicate reads settled,
|
|
10
|
+
* Electron executes immediately and queues NO did-stop-loading waiter. A laxer
|
|
11
|
+
* probe (bare `isLoading()`) opens a divergence window where the caller
|
|
12
|
+
* believes the wc is idle while Electron still queues one waiter per call,
|
|
13
|
+
* piling toward the MaxListeners ceiling. Two DELIBERATE extra strictures on
|
|
14
|
+
* top of Electron's gate:
|
|
15
|
+
* - `about:blank` reads unsettled — it satisfies Electron's check, but a
|
|
16
|
+
* script run against it is wiped by the upcoming real navigation;
|
|
17
|
+
* - probes are reflective (try/catch, isLoading fallback): a partial test wc
|
|
18
|
+
* degrades to "unsettled", mirroring the surrounding modules'
|
|
19
|
+
* degrade-silently convention.
|
|
20
|
+
*/
|
|
21
|
+
export function isFrontendSettled(wc) {
|
|
22
|
+
try {
|
|
23
|
+
if (wc.isDestroyed())
|
|
24
|
+
return false;
|
|
25
|
+
const url = wc.getURL();
|
|
26
|
+
const mainFrameLoading = typeof wc.isLoadingMainFrame === 'function'
|
|
27
|
+
? wc.isLoadingMainFrame()
|
|
28
|
+
: wc.isLoading();
|
|
29
|
+
return !mainFrameLoading && url !== '' && url !== 'about:blank';
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function createLoadDeferredInjector() {
|
|
36
|
+
const pending = new WeakMap();
|
|
37
|
+
return function injectWhenReady(wc, kind, run) {
|
|
38
|
+
if (wc.isDestroyed())
|
|
39
|
+
return;
|
|
40
|
+
if (isFrontendSettled(wc)) {
|
|
41
|
+
run();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
let kinds = pending.get(wc);
|
|
45
|
+
if (!kinds) {
|
|
46
|
+
kinds = new Map();
|
|
47
|
+
pending.set(wc, kinds);
|
|
48
|
+
}
|
|
49
|
+
const alreadyHooked = kinds.has(kind);
|
|
50
|
+
kinds.set(kind, run);
|
|
51
|
+
if (alreadyHooked)
|
|
52
|
+
return;
|
|
53
|
+
wc.once('did-stop-loading', () => {
|
|
54
|
+
const runner = kinds.get(kind);
|
|
55
|
+
kinds.delete(kind);
|
|
56
|
+
if (!runner || wc.isDestroyed())
|
|
57
|
+
return;
|
|
58
|
+
runner();
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=inject-when-ready.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PlacementReconciler } from './placement-reconciler.js';
|
|
2
|
+
import type { ViewManagerContext } from './view-manager.js';
|
|
3
|
+
/**
|
|
4
|
+
* The right-panel Chrome DevTools front-end host (VIEW_ID.simulatorDevtools).
|
|
5
|
+
* It inspects the SERVICE HOST (logic layer) — the hidden BrowserWindow where
|
|
6
|
+
* the mini-app's page code runs. The service window can be swapped on respawn
|
|
7
|
+
* (pre-warm pool), so the front-end is re-resolved fresh and re-pointed on
|
|
8
|
+
* every render-side event.
|
|
9
|
+
*/
|
|
10
|
+
export interface DevtoolsHost {
|
|
11
|
+
/** Rebuild the front-end host + subscribe to render events + point at the service host. */
|
|
12
|
+
attach(): void;
|
|
13
|
+
/** Re-resolve + re-point the DevTools at the now-current service host (retries). */
|
|
14
|
+
followServiceHost(appId?: string): void;
|
|
15
|
+
/** Unsubscribe render events, clear retries, and close the current source. */
|
|
16
|
+
stopFollowing(): void;
|
|
17
|
+
/** Stop Elements forwarding (aggregate simulator detach, step order preserved). */
|
|
18
|
+
stopElementsForwarding(): void;
|
|
19
|
+
/** Destroy the front-end host WCV (aggregate simulator detach). */
|
|
20
|
+
destroyHostView(): void;
|
|
21
|
+
}
|
|
22
|
+
export declare function createDevtoolsHost(ctx: ViewManagerContext, reconciler: PlacementReconciler, deps: {
|
|
23
|
+
/** Reveal a project file in the embedded workbench editor. */
|
|
24
|
+
openFileInWorkbench(relPath: string, line: number, column: number): boolean;
|
|
25
|
+
}): DevtoolsHost;
|
|
26
|
+
//# sourceMappingURL=native-simulator-devtools-host.d.ts.map
|