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

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 (160) hide show
  1. package/dist/main/api.d.ts +1 -1
  2. package/dist/main/app/app.js +59 -2
  3. package/dist/main/index.bundle.js +986 -245
  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 +36 -1
  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/create-project-service.js +9 -2
  21. package/dist/main/services/projects/local-provider.js +6 -0
  22. package/dist/main/services/projects/project-repository.d.ts +29 -1
  23. package/dist/main/services/projects/project-repository.js +151 -17
  24. package/dist/main/services/projects/types.d.ts +13 -2
  25. package/dist/main/services/update/update-manager.d.ts +17 -3
  26. package/dist/main/services/update/update-manager.js +25 -6
  27. package/dist/main/services/views/host-dialog-port-channel.d.ts +18 -0
  28. package/dist/main/services/views/host-dialog-port-channel.js +15 -0
  29. package/dist/main/services/views/host-dialog-session-runtime.d.ts +10 -0
  30. package/dist/main/services/views/host-dialog-session-runtime.js +17 -0
  31. package/dist/main/services/views/host-dialog-view.d.ts +95 -0
  32. package/dist/main/services/views/host-dialog-view.js +147 -0
  33. package/dist/main/services/views/host-sidebar-port-channel.d.ts +18 -0
  34. package/dist/main/services/views/host-sidebar-port-channel.js +15 -0
  35. package/dist/main/services/views/host-sidebar-session-runtime.d.ts +10 -0
  36. package/dist/main/services/views/host-sidebar-session-runtime.js +17 -0
  37. package/dist/main/services/views/host-sidebar-view.d.ts +59 -0
  38. package/dist/main/services/views/host-sidebar-view.js +44 -0
  39. package/dist/main/services/views/host-slot-port-channel.d.ts +107 -0
  40. package/dist/main/services/views/host-slot-port-channel.js +261 -0
  41. package/dist/main/services/views/host-slot-session-runtime.d.ts +40 -0
  42. package/dist/main/services/views/host-slot-session-runtime.js +50 -0
  43. package/dist/main/services/views/host-slot-view.d.ts +109 -0
  44. package/dist/main/services/views/host-slot-view.js +147 -0
  45. package/dist/main/services/views/host-toolbar-port-channel.d.ts +6 -91
  46. package/dist/main/services/views/host-toolbar-port-channel.js +10 -243
  47. package/dist/main/services/views/host-toolbar-session-runtime.d.ts +5 -30
  48. package/dist/main/services/views/host-toolbar-session-runtime.js +9 -47
  49. package/dist/main/services/views/host-toolbar-view.d.ts +34 -7
  50. package/dist/main/services/views/host-toolbar-view.js +30 -224
  51. package/dist/main/services/views/managed-web-contents-view.d.ts +48 -0
  52. package/dist/main/services/views/managed-web-contents-view.js +123 -0
  53. package/dist/main/services/views/overlay-panels-view.d.ts +23 -0
  54. package/dist/main/services/views/overlay-panels-view.js +93 -4
  55. package/dist/main/services/views/placement-reconciler.d.ts +14 -2
  56. package/dist/main/services/views/placement-reconciler.js +27 -0
  57. package/dist/main/services/views/placement-test-driver.d.ts +1 -0
  58. package/dist/main/services/views/placement-test-driver.js +3 -0
  59. package/dist/main/services/views/view-manager-devtools-host-test-fixtures.js +3 -1
  60. package/dist/main/services/views/view-manager.d.ts +10 -78
  61. package/dist/main/services/views/view-manager.js +34 -3
  62. package/dist/main/services/workbench-context.d.ts +18 -4
  63. package/dist/main/services/workbench-context.js +1 -0
  64. package/dist/main/services/workspace/workspace-service.d.ts +2 -0
  65. package/dist/main/services/workspace/workspace-service.js +14 -0
  66. package/dist/main/utils/paths.d.ts +4 -0
  67. package/dist/main/utils/paths.js +4 -0
  68. package/dist/main/utils/sender-policy.js +10 -0
  69. package/dist/native-host/common/common.js +65 -62
  70. package/dist/native-host/render/render.js +2230 -2052
  71. package/dist/native-host/service/service.js +2 -2
  72. package/dist/preload/runtime/host-dialog-advertiser.d.ts +22 -0
  73. package/dist/preload/runtime/host-dialog-advertiser.js +37 -0
  74. package/dist/preload/runtime/host-dialog-port.d.ts +44 -0
  75. package/dist/preload/runtime/host-dialog-port.js +53 -0
  76. package/dist/preload/runtime/host-dialog-runtime.d.ts +28 -0
  77. package/dist/preload/runtime/host-dialog-runtime.js +36 -0
  78. package/dist/preload/runtime/host-sidebar-advertiser.d.ts +19 -0
  79. package/dist/preload/runtime/host-sidebar-advertiser.js +35 -0
  80. package/dist/preload/runtime/host-sidebar-port.d.ts +44 -0
  81. package/dist/preload/runtime/host-sidebar-port.js +53 -0
  82. package/dist/preload/runtime/host-sidebar-runtime.d.ts +28 -0
  83. package/dist/preload/runtime/host-sidebar-runtime.js +36 -0
  84. package/dist/preload/runtime/host-slot-port-bridge.d.ts +18 -0
  85. package/dist/preload/runtime/host-slot-port-bridge.js +112 -0
  86. package/dist/preload/runtime/host-toolbar-advertiser.d.ts +5 -13
  87. package/dist/preload/runtime/host-toolbar-advertiser.js +18 -38
  88. package/dist/preload/runtime/host-toolbar-port.d.ts +9 -0
  89. package/dist/preload/runtime/host-toolbar-port.js +11 -95
  90. package/dist/preload/runtime/wait-for-slot-root.d.ts +20 -0
  91. package/dist/preload/runtime/wait-for-slot-root.js +52 -0
  92. package/dist/preload/windows/host-dialog-runtime.cjs +353 -0
  93. package/dist/preload/windows/host-dialog-runtime.cjs.map +7 -0
  94. package/dist/preload/windows/host-dialog-runtime.d.ts +2 -0
  95. package/dist/preload/windows/host-dialog-runtime.js +13 -0
  96. package/dist/preload/windows/host-sidebar-runtime.cjs +354 -0
  97. package/dist/preload/windows/host-sidebar-runtime.cjs.map +7 -0
  98. package/dist/preload/windows/host-sidebar-runtime.d.ts +2 -0
  99. package/dist/preload/windows/host-sidebar-runtime.js +13 -0
  100. package/dist/preload/windows/host-toolbar-runtime.cjs +134 -51
  101. package/dist/preload/windows/host-toolbar-runtime.cjs.map +3 -3
  102. package/dist/preload/windows/simulator.cjs.map +1 -1
  103. package/dist/renderer/assets/button-D5Q2wkXq.js +2 -0
  104. package/dist/renderer/assets/constants-D7DfVqMp.js +2 -0
  105. package/dist/renderer/assets/constants-D8zsejFq.js +2 -0
  106. package/dist/renderer/assets/createLucideIcon-Bqi8hpdi.js +2 -0
  107. package/dist/renderer/assets/dialog-e1TecTOY.js +46 -0
  108. package/dist/renderer/assets/dist-DKWdE1TK.js +2 -0
  109. package/dist/renderer/assets/hostSidebarDefault-B3yLfy8j.js +2 -0
  110. package/dist/renderer/assets/index-CsPD68N_.js +5 -0
  111. package/dist/renderer/assets/input-Ct3alvkq.js +2 -0
  112. package/dist/renderer/assets/ipc-channels-overlays-LsDzGAtV.js +2 -0
  113. package/dist/renderer/assets/jsx-runtime-2vXHouwr.css +1 -0
  114. package/dist/renderer/assets/jsx-runtime-DGLHmmOq.js +9 -0
  115. package/dist/renderer/assets/popover-Dix5cm_b.js +2 -0
  116. package/dist/renderer/assets/project-api-k7Oq9iaq.js +2 -0
  117. package/dist/renderer/assets/projectCreateDialog-Bbjz75bP.js +2 -0
  118. package/dist/renderer/assets/select-acGb0AmJ.js +2 -0
  119. package/dist/renderer/assets/settings-CQrTMr43.js +2 -0
  120. package/dist/renderer/assets/settings-api-CrUQ9rYV.js +2 -0
  121. package/dist/renderer/assets/settings-tab-bar-Cw1kVIf2.js +2 -0
  122. package/dist/renderer/assets/tooltip-B_-_YVbw.js +2 -0
  123. package/dist/renderer/assets/types-CsEKtFyr.js +2 -0
  124. package/dist/renderer/assets/updateDialog-NsF8223A.js +2 -0
  125. package/dist/renderer/assets/utils-kfQov6Pa.js +2 -0
  126. package/dist/renderer/assets/view-api-CLn3rcQE.js +2 -0
  127. package/dist/renderer/assets/{workbenchSettings-oq_EyfKf.js → workbenchSettings-CV4LVA9b.js} +3 -3
  128. package/dist/renderer/entries/host-sidebar-default/index.html +21 -0
  129. package/dist/renderer/entries/main/index.html +17 -8
  130. package/dist/renderer/entries/popover/index.html +10 -7
  131. package/dist/renderer/entries/project-create-dialog/index.html +27 -0
  132. package/dist/renderer/entries/settings/index.html +10 -7
  133. package/dist/renderer/entries/tooltip/index.html +5 -4
  134. package/dist/renderer/entries/update-dialog/index.html +25 -0
  135. package/dist/renderer/entries/workbench-settings/index.html +11 -7
  136. package/dist/service-host/preload.cjs +10 -0
  137. package/dist/shared/constants.d.ts +22 -0
  138. package/dist/shared/constants.js +22 -0
  139. package/dist/shared/ipc-channels-overlays.d.ts +156 -0
  140. package/dist/shared/ipc-channels-overlays.js +186 -0
  141. package/dist/shared/ipc-channels.d.ts +4 -77
  142. package/dist/shared/ipc-channels.js +4 -98
  143. package/dist/shared/ipc-schemas.d.ts +44 -0
  144. package/dist/shared/ipc-schemas.js +55 -0
  145. package/dist/shared/types.d.ts +71 -0
  146. package/dist/shared/view-ids.d.ts +7 -0
  147. package/dist/shared/view-ids.js +10 -0
  148. package/package.json +8 -8
  149. package/dist/renderer/assets/constants-Bdz0LHdy.js +0 -2
  150. package/dist/renderer/assets/index-CtznrmHR.js +0 -49
  151. package/dist/renderer/assets/input-Dmm6nob5.js +0 -2
  152. package/dist/renderer/assets/ipc-transport-BOg0gR9W.js +0 -9
  153. package/dist/renderer/assets/ipc-transport-DgQhZaE9.css +0 -1
  154. package/dist/renderer/assets/popover-Cd1FEGOX.js +0 -2
  155. package/dist/renderer/assets/select-BaYox7If.js +0 -2
  156. package/dist/renderer/assets/settings-BXvwuFaz.js +0 -2
  157. package/dist/renderer/assets/settings-api-Bo9GbYqs.js +0 -2
  158. package/dist/renderer/assets/settings-tab-bar-Beia6lMr.js +0 -2
  159. package/dist/renderer/assets/tooltip-DfQqK3Sk.js +0 -2
  160. package/dist/renderer/assets/view-api-nn69je7A.js +0 -2
