@dimina-kit/devtools 0.4.0-dev.20260831134112 → 0.4.0-dev.20260907055341
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.
- package/README.md +52 -729
- package/dist/main/app/app.d.ts +27 -7
- package/dist/main/app/app.js +285 -681
- package/dist/main/app/editor-view.d.ts +21 -0
- package/dist/main/app/editor-view.js +71 -0
- package/dist/main/app/global-mirrors.d.ts +23 -0
- package/dist/main/app/global-mirrors.js +37 -0
- package/dist/main/app/host-sidebar-default.d.ts +19 -0
- package/dist/main/app/host-sidebar-default.js +44 -0
- package/dist/main/app/menu-setup.d.ts +13 -0
- package/dist/main/app/menu-setup.js +49 -0
- package/dist/main/app/open-project-ipc.d.ts +13 -0
- package/dist/main/app/open-project-ipc.js +21 -0
- package/dist/main/app/project-list-surface.d.ts +31 -0
- package/dist/main/app/project-list-surface.js +20 -0
- package/dist/main/app/project-window.d.ts +36 -0
- package/dist/main/app/project-window.js +93 -0
- package/dist/main/app/servers.d.ts +17 -0
- package/dist/main/app/servers.js +60 -0
- package/dist/main/app/ui-extension-targets.d.ts +42 -0
- package/dist/main/app/ui-extension-targets.js +101 -0
- package/dist/main/app/window-close-reveal.harness.d.ts +34 -0
- package/dist/main/app/window-close-reveal.harness.js +65 -0
- package/dist/main/app/window-events.d.ts +15 -0
- package/dist/main/app/window-events.js +45 -0
- package/dist/main/app/window-runtime-services.d.ts +41 -0
- package/dist/main/app/window-runtime-services.js +178 -0
- package/dist/main/app/workbench-modules.d.ts +24 -0
- package/dist/main/app/workbench-modules.js +51 -0
- package/dist/main/app/workbench-window.d.ts +85 -0
- package/dist/main/app/workbench-window.js +310 -0
- package/dist/main/index.bundle.js +10669 -9096
- package/dist/main/ipc/app.d.ts +4 -1
- package/dist/main/ipc/app.js +4 -3
- package/dist/main/ipc/device-picker.d.ts +16 -0
- package/dist/main/ipc/device-picker.js +27 -0
- package/dist/main/ipc/index.d.ts +1 -0
- package/dist/main/ipc/index.js +1 -0
- package/dist/main/ipc/internal-devtools.d.ts +2 -1
- package/dist/main/ipc/internal-devtools.js +4 -3
- package/dist/main/ipc/popover.d.ts +4 -1
- package/dist/main/ipc/popover.js +25 -9
- package/dist/main/ipc/project-create.d.ts +2 -1
- package/dist/main/ipc/project-create.js +6 -5
- package/dist/main/ipc/project-fs.d.ts +3 -1
- package/dist/main/ipc/project-fs.js +17 -17
- package/dist/main/ipc/projects.d.ts +3 -3
- package/dist/main/ipc/projects.js +13 -12
- package/dist/main/ipc/session.d.ts +4 -1
- package/dist/main/ipc/session.js +16 -11
- package/dist/main/ipc/settings.d.ts +4 -1
- package/dist/main/ipc/settings.js +12 -19
- package/dist/main/ipc/simulator-module.d.ts +5 -0
- package/dist/main/ipc/simulator-module.js +9 -5
- package/dist/main/ipc/simulator.d.ts +4 -1
- package/dist/main/ipc/simulator.js +12 -18
- package/dist/main/ipc/tooltip.d.ts +2 -1
- package/dist/main/ipc/tooltip.js +8 -7
- package/dist/main/ipc/views.d.ts +4 -1
- package/dist/main/ipc/views.js +20 -9
- package/dist/main/runtime/devtools-backend-before-quit.harness.d.ts +2 -20
- package/dist/main/runtime/devtools-backend-before-quit.harness.js +14 -283
- package/dist/main/runtime/devtools-backend.js +14 -3
- package/dist/main/runtime/devtools-runtime-mock.harness.d.ts +21 -0
- package/dist/main/runtime/devtools-runtime-mock.harness.js +313 -0
- package/dist/main/services/app-services.d.ts +62 -0
- package/dist/main/services/app-services.js +64 -0
- package/dist/main/services/automation/connection-target.d.ts +36 -0
- package/dist/main/services/automation/connection-target.js +29 -0
- package/dist/main/services/automation/console-bridge.d.ts +28 -0
- package/dist/main/services/automation/console-bridge.js +91 -0
- package/dist/main/services/automation/handlers/app.js +4 -4
- package/dist/main/services/automation/handlers/element.js +55 -21
- package/dist/main/services/automation/index.d.ts +12 -1
- package/dist/main/services/automation/index.js +54 -133
- package/dist/main/services/default-adapter.js +1 -1
- package/dist/main/services/fs-bridge-protocol.d.ts +61 -0
- package/dist/main/services/fs-bridge-protocol.js +34 -0
- package/dist/main/services/fs-watch-sse.d.ts +8 -1
- package/dist/main/services/fs-watch-sse.js +19 -5
- package/dist/main/services/mcp/connection-owner.d.ts +38 -0
- package/dist/main/services/mcp/connection-owner.js +79 -0
- package/dist/main/services/mcp/index.d.ts +3 -1
- package/dist/main/services/mcp/index.js +4 -3
- package/dist/main/services/mcp/opened-project.d.ts +88 -0
- package/dist/main/services/mcp/opened-project.js +60 -0
- package/dist/main/services/mcp/target-manager.d.ts +71 -23
- package/dist/main/services/mcp/target-manager.js +269 -142
- package/dist/main/services/mcp/target-selection.d.ts +47 -0
- package/dist/main/services/mcp/target-selection.js +71 -0
- package/dist/main/services/mcp/tools/context-tools.js +20 -5
- package/dist/main/services/mcp/tools/project-tools.d.ts +29 -6
- package/dist/main/services/mcp/tools/project-tools.js +37 -25
- package/dist/main/services/module.d.ts +13 -5
- package/dist/main/services/notifications/renderer-notifier.d.ts +28 -4
- package/dist/main/services/notifications/renderer-notifier.js +15 -3
- package/dist/main/services/projects/local-provider.js +2 -0
- package/dist/main/services/projects/project-repository.d.ts +31 -1
- package/dist/main/services/projects/project-repository.js +144 -20
- package/dist/main/services/projects/types.d.ts +31 -8
- package/dist/main/services/safe-area/index.d.ts +19 -5
- package/dist/main/services/safe-area/index.js +38 -13
- package/dist/main/services/simulator/ui-extensions.d.ts +8 -0
- package/dist/main/services/simulator/ui-extensions.js +16 -6
- package/dist/main/services/simulator-storage/index.d.ts +12 -1
- package/dist/main/services/simulator-storage/index.js +22 -7
- package/dist/main/services/simulator-storage/window-scope.d.ts +20 -0
- package/dist/main/services/simulator-storage/window-scope.js +20 -0
- package/dist/main/services/views/host-slot-port-channel.d.ts +20 -3
- package/dist/main/services/views/host-slot-port-channel.js +33 -5
- package/dist/main/services/views/managed-web-contents-view.js +21 -1
- package/dist/main/services/views/native-simulator-view.js +13 -16
- package/dist/main/services/views/overlay-panels-view.d.ts +13 -0
- package/dist/main/services/views/overlay-panels-view.js +31 -0
- package/dist/main/services/views/view-manager.d.ts +1 -1
- package/dist/main/services/views/view-manager.js +3 -0
- package/dist/main/services/window-contexts/context-router.d.ts +36 -0
- package/dist/main/services/window-contexts/context-router.js +55 -0
- package/dist/main/services/workbench-coi-host.d.ts +52 -0
- package/dist/main/services/workbench-coi-host.js +227 -0
- package/dist/main/services/workbench-coi-server.js +75 -133
- package/dist/main/services/workbench-coi-shutdown.d.ts +40 -0
- package/dist/main/services/workbench-coi-shutdown.js +69 -0
- package/dist/main/services/workbench-coi-static.d.ts +23 -0
- package/dist/main/services/workbench-coi-static.js +87 -0
- package/dist/main/services/workbench-context.d.ts +27 -3
- package/dist/main/services/workbench-context.js +10 -5
- package/dist/main/services/workspace/compile-mode-adapter.d.ts +18 -0
- package/dist/main/services/workspace/compile-mode-adapter.js +57 -0
- package/dist/main/services/workspace/compile-mode-store.d.ts +25 -0
- package/dist/main/services/workspace/compile-mode-store.js +71 -0
- package/dist/main/services/workspace/workspace-compile-modes.d.ts +59 -0
- package/dist/main/services/workspace/workspace-compile-modes.js +93 -0
- package/dist/main/services/workspace/workspace-referer.d.ts +17 -0
- package/dist/main/services/workspace/workspace-referer.js +26 -0
- package/dist/main/services/workspace/workspace-service.d.ts +4 -0
- package/dist/main/services/workspace/workspace-service.js +51 -84
- package/dist/main/services/workspace/workspace-thumbnails.d.ts +22 -0
- package/dist/main/services/workspace/workspace-thumbnails.js +67 -0
- package/dist/main/utils/ipc-context-source.d.ts +40 -0
- package/dist/main/utils/ipc-context-source.js +23 -0
- package/dist/main/utils/ipc-registry.d.ts +42 -36
- package/dist/main/utils/ipc-registry.js +117 -50
- package/dist/main/utils/sender-policy.d.ts +9 -0
- package/dist/main/utils/sender-policy.js +26 -3
- package/dist/main/utils/theme.d.ts +3 -2
- package/dist/main/utils/theme.js +3 -2
- package/dist/main/windows/main-window/create.d.ts +16 -0
- package/dist/main/windows/main-window/create.js +19 -11
- package/dist/main/windows/main-window/events.d.ts +1 -1
- package/dist/main/windows/main-window/events.js +26 -13
- package/dist/main/windows/main-window/index.d.ts +1 -1
- package/dist/main/windows/main-window/index.js +1 -1
- package/dist/native-host/common/common.js +94 -73
- package/dist/native-host/render/render.js +4079 -3171
- package/dist/native-host/service/service.js +2 -2
- package/dist/preload/runtime/native-host.d.ts +4 -0
- package/dist/preload/runtime/temp-files.js +9 -2
- package/dist/preload/runtime/wait-for-slot-root.d.ts +7 -4
- package/dist/preload/runtime/wait-for-slot-root.js +36 -8
- package/dist/preload/windows/host-dialog-runtime.cjs +10 -3
- package/dist/preload/windows/host-dialog-runtime.cjs.map +2 -2
- package/dist/preload/windows/host-sidebar-runtime.cjs +10 -3
- package/dist/preload/windows/host-sidebar-runtime.cjs.map +2 -2
- package/dist/preload/windows/host-toolbar-runtime.cjs +10 -3
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/main.cjs +181 -4
- package/dist/preload/windows/main.cjs.map +4 -4
- package/dist/preload/windows/simulator.cjs +10 -0
- package/dist/preload/windows/simulator.cjs.map +2 -2
- package/dist/preload/windows/simulator.js +10 -0
- package/dist/renderer/assets/button-CB2MWjHY.js +2 -0
- package/dist/renderer/assets/constants-CkoGPQTS.js +2 -0
- package/dist/renderer/assets/constants-zQZ2-y21.js +2 -0
- package/dist/renderer/assets/{createLucideIcon-Bqi8hpdi.js → createLucideIcon-cZ9FlZZw.js} +2 -2
- package/dist/renderer/assets/devicePicker-H2eIO4e1.js +2 -0
- package/dist/renderer/assets/dialog-pHzEA8Vx.js +46 -0
- package/dist/renderer/assets/dist-B5HADirS.js +2 -0
- package/dist/renderer/assets/{dist-DKWdE1TK.js → dist-DIFlRMKe.js} +2 -2
- package/dist/renderer/assets/hostSidebarDefault-DRWh6OCt.js +2 -0
- package/dist/renderer/assets/index-CEL_XFge.js +2 -0
- package/dist/renderer/assets/{input-Ct3alvkq.js → input-CAObw95L.js} +2 -2
- package/dist/renderer/assets/ipc-channels-overlays-gIPUFnqc.js +2 -0
- package/dist/renderer/assets/jsx-runtime-DICEQH_0.css +1 -0
- package/dist/renderer/assets/{jsx-runtime-DGLHmmOq.js → jsx-runtime-DIw5wnYl.js} +1 -1
- package/dist/renderer/assets/plus-BQ9u5EbL.js +2 -0
- package/dist/renderer/assets/popover-Cw7G2Ctp.js +2 -0
- package/dist/renderer/assets/presets-DMZOb9ay.js +2 -0
- package/dist/renderer/assets/project-api-YTOr_Yvo.js +2 -0
- package/dist/renderer/assets/{projectCreateDialog-Bbjz75bP.js → projectCreateDialog-BmLqiYxn.js} +2 -2
- package/dist/renderer/assets/search-BMvuYF48.js +2 -0
- package/dist/renderer/assets/select-nFP95TxM.js +2 -0
- package/dist/renderer/assets/settings-CnpVfSWt.js +2 -0
- package/dist/renderer/assets/settings-api-Ccsf-Nsj.js +2 -0
- package/dist/renderer/assets/settings-tab-bar-CAzrv32m.js +2 -0
- package/dist/renderer/assets/smartphone-Bb2GdIKy.js +2 -0
- package/dist/renderer/assets/tabs-CPKN3Mmq.js +2 -0
- package/dist/renderer/assets/{tooltip-B_-_YVbw.js → tooltip-D6AxXRk5.js} +2 -2
- package/dist/renderer/assets/types-Bh0hA7El.js +2 -0
- package/dist/renderer/assets/updateDialog-CwndJ0Bl.js +2 -0
- package/dist/renderer/assets/{utils-kfQov6Pa.js → utils-sEB5OZEQ.js} +2 -2
- package/dist/renderer/assets/view-api-B-2zPBR5.js +2 -0
- package/dist/renderer/assets/view-ids-BfaDVV5P.js +2 -0
- package/dist/renderer/assets/workbench-BLJ0wKsg.js +5 -0
- package/dist/renderer/assets/{workbenchSettings-CV4LVA9b.js → workbenchSettings-YD0Ctbm_.js} +3 -3
- package/dist/renderer/entries/device-picker/index.html +28 -0
- package/dist/renderer/entries/host-sidebar-default/index.html +6 -5
- package/dist/renderer/entries/main/index.html +16 -17
- package/dist/renderer/entries/popover/index.html +16 -10
- package/dist/renderer/entries/project-create-dialog/index.html +12 -12
- package/dist/renderer/entries/settings/index.html +10 -10
- package/dist/renderer/entries/tooltip/index.html +5 -5
- package/dist/renderer/entries/update-dialog/index.html +10 -10
- package/dist/renderer/entries/workbench/index.html +49 -0
- package/dist/renderer/entries/workbench-settings/index.html +12 -11
- package/dist/service-host/host-env-update.cjs +23 -0
- package/dist/service-host/preload.cjs +24 -49
- package/dist/service-host/service-message-queue.cjs +71 -0
- package/dist/service-host/sync-impls/system-info.js +31 -9
- package/dist/shared/compile-mode-state.d.ts +73 -0
- package/dist/shared/compile-mode-state.js +100 -0
- package/dist/shared/compile-modes.d.ts +152 -0
- package/dist/shared/compile-modes.js +237 -0
- package/dist/shared/ipc-channels-overlays.d.ts +8 -2
- package/dist/shared/ipc-channels-overlays.js +19 -2
- package/dist/shared/ipc-channels.d.ts +5 -10
- package/dist/shared/ipc-channels.js +17 -14
- package/dist/shared/ipc-schemas.d.ts +76 -24
- package/dist/shared/ipc-schemas.js +55 -10
- package/dist/shared/project-window-types.d.ts +42 -0
- package/dist/shared/project-window-types.js +2 -0
- package/dist/shared/types.d.ts +43 -17
- package/dist/shared/view-ids.d.ts +1 -0
- package/dist/shared/view-ids.js +3 -1
- package/dist/simulator/assets/bridge-channels-B3JAmRfl.js +2 -0
- package/dist/simulator/assets/device-shell-ATEhHV2_.css +1 -0
- package/dist/simulator/assets/device-shell-pxnZZp10.js +431 -0
- package/dist/simulator/assets/simulator-Dwp7lnvu.js +10 -0
- package/dist/simulator/assets/simulator-mini-app-DFo7fhi5.js +2 -0
- package/dist/simulator/assets/simulator-ui-B2ddJB1R.js +2 -0
- package/dist/simulator/simulator.html +3 -3
- package/dist/simulator/temp-files.d.ts +6 -0
- package/dist/simulator/temp-files.js +46 -4
- package/dist/simulator/types.d.ts +7 -0
- package/dist/vscode-workbench/assets/__vite-browser-external-JIkWewFf.js +1 -0
- package/dist/vscode-workbench/assets/{dist-CMfmHflW.js → dist-CXG-u1VB.js} +3 -3
- package/dist/vscode-workbench/assets/{iconv-lite-umd-Bx8CgaZq.js → iconv-lite-umd-Dxx9Qyb4.js} +1 -1
- package/dist/vscode-workbench/assets/{index-CdG6YWhW.js → index-6VJMsaWj.js} +460 -460
- package/dist/vscode-workbench/assets/{jschardet-M0qgd2lN.js → jschardet-Ba3D16vt.js} +1 -1
- package/dist/vscode-workbench/index.html +1 -1
- package/package.json +11 -8
- package/dist/renderer/assets/button-D5Q2wkXq.js +0 -2
- package/dist/renderer/assets/constants-D7DfVqMp.js +0 -2
- package/dist/renderer/assets/constants-D8zsejFq.js +0 -2
- package/dist/renderer/assets/dialog-e1TecTOY.js +0 -46
- package/dist/renderer/assets/hostSidebarDefault-B3yLfy8j.js +0 -2
- package/dist/renderer/assets/index-CsPD68N_.js +0 -5
- package/dist/renderer/assets/ipc-channels-overlays-LsDzGAtV.js +0 -2
- package/dist/renderer/assets/jsx-runtime-2vXHouwr.css +0 -1
- package/dist/renderer/assets/popover-Dix5cm_b.js +0 -2
- package/dist/renderer/assets/project-api-k7Oq9iaq.js +0 -2
- package/dist/renderer/assets/select-acGb0AmJ.js +0 -2
- package/dist/renderer/assets/settings-CQrTMr43.js +0 -2
- package/dist/renderer/assets/settings-api-CrUQ9rYV.js +0 -2
- package/dist/renderer/assets/settings-tab-bar-Cw1kVIf2.js +0 -2
- package/dist/renderer/assets/types-CsEKtFyr.js +0 -2
- package/dist/renderer/assets/updateDialog-NsF8223A.js +0 -2
- package/dist/renderer/assets/view-api-CLn3rcQE.js +0 -2
- package/dist/simulator/assets/bridge-channels-zhsumfky.js +0 -2
- package/dist/simulator/assets/device-shell-CmtM1QxP.js +0 -2
- package/dist/simulator/assets/device-shell-iFZo1igL.css +0 -1
- package/dist/simulator/assets/simulator-CIobn3Mh.js +0 -10
- package/dist/simulator/assets/simulator-mini-app-CRe6n9br.js +0 -2
- package/dist/simulator/assets/simulator-ui-C_cP602X.js +0 -2
- package/dist/vscode-workbench/assets/__vite-browser-external-Bc1vizTf.js +0 -1
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ledger of host-registered simulator UI extensions.
|
|
3
|
+
*
|
|
4
|
+
* A registration is app-level — the host makes it once — but an extension can
|
|
5
|
+
* only exist inside a PROJECT window: it mounts into that window's device
|
|
6
|
+
* frame and talks to its simulator renderer. So one registration becomes one
|
|
7
|
+
* live extension per project window, and the ledger is what keeps those copies
|
|
8
|
+
* in step with the windows: every project window that opens gets its own copy,
|
|
9
|
+
* and a copy exists exactly as long as the window that owns it.
|
|
10
|
+
*
|
|
11
|
+
* The project list is deliberately not a target. It runs no bridge router and
|
|
12
|
+
* no simulator, so an extension registered into it could never mount, and
|
|
13
|
+
* `invoke` — which follows the window the user works in — would be answered by
|
|
14
|
+
* that dead copy every time the list window has focus.
|
|
15
|
+
*/
|
|
16
|
+
import { toDisposable } from '@dimina-kit/electron-deck/main';
|
|
17
|
+
import { assertSimulatorUiExtensionShape } from '../services/simulator/ui-extensions.js';
|
|
18
|
+
export function createUiExtensionTargets(deps) {
|
|
19
|
+
/** Per registration, one target per project window that currently holds it. */
|
|
20
|
+
const ledger = new Map();
|
|
21
|
+
/** Ids currently spoken for app-wide, so a clash is caught where it happens. */
|
|
22
|
+
const ids = new Set();
|
|
23
|
+
function attach(window, targets, registration) {
|
|
24
|
+
const extension = window.simulatorUiExtensions.register(registration);
|
|
25
|
+
// Owned by the window: its registry drives this on close, which both tears
|
|
26
|
+
// the extension down and drops the record. A record left behind would keep
|
|
27
|
+
// a disposed extension reachable as an `invoke` target and would make the
|
|
28
|
+
// ledger grow with every window ever opened.
|
|
29
|
+
const owned = window.registry.add(toDisposable(async () => {
|
|
30
|
+
const index = targets.findIndex((t) => t.extension === extension);
|
|
31
|
+
if (index >= 0)
|
|
32
|
+
targets.splice(index, 1);
|
|
33
|
+
await extension.dispose();
|
|
34
|
+
}));
|
|
35
|
+
targets.push({ window, extension, owned });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A window refusing an extension is a fact about that window: the project
|
|
39
|
+
* still opens, the other windows keep their copies, and windows opened later
|
|
40
|
+
* still get theirs. Letting it escape would turn one bad extension into "no
|
|
41
|
+
* project can be opened any more".
|
|
42
|
+
*/
|
|
43
|
+
function tryAttach(window, targets, registration) {
|
|
44
|
+
try {
|
|
45
|
+
attach(window, targets, registration);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.warn(`[simulator-ui] project window did not take extension "${registration.id}":`, error instanceof Error ? error.message : String(error));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
attachTo: (window) => {
|
|
53
|
+
for (const [registration, targets] of ledger)
|
|
54
|
+
tryAttach(window, targets, registration);
|
|
55
|
+
},
|
|
56
|
+
register: (registration) => {
|
|
57
|
+
// Checked here, before anything is recorded: the ledger owns the
|
|
58
|
+
// app-level set of registrations, and hosts register in `onSetup` where
|
|
59
|
+
// there is no project window to do the checking. A rejected registration
|
|
60
|
+
// must leave no record — otherwise it is handed to every project window
|
|
61
|
+
// opened afterwards and takes each of them down as it is built.
|
|
62
|
+
// Snapshotted before anything reads it: the ledger outlives this call and
|
|
63
|
+
// hands the registration to every project window opened later, so a host
|
|
64
|
+
// that reuses its object to describe the next extension would otherwise
|
|
65
|
+
// rewrite what an already-registered one means — the id it releases, and
|
|
66
|
+
// the extension future windows are given.
|
|
67
|
+
const snapshot = { ...registration };
|
|
68
|
+
assertSimulatorUiExtensionShape(snapshot);
|
|
69
|
+
const id = snapshot.id;
|
|
70
|
+
if (ids.has(id)) {
|
|
71
|
+
throw new Error(`Simulator UI extension "${id}" is already registered`);
|
|
72
|
+
}
|
|
73
|
+
const targets = [];
|
|
74
|
+
ids.add(id);
|
|
75
|
+
ledger.set(snapshot, targets);
|
|
76
|
+
for (const window of deps.projectWindows())
|
|
77
|
+
tryAttach(window, targets, snapshot);
|
|
78
|
+
return {
|
|
79
|
+
dispose: () => {
|
|
80
|
+
// Only while this registration is the one holding the id: a second
|
|
81
|
+
// dispose must not free an id a later registration now owns.
|
|
82
|
+
if (!ledger.delete(snapshot))
|
|
83
|
+
return;
|
|
84
|
+
ids.delete(id);
|
|
85
|
+
// Copied: disposing a window-owned record splices it out of `targets`.
|
|
86
|
+
for (const target of [...targets])
|
|
87
|
+
void target.owned.dispose();
|
|
88
|
+
targets.length = 0;
|
|
89
|
+
},
|
|
90
|
+
invoke: (method, params) => {
|
|
91
|
+
const active = deps.activeWindow();
|
|
92
|
+
const target = targets.find((t) => t.window === active) ?? targets[targets.length - 1];
|
|
93
|
+
if (!target)
|
|
94
|
+
throw new Error('simulator UI extension has no live window');
|
|
95
|
+
return target.extension.invoke(method, params);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=ui-extension-targets.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export { stubs, devkitStubs } from '../runtime/devtools-runtime-mock.harness.js';
|
|
2
|
+
/**
|
|
3
|
+
* Shared per-test setup: reset modules (fresh module-level state each test),
|
|
4
|
+
* reset the mock harness above, and dynamically re-import `electron` +
|
|
5
|
+
* `createDevtoolsRuntime` + the lifecycle flag — dynamic, not a static
|
|
6
|
+
* top-level import, because it must happen AFTER `vi.resetModules()` picks
|
|
7
|
+
* up a fresh module instance each test. Registers its own `beforeEach`; call
|
|
8
|
+
* once per describing test file.
|
|
9
|
+
*/
|
|
10
|
+
export interface RuntimeTestState {
|
|
11
|
+
createDevtoolsRuntime: typeof import('./app.js').createDevtoolsRuntime;
|
|
12
|
+
registerAppLifecycle: typeof import('./lifecycle.js').registerAppLifecycle;
|
|
13
|
+
isAppQuitting: typeof import('./lifecycle.js').isAppQuitting;
|
|
14
|
+
electron: typeof import('electron');
|
|
15
|
+
}
|
|
16
|
+
export declare function registerRuntimeTestLifecycle(): RuntimeTestState;
|
|
17
|
+
/**
|
|
18
|
+
* Registers `projectDir` as an openable project (app.json present, empty
|
|
19
|
+
* projects list) and opens it in its own window via the real
|
|
20
|
+
* `openProjectWindow`. Does NOT open a devkit session — the close guards
|
|
21
|
+
* under test branch on window-list membership, not session state (teardown
|
|
22
|
+
* is unconditional; see workbench-window.ts's `wireWorkbenchWindowEvents`
|
|
23
|
+
* doc comment), so a session adds cost without adding coverage here.
|
|
24
|
+
*/
|
|
25
|
+
export declare function openProjectWindow(instance: Awaited<ReturnType<typeof import('./app.js').createDevtoolsRuntime>>, projectDir: string): Promise<ReturnType<Awaited<ReturnType<typeof import('./app.js').createDevtoolsRuntime>>['projectWindows']>[number]>;
|
|
26
|
+
/** A fresh Electron-shaped close event, plus a getter for whether it was prevented. */
|
|
27
|
+
export declare function makeCloseEvent(): {
|
|
28
|
+
event: {
|
|
29
|
+
preventDefault: () => void;
|
|
30
|
+
};
|
|
31
|
+
prevented: () => boolean;
|
|
32
|
+
};
|
|
33
|
+
export declare function emitClose(win: unknown, event: unknown): void;
|
|
34
|
+
//# sourceMappingURL=window-close-reveal.harness.d.ts.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared vitest mock harness for the list/workbench-window close-guard test
|
|
3
|
+
* files (`main-window-close-guard.test.ts`, `workbench-window-reveal-on-
|
|
4
|
+
* close.test.ts`, and siblings) — all drive the REAL `createDevtoolsRuntime`
|
|
5
|
+
* against the electron/fs/`@dimina-kit/devkit` mock set defined in
|
|
6
|
+
* `../runtime/devtools-runtime-mock.harness.ts`, plus the runtime-lifecycle
|
|
7
|
+
* and window-opening helpers below that those tests need in common.
|
|
8
|
+
*
|
|
9
|
+
* `vi.mock(...)` calls in the imported core module run once per importing
|
|
10
|
+
* test file's own isolated module graph (vitest scopes mocking per test
|
|
11
|
+
* file); chaining through this module has the same effect as if they were
|
|
12
|
+
* written directly in the importing file.
|
|
13
|
+
*/
|
|
14
|
+
import { beforeEach, vi } from 'vitest';
|
|
15
|
+
import { stubs, devkitStubs } from '../runtime/devtools-runtime-mock.harness.js';
|
|
16
|
+
export { stubs, devkitStubs } from '../runtime/devtools-runtime-mock.harness.js';
|
|
17
|
+
export function registerRuntimeTestLifecycle() {
|
|
18
|
+
const state = {};
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
vi.resetModules();
|
|
21
|
+
stubs.reset();
|
|
22
|
+
devkitStubs.sessionClose.mockClear();
|
|
23
|
+
state.electron = await import('electron');
|
|
24
|
+
({ createDevtoolsRuntime: state.createDevtoolsRuntime } = await import('./app.js'));
|
|
25
|
+
({ registerAppLifecycle: state.registerAppLifecycle, isAppQuitting: state.isAppQuitting } =
|
|
26
|
+
await import('./lifecycle.js'));
|
|
27
|
+
});
|
|
28
|
+
return state;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Registers `projectDir` as an openable project (app.json present, empty
|
|
32
|
+
* projects list) and opens it in its own window via the real
|
|
33
|
+
* `openProjectWindow`. Does NOT open a devkit session — the close guards
|
|
34
|
+
* under test branch on window-list membership, not session state (teardown
|
|
35
|
+
* is unconditional; see workbench-window.ts's `wireWorkbenchWindowEvents`
|
|
36
|
+
* doc comment), so a session adds cost without adding coverage here.
|
|
37
|
+
*/
|
|
38
|
+
export async function openProjectWindow(instance, projectDir) {
|
|
39
|
+
stubs.projectsWithAppJson.add(projectDir);
|
|
40
|
+
if (stubs.getProjectsJson() === null)
|
|
41
|
+
stubs.setProjectsJson(JSON.stringify([]));
|
|
42
|
+
await instance.openProjectWindow({ path: projectDir });
|
|
43
|
+
// The manager keys its window map by project path and this helper always
|
|
44
|
+
// opens a path it just registered, so the newest entry is the one that was
|
|
45
|
+
// asked for. Matching on anything weaker (e.g. "the first window that isn't
|
|
46
|
+
// the list window") hands back the PREVIOUSLY opened project once a second
|
|
47
|
+
// one is open, which is exactly the multi-window case these tests exist for.
|
|
48
|
+
const found = instance.projectWindows().at(-1);
|
|
49
|
+
if (!found)
|
|
50
|
+
throw new Error(`openProjectWindow(${projectDir}) did not publish a window`);
|
|
51
|
+
return found;
|
|
52
|
+
}
|
|
53
|
+
/** A fresh Electron-shaped close event, plus a getter for whether it was prevented. */
|
|
54
|
+
export function makeCloseEvent() {
|
|
55
|
+
let count = 0;
|
|
56
|
+
return {
|
|
57
|
+
event: { preventDefault: () => { count += 1; } },
|
|
58
|
+
prevented: () => count > 0,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export function emitClose(win, event) {
|
|
62
|
+
;
|
|
63
|
+
win.emit('close', event);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=window-close-reveal.harness.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BrowserWindow } from 'electron';
|
|
2
|
+
import { type Disposable } from '@dimina-kit/electron-deck/main';
|
|
3
|
+
/**
|
|
4
|
+
* Bring `win` back in front of the user from any hidden or minimized state.
|
|
5
|
+
*
|
|
6
|
+
* The project-list window hides instead of closing while projects are open —
|
|
7
|
+
* it owns app-level IPC that cannot be registered a second time, so it must
|
|
8
|
+
* outlive its own close button — which makes "show the project list" a real
|
|
9
|
+
* operation with several entry points (the menu, a macOS dock activate, the
|
|
10
|
+
* last project window closing). They all go through here so none of them can
|
|
11
|
+
* drift into handling only some of the hidden states.
|
|
12
|
+
*/
|
|
13
|
+
export declare function revealWindow(win: BrowserWindow): void;
|
|
14
|
+
export declare function enableDevRendererAutoReload(rendererDir: string): Disposable;
|
|
15
|
+
//# sourceMappingURL=window-events.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { app, BrowserWindow } from 'electron';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { toDisposable } from '@dimina-kit/electron-deck/main';
|
|
4
|
+
/**
|
|
5
|
+
* Bring `win` back in front of the user from any hidden or minimized state.
|
|
6
|
+
*
|
|
7
|
+
* The project-list window hides instead of closing while projects are open —
|
|
8
|
+
* it owns app-level IPC that cannot be registered a second time, so it must
|
|
9
|
+
* outlive its own close button — which makes "show the project list" a real
|
|
10
|
+
* operation with several entry points (the menu, a macOS dock activate, the
|
|
11
|
+
* last project window closing). They all go through here so none of them can
|
|
12
|
+
* drift into handling only some of the hidden states.
|
|
13
|
+
*/
|
|
14
|
+
export function revealWindow(win) {
|
|
15
|
+
if (win.isDestroyed())
|
|
16
|
+
return;
|
|
17
|
+
if (win.isMinimized())
|
|
18
|
+
win.restore();
|
|
19
|
+
win.show();
|
|
20
|
+
win.focus();
|
|
21
|
+
}
|
|
22
|
+
export function enableDevRendererAutoReload(rendererDir) {
|
|
23
|
+
// Auto-reload renderer windows when dist files change during development
|
|
24
|
+
if (app.isPackaged) {
|
|
25
|
+
return toDisposable(() => { });
|
|
26
|
+
}
|
|
27
|
+
let reloadTimer = null;
|
|
28
|
+
const watcher = fs.watch(rendererDir, { recursive: true }, () => {
|
|
29
|
+
if (reloadTimer)
|
|
30
|
+
clearTimeout(reloadTimer);
|
|
31
|
+
reloadTimer = setTimeout(() => {
|
|
32
|
+
for (const win of BrowserWindow.getAllWindows()) {
|
|
33
|
+
win.webContents.reload();
|
|
34
|
+
}
|
|
35
|
+
}, 300);
|
|
36
|
+
});
|
|
37
|
+
return toDisposable(() => {
|
|
38
|
+
if (reloadTimer) {
|
|
39
|
+
clearTimeout(reloadTimer);
|
|
40
|
+
reloadTimer = null;
|
|
41
|
+
}
|
|
42
|
+
watcher.close();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=window-events.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { BrowserWindow } from 'electron';
|
|
2
|
+
import type { ConnectionRegistry, DisposableRegistry } from '@dimina-kit/electron-deck/main';
|
|
3
|
+
import type { SyncStorageChange } from '../../shared/ipc-channels.js';
|
|
4
|
+
import type { SenderPolicy } from '../utils/ipc-registry.js';
|
|
5
|
+
import type { BridgeRouterHandle } from '../ipc/bridge-router.js';
|
|
6
|
+
import type { CdpSessionBroker } from '../services/cdp-session/index.js';
|
|
7
|
+
import type { InternalDevtoolsWindow } from '../windows/internal-devtools-window/index.js';
|
|
8
|
+
import type { NetworkForwarder } from '../services/network-forward/index.js';
|
|
9
|
+
import type { AppDataTap } from '../services/simulator-appdata/index.js';
|
|
10
|
+
import type { StorageApi } from '../services/simulator-storage/index.js';
|
|
11
|
+
import type { WorkspaceService } from '../services/workspace/workspace-service.js';
|
|
12
|
+
/**
|
|
13
|
+
* Narrow view of the context fields these services read, plus the four fields
|
|
14
|
+
* they publish back onto it for bridge-router to consume.
|
|
15
|
+
*/
|
|
16
|
+
export interface WindowRuntimeContext {
|
|
17
|
+
registry: DisposableRegistry;
|
|
18
|
+
connections: ConnectionRegistry;
|
|
19
|
+
cdpSessionBroker: CdpSessionBroker;
|
|
20
|
+
senderPolicy: SenderPolicy;
|
|
21
|
+
workspace: WorkspaceService;
|
|
22
|
+
bridge?: BridgeRouterHandle;
|
|
23
|
+
internalDevtoolsWindow?: InternalDevtoolsWindow;
|
|
24
|
+
storageApi?: StorageApi;
|
|
25
|
+
onServiceStorageChanged?: (appId: string, change: SyncStorageChange) => void;
|
|
26
|
+
networkForward?: NetworkForwarder;
|
|
27
|
+
appData?: AppDataTap;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the active project's appId. Shared by the storage panel filter, the
|
|
31
|
+
* native-host WXML/element-inspect services (which scope the active render
|
|
32
|
+
* guest by appId) and the editor's per-project workspace identity.
|
|
33
|
+
*/
|
|
34
|
+
export declare function createActiveAppIdResolver(context: Pick<WindowRuntimeContext, 'workspace'>): () => string | null;
|
|
35
|
+
/**
|
|
36
|
+
* Panel-backing services that push into one window's renderer: storage, and
|
|
37
|
+
* under native-host the MCP target tracking plus the WXML / AppData /
|
|
38
|
+
* current-page streams.
|
|
39
|
+
*/
|
|
40
|
+
export declare function setupWindowRuntimeServices(context: WindowRuntimeContext, mainWindow: BrowserWindow, getActiveAppId: () => string | null, projectPath: string): void;
|
|
41
|
+
//# sourceMappingURL=window-runtime-services.d.ts.map
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { resolveNativeAppDataKeys, resolveNativeStorageOverview } from './native-overview.js';
|
|
2
|
+
import { registerMcpWindow, noteActiveBridgeId } from '../services/mcp/index.js';
|
|
3
|
+
import { createRenderInspector } from '../services/render-inspect/index.js';
|
|
4
|
+
import { setupSimulatorStorage } from '../services/simulator-storage/index.js';
|
|
5
|
+
import { createNetworkForwarder } from '../services/network-forward/index.js';
|
|
6
|
+
import { setupSimulatorWxml } from '../services/simulator-wxml/index.js';
|
|
7
|
+
import { setupSimulatorAppData } from '../services/simulator-appdata/index.js';
|
|
8
|
+
import { setupSimulatorCurrentPage } from '../services/simulator-current-page/index.js';
|
|
9
|
+
import { toDisposable } from '@dimina-kit/electron-deck/main';
|
|
10
|
+
/**
|
|
11
|
+
* Resolve the active project's appId. Shared by the storage panel filter, the
|
|
12
|
+
* native-host WXML/element-inspect services (which scope the active render
|
|
13
|
+
* guest by appId) and the editor's per-project workspace identity.
|
|
14
|
+
*/
|
|
15
|
+
export function createActiveAppIdResolver(context) {
|
|
16
|
+
return () => {
|
|
17
|
+
const session = context.workspace.getSession();
|
|
18
|
+
const appInfo = session?.appInfo;
|
|
19
|
+
return appInfo?.appId ?? null;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Panel-backing services that push into one window's renderer: storage, and
|
|
24
|
+
* under native-host the MCP target tracking plus the WXML / AppData /
|
|
25
|
+
* current-page streams.
|
|
26
|
+
*/
|
|
27
|
+
export function setupWindowRuntimeServices(context, mainWindow, getActiveAppId, projectPath) {
|
|
28
|
+
// MCP drives whichever project window the user is in, so each window records
|
|
29
|
+
// its own facts and this record dies with the window — other project windows
|
|
30
|
+
// keep theirs. The project path is the window's identity, taken from the
|
|
31
|
+
// project it opened with rather than read back off session state that does
|
|
32
|
+
// not exist until the first compile.
|
|
33
|
+
const mcpWindow = registerMcpWindow(context, {
|
|
34
|
+
nativeHost: false,
|
|
35
|
+
activeBridgeId: null,
|
|
36
|
+
nativeOverviewProvider: null,
|
|
37
|
+
projectPath,
|
|
38
|
+
getAppId: getActiveAppId,
|
|
39
|
+
});
|
|
40
|
+
context.registry.add(mcpWindow.dispose);
|
|
41
|
+
// Native-host: the real mini-app page runs in a nested render-host
|
|
42
|
+
// <webview> guest, not the localhost:7788 shell. Point the MCP
|
|
43
|
+
// `simulator` CDP target at the active render guest and keep it following
|
|
44
|
+
// the visible page across navigation/tab switches. Only wired under
|
|
45
|
+
// native-host so the default path stays byte-identical.
|
|
46
|
+
if (context.bridge?.isNativeHost()) {
|
|
47
|
+
mcpWindow.facts.nativeHost = true;
|
|
48
|
+
mcpWindow.facts.nativeOverviewProvider = async () => {
|
|
49
|
+
const appId = getActiveAppId();
|
|
50
|
+
const stack = context.bridge?.getPageStack?.(appId ?? undefined) ?? [];
|
|
51
|
+
const top = stack[stack.length - 1];
|
|
52
|
+
const overview = {
|
|
53
|
+
currentRoute: top?.pagePath ?? null,
|
|
54
|
+
pageStackDepth: stack.length,
|
|
55
|
+
storageKeys: [],
|
|
56
|
+
storageCount: 0,
|
|
57
|
+
appDataKeys: [],
|
|
58
|
+
};
|
|
59
|
+
if (appId) {
|
|
60
|
+
const storage = await resolveNativeStorageOverview(context, appId);
|
|
61
|
+
overview.storageKeys = storage.storageKeys;
|
|
62
|
+
overview.storageCount = storage.storageCount;
|
|
63
|
+
overview.appDataKeys = resolveNativeAppDataKeys(context, appId);
|
|
64
|
+
}
|
|
65
|
+
return overview;
|
|
66
|
+
};
|
|
67
|
+
const off = context.bridge.onRenderEvent((ev) => noteActiveBridgeId(context, ev.bridgeId));
|
|
68
|
+
context.registry.add(off);
|
|
69
|
+
}
|
|
70
|
+
// Native-host inspector: injects the render-guest IIFE and drives WXML /
|
|
71
|
+
// element-highlight against the active render-host <webview>. Reused by
|
|
72
|
+
// the storage panel (element inspect) and the WXML panel service.
|
|
73
|
+
const renderInspector = createRenderInspector({ connections: context.connections, broker: context.cdpSessionBroker });
|
|
74
|
+
const storage = setupSimulatorStorage(mainWindow.webContents, {
|
|
75
|
+
senderPolicy: context.senderPolicy,
|
|
76
|
+
connections: context.connections,
|
|
77
|
+
broker: context.cdpSessionBroker,
|
|
78
|
+
// Scopes simulator-webview discovery to THIS window — otherwise a second
|
|
79
|
+
// project window can steal the first window's already-attached simulator
|
|
80
|
+
// (see setupSimulatorStorage's `window` option doc).
|
|
81
|
+
window: mainWindow,
|
|
82
|
+
// Per-project filter for the simulator-storage panel: the simulator
|
|
83
|
+
// uses a fixed `persist:simulator` partition + a fixed simulator.html
|
|
84
|
+
// origin, so localStorage is shared across every project that has
|
|
85
|
+
// ever opened. The dimina runtime isolates writes with `${appId}_`
|
|
86
|
+
// prefixes; this callback lets the storage panel filter the CDP
|
|
87
|
+
// snapshot/event stream to the active appId.
|
|
88
|
+
getActiveAppId,
|
|
89
|
+
// Native-host: route element inspection to the active render guest, and
|
|
90
|
+
// read/write storage from the service-host window's file:// store.
|
|
91
|
+
bridge: context.bridge,
|
|
92
|
+
renderInspector,
|
|
93
|
+
});
|
|
94
|
+
context.registry.add(storage);
|
|
95
|
+
// Native-host: expose the async-storage runtime hook so bridge-router
|
|
96
|
+
// routes async wx.setStorage/etc. to the unified service-host store.
|
|
97
|
+
if (storage.storageApi) {
|
|
98
|
+
context.storageApi = storage.storageApi;
|
|
99
|
+
context.registry.add(() => { context.storageApi = undefined; });
|
|
100
|
+
// SYNC wx storage writes bypass main (they hit the service-host localStorage
|
|
101
|
+
// directly); the service-host posts `storageChanged` and bridge-router routes
|
|
102
|
+
// it here so the Storage panel stays live without a manual reload.
|
|
103
|
+
context.onServiceStorageChanged = storage.onSyncStorageChange;
|
|
104
|
+
context.registry.add(() => { context.onServiceStorageChanged = undefined; });
|
|
105
|
+
}
|
|
106
|
+
// Native-host WXML + AppData panels: main sources the data (WXML pulled
|
|
107
|
+
// from the active render guest; AppData tapped from the service→render
|
|
108
|
+
// setData stream in bridge-router) and pushes it to the renderer. Inert on
|
|
109
|
+
// the default dimina-fe path (which sources both from the simulator
|
|
110
|
+
// miniappSnapshot transport), so only wire them when native-host is on.
|
|
111
|
+
if (context.bridge?.isNativeHost()) {
|
|
112
|
+
// Native-host: surface the simulator WCV's network (wx.request/download/
|
|
113
|
+
// upload run there, not in the service host) in the embedded DevTools by
|
|
114
|
+
// injecting its raw Network.* CDP events into the DevTools front-end so the
|
|
115
|
+
// native Network tab renders them (service-host console line is the
|
|
116
|
+
// fallback). The ViewManager calls the forwarder's attachSimulator +
|
|
117
|
+
// setDevtoolsHost from attachNativeSimulator once the simulator WCV +
|
|
118
|
+
// DevTools host exist; getServiceWc here is the fallback sink target.
|
|
119
|
+
const networkForward = createNetworkForwarder({
|
|
120
|
+
getServiceWc: (appId) => context.bridge?.getServiceWc(appId) ?? null,
|
|
121
|
+
getResourceServerBaseUrl: () => context.bridge?.getResourceBaseUrl?.() ?? null,
|
|
122
|
+
// The simulator shell's own static-asset server (serves simulator.html
|
|
123
|
+
// + its JS/CSS, independent from the resource server above — see
|
|
124
|
+
// NetworkForwarderBridge.getSimulatorServerBaseUrl's doc). Host is
|
|
125
|
+
// always 'localhost' — see shared/simulator-route.ts's
|
|
126
|
+
// buildSimulatorUrlFromSpec default. Absent (null port) when no
|
|
127
|
+
// project is open.
|
|
128
|
+
getSimulatorServerBaseUrl: () => {
|
|
129
|
+
const port = context.workspace?.getSession()?.port;
|
|
130
|
+
return typeof port === 'number' ? `http://localhost:${port}/` : null;
|
|
131
|
+
},
|
|
132
|
+
connections: context.connections,
|
|
133
|
+
broker: context.cdpSessionBroker,
|
|
134
|
+
});
|
|
135
|
+
context.networkForward = networkForward;
|
|
136
|
+
context.registry.add(networkForward);
|
|
137
|
+
context.registry.add(() => { context.networkForward = undefined; });
|
|
138
|
+
// Global mirror: once the standalone internal
|
|
139
|
+
// DevTools window builds its own front-end host, mirror the full
|
|
140
|
+
// unfiltered Network stream into it. Attached AFTER context.networkForward
|
|
141
|
+
// is assigned above — the callback re-reads the mutable field on every
|
|
142
|
+
// fire, so ordering only matters for readability here, not correctness.
|
|
143
|
+
context.registry.add(toDisposable(context.internalDevtoolsWindow?.onHostChanged((hostWc) => {
|
|
144
|
+
context.networkForward?.setGlobalDevtoolsHost(hostWc);
|
|
145
|
+
}) ?? (() => { })));
|
|
146
|
+
// Main-process WebSocket traffic (wx.connectSocket runs on the Node `ws`
|
|
147
|
+
// transport, invisible to any webContents debugger): bridge-router fans
|
|
148
|
+
// the trace stream out here, and the forwarder synthesizes it into
|
|
149
|
+
// Network.webSocket* CDP events for the same Network panel sinks.
|
|
150
|
+
context.registry.add(toDisposable(context.bridge?.onNativeWebSocketTrace?.((ownerId, event) => {
|
|
151
|
+
context.networkForward?.reportWebSocketTrace(ownerId, event);
|
|
152
|
+
}) ?? (() => { })));
|
|
153
|
+
context.registry.add(setupSimulatorWxml(mainWindow.webContents, {
|
|
154
|
+
senderPolicy: context.senderPolicy,
|
|
155
|
+
bridge: context.bridge,
|
|
156
|
+
inspector: renderInspector,
|
|
157
|
+
getActiveAppId,
|
|
158
|
+
}));
|
|
159
|
+
const appDataService = setupSimulatorAppData(mainWindow.webContents, {
|
|
160
|
+
senderPolicy: context.senderPolicy,
|
|
161
|
+
getActiveAppId,
|
|
162
|
+
// AppData-panel edit write-back target: the service-host window owning
|
|
163
|
+
// the edited page bridge.
|
|
164
|
+
bridge: context.bridge,
|
|
165
|
+
});
|
|
166
|
+
// bridge-router feeds this via ctx.appData (service→render tap + evict).
|
|
167
|
+
context.appData = appDataService;
|
|
168
|
+
context.registry.add(appDataService);
|
|
169
|
+
context.registry.add(() => { context.appData = undefined; });
|
|
170
|
+
// Push the visible page route to the toolbar on every navigation (the
|
|
171
|
+
// page stack lives in the DeviceShell WCV, invisible to renderer
|
|
172
|
+
// <webview> nav events).
|
|
173
|
+
context.registry.add(setupSimulatorCurrentPage(mainWindow.webContents, {
|
|
174
|
+
bridge: context.bridge,
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=window-runtime-services.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DisposableRegistry } from '@dimina-kit/electron-deck/main';
|
|
2
|
+
import type { WorkbenchAppConfig } from '../../shared/types.js';
|
|
3
|
+
import type { WindowContextRouter } from '../services/window-contexts/context-router.js';
|
|
4
|
+
import type { ProjectWindow } from './project-window.js';
|
|
5
|
+
/**
|
|
6
|
+
* The window context type, taken from `ProjectWindow` so this module doesn't
|
|
7
|
+
* import `WorkbenchContext` directly (see eslint-workbench-context-gate).
|
|
8
|
+
*/
|
|
9
|
+
type WindowContext = ProjectWindow['context'];
|
|
10
|
+
/**
|
|
11
|
+
* The IPC half of the built-in modules: registered ONCE for the application.
|
|
12
|
+
* Each handler answers whichever window a message came from (it takes the
|
|
13
|
+
* router), so a second window needs no second registration — and must not make
|
|
14
|
+
* one, since `ipcMain.handle` is a process-wide singleton per channel.
|
|
15
|
+
*/
|
|
16
|
+
export declare function registerModuleIpc(config: WorkbenchAppConfig, router: WindowContextRouter<WindowContext>, appRegistry: DisposableRegistry): void;
|
|
17
|
+
/**
|
|
18
|
+
* The per-window half: wiring that mutates one concrete context (the
|
|
19
|
+
* simulator's bridge router assigning `ctx.bridge` / `ctx.consoleForwarder`).
|
|
20
|
+
* Runs once per window and is parked on that window's own registry.
|
|
21
|
+
*/
|
|
22
|
+
export declare function setupWindowModules(config: WorkbenchAppConfig, context: WindowContext): void;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=workbench-modules.d.ts.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { popoverModule, projectsModule, sessionModule, settingsModule, simulatorModule, } from '../ipc/index.js';
|
|
2
|
+
const DEFAULT_MODULES = {
|
|
3
|
+
projects: true,
|
|
4
|
+
session: true,
|
|
5
|
+
simulator: true,
|
|
6
|
+
popover: true,
|
|
7
|
+
settings: true,
|
|
8
|
+
};
|
|
9
|
+
const BUILTIN_MODULES = {
|
|
10
|
+
projects: projectsModule,
|
|
11
|
+
session: sessionModule,
|
|
12
|
+
simulator: simulatorModule,
|
|
13
|
+
popover: popoverModule,
|
|
14
|
+
settings: settingsModule,
|
|
15
|
+
};
|
|
16
|
+
function resolveModules(config) {
|
|
17
|
+
return {
|
|
18
|
+
...DEFAULT_MODULES,
|
|
19
|
+
...config.modules,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The IPC half of the built-in modules: registered ONCE for the application.
|
|
24
|
+
* Each handler answers whichever window a message came from (it takes the
|
|
25
|
+
* router), so a second window needs no second registration — and must not make
|
|
26
|
+
* one, since `ipcMain.handle` is a process-wide singleton per channel.
|
|
27
|
+
*/
|
|
28
|
+
export function registerModuleIpc(config, router, appRegistry) {
|
|
29
|
+
const modules = resolveModules(config);
|
|
30
|
+
Object.keys(modules).forEach((moduleId) => {
|
|
31
|
+
if (!modules[moduleId])
|
|
32
|
+
return;
|
|
33
|
+
appRegistry.add(BUILTIN_MODULES[moduleId].setup(router));
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The per-window half: wiring that mutates one concrete context (the
|
|
38
|
+
* simulator's bridge router assigning `ctx.bridge` / `ctx.consoleForwarder`).
|
|
39
|
+
* Runs once per window and is parked on that window's own registry.
|
|
40
|
+
*/
|
|
41
|
+
export function setupWindowModules(config, context) {
|
|
42
|
+
const modules = resolveModules(config);
|
|
43
|
+
Object.keys(modules).forEach((moduleId) => {
|
|
44
|
+
if (!modules[moduleId])
|
|
45
|
+
return;
|
|
46
|
+
const module = BUILTIN_MODULES[moduleId];
|
|
47
|
+
if (module.setupWindow)
|
|
48
|
+
context.registry.add(module.setupWindow(context));
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=workbench-modules.js.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { BrowserWindow } from 'electron';
|
|
2
|
+
import type { WorkbenchAppConfig } from '../../shared/types.js';
|
|
3
|
+
import type { AppServices } from '../services/app-services.js';
|
|
4
|
+
import type { WindowContextRouter } from '../services/window-contexts/context-router.js';
|
|
5
|
+
import { type ProjectRef, type ProjectWindow } from './project-window.js';
|
|
6
|
+
/**
|
|
7
|
+
* The window context type, taken from `ProjectWindow` so this module doesn't
|
|
8
|
+
* import `WorkbenchContext` directly (see eslint-workbench-context-gate).
|
|
9
|
+
*/
|
|
10
|
+
type WindowContext = ProjectWindow['context'];
|
|
11
|
+
export interface WorkbenchWindowDeps {
|
|
12
|
+
config: WorkbenchAppConfig;
|
|
13
|
+
rendererDir: string;
|
|
14
|
+
appServices: AppServices;
|
|
15
|
+
router: WindowContextRouter<WindowContext>;
|
|
16
|
+
/**
|
|
17
|
+
* Per-window module wiring — the `setupWindow` half of the built-in modules
|
|
18
|
+
* (notably the simulator's `installBridgeRouter`, which assigns `ctx.bridge`
|
|
19
|
+
* / `ctx.consoleForwarder` / `ctx.diagnostics`). The IPC half is registered
|
|
20
|
+
* once against the router and is NOT repeated here.
|
|
21
|
+
*/
|
|
22
|
+
setupWindowModules: (ctx: WindowContext) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Told whenever `activeContext()` can have changed — a window opened, took
|
|
25
|
+
* focus, or was torn down. App-level services that hold something aimed at
|
|
26
|
+
* the active project window (the MCP CDP connections) re-aim on it.
|
|
27
|
+
*/
|
|
28
|
+
onActiveContextChanged?: () => void;
|
|
29
|
+
/**
|
|
30
|
+
* Host hook, awaited before a window tears its project down, and told which
|
|
31
|
+
* project that is. A rejection is logged and swallowed: the hook runs on the
|
|
32
|
+
* way out, so it can react but never cancel the teardown behind it.
|
|
33
|
+
*/
|
|
34
|
+
onBeforeClose?: (win: ProjectWindow, project: ProjectRef) => Promise<void> | void;
|
|
35
|
+
/**
|
|
36
|
+
* Host hook, awaited once the window is fully wired and before `open()`
|
|
37
|
+
* reports success, and told which project it belongs to. Unlike
|
|
38
|
+
* `onBeforeClose` it CAN fail the open: there is no usable window to react
|
|
39
|
+
* in yet, so a rejection tears the half-built window down and travels back
|
|
40
|
+
* to the caller unchanged.
|
|
41
|
+
*/
|
|
42
|
+
setupProjectWindow?: (win: ProjectWindow, project: ProjectRef) => Promise<void> | void;
|
|
43
|
+
/**
|
|
44
|
+
* Gate every open waits on before it builds anything. The app registers the
|
|
45
|
+
* open-project IPC before it awaits the host's own setup hook, so a renderer
|
|
46
|
+
* that races ahead must be parked rather than handed a window the host has
|
|
47
|
+
* not finished extending. Omitted means there is nothing to wait for.
|
|
48
|
+
*/
|
|
49
|
+
ready?: Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
export interface WorkbenchWindowManager {
|
|
52
|
+
/**
|
|
53
|
+
* Open `project` in its own window, or focus the window already showing it.
|
|
54
|
+
* Resolves once the window exists and its per-window services are wired.
|
|
55
|
+
* Opens and closes of the same project are serialized, so a call arriving
|
|
56
|
+
* while that project's window is still closing waits it out and then opens a
|
|
57
|
+
* fresh window — never a second one alongside it. Rejects if the window
|
|
58
|
+
* cannot be brought up, leaving nothing behind.
|
|
59
|
+
*
|
|
60
|
+
* `awaitReady: false` skips parking on `deps.ready` (still queued behind
|
|
61
|
+
* other opens/closes of the same path). Only the host's own
|
|
62
|
+
* `instance.openProjectWindow` uses it — see `app.ts`'s call site for why.
|
|
63
|
+
* The renderer-facing IPC path always uses the default.
|
|
64
|
+
*/
|
|
65
|
+
open: (project: ProjectRef, options?: {
|
|
66
|
+
awaitReady?: boolean;
|
|
67
|
+
}) => Promise<BrowserWindow>;
|
|
68
|
+
list: () => ProjectWindow[];
|
|
69
|
+
/**
|
|
70
|
+
* The workbench context the user is working in — the focused one, or the
|
|
71
|
+
* most recently opened when focus sits on the project list. Null until the
|
|
72
|
+
* first project window opens.
|
|
73
|
+
*/
|
|
74
|
+
activeContext: () => WindowContext | null;
|
|
75
|
+
/**
|
|
76
|
+
* Tear every workbench window down (app quit / runtime disposal). Terminal
|
|
77
|
+
* and idempotent: once it starts, no `open()` — pending, queued or already
|
|
78
|
+
* in flight — leaves a live window behind, and it does not resolve until
|
|
79
|
+
* every in-flight open or close has settled.
|
|
80
|
+
*/
|
|
81
|
+
disposeAll: () => Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
export declare function createWorkbenchWindowManager(deps: WorkbenchWindowDeps): WorkbenchWindowManager;
|
|
84
|
+
export {};
|
|
85
|
+
//# sourceMappingURL=workbench-window.d.ts.map
|