@dimina-kit/devtools 0.4.0-dev.20260701083540 → 0.4.0-dev.20260701155140

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 (50) hide show
  1. package/dist/main/app/app.js +11 -0
  2. package/dist/main/app/max-listeners-diagnostic.d.ts +32 -0
  3. package/dist/main/app/max-listeners-diagnostic.js +59 -0
  4. package/dist/main/index.bundle.js +423 -220
  5. package/dist/main/ipc/bridge-router.d.ts +5 -4
  6. package/dist/main/ipc/bridge-router.js +25 -1
  7. package/dist/main/ipc/simulator.js +1 -5
  8. package/dist/main/ipc/views.js +8 -19
  9. package/dist/main/services/automation/wait-active-page.d.ts +4 -2
  10. package/dist/main/services/render-inspect/index.d.ts +9 -0
  11. package/dist/main/services/render-inspect/index.js +13 -1
  12. package/dist/main/services/simulator-storage/index.d.ts +9 -0
  13. package/dist/main/services/simulator-storage/index.js +26 -1
  14. package/dist/main/services/simulator-wxml/index.js +117 -11
  15. package/dist/main/services/views/apply-view-ops.d.ts +11 -0
  16. package/dist/main/services/views/apply-view-ops.js +22 -0
  17. package/dist/main/services/views/placement-test-driver.d.ts +25 -0
  18. package/dist/main/services/views/placement-test-driver.js +48 -0
  19. package/dist/main/services/views/view-manager.d.ts +9 -55
  20. package/dist/main/services/views/view-manager.js +264 -233
  21. package/dist/main/services/workbench-context.d.ts +10 -0
  22. package/dist/preload/windows/host-toolbar-runtime.cjs +6 -13
  23. package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
  24. package/dist/preload/windows/simulator.cjs +0 -3
  25. package/dist/preload/windows/simulator.cjs.map +2 -2
  26. package/dist/preload/windows/simulator.js +0 -3
  27. package/dist/render-host/render-inspect.js +35 -1
  28. package/dist/renderer/assets/index-jDrNHghH.js +49 -0
  29. package/dist/renderer/assets/{input-DR7bfyQE.js → input-Djg2NR4U.js} +2 -2
  30. package/dist/renderer/assets/{ipc-transport-3Arg8jPC.js → ipc-transport-Be-AzCub.js} +2 -2
  31. package/dist/renderer/assets/ipc-transport-C6-KPMqw.css +1 -0
  32. package/dist/renderer/assets/{popover-CPZX3MrT.js → popover-eDUh4NYe.js} +2 -2
  33. package/dist/renderer/assets/{select-BxyPlVyJ.js → select-DesFfkVV.js} +2 -2
  34. package/dist/renderer/assets/{settings-CG_OR03F.js → settings-CRmO7zUG.js} +2 -2
  35. package/dist/renderer/assets/{settings-api-CtPPJF-F.js → settings-api-HQ7ZFPWi.js} +2 -2
  36. package/dist/renderer/assets/{workbenchSettings-ClqCBGOa.js → workbenchSettings-CZBWsliT.js} +2 -2
  37. package/dist/renderer/entries/main/index.html +6 -6
  38. package/dist/renderer/entries/popover/index.html +5 -5
  39. package/dist/renderer/entries/settings/index.html +5 -5
  40. package/dist/renderer/entries/workbench-settings/index.html +4 -4
  41. package/dist/service-host/sync-api-patch.js +33 -3
  42. package/dist/shared/ipc-channels.d.ts +28 -14
  43. package/dist/shared/ipc-channels.js +10 -17
  44. package/dist/shared/ipc-schemas.d.ts +21 -19
  45. package/dist/shared/ipc-schemas.js +32 -26
  46. package/dist/shared/view-ids.d.ts +19 -0
  47. package/dist/shared/view-ids.js +25 -0
  48. package/package.json +5 -5
  49. package/dist/renderer/assets/index-HE9Xr9bQ.js +0 -49
  50. package/dist/renderer/assets/ipc-transport-Dt0jR7Ir.css +0 -1
@@ -108,6 +108,39 @@ function setupCdpPort() {
108
108
  }
109
109
  }
110
110
 
111
+ // src/main/app/max-listeners-diagnostic.ts
112
+ function callSafe(fn) {
113
+ try {
114
+ return fn();
115
+ } catch {
116
+ return void 0;
117
+ }
118
+ }
119
+ function describeMaxListenersWarning(warning) {
120
+ if (warning.name !== "MaxListenersExceededWarning") return null;
121
+ const w = warning;
122
+ const emitter = w.emitter ?? void 0;
123
+ return {
124
+ event: w.type,
125
+ count: w.count,
126
+ wcId: typeof emitter?.id === "number" ? emitter.id : void 0,
127
+ wcType: callSafe(() => emitter?.getType?.()),
128
+ url: callSafe(() => emitter?.getURL?.()),
129
+ destroyed: callSafe(() => emitter?.isDestroyed?.()),
130
+ stack: warning.stack
131
+ };
132
+ }
133
+ function installMaxListenersWarningDiagnostic(log3 = (r) => console.warn("[max-listeners]", r)) {
134
+ const onWarning = (warning) => {
135
+ const report = describeMaxListenersWarning(warning);
136
+ if (report) log3(report);
137
+ };
138
+ process.on("warning", onWarning);
139
+ return () => {
140
+ process.removeListener("warning", onWarning);
141
+ };
142
+ }
143
+
111
144
  // src/main/ipc/project-fs.ts
112
145
  import fs2 from "node:fs/promises";
113
146
  import nodeFs from "node:fs";
