@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
@@ -9,47 +9,27 @@
9
9
  */
10
10
  import { ipcRenderer } from 'electron';
11
11
  import { createSizeAdvertiser } from '@dimina-kit/view-anchor';
12
- import { ViewChannel } from '../../shared/ipc-channels.js';
12
+ import { ViewChannel } from '../../shared/ipc-channels-overlays.js';
13
+ import { whenSlotRootReady } from './wait-for-slot-root.js';
13
14
  /**
14
15
  * Attach the advertiser to the toolbar content's shrink-to-fit root
15
- * (`[data-host-toolbar-root]`). That element MUST be shrink-to-fit on the block
16
- * axis its height must reflect the content, not the host-applied view height,
17
- * or the cross-process loop never converges (`createSizeAdvertiser`'s footgun).
18
- * If the element is missing we warn and no-op rather than measure `<body>`,
19
- * whose block size IS the view size and would advertise nonsense.
20
- *
21
- * Returns a disposer that tears the advertiser down.
22
- */
23
- export function installHostToolbarAdvertiser() {
24
- const root = document.querySelector('[data-host-toolbar-root]');
25
- if (!root) {
26
- console.warn('[host-toolbar-advertiser] no `[data-host-toolbar-root]` element found — ' +
27
- 'not advertising a height. The toolbar content must wrap itself in a ' +
28
- 'shrink-to-fit `[data-host-toolbar-root]` element so its block size is ' +
29
- 'the content height, not the host-given view size.');
30
- return () => { };
31
- }
32
- const advertiser = createSizeAdvertiser(root, {
33
- axis: 'block',
34
- publish: (size) => {
35
- ipcRenderer.send(ViewChannel.HostToolbarAdvertiseHeight, size);
36
- },
37
- });
38
- return () => advertiser.dispose();
39
- }
40
- /**
41
- * Install once the DOM is ready (the root element must exist before we query).
42
- * Self-gating: if the document is already past `loading`, install synchronously;
43
- * otherwise wait for `DOMContentLoaded`.
16
+ * (`[data-host-toolbar-root]`), waiting for it if necessary the root may be
17
+ * mounted asynchronously by a framework rather than present in the initial
18
+ * HTML. That element MUST be shrink-to-fit on the block axis — its height
19
+ * must reflect the content, not the host-applied view height, or the
20
+ * cross-process loop never converges (`createSizeAdvertiser`'s footgun).
44
21
  */
45
22
  export function installHostToolbarAdvertiserWhenReady() {
46
- if (document.readyState === 'loading') {
47
- document.addEventListener('DOMContentLoaded', () => {
48
- installHostToolbarAdvertiser();
49
- }, { once: true });
50
- }
51
- else {
52
- installHostToolbarAdvertiser();
53
- }
23
+ whenSlotRootReady('[data-host-toolbar-root]', '[host-toolbar-advertiser] no `[data-host-toolbar-root]` element found — ' +
24
+ 'not advertising a height yet. The toolbar content must wrap itself in a ' +
25
+ 'shrink-to-fit `[data-host-toolbar-root]` element so its block size is ' +
26
+ 'the content height, not the host-given view size.', (root) => {
27
+ createSizeAdvertiser(root, {
28
+ axis: 'block',
29
+ publish: (size) => {
30
+ ipcRenderer.send(ViewChannel.HostToolbarAdvertiseHeight, size);
31
+ },
32
+ });
33
+ });
54
34
  }
55
35
  //# sourceMappingURL=host-toolbar-advertiser.js.map
@@ -37,6 +37,10 @@
37
37
  * - Inbound dispatch uses `addEventListener('message')` + `start()`
38
38
  * (without `start()` a DOM MessagePort never delivers) and DROPS malformed
39
39
  * envelopes without throwing.
40
+ *
41
+ * Shared implementation: see `host-slot-port-bridge.ts` (the toolbar/sidebar/
42
+ * dialog port bridges are otherwise identical; only the constants below
43
+ * differ).
40
44
  */
41
45
  /**
42
46
  * Cap on pre-handshake queued sends. 128 comfortably covers any sane toolbar
@@ -45,5 +49,10 @@
45
49
  * envelope (queued first-comers survive), one console.warn per load.
46
50
  */
