@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
@@ -36,8 +36,10 @@ export interface ViewSlot {
36
36
  * settings/popover are main-owned and live in `overlayDesired`. Any change
37
37
  * merges the two, runs the pure reconcile core, and applies the ordered ops
38
38
  * through `viewTarget`. `epochCounter` is a single monotonic tick — main is the
39
- * only (serial) reconcile caller, so the core's stale guard passes by
40
- * construction; `rendererGeneration` still drives the reset on renderer restart.
39
+ * only (serial) reconcile caller, so the core's stale-epoch guard passes by
40
+ * construction; `rendererGeneration` is the high-water mark that drives both
41
+ * the reset on a genuinely newer generation and the hard rejection of a
42
+ * snapshot from behind it (see `setPlacementSnapshot`).
41
43
  */
42
44
  export interface PlacementReconciler {
43
45
  registerView(viewId: string, slot: ViewSlot): void;
@@ -56,6 +58,16 @@ export interface PlacementReconciler {
56
58
  setOverlayDesired(viewId: string, desired: DesiredView<DevtoolsExtra>): void;
57
59
  deleteOverlayDesired(viewId: string): void;
58
60
  hasOverlayDesired(viewId: string): boolean;
61
+ /**
62
+ * Hand out a fresh generation seed for a renderer bootstrap (see
63
+ * renderer-placement-generation.ts). Strictly exceeds both the current
64
+ * high-water mark (`rendererGeneration`, which a full renderer reload does
65
+ * NOT reset — this reconciler lives in the long-lived main process) and
66
+ * every previously allocated seed, so a reload that races ahead of its own
67
+ * previous session's accepted snapshots can never be handed a value that
68
+ * `setPlacementSnapshot` would reject as stale.
69
+ */
70
+ allocateGeneration(): number;
59
71
  }
60
72
  export declare function createPlacementReconciler(ctx: ViewManagerContext): PlacementReconciler;
61
73
  //# sourceMappingURL=placement-reconciler.d.ts.map
@@ -5,6 +5,7 @@ export function createPlacementReconciler(ctx) {
5
5
  let placementState = createInitialState();
6
6
  let epochCounter = 0;
7
7
  let rendererGeneration = 0;
8
+ let allocatedGeneration = 0;
8
9
  const appliedActual = new Map();
9
10
  const baseDesired = new Map();
10
11
  const overlayDesired = new Map();
@@ -119,6 +120,28 @@ export function createPlacementReconciler(ctx) {
119
120
  placementState = { ...placementState, actual: cloneAppliedActual() };
120
121
  }
121
122
  function setPlacementSnapshot(snapshot) {
123
+ // Hard reject a snapshot from BEHIND the current high-water mark — a
124
+ // complete no-op, touching neither `rendererGeneration` nor
125
+ // `baseDesired`. The renderer hands out one shared, strictly monotonic
126
+ // sequence across every screen (see renderer-placement-generation.ts),
127
+ // so under normal operation a lower generation can only be a LATE
128
+ // arrival from an already-superseded source (e.g. a dead screen's
129
+ // delayed `dispose()` empty-snapshot flush racing a successor screen's
130
+ // mount). The previous version of this guard clamped
131
+ // `rendererGeneration` to never regress but still unconditionally
132
+ // applied the stale snapshot's CONTENT into `baseDesired` under the
133
+ // clamped (i.e. current) generation number — which defeated the
134
+ // reconcile core's own generation-regression guard
135
+ // (placement-reconcile.ts: `snapshot.generation < prev.generation`) by
136
+ // never letting it see the snapshot's real, lower generation. That let a
137
+ // dead screen's stale/empty view list silently overwrite a currently
138
+ // active screen's real views. Dropping it here, before it ever reaches
139
+ // `baseDesired`, is what actually gives the stale snapshot zero side
140
+ // effects.
141
+ if (snapshot.generation < rendererGeneration) {
142
+ console.warn(`[placement-reconciler] snapshot generation ${snapshot.generation} is behind the current ${rendererGeneration}; dropping without applying its content`);
143
+ return;
144
+ }
122
145
  rendererGeneration = snapshot.generation;
123
146
  baseDesired.clear();
124
147
  for (const v of snapshot.views)
@@ -150,6 +173,10 @@ export function createPlacementReconciler(ctx) {
150
173
  setOverlayDesired: (viewId, desired) => { overlayDesired.set(viewId, desired); },
151
174
  deleteOverlayDesired: (viewId) => { overlayDesired.delete(viewId); },
152
175
  hasOverlayDesired: (viewId) => overlayDesired.has(viewId),
176
+ allocateGeneration: () => {
177
+ allocatedGeneration = Math.max(allocatedGeneration, rendererGeneration) + 1;
178
+ return allocatedGeneration;
179
+ },
153
180
  };
154
181
  }
155
182
  //# sourceMappingURL=placement-reconciler.js.map
@@ -31,6 +31,7 @@ interface OverlaySink {
31
31
  }): void;
32
32
  }
33
33
  export declare function hostToolbarBounds(mgr: SnapshotSink, rect: Rect): void;
34
+ export declare function hostSidebarBounds(mgr: SnapshotSink, rect: Rect): void;
34
35
  export declare function simulatorDevtoolsBounds(mgr: SnapshotSink, rect: Rect): void;
35
36
  export declare function workbenchBounds(mgr: SnapshotSink, rect: Rect): void;
36
37
  export declare function showSettingsReady(mgr: OverlaySink): Promise<void>;
@@ -28,6 +28,9 @@ function pushView(mgr, view, generation = 1) {
28
28
  export function hostToolbarBounds(mgr, rect) {
29
29
  pushView(mgr, { viewId: VIEW_ID.hostToolbar, placement: toPlacement(rect), layer: VIEW_LAYER.hostToolbar });
30
30
  }
31
+ export function hostSidebarBounds(mgr, rect) {
32
+ pushView(mgr, { viewId: VIEW_ID.hostSidebar, placement: toPlacement(rect), layer: VIEW_LAYER.hostSidebar });
33
+ }
31
34
  export function simulatorDevtoolsBounds(mgr, rect) {
32
35
  pushView(mgr, { viewId: VIEW_ID.simulatorDevtools, placement: toPlacement(rect), layer: VIEW_LAYER.base });
33
36
  }
@@ -95,7 +95,9 @@ export function electronModuleMock() {
95
95
  export function pathsModuleMock() {
96
96
  return {
97
97
  mainPreloadPath: '/stub/preload.js',
98
- hostToolbarPreloadPath: '/stub/host-toolbar-preload.js',
98
+ hostToolbarRuntimePreloadPath: '/stub/host-toolbar-preload.js',
99
+ hostSidebarRuntimePreloadPath: '/stub/host-sidebar-preload.js',
100
+ hostDialogRuntimePreloadPath: '/stub/host-dialog-preload.js',
99
101
  cjsSiblingPreloadPath: (p) => p.replace(/\.js$/, '.cjs'),
100
102
  devtoolsPackageRoot: '/stub/devtools-pkg-root',
101
103
  };
@@ -1,9 +1,11 @@
1
1
  import type { WebContents } from 'electron';
2
2
  import type { NativeDeviceInfo } from '../../../shared/ipc-channels.js';
3
3
  import { type WorkbenchContext } from '../workbench-context.js';
4
- import type { HostToolbarMessageSubscription } from './host-toolbar-port-channel.js';
5
4
  import type { PlacementSnapshot } from '@dimina-kit/electron-deck/layout';
6
5
  import type { DevtoolsExtra } from '../../../shared/view-ids.js';
6
+ import { type HostToolbarControl } from './host-toolbar-view.js';
7
+ import { type HostSidebarViewManagerMembers } from './host-sidebar-view.js';
8
+ import { type HostDialogViewManagerMembers } from './host-dialog-view.js';
7
9
  import { type OverlayPanelsView, type TooltipShowPayload } from './overlay-panels-view.js';
8
10
  export type { TooltipShowPayload };
9
11
  export { resolveProjectEditorTarget, type ProjectEditorTarget, } from './resolve-project-editor-target.js';
@@ -91,7 +93,7 @@ export interface ViewManagerContext {
91
93
  * panels) and shares a single injected placement reconciler; this file wires
92
94
  * them together and exposes their combined method surface.
93
95
  */
94
- export interface ViewManager extends Pick<OverlayPanelsView, 'showSettings' | 'hideSettings' | 'showPopover' | 'hidePopover' | 'prepareTooltip' | 'showTooltip' | 'hideTooltip' | 'markOverlayReady' | 'applyTooltipMeasurement'> {
96
+ export interface ViewManager extends Pick<OverlayPanelsView, 'showSettings' | 'hideSettings' | 'showPopover' | 'hidePopover' | 'prepareTooltip' | 'showTooltip' | 'hideTooltip' | 'markOverlayReady' | 'applyTooltipMeasurement' | 'showProjectCreateDialog' | 'hideProjectCreateDialog' | 'showUpdateDialog' | 'hideUpdateDialog' | 'notifyUpdateDownloadProgress' | 'getProjectCreateDialogWebContentsId' | 'getUpdateDialogWebContentsId'>, HostSidebarViewManagerMembers, HostDialogViewManagerMembers {
95
97
  /**
96
98
  * NATIVE-HOST ONLY. Create the simulator itself as a top-level
97
99
  * WebContentsView (not a renderer `<webview>` guest) loading `simulatorUrl`,
@@ -202,6 +204,12 @@ export interface ViewManager extends Pick<OverlayPanelsView, 'showSettings' | 'h
202
204
  * view tree.
203
205
  */
204
206
  setPlacementSnapshot(snapshot: PlacementSnapshot<DevtoolsExtra>): void;
207
+ /**
208
+ * Hand out a fresh generation seed for a renderer bootstrap. See
209
+ * `PlacementReconciler.allocateGeneration`'s doc-comment for why this
210
+ * replaces a wall-clock (`Date.now()`) seed.
211
+ */
212
+ allocatePlacementGeneration(): number;
205
213
  /**
206
214
  * Lazily create the workbench WebContentsView, load `<url>index.html`, and
207
215
  * add it to the contentView. `url` is the COI server's base URL (trailing
@@ -261,82 +269,6 @@ export interface ViewManager extends Pick<OverlayPanelsView, 'showSettings' | 'h
261
269
  */
262
270
  readonly hostToolbar: HostToolbarControl;
263
271
  }
264
- /**
265
- * Height mode for the host-toolbar placeholder strip. `'auto'` (default): the
266
- * session-resident advertiser's reports drive the height. `{ fixed }`: the
267
- * host pins the height; advertiser reports are ignored until `'auto'` again.
268
- */
269
- export type HostToolbarHeightMode = 'auto' | {
270
- fixed: number;
271
- };
272
- /**
273
- * The control object the downstream host uses to own the toolbar
274
- * WebContentsView. Lazily backed by the view-manager's `hostToolbarView`.
275
- */
276
- export interface HostToolbarControl {
277
- /** Load a URL into the toolbar view (lazy-creates the view). */
278
- loadURL(url: string): Promise<void>;
279
- /** Load a local file into the toolbar view (lazy-creates the view). */
280
- loadFile(path: string): Promise<void>;
281
- /** The toolbar view's live WebContents, or null if not yet created/destroyed. */
282
- readonly webContents: WebContents | null;
283
- /** Remove the toolbar view from the contentView and reset it (kept alive). */
284
- hide(): void;
285
- /**
286
- * The HOST's own `webPreferences.preload` for the toolbar view (purely
287
- * additive). The framework's height-advertiser runtime does NOT ride
288
- * `webPreferences.preload` — it is session-resident (registered on
289
- * `session.defaultSession`, self-guarded by the `--dimina-host-toolbar`
290
- * marker + `isMainFrame`), so a host preload set here coexists with it and
291
- * never replaces it. Must be set before the view is (re)created (first
292
- * `loadURL`/`loadFile`, or the next one after the host closed the
293
- * webContents); `null` (default) means "no host preload" — it does not and
294
- * cannot restore any built-in preload.
295
- */
296
- setPreloadPath(path: string | null): void;
297
- /**
298
- * Register a host-side handler for messages the toolbar PAGE sends via
299
- * `window.diminaHostToolbar.send(channel, payload)`. Control-level: may be
300
- * called before the view exists and survives page reloads / wc rebuilds
301
- * (each per-load MessagePort handshake re-attaches the registry to the new
302
- * port). Throws on an empty / non-string channel. `dispose()` detaches
303
- * (idempotent).
304
- */
305
- onMessage(channel: string, handler: (payload: unknown) => void): HostToolbarMessageSubscription;
306
- /**
307
- * Observe handshake readiness — the push counterpart to polling `send()`
308
- * for `true`. Fires the handler once per load generation, exactly when
309
- * that load's MessagePort handshake completes; registering while the
310
- * channel is ALREADY ready fires once asynchronously on a microtask
311
- * (missed-signal race guard, re-validated at fire time). A reload /
312
- * re-handshake fires registered handlers again; a host-initiated
313
- * `loadURL`/`loadFile` invalidates readiness at initiation, so handlers
314
- * registered in that window wait for the NEW document's handshake.
315
- * `dispose()` detaches (idempotent); `disposeAll` sweeps everything.
316
- */
317
- onReady(handler: () => void): HostToolbarMessageSubscription;
318
- /**
319
- * Post `{ channel, payload }` to the toolbar page (received via
320
- * `window.diminaHostToolbar.onMessage(channel, handler)`). Gated and
321
- * non-queueing: returns false — delivering nothing, creating no view —
322
- * while there is no live toolbar webContents, the current load's
323
- * MessagePort handshake hasn't completed, or a document-replacing
324
- * navigation is in flight (`loadURL`/`loadFile` was issued, or the page
325
- * itself started a main-frame cross-document navigation, and the new
326
- * document hasn't handshaked yet); true once the envelope went out.
327
- * No manual `getHostToolbarWebContentsId` gating needed: the false/true
328
- * result IS the readiness signal.
329
- */
330
- send(channel: string, payload: unknown): boolean;
331
- /**
332
- * Pin or unpin the toolbar strip height. `{ fixed }` notifies the renderer
333
- * placeholder with that height immediately (so a preload-less/static toolbar
334
- * is visible without any advertiser report) and ignores subsequent advertiser
335
- * reports. `'auto'` (default) re-enables advertiser-driven height starting
336
- * from the NEXT report — it does not synthesize/replay a stale height.
337
- */
338
- setHeightMode(mode: HostToolbarHeightMode): void;
339
- }
340
272
  /**
341
273
  * Build a ViewManager bound to the given context. The returned object is the
342
274
  * only component allowed to instantiate or add/remove overlay WebContentsViews.
@@ -3,6 +3,8 @@ import { createPlacementReconciler } from './placement-reconciler.js';
3
3
  import { createWorkbenchView } from './workbench-view.js';
4
4
  import { createDevtoolsHost } from './native-simulator-devtools-host.js';
5
5
  import { createHostToolbarView } from './host-toolbar-view.js';
6
+ import { createHostSidebarView } from './host-sidebar-view.js';
7
+ import { createHostDialogView } from './host-dialog-view.js';
6
8
  import { createOverlayPanelsView, } from './overlay-panels-view.js';
7
9
  import { createNativeSimulatorView } from './native-simulator-view.js';
8
10
  export { resolveProjectEditorTarget, } from './resolve-project-editor-target.js';
@@ -34,6 +36,11 @@ export function createViewManager(ctx) {
34
36
  const hostToolbar = createHostToolbarView(ctx, reconciler, {
35
37
  reapplyPresentOverlays: () => reapplyToolbarDependentOverlays(),
36
38
  });
39
+ // Sidebar and dialog are host-scoped like the toolbar (survive project
40
+ // close/reopen) but carry no height-cycle dependency on the overlay panels,
41
+ // so unlike hostToolbar they need no thunk into this scope.
42
+ const hostSidebar = createHostSidebarView(ctx, reconciler);
43
+ const hostDialog = createHostDialogView(ctx, reconciler);
37
44
  const overlayPanels = createOverlayPanelsView(ctx, reconciler, {
38
45
  getHostToolbarHeight: hostToolbar.getHostToolbarHeight,
39
46
  });
@@ -63,9 +70,15 @@ export function createViewManager(ctx) {
63
70
  // a release/cap replay to rebuild.
64
71
  workbench.cancelWorkbenchAttachHold();
65
72
  disposeProjectViews();
66
- // Host-scoped teardown: the toolbar view, its port channel, and the
67
- // ref-counted session-runtime preload registration.
73
+ // Host-scoped teardown: the toolbar/sidebar/dialog views, their port
74
+ // channels, and their ref-counted session-runtime preload registrations.
68
75
  hostToolbar.dispose();
76
+ hostSidebar.dispose();
77
+ hostDialog.dispose();
78
+ // Devtools-owned overlay-panel dialogs (project-create/update) — never
79
+ // torn down by disposeProjectViews(), they'd otherwise outlive every
80
+ // other view once the app tears down.
81
+ overlayPanels.destroyDialogs();
69
82
  }
70
83
  return {
71
84
  attachNativeSimulator: nativeSimulator.attachNativeSimulator,
@@ -82,7 +95,17 @@ export function createViewManager(ctx) {
82
95
  hideTooltip: overlayPanels.hideTooltip,
83
96
  markOverlayReady: overlayPanels.markOverlayReady,
84
97
  applyTooltipMeasurement: overlayPanels.applyTooltipMeasurement,
85
- repositionAll: () => overlayPanels.reapplyPresentOverlays(),
98
+ showProjectCreateDialog: overlayPanels.showProjectCreateDialog,
99
+ hideProjectCreateDialog: overlayPanels.hideProjectCreateDialog,
100
+ showUpdateDialog: overlayPanels.showUpdateDialog,
101
+ hideUpdateDialog: overlayPanels.hideUpdateDialog,
102
+ notifyUpdateDownloadProgress: overlayPanels.notifyUpdateDownloadProgress,
103
+ getProjectCreateDialogWebContentsId: overlayPanels.getProjectCreateDialogWebContentsId,
104
+ getUpdateDialogWebContentsId: overlayPanels.getUpdateDialogWebContentsId,
105
+ repositionAll: () => {
106
+ overlayPanels.reapplyPresentOverlays();
107
+ hostDialog.reposition();
108
+ },
86
109
  disposeProjectViews,
87
110
  disposeAll,
88
111
  getSimulatorWebContentsId: nativeSimulator.getSimulatorWebContentsId,
@@ -96,6 +119,7 @@ export function createViewManager(ctx) {
96
119
  getHostToolbarHeight: hostToolbar.getHostToolbarHeight,
97
120
  resize: () => overlayPanels.applySettingsBoundsIfPresent(),
98
121
  setPlacementSnapshot: reconciler.setPlacementSnapshot,
122
+ allocatePlacementGeneration: reconciler.allocateGeneration,
99
123
  attachWorkbench: workbench.attachWorkbench,
100
124
  setWorkbenchSource: workbench.setWorkbenchSource,
101
125
  detachWorkbench: workbench.detachWorkbench,
@@ -104,6 +128,13 @@ export function createViewManager(ctx) {
104
128
  cancelWorkbenchAttachHold: workbench.cancelWorkbenchAttachHold,
105
129
  setHostToolbarHeight: hostToolbar.setHostToolbarHeight,
106
130
  hostToolbar: hostToolbar.control,
131
+ getHostSidebarWebContentsId: hostSidebar.getHostSidebarWebContentsId,
132
+ getHostSidebarWidth: hostSidebar.getHostSidebarWidth,
133
+ setHostSidebarWidth: hostSidebar.setHostSidebarWidth,
134
+ hostSidebar: hostSidebar.control,
135
+ getHostDialogWebContentsId: hostDialog.getHostDialogWebContentsId,
136
+ reportHostDialogMeasuredExtent: hostDialog.reportMeasuredExtent,
137
+ hostDialog: hostDialog.control,
107
138
  };
108
139
  }
109
140
  //# sourceMappingURL=view-manager.js.map
@@ -21,8 +21,8 @@ import { type WorkspaceService } from './workspace/workspace-service.js';
21
21
  import { type SimulatorApiRegistry } from './simulator/custom-apis.js';
22
22
  import { type SimulatorUiExtensionRegistry } from './simulator/ui-extensions.js';
23
23
  import { sanitizeTemplates } from './projects/templates.js';
24
- import type { ProjectsProvider, ProjectTemplate } from './projects/types.js';
25
- import type { CustomCreateProjectDialogResult } from '../../shared/types.js';
24
+ import type { Project, ProjectsProvider, ProjectTemplate } from './projects/types.js';
25
+ import type { CustomCreateProjectDialogResult, CustomEditProjectDialogResult } from '../../shared/types.js';
26
26
  /**
27
27
  * Shared mutable state for the workbench application.
28
28
  * Passed to each IPC module so they can read/write shared state without closures.
@@ -96,6 +96,17 @@ export interface WorkbenchContext extends RuntimeContext {
96
96
  parentWindow: BrowserWindow;
97
97
  templates: ProjectTemplate[];
98
98
  }) => Promise<CustomCreateProjectDialogResult>;
99
+ /**
100
+ * Optional host hook for the "编辑项目" dialog. When present, the
101
+ * `projects:openEditDialog` IPC runs it and wraps whatever it resolves to
102
+ * as `{ result }`; when absent, the IPC returns `null` and the renderer
103
+ * shows the built-in dialog. `project` comes from `workspace.listProjects`,
104
+ * not the renderer's IPC args.
105
+ */
106
+ customEditProjectDialog?: (ctx: {
107
+ parentWindow: BrowserWindow;
108
+ project: Project;
109
+ }) => Promise<CustomEditProjectDialogResult>;
99
110
  /**
100
111
  * Host permission gate consulted by `workspace.openProject` BEFORE any side
101
112
  * effect. Throwing vetoes the open (see `WorkbenchAppConfig.onBeforeOpenProject`).
@@ -239,8 +250,9 @@ export interface WorkbenchContext extends RuntimeContext {
239
250
  * because their shapes intentionally differ from the config:
240
251
  * - `preloadPath` / `rendererDir` are REQUIRED here (the caller resolves the
241
252
  * defaults before constructing the context) but optional in the config;
242
- * - `projectsProvider` / `projectTemplates` / `customCreateProjectDialog` use
243
- * the main-process types, not the structural mirrors in `shared/types`.
253
+ * - `projectsProvider` / `projectTemplates` / `customCreateProjectDialog` /
254
+ * `customEditProjectDialog` use the main-process types, not the structural
255
+ * mirrors in `shared/types`.
244
256
  */
245
257
  export interface CreateContextOptions extends Pick<WorkbenchConfig, 'adapter' | 'apiNamespaces' | 'appName' | 'fileTypes'> {
246
258
  mainWindow: BrowserWindow;
@@ -255,6 +267,8 @@ export interface CreateContextOptions extends Pick<WorkbenchConfig, 'adapter' |
255
267
  builtinTemplates?: 'all' | 'none' | readonly string[];
256
268
  /** Host-supplied "新建项目" dialog hook. */
257
269
  customCreateProjectDialog?: WorkbenchContext['customCreateProjectDialog'];
270
+ /** Host-supplied "编辑项目" dialog hook. */
271
+ customEditProjectDialog?: WorkbenchContext['customEditProjectDialog'];
258
272
  /** Host permission gate run before a project opens (throw to veto). */
259
273
  onBeforeOpenProject?: WorkbenchContext['onBeforeOpenProject'];
260
274
  }
@@ -74,6 +74,7 @@ export function createWorkbenchContext(opts) {
74
74
  ctx.projectsProvider = opts.projectsProvider ?? createLocalProjectsProvider();
75
75
  ctx.projectTemplates = resolveTemplates(BUILTIN_TEMPLATES, opts.projectTemplates ?? [], opts.builtinTemplates ?? 'all');
76
76
  ctx.customCreateProjectDialog = opts.customCreateProjectDialog;
77
+ ctx.customEditProjectDialog = opts.customEditProjectDialog;
77
78
  ctx.onBeforeOpenProject = opts.onBeforeOpenProject;
78
79
  ctx.workspace = createWorkspaceService(ctx);
79
80
  ctx.senderPolicy = createWorkbenchSenderPolicy(ctx);
@@ -1,6 +1,7 @@
1
1
  import type { AppInfo, CompileConfig, ProjectSession } from '../../../shared/types.js';
2
2
  import type { WorkbenchContext } from '../workbench-context.js';
3
3
  import type { Project, ProjectPages, ProjectSettings } from '../projects/project-repository.js';
4
+ import type { ProjectPatch } from '../projects/types.js';
4
5
  /**
5
6
  * Result returned to the renderer after `project:open` finishes.
6
7
  * Mirrors the previous inline shape in ipc/session.ts so no
@@ -28,6 +29,7 @@ export interface WorkspaceService {
28
29
  listProjects(): Promise<Project[]>;
29
30
  addProject(dirPath: string): Promise<Project>;
30
31
  removeProject(dirPath: string): Promise<void>;
32
+ updateProject(dirPath: string, patch: ProjectPatch): Promise<Project>;
31
33
  hasProject(dirPath: string): Promise<boolean>;
32
34
  validateProjectDir(dirPath: string): Promise<string | null>;
33
35
  openProject(projectPath: string): Promise<OpenProjectResult>;
@@ -158,6 +158,20 @@ export function createWorkspaceService(ctx) {
158
158
  removeProject: async (dirPath) => {
159
159
  await provider.removeProject(dirPath);
160
160
  },
161
+ updateProject: async (dirPath, patch) => {
162
+ const projects = await provider.listProjects();
163
+ const existing = projects.find((p) => p.path === dirPath);
164
+ if (!existing)
165
+ throw new Error(`No such project: ${dirPath}`);
166
+ // A provider without `updateProject` cannot persist the edit. Returning
167
+ // the record unchanged would look like a successful save to the
168
+ // renderer (dialog closes, list reloads) while silently discarding the
169
+ // user's input, so this must fail loudly instead.
170
+ if (!provider.updateProject) {
171
+ throw new Error('当前宿主不支持编辑项目');
172
+ }
173
+ return provider.updateProject(dirPath, patch);
174
+ },
161
175
  hasProject: async (dirPath) => {
162
176
  const projects = await provider.listProjects();
163
177
  return projects.some((p) => p.path === dirPath);
@@ -31,6 +31,10 @@ export declare const mainPreloadPath: string;
31
31
  * npm/pnpm node_modules and ASAR packaging alike get an absolute, correct path.
32
32
  */
33
33
  export declare const hostToolbarRuntimePreloadPath: string;
34
+ /** Session-registered sidebar-runtime preload bundle, mirroring {@link hostToolbarRuntimePreloadPath}. */
35
+ export declare const hostSidebarRuntimePreloadPath: string;
36
+ /** Session-registered dialog-runtime preload bundle, mirroring {@link hostToolbarRuntimePreloadPath}. */
37
+ export declare const hostDialogRuntimePreloadPath: string;
34
38
  export declare const simulatorDir: string;
35
39
  /**
36
40
  * DevTools builds its own copy of every native mini-app runtime asset. Pin the
@@ -59,6 +59,10 @@ export const mainPreloadPath = path.join(devtoolsPackageRoot, 'dist/preload/wind
59
59
  * npm/pnpm node_modules and ASAR packaging alike get an absolute, correct path.
60
60
  */
61
61
  export const hostToolbarRuntimePreloadPath = path.join(devtoolsPackageRoot, 'dist/preload/windows/host-toolbar-runtime.cjs');
62
+ /** Session-registered sidebar-runtime preload bundle, mirroring {@link hostToolbarRuntimePreloadPath}. */
63
+ export const hostSidebarRuntimePreloadPath = path.join(devtoolsPackageRoot, 'dist/preload/windows/host-sidebar-runtime.cjs');
64
+ /** Session-registered dialog-runtime preload bundle, mirroring {@link hostToolbarRuntimePreloadPath}. */
65
+ export const hostDialogRuntimePreloadPath = path.join(devtoolsPackageRoot, 'dist/preload/windows/host-dialog-runtime.cjs');
62
66
  export const simulatorDir = path.join(devtoolsPackageRoot, 'dist/simulator');
63
67
  /**
64
68
  * DevTools builds its own copy of every native mini-app runtime asset. Pin the
@@ -54,6 +54,16 @@ export function createWorkbenchSenderPolicy(ctx) {
54
54
  const tooltipViewId = ctx.views.getTooltipWebContentsId();
55
55
  if (tooltipViewId != null && sender.id === tooltipViewId)
56
56
  return true;
57
+ // Project-create-dialog overlay view. Devtools-owned bundled renderer
58
+ // (the WCV that replaced the Radix DOM-portal dialog), same trust level
59
+ // as settings/popover/tooltip.
60
+ const projectCreateDialogViewId = ctx.views.getProjectCreateDialogWebContentsId();
61
+ if (projectCreateDialogViewId != null && sender.id === projectCreateDialogViewId)
62
+ return true;
63
+ // Update-available overlay view. Same devtools-owned trust level.
64
+ const updateDialogViewId = ctx.views.getUpdateDialogWebContentsId();
65
+ if (updateDialogViewId != null && sender.id === updateDialogViewId)
66
+ return true;
57
67
  // The host-toolbar overlay is DELIBERATELY NOT trusted here. The host loads
58
68
  // arbitrary content into it, so granting it the global white-list would open
59
69
  // all ~72 IpcRegistry channels to that content. Its one channel (the reverse