@@ -306,9 +339,6 @@ var SimulatorChannel = {
306
339
  // Ask main to create the simulator as a top-level WebContentsView (so nested
307
340
  // render-host <webview>s can attach). Native-host is the sole runtime.
308
341
  AttachNative: "simulator:attach-native",
309
- // Renderer reports the device-bezel inner-screen rect (CSS px from content
310
- // top-left) + zoom so main can overlay the simulator WCV on it.
311
- SetNativeBounds: "simulator:set-native-bounds",
312
342
  // Renderer pushes the selected device's LOGICAL metrics (screen size,
313
343
  // pixelRatio, statusBarHeight, …) when the device dropdown changes. Main
314
344
  // maps it to a HostEnvSnapshot and live-updates the running service-host
@@ -353,7 +383,11 @@ var SimulatorElementChannel = {
353
383
  };
354
384
  var SimulatorWxmlChannel = {
355
385
  GetSnapshot: "simulator:wxml:snapshot",
356
- Event: "simulator:wxml:event"
386
+ Event: "simulator:wxml:event",
387
+ // renderer→main: whether the WXML panel is currently visible/active. Main
388
+ // only installs the render-guest DOM MutationObserver + pushes live tree
389
+ // updates while active, so an unseen panel never drives a full Vue-tree walk.
390
+ SetActive: "simulator:wxml:setActive"
357
391
  };
358
392
  var SimulatorAppDataChannel = {
359
393
  GetSnapshot: "simulator:appdata:snapshot",
@@ -423,14 +457,6 @@ var DialogChannel = {
423
457
  OpenDirectory: "dialog:openDirectory"
424
458
  };
425
459
  var ViewChannel = {
426
- /** Update the simulator DevTools view's bounds (or hide if w/h = 0). */
427
- SimulatorDevtoolsBounds: "view:simulator:devtools-bounds",
428
- /**
429
- * Host-controllable toolbar WebContentsView (sits ABOVE the devtools built-in
430
- * header). Forward anchor: the main renderer reports the toolbar placeholder's
431
- * bounds (or w/h=0 to hide). invoke.
432
- */
433
- HostToolbarBounds: "view:host-toolbar:bounds",
434
460
  /**
435
461
  * Reverse size-advertiser: the host-toolbar WCV's OWN renderer advertises its
436
462
  * intrinsic content height so main reserves exactly that much. Payload
@@ -463,12 +489,13 @@ var ViewChannel = {
463
489
  */
464
490
  HostToolbarGetHeight: "view:host-toolbar:get-height",
465
491
  /**
466
- * Update the embedded workbench editor view's bounds (or hide if w/h=0).
467
- * Forward anchor mirroring `SimulatorDevtoolsBounds`: the main renderer
468
- * measures the 'editor' dock slot's placeholder rect and publishes it so
469
- * main overlays the workbench WebContentsView precisely.
492
+ * Renderer main: the window-level placement snapshot (one monotonic epoch
493
+ * per commit tick, one generation per renderer lifetime) that drives the view
494
+ * reconciler. The single source of truth for every managed native view's
495
+ * bounds/visibility/z-order supersedes the per-view bounds channels above.
496
+ * invoke.
470
497
  */
471
- WorkbenchBounds: "view:workbench-bounds"
498
+ PlacementSnapshot: "view:placement-snapshot"
472
499
  };
473
500
  var PopoverChannel = {
474
501
  Show: "popover:show",
@@ -2411,6 +2438,48 @@ function parseRoute(url) {
2411
2438
  }
2412
2439
  }
2413
2440
 
2441
+ // src/main/services/views/view-manager.ts
2442
+ import { reconcile, createInitialState } from "@dimina-kit/electron-deck/layout";
2443
+
2444
+ // src/main/services/views/apply-view-ops.ts
2445
+ function applyViewOps(ops, target) {
2446
+ for (const op of ops) {
2447
+ switch (op.kind) {
2448
+ case "detach":
2449
+ target.detach(op.viewId);
2450
+ break;
2451
+ case "setVisible":
2452
+ target.setVisible(op.viewId, op.visible);
2453
+ break;
2454
+ case "setBounds":
2455
+ target.setBounds(op.viewId, op.bounds, op.extra);
2456
+ break;
2457
+ case "attach":
2458
+ target.attach(op.viewId);
2459
+ break;
2460
+ case "reorder":
2461
+ target.reorder(op.order);
2462
+ break;
2463
+ }
2464
+ }
2465
+ }
2466
+
2467
+ // src/shared/view-ids.ts
2468
+ var VIEW_ID = {
2469
+ simulator: "simulator",
2470
+ simulatorDevtools: "simulator-devtools",
2471
+ workbench: "workbench",
2472
+ hostToolbar: "host-toolbar",
2473
+ settings: "settings",
2474
+ popover: "popover"
2475
+ };
2476
+ var VIEW_LAYER = {
2477
+ base: 0,
2478
+ hostToolbar: 5,
2479
+ settings: 10,
2480
+ popover: 20
2481
+ };
2482
+
2414
2483
  // src/main/services/views/view-manager.ts
2415
2484
  function resolveProjectEditorTarget(serviceHostUrl, activeProjectRoot, req, isFile = (absolutePath) => fs4.statSync(absolutePath).isFile()) {
2416
2485
  const sourceContext = projectSourceContextFromServiceHostUrl(
@@ -2434,6 +2503,15 @@ function resolveProjectEditorTarget(serviceHostUrl, activeProjectRoot, req, isFi
2434
2503
  column: typeof req.column === "number" ? req.column + 1 : void 0
2435
2504
  };
2436
2505
  }
2506
+ var DEVTOOLS_HOST_EXEC_JS_MAX_LISTENERS = 50;
2507
+ function raiseExecuteJavaScriptListenerCeiling(wc) {
2508
+ try {
2509
+ if (wc.isDestroyed()) return;
2510
+ if (wc.getMaxListeners() >= DEVTOOLS_HOST_EXEC_JS_MAX_LISTENERS) return;
2511
+ wc.setMaxListeners(DEVTOOLS_HOST_EXEC_JS_MAX_LISTENERS);
2512
+ } catch {
2513
+ }
2514
+ }
2437
2515
  function createViewManager(ctx) {
2438
2516
  const safeArea = createSafeAreaController({ connections: ctx.connections });
2439
2517
  let simulatorView = null;
@@ -2442,11 +2520,9 @@ function createViewManager(ctx) {
2442
2520
  let nativeSimulatorViewAdded = false;
2443
2521
  let nativeSimulatorProjectPath = null;
2444
2522
  let settleNativeSimulatorReady = null;
2445
- let lastRendererRect = null;
2446
2523
  let nativeCustomApiBridgeHandler = null;
2447
2524
  let currentZoomFactor = 1;
2448
2525
  let settingsView = null;
2449
- let settingsViewAdded = false;
2450
2526
  let popoverView = null;
2451
2527
  let simulatorWebContentsId = null;
2452
2528
  let nativeDevtoolsSourceWc = null;
@@ -2455,9 +2531,7 @@ function createViewManager(ctx) {
2455
2531
  let stopServiceConsole = null;
2456
2532
  let nativeDevtoolsRetryTimer = null;
2457
2533
  let nativeDevtoolsRetryToken = 0;
2458
- let simulatorBoundsOverride = null;
2459
2534
  let workbenchView = null;
2460
- let workbenchViewAdded = false;
2461
2535
  let workbenchThemeSyncBound = false;
2462
2536
  let workbenchUrl = null;
2463
2537
  let hostToolbarView = null;
@@ -2484,29 +2558,148 @@ function createViewManager(ctx) {
2484
2558
  } catch {
2485
2559
  }
2486
2560
  }
2487
- function isHidden(b) {
2488
- return b.width <= 0 || b.height <= 0;
2561
+ let placementState = createInitialState();
2562
+ let epochCounter = 0;
2563
+ let rendererGeneration = 0;
2564
+ const baseDesired = /* @__PURE__ */ new Map();
2565
+ const overlayDesired = /* @__PURE__ */ new Map();
2566
+ function gateReadiness(v) {
2567
+ if (v.viewId === VIEW_ID.simulator && !nativeSimulatorView)
2568
+ return { ...v, placement: { visible: false } };
2569
+ if (v.viewId === VIEW_ID.simulatorDevtools && !simulatorView)
2570
+ return { ...v, placement: { visible: false } };
2571
+ if (v.viewId === VIEW_ID.workbench && !workbenchView && !workbenchUrl)
2572
+ return { ...v, placement: { visible: false } };
2573
+ return v;
2574
+ }
2575
+ function resolveView(viewId) {
2576
+ switch (viewId) {
2577
+ case VIEW_ID.simulator:
2578
+ return nativeSimulatorView;
2579
+ case VIEW_ID.simulatorDevtools:
2580
+ return simulatorView;
2581
+ case VIEW_ID.workbench:
2582
+ return workbenchView;
2583
+ case VIEW_ID.hostToolbar:
2584
+ return hostToolbarView;
2585
+ case VIEW_ID.settings:
2586
+ return settingsView;
2587
+ case VIEW_ID.popover:
2588
+ return popoverView;
2589
+ default:
2590
+ return null;
2591
+ }
2489
2592
  }
2490
- function setSimulatorDevtoolsBounds(bounds) {
2491
- simulatorBoundsOverride = bounds;
2492
- if (!simulatorView || simulatorView.webContents.isDestroyed()) return;
2493
- if (ctx.windows.mainWindow.isDestroyed()) return;
2494
- if (isHidden(bounds)) {
2495
- if (simulatorViewAdded) {
2593
+ function markAdded(viewId, added) {
2594
+ switch (viewId) {
2595
+ case VIEW_ID.simulator:
2596
+ nativeSimulatorViewAdded = added;
2597
+ break;
2598
+ case VIEW_ID.simulatorDevtools:
2599
+ simulatorViewAdded = added;
2600
+ break;
2601
+ case VIEW_ID.hostToolbar:
2602
+ hostToolbarViewAdded = added;
2603
+ break;
2604
+ }
2605
+ }
2606
+ function applyNativeSimulatorBounds(view, bounds, zoom) {
2607
+ const p = computeNativeSimulatorViewParams(bounds, zoom);
2608
+ currentZoomFactor = p.zoomFactor;
2609
+ view.setBounds(p.bounds);
2610
+ const simWc = view.webContents;
2611
+ if (!simWc.isDestroyed()) simWc.setZoomFactor(p.zoomFactor);
2612
+ try {
2613
+ for (const wc of webContents.getAllWebContents()) {
2614
+ if (wc.isDestroyed()) continue;
2615
+ if (wc.hostWebContents === simWc) wc.setZoomFactor(p.zoomFactor);
2616
+ }
2617
+ } catch {
2618
+ }
2619
+ }
2620
+ const viewTarget = {
2621
+ attach(viewId) {
2622
+ if (ctx.windows.mainWindow.isDestroyed()) return;
2623
+ if (viewId === VIEW_ID.workbench && !workbenchView && workbenchUrl) {
2624
+ void attachWorkbench(workbenchUrl);
2625
+ return;
2626
+ }
2627
+ if (viewId === VIEW_ID.hostToolbar) {
2628
+ const view2 = ensureHostToolbarView();
2629
+ ctx.windows.mainWindow.contentView.addChildView(view2);
2630
+ hostToolbarViewAdded = true;
2631
+ return;
2632
+ }
2633
+ const view = resolveView(viewId);
2634
+ if (!view) return;
2635
+ ctx.windows.mainWindow.contentView.addChildView(view);
2636
+ markAdded(viewId, true);
2637
+ },
2638
+ detach(viewId) {
2639
+ const view = resolveView(viewId);
2640
+ if (view && !ctx.windows.mainWindow.isDestroyed()) {
2496
2641
  try {
2497
- ctx.windows.mainWindow.contentView.removeChildView(simulatorView);
2642
+ ctx.windows.mainWindow.contentView.removeChildView(view);
2498
2643
  } catch {
2499
2644
  }
2500
- simulatorViewAdded = false;
2501
2645
  }
2502
- return;
2503
- }
2504
- if (!simulatorViewAdded) {
2505
- ctx.windows.mainWindow.contentView.addChildView(simulatorView);
2506
- simulatorViewAdded = true;
2507
- raiseTopOverlays();
2646
+ markAdded(viewId, false);
2647
+ },
2648
+ setBounds(viewId, bounds, extra) {
2649
+ const view = resolveView(viewId);
2650
+ if (!view || view.webContents.isDestroyed()) return;
2651
+ if (viewId === VIEW_ID.simulator) {
2652
+ applyNativeSimulatorBounds(view, bounds, extra?.zoom ?? 1);
2653
+ return;
2654
+ }
2655
+ view.setBounds(bounds);
2656
+ },
2657
+ setVisible(viewId, visible) {
2658
+ const view = resolveView(viewId);
2659
+ if (!view) return;
2660
+ try {
2661
+ view.setVisible(visible);
2662
+ } catch {
2663
+ }
2664
+ },
2665
+ reorder(order) {
2666
+ if (order.length <= 1 || ctx.windows.mainWindow.isDestroyed()) return;
2667
+ const cv = ctx.windows.mainWindow.contentView;
2668
+ for (const viewId of order) {
2669
+ const view = resolveView(viewId);
2670
+ if (view) {
2671
+ try {
2672
+ cv.addChildView(view);
2673
+ } catch {
2674
+ }
2675
+ }
2676
+ }
2508
2677
  }
2509
- simulatorView.setBounds(bounds);
2678
+ };
2679
+ function ensureLazyViews() {
2680
+ const ht = baseDesired.get(VIEW_ID.hostToolbar);
2681
+ if (ht?.placement.visible && !liveHostToolbarWebContents()) ensureHostToolbarView();
2682
+ const wb = baseDesired.get(VIEW_ID.workbench);
2683
+ if (wb?.placement.visible && !workbenchView && workbenchUrl) void attachWorkbench(workbenchUrl);
2684
+ }
2685
+ function reconcileNow() {
2686
+ ensureLazyViews();
2687
+ const views = [];
2688
+ for (const v of baseDesired.values()) views.push(gateReadiness(v));
2689
+ for (const v of overlayDesired.values()) views.push(v);
2690
+ const result = reconcile(placementState, {
2691
+ generation: rendererGeneration,
2692
+ epoch: ++epochCounter,
2693
+ views
2694
+ });
2695
+ placementState = result.state;
2696
+ applyViewOps(result.ops, viewTarget);
2697
+ }
2698
+ function setPlacementSnapshot(snapshot) {
2699
+ rendererGeneration = snapshot.generation;
2700
+ baseDesired.clear();
2701
+ for (const v of snapshot.views) baseDesired.set(v.viewId, v);
2702
+ reconcileNow();
2510
2703
  }
2511
2704
  function workbenchThemeScheme() {
2512
2705
  return nativeTheme3.shouldUseDarkColors ? "dark" : "light";
@@ -2538,8 +2731,6 @@ function createViewManager(ctx) {
2538
2731
  } catch {
2539
2732
  }
2540
2733
  ctx.windows.mainWindow.contentView.addChildView(view);
2541
- workbenchViewAdded = true;
2542
- raiseTopOverlays();
2543
2734
  const loadUrl = `${url}index.html?theme=${workbenchThemeScheme()}`;
2544
2735
  await view.webContents.loadURL(loadUrl).catch((err) => {
2545
2736
  console.error("[workbench] attachWorkbench \u2014 loadURL failed", err);
@@ -2548,29 +2739,6 @@ function createViewManager(ctx) {
2548
2739
  function setWorkbenchSource(url) {
2549
2740
  workbenchUrl = url;
2550
2741
  }
2551
- function setWorkbenchBounds(bounds) {
2552
- if (ctx.windows.mainWindow.isDestroyed()) return;
2553
- if (isHidden(bounds)) {
2554
- if (workbenchView && workbenchViewAdded && !workbenchView.webContents.isDestroyed()) {
2555
- try {
2556
- ctx.windows.mainWindow.contentView.removeChildView(workbenchView);
2557
- } catch {
2558
- }
2559
- workbenchViewAdded = false;
2560
- }
2561
- return;
2562
- }
2563
- if (!workbenchView && workbenchUrl) {
2564
- void attachWorkbench(workbenchUrl);
2565
- }
2566
- if (!workbenchView || workbenchView.webContents.isDestroyed()) return;
2567
- if (!workbenchViewAdded) {
2568
- ctx.windows.mainWindow.contentView.addChildView(workbenchView);
2569
- workbenchViewAdded = true;
2570
- raiseTopOverlays();
2571
- }
2572
- workbenchView.setBounds(bounds);
2573
- }
2574
2742
  function detachWorkbench() {
2575
2743
  if (workbenchThemeSyncBound) {
2576
2744
  nativeTheme3.removeListener("updated", pushWorkbenchTheme);
@@ -2578,7 +2746,8 @@ function createViewManager(ctx) {
2578
2746
  }
2579
2747
  destroyViewInternal(workbenchView);
2580
2748
  workbenchView = null;
2581
- workbenchViewAdded = false;
2749
+ baseDesired.delete(VIEW_ID.workbench);
2750
+ reconcileNow();
2582
2751
  }
2583
2752
  function workspaceUriFor(rel) {
2584
2753
  const encoded = rel.split("/").map(encodeURIComponent).join("/");
@@ -2632,6 +2801,7 @@ function createViewManager(ctx) {
2632
2801
  }
2633
2802
  hostToolbarViewAdded = false;
2634
2803
  }
2804
+ placementState.actual.delete(VIEW_ID.hostToolbar);
2635
2805
  if (!hostToolbarRuntimeAcquired) {
2636
2806
  acquireHostToolbarSessionRuntime();
2637
2807
  hostToolbarRuntimeAcquired = true;
@@ -2658,43 +2828,23 @@ function createViewManager(ctx) {
2658
2828
  }
2659
2829
  return view;
2660
2830
  }
2661
- function setHostToolbarBounds(bounds) {
2662
- if (ctx.windows.mainWindow.isDestroyed()) return;
2663
- if (isHidden(bounds)) {
2664
- if (hostToolbarView && hostToolbarViewAdded && liveHostToolbarWebContents()) {
2665
- try {
2666
- ctx.windows.mainWindow.contentView.removeChildView(hostToolbarView);
2667
- } catch {
2668
- }
2669
- }
2670
- hostToolbarViewAdded = false;
2671
- return;
2672
- }
2673
- const view = ensureHostToolbarView();
2674
- if (!hostToolbarViewAdded) {
2675
- ctx.windows.mainWindow.contentView.addChildView(view);
2676
- hostToolbarViewAdded = true;
2677
- }
2678
- view.setBounds(bounds);
2679
- }
2680
2831
  function notifyHostToolbarHeight(height) {
2681
2832
  hostToolbarLastHeight = height;
2682
2833
  ctx.notify.hostToolbarHeightChanged(height);
2683
- if (settingsViewAdded) applySettingsBounds();
2684
- if (popoverView) applyPopoverBounds();
2834
+ if (overlayDesired.has(VIEW_ID.settings)) applySettingsBounds();
2835
+ if (overlayDesired.has(VIEW_ID.popover)) applyPopoverBounds();
2685
2836
  }
2686
2837
  function setHostToolbarHeight(extent) {
2687
2838
  if (hostToolbarHeightMode !== "auto") return;
2688
2839
  notifyHostToolbarHeight(extent);
2689
2840
  }
2690
2841
  function hideHostToolbar() {
2691
- if (hostToolbarView && hostToolbarViewAdded && !ctx.windows.mainWindow.isDestroyed()) {
2692
- try {
2693
- ctx.windows.mainWindow.contentView.removeChildView(hostToolbarView);
2694
- } catch {
2695
- }
2696
- }
2697
- hostToolbarViewAdded = false;
2842
+ baseDesired.set(VIEW_ID.hostToolbar, {
2843
+ viewId: VIEW_ID.hostToolbar,
2844
+ placement: { visible: false },
2845
+ layer: VIEW_LAYER.hostToolbar
2846
+ });
2847
+ reconcileNow();
2698
2848
  notifyHostToolbarHeight(0);
2699
2849
  }
2700
2850
  const hostToolbar = {
@@ -2744,12 +2894,28 @@ function createViewManager(ctx) {
2744
2894
  function applySettingsBounds() {
2745
2895
  if (!settingsView || ctx.windows.mainWindow.isDestroyed()) return;
2746
2896
  const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
2747
- settingsView.setBounds(computeSettingsBounds(w, h, overlayHeaderHeight()));
2897
+ overlayDesired.set(VIEW_ID.settings, {
2898
+ viewId: VIEW_ID.settings,
2899
+ placement: {
2900
+ visible: true,
2901
+ bounds: computeSettingsBounds(w, h, overlayHeaderHeight())
2902
+ },
2903
+ layer: VIEW_LAYER.settings
2904
+ });
2905
+ reconcileNow();
2748
2906
  }
2749
2907
  function applyPopoverBounds() {
2750
2908
  if (!popoverView || ctx.windows.mainWindow.isDestroyed()) return;
2751
2909
  const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
2752
- popoverView.setBounds(computePopoverBounds(w, h, overlayHeaderHeight()));
2910
+ overlayDesired.set(VIEW_ID.popover, {
2911
+ viewId: VIEW_ID.popover,
2912
+ placement: {
2913
+ visible: true,
2914
+ bounds: computePopoverBounds(w, h, overlayHeaderHeight())
2915
+ },
2916
+ layer: VIEW_LAYER.popover
2917
+ });
2918
+ reconcileNow();
2753
2919
  }
2754
2920
  function clearNativeDevtoolsRetry() {
2755
2921
  nativeDevtoolsRetryToken++;
@@ -2921,6 +3087,7 @@ function createViewManager(ctx) {
2921
3087
  }
2922
3088
  simulatorView = new WebContentsView2();
2923
3089
  const devtoolsWc = simulatorView.webContents;
3090
+ raiseExecuteJavaScriptListenerCeiling(devtoolsWc);
2924
3091
  ctx.networkForward?.setDevtoolsHost(devtoolsWc);
2925
3092
  if (ctx.bridge) {
2926
3093
  try {
@@ -2961,11 +3128,7 @@ function createViewManager(ctx) {
2961
3128
  `).catch(() => {
2962
3129
  });
2963
3130
  });
2964
- if (simulatorBoundsOverride && !isHidden(simulatorBoundsOverride)) {
2965
- ctx.windows.mainWindow.contentView.addChildView(simulatorView);
2966
- simulatorViewAdded = true;
2967
- simulatorView.setBounds(simulatorBoundsOverride);
2968
- }
3131
+ reconcileNow();
2969
3132
  if (ctx.bridge?.isNativeHost()) {
2970
3133
  unsubscribeNativeRenderEvents = ctx.bridge.onRenderEvent(onNativeRenderEvent);
2971
3134
  followNativeDevtoolsServiceHost();
@@ -2994,6 +3157,7 @@ function createViewManager(ctx) {
2994
3157
  }
2995
3158
  nativeSimulatorView = null;
2996
3159
  nativeSimulatorViewAdded = false;
3160
+ reconcileNow();
2997
3161
  }
2998
3162
  function attachNativeCustomApiBridge(simWc) {
2999
3163
  detachNativeCustomApiBridge();
@@ -3122,9 +3286,7 @@ function createViewManager(ctx) {
3122
3286
  });
3123
3287
  simulatorWebContentsId = simWc.id;
3124
3288
  ctx.networkForward?.attachSimulator(simWc);
3125
- if (lastRendererRect) {
3126
- setNativeSimulatorViewBounds(lastRendererRect);
3127
- }
3289
+ reconcileNow();
3128
3290
  attachNativeSimulatorDevtoolsHost();
3129
3291
  return ready;
3130
3292
  }
@@ -3144,14 +3306,11 @@ function createViewManager(ctx) {
3144
3306
  hidePopover();
3145
3307
  destroyViewInternal(settingsView);
3146
3308
  settingsView = null;
3147
- settingsViewAdded = false;
3148
3309
  destroyViewInternal(simulatorView);
3149
3310
  simulatorView = null;
3150
3311
  simulatorViewAdded = false;
3151
3312
  simulatorWebContentsId = null;
3152
3313
  nativeSimulatorProjectPath = null;
3153
- simulatorBoundsOverride = null;
3154
- lastRendererRect = null;
3155
3314
  }
3156
3315
  function removeSimulatorDevtoolsView() {
3157
3316
  if (simulatorView && simulatorViewAdded) {
@@ -3179,26 +3338,11 @@ function createViewManager(ctx) {
3179
3338
  path7.join(ctx.rendererDir, "entries/settings/index.html")
3180
3339
  );
3181
3340
  }
3182
- if (!settingsViewAdded) {
3183
- ctx.windows.mainWindow.contentView.addChildView(settingsView);
3184
- settingsViewAdded = true;
3185
- }
3186
3341
  applySettingsBounds();
3187
3342
  }
3188
3343
  function hideSettings() {
3189
- if (settingsView && settingsViewAdded) {
3190
- try {
3191
- ctx.windows.mainWindow.contentView.removeChildView(settingsView);
3192
- } catch {
3193
- }
3194
- settingsViewAdded = false;
3195
- }
3196
- }
3197
- function raiseTopOverlays() {
3198
- if (ctx.windows.mainWindow.isDestroyed()) return;
3199
- const cv = ctx.windows.mainWindow.contentView;
3200
- if (settingsView && settingsViewAdded) cv.addChildView(settingsView);
3201
- if (popoverView) cv.addChildView(popoverView);
3344
+ overlayDesired.delete(VIEW_ID.settings);
3345
+ reconcileNow();
3202
3346
  }
3203
3347
  function showPopover(data) {
3204
3348
  hidePopover();
@@ -3213,7 +3357,6 @@ function createViewManager(ctx) {
3213
3357
  applyNavigationHardening(popover.webContents, ctx.rendererDir);
3214
3358
  popoverView = popover;
3215
3359
  popover.setBackgroundColor("#00000000");
3216
- ctx.windows.mainWindow.contentView.addChildView(popover);
3217
3360
  applyPopoverBounds();
3218
3361
  popover.webContents.once("did-finish-load", () => {
3219
3362
  ctx.notify.popoverInit(popover, data);
@@ -3223,17 +3366,16 @@ function createViewManager(ctx) {
3223
3366
  );
3224
3367
  }
3225
3368
  function hidePopover() {
3226
- if (popoverView) {
3227
- destroyViewInternal(popoverView);
3228
- popoverView = null;
3229
- ctx.notify.popoverClosed();
3230
- }
3369
+ if (!popoverView) return;
3370
+ overlayDesired.delete(VIEW_ID.popover);
3371
+ destroyViewInternal(popoverView);
3372
+ popoverView = null;
3373
+ reconcileNow();
3374
+ ctx.notify.popoverClosed();
3231
3375
  }
3232
3376
  function repositionAll() {
3233
- if (settingsView && settingsViewAdded)
3234
- applySettingsBounds();
3235
- if (popoverView)
3236
- applyPopoverBounds();
3377
+ if (overlayDesired.has(VIEW_ID.settings)) applySettingsBounds();
3378
+ if (overlayDesired.has(VIEW_ID.popover)) applyPopoverBounds();
3237
3379
  }
3238
3380
  function disposeAll() {
3239
3381
  detachSimulator();
@@ -3248,43 +3390,8 @@ function createViewManager(ctx) {
3248
3390
  }
3249
3391
  safeArea.dispose();
3250
3392
  }
3251
- function setNativeSimulatorViewBounds(params) {
3252
- lastRendererRect = params;
3253
- if (ctx.windows.mainWindow.isDestroyed() || !nativeSimulatorView) return;
3254
- const p = computeNativeSimulatorViewParams(params, params.zoom);
3255
- currentZoomFactor = p.zoomFactor;
3256
- if (isHidden(p.bounds)) {
3257
- if (nativeSimulatorViewAdded) {
3258
- try {
3259
- ctx.windows.mainWindow.contentView.removeChildView(nativeSimulatorView);
3260
- } catch {
3261
- }
3262
- nativeSimulatorViewAdded = false;
3263
- }
3264
- return;
3265
- }
3266
- if (!nativeSimulatorViewAdded) {
3267
- ctx.windows.mainWindow.contentView.addChildView(nativeSimulatorView);
3268
- nativeSimulatorViewAdded = true;
3269
- raiseTopOverlays();
3270
- }
3271
- nativeSimulatorView.setBounds(p.bounds);
3272
- const simWc = nativeSimulatorView.webContents;
3273
- if (!simWc.isDestroyed()) {
3274
- simWc.setZoomFactor(p.zoomFactor);
3275
- }
3276
- try {
3277
- for (const wc of webContents.getAllWebContents()) {
3278
- if (wc.isDestroyed()) continue;
3279
- if (wc.hostWebContents === simWc) {
3280
- wc.setZoomFactor(p.zoomFactor);
3281
- }
3282
- }
3283
- } catch {
3284
- }
3285
- }
3286
3393
  function resize(_simWidth) {
3287
- if (settingsViewAdded) applySettingsBounds();
3394
+ if (overlayDesired.has(VIEW_ID.settings)) applySettingsBounds();
3288
3395
  }
3289
3396
  return {
3290
3397
  attachNativeSimulator,
@@ -3320,15 +3427,12 @@ function createViewManager(ctx) {
3320
3427
  },
3321
3428
  getHostToolbarWebContentsId: () => liveHostToolbarWebContents()?.id ?? null,
3322
3429
  getHostToolbarHeight: () => hostToolbarLastHeight,
3323
- setNativeSimulatorViewBounds,
3324
3430
  resize,
3325
- setSimulatorDevtoolsBounds,
3431
+ setPlacementSnapshot,
3326
3432
  attachWorkbench,
3327
3433
  setWorkbenchSource,
3328
- setWorkbenchBounds,
3329
3434
  detachWorkbench,
3330
3435
  openFileInWorkbench,
3331
- setHostToolbarBounds,
3332
3436
  setHostToolbarHeight,
3333
3437
  hostToolbar
3334
3438
  };
@@ -4088,15 +4192,6 @@ var SimulatorAttachNativeSchema = z3.tuple([
4088
4192
  }),
4089
4193
  SimWidth
4090
4194
  ]);
4091
- var SimulatorSetNativeBoundsSchema = z3.tuple([
4092
- z3.object({
4093
- x: z3.number().finite(),
4094
- y: z3.number().finite(),
4095
- width: z3.number().finite(),
4096
- height: z3.number().finite(),
4097
- zoom: z3.number().finite().positive()
4098
- })
4099
- ]);
4100
4195
  var SimulatorSetDeviceInfoSchema = z3.tuple([
4101
4196
  z3.object({
4102
4197
  brand: z3.string().max(64),
@@ -4117,12 +4212,31 @@ var SimulatorSetDeviceInfoSchema = z3.tuple([
4117
4212
  })
4118
4213
  ]);
4119
4214
  var NonNegInt = z3.number().int().min(0).max(1e5);
4120
- var ViewBoundsSchema = z3.tuple([
4215
+ var FiniteNum = z3.number().finite();
4216
+ var PlacementSchema = z3.union([
4121
4217
  z3.object({
4122
- x: NonNegInt,
4123
- y: NonNegInt,
4124
- width: NonNegInt,
4125
- height: NonNegInt
4218
+ visible: z3.literal(true),
4219
+ bounds: z3.object({
4220
+ x: FiniteNum,
4221
+ y: FiniteNum,
4222
+ width: FiniteNum,
4223
+ height: FiniteNum
4224
+ })
4225
+ }),
4226
+ z3.object({ visible: z3.literal(false) })
4227
+ ]);
4228
+ var PlacementSnapshotSchema = z3.tuple([
4229
+ z3.object({
4230
+ generation: z3.number().int().min(0),
4231
+ epoch: z3.number().int().min(0),
4232
+ views: z3.array(
4233
+ z3.object({
4234
+ viewId: z3.string().min(1).max(64),
4235
+ placement: PlacementSchema,
4236
+ layer: z3.number().int(),
4237
+ extra: z3.object({ zoom: z3.number().finite().positive().optional() }).optional()
4238
+ })
4239
+ ).max(64)
4126
4240
  })
4127
4241
  ]);
4128
4242
  var HostToolbarAdvertiseHeightSchema = z3.tuple([
@@ -4244,9 +4358,6 @@ function registerSimulatorIpc(ctx) {
4244
4358
  return ctx.views.attachNativeSimulator(simulatorUrl, simWidth);
4245
4359
  }).handle(SimulatorChannel.Detach, () => {
4246
4360
  ctx.views.detachSimulator();
4247
- }).handle(SimulatorChannel.SetNativeBounds, (_, ...args) => {
4248
- const [p] = validate(SimulatorChannel.SetNativeBounds, SimulatorSetNativeBoundsSchema, args);
4249
- ctx.views.setNativeSimulatorViewBounds(p);
4250
4361
  }).handle(SimulatorChannel.SetDeviceInfo, (_, ...args) => {
4251
4362
  const [device] = validate(SimulatorChannel.SetDeviceInfo, SimulatorSetDeviceInfoSchema, args);
4252
4363
  ctx.bridge?.setDevice(device);
@@ -5618,7 +5729,22 @@ function setupSimulatorStorage(host, options) {
5618
5729
  }
5619
5730
  }
5620
5731
  const storageApi = options.bridge?.isNativeHost() ? { invoke: runtimeInvoke } : null;
5621
- return { dispose: () => registry.dispose(), storageApi };
5732
+ function onSyncStorageChange(appId, change) {
5733
+ if (appId !== getActiveAppId()) return;
5734
+ if (host.isDestroyed()) return;
5735
+ switch (change.op) {
5736
+ case "set":
5737
+ pushSyntheticEvent({ type: "added", key: change.key, newValue: change.value });
5738
+ break;
5739
+ case "remove":
5740
+ pushSyntheticEvent({ type: "removed", key: change.key });
5741
+ break;
5742
+ case "clear":
5743
+ host.send(SimulatorStorageChannel.Event, { type: "cleared" });
5744
+ break;
5745
+ }
5746
+ }
5747
+ return { dispose: () => registry.dispose(), storageApi, onSyncStorageChange };
5622
5748
  }
5623
5749
  function findSimulatorWebContents() {
5624
5750
  for (const wc of wcStatic.getAllWebContents()) {
@@ -6101,7 +6227,8 @@ async function handleSpawn(state, ctx, event, opts) {
6101
6227
  activeBridgeId: null,
6102
6228
  poolEntryId,
6103
6229
  onServiceClosed: null,
6104
- onServiceBoot: null
6230
+ onServiceBoot: null,
6231
+ registryHandle: null
6105
6232
  };
6106
6233
  const rootPage = {
6107
6234
  bridgeId,
@@ -6126,7 +6253,7 @@ async function handleSpawn(state, ctx, event, opts) {
6126
6253
  state.wcIdToAppSessionId.delete(appSession.serviceWc.id);
6127
6254
  }
6128
6255
  });
6129
- ctx.registry.add(() => disposeAppSession(state, appSessionId));
6256
+ appSession.registryHandle = ctx.registry.add(() => disposeAppSession(state, appSessionId));
6130
6257
  const onServiceClosed = () => {
6131
6258
  void disposeAppSession(state, appSessionId, { serviceAlreadyClosed: true });
6132
6259
  };
@@ -6379,6 +6506,12 @@ function handleContainerMsg(ap, page, msg, ctx, state) {
6379
6506
  case "consoleLog":
6380
6507
  ctx.guestConsole?.emit(msg.body);
6381
6508
  break;
6509
+ case "storageChanged":
6510
+ ctx.onServiceStorageChanged?.(ap.appId, msg.body);
6511
+ break;
6512
+ case "wxmlChanged":
6513
+ state.emitRenderEvent({ kind: "domMutated", appId: ap.appId, bridgeId: page.bridgeId });
6514
+ break;
6382
6515
  default:
6383
6516
  break;
6384
6517
  }
@@ -6736,6 +6869,9 @@ async function disposeAppSession(state, appSessionId, opts = {}) {
6736
6869
  const ap = state.appSessions.get(appSessionId);
6737
6870
  if (!ap) return;
6738
6871
  state.appSessions.delete(appSessionId);
6872
+ const registryHandle = ap.registryHandle;
6873
+ ap.registryHandle = null;
6874
+ void registryHandle?.dispose();
6739
6875
  state.appLifecycle.dispose(appSessionId);
6740
6876
  state.evictAppDataBridges(ap);
6741
6877
  for (const [requestId, pending] of state.pendingApiCalls) {
@@ -6893,27 +7029,13 @@ function makeHostEnv(snapshot) {
6893
7029
  // src/main/ipc/views.ts
6894
7030
  import { ipcMain as ipcMain4 } from "electron";
6895
7031
  function registerViewsIpc(ctx) {
6896
- const registry = new IpcRegistry(ctx.senderPolicy).handle(ViewChannel.SimulatorDevtoolsBounds, (_event, ...args) => {
6897
- const [bounds] = validate(
6898
- ViewChannel.SimulatorDevtoolsBounds,
6899
- ViewBoundsSchema,
6900
- args
6901
- );
6902
- ctx.views.setSimulatorDevtoolsBounds(bounds);
6903
- }).handle(ViewChannel.WorkbenchBounds, (_event, ...args) => {
6904
- const [bounds] = validate(
6905
- ViewChannel.WorkbenchBounds,
6906
- ViewBoundsSchema,
7032
+ const registry = new IpcRegistry(ctx.senderPolicy).handle(ViewChannel.PlacementSnapshot, (_event, ...args) => {
7033
+ const [snapshot] = validate(
7034
+ ViewChannel.PlacementSnapshot,
7035
+ PlacementSnapshotSchema,
6907
7036
  args
6908
7037
  );
6909
- ctx.views.setWorkbenchBounds(bounds);
6910
- }).handle(ViewChannel.HostToolbarBounds, (_event, ...args) => {
6911
- const [bounds] = validate(
6912
- ViewChannel.HostToolbarBounds,
6913
- ViewBoundsSchema,
6914
- args
6915
- );
6916
- ctx.views.setHostToolbarBounds(bounds);
7038
+ ctx.views.setPlacementSnapshot(snapshot);
6917
7039
  }).handle(ViewChannel.HostToolbarGetHeight, () => ctx.views.getHostToolbarHeight());
6918
7040
  const onAdvertiseHeight = (event, ...args) => {
6919
7041
  if (event.sender.id !== ctx.views.getHostToolbarWebContentsId()) return;
@@ -8813,21 +8935,87 @@ import { DisposableRegistry as DisposableRegistry8 } from "@dimina-kit/electron-
8813
8935
  function setupSimulatorWxml(host, options) {
8814
8936
  const { bridge, inspector, getActiveAppId } = options;
8815
8937
  const registry = new DisposableRegistry8();
8816
- async function pull() {
8817
- const wc = bridge.getActiveRenderWc(getActiveAppId() ?? void 0);
8938
+ let active = false;
8939
+ let seq = 0;
8940
+ let pulling = false;
8941
+ let again = false;
8942
+ let observedWc = null;
8943
+ function activeWc() {
8944
+ return bridge.getActiveRenderWc(getActiveAppId() ?? void 0);
8945
+ }
8946
+ async function pull(wc) {
8818
8947
  if (!wc) return null;
8819
8948
  return inspector.getWxml(wc);
8820
8949
  }
8950
+ function schedulePull() {
8951
+ if (!active) return;
8952
+ const mySeq = ++seq;
8953
+ if (pulling) {
8954
+ again = true;
8955
+ return;
8956
+ }
8957
+ pulling = true;
8958
+ void pull(activeWc()).then((tree) => {
8959
+ if (mySeq === seq && active && !host.isDestroyed()) {
8960
+ host.send(SimulatorWxmlChannel.Event, tree);
8961
+ }
8962
+ }).finally(() => {
8963
+ pulling = false;
8964
+ if (again) {
8965
+ again = false;
8966
+ schedulePull();
8967
+ }
8968
+ });
8969
+ }
8970
+ function startObserving(wc) {
8971
+ if (!wc) return;
8972
+ observedWc = wc;
8973
+ void inspector.setWxmlObserving(wc, true);
8974
+ }
8975
+ function stopObserving() {
8976
+ const wc = observedWc;
8977
+ observedWc = null;
8978
+ if (wc) void inspector.setWxmlObserving(wc, false);
8979
+ }
8980
+ function reconcileObserving() {
8981
+ if (!active) return;
8982
+ const wc = activeWc();
8983
+ if (wc !== observedWc) {
8984
+ stopObserving();
8985
+ startObserving(wc);
8986
+ }
8987
+ }
8988
+ function cancelPending() {
8989
+ seq++;
8990
+ again = false;
8991
+ }
8821
8992
  const ipc = new IpcRegistry(options.senderPolicy);
8822
- ipc.handle(SimulatorWxmlChannel.GetSnapshot, () => pull());
8993
+ ipc.handle(SimulatorWxmlChannel.GetSnapshot, () => pull(activeWc()));
8994
+ ipc.handle(SimulatorWxmlChannel.SetActive, (_event, on) => {
8995
+ if (on) {
8996
+ active = true;
8997
+ reconcileObserving();
8998
+ schedulePull();
8999
+ } else {
9000
+ active = false;
9001
+ cancelPending();
9002
+ stopObserving();
9003
+ }
9004
+ });
8823
9005
  registry.add(ipc);
8824
- const unsubscribe = bridge.onRenderEvent(() => {
8825
- void pull().then((tree) => {
8826
- if (host.isDestroyed()) return;
8827
- host.send(SimulatorWxmlChannel.Event, tree);
8828
- });
9006
+ const unsubscribe = bridge.onRenderEvent((event) => {
9007
+ if (!active) return;
9008
+ const appId = getActiveAppId();
9009
+ if (appId && event.appId !== appId) return;
9010
+ reconcileObserving();
9011
+ schedulePull();
8829
9012
  });
8830
9013
  registry.add(unsubscribe);
9014
+ registry.add(() => {
9015
+ active = false;
9016
+ cancelPending();
9017
+ stopObserving();
9018
+ });
8831
9019
  return registry;
8832
9020
  }
8833
9021
 
@@ -9209,7 +9397,17 @@ function createRenderInspector(options = {}) {
9209
9397
  } catch {
9210
9398
  }
9211
9399
  }
9212
- return { getWxml, highlight, unhighlight };
9400
+ async function setWxmlObserving(wc, on) {
9401
+ if (wc.isDestroyed()) return;
9402
+ if (!await ensureInjected(wc)) return;
9403
+ try {
9404
+ await wc.executeJavaScript(
9405
+ `window.__diminaRenderInspect && window.__diminaRenderInspect.setWxmlObserving(${on ? "true" : "false"})`
9406
+ );
9407
+ } catch {
9408
+ }
9409
+ }
9410
+ return { getWxml, highlight, unhighlight, setWxmlObserving };
9213
9411
  }
9214
9412
 
9215
9413
  // src/main/services/simulator-temp-files/index.ts
@@ -10368,6 +10566,7 @@ function runDevtoolsBootstrap(config = {}) {
10368
10566
  }
10369
10567
  setupCdpPort();
10370
10568
  suppressInsecureCspWarnings();
10569
+ if (!app15.isPackaged) installMaxListenersWarningDiagnostic();
10371
10570
  registerDifileScheme();
10372
10571
  try {
10373
10572
  app15.commandLine.appendSwitch("enable-features", "SharedArrayBuffer");
@@ -10492,6 +10691,10 @@ async function createDevtoolsRuntime(config = {}) {
10492
10691
  context.registry.add(() => {
10493
10692
  context.storageApi = void 0;
10494
10693
  });
10694
+ context.onServiceStorageChanged = storage.onSyncStorageChange;
10695
+ context.registry.add(() => {
10696
+ context.onServiceStorageChanged = void 0;
10697
+ });
10495
10698
  }
10496
10699
  if (context.bridge?.isNativeHost()) {
10497
10700
  const networkForward = createNetworkForwarder({