@dimina-kit/devtools 0.4.0-dev.20260701083540 → 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.
Files changed (81) hide show
  1. package/dist/main/app/app.js +11 -0
  2. package/dist/main/app/max-listeners-diagnostic.d.ts +32 -0
  3. package/dist/main/app/max-listeners-diagnostic.js +63 -0
  4. package/dist/main/index.bundle.js +1657 -1158
  5. package/dist/main/ipc/bridge-router.d.ts +33 -4
  6. package/dist/main/ipc/bridge-router.js +200 -51
  7. package/dist/main/ipc/session-listener-bag.d.ts +41 -0
  8. package/dist/main/ipc/session-listener-bag.js +40 -0
  9. package/dist/main/ipc/simulator.js +5 -5
  10. package/dist/main/ipc/views.js +8 -19
  11. package/dist/main/services/automation/wait-active-page.d.ts +4 -2
  12. package/dist/main/services/elements-forward/index.js +19 -0
  13. package/dist/main/services/network-forward/index.js +13 -0
  14. package/dist/main/services/render-inspect/index.d.ts +9 -0
  15. package/dist/main/services/render-inspect/index.js +13 -1
  16. package/dist/main/services/simulator-storage/index.d.ts +9 -0
  17. package/dist/main/services/simulator-storage/index.js +26 -1
  18. package/dist/main/services/simulator-wxml/index.js +117 -11
  19. package/dist/main/services/views/apply-view-ops.d.ts +11 -0
  20. package/dist/main/services/views/apply-view-ops.js +22 -0
  21. package/dist/main/services/views/destroy-child-view.d.ts +9 -0
  22. package/dist/main/services/views/destroy-child-view.js +23 -0
  23. package/dist/main/services/views/host-toolbar-view.d.ts +21 -0
  24. package/dist/main/services/views/host-toolbar-view.js +249 -0
  25. package/dist/main/services/views/inject-when-ready.d.ts +41 -0
  26. package/dist/main/services/views/inject-when-ready.js +62 -0
  27. package/dist/main/services/views/native-simulator-devtools-host.d.ts +26 -0
  28. package/dist/main/services/views/native-simulator-devtools-host.js +484 -0
  29. package/dist/main/services/views/native-simulator-view.d.ts +28 -0
  30. package/dist/main/services/views/native-simulator-view.js +428 -0
  31. package/dist/main/services/views/overlay-panels-view.d.ts +29 -0
  32. package/dist/main/services/views/overlay-panels-view.js +150 -0
  33. package/dist/main/services/views/placement-reconciler.d.ts +73 -0
  34. package/dist/main/services/views/placement-reconciler.js +120 -0
  35. package/dist/main/services/views/placement-test-driver.d.ts +25 -0
  36. package/dist/main/services/views/placement-test-driver.js +48 -0
  37. package/dist/main/services/views/resolve-project-editor-target.d.ts +13 -0
  38. package/dist/main/services/views/resolve-project-editor-target.js +33 -0
  39. package/dist/main/services/views/view-manager.d.ts +28 -70
  40. package/dist/main/services/views/view-manager.js +66 -1514
  41. package/dist/main/services/views/workbench-view.d.ts +15 -0
  42. package/dist/main/services/views/workbench-view.js +170 -0
  43. package/dist/main/services/workbench-context.d.ts +10 -0
  44. package/dist/preload/windows/host-toolbar-runtime.cjs +6 -13
  45. package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
  46. package/dist/preload/windows/main.cjs +10 -1
  47. package/dist/preload/windows/main.cjs.map +2 -2
  48. package/dist/preload/windows/simulator.cjs +6 -3
  49. package/dist/preload/windows/simulator.cjs.map +2 -2
  50. package/dist/preload/windows/simulator.js +6 -3
  51. package/dist/render-host/render-inspect.js +35 -1
  52. package/dist/renderer/assets/index-ChF9V4r-.js +49 -0
  53. package/dist/renderer/assets/{input-DR7bfyQE.js → input-Cjk0wSEh.js} +2 -2
  54. package/dist/renderer/assets/ipc-transport-D5dKIti1.css +1 -0
  55. package/dist/renderer/assets/{ipc-transport-3Arg8jPC.js → ipc-transport-OZS-KmOW.js} +2 -2
  56. package/dist/renderer/assets/{popover-CPZX3MrT.js → popover-CQVvOe90.js} +2 -2
  57. package/dist/renderer/assets/{select-BxyPlVyJ.js → select-BQDXi5ih.js} +2 -2
  58. package/dist/renderer/assets/{settings-api-CtPPJF-F.js → settings-api-B6x2mhaD.js} +2 -2
  59. package/dist/renderer/assets/{settings-CG_OR03F.js → settings-tP3Px2KR.js} +2 -2
  60. package/dist/renderer/assets/{workbenchSettings-ClqCBGOa.js → workbenchSettings-Bim9ol9R.js} +2 -2
  61. package/dist/renderer/entries/main/index.html +6 -6
  62. package/dist/renderer/entries/popover/index.html +5 -5
  63. package/dist/renderer/entries/settings/index.html +5 -5
  64. package/dist/renderer/entries/workbench-settings/index.html +4 -4
  65. package/dist/service-host/sync-api-patch.js +33 -3
  66. package/dist/shared/bridge-channels.d.ts +17 -0
  67. package/dist/shared/bridge-channels.js +9 -0
  68. package/dist/shared/ipc-channels.d.ts +29 -14
  69. package/dist/shared/ipc-channels.js +16 -17
  70. package/dist/shared/ipc-schemas.d.ts +25 -17
  71. package/dist/shared/ipc-schemas.js +38 -22
  72. package/dist/shared/view-ids.d.ts +19 -0
  73. package/dist/shared/view-ids.js +25 -0
  74. package/dist/simulator/assets/{bridge-channels-BUQ5AbvJ.js → bridge-channels-zhsumfky.js} +2 -2
  75. package/dist/simulator/assets/{device-shell-CT3LRnTB.js → device-shell-CUl0ILfn.js} +2 -2
  76. package/dist/simulator/assets/{simulator-BizhGGE3.js → simulator-Dz8iGcgy.js} +5 -5
  77. package/dist/simulator/assets/{simulator-mini-app-BfNuDF3R.js → simulator-mini-app-Bt639XL_.js} +2 -2
  78. package/dist/simulator/simulator.html +2 -1
  79. package/package.json +4 -4
  80. package/dist/renderer/assets/index-HE9Xr9bQ.js +0 -49
  81. package/dist/renderer/assets/ipc-transport-Dt0jR7Ir.css +0 -1
