@dimina-kit/devtools 0.4.0-dev.20260824071518 → 0.4.0-dev.20260828092243

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 (153) hide show
  1. package/dist/main/api.d.ts +1 -1
  2. package/dist/main/app/app.js +55 -2
  3. package/dist/main/index.bundle.js +887 -234
  4. package/dist/main/ipc/index.d.ts +2 -0
  5. package/dist/main/ipc/index.js +2 -0
  6. package/dist/main/ipc/popover.js +1 -1
  7. package/dist/main/ipc/project-create.d.ts +15 -0
  8. package/dist/main/ipc/project-create.js +26 -0
  9. package/dist/main/ipc/projects.d.ts +1 -1
  10. package/dist/main/ipc/projects.js +11 -0
  11. package/dist/main/ipc/settings.js +2 -1
  12. package/dist/main/ipc/simulator-module.d.ts +4 -3
  13. package/dist/main/ipc/simulator-module.js +4 -5
  14. package/dist/main/ipc/tooltip.js +1 -1
  15. package/dist/main/ipc/views.d.ts +15 -1
  16. package/dist/main/ipc/views.js +61 -4
  17. package/dist/main/runtime/miniapp-runtime.d.ts +87 -19
  18. package/dist/main/services/notifications/renderer-notifier.d.ts +30 -1
  19. package/dist/main/services/notifications/renderer-notifier.js +23 -1
  20. package/dist/main/services/projects/project-repository.d.ts +4 -1
  21. package/dist/main/services/projects/project-repository.js +63 -5
  22. package/dist/main/services/update/update-manager.d.ts +17 -3
  23. package/dist/main/services/update/update-manager.js +25 -6
  24. package/dist/main/services/views/host-dialog-port-channel.d.ts +18 -0
  25. package/dist/main/services/views/host-dialog-port-channel.js +15 -0
  26. package/dist/main/services/views/host-dialog-session-runtime.d.ts +10 -0
  27. package/dist/main/services/views/host-dialog-session-runtime.js +17 -0
  28. package/dist/main/services/views/host-dialog-view.d.ts +95 -0
  29. package/dist/main/services/views/host-dialog-view.js +147 -0
  30. package/dist/main/services/views/host-sidebar-port-channel.d.ts +18 -0
  31. package/dist/main/services/views/host-sidebar-port-channel.js +15 -0
  32. package/dist/main/services/views/host-sidebar-session-runtime.d.ts +10 -0
  33. package/dist/main/services/views/host-sidebar-session-runtime.js +17 -0
  34. package/dist/main/services/views/host-sidebar-view.d.ts +59 -0
  35. package/dist/main/services/views/host-sidebar-view.js +44 -0
  36. package/dist/main/services/views/host-slot-port-channel.d.ts +107 -0
  37. package/dist/main/services/views/host-slot-port-channel.js +261 -0
  38. package/dist/main/services/views/host-slot-session-runtime.d.ts +40 -0
  39. package/dist/main/services/views/host-slot-session-runtime.js +50 -0
  40. package/dist/main/services/views/host-slot-view.d.ts +109 -0
  41. package/dist/main/services/views/host-slot-view.js +147 -0
  42. package/dist/main/services/views/host-toolbar-port-channel.d.ts +6 -91
  43. package/dist/main/services/views/host-toolbar-port-channel.js +10 -243
  44. package/dist/main/services/views/host-toolbar-session-runtime.d.ts +5 -30
  45. package/dist/main/services/views/host-toolbar-session-runtime.js +9 -47
  46. package/dist/main/services/views/host-toolbar-view.d.ts +34 -7
  47. package/dist/main/services/views/host-toolbar-view.js +30 -224
  48. package/dist/main/services/views/managed-web-contents-view.d.ts +48 -0
  49. package/dist/main/services/views/managed-web-contents-view.js +123 -0
  50. package/dist/main/services/views/overlay-panels-view.d.ts +23 -0
  51. package/dist/main/services/views/overlay-panels-view.js +93 -4
  52. package/dist/main/services/views/placement-reconciler.d.ts +14 -2
  53. package/dist/main/services/views/placement-reconciler.js +27 -0
  54. package/dist/main/services/views/placement-test-driver.d.ts +1 -0
  55. package/dist/main/services/views/placement-test-driver.js +3 -0
  56. package/dist/main/services/views/view-manager-devtools-host-test-fixtures.js +3 -1
  57. package/dist/main/services/views/view-manager.d.ts +10 -78
  58. package/dist/main/services/views/view-manager.js +34 -3
  59. package/dist/main/utils/paths.d.ts +4 -0
  60. package/dist/main/utils/paths.js +4 -0
  61. package/dist/main/utils/sender-policy.js +10 -0
  62. package/dist/native-host/common/common.js +65 -62
  63. package/dist/native-host/render/render.js +2230 -2052
  64. package/dist/native-host/service/service.js +2 -2
  65. package/dist/preload/runtime/host-dialog-advertiser.d.ts +22 -0
  66. package/dist/preload/runtime/host-dialog-advertiser.js +37 -0
  67. package/dist/preload/runtime/host-dialog-port.d.ts +44 -0
  68. package/dist/preload/runtime/host-dialog-port.js +53 -0
  69. package/dist/preload/runtime/host-dialog-runtime.d.ts +28 -0
  70. package/dist/preload/runtime/host-dialog-runtime.js +36 -0
  71. package/dist/preload/runtime/host-sidebar-advertiser.d.ts +19 -0
  72. package/dist/preload/runtime/host-sidebar-advertiser.js +35 -0
  73. package/dist/preload/runtime/host-sidebar-port.d.ts +44 -0
  74. package/dist/preload/runtime/host-sidebar-port.js +53 -0
  75. package/dist/preload/runtime/host-sidebar-runtime.d.ts +28 -0
  76. package/dist/preload/runtime/host-sidebar-runtime.js +36 -0
  77. package/dist/preload/runtime/host-slot-port-bridge.d.ts +18 -0
  78. package/dist/preload/runtime/host-slot-port-bridge.js +112 -0
  79. package/dist/preload/runtime/host-toolbar-advertiser.d.ts +5 -13
  80. package/dist/preload/runtime/host-toolbar-advertiser.js +18 -38
  81. package/dist/preload/runtime/host-toolbar-port.d.ts +9 -0
  82. package/dist/preload/runtime/host-toolbar-port.js +11 -95
  83. package/dist/preload/runtime/wait-for-slot-root.d.ts +20 -0
  84. package/dist/preload/runtime/wait-for-slot-root.js +52 -0
  85. package/dist/preload/windows/host-dialog-runtime.cjs +353 -0
  86. package/dist/preload/windows/host-dialog-runtime.cjs.map +7 -0
  87. package/dist/preload/windows/host-dialog-runtime.d.ts +2 -0
  88. package/dist/preload/windows/host-dialog-runtime.js +13 -0
  89. package/dist/preload/windows/host-sidebar-runtime.cjs +354 -0
  90. package/dist/preload/windows/host-sidebar-runtime.cjs.map +7 -0
  91. package/dist/preload/windows/host-sidebar-runtime.d.ts +2 -0
  92. package/dist/preload/windows/host-sidebar-runtime.js +13 -0
  93. package/dist/preload/windows/host-toolbar-runtime.cjs +134 -51
  94. package/dist/preload/windows/host-toolbar-runtime.cjs.map +3 -3
  95. package/dist/preload/windows/simulator.cjs.map +1 -1
  96. package/dist/renderer/assets/button-DsNqZm7o.js +2 -0
  97. package/dist/renderer/assets/constants-D7DfVqMp.js +2 -0
  98. package/dist/renderer/assets/constants-D8zsejFq.js +2 -0
  99. package/dist/renderer/assets/createLucideIcon-CYJeT1ji.js +2 -0
  100. package/dist/renderer/assets/dialog-pT4qWmka.js +46 -0
  101. package/dist/renderer/assets/dist-o70xmpc1.js +2 -0
  102. package/dist/renderer/assets/hostSidebarDefault-NvGZlE9O.js +2 -0
  103. package/dist/renderer/assets/index-zErhG3ta.js +5 -0
  104. package/dist/renderer/assets/input-4QxTXMZN.js +2 -0
  105. package/dist/renderer/assets/ipc-channels-overlays-Blr5TNoB.js +2 -0
  106. package/dist/renderer/assets/jsx-runtime-B-3rq1y5.css +1 -0
  107. package/dist/renderer/assets/jsx-runtime-CqVdW3eg.js +9 -0
  108. package/dist/renderer/assets/popover-CJiSWwuE.js +2 -0
  109. package/dist/renderer/assets/project-api-DZ1Zi6EC.js +2 -0
  110. package/dist/renderer/assets/projectCreateDialog-DMWNhw_1.js +2 -0
  111. package/dist/renderer/assets/select-C86pNcsu.js +2 -0
  112. package/dist/renderer/assets/settings-BoI8mLT1.js +2 -0
  113. package/dist/renderer/assets/settings-api-Bs_g4NHs.js +2 -0
  114. package/dist/renderer/assets/settings-tab-bar-DHLLygqv.js +2 -0
  115. package/dist/renderer/assets/tooltip-BhAyY0T4.js +2 -0
  116. package/dist/renderer/assets/types-YYjkvane.js +2 -0
  117. package/dist/renderer/assets/updateDialog-DPum3wx1.js +2 -0
  118. package/dist/renderer/assets/utils-kfQov6Pa.js +2 -0
  119. package/dist/renderer/assets/view-api-DFhb2R8-.js +2 -0
  120. package/dist/renderer/assets/{workbenchSettings-oq_EyfKf.js → workbenchSettings-DrajRQUk.js} +3 -3
  121. package/dist/renderer/entries/host-sidebar-default/index.html +21 -0
  122. package/dist/renderer/entries/main/index.html +15 -8
  123. package/dist/renderer/entries/popover/index.html +10 -7
  124. package/dist/renderer/entries/project-create-dialog/index.html +27 -0
  125. package/dist/renderer/entries/settings/index.html +10 -7
  126. package/dist/renderer/entries/tooltip/index.html +5 -4
  127. package/dist/renderer/entries/update-dialog/index.html +25 -0
  128. package/dist/renderer/entries/workbench-settings/index.html +11 -7
  129. package/dist/service-host/preload.cjs +10 -0
  130. package/dist/shared/constants.d.ts +22 -0
  131. package/dist/shared/constants.js +22 -0
  132. package/dist/shared/ipc-channels-overlays.d.ts +156 -0
  133. package/dist/shared/ipc-channels-overlays.js +186 -0
  134. package/dist/shared/ipc-channels.d.ts +0 -77
  135. package/dist/shared/ipc-channels.js +0 -98
  136. package/dist/shared/ipc-schemas.d.ts +33 -0
  137. package/dist/shared/ipc-schemas.js +41 -0
  138. package/dist/shared/types.d.ts +10 -0
  139. package/dist/shared/view-ids.d.ts +7 -0
  140. package/dist/shared/view-ids.js +10 -0
  141. package/package.json +8 -8
  142. package/dist/renderer/assets/constants-Bdz0LHdy.js +0 -2
  143. package/dist/renderer/assets/index-CtznrmHR.js +0 -49
  144. package/dist/renderer/assets/input-Dmm6nob5.js +0 -2
  145. package/dist/renderer/assets/ipc-transport-BOg0gR9W.js +0 -9
  146. package/dist/renderer/assets/ipc-transport-DgQhZaE9.css +0 -1
  147. package/dist/renderer/assets/popover-Cd1FEGOX.js +0 -2
  148. package/dist/renderer/assets/select-BaYox7If.js +0 -2
  149. package/dist/renderer/assets/settings-BXvwuFaz.js +0 -2
  150. package/dist/renderer/assets/settings-api-Bo9GbYqs.js +0 -2
  151. package/dist/renderer/assets/settings-tab-bar-Beia6lMr.js +0 -2
  152. package/dist/renderer/assets/tooltip-DfQqK3Sk.js +0 -2
  153. package/dist/renderer/assets/view-api-nn69je7A.js +0 -2