47
51
  export declare const HOST_TOOLBAR_PENDING_LIMIT = 128;
52
+ /**
53
+ * Subscribe the handshake channel and expose the page bridge. Call ONLY from
54
+ * a passing toolbar-runtime guard (`activateHostToolbarRuntime`) — a failing
55
+ * guard must leave zero footprint (no bridge key, no IPC listener).
56
+ */
48
57
  export declare function installHostToolbarPortBridge(): void;
49
58
  //# sourceMappingURL=host-toolbar-port.d.ts.map
@@ -37,10 +37,13 @@
37
37
  * - Inbound dispatch uses `addEventListener('message')` + `start()`
38
38
  * (without `start()` a DOM MessagePort never delivers) and DROPS malformed
39
39
  * envelopes without throwing.
40
+ *
41
+ * Shared implementation: see `host-slot-port-bridge.ts` (the toolbar/sidebar/
42
+ * dialog port bridges are otherwise identical; only the constants below
43
+ * differ).
40
44
  */
41
- import { contextBridge, ipcRenderer } from 'electron';
42
- import { ViewChannel } from '../../shared/ipc-channels.js';
43
- const BRIDGE_KEY = 'diminaHostToolbar';
45
+ import { ViewChannel } from '../../shared/ipc-channels-overlays.js';
46
+ import { createHostSlotPortBridge } from './host-slot-port-bridge.js';
44
47
  /**
45
48
  * Cap on pre-handshake queued sends. 128 comfortably covers any sane toolbar
46
49
  * boot sequence while bounding what a page whose handshake never completes
@@ -53,99 +56,12 @@ export const HOST_TOOLBAR_PENDING_LIMIT = 128;
53
56
  * a passing toolbar-runtime guard (`activateHostToolbarRuntime`) — a failing
54
57
  * guard must leave zero footprint (no bridge key, no IPC listener).
55
58
  */