@@ -0,0 +1,73 @@
1
+ import type { WebContentsView } from 'electron';
2
+ import * as layout from '../layout/index.js';
3
+ import type { DesiredView, PlacementSnapshot } from '@dimina-kit/electron-deck/layout';
4
+ import type { DevtoolsExtra } from '../../../shared/view-ids.js';
5
+ import type { ViewManagerContext } from './view-manager.js';
6
+ /**
7
+ * The per-view wiring the reconciler needs to converge the main-process view
8
+ * tree. Each view domain registers exactly one slot; the reconciler owns no
9
+ * view references itself, so the domain's own `let viewRef` stays the single
10
+ * source of truth (the slot exposes accessors into it, never a copy).
11
+ */
12
+ export interface ViewSlot {
13
+ /** The live WebContentsView for this slot, or null when not yet created. */
14
+ getView(): WebContentsView | null;
15
+ /** Record whether the view is currently added to the contentView. */
16
+ setAdded?(added: boolean): void;
17
+ /**
18
+ * When true, force the desired placement to hidden — the view-creation site
19
+ * has not produced the WCV yet, so the reconciler must never record an attach
20
+ * that addChildView can't perform. The creation site calls `reconcileNow()`
21
+ * to re-open the gate.
22
+ */
23
+ gateHidden?(): boolean;
24
+ /**
25
+ * Run before the generic attach. Return true when the slot fully handled the
26
+ * attach itself (e.g. a lazy async load that adds the view on completion), so
27
+ * the reconciler must NOT addChildView here.
28
+ */
29
+ beforeAttach?(): boolean;
30
+ /** Lazily create the view on attach (host-toolbar); used instead of getView. */
31
+ ensureView?(): WebContentsView | null;
32
+ /** Domain-specific setBounds (simulator zoom rides here). */
33
+ applyBounds?(view: WebContentsView, bounds: layout.Bounds, extra: DevtoolsExtra | undefined): void;
34
+ /**
35
+ * Create the lazily-built view BEFORE reconcile when its desired placement is
36
+ * visible, so the setBounds op — which the core emits before attach — lands
37
+ * on a live view rather than a not-yet-created one.
38
+ */
39
+ ensureLazy?(desired: DesiredView<DevtoolsExtra> | undefined): void;
40
+ }
41
+ /**
42
+ * Level-triggered placement reconciler (docs/view-placement-reconciler.md). The
43
+ * renderer publishes a window-level snapshot into `baseDesired`;
44
+ * settings/popover are main-owned and live in `overlayDesired`. Any change
45
+ * merges the two, runs the pure reconcile core, and applies the ordered ops
46
+ * through `viewTarget`. `epochCounter` is a single monotonic tick — main is the
47
+ * only (serial) reconcile caller, so the core's stale guard passes by
48
+ * construction; `rendererGeneration` still drives the reset on renderer restart.
49
+ */
50
+ export interface PlacementReconciler {
51
+ registerView(viewId: string, slot: ViewSlot): void;
52
+ reconcileNow(): void;
53
+ /**
54
+ * Apply the renderer's window-level placement snapshot — the single source of
55
+ * truth for every managed native view's bounds/visibility/z-order.
56
+ */
57
+ setPlacementSnapshot(snapshot: PlacementSnapshot<DevtoolsExtra>): void;
58
+ /**
59
+ * Forget a view's reconciled mount state so the NEXT rebuilt view is treated
60
+ * as a fresh attach. Required wherever a view instance is replaced/destroyed
61
+ * via a manual removeChildView that bypasses the reconciler (otherwise the
62
+ * level-triggered core still records the old instance as attached and never
63
+ * emits the attach op for the replacement — a sticky invisible view).
64
+ */
65
+ forgetActual(viewId: string): void;
66
+ setBaseDesired(viewId: string, desired: DesiredView<DevtoolsExtra>): void;
67
+ deleteBaseDesired(viewId: string): void;
68
+ setOverlayDesired(viewId: string, desired: DesiredView<DevtoolsExtra>): void;
69
+ deleteOverlayDesired(viewId: string): void;
70
+ hasOverlayDesired(viewId: string): boolean;
71
+ }
72
+ export declare function createPlacementReconciler(ctx: ViewManagerContext): PlacementReconciler;
73
+ //# sourceMappingURL=placement-reconciler.d.ts.map
@@ -0,0 +1,120 @@
1
+ import { reconcile, createInitialState } from '@dimina-kit/electron-deck/layout';
2
+ import { applyViewOps } from './apply-view-ops.js';
3
+ export function createPlacementReconciler(ctx) {
4
+ let placementState = createInitialState();
5
+ let epochCounter = 0;
6
+ let rendererGeneration = 0;
7
+ const baseDesired = new Map();
8
+ const overlayDesired = new Map();
9
+ const slots = new Map();
10
+ function gateReadiness(v) {
11
+ const slot = slots.get(v.viewId);
12
+ if (slot?.gateHidden?.())
13
+ return { ...v, placement: { visible: false } };
14
+ return v;
15
+ }
16
+ const viewTarget = {
17
+ attach(viewId) {
18
+ if (ctx.windows.mainWindow.isDestroyed())
19
+ return;
20
+ const slot = slots.get(viewId);
21
+ if (!slot)
22
+ return;
23
+ if (slot.beforeAttach?.())
24
+ return;
25
+ const view = slot.ensureView ? slot.ensureView() : slot.getView();
26
+ if (!view)
27
+ return;
28
+ ctx.windows.mainWindow.contentView.addChildView(view);
29
+ slot.setAdded?.(true);
30
+ },
31
+ detach(viewId) {
32
+ const slot = slots.get(viewId);
33
+ const view = slot?.getView() ?? null;
34
+ if (view && !ctx.windows.mainWindow.isDestroyed()) {
35
+ try {
36
+ ctx.windows.mainWindow.contentView.removeChildView(view);
37
+ }
38
+ catch { /* already removed */ }
39
+ }
40
+ slot?.setAdded?.(false);
41
+ },
42
+ setBounds(viewId, bounds, extra) {
43
+ const slot = slots.get(viewId);
44
+ const view = slot?.getView() ?? null;
45
+ if (!view || view.webContents.isDestroyed())
46
+ return;
47
+ if (slot?.applyBounds) {
48
+ slot.applyBounds(view, bounds, extra);
49
+ return;
50
+ }
51
+ view.setBounds(bounds);
52
+ },
53
+ setVisible(viewId, visible) {
54
+ const view = slots.get(viewId)?.getView() ?? null;
55
+ if (!view)
56
+ return;
57
+ try {
58
+ view.setVisible(visible);
59
+ }
60
+ catch { /* stub may lack setVisible */ }
61
+ },
62
+ reorder(order) {
63
+ // A single attached view is already in place — nothing to reorder.
64
+ if (order.length <= 1 || ctx.windows.mainWindow.isDestroyed())
65
+ return;
66
+ const cv = ctx.windows.mainWindow.contentView;
67
+ for (const viewId of order) {
68
+ const view = slots.get(viewId)?.getView() ?? null;
69
+ if (view) {
70
+ try {
71
+ cv.addChildView(view);
72
+ }
73
+ catch { /* already attached */ }
74
+ }
75
+ }
76
+ },
77
+ };
78
+ // Create the lazily-built views (host-toolbar, workbench) BEFORE reconcile so
79
+ // the setBounds op — which the core emits before attach — lands on a live view
80
+ // rather than a not-yet-created one.
81
+ function ensureLazyViews() {
82
+ for (const [viewId, slot] of slots) {
83
+ slot.ensureLazy?.(baseDesired.get(viewId));
84
+ }
85
+ }
86
+ function reconcileNow() {
87
+ ensureLazyViews();
88
+ const views = [];
89
+ for (const v of baseDesired.values())
90
+ views.push(gateReadiness(v));
91
+ for (const v of overlayDesired.values())
92
+ views.push(v);
93
+ const result = reconcile(placementState, {
94
+ generation: rendererGeneration,
95
+ epoch: ++epochCounter,
96
+ views,
97
+ });
98
+ placementState = result.state;
99
+ applyViewOps(result.ops, viewTarget);
100
+ }
101
+ function setPlacementSnapshot(snapshot) {
102
+ rendererGeneration = snapshot.generation;
103
+ baseDesired.clear();
104
+ for (const v of snapshot.views)
105
+ baseDesired.set(v.viewId, v);
106
+ reconcileNow();
107
+ }
108
+ return {
109
+ registerView: (viewId, slot) => { slots.set(viewId, slot); },
110
+ reconcileNow,
111
+ setPlacementSnapshot,
112
+ forgetActual: (viewId) => { placementState.actual.delete(viewId); },
113
+ setBaseDesired: (viewId, desired) => { baseDesired.set(viewId, desired); },
114
+ deleteBaseDesired: (viewId) => { baseDesired.delete(viewId); },
115
+ setOverlayDesired: (viewId, desired) => { overlayDesired.set(viewId, desired); },
116
+ deleteOverlayDesired: (viewId) => { overlayDesired.delete(viewId); },
117
+ hasOverlayDesired: (viewId) => overlayDesired.has(viewId),
118
+ };
119
+ }
120
+ //# sourceMappingURL=placement-reconciler.js.map
@@ -0,0 +1,25 @@
1
+ import type { DesiredView } from '@dimina-kit/electron-deck/layout';
2
+ import { type DevtoolsExtra } from '../../../shared/view-ids.js';
3
+ interface Rect {
4
+ x: number;
5
+ y: number;
6
+ width: number;
7
+ height: number;
8
+ }
9
+ interface SnapshotSink {
10
+ setPlacementSnapshot(snapshot: {
11
+ generation: number;
12
+ epoch: number;
13
+ views: DesiredView<DevtoolsExtra>[];
14
+ }): void;
15
+ }
16
+ export declare function hostToolbarBounds(mgr: SnapshotSink, rect: Rect): void;
17
+ export declare function simulatorDevtoolsBounds(mgr: SnapshotSink, rect: Rect): void;
18
+ export declare function workbenchBounds(mgr: SnapshotSink, rect: Rect): void;
19
+ export declare function simulatorBounds(mgr: SnapshotSink, params: Rect & {
20
+ zoom: number;
21
+ }): void;
22
+ /** Drop a view from this manager's desired table (reconcile detaches it). */
23
+ export declare function removeView(mgr: SnapshotSink, viewId: string): void;
24
+ export {};
25
+ //# sourceMappingURL=placement-test-driver.d.ts.map
@@ -0,0 +1,48 @@
1
+ // Test-only helper: drives the view manager through its real runtime entry
2
+ // point, `setPlacementSnapshot`, the way the renderer's central publisher does
3
+ // — accumulating each view's desired placement (per manager) and publishing the
4
+ // WHOLE table under a monotonic epoch. A single-view update thus keeps the other
5
+ // views' last-declared placement, matching the renderer's level-triggered stream
6
+ // rather than the old per-view setXxxBounds edges. These free functions let the
7
+ // many view-manager tests exercise reconcile behaviour with a drop-in rename
8
+ // (`mgr.setHostToolbarBounds(r)` → `hostToolbarBounds(mgr, r)`).
9
+ import { VIEW_ID, VIEW_LAYER } from '../../../shared/view-ids.js';
10
+ // Monotonic across every push in a test file (vitest isolates module state per
11
+ // file), so a fresh manager (lastEpoch -1) accepts the first push and repeated
12
+ // pushes on one manager never look stale.
13
+ let globalEpoch = 0;
14
+ const desiredByMgr = new WeakMap();
15
+ function toPlacement(r) {
16
+ return r.width > 0 && r.height > 0 ? { visible: true, bounds: r } : { visible: false };
17
+ }
18
+ function pushView(mgr, view, generation = 1) {
19
+ let desired = desiredByMgr.get(mgr);
20
+ if (!desired) {
21
+ desired = new Map();
22
+ desiredByMgr.set(mgr, desired);
23
+ }
24
+ desired.set(view.viewId, view);
25
+ mgr.setPlacementSnapshot({ generation, epoch: globalEpoch++, views: [...desired.values()] });
26
+ }
27
+ export function hostToolbarBounds(mgr, rect) {
28
+ pushView(mgr, { viewId: VIEW_ID.hostToolbar, placement: toPlacement(rect), layer: VIEW_LAYER.hostToolbar });
29
+ }
30
+ export function simulatorDevtoolsBounds(mgr, rect) {
31
+ pushView(mgr, { viewId: VIEW_ID.simulatorDevtools, placement: toPlacement(rect), layer: VIEW_LAYER.base });
32
+ }
33
+ export function workbenchBounds(mgr, rect) {
34
+ pushView(mgr, { viewId: VIEW_ID.workbench, placement: toPlacement(rect), layer: VIEW_LAYER.base });
35
+ }
36
+ export function simulatorBounds(mgr, params) {
37
+ const { zoom, ...rect } = params;
38
+ pushView(mgr, { viewId: VIEW_ID.simulator, placement: toPlacement(rect), layer: VIEW_LAYER.base, extra: { zoom } });
39
+ }
40
+ /** Drop a view from this manager's desired table (reconcile detaches it). */
41
+ export function removeView(mgr, viewId) {
42
+ const desired = desiredByMgr.get(mgr);
43
+ if (!desired)
44
+ return;
45
+ desired.delete(viewId);
46
+ mgr.setPlacementSnapshot({ generation: 1, epoch: globalEpoch++, views: [...desired.values()] });
47
+ }
48
+ //# sourceMappingURL=placement-test-driver.js.map
@@ -0,0 +1,13 @@
1
+ import { type OpenInEditorRequest } from '../../../shared/open-in-editor.js';
2
+ export interface ProjectEditorTarget {
3
+ path: string;
4
+ line?: number;
5
+ column?: number;
6
+ }
7
+ /**
8
+ * Resolve a DevTools source request against the service-host URL that created
9
+ * the inspected app. Its pkgRoot is authoritative; the workspace is only a
10
+ * stale-session consistency guard.
11
+ */
12
+ export declare function resolveProjectEditorTarget(serviceHostUrl: string, activeProjectRoot: string | undefined, req: OpenInEditorRequest, isFile?: (absolutePath: string) => boolean): ProjectEditorTarget | null;
13
+ //# sourceMappingURL=resolve-project-editor-target.d.ts.map
@@ -0,0 +1,33 @@
1
+ import fs from 'node:fs';
2
+ import path from 'path';
3
+ import { projectSourceContextFromServiceHostUrl, resourceUrlToProjectRelativePath, } from '../../../shared/open-in-editor.js';
4
+ /**
5
+ * Resolve a DevTools source request against the service-host URL that created
6
+ * the inspected app. Its pkgRoot is authoritative; the workspace is only a
7
+ * stale-session consistency guard.
8
+ */
9
+ export function resolveProjectEditorTarget(serviceHostUrl, activeProjectRoot, req, isFile = (absolutePath) => fs.statSync(absolutePath).isFile()) {
10
+ const sourceContext = projectSourceContextFromServiceHostUrl(serviceHostUrl, activeProjectRoot);
11
+ if (!sourceContext)
12
+ return null;
13
+ const rel = resourceUrlToProjectRelativePath(req.url, sourceContext);
14
+ if (!rel)
15
+ return null;
16
+ const absolute = path.resolve(sourceContext.projectRoot, ...rel.split('/'));
17
+ const fromRoot = path.relative(path.resolve(sourceContext.projectRoot), absolute);
18
+ if (!fromRoot || fromRoot.startsWith('..') || path.isAbsolute(fromRoot))
19
+ return null;
20
+ try {
21
+ if (!isFile(absolute))
22
+ return null;
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ return {
28
+ path: rel,
29
+ line: typeof req.line === 'number' ? req.line + 1 : undefined,
30
+ column: typeof req.column === 'number' ? req.column + 1 : undefined,
31
+ };
32
+ }
33
+ //# sourceMappingURL=resolve-project-editor-target.js.map
@@ -1,8 +1,10 @@
1
1
  import type { WebContents } from 'electron';
2
2
  import type { NativeDeviceInfo } from '../../../shared/ipc-channels.js';
3
- import { type OpenInEditorRequest } from '../../../shared/open-in-editor.js';
4
3
  import { type WorkbenchContext } from '../workbench-context.js';
5
- import { type HostToolbarMessageSubscription } from './host-toolbar-port-channel.js';
4
+ import type { HostToolbarMessageSubscription } from './host-toolbar-port-channel.js';
5
+ import type { PlacementSnapshot } from '@dimina-kit/electron-deck/layout';
6
+ import type { DevtoolsExtra } from '../../../shared/view-ids.js';
7
+ export { resolveProjectEditorTarget, type ProjectEditorTarget, } from './resolve-project-editor-target.js';
6
8
  /**
7
9
  * Context surface used by the ViewManager. We only need a small slice of the
8
10
  * full WorkbenchContext here; typing it this way documents the actual dependency.
@@ -11,10 +13,10 @@ export interface ViewManagerContext {
11
13
  windows: WorkbenchContext['windows'];
12
14
  rendererDir: string;
13
15
  /**
14
- * Per-webContents connection registry (foundation.md §4). The native-host
16
+ * Per-webContents connection registry. The native-host
15
17
  * simulator WebContentsView is acquired here so the registry tracks that
16
18
  * trusted webContents and tears its per-wc resources (the custom-api bridge
17
- * `ipcMain.on`) down deterministically on destroy — see P1 DoD #3. Required:
19
+ * `ipcMain.on`) down deterministically on destroy. Required:
18
20
  * `createWorkbenchContext` always supplies it.
19
21
  */
20
22
  connections: WorkbenchContext['connections'];
@@ -67,6 +69,11 @@ export interface ViewManagerContext {
67
69
  * main-process WebContentsView (`attachWorkbench`) hung off the main window's
68
70
  * contentView, like the other overlays. The main window's own renderer is the
69
71
  * content root and is not managed here.
72
+ *
73
+ * This module is the composition root: each view domain lives in its own
74
+ * factory module (simulator, devtools-host, workbench, host-toolbar, overlay
75
+ * panels) and shares a single injected placement reconciler; this file wires
76
+ * them together and exposes their combined method surface.
70
77
  */
71
78
  export interface ViewManager {
72
79
  /**
@@ -87,6 +94,16 @@ export interface ViewManager {
87
94
  * geometry is anchor-published.
88
95
  */
89
96
  attachNativeSimulator(simulatorUrl: string, simWidth: number): Promise<void>;
97
+ /**
98
+ * Soft-reload the LIVE native simulator after a watcher rebuild: forward a
99
+ * SIMULATOR_EVENTS.RELAUNCH (carrying the rebuilt simulator URL) into the
100
+ * existing WCV so the shell boots a new app session in place and swaps when
101
+ * it is ready — the phone shell never unmounts. Returns false (no event
102
+ * sent) when there is no live simulator view or its shell has not finished
103
+ * its first boot (first render guest did-finish-load); the caller then falls
104
+ * back to the hard attachNativeSimulator rebuild.
105
+ */
106
+ softReloadNativeSimulator(simulatorUrl: string): boolean;
90
107
  /**
91
108
  * Destroy and null out the simulator view (e.g. on simulator detach).
92
109
  * Also destroys the cached settings view and hides the popover —
@@ -135,22 +152,6 @@ export interface ViewManager {
135
152
  * always on close-project → reopen) would otherwise be lost forever.
136
153
  */
137
154
  getHostToolbarHeight(): number;
138
- /**
139
- * NATIVE-HOST ONLY. Position the simulator content WebContentsView over the
140
- * renderer-measured simulator panel REGION rect (the flex:1 placeholder slot,
141
- * CSS px from the main window content top-left, which maps 1:1 to overlay
142
- * setBounds DIP) and apply the device zoom. The WCV fills the region as a
143
- * plain rectangle; DeviceShell draws + scrolls the phone inside. No-op in the
144
- * default `<webview>` path (`nativeSimulatorView` is null). See
145
- * `computeNativeSimulatorViewParams`.
146
- */
147
- setNativeSimulatorViewBounds(params: {
148
- x: number;
149
- y: number;
150
- width: number;
151
- height: number;
152
- zoom: number;
153
- }): void;
154
155
  /**
155
156
  * NATIVE-HOST ONLY. Re-push the selected device's CSS `env(safe-area-inset-*)`
156
157
  * override to every attached render-host guest (on device change). New guests
@@ -164,17 +165,12 @@ export interface ViewManager {
164
165
  */
165
166
  resize(simWidth: number): void;
166
167
  /**
167
- * Apply a renderer-measured rectangle to the simulator's Chromium
168
- * DevTools overlay view. `{ width: 0, height: 0 }` is treated as "hide" —
169
- * the view is removed from the contentView but its WebContents is kept
170
- * alive so re-showing it doesn't re-pay the DevTools bootstrap.
168
+ * Apply the renderer's window-level placement snapshot the single source of
169
+ * truth for every managed native view's bounds/visibility/z-order. Merged with
170
+ * main-owned settings/popover desired state and reconciled against the actual
171
+ * view tree.
171
172
  */
172
- setSimulatorDevtoolsBounds(bounds: {
173
- x: number;
174
- y: number;
175
- width: number;
176
- height: number;
177
- }): void;
173
+ setPlacementSnapshot(snapshot: PlacementSnapshot<DevtoolsExtra>): void;
178
174
  /**
179
175
  * Lazily create the workbench WebContentsView, load `<url>index.html`, and
180
176
  * add it to the contentView. `url` is the COI server's base URL (trailing
@@ -188,19 +184,6 @@ export interface ViewManager {
188
184
  * `setWorkbenchBounds`, keeping it off the app boot critical path.
189
185
  */
190
186
  setWorkbenchSource(url: string): void;
191
- /**
192
- * Apply a renderer-measured rectangle to the workbench editor view. Mirrors
193
- * `setSimulatorDevtoolsBounds`: `{ width: 0, height: 0 }` is "hide" — the view
194
- * is removed from the contentView (kept under settings/popover when re-added)
195
- * but its WebContents stays alive. The first non-zero rect lazily creates +
196
- * loads the workbench (from the URL set by `setWorkbenchSource`).
197
- */
198
- setWorkbenchBounds(bounds: {
199
- x: number;
200
- y: number;
201
- width: number;
202
- height: number;
203
- }): void;
204
187
  /** Destroy the workbench editor view (teardown). No-op if never attached. */
205
188
  detachWorkbench(): void;
206
189
  /**
@@ -211,20 +194,6 @@ export interface ViewManager {
211
194
  * request was dispatched to the workbench.
212
195
  */
213
196
  openFileInWorkbench(relPath: string, line: number, column: number): boolean;
214
- /**
215
- * Apply a renderer-measured rectangle to the host-controllable toolbar
216
- * WebContentsView (the strip above the devtools header). Forward anchor,
217
- * mirroring `setSimulatorDevtoolsBounds`. `{ width: 0, height: 0 }` is
218
- * treated as "hide" — the view is removed from the contentView but its
219
- * WebContents (and the host's loaded content) stays alive. Lazily creates
220
- * the view on the first non-empty rect.
221
- */
222
- setHostToolbarBounds(bounds: {
223
- x: number;
224
- y: number;
225
- width: number;
226
- height: number;
227
- }): void;
228
197
  /**
229
198
  * Reverse size-advertiser sink: the toolbar WCV's own renderer advertises
230
199
  * its intrinsic content height (block-axis extent); we retain it as the
@@ -319,23 +288,12 @@ export interface HostToolbarControl {
319
288
  */
320
289
  setHeightMode(mode: HostToolbarHeightMode): void;
321
290
  }
322
- export interface ProjectEditorTarget {
323
- path: string;
324
- line?: number;
325
- column?: number;
326
- }
327
- /**
328
- * Resolve a DevTools source request against the service-host URL that created
329
- * the inspected app. Its pkgRoot is authoritative; the workspace is only a
330
- * stale-session consistency guard.
331
- */
332
- export declare function resolveProjectEditorTarget(serviceHostUrl: string, activeProjectRoot: string | undefined, req: OpenInEditorRequest, isFile?: (absolutePath: string) => boolean): ProjectEditorTarget | null;
333
291
  /**
334
292
  * Build a ViewManager bound to the given context. The returned object is the
335
293
  * only component allowed to instantiate or add/remove overlay WebContentsViews.
336
294
  *
337
- * All view-related mutable state lives inside this closure and is not exposed
338
- * on the context object.
295
+ * All view-related mutable state lives inside the per-domain factory closures
296
+ * (and the single placement reconciler) below, never on the context object.
339
297
  */
340
298
  export declare function createViewManager(ctx: ViewManagerContext): ViewManager;
341
299
  //# sourceMappingURL=view-manager.d.ts.map