@dimina-kit/devtools 0.3.2-dev.20260601115343 → 0.3.2-dev.20260610082053
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 +49 -59
- package/dist/main/api.d.ts +1 -2
- package/dist/main/api.js +5 -1
- package/dist/main/app/app.d.ts +15 -5
- package/dist/main/app/app.js +242 -122
- package/dist/main/app/bootstrap.d.ts +16 -0
- package/dist/main/app/bootstrap.js +20 -0
- package/dist/main/app/launch.d.ts +8 -4
- package/dist/main/app/launch.js +9 -4
- package/dist/main/index.bundle.js +5812 -1729
- package/dist/main/index.js +9 -1
- package/dist/main/ipc/app.d.ts +1 -1
- package/dist/main/ipc/bridge-router.d.ts +61 -0
- package/dist/main/ipc/bridge-router.js +1300 -0
- package/dist/main/ipc/panels.d.ts +1 -1
- package/dist/main/ipc/panels.js +6 -2
- package/dist/main/ipc/popover.d.ts +1 -1
- package/dist/main/ipc/project-fs.d.ts +1 -1
- package/dist/main/ipc/projects.d.ts +1 -1
- package/dist/main/ipc/session.d.ts +1 -1
- package/dist/main/ipc/settings.d.ts +1 -1
- package/dist/main/ipc/simulator-module.d.ts +6 -0
- package/dist/main/ipc/simulator-module.js +9 -1
- package/dist/main/ipc/simulator.d.ts +2 -2
- package/dist/main/ipc/simulator.js +49 -5
- package/dist/main/ipc/toolbar.d.ts +1 -1
- package/dist/main/ipc/views.d.ts +1 -1
- package/dist/main/ipc/views.js +40 -2
- package/dist/main/runtime/devtools-backend.d.ts +17 -0
- package/dist/main/runtime/devtools-backend.js +49 -0
- package/dist/main/runtime/miniapp-runtime.d.ts +39 -0
- package/dist/main/runtime/miniapp-runtime.js +17 -0
- package/dist/main/services/automation/exec.d.ts +27 -2
- package/dist/main/services/automation/exec.js +37 -3
- package/dist/main/services/automation/handlers/app.js +127 -11
- package/dist/main/services/automation/handlers/page.js +36 -19
- package/dist/main/services/automation/index.js +40 -13
- package/dist/main/services/automation/wait-active-page.d.ts +56 -0
- package/dist/main/services/automation/wait-active-page.js +71 -0
- package/dist/main/services/console-forward/index.d.ts +36 -0
- package/dist/main/services/console-forward/index.js +81 -0
- package/dist/main/services/dimina-resource-server.d.ts +7 -0
- package/dist/main/services/dimina-resource-server.js +99 -0
- package/dist/main/services/elements-forward/index.d.ts +66 -0
- package/dist/main/services/elements-forward/index.js +583 -0
- package/dist/main/services/layout/index.d.ts +22 -0
- package/dist/main/services/layout/index.js +25 -0
- package/dist/main/services/mcp/index.d.ts +1 -0
- package/dist/main/services/mcp/index.js +3 -0
- package/dist/main/services/mcp/server.d.ts +1 -1
- package/dist/main/services/mcp/server.js +1 -1
- package/dist/main/services/mcp/target-manager.d.ts +35 -0
- package/dist/main/services/mcp/target-manager.js +63 -1
- package/dist/main/services/mcp/tools/context-tools.js +15 -1
- package/dist/main/services/module.d.ts +1 -1
- package/dist/main/services/network-forward/index.d.ts +190 -0
- package/dist/main/services/network-forward/index.js +765 -0
- package/dist/main/services/notifications/renderer-notifier.d.ts +11 -0
- package/dist/main/services/notifications/renderer-notifier.js +7 -1
- package/dist/main/services/render-inspect/index.d.ts +41 -0
- package/dist/main/services/render-inspect/index.js +88 -0
- package/dist/main/services/safe-area/index.d.ts +17 -0
- package/dist/main/services/safe-area/index.js +59 -0
- package/dist/main/services/service-host-pool/pool.d.ts +197 -0
- package/dist/main/services/service-host-pool/pool.js +364 -0
- package/dist/main/services/simulator/custom-apis.d.ts +34 -0
- package/dist/main/services/simulator/custom-apis.js +22 -0
- package/dist/main/services/simulator-appdata/index.d.ts +35 -0
- package/dist/main/services/simulator-appdata/index.js +71 -0
- package/dist/main/services/simulator-current-page/index.d.ts +24 -0
- package/dist/main/services/simulator-current-page/index.js +19 -0
- package/dist/main/services/simulator-storage/index.d.ts +37 -2
- package/dist/main/services/simulator-storage/index.js +209 -32
- package/dist/main/services/simulator-storage/service-storage-ops.d.ts +40 -0
- package/dist/main/services/simulator-storage/service-storage-ops.js +67 -0
- package/dist/main/services/simulator-temp-files/index.d.ts +1 -1
- package/dist/main/services/simulator-temp-files/index.js +1 -1
- package/dist/main/services/simulator-wxml/index.d.ts +29 -0
- package/dist/main/services/simulator-wxml/index.js +28 -0
- package/dist/main/services/toolbar/toolbar-store.d.ts +3 -3
- package/dist/main/services/toolbar/toolbar-store.js +1 -18
- package/dist/main/services/views/devtools-tabs.d.ts +47 -0
- package/dist/main/services/views/devtools-tabs.js +95 -0
- package/dist/main/services/views/view-manager.d.ts +125 -0
- package/dist/main/services/views/view-manager.js +839 -4
- package/dist/main/services/workbench-context.d.ts +67 -7
- package/dist/main/services/workbench-context.js +6 -1
- package/dist/main/services/workspace/workspace-service.js +7 -13
- package/dist/main/utils/ipc-registry.d.ts +1 -1
- package/dist/main/utils/ipc-registry.js +21 -4
- package/dist/main/utils/paths.d.ts +15 -0
- package/dist/main/utils/paths.js +19 -0
- package/dist/main/utils/sender-policy.d.ts +9 -3
- package/dist/main/utils/sender-policy.js +18 -4
- package/dist/main/utils/theme.d.ts +1 -1
- package/dist/main/utils/theme.js +1 -1
- package/dist/main/windows/main-window/create.d.ts +0 -6
- package/dist/main/windows/main-window/create.js +11 -59
- package/dist/main/windows/main-window/events.d.ts +1 -1
- package/dist/main/windows/main-window/events.js +1 -1
- package/dist/main/windows/service-host-window/create.d.ts +52 -0
- package/dist/main/windows/service-host-window/create.js +112 -0
- package/dist/native-host/common/common.js +368 -0
- package/dist/native-host/container/pageFrame.css +1 -0
- package/dist/native-host/render/render.js +9334 -0
- package/dist/native-host/service/service.js +6 -0
- package/dist/preload/index.d.ts +2 -0
- package/dist/preload/index.js +6 -0
- package/dist/preload/instrumentation/app-data.d.ts +18 -20
- package/dist/preload/instrumentation/app-data.js +23 -160
- package/dist/preload/instrumentation/wxml-extract.d.ts +1 -1
- package/dist/preload/instrumentation/wxml-extract.js +1 -1
- package/dist/preload/runtime/bridge.d.ts +3 -8
- package/dist/preload/runtime/bridge.js +2 -32
- package/dist/preload/runtime/custom-apis.js +20 -17
- package/dist/preload/runtime/host-toolbar-advertiser.d.ts +27 -0
- package/dist/preload/runtime/host-toolbar-advertiser.js +55 -0
- package/dist/preload/runtime/main-api-runner.d.ts +9 -0
- package/dist/preload/runtime/main-api-runner.js +85 -0
- package/dist/preload/runtime/native-host.d.ts +43 -0
- package/dist/preload/runtime/native-host.js +83 -0
- package/dist/preload/shared/expose.d.ts +10 -5
- package/dist/preload/shared/expose.js +30 -12
- package/dist/preload/shared/sid-registry.d.ts +11 -0
- package/dist/preload/shared/sid-registry.js +38 -0
- package/dist/preload/windows/host-toolbar.cjs +161 -0
- package/dist/preload/windows/host-toolbar.cjs.map +7 -0
- package/dist/preload/windows/host-toolbar.d.ts +2 -0
- package/dist/preload/windows/host-toolbar.js +12 -0
- package/dist/preload/windows/main.cjs +1935 -0
- package/dist/preload/windows/main.cjs.map +4 -4
- package/dist/preload/windows/simulator.cjs +925 -0
- package/dist/preload/windows/simulator.cjs.map +7 -0
- package/dist/preload/windows/simulator.js +244 -574
- package/dist/render-host/pageFrame.html +29 -0
- package/dist/render-host/preload.cjs +154 -0
- package/dist/render-host/render-inspect.js +295 -0
- package/dist/renderer/assets/index-CcJKzatF.js +50 -0
- package/dist/renderer/assets/{input-CCYS8Ave.js → input-QGx6FFX1.js} +2 -2
- package/dist/renderer/assets/ipc-transport-BT4QYQqu.css +1 -0
- package/dist/renderer/assets/{ipc-transport-Bn4KXvhu.js → ipc-transport-DvZvwK-Z.js} +2 -2
- package/dist/renderer/assets/{popover-CH4rwpdt.js → popover-BOH1If1J.js} +2 -2
- package/dist/renderer/assets/select-C7JQ8G5N.js +2 -0
- package/dist/renderer/assets/{settings-CMTB-t0x.js → settings-DpAbTJyF.js} +2 -2
- package/dist/renderer/assets/{settings-api-Csdngf9Z.js → settings-api-RD2IZF53.js} +2 -2
- package/dist/renderer/assets/{workbenchSettings-CODFCzOg.js → workbenchSettings-CNJX4Qna.js} +2 -2
- package/dist/renderer/entries/main/index.html +5 -5
- package/dist/renderer/entries/popover/index.html +5 -5
- package/dist/renderer/entries/settings/index.html +5 -5
- package/dist/renderer/entries/workbench-settings/index.html +4 -4
- package/dist/service-host/preload.cjs +254 -0
- package/dist/service-host/service.html +10 -0
- package/dist/service-host/sourcemap-rewrite.cjs +58 -0
- package/dist/service-host/sync-api-patch.js +20 -0
- package/dist/service-host/sync-impls/menu-button.js +16 -0
- package/dist/service-host/sync-impls/storage.js +50 -0
- package/dist/service-host/sync-impls/system-info.js +54 -0
- package/dist/shared/appdata-accumulator.d.ts +95 -0
- package/dist/shared/appdata-accumulator.js +213 -0
- package/dist/shared/bridge-channels.d.ts +364 -0
- package/dist/shared/bridge-channels.js +54 -0
- package/dist/shared/ipc-channels.d.ts +84 -1
- package/dist/shared/ipc-channels.js +90 -10
- package/dist/shared/ipc-schemas.d.ts +59 -2
- package/dist/shared/ipc-schemas.js +64 -3
- package/dist/shared/open-in-editor.d.ts +71 -0
- package/dist/shared/open-in-editor.js +138 -0
- package/dist/shared/simulator-api-metadata.d.ts +21 -0
- package/dist/shared/simulator-api-metadata.js +23 -0
- package/dist/shared/types.d.ts +2 -39
- package/dist/simulator/assets/device-shell-DsdcNEkt.css +1 -0
- package/dist/simulator/assets/device-shell-vwYSOVrh.js +2 -0
- package/dist/simulator/assets/jsx-runtime-P6ZegaOf.js +2 -0
- package/dist/simulator/assets/simulator-DddliUL5.js +10 -0
- package/dist/simulator/assets/simulator-mini-app-BDNu5n26.js +2 -0
- package/dist/simulator/device-shell/menu-button-geometry.js +8 -0
- package/dist/simulator/simulator.html +2 -112
- package/package.json +8 -9
- package/dist/main/utils/disposable.d.ts +0 -18
- package/dist/main/utils/disposable.js +0 -67
- package/dist/renderer/assets/index-BDMxXUfn.js +0 -50
- package/dist/renderer/assets/ipc-transport-Cu7tubyg.css +0 -1
- package/dist/renderer/assets/select-Ct4-sijm.js +0 -2
- package/dist/simulator/assets/simulator-B4e3c6_O.js +0 -9
|
@@ -4,29 +4,32 @@ import { exposeOnMainWorld } from '../shared/expose.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* Re-send interval and ceiling for `list()` (see `listWithRetry`).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* call would otherwise hang until `custom-api-boot.ts`'s 3s deadlock-breaker.
|
|
7
|
+
* `ipcRenderer.send` is fire-and-forget — a request sent before the main-side
|
|
8
|
+
* `ipcMain.on` listener is live (e.g. across a relaunch / re-attach cycle) is
|
|
9
|
+
* lost, and the bridge call would otherwise hang until `custom-api-boot.ts`'s
|
|
10
|
+
* 3s deadlock-breaker.
|
|
12
11
|
*
|
|
13
12
|
* `list` is an idempotent read, so it is safe to re-send until a response
|
|
14
|
-
* arrives. The retry resolves
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* arrives. The retry resolves quickly in practice; the ceiling only bounds the
|
|
14
|
+
* leak if the listener never answers, and is kept below `custom-api-boot.ts`'s
|
|
15
|
+
* `CUSTOM_API_LIST_TIMEOUT_MS` so the retry exhausts before — not after — that
|
|
16
|
+
* outer timeout would fire.
|
|
18
17
|
*/
|
|
19
18
|
const LIST_RETRY_INTERVAL_MS = 150;
|
|
20
19
|
const LIST_RETRY_CEILING_MS = 2500;
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
// back
|
|
26
|
-
//
|
|
20
|
+
// native-host is the sole runtime: the simulator is a top-level
|
|
21
|
+
// WebContentsView with no embedder to `sendToHost`, so it `ipcRenderer.send`s
|
|
22
|
+
// the request straight to a `ctx.simulatorApis`-backed `ipcMain.on` listener
|
|
23
|
+
// bound to this exact simWc (see view-manager `attachNativeCustomApiBridge`),
|
|
24
|
+
// which posts the result back via `simWc.send`. Responses land on the
|
|
25
|
+
// `ipcRenderer.on(Response)` handler and are correlated to requests by id, so
|
|
26
|
+
// concurrent invokes do not tangle.
|
|
27
27
|
function buildBridge() {
|
|
28
28
|
let nextId = 1;
|
|
29
29
|
const pending = new Map();
|
|
30
|
+
const sendRequest = (req) => {
|
|
31
|
+
ipcRenderer.send(SimulatorCustomApiBridgeChannel.Request, req);
|
|
32
|
+
};
|
|
30
33
|
ipcRenderer.on(SimulatorCustomApiBridgeChannel.Response, (_event, payload) => {
|
|
31
34
|
const entry = pending.get(payload.id);
|
|
32
35
|
if (!entry)
|
|
@@ -45,7 +48,7 @@ function buildBridge() {
|
|
|
45
48
|
resolve: (value) => resolve(value),
|
|
46
49
|
reject,
|
|
47
50
|
});
|
|
48
|
-
|
|
51
|
+
sendRequest(req);
|
|
49
52
|
});
|
|
50
53
|
};
|
|
51
54
|
/**
|
|
@@ -90,7 +93,7 @@ function buildBridge() {
|
|
|
90
93
|
reject(reason);
|
|
91
94
|
},
|
|
92
95
|
});
|
|
93
|
-
|
|
96
|
+
sendRequest({ id, op: 'list' });
|
|
94
97
|
};
|
|
95
98
|
state.retryTimer = setInterval(attempt, LIST_RETRY_INTERVAL_MS);
|
|
96
99
|
state.ceilingTimer = setTimeout(() => {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reverse size-advertiser preload for the host-controllable toolbar
|
|
3
|
+
* WebContentsView. Runs in that WCV's OWN renderer (the toolbar content's
|
|
4
|
+
* preload), measures the toolbar's intrinsic block (height) extent and sends it
|
|
5
|
+
* to the main process. Main pushes the value back to the main-window renderer as
|
|
6
|
+
* `HostToolbarHeightChanged`, which resizes the toolbar placeholder, re-measures
|
|
7
|
+
* the forward anchor, and re-overlays this WCV — closing the dynamic-height loop
|
|
8
|
+
* (see `@dimina-kit/view-anchor` `createSizeAdvertiser`).
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Attach the advertiser to the toolbar content's shrink-to-fit root
|
|
12
|
+
* (`[data-host-toolbar-root]`). That element MUST be shrink-to-fit on the block
|
|
13
|
+
* axis — its height must reflect the content, not the host-applied view height,
|
|
14
|
+
* or the cross-process loop never converges (`createSizeAdvertiser`'s footgun).
|
|
15
|
+
* If the element is missing we warn and no-op rather than measure `<body>`,
|
|
16
|
+
* whose block size IS the view size and would advertise nonsense.
|
|
17
|
+
*
|
|
18
|
+
* Returns a disposer that tears the advertiser down.
|
|
19
|
+
*/
|
|
20
|
+
export declare function installHostToolbarAdvertiser(): () => void;
|
|
21
|
+
/**
|
|
22
|
+
* Install once the DOM is ready (the root element must exist before we query).
|
|
23
|
+
* Self-gating: if the document is already past `loading`, install synchronously;
|
|
24
|
+
* otherwise wait for `DOMContentLoaded`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function installHostToolbarAdvertiserWhenReady(): void;
|
|
27
|
+
//# sourceMappingURL=host-toolbar-advertiser.d.ts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reverse size-advertiser preload for the host-controllable toolbar
|
|
3
|
+
* WebContentsView. Runs in that WCV's OWN renderer (the toolbar content's
|
|
4
|
+
* preload), measures the toolbar's intrinsic block (height) extent and sends it
|
|
5
|
+
* to the main process. Main pushes the value back to the main-window renderer as
|
|
6
|
+
* `HostToolbarHeightChanged`, which resizes the toolbar placeholder, re-measures
|
|
7
|
+
* the forward anchor, and re-overlays this WCV — closing the dynamic-height loop
|
|
8
|
+
* (see `@dimina-kit/view-anchor` `createSizeAdvertiser`).
|
|
9
|
+
*/
|
|
10
|
+
import { ipcRenderer } from 'electron';
|
|
11
|
+
import { createSizeAdvertiser } from '@dimina-kit/view-anchor';
|
|
12
|
+
import { ViewChannel } from '../../shared/ipc-channels.js';
|
|
13
|
+
/**
|
|
14
|
+
* Attach the advertiser to the toolbar content's shrink-to-fit root
|
|
15
|
+
* (`[data-host-toolbar-root]`). That element MUST be shrink-to-fit on the block
|
|
16
|
+
* axis — its height must reflect the content, not the host-applied view height,
|
|
17
|
+
* or the cross-process loop never converges (`createSizeAdvertiser`'s footgun).
|
|
18
|
+
* If the element is missing we warn and no-op rather than measure `<body>`,
|
|
19
|
+
* whose block size IS the view size and would advertise nonsense.
|
|
20
|
+
*
|
|
21
|
+
* Returns a disposer that tears the advertiser down.
|
|
22
|
+
*/
|
|
23
|
+
export function installHostToolbarAdvertiser() {
|
|
24
|
+
const root = document.querySelector('[data-host-toolbar-root]');
|
|
25
|
+
if (!root) {
|
|
26
|
+
console.warn('[host-toolbar-advertiser] no `[data-host-toolbar-root]` element found — ' +
|
|
27
|
+
'not advertising a height. The toolbar content must wrap itself in a ' +
|
|
28
|
+
'shrink-to-fit `[data-host-toolbar-root]` element so its block size is ' +
|
|
29
|
+
'the content height, not the host-given view size.');
|
|
30
|
+
return () => { };
|
|
31
|
+
}
|
|
32
|
+
const advertiser = createSizeAdvertiser(root, {
|
|
33
|
+
axis: 'block',
|
|
34
|
+
publish: (size) => {
|
|
35
|
+
ipcRenderer.send(ViewChannel.HostToolbarAdvertiseHeight, size);
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
return () => advertiser.dispose();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Install once the DOM is ready (the root element must exist before we query).
|
|
42
|
+
* Self-gating: if the document is already past `loading`, install synchronously;
|
|
43
|
+
* otherwise wait for `DOMContentLoaded`.
|
|
44
|
+
*/
|
|
45
|
+
export function installHostToolbarAdvertiserWhenReady() {
|
|
46
|
+
if (document.readyState === 'loading') {
|
|
47
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
48
|
+
installHostToolbarAdvertiser();
|
|
49
|
+
}, { once: true });
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
installHostToolbarAdvertiser();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=host-toolbar-advertiser.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type LooseApiHandler = (this: any, params?: unknown) => unknown | Promise<unknown>;
|
|
2
|
+
export interface ApiRunVerdict {
|
|
3
|
+
ok: boolean;
|
|
4
|
+
result?: unknown;
|
|
5
|
+
errMsg?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function runApiAsync(handlers: Record<string, LooseApiHandler | undefined>, name: string, params: unknown): Promise<ApiRunVerdict>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=main-api-runner.d.ts.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
function makeBaseContext() {
|
|
2
|
+
// Minimal viewport rect: enough for handlers that read
|
|
3
|
+
// `parent.el.querySelector('.dimina-native-webview__root').getBoundingClientRect()`
|
|
4
|
+
// (see simulator-api.ts readWindowMetrics).
|
|
5
|
+
const fakeRect = { width: 390, height: 844, x: 0, y: 0, top: 0, left: 0, right: 390, bottom: 844 };
|
|
6
|
+
const fakeRoot = {
|
|
7
|
+
getBoundingClientRect: () => fakeRect,
|
|
8
|
+
};
|
|
9
|
+
return {
|
|
10
|
+
appId: '',
|
|
11
|
+
createCallbackFunction: () => undefined,
|
|
12
|
+
parent: {
|
|
13
|
+
el: {
|
|
14
|
+
querySelector: () => fakeRoot,
|
|
15
|
+
},
|
|
16
|
+
getStatusBarRect: () => ({ height: 0 }),
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function runApiAsync(handlers, name, params) {
|
|
21
|
+
const handler = handlers[name];
|
|
22
|
+
if (!handler) {
|
|
23
|
+
return Promise.resolve({ ok: false, errMsg: `${name}:fail no handler` });
|
|
24
|
+
}
|
|
25
|
+
return new Promise((resolve) => {
|
|
26
|
+
let resolved = false;
|
|
27
|
+
const finish = (verdict) => {
|
|
28
|
+
if (resolved)
|
|
29
|
+
return;
|
|
30
|
+
resolved = true;
|
|
31
|
+
resolve(verdict);
|
|
32
|
+
};
|
|
33
|
+
const SUCCESS = Symbol('main-cb-success');
|
|
34
|
+
const FAIL = Symbol('main-cb-fail');
|
|
35
|
+
const COMPLETE = Symbol('main-cb-complete');
|
|
36
|
+
const base = makeBaseContext();
|
|
37
|
+
const ctx = {
|
|
38
|
+
...base,
|
|
39
|
+
createCallbackFunction(id) {
|
|
40
|
+
if (id === undefined || id === null)
|
|
41
|
+
return undefined;
|
|
42
|
+
return (...args) => {
|
|
43
|
+
const arg = args[0];
|
|
44
|
+
if (id === SUCCESS) {
|
|
45
|
+
finish({ ok: true, result: arg });
|
|
46
|
+
}
|
|
47
|
+
else if (id === FAIL) {
|
|
48
|
+
const errMsg = arg && typeof arg === 'object' && 'errMsg' in arg
|
|
49
|
+
? String(arg.errMsg)
|
|
50
|
+
: `${name}:fail`;
|
|
51
|
+
finish({ ok: false, errMsg, result: arg });
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
const userParams = params && typeof params === 'object' && !Array.isArray(params)
|
|
57
|
+
? { ...params }
|
|
58
|
+
: {};
|
|
59
|
+
const hadSuccess = userParams.success !== undefined && userParams.success !== null;
|
|
60
|
+
const hadFail = userParams.fail !== undefined && userParams.fail !== null;
|
|
61
|
+
const hadComplete = userParams.complete !== undefined && userParams.complete !== null;
|
|
62
|
+
userParams.success = SUCCESS;
|
|
63
|
+
userParams.fail = FAIL;
|
|
64
|
+
if (hadComplete)
|
|
65
|
+
userParams.complete = COMPLETE;
|
|
66
|
+
try {
|
|
67
|
+
const ret = handler.call(ctx, userParams);
|
|
68
|
+
if (ret && typeof ret.then === 'function') {
|
|
69
|
+
Promise.resolve(ret).then((r) => finish({ ok: true, result: r }), (err) => {
|
|
70
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
71
|
+
finish({ ok: false, errMsg: `${name}:fail ${msg}` });
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (!hadSuccess && !hadFail) {
|
|
76
|
+
finish({ ok: true, result: ret });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
81
|
+
finish({ ok: false, errMsg: `${name}:fail ${msg}` });
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=main-api-runner.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { NativeDeviceInfo } from '../../shared/ipc-channels.js';
|
|
2
|
+
import type { ActivePagePayload, ApiResponsePayload, NavCallbackPayload, PageLifecyclePayload, PageOpenRequest, PageOpenResult, PageStackPayload, SpawnRequest, SpawnResult } from '../../shared/bridge-channels.js';
|
|
3
|
+
export interface RenderHostUrlOptions {
|
|
4
|
+
bridgeId: string;
|
|
5
|
+
appId: string;
|
|
6
|
+
pagePath: string;
|
|
7
|
+
}
|
|
8
|
+
export interface DiminaNativeHostBridge {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
spawn(opts: SpawnRequest): Promise<SpawnResult>;
|
|
11
|
+
dispose(bridgeId: string): void;
|
|
12
|
+
openPage(opts: PageOpenRequest): Promise<PageOpenResult>;
|
|
13
|
+
closePage(bridgeId: string): void;
|
|
14
|
+
notifyLifecycle(payload: PageLifecyclePayload): void;
|
|
15
|
+
notifyNavCallback(payload: NavCallbackPayload): void;
|
|
16
|
+
notifyApiResponse(payload: ApiResponsePayload): void;
|
|
17
|
+
/** Tell main which page is the visible top-of-stack (for panel/automation targeting). */
|
|
18
|
+
notifyActivePage(payload: ActivePagePayload): void;
|
|
19
|
+
/** Tell main the full ordered page stack (for automation's App.getPageStack). */
|
|
20
|
+
notifyPageStack(payload: PageStackPayload): void;
|
|
21
|
+
createRenderHostUrl(opts: RenderHostUrlOptions): string;
|
|
22
|
+
renderPreloadUrl: string;
|
|
23
|
+
/**
|
|
24
|
+
* The selected device at bridge-install time, if the renderer already pushed
|
|
25
|
+
* it (it does — SetDeviceInfo precedes AttachNative). DeviceShell reads this
|
|
26
|
+
* as its initial device; live changes arrive via the DEVICE_CHANGE event.
|
|
27
|
+
*/
|
|
28
|
+
device?: NativeDeviceInfo;
|
|
29
|
+
/**
|
|
30
|
+
* Subscribe to a main→simulator event channel (SIMULATOR_EVENTS). Returns an
|
|
31
|
+
* unsubscribe fn. The simulator renderer (DeviceShell) runs in the webview
|
|
32
|
+
* main world with `nodeIntegration:false`, so it cannot `import 'electron'`;
|
|
33
|
+
* this bridge owns the `ipcRenderer` plumbing on its behalf.
|
|
34
|
+
*/
|
|
35
|
+
onSimulatorEvent<T = unknown>(channel: string, listener: (payload: T) => void): () => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Install the native-host bridge on the simulator main world when native-host
|
|
39
|
+
* mode is on. Self-gating: a no-op disposer is returned when it's off, so the
|
|
40
|
+
* caller can install unconditionally.
|
|
41
|
+
*/
|
|
42
|
+
export declare function installNativeHostBridge(): () => void;
|
|
43
|
+
//# sourceMappingURL=native-host.d.ts.map
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { ipcRenderer } from 'electron';
|
|
2
|
+
import { BRIDGE_CHANNELS as C } from '../../shared/bridge-channels.js';
|
|
3
|
+
import { exposeOnMainWorld } from '../shared/expose.js';
|
|
4
|
+
/**
|
|
5
|
+
* Ask the main process (synchronously, at install time) whether native-host is
|
|
6
|
+
* on and, if so, for the render-host file:// URLs. The simulator webview's
|
|
7
|
+
* preload can't read the launch `process.env`, and — crucially — can't use
|
|
8
|
+
* `node:path`/`node:url` to compute paths (the guest preload has no Node
|
|
9
|
+
* builtins), so the main process (which has both) supplies everything here.
|
|
10
|
+
*/
|
|
11
|
+
function queryNativeHostConfig() {
|
|
12
|
+
try {
|
|
13
|
+
const res = ipcRenderer.sendSync(C.NATIVE_HOST_ENABLED);
|
|
14
|
+
return res && res.enabled ? res : null;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function buildBridge(cfg) {
|
|
21
|
+
return {
|
|
22
|
+
enabled: true,
|
|
23
|
+
spawn(opts) {
|
|
24
|
+
return ipcRenderer.invoke(C.SPAWN, opts);
|
|
25
|
+
},
|
|
26
|
+
dispose(bridgeId) {
|
|
27
|
+
const payload = { bridgeId };
|
|
28
|
+
ipcRenderer.send(C.DISPOSE, payload);
|
|
29
|
+
},
|
|
30
|
+
openPage(opts) {
|
|
31
|
+
return ipcRenderer.invoke(C.PAGE_OPEN, opts);
|
|
32
|
+
},
|
|
33
|
+
closePage(bridgeId) {
|
|
34
|
+
const payload = { bridgeId };
|
|
35
|
+
ipcRenderer.send(C.PAGE_CLOSE, payload);
|
|
36
|
+
},
|
|
37
|
+
notifyLifecycle(payload) {
|
|
38
|
+
ipcRenderer.send(C.PAGE_LIFECYCLE, payload);
|
|
39
|
+
},
|
|
40
|
+
notifyNavCallback(payload) {
|
|
41
|
+
ipcRenderer.send(C.NAV_CALLBACK, payload);
|
|
42
|
+
},
|
|
43
|
+
notifyApiResponse(payload) {
|
|
44
|
+
ipcRenderer.send(C.API_RESPONSE, payload);
|
|
45
|
+
},
|
|
46
|
+
notifyActivePage(payload) {
|
|
47
|
+
ipcRenderer.send(C.ACTIVE_PAGE, payload);
|
|
48
|
+
},
|
|
49
|
+
notifyPageStack(payload) {
|
|
50
|
+
ipcRenderer.send(C.PAGE_STACK, payload);
|
|
51
|
+
},
|
|
52
|
+
createRenderHostUrl(opts) {
|
|
53
|
+
// `URL` + `URLSearchParams` are web globals — no node:url needed.
|
|
54
|
+
const url = new URL(cfg.renderHostHtmlUrl);
|
|
55
|
+
url.searchParams.set('bridgeId', opts.bridgeId);
|
|
56
|
+
url.searchParams.set('appId', opts.appId);
|
|
57
|
+
url.searchParams.set('pagePath', opts.pagePath);
|
|
58
|
+
return url.toString();
|
|
59
|
+
},
|
|
60
|
+
renderPreloadUrl: cfg.renderPreloadUrl,
|
|
61
|
+
device: cfg.device,
|
|
62
|
+
onSimulatorEvent(channel, listener) {
|
|
63
|
+
const wrapped = (_event, payload) => {
|
|
64
|
+
;
|
|
65
|
+
listener(payload);
|
|
66
|
+
};
|
|
67
|
+
ipcRenderer.on(channel, wrapped);
|
|
68
|
+
return () => ipcRenderer.removeListener(channel, wrapped);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Install the native-host bridge on the simulator main world when native-host
|
|
74
|
+
* mode is on. Self-gating: a no-op disposer is returned when it's off, so the
|
|
75
|
+
* caller can install unconditionally.
|
|
76
|
+
*/
|
|
77
|
+
export function installNativeHostBridge() {
|
|
78
|
+
const cfg = queryNativeHostConfig();
|
|
79
|
+
if (!cfg)
|
|
80
|
+
return () => { };
|
|
81
|
+
return exposeOnMainWorld('__diminaNativeHost', buildBridge(cfg));
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=native-host.js.map
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Expose `value` on the renderer's main world under `key`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
4
|
+
* Uses Electron's `contextBridge` only when `contextIsolation` is enabled
|
|
5
|
+
* (the path that reaches the renderer's `window` through the isolated world).
|
|
6
|
+
* When context isolation is OFF — e.g. the simulator/render-host/service-host
|
|
7
|
+
* frames — `contextBridge.exposeInMainWorld` would always throw, so we skip it
|
|
8
|
+
* entirely and assign `value` directly onto the preload realm's `window`.
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
+
* `process.contextIsolated` is Electron's renderer-side boolean for the current
|
|
11
|
+
* frame: `true` when context isolation is on, `false` when it's off. (It is
|
|
12
|
+
* `undefined` only in the main process, which never runs this preload helper.)
|
|
13
|
+
*
|
|
14
|
+
* Returns a disposer. It can only undo the direct-assignment path (a
|
|
10
15
|
* `contextBridge` binding cannot be un-exposed); on the contextBridge path
|
|
11
16
|
* the disposer is a no-op. The disposer never clobbers a `window[key]` that
|
|
12
17
|
* something else has since reassigned.
|
|
@@ -2,28 +2,46 @@ import { contextBridge } from 'electron';
|
|
|
2
2
|
/**
|
|
3
3
|
* Expose `value` on the renderer's main world under `key`.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* `
|
|
5
|
+
* Uses Electron's `contextBridge` only when `contextIsolation` is enabled
|
|
6
|
+
* (the path that reaches the renderer's `window` through the isolated world).
|
|
7
|
+
* When context isolation is OFF — e.g. the simulator/render-host/service-host
|
|
8
|
+
* frames — `contextBridge.exposeInMainWorld` would always throw, so we skip it
|
|
9
|
+
* entirely and assign `value` directly onto the preload realm's `window`.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
+
* `process.contextIsolated` is Electron's renderer-side boolean for the current
|
|
12
|
+
* frame: `true` when context isolation is on, `false` when it's off. (It is
|
|
13
|
+
* `undefined` only in the main process, which never runs this preload helper.)
|
|
14
|
+
*
|
|
15
|
+
* Returns a disposer. It can only undo the direct-assignment path (a
|
|
11
16
|
* `contextBridge` binding cannot be un-exposed); on the contextBridge path
|
|
12
17
|
* the disposer is a no-op. The disposer never clobbers a `window[key]` that
|
|
13
18
|
* something else has since reassigned.
|
|
14
19
|
*/
|
|
15
20
|
export function exposeOnMainWorld(key, value) {
|
|
16
|
-
let
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
let assignedToWindow = false;
|
|
22
|
+
if (process.contextIsolated) {
|
|
23
|
+
// Isolated world (main / settings / view-manager host windows): the only
|
|
24
|
+
// way to reach the renderer's `window` is via contextBridge. Keep the
|
|
25
|
+
// defensive fallback + warn for the genuinely-unexpected failure case.
|
|
26
|
+
try {
|
|
27
|
+
contextBridge.exposeInMainWorld(key, value);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
console.warn('[devtools/expose] contextBridge.exposeInMainWorld failed, falling back to direct window assignment:', err);
|
|
31
|
+
window[key] = value;
|
|
32
|
+
assignedToWindow = true;
|
|
33
|
+
}
|
|
19
34
|
}
|
|
20
|
-
|
|
21
|
-
|
|
35
|
+
else {
|
|
36
|
+
// Context isolation off (simulator <webview>, render-host, service-host):
|
|
37
|
+
// contextBridge is unusable here and would always throw, so assign the
|
|
38
|
+
// preload realm's `window` directly without the noisy failed attempt.
|
|
39
|
+
;
|
|
22
40
|
window[key] = value;
|
|
23
|
-
|
|
41
|
+
assignedToWindow = true;
|
|
24
42
|
}
|
|
25
43
|
return () => {
|
|
26
|
-
if (!
|
|
44
|
+
if (!assignedToWindow)
|
|
27
45
|
return;
|
|
28
46
|
const w = window;
|
|
29
47
|
if (w[key] === value)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface WxmlNode {
|
|
2
|
+
tagName: string;
|
|
3
|
+
attrs: Record<string, string>;
|
|
4
|
+
children: WxmlNode[];
|
|
5
|
+
text?: string;
|
|
6
|
+
sid?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const SYNTHETIC_SID_PREFIX = "devtools-";
|
|
9
|
+
export declare function registerSyntheticSid(el: HTMLElement): string;
|
|
10
|
+
export declare function findElementBySid(doc: Document, sid: string): HTMLElement | null;
|
|
11
|
+
//# sourceMappingURL=sid-registry.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Stable-id registry for WXML nodes, shared by the iframe-path extractor
|
|
2
|
+
// (preload/instrumentation/wxml-extract + runtime/bridge) and the native-host
|
|
3
|
+
// render-guest inspector (render-host/render-inspect). It is dependency-free so
|
|
4
|
+
// the render-inspect bundle injected into the guest main world stays small and
|
|
5
|
+
// doesn't drag in the iframe/exposeOnMainWorld machinery from runtime/bridge.
|
|
6
|
+
// 合成 sid 注册表:用 WeakMap 把元素 ↔ sid 双向绑定,避免在源 DOM 上写
|
|
7
|
+
// `data-*` 属性(提取本应只读,且属性形式会污染用户的快照/选择器)。
|
|
8
|
+
// elBySyntheticSid 为反向查找用 WeakRef,元素被 GC 后下次 lookup 自动清理。
|
|
9
|
+
export const SYNTHETIC_SID_PREFIX = 'devtools-';
|
|
10
|
+
const syntheticSidByEl = new WeakMap();
|
|
11
|
+
const elBySyntheticSid = new Map();
|
|
12
|
+
let nextSyntheticSid = 1;
|
|
13
|
+
export function registerSyntheticSid(el) {
|
|
14
|
+
const existing = syntheticSidByEl.get(el);
|
|
15
|
+
if (existing)
|
|
16
|
+
return existing;
|
|
17
|
+
const synthetic = `${SYNTHETIC_SID_PREFIX}${nextSyntheticSid++}`;
|
|
18
|
+
syntheticSidByEl.set(el, synthetic);
|
|
19
|
+
elBySyntheticSid.set(synthetic, new WeakRef(el));
|
|
20
|
+
return synthetic;
|
|
21
|
+
}
|
|
22
|
+
export function findElementBySid(doc, sid) {
|
|
23
|
+
if (sid.startsWith(SYNTHETIC_SID_PREFIX)) {
|
|
24
|
+
const ref = elBySyntheticSid.get(sid);
|
|
25
|
+
if (!ref)
|
|
26
|
+
return null;
|
|
27
|
+
const el = ref.deref();
|
|
28
|
+
if (!el || !el.isConnected) {
|
|
29
|
+
elBySyntheticSid.delete(sid);
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (el.ownerDocument !== doc)
|
|
33
|
+
return null;
|
|
34
|
+
return el;
|
|
35
|
+
}
|
|
36
|
+
return doc.querySelector(`[data-sid="${CSS.escape(sid)}"]`);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=sid-registry.js.map
|