56
- /**
57
- * Entry-waist channel validation, parity with the main side's
58
- * `hostToolbar.onMessage` guard (same TypeError, message names `channel`).
59
- * Runs BEFORE any state is touched (no queue slot, no registry entry), in
60
- * both port states — a page author's typo throws at the call site instead of
61
- * vanishing into main's silent inbound drop.
62
- */
63
- function assertValidChannel(method, channel) {
64
- if (typeof channel !== 'string' || channel === '') {
65
- throw new TypeError(`diminaHostToolbar.${method}: channel must be a non-empty string`);
66
- }
67
- }
68
59
  export function installHostToolbarPortBridge() {
69
- let activePort = null;
70
- const pending = [];
71
- // One overflow warning per load (this installer runs once per document) —
72
- // a runaway page send-loop must not get per-drop console spam.
73
- let warnedPendingOverflow = false;
74
- const handlers = [];
75
- const dispatch = (data) => {
76
- // Defensive symmetry with main: drop anything that is not an object
77
- // envelope with a string channel — never throw in the dispatcher.
78
- if (typeof data !== 'object' || data === null)
79
- return;
80
- const { channel, payload } = data;
81
- if (typeof channel !== 'string')
82
- return;
83
- for (const entry of [...handlers]) {
84
- if (entry.channel === channel)
85
- entry.handler(payload);
86
- }
87
- };
88
- const onPortMessage = (event) => {
89
- dispatch(event.data);
90
- };
91
- ipcRenderer.on(ViewChannel.HostToolbarPort, (event) => {
92
- const port = event.ports[0];
93
- if (!port)
94
- return;
95
- // Same-load duplicate handshake: the LATER port wins. Main closed (or is
96
- // about to close) its end of the old pair — detach and stop writing to it.
97
- if (activePort) {
98
- try {
99
- activePort.removeEventListener('message', onPortMessage);
100
- activePort.close();
101
- }
102
- catch {
103
- /* already dead */
104
- }
105
- }
106
- activePort = port;
107
- // addEventListener (not onmessage) keeps the handler removable on
108
- // re-handshake; it REQUIRES start() or inbound never delivers.
109
- port.addEventListener('message', onPortMessage);
110
- port.start();
111
- // Flush sends issued before the port arrived, in order.
112
- while (pending.length > 0) {
113
- const envelope = pending.shift();
114
- port.postMessage(envelope);
115
- }
116
- });
117
- // EXACTLY { send, onMessage } — functions only; the port stays in the
118
- // isolated world.
119
- contextBridge.exposeInMainWorld(BRIDGE_KEY, {
120
- send(channel, payload) {
121
- assertValidChannel('send', channel);
122
- const envelope = { channel, payload };
123
- if (activePort) {
124
- activePort.postMessage(envelope);
125
- return;
126
- }
127
- // Bounded queue: drop the NEWEST send on overflow (FIFO first-comers
128
- // survive), warn once per load, never throw into page code.
129
- if (pending.length >= HOST_TOOLBAR_PENDING_LIMIT) {
130
- if (!warnedPendingOverflow) {
131
- warnedPendingOverflow = true;
132
- console.warn(`[dimina-devtools] host-toolbar pending queue full (${HOST_TOOLBAR_PENDING_LIMIT}); ` +
133
- 'dropping further pre-handshake send() calls until the port arrives');
134
- }
135
- return;
136
- }
137
- pending.push(envelope);
138
- },
139
- onMessage(channel, handler) {
140
- assertValidChannel('onMessage', channel);
141
- const entry = { channel, handler };
142
- handlers.push(entry);
143
- return () => {
144
- const i = handlers.indexOf(entry);
145
- if (i >= 0)
146
- handlers.splice(i, 1);
147
- };
148
- },
60
+ createHostSlotPortBridge({
61
+ bridgeKey: 'diminaHostToolbar',
62
+ channel: ViewChannel.HostToolbarPort,
63
+ pendingLimit: HOST_TOOLBAR_PENDING_LIMIT,
64
+ label: 'host-toolbar',
149
65
  });
150
66
  }
151
67
  //# sourceMappingURL=host-toolbar-port.js.map
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Shared readiness wait for a host-slot content's shrink-to-fit measurement
3
+ * root (`[data-host-*-root]`). A one-shot `document.querySelector` at
4
+ * `DOMContentLoaded` time only works when the root is present in the initial
5
+ * HTML. Framework-rendered content (e.g. a React app) can mount its root
6
+ * asynchronously, after `DOMContentLoaded` has already fired — a one-shot
7
+ * check misses it permanently and the slot's width/height is never
8
+ * advertised. This keeps watching via `MutationObserver` instead of assuming
9
+ * a synchronous mount, without polling on a fixed delay.
10
+ *
11
+ * The "root is missing" warning exists for downstream authors who forgot the
12
+ * element entirely, so it must not fire on the healthy async-mount path — a
13
+ * warning printed on every normal load is noise that trains its readers to
14
+ * ignore it. It is therefore withheld until the document has finished loading
15
+ * (`window.load`, a real event rather than a guessed delay) with the root
16
+ * still absent; the observer stays armed either way, so a root that mounts
17
+ * even later is still picked up.
18
+ */
19
+ export declare function whenSlotRootReady(selector: string, missingWarning: string, install: (root: HTMLElement) => void): void;
20
+ //# sourceMappingURL=wait-for-slot-root.d.ts.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Shared readiness wait for a host-slot content's shrink-to-fit measurement
3
+ * root (`[data-host-*-root]`). A one-shot `document.querySelector` at
4
+ * `DOMContentLoaded` time only works when the root is present in the initial
5
+ * HTML. Framework-rendered content (e.g. a React app) can mount its root
6
+ * asynchronously, after `DOMContentLoaded` has already fired — a one-shot
7
+ * check misses it permanently and the slot's width/height is never
8
+ * advertised. This keeps watching via `MutationObserver` instead of assuming
9
+ * a synchronous mount, without polling on a fixed delay.
10
+ *
11
+ * The "root is missing" warning exists for downstream authors who forgot the
12
+ * element entirely, so it must not fire on the healthy async-mount path — a
13
+ * warning printed on every normal load is noise that trains its readers to
14
+ * ignore it. It is therefore withheld until the document has finished loading
15
+ * (`window.load`, a real event rather than a guessed delay) with the root
16
+ * still absent; the observer stays armed either way, so a root that mounts
17
+ * even later is still picked up.
18
+ */
19
+ export function whenSlotRootReady(selector, missingWarning, install) {
20
+ function attempt() {
21
+ const root = document.querySelector(selector);
22
+ if (root) {
23
+ install(root);
24
+ return;
25
+ }
26
+ let installed = false;
27
+ const observer = new MutationObserver(() => {
28
+ const lateRoot = document.querySelector(selector);
29
+ if (!lateRoot)
30
+ return;
31
+ observer.disconnect();
32
+ installed = true;
33
+ install(lateRoot);
34
+ });
35
+ observer.observe(document.documentElement, { childList: true, subtree: true });
36
+ const warnIfStillMissing = () => {
37
+ if (!installed)
38
+ console.warn(missingWarning);
39
+ };
40
+ if (document.readyState === 'complete')
41
+ warnIfStillMissing();
42
+ else
43
+ window.addEventListener('load', warnIfStillMissing, { once: true });
44
+ }
45
+ if (document.readyState === 'loading') {
46
+ document.addEventListener('DOMContentLoaded', attempt, { once: true });
47
+ }
48
+ else {
49
+ attempt();
50
+ }
51
+ }
52
+ //# sourceMappingURL=wait-for-slot-root.js.map
@@ -0,0 +1,353 @@
1
+ "use strict";
2
+
3
+ // src/shared/constants.ts
4
+ var HOST_DIALOG_RUNTIME_MARKER = "--dimina-host-dialog";
5
+
6
+ // src/preload/runtime/host-dialog-advertiser.ts
7
+ var import_electron = require("electron");
8
+
9
+ // ../view-anchor/src/measure-loop.ts
10
+ function createMeasureLoop(cfg) {
11
+ const { produce, same, sink } = cfg;
12
+ let rafId = null;
13
+ let active = false;
14
+ let disposed = false;
15
+ let last = null;
16
+ const cancel = () => {
17
+ if (rafId !== null) {
18
+ cancelAnimationFrame(rafId);
19
+ rafId = null;
20
+ }
21
+ };
22
+ return {
23
+ schedule() {
24
+ if (disposed || !active || rafId !== null) return;
25
+ rafId = requestAnimationFrame(() => {
26
+ rafId = null;
27
+ if (disposed || !active) return;
28
+ const value = produce();
29
+ if (value === null) return;
30
+ if (last !== null && same(value, last)) return;
31
+ last = value;
32
+ sink(value);
33
+ });
34
+ },
35
+ emitNow(value) {
36
+ if (disposed) return;
37
+ last = value;
38
+ sink(value);
39
+ },
40
+ setActive(on) {
41
+ active = on;
42
+ },
43
+ cancel,
44
+ dispose() {
45
+ if (disposed) return;
46
+ disposed = true;
47
+ cancel();
48
+ }
49
+ };
50
+ }
51
+
52
+ // ../view-anchor/src/size-advertiser.ts
53
+ function createSizeAdvertiser(target, opts) {
54
+ const axis = opts.axis;
55
+ let publish = opts.publish;
56
+ let observer = null;
57
+ let disposed = false;
58
+ let latest = null;
59
+ const produce = () => {
60
+ if (!latest) return null;
61
+ const raw = axis === "block" ? latest.blockSize : latest.inlineSize;
62
+ if (!Number.isFinite(raw)) return null;
63
+ return { axis, extent: Math.max(0, Math.round(raw)) };
64
+ };
65
+ const loop = createMeasureLoop({
66
+ produce,
67
+ same: (a, b) => a.extent === b.extent,
68
+ // axis is constant
69
+ sink: (size) => publish(size)
70
+ });
71
+ const onResize = (entries) => {
72
+ const entry = entries[entries.length - 1];
73
+ if (entry) {
74
+ latest = entry.borderBoxSize?.[0] ?? entry.contentBoxSize?.[0] ?? latest;
75
+ }
76
+ loop.schedule();
77
+ };
78
+ const doc = target.ownerDocument;
79
+ if (target === doc.body || target === doc.documentElement) {
80
+ console.warn(
81
+ `[view-anchor] size-advertiser: <${target === doc.body ? "body" : "html"}>'s ${axis} size is the host-given view size, not the content size \u2014 the advertiser will never shrink to content. Measure a shrink-to-fit wrapper. See bidirectional-design.md's single-axis-ownership section.`
82
+ );
83
+ }
84
+ loop.setActive(true);
85
+ observer = new ResizeObserver(onResize);
86
+ observer.observe(target);
87
+ return {
88
+ update(nextPublish) {
89
+ if (disposed) return;
90
+ publish = nextPublish;
91
+ const cur = produce();
92
+ if (cur) loop.emitNow(cur);
93
+ },
94
+ dispose() {
95
+ if (disposed) return;
96
+ disposed = true;
97
+ loop.cancel();
98
+ if (observer) {
99
+ observer.disconnect();
100
+ observer = null;
101
+ }
102
+ loop.dispose();
103
+ }
104
+ };
105
+ }
106
+
107
+ // src/shared/ipc-channels-overlays.ts
108
+ var ViewChannel = {
109
+ /**
110
+ * Reverse size-advertiser: the host-toolbar WCV's OWN renderer advertises its
111
+ * intrinsic content height so main reserves exactly that much. Payload
112
+ * `{ axis: 'block', extent }`. fire-and-forget (send), NOT invoke.
113
+ */
114
+ HostToolbarAdvertiseHeight: "view:host-toolbar:advertise-height",
115
+ /**
116
+ * main → host-toolbar WCV renderer: per-load MessagePort handshake for the
117
+ * gated narrow channel. On every toolbar `did-finish-load` main creates a
118
+ * `MessageChannelMain` and transfers port2 here
119
+ * (`wc.postMessage(HostToolbarPort, null, [port2])`); the session-resident
120
+ * toolbar runtime preload receives it via `event.ports[0]` and bridges it to
121
+ * the page as `window.diminaHostToolbar`. Envelope both directions:
122
+ * `{ channel: string, payload: unknown }`.
123
+ */
124
+ HostToolbarPort: "view:host-toolbar:port",
125
+ /**
126
+ * main → main-window renderer: push the reserved host-toolbar height so the
127
+ * renderer placeholder div resizes (closing the dynamic-height loop).
128
+ */
129
+ HostToolbarHeightChanged: "view:host-toolbar:height-changed",
130
+ /**
131
+ * main ← main-window renderer (invoke): pull the last NOTIFIED toolbar
132
+ * height retained in main. Mount-time replay companion to
133
+ * `HostToolbarHeightChanged`: the push listener mounts with the project
134
+ * view and the toolbar's size-advertiser deduplicates (never re-reports),
135
+ * so a height pushed while no project view was mounted would otherwise be
136
+ * lost forever (cold start on the project list races it; close-project →
137
+ * reopen hits it deterministically). No payload; resolves a number.
138
+ */
139
+ HostToolbarGetHeight: "view:host-toolbar:get-height",
140
+ /**
141
+ * Reverse size-advertiser for the host-sidebar WCV, mirroring
142
+ * `HostToolbarAdvertiseHeight` on the inline (width) axis instead of block.
143
+ * Payload `{ axis: 'inline', extent }`. fire-and-forget (send), NOT invoke.
144
+ */
145
+ HostSidebarAdvertiseWidth: "view:host-sidebar:advertise-width",
146
+ /**
147
+ * main → host-sidebar WCV renderer: per-load MessagePort handshake, same
148
+ * contract as `HostToolbarPort` (see that entry).
149
+ */
150
+ HostSidebarPort: "view:host-sidebar:port",
151
+ /**
152
+ * main → main-window renderer: push the reserved host-sidebar width so the
153
+ * renderer placeholder div resizes, mirroring `HostToolbarHeightChanged`.
154
+ */
155
+ HostSidebarWidthChanged: "view:host-sidebar:width-changed",
156
+ /**
157
+ * main ← main-window renderer (invoke): pull the last NOTIFIED sidebar
158
+ * width, mirroring `HostToolbarGetHeight`'s mount-time replay role.
159
+ */
160
+ HostSidebarGetWidth: "view:host-sidebar:get-width",
161
+ /**
162
+ * main → main-window renderer: push the project category (`Project.type`)
163
+ * selected in the host-sidebar's content — devtools' own default icon rail,
164
+ * or any downstream replacement that sends on the same channel. No
165
+ * pull/replay companion like `HostSidebarGetWidth`: the default category is
166
+ * a stable initial value regardless of load-order, and nothing is ever sent
167
+ * before the main-window renderer (and thus `ProjectListScreen`) is already
168
+ * mounted.
169
+ */
170
+ HostSidebarCategorySelected: "view:host-sidebar:category-selected",
171
+ /**
172
+ * Reverse size-advertiser for the host-dialog WCV. Unlike the toolbar/sidebar
173
+ * (single-axis, `setBaseDesired`-placed strips), the dialog is a BOTH-AXES
174
+ * overlay positioned by `setOverlayDesired` — main centers it in the main
175
+ * window once it knows both dimensions. One channel carries either axis'
176
+ * report (`{ axis: 'block' | 'inline', extent }`); the dialog's own content
177
+ * advertises both from the same root (see `host-dialog-advertiser.ts`).
178
+ * fire-and-forget (send), NOT invoke.
179
+ *
180
+ * No `HostDialogSizeChanged` / `HostDialogGetSize` counterparts: those exist
181
+ * for toolbar/sidebar so a renderer-owned PLACEHOLDER can replay a size it
182
+ * missed. The dialog has no such placeholder — it is a main-driven overlay
183
+ * shown/hidden on demand (`hostDialog.show()`/`hide()`), so there is nothing
184
+ * in the renderer to replay a size into.
185
+ */
186
+ HostDialogAdvertiseSize: "view:host-dialog:advertise-size",
187
+ /**
188
+ * main → host-dialog WCV renderer: per-load MessagePort handshake, same
189
+ * contract as `HostToolbarPort` (see that entry).
190
+ */
191
+ HostDialogPort: "view:host-dialog:port",
192
+ /**
193
+ * Renderer → main: the window-level placement snapshot (one monotonic epoch
194
+ * per commit tick, one generation per renderer lifetime) that drives the view
195
+ * reconciler. The single source of truth for every managed native view's
196
+ * bounds/visibility/z-order — supersedes the per-view bounds channels above.
197
+ * invoke.
198
+ */
199
+ PlacementSnapshot: "view:placement-snapshot",
200
+ /**
201
+ * main ← main-window renderer (invoke): allocate a fresh placement
202
+ * generation seed for this renderer bootstrap. See
203
+ * renderer-placement-generation.ts for why the seed comes from main
204
+ * (a wall-clock `Date.now()` seed is not guaranteed to exceed main's
205
+ * still-standing high-water mark across two reloads that happen faster
206
+ * than the clock's resolution). No payload; resolves a number.
207
+ */
208
+ AllocatePlacementGeneration: "view:allocate-placement-generation"
209
+ };
210
+
211
+ // src/preload/runtime/wait-for-slot-root.ts
212
+ function whenSlotRootReady(selector, missingWarning, install) {
213
+ function attempt() {
214
+ const root = document.querySelector(selector);
215
+ if (root) {
216
+ install(root);
217
+ return;
218
+ }
219
+ let installed = false;
220
+ const observer = new MutationObserver(() => {
221
+ const lateRoot = document.querySelector(selector);
222
+ if (!lateRoot) return;
223
+ observer.disconnect();
224
+ installed = true;
225
+ install(lateRoot);
226
+ });
227
+ observer.observe(document.documentElement, { childList: true, subtree: true });
228
+ const warnIfStillMissing = () => {
229
+ if (!installed) console.warn(missingWarning);
230
+ };
231
+ if (document.readyState === "complete") warnIfStillMissing();
232
+ else window.addEventListener("load", warnIfStillMissing, { once: true });
233
+ }
234
+ if (document.readyState === "loading") {
235
+ document.addEventListener("DOMContentLoaded", attempt, { once: true });
236
+ } else {
237
+ attempt();
238
+ }
239
+ }
240
+
241
+ // src/preload/runtime/host-dialog-advertiser.ts
242
+ function installHostDialogAdvertiserWhenReady() {
243
+ whenSlotRootReady(
244
+ "[data-host-dialog-root]",
245
+ "[host-dialog-advertiser] no `[data-host-dialog-root]` element found \u2014 not advertising a size yet. The dialog content must wrap itself in a shrink-to-fit `[data-host-dialog-root]` element so its size is the content size, not the host-given view size.",
246
+ (root) => {
247
+ const publish = (size) => {
248
+ import_electron.ipcRenderer.send(ViewChannel.HostDialogAdvertiseSize, size);
249
+ };
250
+ createSizeAdvertiser(root, { axis: "block", publish });
251
+ createSizeAdvertiser(root, { axis: "inline", publish });
252
+ }
253
+ );
254
+ }
255
+
256
+ // src/preload/runtime/host-slot-port-bridge.ts
257
+ var import_electron2 = require("electron");
258
+ function createHostSlotPortBridge(opts) {
259
+ const { bridgeKey, channel, pendingLimit, label } = opts;
260
+ let activePort = null;
261
+ const pending = [];
262
+ let warnedPendingOverflow = false;
263
+ const handlers = [];
264
+ function assertValidChannel(method, ch) {
265
+ if (typeof ch !== "string" || ch === "") {
266
+ throw new TypeError(`${bridgeKey}.${method}: channel must be a non-empty string`);
267
+ }
268
+ }
269
+ const dispatch = (data) => {
270
+ if (typeof data !== "object" || data === null) return;
271
+ const { channel: ch, payload } = data;
272
+ if (typeof ch !== "string") return;
273
+ for (const entry of [...handlers]) {
274
+ if (entry.channel === ch) entry.handler(payload);
275
+ }
276
+ };
277
+ const onPortMessage = (event) => {
278
+ dispatch(event.data);
279
+ };
280
+ import_electron2.ipcRenderer.on(channel, (event) => {
281
+ const port = event.ports[0];
282
+ if (!port) return;
283
+ if (activePort) {
284
+ try {
285
+ activePort.removeEventListener("message", onPortMessage);
286
+ activePort.close();
287
+ } catch {
288
+ }
289
+ }
290
+ activePort = port;
291
+ port.addEventListener("message", onPortMessage);
292
+ port.start();
293
+ while (pending.length > 0) {
294
+ const envelope = pending.shift();
295
+ port.postMessage(envelope);
296
+ }
297
+ });
298
+ import_electron2.contextBridge.exposeInMainWorld(bridgeKey, {
299
+ send(ch, payload) {
300
+ assertValidChannel("send", ch);
301
+ const envelope = { channel: ch, payload };
302
+ if (activePort) {
303
+ activePort.postMessage(envelope);
304
+ return;
305
+ }
306
+ if (pending.length >= pendingLimit) {
307
+ if (!warnedPendingOverflow) {
308
+ warnedPendingOverflow = true;
309
+ console.warn(
310
+ `[dimina-devtools] ${label} pending queue full (${pendingLimit}); dropping further pre-handshake send() calls until the port arrives`
311
+ );
312
+ }
313
+ return;
314
+ }
315
+ pending.push(envelope);
316
+ },
317
+ onMessage(ch, handler) {
318
+ assertValidChannel("onMessage", ch);
319
+ const entry = { channel: ch, handler };
320
+ handlers.push(entry);
321
+ return () => {
322
+ const i = handlers.indexOf(entry);
323
+ if (i >= 0) handlers.splice(i, 1);
324
+ };
325
+ }
326
+ });
327
+ }
328
+
329
+ // src/preload/runtime/host-dialog-port.ts
330
+ var HOST_DIALOG_PENDING_LIMIT = 128;
331
+ function installHostDialogPortBridge() {
332
+ createHostSlotPortBridge({
333
+ bridgeKey: "diminaHostDialog",
334
+ channel: ViewChannel.HostDialogPort,
335
+ pendingLimit: HOST_DIALOG_PENDING_LIMIT,
336
+ label: "host-dialog"
337
+ });
338
+ }
339
+
340
+ // src/preload/runtime/host-dialog-runtime.ts
341
+ function shouldActivateHostDialogRuntime(argv, isMainFrame) {
342
+ return isMainFrame && argv.includes(HOST_DIALOG_RUNTIME_MARKER);
343
+ }
344
+ function activateHostDialogRuntime(env) {
345
+ if (!shouldActivateHostDialogRuntime(env.argv, env.isMainFrame)) return false;
346
+ installHostDialogAdvertiserWhenReady();
347
+ installHostDialogPortBridge();
348
+ return true;
349
+ }
350
+
351
+ // src/preload/windows/host-dialog-runtime.ts
352
+ activateHostDialogRuntime({ argv: process.argv, isMainFrame: process.isMainFrame });
353
+ //# sourceMappingURL=host-dialog-runtime.cjs.map