@@ -1,21 +1,48 @@
1
+ import type { HostSlotControl } from './host-slot-view.js';
1
2
  import type { PlacementReconciler } from './placement-reconciler.js';
2
- import type { HostToolbarControl, ViewManagerContext } from './view-manager.js';
3
+ import type { ViewManagerContext } from './view-manager.js';
3
4
  /**
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.
5
+ * Height mode for the host-toolbar placeholder strip. `'auto'` (default): the
6
+ * session-resident advertiser's reports drive the height. `{ fixed }`: the
7
+ * host pins the height; advertiser reports are ignored until `'auto'` again.
8
8
  */
9
+ export type HostToolbarHeightMode = 'auto' | {
10
+ fixed: number;
11
+ };
12
+ /**
13
+ * The control object the downstream host uses to own the toolbar
14
+ * WebContentsView. Lazily backed by the view-manager's `hostToolbarView`.
15
+ * Derives the shared members (`loadURL`, `loadFile`, `webContents`, `hide`,
16
+ * `setPreloadPath`, `onMessage`, `onReady`, `send`) from `HostSlotControl` —
17
+ * see that interface for their contract, generalized from
18
+ * `window.diminaHostToolbar` to the axis-neutral "slot page" — and adds only
19
+ * `setHeightMode` in place of the base's `setExtentMode`.
20
+ */
21
+ export interface HostToolbarControl extends Omit<HostSlotControl, 'setExtentMode'> {
22
+ /**
23
+ * Pin or unpin the toolbar strip height. `{ fixed }` notifies the renderer
24
+ * placeholder with that height immediately (so a preload-less/static toolbar
25
+ * is visible without any advertiser report) and ignores subsequent advertiser
26
+ * reports. `'auto'` (default) re-enables advertiser-driven height starting
27
+ * from the NEXT report — it does not synthesize/replay a stale height.
28
+ */
29
+ setHeightMode(mode: HostToolbarHeightMode): void;
30
+ }
9
31
  export interface HostToolbarView {
10
32
  readonly control: HostToolbarControl;
11
33
  setHostToolbarHeight(extent: number): void;
12
34
  getHostToolbarHeight(): number;
13
35
  getHostToolbarWebContentsId(): number | null;
14
- /** Teardown for `disposeAll`: sweep the port, destroy the view, release the runtime ref. */
15
36
  dispose(): void;
16
37
  }