@@ -1,97 +1,12 @@
1
1
  /**
2
- * Gated narrow channel between the main process and the host-toolbar
3
- * WebContentsView's page, over a per-load transferred MessagePort.
4
- *
5
- * Why a MessagePort and not plain IPC: the toolbar page is HOST-ARBITRARY
6
- * content. A dedicated port pair gives it exactly one pipe whose main-side end
7
- * lives in this module — the page never gains a generic `ipcRenderer` reach
8
- * into the ~72 internal devtools channels, and main-side inbound traffic is
9
- * validated at this single waist.
10
- *
11
- * Lifecycle (per-load handshake):
12
- * - On every toolbar-wc `did-finish-load` main builds a fresh
13
- * `MessageChannelMain`, transfers port2 to the new document via
14
- * `wc.postMessage(ViewChannel.HostToolbarPort, null, [port2])`, keeps
15
- * port1 and `start()`s it. The previous port1 (if any) is closed first —
16
- * its document is gone.
17
- * - `onMessage` registrations are CONTROL-level (this module's registry), not
18
- * per-port: they may be made before any view exists and survive page
19
- * reloads / wc rebuilds, because each new handshake dispatches into the
20
- * same registry.
21
- * - `send` is gated and non-queueing: `false` means "not delivered, ever" —
22
- * no toolbar view is conjured, nothing is buffered for a later handshake.
23
- * - A port1 `'close'` event (the renderer end died without a re-handshake
24
- * yet) drops the live-port reference so `send` reports `false` instead of
25
- * posting into a dead pipe.
26
- * - NAVIGATION INVALIDATES THE PORT. The port pair belongs to one DOCUMENT,
27
- * so starting a navigation that replaces that document closes port1 and
28
- * `send` returns `false` until the new document's `did-finish-load`
29
- * handshake. Two paths:
30
- * (a) host-initiated `hostToolbar.loadURL/loadFile` calls `invalidate()`
31
- * synchronously AT INITIATION (view-manager does this before the
32
- * `webContents.loadURL/loadFile` await), so a same-tick `send` can
33
- * never report `true` for an envelope posted into the document the
34
- * load is about to replace;
35
- * (b) page-initiated navigation (location.href / reload) is caught by a
36
- * `did-start-navigation` listener — guarded to the ACTIVE wc,
37
- * main-frame, cross-document only. Same-document navigations
38
- * (anchors, pushState, history) and subframe navigations do NOT
39
- * invalidate: the document the port lives in survives those, and no
40
- * main-frame `did-finish-load` would follow to ever restore the
41
- * channel.
42
- *
43
- * Envelope both directions: `{ channel: string, payload: unknown }`. Inbound
44
- * data that is not an object with a string `channel` is DROPPED without
45
- * throwing (the counterpart is arbitrary host content).
2
+ * Toolbar-specific instantiation of `createHostSlotPortChannel` (see that
3
+ * module for the full per-load handshake / navigation-invalidation
4
+ * contract).
46
5
  */
