@dimina-kit/devtools 0.4.0-dev.20260828161241 → 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/render-host/pageFrame.html +1 -1
- package/dist/render-host/preload.cjs +16 -4
- 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
|
@@ -2,14 +2,28 @@ import type { WebContents } from 'electron';
|
|
|
2
2
|
import type { ConnectionRegistry } from '@dimina-kit/electron-deck/main';
|
|
3
3
|
import type { NativeDeviceInfo } from '../../../shared/ipc-channels.js';
|
|
4
4
|
import { type CdpSessionBroker } from '../cdp-session/index.js';
|
|
5
|
+
/** What the guest's own page contributes to the inset policy: whether the
|
|
6
|
+
* shell draws a tabBar under it, and whether it draws a navigation bar over
|
|
7
|
+
* the notch for it. */
|
|
8
|
+
export interface GuestPageInsetPolicy {
|
|
9
|
+
isTabPage: boolean;
|
|
10
|
+
isCustomNav: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Read a guest's inset policy off its render-host URL (`isTab`, `navStyle` —
|
|
14
|
+
* both written by `buildRenderHostDocumentUrl`). An unparseable URL degrades to
|
|
15
|
+
* the default-nav, non-tab policy rather than failing the attach.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseGuestPageInsetPolicy(src: string): GuestPageInsetPolicy;
|
|
5
18
|
export interface SafeAreaController {
|
|
6
19
|
/** Attach the debugger to a freshly-attached render-host guest and push the
|
|
7
|
-
* current device's insets. `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
|
|
20
|
+
* current device's insets. `page` selects the top policy (real inset only for
|
|
21
|
+
* a custom-nav page) and the bottom policy (0 for tab pages, the real inset
|
|
22
|
+
* for full-bleed non-tab pages). No-op (warn) if the guest is already claimed
|
|
23
|
+
* by an external CDP client — env then stays 0. */
|
|
24
|
+
applyToGuest(guestWc: WebContents, device: NativeDeviceInfo | null, page: GuestPageInsetPolicy): void;
|
|
11
25
|
/** Re-push insets to every still-attached guest after a device change (each
|
|
12
|
-
* guest keeps the page
|
|
26
|
+
* guest keeps the page policy it attached with). */
|
|
13
27
|
reapplyAll(device: NativeDeviceInfo | null): void;
|
|
14
28
|
/** Release this controller's session leases (teardown). Does not itself
|
|
15
29
|
* detach the shared debugger session — see cdp-session/index.ts. */
|
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
import { createCdpSessionBroker } from '../cdp-session/index.js';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Read a guest's inset policy off its render-host URL (`isTab`, `navStyle` —
|
|
4
|
+
* both written by `buildRenderHostDocumentUrl`). An unparseable URL degrades to
|
|
5
|
+
* the default-nav, non-tab policy rather than failing the attach.
|
|
6
|
+
*/
|
|
7
|
+
export function parseGuestPageInsetPolicy(src) {
|
|
8
|
+
try {
|
|
9
|
+
const params = new URL(src).searchParams;
|
|
10
|
+
return {
|
|
11
|
+
isTabPage: params.get('isTab') === '1',
|
|
12
|
+
isCustomNav: params.get('navStyle') === 'custom',
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return { isTabPage: false, isCustomNav: false };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function guestInsets(device, page) {
|
|
20
|
+
// Only a custom-nav (full-bleed) page borders the unsafe top zone; a
|
|
21
|
+
// default-nav page already starts below the shell nav bar, which covers the
|
|
22
|
+
// notch itself.
|
|
23
|
+
const top = page.isCustomNav ? (device?.safeAreaInsets.top ?? 0) : 0;
|
|
4
24
|
// A tab page's content sits above the shell-drawn tabBar (which fills the
|
|
5
25
|
// bottom safe area), so it never borders the bottom unsafe zone. A non-tab
|
|
6
26
|
// page is full-bleed to the device bottom, so surface the real inset for its
|
|
7
27
|
// own `env(safe-area-inset-bottom)` opt-in.
|
|
8
|
-
const bottom = isTabPage ? 0 : (device?.safeAreaInsets.bottom ?? 0);
|
|
9
|
-
|
|
28
|
+
const bottom = page.isTabPage ? 0 : (device?.safeAreaInsets.bottom ?? 0);
|
|
29
|
+
// Left/right come straight from the device (e.g. a landscape Dynamic Island
|
|
30
|
+
// rotates into a side notch) — unlike top/bottom they don't depend on page
|
|
31
|
+
// type, since neither shell chrome nor the tabBar reserves horizontal space.
|
|
32
|
+
const right = device?.safeAreaInsets.right ?? 0;
|
|
33
|
+
const left = device?.safeAreaInsets.left ?? 0;
|
|
34
|
+
return { top, topMax: top, right, rightMax: right, bottom, bottomMax: bottom, left, leftMax: left };
|
|
10
35
|
}
|
|
11
36
|
export function createSafeAreaController(options = {}) {
|
|
12
37
|
// Own (and dispose on this controller's own dispose()) a private broker
|
|
@@ -17,10 +42,10 @@ export function createSafeAreaController(options = {}) {
|
|
|
17
42
|
// passes one; falls back to a private instance so this module stays
|
|
18
43
|
// independently testable/usable.
|
|
19
44
|
const broker = options.broker ?? createCdpSessionBroker({ connections: options.connections });
|
|
20
|
-
// Each guest's page
|
|
45
|
+
// Each guest's page policy, fixed for its life — tracked SEPARATELY from the
|
|
21
46
|
// lease so a lost session (external detach) doesn't lose the policy: a
|
|
22
47
|
// later `override`/`reapplyAll` can reacquire and keep applying the same
|
|
23
|
-
//
|
|
48
|
+
// policy this guest attached with.
|
|
24
49
|
const pageType = new Map();
|
|
25
50
|
// Current lease per guest, if any. Cleared (not just left stale) on
|
|
26
51
|
// `lease.onDetach` — an external detach or a real Chrome DevTools window
|
|
@@ -39,7 +64,7 @@ export function createSafeAreaController(options = {}) {
|
|
|
39
64
|
lease.onDetach(() => { leases.delete(wc); });
|
|
40
65
|
return lease;
|
|
41
66
|
}
|
|
42
|
-
function override(wc, device,
|
|
67
|
+
function override(wc, device, page) {
|
|
43
68
|
if (wc.isDestroyed())
|
|
44
69
|
return;
|
|
45
70
|
const lease = ensureLease(wc);
|
|
@@ -51,17 +76,17 @@ export function createSafeAreaController(options = {}) {
|
|
|
51
76
|
return;
|
|
52
77
|
}
|
|
53
78
|
void lease
|
|
54
|
-
.send('Emulation.setSafeAreaInsetsOverride', { insets: guestInsets(device,
|
|
79
|
+
.send('Emulation.setSafeAreaInsetsOverride', { insets: guestInsets(device, page) })
|
|
55
80
|
.catch((err) => {
|
|
56
81
|
console.warn('[safe-area] setSafeAreaInsetsOverride failed:', err instanceof Error ? err.message : err);
|
|
57
82
|
});
|
|
58
83
|
}
|
|
59
84
|
return {
|
|
60
|
-
applyToGuest: (wc, device,
|
|
85
|
+
applyToGuest: (wc, device, page) => {
|
|
61
86
|
if (!wc || wc.isDestroyed())
|
|
62
87
|
return;
|
|
63
88
|
const isFirstTime = !pageType.has(wc);
|
|
64
|
-
pageType.set(wc,
|
|
89
|
+
pageType.set(wc, page);
|
|
65
90
|
if (isFirstTime) {
|
|
66
91
|
const forget = () => { pageType.delete(wc); leases.delete(wc); };
|
|
67
92
|
if (options.connections) {
|
|
@@ -71,11 +96,11 @@ export function createSafeAreaController(options = {}) {
|
|
|
71
96
|
wc.once('destroyed', forget);
|
|
72
97
|
}
|
|
73
98
|
}
|
|
74
|
-
override(wc, device,
|
|
99
|
+
override(wc, device, page);
|
|
75
100
|
},
|
|
76
101
|
reapplyAll: (device) => {
|
|
77
|
-
for (const [wc,
|
|
78
|
-
override(wc, device,
|
|
102
|
+
for (const [wc, page] of pageType)
|
|
103
|
+
override(wc, device, page);
|
|
79
104
|
},
|
|
80
105
|
dispose: () => {
|
|
81
106
|
// Release our leases only — the shared session's actual detach is the
|
|
@@ -9,5 +9,13 @@ export interface SimulatorUiExtensionRegistry {
|
|
|
9
9
|
export interface SimulatorUiExtensionRegistryOptions {
|
|
10
10
|
loadSource?: (scriptPath: string) => Promise<string>;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* The rules a registration has to satisfy on its own, with no window and no
|
|
14
|
+
* renderer involved: the id is a lookup key on both sides of the bridge, and
|
|
15
|
+
* the script is read straight from disk with no base to resolve against. They
|
|
16
|
+
* hold wherever a registration is accepted, so whoever accepts one first is
|
|
17
|
+
* where a host learns it is unusable.
|
|
18
|
+
*/
|
|
19
|
+
export declare function assertSimulatorUiExtensionShape(registration: SimulatorUiExtensionRegistration): void;
|
|
12
20
|
export declare function createSimulatorUiExtensionRegistry(options?: SimulatorUiExtensionRegistryOptions): SimulatorUiExtensionRegistry;
|
|
13
21
|
//# sourceMappingURL=ui-extensions.d.ts.map
|
|
@@ -2,17 +2,27 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import { isAbsolute } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
const EXTENSION_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
5
|
+
/**
|
|
6
|
+
* The rules a registration has to satisfy on its own, with no window and no
|
|
7
|
+
* renderer involved: the id is a lookup key on both sides of the bridge, and
|
|
8
|
+
* the script is read straight from disk with no base to resolve against. They
|
|
9
|
+
* hold wherever a registration is accepted, so whoever accepts one first is
|
|
10
|
+
* where a host learns it is unusable.
|
|
11
|
+
*/
|
|
12
|
+
export function assertSimulatorUiExtensionShape(registration) {
|
|
13
|
+
if (!EXTENSION_ID_RE.test(registration.id)) {
|
|
14
|
+
throw new Error(`Invalid simulator UI extension id: "${registration.id}"`);
|
|
15
|
+
}
|
|
16
|
+
if (!isAbsolute(registration.rendererScriptPath)) {
|
|
17
|
+
throw new Error('Simulator UI extension rendererScriptPath must be absolute');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
5
20
|
export function createSimulatorUiExtensionRegistry(options = {}) {
|
|
6
21
|
const loadSource = options.loadSource ?? (scriptPath => readFile(scriptPath, 'utf8'));
|
|
7
22
|
const entries = new Map();
|
|
8
23
|
let active = null;
|
|
9
24
|
function assertRegistration(registration) {
|
|
10
|
-
|
|
11
|
-
throw new Error(`Invalid simulator UI extension id: "${registration.id}"`);
|
|
12
|
-
}
|
|
13
|
-
if (!isAbsolute(registration.rendererScriptPath)) {
|
|
14
|
-
throw new Error('Simulator UI extension rendererScriptPath must be absolute');
|
|
15
|
-
}
|
|
25
|
+
assertSimulatorUiExtensionShape(registration);
|
|
16
26
|
if (entries.has(registration.id)) {
|
|
17
27
|
throw new Error(`Simulator UI extension "${registration.id}" is already registered`);
|
|
18
28
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* opens one, the shared session detaches externally and events stop
|
|
20
20
|
* flowing until they close it.
|
|
21
21
|
*/
|
|
22
|
-
import { type WebContents } from 'electron';
|
|
22
|
+
import { type BrowserWindow, type WebContents } from 'electron';
|
|
23
23
|
import { type ConnectionRegistry, type Disposable } from '@dimina-kit/electron-deck/main';
|
|
24
24
|
import { type SyncStorageChange } from '../../../shared/ipc-channels.js';
|
|
25
25
|
import { type SenderPolicy } from '../../utils/ipc-registry.js';
|
|
@@ -96,6 +96,17 @@ export interface SimulatorStorageOptions {
|
|
|
96
96
|
* compile and behave unchanged, just without cross-module session sharing.
|
|
97
97
|
*/
|
|
98
98
|
broker?: CdpSessionBroker;
|
|
99
|
+
/**
|
|
100
|
+
* Owning window (typically `mainWindow`). Scopes every simulator-webview
|
|
101
|
+
* discovery path (initial scan, `web-contents-created`, lazy re-find) to
|
|
102
|
+
* webviews that live inside THIS window — required in a multi-window
|
|
103
|
+
* workbench, where `webContents`/`app.on('web-contents-created')` are
|
|
104
|
+
* process-global and would otherwise let one window's instance attach to
|
|
105
|
+
* (and read/write through) another window's simulator. Optional so
|
|
106
|
+
* existing single-window callers/tests compile and keep their prior
|
|
107
|
+
* unscoped behavior.
|
|
108
|
+
*/
|
|
109
|
+
window?: BrowserWindow;
|
|
99
110
|
}
|
|
100
111
|
export declare function setupSimulatorStorage(host: WebContents, options: SimulatorStorageOptions): SimulatorStorageHandle;
|
|
101
112
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -25,6 +25,7 @@ import { SimulatorElementChannel, SimulatorStorageChannel, } from '../../../shar
|
|
|
25
25
|
import { IpcRegistry } from '../../utils/ipc-registry.js';
|
|
26
26
|
import { decodeStorageValue, encodeStorageValue, serviceStorage } from './service-storage-ops.js';
|
|
27
27
|
import { createCdpSessionBroker } from '../cdp-session/index.js';
|
|
28
|
+
import { windowHostsWebContents } from './window-scope.js';
|
|
28
29
|
/** Async wx storage API names routed through the unified service-window store. */
|
|
29
30
|
export const STORAGE_API_NAMES = new Set([
|
|
30
31
|
'setStorage',
|
|
@@ -40,6 +41,17 @@ function isSimulatorWebview(wc) {
|
|
|
40
41
|
return false;
|
|
41
42
|
return wc.getURL().includes('simulator.html');
|
|
42
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* `win` undefined means no owning window was configured — the legacy
|
|
46
|
+
* unscoped behavior, kept so single-window callers/tests that don't pass
|
|
47
|
+
* `window` keep compiling and behaving unchanged. Every production call
|
|
48
|
+
* site (window-runtime-services.ts) always passes its window.
|
|
49
|
+
*/
|
|
50
|
+
function belongsToWindow(win, wc) {
|
|
51
|
+
if (!win)
|
|
52
|
+
return true;
|
|
53
|
+
return windowHostsWebContents(win, wc);
|
|
54
|
+
}
|
|
43
55
|
function safeOff(target, event, fn) {
|
|
44
56
|
try {
|
|
45
57
|
if (target.isDestroyed?.())
|
|
@@ -198,7 +210,7 @@ export function setupSimulatorStorage(host, options) {
|
|
|
198
210
|
async function ensureAttached() {
|
|
199
211
|
if (attachedWc && !attachedWc.isDestroyed())
|
|
200
212
|
return;
|
|
201
|
-
const sim = findSimulatorWebContents();
|
|
213
|
+
const sim = findSimulatorWebContents(options.window);
|
|
202
214
|
if (!sim)
|
|
203
215
|
return;
|
|
204
216
|
await attachToSim(sim);
|
|
@@ -392,7 +404,7 @@ export function setupSimulatorStorage(host, options) {
|
|
|
392
404
|
// Attach to any simulator webview that already exists (project may have
|
|
393
405
|
// been opened before this function runs).
|
|
394
406
|
for (const wc of wcStatic.getAllWebContents()) {
|
|
395
|
-
if (isSimulatorWebview(wc)) {
|
|
407
|
+
if (isSimulatorWebview(wc) && belongsToWindow(options.window, wc)) {
|
|
396
408
|
void attachToSim(wc);
|
|
397
409
|
break;
|
|
398
410
|
}
|
|
@@ -406,7 +418,7 @@ export function setupSimulatorStorage(host, options) {
|
|
|
406
418
|
const sub = new DisposableRegistry();
|
|
407
419
|
wcSubs.set(wc, sub);
|
|
408
420
|
const onFinishLoad = () => {
|
|
409
|
-
if (isSimulatorWebview(wc))
|
|
421
|
+
if (isSimulatorWebview(wc) && belongsToWindow(options.window, wc))
|
|
410
422
|
void attachToSim(wc);
|
|
411
423
|
};
|
|
412
424
|
wc.on('did-finish-load', onFinishLoad);
|
|
@@ -455,7 +467,7 @@ export function setupSimulatorStorage(host, options) {
|
|
|
455
467
|
return null;
|
|
456
468
|
return options.renderInspector.highlight(wc, sid);
|
|
457
469
|
}
|
|
458
|
-
const sim = findSimulatorWebContents();
|
|
470
|
+
const sim = findSimulatorWebContents(options.window);
|
|
459
471
|
if (!sim)
|
|
460
472
|
return null;
|
|
461
473
|
try {
|
|
@@ -474,7 +486,7 @@ export function setupSimulatorStorage(host, options) {
|
|
|
474
486
|
await options.renderInspector.unhighlight(wc);
|
|
475
487
|
return;
|
|
476
488
|
}
|
|
477
|
-
const sim = findSimulatorWebContents();
|
|
489
|
+
const sim = findSimulatorWebContents(options.window);
|
|
478
490
|
if (!sim)
|
|
479
491
|
return;
|
|
480
492
|
try {
|
|
@@ -591,9 +603,12 @@ export function setupSimulatorStorage(host, options) {
|
|
|
591
603
|
// bridge via executeJavaScript. Looked up independently from `attachedWc` so
|
|
592
604
|
// it keeps working when the user opens Chrome DevTools and the storage
|
|
593
605
|
// debugger detaches (debugger.attach is mutually exclusive with F12).
|
|
594
|
-
|
|
606
|
+
// Scoped to `win` for the same reason as the attach paths above — an
|
|
607
|
+
// unscoped scan would resolve to whichever window's simulator comes first
|
|
608
|
+
// in the process-global registry, not necessarily this instance's own.
|
|
609
|
+
function findSimulatorWebContents(win) {
|
|
595
610
|
for (const wc of wcStatic.getAllWebContents()) {
|
|
596
|
-
if (isSimulatorWebview(wc))
|
|
611
|
+
if (isSimulatorWebview(wc) && belongsToWindow(win, wc))
|
|
597
612
|
return wc;
|
|
598
613
|
}
|
|
599
614
|
return null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Window-ownership judgment for simulator webContents discovery.
|
|
3
|
+
*
|
|
4
|
+
* The workbench runs one `setupSimulatorStorage` instance per project
|
|
5
|
+
* window, but Electron's `webContents`/`app.on('web-contents-created')`
|
|
6
|
+
* APIs are process-global — every instance sees every window's webviews.
|
|
7
|
+
* Without this filter, whichever instance's scan/callback fires first wins
|
|
8
|
+
* the simulator it finds, so opening a second project window can steal the
|
|
9
|
+
* first window's already-attached simulator (its Storage panel then reads
|
|
10
|
+
* and writes the second project's partition).
|
|
11
|
+
*
|
|
12
|
+
* The ownership rule itself (does a webContents sit inside a window's own
|
|
13
|
+
* renderer, its `contentView` tree, or a `<webview>` guest embedded in
|
|
14
|
+
* either) is shared with dimina-electron-runtime's bridge router, which
|
|
15
|
+
* faces the identical process-global-vs-per-window problem for its IPC
|
|
16
|
+
* routing — so it's owned by @dimina-kit/electron-deck/main and re-exported
|
|
17
|
+
* here under the name this package's callers expect.
|
|
18
|
+
*/
|
|
19
|
+
export { windowHostsWebContents } from '@dimina-kit/electron-deck/main';
|
|
20
|
+
//# sourceMappingURL=window-scope.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Window-ownership judgment for simulator webContents discovery.
|
|
3
|
+
*
|
|
4
|
+
* The workbench runs one `setupSimulatorStorage` instance per project
|
|
5
|
+
* window, but Electron's `webContents`/`app.on('web-contents-created')`
|
|
6
|
+
* APIs are process-global — every instance sees every window's webviews.
|
|
7
|
+
* Without this filter, whichever instance's scan/callback fires first wins
|
|
8
|
+
* the simulator it finds, so opening a second project window can steal the
|
|
9
|
+
* first window's already-attached simulator (its Storage panel then reads
|
|
10
|
+
* and writes the second project's partition).
|
|
11
|
+
*
|
|
12
|
+
* The ownership rule itself (does a webContents sit inside a window's own
|
|
13
|
+
* renderer, its `contentView` tree, or a `<webview>` guest embedded in
|
|
14
|
+
* either) is shared with dimina-electron-runtime's bridge router, which
|
|
15
|
+
* faces the identical process-global-vs-per-window problem for its IPC
|
|
16
|
+
* routing — so it's owned by @dimina-kit/electron-deck/main and re-exported
|
|
17
|
+
* here under the name this package's callers expect.
|
|
18
|
+
*/
|
|
19
|
+
export { windowHostsWebContents } from '@dimina-kit/electron-deck/main';
|
|
20
|
+
//# sourceMappingURL=window-scope.js.map
|
|
@@ -50,13 +50,30 @@ import type { WebContents } from 'electron';
|
|
|
50
50
|
export interface HostSlotMessageSubscription {
|
|
51
51
|
dispose(): void;
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Handle returned by `attach`, scoped to the ONE webContents it was made for.
|
|
55
|
+
* `dispose()` removes the listeners that `attach` installed on that wc and, if
|
|
56
|
+
* that wc still owns the live port, closes it. Idempotent, and never touches a
|
|
57
|
+
* successor's attachment: releasing a superseded wc leaves the current one
|
|
58
|
+
* delivering.
|
|
59
|
+
*
|
|
60
|
+
* The owner calls this when it replaces or destroys that wc, so the channel
|
|
61
|
+
* holds no main-side state for a webContents its owner has let go — the
|
|
62
|
+
* channel does not have to be the wc's sole owner for its listeners to be
|
|
63
|
+
* released on time.
|
|
64
|
+
*/
|
|
65
|
+
export interface HostSlotAttachment {
|
|
66
|
+
dispose(): void;
|
|
67
|
+
}
|
|
53
68
|
export interface HostSlotPortChannel {
|
|
54
69
|
/**
|
|
55
70
|
* Hook a freshly created slot webContents: registers the `did-finish-load`
|
|
56
|
-
* (per-load handshake)
|
|
57
|
-
*
|
|
71
|
+
* (per-load handshake), `did-start-navigation` (document-replacing
|
|
72
|
+
* navigation) and `destroyed` (drop the live port) listeners via
|
|
73
|
+
* `wc.on(...)`. Call exactly once per wc, right after the view is created,
|
|
74
|
+
* and `dispose()` the returned handle when that wc is replaced or destroyed.
|
|
58
75
|
*/
|
|
59
|
-
attach(wc: WebContents):
|
|
76
|
+
attach(wc: WebContents): HostSlotAttachment;
|
|
60
77
|
/**
|
|
61
78
|
* Drop the live port NOW (close + clear): the document it belongs to is
|
|
62
79
|
* being replaced. Called synchronously when the HOST initiates a
|
|
@@ -165,7 +165,7 @@ export function createHostSlotPortChannel(opts) {
|
|
|
165
165
|
}
|
|
166
166
|
return {
|
|
167
167
|
attach(wc) {
|
|
168
|
-
|
|
168
|
+
const onDidFinishLoad = () => handshake(wc);
|
|
169
169
|
// Page-initiated navigation (location.href / reload): the document the
|
|
170
170
|
// port lives in is being replaced — invalidate so send() reports false
|
|
171
171
|
// through the navigation window instead of confirming delivery into a
|
|
@@ -178,7 +178,7 @@ export function createHostSlotPortChannel(opts) {
|
|
|
178
178
|
// - main frame only: an <iframe> navigating keeps the main document.
|
|
179
179
|
// Reads the details object (electron >= 12 shape); falls back to the
|
|
180
180
|
// deprecated positional args (`isInPlace` === details.isSameDocument).
|
|
181
|
-
|
|
181
|
+
const onDidStartNavigation = (details, _url, isInPlace, isMainFramePositional) => {
|
|
182
182
|
if (activeWc !== wc)
|
|
183
183
|
return;
|
|
184
184
|
const isSameDocument = typeof details?.isSameDocument === 'boolean'
|
|
@@ -190,11 +190,39 @@ export function createHostSlotPortChannel(opts) {
|
|
|
190
190
|
if (isSameDocument || !isMainFrame)
|
|
191
191
|
return;
|
|
192
192
|
dropActivePort(true, 'awaitingHandshake');
|
|
193
|
-
}
|
|
194
|
-
|
|
193
|
+
};
|
|
194
|
+
const onDestroyed = () => {
|
|
195
195
|
if (activeWc === wc)
|
|
196
196
|
dropActivePort(true, 'absent');
|
|
197
|
-
}
|
|
197
|
+
};
|
|
198
|
+
wc.on('did-finish-load', onDidFinishLoad);
|
|
199
|
+
wc.on('did-start-navigation', onDidStartNavigation);
|
|
200
|
+
wc.on('destroyed', onDestroyed);
|
|
201
|
+
let released = false;
|
|
202
|
+
return {
|
|
203
|
+
dispose() {
|
|
204
|
+
if (released)
|
|
205
|
+
return;
|
|
206
|
+
released = true;
|
|
207
|
+
// This wc is going away: if it still owns the live port, the
|
|
208
|
+
// document that port belongs to is going with it, so close it and
|
|
209
|
+
// let send() report false. A superseded wc owns nothing — the
|
|
210
|
+
// successor's port is untouched.
|
|
211
|
+
if (activeWc === wc)
|
|
212
|
+
dropActivePort(true, 'absent');
|
|
213
|
+
// A destroyed webContents still carries its JS-side emitter, so the
|
|
214
|
+
// removals below are meaningful on both live and dead wcs; the
|
|
215
|
+
// try/catch only covers hosts that reject the call outright.
|
|
216
|
+
try {
|
|
217
|
+
wc.off('did-finish-load', onDidFinishLoad);
|
|
218
|
+
wc.off('did-start-navigation', onDidStartNavigation);
|
|
219
|
+
wc.off('destroyed', onDestroyed);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
/* wc already gone; its listeners went with it */
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
};
|
|
198
226
|
},
|
|
199
227
|
invalidate() {
|
|
200
228
|
dropActivePort(true, 'awaitingHandshake');
|
|
@@ -4,6 +4,18 @@ export function createManagedWebContentsView(opts) {
|
|
|
4
4
|
let view = null;
|
|
5
5
|
let preloadOverride = null;
|
|
6
6
|
let runtimeAcquired = false;
|
|
7
|
+
/** The channel attachment for the CURRENT wc; released when that wc is replaced or destroyed. */
|
|
8
|
+
let attachment = null;
|
|
9
|
+
/**
|
|
10
|
+
* Hand the channel back the wc this manager is done with. This manager owns
|
|
11
|
+
* the wc's whole life, so it is the only thing that knows the wc is gone;
|
|
12
|
+
* without this the channel would keep listeners on a webContents nobody can
|
|
13
|
+
* reach any more.
|
|
14
|
+
*/
|
|
15
|
+
function releaseAttachment() {
|
|
16
|
+
attachment?.dispose();
|
|
17
|
+
attachment = null;
|
|
18
|
+
}
|
|
7
19
|
function liveWebContents() {
|
|
8
20
|
const wc = view?.webContents;
|
|
9
21
|
if (!wc || wc.isDestroyed())
|
|
@@ -22,6 +34,7 @@ export function createManagedWebContentsView(opts) {
|
|
|
22
34
|
if (view !== current)
|
|
23
35
|
return;
|
|
24
36
|
console.error(`[${opts.viewId}] ${detail} — destroying so the next ensureView() rebuilds`);
|
|
37
|
+
releaseAttachment();
|
|
25
38
|
view = null;
|
|
26
39
|
opts.reconciler.destroyView(opts.viewId, current);
|
|
27
40
|
opts.onBroken?.();
|
|
@@ -30,6 +43,10 @@ export function createManagedWebContentsView(opts) {
|
|
|
30
43
|
if (view && liveWebContents()) {
|
|
31
44
|
return view;
|
|
32
45
|
}
|
|
46
|
+
// The outgoing wc (if any) is about to be destroyed, so its attachment
|
|
47
|
+
// goes first — a wc this manager no longer owns must not keep the channel
|
|
48
|
+
// wired to it.
|
|
49
|
+
releaseAttachment();
|
|
33
50
|
if (view) {
|
|
34
51
|
opts.reconciler.destroyView(opts.viewId, view);
|
|
35
52
|
}
|
|
@@ -48,7 +65,7 @@ export function createManagedWebContentsView(opts) {
|
|
|
48
65
|
}
|
|
49
66
|
const next = new WebContentsView({ webPreferences });
|
|
50
67
|
view = next;
|
|
51
|
-
opts.port.attach(next.webContents);
|
|
68
|
+
attachment = opts.port.attach(next.webContents);
|
|
52
69
|
try {
|
|
53
70
|
next.setBackgroundColor('#121212');
|
|
54
71
|
}
|
|
@@ -105,6 +122,9 @@ export function createManagedWebContentsView(opts) {
|
|
|
105
122
|
// registry, so a send() racing teardown reports false instead of posting
|
|
106
123
|
// into a wc that is about to be closed.
|
|
107
124
|
opts.port.dispose();
|
|
125
|
+
// Then hand back the wc itself, so no listener rests on a webContents
|
|
126
|
+
// this manager is about to close.
|
|
127
|
+
releaseAttachment();
|
|
108
128
|
// Host-controllable slot view: removed from the contentView + its
|
|
109
129
|
// WebContents closed (the host's loaded content is torn down on app exit).
|
|
110
130
|
opts.reconciler.destroyView(opts.viewId, view);
|
|
@@ -5,6 +5,7 @@ import { handleWindowOpenExternal } from '../../windows/navigation-hardening.js'
|
|
|
5
5
|
import { SimulatorCustomApiBridgeChannel } from '../../../shared/ipc-channels.js';
|
|
6
6
|
import * as layout from '../layout/index.js';
|
|
7
7
|
import { handleCustomApiBridgeRequest, } from '../simulator/custom-apis.js';
|
|
8
|
+
import { parseGuestPageInsetPolicy } from '../safe-area/index.js';
|
|
8
9
|
import { configureMiniappSession, miniappPartition } from './miniapp-partition.js';
|
|
9
10
|
import { refreshGuestStylesheets } from './refresh-styles.js';
|
|
10
11
|
import { parseRoute } from '../../../shared/simulator-route.js';
|
|
@@ -230,27 +231,23 @@ export function createNativeSimulatorView(ctx, reconciler, deps) {
|
|
|
230
231
|
// them with contextIsolation/sandbox off so the render runtime + its preload
|
|
231
232
|
// share the page realm. (A top-level WebContentsView can host these guests; a
|
|
232
233
|
// `<webview>` guest cannot — that's the whole point of Option A.)
|
|
233
|
-
//
|
|
234
|
-
// URL in will-attach (where `params.src` carries the full
|
|
235
|
-
// FIFO in the matching did-attach — `guestWc.getURL()` is
|
|
234
|
+
// Inset policy (`isTab`, `navStyle`) of each attaching guest, captured from
|
|
235
|
+
// its render-host URL in will-attach (where `params.src` carries the full
|
|
236
|
+
// URL) and consumed FIFO in the matching did-attach — `guestWc.getURL()` is
|
|
237
|
+
// still empty there.
|
|
236
238
|
// Per-attach scope: a fresh simWc + handlers are built on every (re)attach.
|
|
237
239
|
// (The guest's `bgColor` query param — WeChat/Android/Harmony white-flash
|
|
238
240
|
// parity — is consumed entirely outside main: device-shell.tsx's `<webview>`
|
|
239
241
|
// CSS background and render-host/preload.cjs both read it directly, since
|
|
240
242
|
// `WebContents` has no `setBackgroundColor` for main to call here.)
|
|
241
|
-
const
|
|
243
|
+
const pendingGuestPages = [];
|
|
242
244
|
simWc.on('will-attach-webview', (_event, webPreferences, params) => {
|
|
243
245
|
;
|
|
244
246
|
webPreferences.partition = partition;
|
|
245
247
|
params.partition = partition;
|
|
246
248
|
webPreferences.contextIsolation = false;
|
|
247
249
|
webPreferences.sandbox = false;
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
isTab = new URL(params.src).searchParams.get('isTab') === '1';
|
|
251
|
-
}
|
|
252
|
-
catch { /* keep false */ }
|
|
253
|
-
pendingGuestIsTab.push(isTab);
|
|
250
|
+
pendingGuestPages.push(parseGuestPageInsetPolicy(params.src));
|
|
254
251
|
});
|
|
255
252
|
simWc.on('did-attach-webview', (_event, guestWc) => {
|
|
256
253
|
// Scale the nested render-host page with the device zoom. The host WCV is
|
|
@@ -264,13 +261,13 @@ export function createNativeSimulatorView(ctx, reconciler, deps) {
|
|
|
264
261
|
}
|
|
265
262
|
catch { /* guest not ready; setNativeSimulatorViewBounds re-applies */ }
|
|
266
263
|
// Simulate this device's CSS env(safe-area-inset-*) on the fresh guest
|
|
267
|
-
// before it paints, so notch-aware page layout resolves correctly.
|
|
268
|
-
// bottom inset
|
|
269
|
-
//
|
|
270
|
-
//
|
|
264
|
+
// before it paints, so notch-aware page layout resolves correctly. Both
|
|
265
|
+
// the top and the bottom inset depend on the page (see services/safe-area):
|
|
266
|
+
// only a custom-nav page borders the unsafe top zone, and only a non-tab
|
|
267
|
+
// page borders the bottom one. The policy was captured from the
|
|
271
268
|
// render-host URL in will-attach (FIFO).
|
|
272
|
-
const
|
|
273
|
-
safeArea.applyToGuest(guestWc, ctx.bridge?.getDevice() ?? null,
|
|
269
|
+
const guestPage = pendingGuestPages.shift() ?? { isTabPage: false, isCustomNav: false };
|
|
270
|
+
safeArea.applyToGuest(guestWc, ctx.bridge?.getDevice() ?? null, guestPage);
|
|
274
271
|
// Page-level resource loads (images/fonts/page fetch) run in THIS guest's
|
|
275
272
|
// network stack, never the simulator's — without this, only wx.request
|
|
276
273
|
// (forwarded to the simulator) shows in the Network panel and everything
|
|
@@ -16,6 +16,10 @@ export interface ProjectCreateShowPayload {
|
|
|
16
16
|
templates: unknown[];
|
|
17
17
|
defaultBaseDir: string;
|
|
18
18
|
}
|
|
19
|
+
/** Payload shown by the device-picker overlay panel (`devicePicker:show`). */
|
|
20
|
+
export interface DevicePickerShowPayload {
|
|
21
|
+
deviceName: string;
|
|
22
|
+
}
|
|
19
23
|
/**
|
|
20
24
|
* The main-owned overlay panels: the settings sheet (right-side panel over a
|
|
21
25
|
* transparent backdrop), the transient compile-mode popover, and the tooltip.
|
|
@@ -65,8 +69,17 @@ export interface OverlayPanelsView {
|
|
|
65
69
|
hideUpdateDialog(): void;
|
|
66
70
|
/** Forward a download-progress tick into the (already-shown) update overlay. */
|
|
67
71
|
notifyUpdateDownloadProgress(percent: number): void;
|
|
72
|
+
/**
|
|
73
|
+
* Show the simulator toolbar's device picker (VIEW_LAYER.dialog). Same
|
|
74
|
+
* reason as `showProjectCreateDialog`: the simulator WCV overlaps the
|
|
75
|
+
* centred search panel, so it cannot be a DOM dialog in the toolbar's own
|
|
76
|
+
* renderer.
|
|
77
|
+
*/
|
|
78
|
+
showDevicePicker(data: DevicePickerShowPayload): void;
|
|
79
|
+
hideDevicePicker(): void;
|
|
68
80
|
getProjectCreateDialogWebContentsId(): number | null;
|
|
69
81
|
getUpdateDialogWebContentsId(): number | null;
|
|
82
|
+
getDevicePickerWebContentsId(): number | null;
|
|
70
83
|
}
|
|
71
84
|
export declare function createOverlayPanelsView(ctx: ViewManagerContext, reconciler: PlacementReconciler, deps: {
|
|
72
85
|
/** The host-toolbar strip height that offsets the overlay top edge. */
|