38
+ /**
39
+ * Toolbar-specific instantiation of `createHostSlotView` (see that module for
40
+ * the full lazy-create / port-channel / extent-mode contract). Kept as its own
41
+ * named wrapper — not inlined into `view-manager.ts` — to freeze the existing
42
+ * `HostToolbarControl`/`HostToolbarHeightMode` public surface independently of
43
+ * the generic slot's neutral naming.
44
+ */
17
45
  export declare function createHostToolbarView(ctx: ViewManagerContext, reconciler: PlacementReconciler, deps: {
18
- /** Re-apply the settings/popover overlays whose height depends on the toolbar strip. */
19
46
  reapplyPresentOverlays(): void;
20
47
  }): HostToolbarView;
21
48
  //# sourceMappingURL=host-toolbar-view.d.ts.map
@@ -1,236 +1,42 @@
1
- import { WebContentsView } from 'electron';
2
- import { handleWindowOpenExternal } from '../../windows/navigation-hardening.js';
3
1
  import { HOST_TOOLBAR_RUNTIME_MARKER } from '../../../shared/constants.js';
4
2
  import { VIEW_ID, VIEW_LAYER } from '../../../shared/view-ids.js';
5
3
  import { acquireHostToolbarSessionRuntime, releaseHostToolbarSessionRuntime, } from './host-toolbar-session-runtime.js';