47
6
  import type { WebContents } from 'electron';
48
- /** Handle returned by `onMessage`; `dispose()` detaches (idempotent). */
49
- export interface HostToolbarMessageSubscription {
50
- dispose(): void;
51
- }
52
- export interface HostToolbarPortChannel {
53
- /**
54
- * Hook a freshly created toolbar webContents: registers the
55
- * `did-finish-load` (per-load handshake) and `destroyed` (drop the live
56
- * port) listeners via `wc.on(...)`. Call exactly once per wc, right after
57
- * the view is created.
58
- */
59
- attach(wc: WebContents): void;
60
- /**
61
- * Drop the live port NOW (close + clear): the document it belongs to is
62
- * being replaced. Called by view-manager synchronously when the HOST
63
- * initiates a `loadURL`/`loadFile` — the host-initiated half of the
64
- * navigation-invalidates contract (the page-initiated half is the
65
- * `did-start-navigation` listener `attach` installs). `send` returns false
66
- * from this call until the next `did-finish-load` handshake. Idempotent.
67
- */
68
- invalidate(): void;
69
- /** Register a control-level inbound handler for `channel`. */
70
- onMessage(channel: string, handler: (payload: unknown) => void): HostToolbarMessageSubscription;
71
- /**
72
- * Observe handshake readiness. Fires `handler` once per load GENERATION,
73
- * at the moment that generation's handshake completes (`send` flips true).
74
- * Registering while already `ready` schedules a one-shot catch-up fire on a
75
- * microtask — never synchronously — and the catch-up RE-CHECKS at fire time
76
- * that (a) the subscription is still registered and (b) the generation is
77
- * unchanged / the port is still live, so a same-frame `dispose()` or
78
- * host-initiated load suppresses it. Inert (never fires) after `dispose()`.
79
- */
80
- onReady(handler: () => void): HostToolbarMessageSubscription;
81
- /**
82
- * Post `{ channel, payload }` to the toolbar page over the live port.
83
- * Returns false (delivering NOTHING, creating NOTHING) when there is no
84
- * live toolbar wc, the current load's handshake hasn't completed, or a
85
- * document-replacing navigation is in flight (see `invalidate`).
86
- */
87
- send(channel: string, payload: unknown): boolean;
88
- /**
89
- * Teardown (view-manager `disposeAll`): close the live port, sweep the
90
- * handler registry, refuse further handshakes. Subsequent `send` returns
91
- * false; late `dispose()` of an old subscription stays a no-op.
92
- */
93
- dispose(): void;
94
- }
7
+ import { type HostSlotMessageSubscription, type HostSlotPortChannel } from './host-slot-port-channel.js';
8
+ export type HostToolbarMessageSubscription = HostSlotMessageSubscription;
9
+ export type HostToolbarPortChannel = HostSlotPortChannel;
95
10
  export declare function createHostToolbarPortChannel(opts: {
96
11
  /**
97
12
  * Is `wc` still the manager's CURRENT live toolbar webContents? Guards a
@@ -1,248 +1,15 @@
1
1
  /**
2
- * Gated narrow channel between the main process and the host-toolbar
3
- * WebContentsView's page, over a per-load transferred MessagePort.
4
- *
5
- * Why a MessagePort and not plain IPC: the toolbar page is HOST-ARBITRARY
6
- * content. A dedicated port pair gives it exactly one pipe whose main-side end
7
- * lives in this module — the page never gains a generic `ipcRenderer` reach
8
- * into the ~72 internal devtools channels, and main-side inbound traffic is
9
- * validated at this single waist.
10
- *
11
- * Lifecycle (per-load handshake):
12
- * - On every toolbar-wc `did-finish-load` main builds a fresh
13
- * `MessageChannelMain`, transfers port2 to the new document via
14
- * `wc.postMessage(ViewChannel.HostToolbarPort, null, [port2])`, keeps
15
- * port1 and `start()`s it. The previous port1 (if any) is closed first —
16
- * its document is gone.
17
- * - `onMessage` registrations are CONTROL-level (this module's registry), not
18
- * per-port: they may be made before any view exists and survive page
19
- * reloads / wc rebuilds, because each new handshake dispatches into the
20
- * same registry.
21
- * - `send` is gated and non-queueing: `false` means "not delivered, ever" —
22
- * no toolbar view is conjured, nothing is buffered for a later handshake.
23
- * - A port1 `'close'` event (the renderer end died without a re-handshake
24
- * yet) drops the live-port reference so `send` reports `false` instead of
25
- * posting into a dead pipe.
26
- * - NAVIGATION INVALIDATES THE PORT. The port pair belongs to one DOCUMENT,
27
- * so starting a navigation that replaces that document closes port1 and
28
- * `send` returns `false` until the new document's `did-finish-load`
29
- * handshake. Two paths:
30
- * (a) host-initiated `hostToolbar.loadURL/loadFile` calls `invalidate()`
31
- * synchronously AT INITIATION (view-manager does this before the
32
- * `webContents.loadURL/loadFile` await), so a same-tick `send` can
33
- * never report `true` for an envelope posted into the document the
34
- * load is about to replace;
35
- * (b) page-initiated navigation (location.href / reload) is caught by a
36
- * `did-start-navigation` listener — guarded to the ACTIVE wc,
37
- * main-frame, cross-document only. Same-document navigations
38
- * (anchors, pushState, history) and subframe navigations do NOT
39
- * invalidate: the document the port lives in survives those, and no
40
- * main-frame `did-finish-load` would follow to ever restore the
41
- * channel.
42
- *
43
- * Envelope both directions: `{ channel: string, payload: unknown }`. Inbound
44
- * data that is not an object with a string `channel` is DROPPED without
45
- * throwing (the counterpart is arbitrary host content).
2
+ * Toolbar-specific instantiation of `createHostSlotPortChannel` (see that
3
+ * module for the full per-load handshake / navigation-invalidation
4
+ * contract).
46
5
  */
47
- import { MessageChannelMain } from 'electron';
48
- import { ViewChannel } from '../../../shared/ipc-channels.js';
6
+ import { ViewChannel } from '../../../shared/ipc-channels-overlays.js';
7
+ import { createHostSlotPortChannel, } from './host-slot-port-channel.js';
49
8
  export function createHostToolbarPortChannel(opts) {
50
- let activePort = null;
51
- /** The wc that owns `activePort` (so a stale wc's `destroyed` can't drop a successor's port). */
52
- let activeWc = null;
53
- /** Named lifecycle state. INVARIANT: `state === 'ready'` ⟺ `activePort !== null`. */
54
- let state = 'absent';
55
- /**
56
- * Monotonic per-handshake counter. Each completed handshake is one load
57
- * GENERATION; `onReady` catch-up fires capture it at registration and
58
- * re-check it at fire time so a fire scheduled for generation N can never
59
- * deliver after a navigation/handshake moved the channel past N.
60
- */
61
- let generation = 0;
62
- // Array (not Map<channel, Set>) so the same handler function may be
63
- // registered twice and each registration disposes independently.
64
- const handlers = [];
65
- // onReady registrations. Same array-of-entries discipline as `handlers`.
66
- const readyHandlers = [];
67
- function dispatch(data) {
68
- // Inbound waist: the toolbar page is host-arbitrary content — anything
69
- // that is not an object envelope with a string channel is dropped.
70
- if (typeof data !== 'object' || data === null)
71
- return;
72
- const { channel, payload } = data;
73
- if (typeof channel !== 'string')
74
- return;
75
- // Snapshot so a handler that (un)subscribes mid-dispatch can't skew iteration.
76
- for (const entry of [...handlers]) {
77
- if (entry.channel === channel)
78
- entry.handler(payload);
79
- }
80
- }
81
- /**
82
- * Drop the live port and transition to `next` (`'absent'` for death paths,
83
- * `'awaitingHandshake'` for navigation paths). Never demotes `disposed`.
84
- */
85
- function dropActivePort(close, next) {
86
- const port = activePort;
87
- activePort = null;
88
- activeWc = null;
89
- if (state !== 'disposed')
90
- state = next;
91
- if (close && port) {
92
- try {
93
- port.close();
94
- }
95
- catch {
96
- /* already closed */
97
- }
98
- }
99
- }
100
- /**
101
- * Invoke one onReady handler with exception ISOLATION: subscribers are
102
- * arbitrary control-level code — one throwing must neither starve sibling
103
- * registrations nor escape the surrounding event/microtask callback (a
104
- * throw out of a `did-finish-load` listener or a `queueMicrotask` body is
105
- * process-level `uncaughtException` territory). Report-and-continue.
106
- */
107
- function invokeReadyHandler(handler) {
108
- try {
109
- handler();
110
- }
111
- catch (err) {
112
- console.error('[host-toolbar] onReady handler threw:', err);
113
- }
114
- }
115
- /** Fire every still-registered onReady handler exactly once (snapshot iteration). */
116
- function fireReadyHandlers() {
117
- for (const entry of [...readyHandlers]) {
118
- // A handler may dispose a sibling registration mid-fire: re-check
119
- // membership so a disposed entry never fires. Per-handler isolation
120
- // (NOT around the loop): a throwing handler must not abort the fire
121
- // for later-registered siblings.
122
- if (readyHandlers.includes(entry))
123
- invokeReadyHandler(entry.handler);
124
- }
125
- }
126
- function handshake(wc) {
127
- if (state === 'disposed')
128
- return;
129
- if (!opts.isCurrent(wc))
130
- return;
131
- // The previous load's document is gone; its port goes with it.
132
- dropActivePort(true, 'awaitingHandshake');
133
- const { port1, port2 } = new MessageChannelMain();
134
- port1.on('message', (event) => {
135
- dispatch(event.data);
136
- });
137
- // Renderer end died without a re-handshake (page crash / wc close): drop
138
- // the reference so send() reports false instead of posting into the void.
139
- port1.on('close', () => {
140
- if (activePort === port1)
141
- dropActivePort(false, 'absent');
142
- });
143
- wc.postMessage(ViewChannel.HostToolbarPort, null, [port2]);
144
- port1.start();
145
- activePort = port1;
146
- activeWc = wc;
147
- state = 'ready';
148
- generation++;
149
- // Readiness signal AFTER the port is live: a handler calling send() from
150
- // inside its onReady fire must observe `true`.
151
- fireReadyHandlers();
152
- }
153
- return {
154
- attach(wc) {
155
- wc.on('did-finish-load', () => handshake(wc));
156
- // Page-initiated navigation (location.href / reload): the document the
157
- // port lives in is being replaced — invalidate so send() reports false
158
- // through the navigation window instead of confirming delivery into a
159
- // document being torn down. TRIPLE guard, because over-invalidating
160
- // mutes the channel FOREVER (no main-frame did-finish-load follows to
161
- // re-handshake):
162
- // - activeWc: a stale wc's late event must not drop a successor's port
163
- // (same discipline as the 'destroyed' handler below);
164
- // - cross-document only: anchors/pushState/history keep the document;
165
- // - main frame only: an <iframe> navigating keeps the main document.
166
- // Reads the details object (electron >= 12 shape); falls back to the
167
- // deprecated positional args (`isInPlace` === details.isSameDocument).
168
- wc.on('did-start-navigation', (details, _url, isInPlace, isMainFramePositional) => {
169
- if (activeWc !== wc)
170
- return;
171
- const isSameDocument = typeof details?.isSameDocument === 'boolean'
172
- ? details.isSameDocument
173
- : isInPlace;
174
- const isMainFrame = typeof details?.isMainFrame === 'boolean'
175
- ? details.isMainFrame
176
- : isMainFramePositional;
177
- if (isSameDocument || !isMainFrame)
178
- return;
179
- dropActivePort(true, 'awaitingHandshake');
180
- });
181
- wc.on('destroyed', () => {
182
- if (activeWc === wc)
183
- dropActivePort(true, 'absent');
184
- });
185
- },
186
- invalidate() {
187
- dropActivePort(true, 'awaitingHandshake');
188
- },
189
- onMessage(channel, handler) {
190
- if (typeof channel !== 'string' || channel === '') {
191
- throw new TypeError('hostToolbar.onMessage: channel must be a non-empty string');
192
- }
193
- const entry = { channel, handler };
194
- handlers.push(entry);
195
- return {
196
- dispose() {
197
- const i = handlers.indexOf(entry);
198
- if (i >= 0)
199
- handlers.splice(i, 1);
200
- },
201
- };
202
- },
203
- onReady(handler) {
204
- // Torn-down control: inert registration — never fires, never throws.
205
- if (state === 'disposed') {
206
- return { dispose() { } };
207
- }
208
- const entry = { handler };
209
- readyHandlers.push(entry);
210
- if (state === 'ready') {
211
- // Missed-signal catch-up: the handshake already happened, so the
212
- // subscriber would otherwise wait forever. Asynchronous on a
213
- // microtask (never re-enter host code synchronously inside
214
- // onReady()), and RE-CHECKED at fire time — both the subscription's
215
- // liveness and the load generation can change between scheduling and
216
- // the microtask (same-frame dispose() / same-frame loadFile).
217
- const scheduledGeneration = generation;
218
- queueMicrotask(() => {
219
- if (state !== 'ready' || generation !== scheduledGeneration || !activePort)
220
- return;
221
- if (!readyHandlers.includes(entry))
222
- return;
223
- invokeReadyHandler(entry.handler);
224
- });
225
- }
226
- return {
227
- dispose() {
228
- const i = readyHandlers.indexOf(entry);
229
- if (i >= 0)
230
- readyHandlers.splice(i, 1);
231
- },
232
- };
233
- },
234
- send(channel, payload) {
235
- if (!activePort)
236
- return false;
237
- activePort.postMessage({ channel, payload });
238
- return true;
239
- },
240
- dispose() {
241
- dropActivePort(true, 'absent');
242
- state = 'disposed';
243
- handlers.length = 0;
244
- readyHandlers.length = 0;
245
- },
246
- };
9
+ return createHostSlotPortChannel({
10
+ isCurrent: opts.isCurrent,
11
+ channel: ViewChannel.HostToolbarPort,
12
+ logPrefix: '[host-toolbar]',
13
+ });
247
14
  }
248
15
  //# sourceMappingURL=host-toolbar-port-channel.js.map
@@ -1,35 +1,10 @@
1
1
  /**
2
- * Ref-counted registration of the host-toolbar framework runtime on
3
- * `session.defaultSession`.
4
- *
5
- * The toolbar's height advertiser does not ride the toolbar WCV's
6
- * `webPreferences.preload`: a host's `setPreloadPath` would replace it and the
7
- * strip height would collapse to 0. Instead the runtime bundle
8
- * (`hostToolbarRuntimePreloadPath`) is registered once per process as a
9
- * session frame preload; its own guard (`--dimina-host-toolbar` marker +
10
- * `isMainFrame`) keeps it a zero-footprint no-op in every other defaultSession
11
- * renderer.
12
- *
13
- * Ref-counting: multiple ViewManagers can coexist in one
14
- * process and share the ONE defaultSession. Each manager acquires at most one
15
- * reference (on first toolbar need) and releases it in `disposeAll`. Only the
16
- * first acquire registers; only the last release unregisters (with the id
17
- * `registerPreloadScript` returned). After a full release a new acquire
18
- * re-registers — there is deliberately no "registered once ever" latch, so
19
- * dispose-everything-then-relaunch flows keep their toolbar runtime.
20
- *
21
- * Module-level state; tests reset it via `vi.resetModules()` + re-import.
22
- */
23
- /**
24
- * Take a reference on the shared session registration. Registers the runtime
25
- * preload on `session.defaultSession` when the count rises from zero. Call at
26
- * most once per ViewManager (the manager tracks its own acquired-flag).
2
+ * Toolbar-specific instantiation of `createHostSlotSessionRuntime` (see that
3
+ * module for the full ref-counting contract). Kept as a thin, independently
4
+ * named wrapper rather than inlined into `host-toolbar-view.ts` because
5
+ * `host-toolbar-session-preload.test.ts` re-imports this module's state via
6
+ * `vi.resetModules()` per test.
27
7
  */
28
8
  export declare function acquireHostToolbarSessionRuntime(): void;
29
- /**
30
- * Release a reference. Unregisters (with the stored registration id) only when
31
- * the LAST reference is released; a still-alive ViewManager's toolbar keeps
32
- * its session runtime. Safe to call only by managers that actually acquired.
33
- */
34
9
  export declare function releaseHostToolbarSessionRuntime(): void;
35
10
  //# sourceMappingURL=host-toolbar-session-runtime.d.ts.map
@@ -1,55 +1,17 @@
1
1
  /**
2
- * Ref-counted registration of the host-toolbar framework runtime on
3
- * `session.defaultSession`.
4
- *
5
- * The toolbar's height advertiser does not ride the toolbar WCV's
6
- * `webPreferences.preload`: a host's `setPreloadPath` would replace it and the
7
- * strip height would collapse to 0. Instead the runtime bundle
8
- * (`hostToolbarRuntimePreloadPath`) is registered once per process as a
9
- * session frame preload; its own guard (`--dimina-host-toolbar` marker +
10
- * `isMainFrame`) keeps it a zero-footprint no-op in every other defaultSession
11
- * renderer.
12
- *
13
- * Ref-counting: multiple ViewManagers can coexist in one
14
- * process and share the ONE defaultSession. Each manager acquires at most one
15
- * reference (on first toolbar need) and releases it in `disposeAll`. Only the
16
- * first acquire registers; only the last release unregisters (with the id
17
- * `registerPreloadScript` returned). After a full release a new acquire
18
- * re-registers — there is deliberately no "registered once ever" latch, so
19
- * dispose-everything-then-relaunch flows keep their toolbar runtime.
20
- *
21
- * Module-level state; tests reset it via `vi.resetModules()` + re-import.
2
+ * Toolbar-specific instantiation of `createHostSlotSessionRuntime` (see that
3
+ * module for the full ref-counting contract). Kept as a thin, independently
4
+ * named wrapper rather than inlined into `host-toolbar-view.ts` because
5
+ * `host-toolbar-session-preload.test.ts` re-imports this module's state via
6
+ * `vi.resetModules()` per test.
22
7
  */
23
- import { session } from 'electron';
8
+ import { createHostSlotSessionRuntime } from './host-slot-session-runtime.js';
24
9
  import { hostToolbarRuntimePreloadPath } from '../../utils/paths.js';
25
- let refCount = 0;
26
- let registrationId = null;
27
- /**
28
- * Take a reference on the shared session registration. Registers the runtime
29
- * preload on `session.defaultSession` when the count rises from zero. Call at
30
- * most once per ViewManager (the manager tracks its own acquired-flag).
31
- */
10
+ const runtime = createHostSlotSessionRuntime(hostToolbarRuntimePreloadPath);
32
11
  export function acquireHostToolbarSessionRuntime() {
33
- if (refCount === 0) {
34
- registrationId = session.defaultSession.registerPreloadScript({
35
- type: 'frame',
36
- filePath: hostToolbarRuntimePreloadPath,
37
- });
38
- }
39
- refCount++;
12
+ runtime.acquire();
40
13
  }
41
- /**
42
- * Release a reference. Unregisters (with the stored registration id) only when
43
- * the LAST reference is released; a still-alive ViewManager's toolbar keeps
44
- * its session runtime. Safe to call only by managers that actually acquired.
45
- */
46
14
  export function releaseHostToolbarSessionRuntime() {
47
- if (refCount === 0)
48
- return;
49
- refCount--;
50
- if (refCount === 0 && registrationId !== null) {
51
- session.defaultSession.unregisterPreloadScript(registrationId);
52
- registrationId = null;
53
- }
15
+ runtime.release();
54
16
  }
55
17
  //# sourceMappingURL=host-toolbar-session-runtime.js.map
@@ -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