@dimina-kit/devtools 0.4.0-dev.20260718143821 → 0.4.0-dev.20260728063215
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 +67 -1
- package/dist/main/app/lifecycle.js +9 -0
- package/dist/main/index.bundle.js +928 -162
- package/dist/main/ipc/bridge-router.d.ts +36 -0
- package/dist/main/ipc/bridge-router.js +56 -0
- package/dist/main/ipc/index.d.ts +1 -0
- package/dist/main/ipc/index.js +1 -0
- package/dist/main/ipc/internal-devtools.d.ts +15 -0
- package/dist/main/ipc/internal-devtools.js +9 -0
- package/dist/main/services/compile-standby.js +4 -0
- package/dist/main/services/console-forward/cdp-inject.d.ts +18 -0
- package/dist/main/services/console-forward/cdp-inject.js +30 -0
- package/dist/main/services/console-forward/global-console-mirror.d.ts +33 -0
- package/dist/main/services/console-forward/global-console-mirror.js +71 -0
- package/dist/main/services/console-forward/global-diagnostics-mirror.d.ts +33 -0
- package/dist/main/services/console-forward/global-diagnostics-mirror.js +73 -0
- package/dist/main/services/console-forward/index.d.ts +15 -1
- package/dist/main/services/console-forward/index.js +42 -2
- package/dist/main/services/console-forward/internal-log.d.ts +11 -0
- package/dist/main/services/console-forward/internal-log.js +23 -0
- package/dist/main/services/console-forward/open-gated-relay.d.ts +67 -0
- package/dist/main/services/console-forward/open-gated-relay.js +55 -0
- package/dist/main/services/diagnostics/index.d.ts +10 -0
- package/dist/main/services/elements-forward/index.js +14 -96
- package/dist/main/services/network-forward/frontend-dispatch.d.ts +64 -0
- package/dist/main/services/network-forward/frontend-dispatch.js +113 -8
- package/dist/main/services/network-forward/global-body-gate.d.ts +46 -0
- package/dist/main/services/network-forward/global-body-gate.js +93 -0
- package/dist/main/services/network-forward/global-mirror-test-fixtures.d.ts +48 -0
- package/dist/main/services/network-forward/global-mirror-test-fixtures.js +96 -0
- package/dist/main/services/network-forward/index.d.ts +31 -0
- package/dist/main/services/network-forward/index.js +256 -8
- package/dist/main/services/network-forward/user-facing.d.ts +21 -0
- package/dist/main/services/network-forward/user-facing.js +50 -0
- package/dist/main/services/views/console-filter.d.ts +145 -0
- package/dist/main/services/views/console-filter.js +233 -0
- package/dist/main/services/views/frontend-bootstrap-gate.d.ts +59 -0
- package/dist/main/services/views/frontend-bootstrap-gate.js +117 -0
- package/dist/main/services/views/native-simulator-devtools-host.js +138 -30
- package/dist/main/services/views/view-manager-devtools-host-test-fixtures.d.ts +76 -0
- package/dist/main/services/views/view-manager-devtools-host-test-fixtures.js +182 -0
- package/dist/main/services/workbench-context.d.ts +10 -0
- package/dist/main/utils/theme.d.ts +10 -6
- package/dist/main/utils/theme.js +10 -6
- package/dist/main/windows/internal-devtools-window/index.d.ts +66 -0
- package/dist/main/windows/internal-devtools-window/index.js +160 -0
- package/dist/native-host/render/render.js +89 -73
- package/dist/native-host/service/service.js +2 -2
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +1 -1
- package/dist/preload/windows/simulator.cjs.map +1 -1
- package/dist/renderer/assets/index-M5NDq_vi.js +49 -0
- package/dist/renderer/assets/{input-c2OcrrZy.js → input-dsgeTmVX.js} +2 -2
- package/dist/renderer/assets/ipc-transport-BgFdT9bT.js +9 -0
- package/dist/renderer/assets/{popover-kv2qspWz.js → popover-Disfu1cx.js} +2 -2
- package/dist/renderer/assets/{select-DKqzMtTh.js → select-DAw1hzkl.js} +2 -2
- package/dist/renderer/assets/{settings-dJNKTGr8.js → settings-M_8GFW2M.js} +2 -2
- package/dist/renderer/assets/settings-api-DFR5eDl_.js +2 -0
- package/dist/renderer/assets/{workbenchSettings-DQ_VP5-W.js → workbenchSettings-CxdXeoOu.js} +2 -2
- package/dist/renderer/entries/main/index.html +5 -5
- package/dist/renderer/entries/popover/index.html +4 -4
- package/dist/renderer/entries/settings/index.html +4 -4
- package/dist/renderer/entries/workbench-settings/index.html +3 -3
- package/dist/shared/ipc-channels.d.ts +3 -0
- package/dist/shared/ipc-channels.js +6 -0
- package/package.json +8 -8
- package/dist/renderer/assets/index-DfDIvgvK.js +0 -49
- package/dist/renderer/assets/ipc-transport-CuDJ07aE.js +0 -9
- package/dist/renderer/assets/settings-api-qpXKDRXt.js +0 -2
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { WebContentsView } from 'electron';
|
|
1
|
+
import { WebContentsView, webContents as electronWebContents } from 'electron';
|
|
2
2
|
import { buildDevtoolsProjectSourceLinksScript, decodeOpenInEditorUrl, projectSourceContextFromServiceHostUrl, } from '../../../shared/open-in-editor.js';
|
|
3
3
|
import { buildCustomizeTabsScript } from './devtools-tabs.js';
|
|
4
|
+
import { buildConsoleFilterScript, buildLiveConsoleFilterScript } from './console-filter.js';
|
|
5
|
+
import { whenFrontendBootstrapped } from './frontend-bootstrap-gate.js';
|
|
4
6
|
import { installElementsForward } from '../elements-forward/index.js';
|
|
5
7
|
import { installServiceConsoleForward } from '../service-console/index.js';
|
|
6
8
|
import { VIEW_ID } from '../../../shared/view-ids.js';
|
|
@@ -54,6 +56,7 @@ export function createDevtoolsHost(ctx, reconciler, deps) {
|
|
|
54
56
|
// (`rebuildDevtoolsHostView`) rather than target it again.
|
|
55
57
|
let devtoolsHostUsed = false;
|
|
56
58
|
let unsubscribeNativeRenderEvents = null;
|
|
59
|
+
let unsubscribeNativeServiceHostReady = null;
|
|
57
60
|
// Disposer for the Elements-forward feature (routes the front-end's Elements
|
|
58
61
|
// CDP traffic at the active render guest). Installed in
|
|
59
62
|
// `attach`, stopped on detach / host destroyed.
|
|
@@ -106,6 +109,13 @@ export function createDevtoolsHost(ctx, reconciler, deps) {
|
|
|
106
109
|
catch { /* ignore */ }
|
|
107
110
|
unsubscribeNativeRenderEvents = null;
|
|
108
111
|
}
|
|
112
|
+
if (unsubscribeNativeServiceHostReady) {
|
|
113
|
+
try {
|
|
114
|
+
unsubscribeNativeServiceHostReady();
|
|
115
|
+
}
|
|
116
|
+
catch { /* ignore */ }
|
|
117
|
+
unsubscribeNativeServiceHostReady = null;
|
|
118
|
+
}
|
|
109
119
|
closeNativeDevtoolsSource();
|
|
110
120
|
}
|
|
111
121
|
function injectOpenResourceHandler(serviceWc, devtoolsWc) {
|
|
@@ -158,6 +168,39 @@ export function createDevtoolsHost(ctx, reconciler, deps) {
|
|
|
158
168
|
}
|
|
159
169
|
catch { /* wc surface incomplete / torn down; degrade silently */ }
|
|
160
170
|
}
|
|
171
|
+
// User-facing Console de-noise: hide dimina
|
|
172
|
+
// framework internal log lines from THIS right-panel Console — the
|
|
173
|
+
// standalone internal DevTools window (native-only, wired elsewhere) shows
|
|
174
|
+
// them unfiltered. Re-applied on every re-point, same policy as
|
|
175
|
+
// customizeDevtoolsTabs. Runs BOTH the persisted-preference write (for a
|
|
176
|
+
// not-yet-constructed panel) AND the live-object drive (for a panel that's
|
|
177
|
+
// already constructed by the time this injection lands, or finishes
|
|
178
|
+
// constructing shortly after — see console-filter.ts's header comment for
|
|
179
|
+
// why the persisted write alone cannot cover that case).
|
|
180
|
+
// Bootstrap-gated: the live script touches `Console.ConsoleView.instance()`,
|
|
181
|
+
// which — fired before the front-end's own bootstrap completes —
|
|
182
|
+
// constructs IssuesManager early and permanently kills that bootstrap (see
|
|
183
|
+
// frontend-bootstrap-gate.ts). Gate resolving false = degrade silently,
|
|
184
|
+
// this module's standing convention.
|
|
185
|
+
function applyConsoleFilter(devtoolsWc) {
|
|
186
|
+
try {
|
|
187
|
+
if (devtoolsWc.isDestroyed())
|
|
188
|
+
return;
|
|
189
|
+
const inject = () => {
|
|
190
|
+
void whenFrontendBootstrapped(devtoolsWc).then((ready) => {
|
|
191
|
+
if (!ready || devtoolsWc.isDestroyed())
|
|
192
|
+
return;
|
|
193
|
+
try {
|
|
194
|
+
void devtoolsWc.executeJavaScript(buildConsoleFilterScript()).catch(() => { });
|
|
195
|
+
void devtoolsWc.executeJavaScript(buildLiveConsoleFilterScript()).catch(() => { });
|
|
196
|
+
}
|
|
197
|
+
catch { /* wc torn down mid-call */ }
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
injectWhenReady(devtoolsWc, 'console-filter', inject);
|
|
201
|
+
}
|
|
202
|
+
catch { /* wc surface incomplete / torn down; degrade silently */ }
|
|
203
|
+
}
|
|
161
204
|
function wireOpenInEditor(serviceWc, devtoolsWc) {
|
|
162
205
|
// Inject the front-end handler on every (re)attach — the DevTools front-end
|
|
163
206
|
// wc is recreated per simulatorView, so a fresh host needs the handler set.
|
|
@@ -246,6 +289,9 @@ export function createDevtoolsHost(ctx, reconciler, deps) {
|
|
|
246
289
|
// Re-applied on every re-point so a service-host pool swap (fresh
|
|
247
290
|
// openDevTools) re-asserts the custom tab bar.
|
|
248
291
|
customizeDevtoolsTabs(simulatorView.webContents);
|
|
292
|
+
// De-noise the user-facing Console: hide
|
|
293
|
+
// dimina framework internal log lines from THIS panel by default.
|
|
294
|
+
applyConsoleFilter(simulatorView.webContents);
|
|
249
295
|
// Capture service-layer console via CDP (NOT a preload monkeypatch, which
|
|
250
296
|
// would clobber native source attribution) and feed it to the console
|
|
251
297
|
// fan-out (automation `App.logAdded`). Bound to THIS service wc; replaced
|
|
@@ -286,8 +332,25 @@ export function createDevtoolsHost(ctx, reconciler, deps) {
|
|
|
286
332
|
return false;
|
|
287
333
|
return pointNativeDevtoolsAtServiceWc(wc);
|
|
288
334
|
}
|
|
289
|
-
|
|
290
|
-
|
|
335
|
+
// Bound on how long the FALLBACK poll (below) keeps retrying before giving
|
|
336
|
+
// up — a pure safety valve, not the real mechanism. The real mechanism is
|
|
337
|
+
// `onNativeServiceHostReady` (an event, not a poll): it fires the moment
|
|
338
|
+
// `ctx.bridge.getServiceWc` is GUARANTEED to resolve, so this fallback only
|
|
339
|
+
// exists for the residual gap where `followNativeDevtoolsServiceHost` runs
|
|
340
|
+
// from a render event that races ahead of that event somehow. A fixed short
|
|
341
|
+
// attempt count here (originally 20×50ms = 1s) was the actual production
|
|
342
|
+
// bug this module was fixed for: under real machine load,
|
|
343
|
+
// `ctx.bridge.getServiceWc(appId)` can take longer than 1s to resolve, and
|
|
344
|
+
// once the fixed budget ran out the right-panel DevTools attach was
|
|
345
|
+
// silently, permanently lost for the rest of that session (confirmed via
|
|
346
|
+
// real reproduction + timing instrumentation). Bounded by WALL-CLOCK time
|
|
347
|
+
// (generous — normal resolution is well under a second) rather than a
|
|
348
|
+
// small attempt count, since the fallback's whole job is to outlast a slow
|
|
349
|
+
// machine, not a slow algorithm.
|
|
350
|
+
const NATIVE_DEVTOOLS_FALLBACK_POLL_MAX_MS = 60_000;
|
|
351
|
+
const NATIVE_DEVTOOLS_FALLBACK_POLL_INTERVAL_MS = 50;
|
|
352
|
+
function scheduleNativeDevtoolsFollow(appId, startedAt = Date.now()) {
|
|
353
|
+
if (Date.now() - startedAt >= NATIVE_DEVTOOLS_FALLBACK_POLL_MAX_MS)
|
|
291
354
|
return;
|
|
292
355
|
if (!ctx.bridge?.isNativeHost())
|
|
293
356
|
return;
|
|
@@ -300,8 +363,8 @@ export function createDevtoolsHost(ctx, reconciler, deps) {
|
|
|
300
363
|
return;
|
|
301
364
|
if (pointNativeDevtoolsAtActiveServiceHost(appId))
|
|
302
365
|
return;
|
|
303
|
-
scheduleNativeDevtoolsFollow(appId,
|
|
304
|
-
},
|
|
366
|
+
scheduleNativeDevtoolsFollow(appId, startedAt);
|
|
367
|
+
}, NATIVE_DEVTOOLS_FALLBACK_POLL_INTERVAL_MS);
|
|
305
368
|
}
|
|
306
369
|
function followNativeDevtoolsServiceHost(appId) {
|
|
307
370
|
clearNativeDevtoolsRetry();
|
|
@@ -309,10 +372,53 @@ export function createDevtoolsHost(ctx, reconciler, deps) {
|
|
|
309
372
|
return;
|
|
310
373
|
scheduleNativeDevtoolsFollow(appId);
|
|
311
374
|
}
|
|
375
|
+
// The real mechanism: fires the moment a service host's `service.html`
|
|
376
|
+
// did-finish-load's, i.e. the exact instant `serviceWcId` is guaranteed
|
|
377
|
+
// resolvable — no polling, no race against a fixed retry budget. Resolves
|
|
378
|
+
// the wc DIRECTLY via the id the event carries (never re-resolving through
|
|
379
|
+
// `getServiceWc(appId)`, which during same-app respawn overlap returns the
|
|
380
|
+
// newest session, not necessarily the one that fired this event), then
|
|
381
|
+
// validates the event against that same authority before acting — see the
|
|
382
|
+
// generation gate below.
|
|
383
|
+
function onNativeServiceHostReady(event) {
|
|
384
|
+
if (!ctx.bridge?.isNativeHost())
|
|
385
|
+
return;
|
|
386
|
+
if (!simulatorView || simulatorView.webContents.isDestroyed())
|
|
387
|
+
return;
|
|
388
|
+
const wc = electronWebContents.fromId(event.serviceWcId);
|
|
389
|
+
if (!wc || wc.isDestroyed())
|
|
390
|
+
return;
|
|
391
|
+
// Generation gate: `getServiceWc` resolves the NEWEST live session
|
|
392
|
+
// (bridge-router's findAppSessionByAppId is last-inserted-wins), so an
|
|
393
|
+
// event it CONTRADICTS is a superseded session's late-arriving ready —
|
|
394
|
+
// repointing there would resurrect a dying host (the newer session's own
|
|
395
|
+
// ready does/did the real repoint). An authority that cannot resolve at
|
|
396
|
+
// all fails OPEN: the event is the only signal available, and dropping
|
|
397
|
+
// it would strand the attach on nothing. Fail-open cannot stick to a
|
|
398
|
+
// dying wc in practice — the direct emit is same-tick with bootServiceHost
|
|
399
|
+
// (session still registered), the catch-up path re-validates the session
|
|
400
|
+
// before delivering, and even a hypothetical miss just makes point()
|
|
401
|
+
// return false into the wall-clock-bounded fallback.
|
|
402
|
+
const current = ctx.bridge.getServiceWc(event.appId);
|
|
403
|
+
if (current && current.id !== event.serviceWcId)
|
|
404
|
+
return;
|
|
405
|
+
// Only a SUCCESSFUL repoint may retire the standing fallback poll — a
|
|
406
|
+
// failed attempt (service wc torn down mid-point is the common race)
|
|
407
|
+
// must leave/re-arm it, or this very event cancels the retry that would
|
|
408
|
+
// have eventually attached.
|
|
409
|
+
if (pointNativeDevtoolsAtServiceWc(wc)) {
|
|
410
|
+
clearNativeDevtoolsRetry();
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
scheduleNativeDevtoolsFollow(event.appId);
|
|
414
|
+
}
|
|
312
415
|
// Render-side activity (a page DOM mounting / the visible page changing)
|
|
313
416
|
// always follows a spawn or respawn, by which point the service window exists
|
|
314
417
|
// (and may have been swapped by the pool). Re-resolve + re-point the DevTools
|
|
315
|
-
// at the now-current service host on every such event.
|
|
418
|
+
// at the now-current service host on every such event. Belt-and-suspenders
|
|
419
|
+
// alongside `onNativeServiceHostReady` — by the time a render event fires,
|
|
420
|
+
// the service host that produced it is definitionally already resolvable,
|
|
421
|
+
// so this path should normally resolve immediately (no fallback poll needed).
|
|
316
422
|
function onNativeRenderEvent(event) {
|
|
317
423
|
if (event.kind !== 'activePage' && event.kind !== 'domReady')
|
|
318
424
|
return;
|
|
@@ -341,11 +447,17 @@ export function createDevtoolsHost(ctx, reconciler, deps) {
|
|
|
341
447
|
// Default DevTools to Console panel (Chrome DevTools defaults to Elements).
|
|
342
448
|
// The DevTools UI lives inside closed shadow roots, so a light-DOM
|
|
343
449
|
// querySelector('[role="tab"]') cannot reach the tab bar to click it.
|
|
344
|
-
// Instead drive the front-end's own view manager
|
|
345
|
-
//
|
|
346
|
-
//
|
|
347
|
-
//
|
|
348
|
-
//
|
|
450
|
+
// Instead drive the front-end's own view manager via `globalThis.EUI`
|
|
451
|
+
// (the bundle's real exposure of the ui/legacy namespace) — NOT
|
|
452
|
+
// `globalThis.UI`, which never exists on this front-end build (same
|
|
453
|
+
// finding devtools-tabs.ts records; an earlier `UI.…`-polling version of
|
|
454
|
+
// this script was dead code and the panel silently defaulted to
|
|
455
|
+
// Elements). Gated on frontend bootstrap: `ViewManager.instance()` is a
|
|
456
|
+
// singleton construction, only safe after the front-end's own MainImpl
|
|
457
|
+
// finished wiring (see frontend-bootstrap-gate.ts). (A persisted
|
|
458
|
+
// `panel-selected-tab` preference write is NOT an alternative mechanism —
|
|
459
|
+
// this custom devtools:// host persists nothing to disk; see
|
|
460
|
+
// console-filter.ts's header.)
|
|
349
461
|
const devtoolsWc = simulatorView.webContents;
|
|
350
462
|
// The boot-time burst of `executeJavaScript()` injects on this host wc (tab
|
|
351
463
|
// customization / console default / Elements+Network forwarding below) each
|
|
@@ -400,27 +512,22 @@ export function createDevtoolsHost(ctx, reconciler, deps) {
|
|
|
400
512
|
});
|
|
401
513
|
}
|
|
402
514
|
injectWhenReady(devtoolsWc, 'console-default', () => {
|
|
403
|
-
devtoolsWc.
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
tries++
|
|
515
|
+
void whenFrontendBootstrapped(devtoolsWc).then((ready) => {
|
|
516
|
+
if (!ready || devtoolsWc.isDestroyed())
|
|
517
|
+
return;
|
|
518
|
+
devtoolsWc.executeJavaScript(`
|
|
519
|
+
(function() {
|
|
409
520
|
try {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
521
|
+
var EUI = globalThis.EUI
|
|
522
|
+
var vm = EUI && EUI.ViewManager && EUI.ViewManager.ViewManager
|
|
523
|
+
&& typeof EUI.ViewManager.ViewManager.instance === 'function'
|
|
524
|
+
? EUI.ViewManager.ViewManager.instance()
|
|
413
525
|
: null
|
|
414
|
-
if (vm && typeof vm.showView === 'function')
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
} catch {}
|
|
420
|
-
if (tries > 80) clearInterval(timer)
|
|
421
|
-
}, 50)
|
|
422
|
-
})()
|
|
423
|
-
`).catch(() => { });
|
|
526
|
+
if (vm && typeof vm.showView === 'function') void vm.showView('console')
|
|
527
|
+
} catch (_) {}
|
|
528
|
+
})()
|
|
529
|
+
`).catch(() => { });
|
|
530
|
+
});
|
|
424
531
|
});
|
|
425
532
|
// Anchor-only mount: the renderer's published rect is the SOLE authority.
|
|
426
533
|
// If a non-zero rect was already published (it can land before this attach
|
|
@@ -440,6 +547,7 @@ export function createDevtoolsHost(ctx, reconciler, deps) {
|
|
|
440
547
|
rebuildDevtoolsHostView();
|
|
441
548
|
if (ctx.bridge?.isNativeHost()) {
|
|
442
549
|
unsubscribeNativeRenderEvents = ctx.bridge.onRenderEvent(onNativeRenderEvent);
|
|
550
|
+
unsubscribeNativeServiceHostReady = ctx.bridge.onServiceHostReady(onNativeServiceHostReady);
|
|
443
551
|
followNativeDevtoolsServiceHost();
|
|
444
552
|
}
|
|
445
553
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared harness for the simulator-DevTools host suites
|
|
3
|
+
* (`view-manager-devtools-host-repoint.test.ts` +
|
|
4
|
+
* `view-manager-service-host-ready.test.ts`), split out so each test file
|
|
5
|
+
* stays under the repo's 500-line-per-file ratchet. Pure test scaffolding,
|
|
6
|
+
* not code under test — same pattern as
|
|
7
|
+
* network-forward/global-mirror-test-fixtures.ts.
|
|
8
|
+
*
|
|
9
|
+
* Consumers register the module mocks themselves (vi.mock factories are
|
|
10
|
+
* hoisted per test file, so they live there, thin):
|
|
11
|
+
* vi.mock('electron', async () =>
|
|
12
|
+
* (await import('./view-manager-devtools-host-test-fixtures.js')).electronModuleMock())
|
|
13
|
+
* vi.mock('../../utils/paths.js', async () =>
|
|
14
|
+
* (await import('./view-manager-devtools-host-test-fixtures.js')).pathsModuleMock())
|
|
15
|
+
* The electron factory closes over this module's `constructed` /
|
|
16
|
+
* `serviceWcRegistry` registries, so test assertions and the mock see the
|
|
17
|
+
* same objects (vitest gives each test FILE its own instance of this module —
|
|
18
|
+
* no cross-file bleed).
|
|
19
|
+
*/
|
|
20
|
+
import { vi } from 'vitest';
|
|
21
|
+
import type { RenderEvent, ServiceHostReadyEvent } from '../../ipc/bridge-router.js';
|
|
22
|
+
import type { ViewManagerContext } from './view-manager.js';
|
|
23
|
+
export type StubWebContents = {
|
|
24
|
+
destroyed: boolean;
|
|
25
|
+
id: number;
|
|
26
|
+
isDestroyed: () => boolean;
|
|
27
|
+
close: ReturnType<typeof vi.fn>;
|
|
28
|
+
loadURL: ReturnType<typeof vi.fn>;
|
|
29
|
+
loadFile: ReturnType<typeof vi.fn>;
|
|
30
|
+
on: ReturnType<typeof vi.fn>;
|
|
31
|
+
once: ReturnType<typeof vi.fn>;
|
|
32
|
+
removeListener: ReturnType<typeof vi.fn>;
|
|
33
|
+
setWindowOpenHandler: ReturnType<typeof vi.fn>;
|
|
34
|
+
setZoomFactor: ReturnType<typeof vi.fn>;
|
|
35
|
+
send: ReturnType<typeof vi.fn>;
|
|
36
|
+
setMaxListeners: ReturnType<typeof vi.fn>;
|
|
37
|
+
getMaxListeners: ReturnType<typeof vi.fn>;
|
|
38
|
+
isLoading: ReturnType<typeof vi.fn>;
|
|
39
|
+
executeJavaScript: ReturnType<typeof vi.fn>;
|
|
40
|
+
setDevToolsWebContents: ReturnType<typeof vi.fn>;
|
|
41
|
+
openDevTools: ReturnType<typeof vi.fn>;
|
|
42
|
+
isDevToolsOpened: ReturnType<typeof vi.fn>;
|
|
43
|
+
closeDevTools: ReturnType<typeof vi.fn>;
|
|
44
|
+
getURL: ReturnType<typeof vi.fn>;
|
|
45
|
+
};
|
|
46
|
+
export type StubView = {
|
|
47
|
+
webContents: StubWebContents;
|
|
48
|
+
setBounds: ReturnType<typeof vi.fn>;
|
|
49
|
+
setBackgroundColor: ReturnType<typeof vi.fn>;
|
|
50
|
+
};
|
|
51
|
+
/** Every WebContentsView ever constructed by the code under test, in
|
|
52
|
+
* construction order: attachNativeSimulator builds [0] = the native simulator
|
|
53
|
+
* content view, then attachNativeSimulatorDevtoolsHost builds [1] = the
|
|
54
|
+
* DevTools front-end host view. Reset in each file's beforeEach. */
|
|
55
|
+
export declare const constructed: StubView[];
|
|
56
|
+
/** Service-host wcs registered by `makeServiceWc`, looked up by
|
|
57
|
+
* `electron.webContents.fromId` — mirrors real Electron's global wc registry
|
|
58
|
+
* so `onNativeServiceHostReady`'s `webContents.fromId(event.serviceWcId)`
|
|
59
|
+
* resolution has something real to find. */
|
|
60
|
+
export declare const serviceWcRegistry: Map<number, StubWebContents>;
|
|
61
|
+
/** The `electron` module surface view-manager and its injectors touch. */
|
|
62
|
+
export declare function electronModuleMock(): Record<string, unknown>;
|
|
63
|
+
export declare function pathsModuleMock(): Record<string, unknown>;
|
|
64
|
+
export declare const SIM_URL = "http://localhost:7788/simulator.html?appId=repoint";
|
|
65
|
+
/** A hidden SERVICE-HOST BrowserWindow wc (top-level, can host DevTools). */
|
|
66
|
+
export declare function makeServiceWc(id: number): StubWebContents;
|
|
67
|
+
export interface DevtoolsHostHarness {
|
|
68
|
+
addChildView: ReturnType<typeof vi.fn>;
|
|
69
|
+
removeChildView: ReturnType<typeof vi.fn>;
|
|
70
|
+
setActiveServiceWc: (wc: StubWebContents) => void;
|
|
71
|
+
emitRenderEvent: (event: RenderEvent) => void;
|
|
72
|
+
emitServiceHostReady: (event: ServiceHostReadyEvent) => void;
|
|
73
|
+
ctx: ViewManagerContext;
|
|
74
|
+
}
|
|
75
|
+
export declare function makeContext(): DevtoolsHostHarness;
|
|
76
|
+
//# sourceMappingURL=view-manager-devtools-host-test-fixtures.d.ts.map
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared harness for the simulator-DevTools host suites
|
|
3
|
+
* (`view-manager-devtools-host-repoint.test.ts` +
|
|
4
|
+
* `view-manager-service-host-ready.test.ts`), split out so each test file
|
|
5
|
+
* stays under the repo's 500-line-per-file ratchet. Pure test scaffolding,
|
|
6
|
+
* not code under test — same pattern as
|
|
7
|
+
* network-forward/global-mirror-test-fixtures.ts.
|
|
8
|
+
*
|
|
9
|
+
* Consumers register the module mocks themselves (vi.mock factories are
|
|
10
|
+
* hoisted per test file, so they live there, thin):
|
|
11
|
+
* vi.mock('electron', async () =>
|
|
12
|
+
* (await import('./view-manager-devtools-host-test-fixtures.js')).electronModuleMock())
|
|
13
|
+
* vi.mock('../../utils/paths.js', async () =>
|
|
14
|
+
* (await import('./view-manager-devtools-host-test-fixtures.js')).pathsModuleMock())
|
|
15
|
+
* The electron factory closes over this module's `constructed` /
|
|
16
|
+
* `serviceWcRegistry` registries, so test assertions and the mock see the
|
|
17
|
+
* same objects (vitest gives each test FILE its own instance of this module —
|
|
18
|
+
* no cross-file bleed).
|
|
19
|
+
*/
|
|
20
|
+
import { vi } from 'vitest';
|
|
21
|
+
import { createConnectionRegistry } from '@dimina-kit/electron-deck/main';
|
|
22
|
+
/** Every WebContentsView ever constructed by the code under test, in
|
|
23
|
+
* construction order: attachNativeSimulator builds [0] = the native simulator
|
|
24
|
+
* content view, then attachNativeSimulatorDevtoolsHost builds [1] = the
|
|
25
|
+
* DevTools front-end host view. Reset in each file's beforeEach. */
|
|
26
|
+
export const constructed = [];
|
|
27
|
+
/** Service-host wcs registered by `makeServiceWc`, looked up by
|
|
28
|
+
* `electron.webContents.fromId` — mirrors real Electron's global wc registry
|
|
29
|
+
* so `onNativeServiceHostReady`'s `webContents.fromId(event.serviceWcId)`
|
|
30
|
+
* resolution has something real to find. */
|
|
31
|
+
export const serviceWcRegistry = new Map();
|
|
32
|
+
/** One stub wc surface shared by BOTH stub flavors (the constructed
|
|
33
|
+
* WebContentsView host wcs and the standalone service-host wcs) — a single
|
|
34
|
+
* factory instead of two hand-maintained near-identical literals. */
|
|
35
|
+
function makeStubWc(id, overrides = {}) {
|
|
36
|
+
return {
|
|
37
|
+
destroyed: false,
|
|
38
|
+
id,
|
|
39
|
+
isDestroyed() { return this.destroyed; },
|
|
40
|
+
close: vi.fn(),
|
|
41
|
+
loadURL: vi.fn(() => Promise.resolve()),
|
|
42
|
+
loadFile: vi.fn(() => Promise.resolve()),
|
|
43
|
+
on: vi.fn(),
|
|
44
|
+
once: vi.fn(),
|
|
45
|
+
removeListener: vi.fn(),
|
|
46
|
+
setWindowOpenHandler: vi.fn(),
|
|
47
|
+
setZoomFactor: vi.fn(),
|
|
48
|
+
send: vi.fn(),
|
|
49
|
+
setMaxListeners: vi.fn(),
|
|
50
|
+
getMaxListeners: vi.fn(() => 10),
|
|
51
|
+
// DevTools front-end host wc surface (the WebContentsView flavor is used
|
|
52
|
+
// for `simulatorView.webContents`, i.e. the right-panel DevTools host).
|
|
53
|
+
isLoading: vi.fn(() => false),
|
|
54
|
+
executeJavaScript: vi.fn(() => Promise.resolve()),
|
|
55
|
+
setDevToolsWebContents: vi.fn(),
|
|
56
|
+
openDevTools: vi.fn(),
|
|
57
|
+
isDevToolsOpened: vi.fn(() => false),
|
|
58
|
+
closeDevTools: vi.fn(),
|
|
59
|
+
getURL: vi.fn(() => ''),
|
|
60
|
+
...overrides,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** The `electron` module surface view-manager and its injectors touch. */
|
|
64
|
+
export function electronModuleMock() {
|
|
65
|
+
let nextId = 1;
|
|
66
|
+
class WebContentsView {
|
|
67
|
+
webContents;
|
|
68
|
+
setBounds = vi.fn();
|
|
69
|
+
setBackgroundColor = vi.fn();
|
|
70
|
+
constructor(_opts) {
|
|
71
|
+
this.webContents = makeStubWc(nextId++, {
|
|
72
|
+
close: vi.fn(function () { this.destroyed = true; }),
|
|
73
|
+
});
|
|
74
|
+
constructed.push(this);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const ipcMain = {
|
|
78
|
+
on: vi.fn(),
|
|
79
|
+
removeListener: vi.fn(),
|
|
80
|
+
handle: vi.fn(),
|
|
81
|
+
removeHandler: vi.fn(),
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
WebContentsView,
|
|
85
|
+
ipcMain,
|
|
86
|
+
shell: { openExternal: vi.fn() },
|
|
87
|
+
nativeTheme: { shouldUseDarkColors: false, on: vi.fn(), removeListener: vi.fn() },
|
|
88
|
+
webContents: {
|
|
89
|
+
fromId: vi.fn((id) => serviceWcRegistry.get(id)),
|
|
90
|
+
getAllWebContents: vi.fn(() => []),
|
|
91
|
+
},
|
|
92
|
+
default: { ipcMain },
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export function pathsModuleMock() {
|
|
96
|
+
return {
|
|
97
|
+
mainPreloadPath: '/stub/preload.js',
|
|
98
|
+
hostToolbarPreloadPath: '/stub/host-toolbar-preload.js',
|
|
99
|
+
cjsSiblingPreloadPath: (p) => p.replace(/\.js$/, '.cjs'),
|
|
100
|
+
devtoolsPackageRoot: '/stub/devtools-pkg-root',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export const SIM_URL = 'http://localhost:7788/simulator.html?appId=repoint';
|
|
104
|
+
/** A hidden SERVICE-HOST BrowserWindow wc (top-level, can host DevTools). */
|
|
105
|
+
export function makeServiceWc(id) {
|
|
106
|
+
const wc = makeStubWc(id, { isDevToolsOpened: vi.fn(() => true) });
|
|
107
|
+
serviceWcRegistry.set(id, wc);
|
|
108
|
+
return wc;
|
|
109
|
+
}
|
|
110
|
+
export function makeContext() {
|
|
111
|
+
const addChildView = vi.fn();
|
|
112
|
+
const removeChildView = vi.fn();
|
|
113
|
+
const contentView = { addChildView, removeChildView, children: [] };
|
|
114
|
+
const mainWindow = {
|
|
115
|
+
destroyed: false,
|
|
116
|
+
contentView,
|
|
117
|
+
isDestroyed() { return this.destroyed; },
|
|
118
|
+
getContentSize: () => [1280, 980],
|
|
119
|
+
};
|
|
120
|
+
const notify = {
|
|
121
|
+
popoverInit: vi.fn(),
|
|
122
|
+
popoverClosed: vi.fn(),
|
|
123
|
+
hostToolbarHeightChanged: vi.fn(),
|
|
124
|
+
};
|
|
125
|
+
// ── ctx.bridge stub ───────────────────────────────────────────────────────
|
|
126
|
+
// Minimal `BridgeRouterHandle`: `getServiceWc` resolves to whatever the test
|
|
127
|
+
// currently points `currentServiceWc` at (simulating a pre-warm-pool swap
|
|
128
|
+
// between render events), and `onRenderEvent` fans a manually-driven
|
|
129
|
+
// `RenderEvent` out to every subscriber (view-manager's own follow-path AND
|
|
130
|
+
// elements-forward's internal subscription both register here).
|
|
131
|
+
let currentServiceWc = null;
|
|
132
|
+
const renderEventListeners = new Set();
|
|
133
|
+
const serviceHostReadyListeners = new Set();
|
|
134
|
+
const bridge = {
|
|
135
|
+
isNativeHost: () => true,
|
|
136
|
+
resolveRenderWc: () => null,
|
|
137
|
+
getServiceWc: vi.fn(() => currentServiceWc),
|
|
138
|
+
getServiceWcForBridge: () => null,
|
|
139
|
+
getActiveRenderWc: () => null,
|
|
140
|
+
getActiveBridgeId: () => null,
|
|
141
|
+
onRenderEvent: (listener) => {
|
|
142
|
+
renderEventListeners.add(listener);
|
|
143
|
+
return () => renderEventListeners.delete(listener);
|
|
144
|
+
},
|
|
145
|
+
onServiceHostReady: (listener) => {
|
|
146
|
+
serviceHostReadyListeners.add(listener);
|
|
147
|
+
return () => serviceHostReadyListeners.delete(listener);
|
|
148
|
+
},
|
|
149
|
+
getDevice: () => null,
|
|
150
|
+
setDevice: () => { },
|
|
151
|
+
disposeSessionsForSimulator: () => Promise.resolve(),
|
|
152
|
+
};
|
|
153
|
+
function setActiveServiceWc(wc) {
|
|
154
|
+
currentServiceWc = wc;
|
|
155
|
+
}
|
|
156
|
+
function emitRenderEvent(event) {
|
|
157
|
+
for (const l of [...renderEventListeners])
|
|
158
|
+
l(event);
|
|
159
|
+
}
|
|
160
|
+
function emitServiceHostReady(event) {
|
|
161
|
+
for (const l of [...serviceHostReadyListeners])
|
|
162
|
+
l(event);
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
addChildView,
|
|
166
|
+
removeChildView,
|
|
167
|
+
setActiveServiceWc,
|
|
168
|
+
emitRenderEvent,
|
|
169
|
+
emitServiceHostReady,
|
|
170
|
+
ctx: {
|
|
171
|
+
windows: {
|
|
172
|
+
mainWindow: mainWindow,
|
|
173
|
+
},
|
|
174
|
+
rendererDir: '/stub/renderer',
|
|
175
|
+
notify: notify,
|
|
176
|
+
connections: createConnectionRegistry(),
|
|
177
|
+
preloadPath: '/stub/sim-preload.js',
|
|
178
|
+
bridge: bridge,
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=view-manager-devtools-host-test-fixtures.js.map
|
|
@@ -4,6 +4,7 @@ import type { BridgeRouterHandle } from '../ipc/bridge-router.js';
|
|
|
4
4
|
import type { ConsoleForwarder } from './console-forward/index.js';
|
|
5
5
|
import type { DiagnosticsBus } from './diagnostics/index.js';
|
|
6
6
|
import type { NetworkForwarder } from './network-forward/index.js';
|
|
7
|
+
import type { InternalDevtoolsWindow } from '../windows/internal-devtools-window/index.js';
|
|
7
8
|
import { type CdpSessionBroker } from './cdp-session/index.js';
|
|
8
9
|
import type { AppDataTap } from './simulator-appdata/index.js';
|
|
9
10
|
import type { StorageApi } from './simulator-storage/index.js';
|
|
@@ -197,6 +198,15 @@ export interface WorkbenchContext {
|
|
|
197
198
|
* DevTools host exist. Undefined until bootstrap wires it.
|
|
198
199
|
*/
|
|
199
200
|
networkForward?: NetworkForwarder;
|
|
201
|
+
/**
|
|
202
|
+
* Controller for the standalone internal (app-wide) DevTools debug window
|
|
203
|
+
* — the independent floating CDP panel that debugs the whole Electron app
|
|
204
|
+
* (as opposed to the right-panel CDP, which inspects only the user's
|
|
205
|
+
* mini-program). Assembled in app bootstrap via
|
|
206
|
+
* `createInternalDevtoolsWindow(mainWindow)`; undefined only in contexts
|
|
207
|
+
* that skip that wiring (e.g. narrow test doubles).
|
|
208
|
+
*/
|
|
209
|
+
internalDevtoolsWindow?: InternalDevtoolsWindow;
|
|
200
210
|
}
|
|
201
211
|
/**
|
|
202
212
|
* Inputs for `createWorkbenchContext`. The scalar config fields it shares with
|
|
@@ -35,12 +35,16 @@ export declare function simDeskBg(): string;
|
|
|
35
35
|
* The defect is platform-agnostic, so the fix is too: one `nativeTheme`
|
|
36
36
|
* `updated` listener re-syncs every current and future BrowserWindow.
|
|
37
37
|
*
|
|
38
|
-
* Known limitation: on Linux
|
|
39
|
-
* system theme
|
|
40
|
-
* `
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
38
|
+
* Known limitation: on some Linux desktops (KDE Plasma + Wayland and other
|
|
39
|
+
* wlroots compositors) an OS-level system theme change flips `updated` with
|
|
40
|
+
* a stale/inverted `shouldUseDarkColors` instead of the correct value — a
|
|
41
|
+
* Chromium ≥142 regression (electron/electron#48736, crbug 462191707, open
|
|
42
|
+
* as of 2026-06) distinct from the older #25925 (fixed since Electron 13,
|
|
43
|
+
* 2021). GNOME/GTK-portal desktops are unaffected. In-app theme switches go
|
|
44
|
+
* through `applyTheme()` and are unaffected on every platform; the gap is
|
|
45
|
+
* limited to the affected Linux desktops + `theme: 'system'` + an OS theme
|
|
46
|
+
* change, an upstream Electron limitation that also leaves the renderer's
|
|
47
|
+
* `prefers-color-scheme` stale.
|
|
44
48
|
*
|
|
45
49
|
* Returns a Disposable that detaches the listener. Install it once during
|
|
46
50
|
* app setup and hand the Disposable to the workbench registry.
|
package/dist/main/utils/theme.js
CHANGED
|
@@ -41,12 +41,16 @@ export function simDeskBg() {
|
|
|
41
41
|
* The defect is platform-agnostic, so the fix is too: one `nativeTheme`
|
|
42
42
|
* `updated` listener re-syncs every current and future BrowserWindow.
|
|
43
43
|
*
|
|
44
|
-
* Known limitation: on Linux
|
|
45
|
-
* system theme
|
|
46
|
-
* `
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
44
|
+
* Known limitation: on some Linux desktops (KDE Plasma + Wayland and other
|
|
45
|
+
* wlroots compositors) an OS-level system theme change flips `updated` with
|
|
46
|
+
* a stale/inverted `shouldUseDarkColors` instead of the correct value — a
|
|
47
|
+
* Chromium ≥142 regression (electron/electron#48736, crbug 462191707, open
|
|
48
|
+
* as of 2026-06) distinct from the older #25925 (fixed since Electron 13,
|
|
49
|
+
* 2021). GNOME/GTK-portal desktops are unaffected. In-app theme switches go
|
|
50
|
+
* through `applyTheme()` and are unaffected on every platform; the gap is
|
|
51
|
+
* limited to the affected Linux desktops + `theme: 'system'` + an OS theme
|
|
52
|
+
* change, an upstream Electron limitation that also leaves the renderer's
|
|
53
|
+
* `prefers-color-scheme` stale.
|
|
50
54
|
*
|
|
51
55
|
* Returns a Disposable that detaches the listener. Install it once during
|
|
52
56
|
* app setup and hand the Disposable to the workbench registry.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { WebContents } from 'electron';
|
|
2
|
+
import { BrowserWindow } from 'electron';
|
|
3
|
+
/**
|
|
4
|
+
* Standalone (non-dock) DevTools window for the whole Electron app — the
|
|
5
|
+
* independent floating CDP debug panel's host window. Unlike the right-panel
|
|
6
|
+
* CDP (`native-simulator-devtools-host.ts`, which re-points at a swappable
|
|
7
|
+
* service-host wc via a reconciler-driven overlay), `target` here is the main
|
|
8
|
+
* window's own webContents and never swaps, so this controller needs none of
|
|
9
|
+
* that machinery: just a plain window with a WebContentsView filling it as
|
|
10
|
+
* the DevTools front-end host.
|
|
11
|
+
*
|
|
12
|
+
* The window + its `setDevToolsWebContents` attachment are built ONCE (on
|
|
13
|
+
* the first `open()`) and never rebuilt afterward — the close button hides
|
|
14
|
+
* rather than destroys. This is deliberate, not an oversight: real-repro
|
|
15
|
+
* diagnostic instrumentation + a source-level Electron/Chromium
|
|
16
|
+
* investigation this session established that destroying and rebuilding
|
|
17
|
+
* this attachment on every close/reopen cycle cannot be made reliable.
|
|
18
|
+
* `closeDevTools()` is effectively a no-op on the `setDevToolsWebContents`
|
|
19
|
+
* external-front-end path (Electron's `InspectableWebContents::CloseDevTools`
|
|
20
|
+
* only does real cleanup when `managed_devtools_web_contents_` is set, which
|
|
21
|
+
* external attachments never populate) — the ONLY authoritative "detached"
|
|
22
|
+
* signal, `'devtools-closed'`, is tied to the OLD front-end host's underlying
|
|
23
|
+
* `content::WebContents` C++ object being destroyed, which was observed
|
|
24
|
+
* (real timestamped log, this session) to take 20+ seconds — the same
|
|
25
|
+
* order of magnitude as this app's own independently-discovered
|
|
26
|
+
* `'close'`-to-`'closed'` BrowserWindow teardown lag. This is a long-standing,
|
|
27
|
+
* unresolved upstream behavior (electron/electron#14095, #17168, #27110,
|
|
28
|
+
* #37356), not something fixable from this module. Electron's own
|
|
29
|
+
* `setDevToolsWebContents` documentation example builds its host window
|
|
30
|
+
* exactly once for the app's lifetime and never rebuilds it — reusing the
|
|
31
|
+
* same host sidesteps the entire bug class instead of chasing a fast
|
|
32
|
+
* "really detached now" signal that does not exist.
|
|
33
|
+
*/
|
|
34
|
+
export interface InternalDevtoolsWindowOptions {
|
|
35
|
+
/** Authority for "the app is quitting right now" (see app/lifecycle.ts).
|
|
36
|
+
* During a real quit every window is closing for real — the controller's
|
|
37
|
+
* habitual close-interception (preventDefault + hide) would CANCEL the
|
|
38
|
+
* quit and leave the process alive with a hidden window nothing will ever
|
|
39
|
+
* show again, so a truthy answer here lets the native close proceed. */
|
|
40
|
+
isAppQuitting?: () => boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface InternalDevtoolsWindow {
|
|
43
|
+
/** Create (on the very first call) and show/focus the window, attaching
|
|
44
|
+
* its DevTools front-end host to `target`'s DevTools exactly once. Every
|
|
45
|
+
* later call just re-shows/focuses the SAME window and host — the
|
|
46
|
+
* underlying DevTools attachment is never rebuilt (see module doc). */
|
|
47
|
+
open(): void;
|
|
48
|
+
/** Actually destroy the window and release the DevTools attachment.
|
|
49
|
+
* Distinct from the user closing the window (which only hides it) — this
|
|
50
|
+
* is for real app-level teardown. Safe to call even if `open()` was never
|
|
51
|
+
* called. */
|
|
52
|
+
dispose(): void;
|
|
53
|
+
/** Subscribe to the front-end host's visibility: fires with the host wc
|
|
54
|
+
* when the window is built (first `open()`) or shown again, and with null
|
|
55
|
+
* when the window is hidden (user close) or destroyed (`dispose()`).
|
|
56
|
+
* Global CDP consumers (network-forward, service-console) gate their
|
|
57
|
+
* dispatch target here — hidden means "stop spending work mirroring into
|
|
58
|
+
* a window nobody can see," not "the attachment is gone." A subscriber
|
|
59
|
+
* registering while the window is ALREADY visible gets the current host
|
|
60
|
+
* replayed one microtask later (same catch-up contract as bridge-router's
|
|
61
|
+
* `onServiceHostReady`) — consumers wired up after `open()` must not stay
|
|
62
|
+
* stuck believing there is no host. Returns an unsubscribe. */
|
|
63
|
+
onHostChanged(handler: (hostWc: WebContents | null) => void): () => void;
|
|
64
|
+
}
|
|
65
|
+
export declare function createInternalDevtoolsWindow(target: BrowserWindow, opts?: InternalDevtoolsWindowOptions): InternalDevtoolsWindow;
|
|
66
|
+
//# sourceMappingURL=index.d.ts.map
|