6
4
  import { createHostToolbarPortChannel } from './host-toolbar-port-channel.js';
5
+ import { createHostSlotView, deriveSlotControl } from './host-slot-view.js';
6
+ /**
7
+ * Toolbar-specific instantiation of `createHostSlotView` (see that module for
8
+ * the full lazy-create / port-channel / extent-mode contract). Kept as its own
9
+ * named wrapper — not inlined into `view-manager.ts` — to freeze the existing
10
+ * `HostToolbarControl`/`HostToolbarHeightMode` public surface independently of
11
+ * the generic slot's neutral naming.
12
+ */
7
13
  export function createHostToolbarView(ctx, reconciler, deps) {
8
- let hostToolbarView = null;
9
- let hostToolbarPreloadOverride = null;
10
- // Whether THIS manager holds a reference on the shared defaultSession
11
- // registration of the toolbar-runtime preload (see
12
- // host-toolbar-session-runtime.ts). Acquired on first toolbar need,
13
- // released exactly once in dispose — a manager that never used the
14
- // toolbar must not decrement a ref it never took.
15
- let hostToolbarRuntimeAcquired = false;
16
- // Placeholder height authority: 'auto' = advertiser reports forward to the
17
- // renderer; { fixed } = host-pinned, advertiser reports are dropped.
18
- let hostToolbarHeightMode = 'auto';
19
- // Last toolbar height NOTIFIED to the main-window renderer — the replay
20
- // source behind `getHostToolbarHeight()`. Updated ONLY inside
21
- // `notifyHostToolbarHeight` so the retained value can never diverge from
22
- // what the renderer was told (an advertiser report dropped by a `{ fixed }`
23
- // pin must not pollute it, and a setHeightMode validation reject leaves it
24
- // untouched).
25
- let hostToolbarLastHeight = 0;
26
- // Gated narrow channel to the toolbar PAGE (per-load MessagePort handshake;
27
- // see host-toolbar-port-channel.ts). Control-level registry — created with
28
- // the manager so onMessage() works before any toolbar view exists.
29
- const hostToolbarPort = createHostToolbarPortChannel({
30
- isCurrent: (wc) => liveHostToolbarWebContents() === wc,
14
+ const port = createHostToolbarPortChannel({
15
+ isCurrent: (wc) => slot.getWebContentsId() === wc.id,
31
16
  });
32
- // The toolbar's webContents lifecycle belongs to the HOST, which may close
33
- // it out from under us (the documented rebuild path). In real Electron a
34
- // WebContentsView whose webContents was destroyed can report `webContents`
35
- // as undefined — not merely a destroyed handle — so every access must
36
- // tolerate BOTH (observed in the R1 e2e: `.isDestroyed()` on undefined threw
37
- // inside the control surface after the host closed the wc).
38
- function liveHostToolbarWebContents() {
39
- const wc = hostToolbarView?.webContents;
40
- if (!wc || wc.isDestroyed())
41
- return null;
42
- return wc;
43
- }
44
- // Lazily create the host-toolbar view. Mirrors `showSettings` for the
45
- // webPreferences shape and the native simulator for nav hardening +
46
- // background color (the host may load arbitrary URLs / content). Idempotent.
47
- function ensureHostToolbarView() {
48
- if (hostToolbarView && liveHostToolbarWebContents()) {
49
- return hostToolbarView;
50
- }
51
- // Rebuilding after the host destroyed the underlying webContents first
52
- // retires the concrete instance from the native-tree ledger.
53
- if (hostToolbarView) {
54
- reconciler.destroyView(VIEW_ID.hostToolbar, hostToolbarView);
55
- }
56
- // The framework's height-advertiser runtime is SESSION-resident: register
57
- // it on session.defaultSession (ref-counted across coexisting managers)
58
- // BEFORE the view exists, so the very first load already runs it. The
59
- // toolbar WCV stays on the defaultSession (no partition/session override)
60
- // — moving it onto its own partition would silently detach it from this
61
- // registration and height advertising would die with no error.
62
- if (!hostToolbarRuntimeAcquired) {
63
- acquireHostToolbarSessionRuntime();
64
- hostToolbarRuntimeAcquired = true;
65
- }
66
- // `webPreferences.preload` is the HOST's alone (setPreloadPath); the
67
- // built-in advertiser no longer rides it (it would execute twice — the
68
- // session copy + the webPreferences copy). The additionalArguments marker
69
- // is what the session runtime's guard keys on to activate here and stay a
70
- // zero-footprint no-op in every other defaultSession renderer.
71
- const webPreferences = {
72
- nodeIntegration: false,
73
- contextIsolation: true,
74
- sandbox: false,
75
- additionalArguments: [HOST_TOOLBAR_RUNTIME_MARKER],
76
- };
77
- if (hostToolbarPreloadOverride !== null) {
78
- webPreferences.preload = hostToolbarPreloadOverride;
79
- }
80
- const view = new WebContentsView({ webPreferences });
81
- hostToolbarView = view;
82
- // Hook the per-load MessagePort handshake (did-finish-load) + dead-port
83
- // cleanup (destroyed) on the fresh wc. AFTER the assignment above so the
84
- // channel's isCurrent guard sees this wc as the live one.
85
- hostToolbarPort.attach(view.webContents);
86
- // Paint the surface a neutral color so growing the reserved strip never
87
- // flashes white before the host content paints (mirrors the native
88
- // simulator's setBackgroundColor anti-flash).
89
- try {
90
- view.setBackgroundColor('#121212');
91
- }
92
- catch { /* stub may lack it */ }
93
- // The host may load arbitrary URLs; route popups + cross-origin in-place
94
- // navigation to the OS browser (mirror the native simulator hardening).
95
- try {
96
- view.webContents.setWindowOpenHandler(({ url }) => handleWindowOpenExternal(url));
97
- }
98
- catch { /* stub may lack it */ }
99
- return view;
100
- }
101
- // Single funnel for the height notify: retain-then-push, so the retained
102
- // value is exactly the last value the renderer was told. Every height
103
- // notify site MUST go through here — the renderer pulls the retained value
104
- // on project-view mount to replay a push it missed (the toolbar's
105
- // size-advertiser deduplicates and never re-reports).
106
- function notifyHostToolbarHeight(height) {
107
- hostToolbarLastHeight = height;
108
- ctx.notify.hostToolbarHeightChanged(height);
109
- deps.reapplyPresentOverlays();
110
- }
111
- function setHostToolbarHeight(extent) {
112
- // While the host pins a fixed height, drop advertiser reports entirely —
113
- // the session-resident advertiser is always installed, so forwarding its
114
- // reports would make the strip oscillate between the pinned and measured
115
- // heights on every content resize. Dropped reports must not touch the
116
- // retained value either: retention records what was NOTIFIED, not what
117
- // was reported.
118
- if (hostToolbarHeightMode !== 'auto')
119
- return;
120
- // Push the reserved height back to the main-window renderer so its
121
- // placeholder div resizes (closing the dynamic-height loop). The notified
122
- // height IS retained in main (`getHostToolbarHeight`) so a renderer that
123
- // mounts later can pull/replay it; the renderer placeholder remains the
124
- // geometry authority — the forward anchor re-reports bounds from it.
125
- notifyHostToolbarHeight(extent);
126
- }
127
- function hideHostToolbar() {
128
- reconciler.setBaseDesired(VIEW_ID.hostToolbar, {
129
- viewId: VIEW_ID.hostToolbar,
130
- placement: { visible: false },
131
- layer: VIEW_LAYER.hostToolbar,
132
- });
133
- reconciler.reconcileNow();
134
- // Collapse the renderer placeholder to 0 too. Otherwise its anchor keeps a
135
- // non-zero reserved height and re-publishes bounds on the next window
136
- // resize, silently re-adding the view we just hid (unstable hide). Zeroing
137
- // the height flips the anchor to `present:false` so it stops re-publishing.
138
- // Through the funnel so the retained value follows to 0 — a renderer
139
- // mounting after the hide must replay 0, not the stale pre-hide height.
140
- notifyHostToolbarHeight(0);
141
- }
142
- const control = {
143
- async loadURL(url) {
144
- const view = ensureHostToolbarView();
145
- // Invalidate SYNCHRONOUSLY at initiation, before the load is issued:
146
- // the current document is about to be replaced, so a same-tick send()
147
- // must report false instead of confirming delivery into it. The channel
148
- // recovers on the new document's did-finish-load handshake. (Cannot
149
- // rely on did-start-navigation here — that only covers page-initiated
150
- // navigations once the load is actually under way.)
151
- hostToolbarPort.invalidate();
152
- await view.webContents.loadURL(url);
153
- },
154
- async loadFile(filePath) {
155
- const view = ensureHostToolbarView();
156
- // Same initiation-invalidates contract as loadURL above.
157
- hostToolbarPort.invalidate();
158
- await view.webContents.loadFile(filePath);
159
- },
160
- get webContents() {
161
- return liveHostToolbarWebContents();
162
- },
163
- hide() {
164
- hideHostToolbar();
165
- },
166
- setPreloadPath(path) {
167
- // The HOST's own webPreferences.preload, applied when the view is next
168
- // (re)created. `null` = no host preload. The framework advertiser is
169
- // session-resident and unaffected either way (see ensureHostToolbarView).
170
- hostToolbarPreloadOverride = path;
171
- },
172
- setHeightMode(mode) {
173
- // Validate BEFORE touching any state: a poisoned `{ fixed }` (NaN /
174
- // ±Infinity / negative) must neither reach the renderer placeholder
175
- // (`height: NaNpx` corrupts the strip with no error anywhere) nor
176
- // clobber the standing mode — fail-closed, not fail-corrupt.
177
- if (mode !== 'auto' && !(Number.isFinite(mode.fixed) && mode.fixed >= 0)) {
178
- throw new TypeError(`hostToolbar.setHeightMode: fixed height must be a finite, non-negative number (got ${mode.fixed})`);
179
- }
180
- hostToolbarHeightMode = mode;
181
- if (mode !== 'auto') {
182
- // Pin immediately: a preload-less/static toolbar never advertises, so
183
- // waiting for the next report would leave the strip at height 0.
184
- notifyHostToolbarHeight(mode.fixed);
185
- }
186
- // Switching back to 'auto' deliberately does NOT synthesize a notify —
187
- // replaying a stale cached height would flash the old size; the NEXT
188
- // advertiser report drives the placeholder again. The RETAINED value
189
- // survives the switch though: a freshly-mounting renderer still needs
190
- // the pinned height until that next report lands.
191
- },
192
- onMessage(channel, handler) {
193
- return hostToolbarPort.onMessage(channel, handler);
194
- },
195
- onReady(handler) {
196
- return hostToolbarPort.onReady(handler);
197
- },
198
- send(channel, payload) {
199
- return hostToolbarPort.send(channel, payload);
200
- },
201
- };
202
- reconciler.registerView(VIEW_ID.hostToolbar, {
203
- getView: () => hostToolbarView,
204
- ensureView: () => ensureHostToolbarView(),
205
- ensureLazy: (desired) => {
206
- if (desired?.placement.visible && !liveHostToolbarWebContents())
207
- ensureHostToolbarView();
208
- },
17
+ const slot = createHostSlotView(reconciler, {
18
+ viewId: VIEW_ID.hostToolbar,
19
+ layer: VIEW_LAYER.hostToolbar,
20
+ marker: HOST_TOOLBAR_RUNTIME_MARKER,
21
+ sessionRuntime: {
22
+ acquire: acquireHostToolbarSessionRuntime,
23
+ release: releaseHostToolbarSessionRuntime,
24
+ },
25
+ portChannel: port,
26
+ setExtentModeErrorLabel: 'hostToolbar.setHeightMode',
27
+ }, {
28
+ onExtentChanged: (height) => ctx.notify.hostToolbarHeightChanged(height),
29
+ reapplyPresentOverlays: () => deps.reapplyPresentOverlays(),
30
+ });
31
+ const control = deriveSlotControl(slot.control, {
32
+ setHeightMode: (mode) => slot.control.setExtentMode(mode),
209
33
  });
210
- function dispose() {
211
- // Narrow channel first: close the live MessagePort + sweep the onMessage
212
- // registry, so a send() racing teardown reports false instead of posting
213
- // into a wc that is about to be closed.
214
- hostToolbarPort.dispose();
215
- // Host-controllable toolbar view: removed from the contentView + its
216
- // WebContents closed (the host's loaded content is torn down on app exit).
217
- reconciler.destroyView(VIEW_ID.hostToolbar, hostToolbarView);
218
- hostToolbarView = null;
219
- // Release this manager's reference on the shared defaultSession
220
- // toolbar-runtime registration (only if it ever acquired one — a manager
221
- // that never used the toolbar must not drive the shared count to zero).
222
- // The LAST release unregisters; other coexisting managers keep theirs.
223
- if (hostToolbarRuntimeAcquired) {
224
- releaseHostToolbarSessionRuntime();
225
- hostToolbarRuntimeAcquired = false;
226
- }
227
- }
228
34
  return {
229
35
  control,
230
- setHostToolbarHeight,
231
- getHostToolbarHeight: () => hostToolbarLastHeight,
232
- getHostToolbarWebContentsId: () => liveHostToolbarWebContents()?.id ?? null,
233
- dispose,
36
+ setHostToolbarHeight: (extent) => slot.setExtent(extent),
37
+ getHostToolbarHeight: () => slot.getExtent(),
38
+ getHostToolbarWebContentsId: () => slot.getWebContentsId(),
39
+ dispose: () => slot.dispose(),
234
40
  };
235
41
  }
236
42
  //# sourceMappingURL=host-toolbar-view.js.map
@@ -0,0 +1,48 @@
1
+ import type { WebContents } from 'electron';
2
+ import { WebContentsView } from 'electron';
3
+ import type { PlacementReconciler } from './placement-reconciler.js';
4
+ import type { HostSlotPortChannel } from './host-slot-port-channel.js';
5
+ export interface ManagedWebContentsViewOptions {
6
+ reconciler: PlacementReconciler;
7
+ viewId: string;
8
+ /** `--dimina-host-*` marker passed as `additionalArguments`, self-guards the session-resident advertiser preload. */
9
+ marker: string;
10
+ sessionRuntime: {
11
+ acquire(): void;
12
+ release(): void;
13
+ };
14
+ /** The per-load handshake channel; shares this view's lazy-create/liveness/dispose lifecycle. */
15
+ port: HostSlotPortChannel;
16
+ /**
17
+ * Fires after a crashed/failed view has been torn down (see `ensureView`'s
18
+ * `render-process-gone`/`did-fail-load` handling below). The base slots
19
+ * (host-toolbar/host-sidebar) don't need this — their `ensureLazy` already
20
+ * rebuilds a fresh view on the next reconcile pass once `liveWebContents()`
21
+ * correctly reports the crash. host-dialog does: its on-demand placement
22
+ * (`visible` flag, `overlayDesired`) isn't reconciler-driven the same way,
23
+ * so without this a stale `visible: true` would resurrect a blank,
24
+ * content-less modal on the next reposition (e.g. a window resize).
25
+ */
26
+ onBroken?(): void;
27
+ }
28
+ /**
29
+ * Shared lazy-create / liveness / load / teardown lifecycle for the
30
+ * host-controllable WebContentsViews (host-toolbar, host-sidebar,
31
+ * host-dialog): a single `WebContentsView` recreated on demand when the
32
+ * previous one dies, backed by a ref-counted session-runtime registration and
33
+ * the per-load port-channel attach. Placement (persistent strip vs by-demand
34
+ * centered overlay) is layered on top by the caller — this module only owns
35
+ * "is there a live view, and (re)create/load/tear it down when needed."
36
+ */
37
+ export interface ManagedWebContentsView {
38
+ loadURL(url: string): Promise<void>;
39
+ loadFile(filePath: string): Promise<void>;
40
+ liveWebContents(): WebContents | null;
41
+ /** Raw view accessor for `reconciler.registerView`'s `getView` slot (may be non-null with a destroyed webContents). */
42
+ getView(): WebContentsView | null;
43
+ setPreloadPath(path: string | null): void;
44
+ ensureView(): WebContentsView;
45
+ dispose(): void;
46
+ }
47
+ export declare function createManagedWebContentsView(opts: ManagedWebContentsViewOptions): ManagedWebContentsView;
48
+ //# sourceMappingURL=managed-web-contents-view.d.ts.map
@@ -0,0 +1,123 @@
1
+ import { WebContentsView } from 'electron';
2
+ import { handleWindowOpenExternal } from '../../windows/navigation-hardening.js';
3
+ export function createManagedWebContentsView(opts) {
4
+ let view = null;
5
+ let preloadOverride = null;
6
+ let runtimeAcquired = false;
7
+ function liveWebContents() {
8
+ const wc = view?.webContents;
9
+ if (!wc || wc.isDestroyed())
10
+ return null;
11
+ return wc;
12
+ }
13
+ // `liveWebContents()`'s `!wc.isDestroyed()` alone cannot tell "alive" from
14
+ // "alive but broken" — a crashed renderer process or a failed main-frame
15
+ // load leaves `webContents` non-destroyed but blank/unresponsive, so
16
+ // without this the same dead view (still fielding clicks if it's an
17
+ // on-screen slot) would be handed back to every future `ensureView()`
18
+ // forever, and the host's own `webContents` getter would keep reporting it
19
+ // as live. Guarded by `view !== current` so a listener from an already-
20
+ // superseded instance can't tear down the CURRENT one.
21
+ function teardown(current, detail) {
22
+ if (view !== current)
23
+ return;
24
+ console.error(`[${opts.viewId}] ${detail} — destroying so the next ensureView() rebuilds`);
25
+ view = null;
26
+ opts.reconciler.destroyView(opts.viewId, current);
27
+ opts.onBroken?.();
28
+ }
29
+ function ensureView() {
30
+ if (view && liveWebContents()) {
31
+ return view;
32
+ }
33
+ if (view) {
34
+ opts.reconciler.destroyView(opts.viewId, view);
35
+ }
36
+ if (!runtimeAcquired) {
37
+ opts.sessionRuntime.acquire();
38
+ runtimeAcquired = true;
39
+ }
40
+ const webPreferences = {
41
+ nodeIntegration: false,
42
+ contextIsolation: true,
43
+ sandbox: false,
44
+ additionalArguments: [opts.marker],
45
+ };
46
+ if (preloadOverride !== null) {
47
+ webPreferences.preload = preloadOverride;
48
+ }
49
+ const next = new WebContentsView({ webPreferences });
50
+ view = next;
51
+ opts.port.attach(next.webContents);
52
+ try {
53
+ next.setBackgroundColor('#121212');
54
+ }
55
+ catch {
56
+ /* stub may lack it */
57
+ }
58
+ try {
59
+ next.webContents.setWindowOpenHandler(({ url }) => handleWindowOpenExternal(url));
60
+ }
61
+ catch {
62
+ /* stub may lack it */
63
+ }
64
+ next.webContents.on('did-fail-load', (_event, errorCode, _errorDescription, _validatedURL, isMainFrame) => {
65
+ // -3 is ERR_ABORTED, which fires on every routine superseded navigation
66
+ // (e.g. a fresh loadURL/loadFile cancelling this one) — not a real failure.
67
+ if (!isMainFrame || errorCode === -3)
68
+ return;
69
+ teardown(next, `did-fail-load (code ${errorCode})`);
70
+ });
71
+ next.webContents.on('render-process-gone', (_event, details) => {
72
+ teardown(next, `render-process-gone (${details.reason})`);
73
+ });
74
+ return next;
75
+ }
76
+ return {
77
+ async loadURL(url) {
78
+ const v = ensureView();
79
+ // Invalidate SYNCHRONOUSLY at initiation, before the load is issued:
80
+ // the current document is about to be replaced, so a same-tick send()
81
+ // must report false instead of confirming delivery into it. The channel
82
+ // recovers on the new document's did-finish-load handshake. (Cannot
83
+ // rely on did-start-navigation here — that only covers page-initiated
84
+ // navigations once the load is actually under way.)
85
+ opts.port.invalidate();
86
+ await v.webContents.loadURL(url);
87
+ },
88
+ async loadFile(filePath) {
89
+ const v = ensureView();
90
+ // Same initiation-invalidates contract as loadURL above.
91
+ opts.port.invalidate();
92
+ await v.webContents.loadFile(filePath);
93
+ },
94
+ liveWebContents,
95
+ getView: () => view,
96
+ setPreloadPath(path) {
97
+ // The HOST's own webPreferences.preload, applied when the view is next
98
+ // (re)created. `null` = no host preload. The framework advertiser is
99
+ // session-resident and unaffected either way (see ensureView).
100
+ preloadOverride = path;
101
+ },
102
+ ensureView,
103
+ dispose() {
104
+ // Narrow channel first: close the live MessagePort + sweep the onMessage
105
+ // registry, so a send() racing teardown reports false instead of posting
106
+ // into a wc that is about to be closed.
107
+ opts.port.dispose();
108
+ // Host-controllable slot view: removed from the contentView + its
109
+ // WebContents closed (the host's loaded content is torn down on app exit).
110
+ opts.reconciler.destroyView(opts.viewId, view);
111
+ view = null;
112
+ // Release this manager's reference on the shared defaultSession
113
+ // slot-runtime registration (only if it ever acquired one — a manager
114
+ // that never used the slot must not drive the shared count to zero).
115
+ // The LAST release unregisters; other coexisting managers keep theirs.
116
+ if (runtimeAcquired) {
117
+ opts.sessionRuntime.release();
118
+ runtimeAcquired = false;
119
+ }
120
+ },
121
+ };
122
+ }
123
+ //# sourceMappingURL=managed-web-contents-view.js.map
@@ -1,4 +1,5 @@
1
1
  import type { WebContents } from 'electron';
2
+ import type { UpdateInfo } from '../../../shared/types.js';
2
3
  import type { PlacementReconciler } from './placement-reconciler.js';
3
4
  import type { ViewManagerContext } from './view-manager.js';
4
5
  export interface TooltipShowPayload {
@@ -10,6 +11,11 @@ export interface TooltipShowPayload {
10
11
  };
11
12
  text: string;
12
13
  }
14
+ /** Payload shown by the project-create-dialog overlay panel (`projectCreate:show`). */
15
+ export interface ProjectCreateShowPayload {
16
+ templates: unknown[];
17
+ defaultBaseDir: string;
18
+ }
13
19
  /**
14
20
  * The main-owned overlay panels: the settings sheet (right-side panel over a
15
21
  * transparent backdrop), the transient compile-mode popover, and the tooltip.
@@ -40,10 +46,27 @@ export interface OverlayPanelsView {
40
46
  applySettingsBoundsIfPresent(): void;
41
47
  /** Destroy the cached settings + tooltip views (aggregate simulator detach). */
42
48
  destroySettings(): void;
49
+ /** Destroy the project-create/update dialog panel views (app-level teardown). */
50
+ destroyDialogs(): void;
43
51
  getSettingsWebContents(): WebContents | null;
44
52
  getSettingsWebContentsId(): number | null;
45
53
  getPopoverWebContentsId(): number | null;
46
54
  getTooltipWebContentsId(): number | null;
55
+ /**
56
+ * Show the project-create-dialog overlay panel (VIEW_LAYER.dialog) — the
57
+ * real WebContentsView that replaced the Radix `fixed inset-0` DOM portal
58
+ * (see view-ids.ts's VIEW_LAYER doc-comment for why a DOM overlay can't
59
+ * paint above the simulator/host-toolbar/host-sidebar WCVs).
60
+ */
61
+ showProjectCreateDialog(data: ProjectCreateShowPayload): void;
62
+ hideProjectCreateDialog(): void;
63
+ /** Show the update-available overlay panel, fed the discovered update's info. */
64
+ showUpdateDialog(data: UpdateInfo): void;
65
+ hideUpdateDialog(): void;
66
+ /** Forward a download-progress tick into the (already-shown) update overlay. */
67
+ notifyUpdateDownloadProgress(percent: number): void;
68
+ getProjectCreateDialogWebContentsId(): number | null;
69
+ getUpdateDialogWebContentsId(): number | null;
47
70
  }
48
71
  export declare function createOverlayPanelsView(ctx: ViewManagerContext, reconciler: PlacementReconciler, deps: {
49
72
  /** The host-toolbar strip height that offsets the overlay top edge. */