@dimina-kit/devtools 0.3.2-dev.20260601115343 → 0.3.2-dev.20260610114009

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/README.md +49 -59
  2. package/dist/main/api.d.ts +1 -2
  3. package/dist/main/api.js +5 -1
  4. package/dist/main/app/app.d.ts +15 -5
  5. package/dist/main/app/app.js +249 -122
  6. package/dist/main/app/bootstrap.d.ts +16 -0
  7. package/dist/main/app/bootstrap.js +20 -0
  8. package/dist/main/app/launch.d.ts +8 -4
  9. package/dist/main/app/launch.js +9 -4
  10. package/dist/main/index.bundle.js +6071 -1863
  11. package/dist/main/index.js +9 -1
  12. package/dist/main/ipc/app.d.ts +1 -1
  13. package/dist/main/ipc/bridge-router.d.ts +61 -0
  14. package/dist/main/ipc/bridge-router.js +1333 -0
  15. package/dist/main/ipc/panels.d.ts +1 -1
  16. package/dist/main/ipc/panels.js +6 -2
  17. package/dist/main/ipc/popover.d.ts +1 -1
  18. package/dist/main/ipc/project-fs.d.ts +1 -1
  19. package/dist/main/ipc/projects.d.ts +1 -1
  20. package/dist/main/ipc/session.d.ts +1 -1
  21. package/dist/main/ipc/settings.d.ts +1 -1
  22. package/dist/main/ipc/simulator-module.d.ts +6 -0
  23. package/dist/main/ipc/simulator-module.js +9 -1
  24. package/dist/main/ipc/simulator.d.ts +2 -2
  25. package/dist/main/ipc/simulator.js +29 -5
  26. package/dist/main/ipc/toolbar.d.ts +1 -1
  27. package/dist/main/ipc/views.d.ts +1 -1
  28. package/dist/main/ipc/views.js +40 -2
  29. package/dist/main/runtime/devtools-backend.d.ts +17 -0
  30. package/dist/main/runtime/devtools-backend.js +49 -0
  31. package/dist/main/runtime/miniapp-runtime.d.ts +39 -0
  32. package/dist/main/runtime/miniapp-runtime.js +17 -0
  33. package/dist/main/services/automation/exec.d.ts +27 -2
  34. package/dist/main/services/automation/exec.js +37 -3
  35. package/dist/main/services/automation/handlers/app.js +127 -11
  36. package/dist/main/services/automation/handlers/page.js +36 -19
  37. package/dist/main/services/automation/index.js +40 -13
  38. package/dist/main/services/automation/wait-active-page.d.ts +56 -0
  39. package/dist/main/services/automation/wait-active-page.js +71 -0
  40. package/dist/main/services/console-forward/index.d.ts +36 -0
  41. package/dist/main/services/console-forward/index.js +81 -0
  42. package/dist/main/services/dimina-resource-server.d.ts +7 -0
  43. package/dist/main/services/dimina-resource-server.js +99 -0
  44. package/dist/main/services/elements-forward/index.d.ts +66 -0
  45. package/dist/main/services/elements-forward/index.js +583 -0
  46. package/dist/main/services/layout/index.d.ts +22 -0
  47. package/dist/main/services/layout/index.js +25 -0
  48. package/dist/main/services/mcp/index.d.ts +1 -0
  49. package/dist/main/services/mcp/index.js +3 -0
  50. package/dist/main/services/mcp/server.d.ts +1 -1
  51. package/dist/main/services/mcp/server.js +1 -1
  52. package/dist/main/services/mcp/target-manager.d.ts +35 -0
  53. package/dist/main/services/mcp/target-manager.js +63 -1
  54. package/dist/main/services/mcp/tools/context-tools.js +15 -1
  55. package/dist/main/services/module.d.ts +1 -1
  56. package/dist/main/services/network-forward/index.d.ts +190 -0
  57. package/dist/main/services/network-forward/index.js +765 -0
  58. package/dist/main/services/notifications/renderer-notifier.d.ts +11 -0
  59. package/dist/main/services/notifications/renderer-notifier.js +7 -1
  60. package/dist/main/services/render-inspect/index.d.ts +41 -0
  61. package/dist/main/services/render-inspect/index.js +88 -0
  62. package/dist/main/services/safe-area/index.d.ts +17 -0
  63. package/dist/main/services/safe-area/index.js +59 -0
  64. package/dist/main/services/service-host-pool/pool.d.ts +197 -0
  65. package/dist/main/services/service-host-pool/pool.js +364 -0
  66. package/dist/main/services/simulator/custom-apis.d.ts +34 -0
  67. package/dist/main/services/simulator/custom-apis.js +22 -0
  68. package/dist/main/services/simulator-appdata/index.d.ts +35 -0
  69. package/dist/main/services/simulator-appdata/index.js +71 -0
  70. package/dist/main/services/simulator-current-page/index.d.ts +24 -0
  71. package/dist/main/services/simulator-current-page/index.js +19 -0
  72. package/dist/main/services/simulator-storage/index.d.ts +37 -2
  73. package/dist/main/services/simulator-storage/index.js +209 -32
  74. package/dist/main/services/simulator-storage/service-storage-ops.d.ts +40 -0
  75. package/dist/main/services/simulator-storage/service-storage-ops.js +67 -0
  76. package/dist/main/services/simulator-temp-files/index.d.ts +1 -1
  77. package/dist/main/services/simulator-temp-files/index.js +39 -17
  78. package/dist/main/services/simulator-wxml/index.d.ts +29 -0
  79. package/dist/main/services/simulator-wxml/index.js +28 -0
  80. package/dist/main/services/toolbar/toolbar-store.d.ts +3 -3
  81. package/dist/main/services/toolbar/toolbar-store.js +1 -18
  82. package/dist/main/services/views/devtools-tabs.d.ts +47 -0
  83. package/dist/main/services/views/devtools-tabs.js +95 -0
  84. package/dist/main/services/views/miniapp-partition.d.ts +80 -0
  85. package/dist/main/services/views/miniapp-partition.js +138 -0
  86. package/dist/main/services/views/simulator-session-policy.d.ts +28 -0
  87. package/dist/main/services/views/simulator-session-policy.js +82 -0
  88. package/dist/main/services/views/view-manager.d.ts +125 -0
  89. package/dist/main/services/views/view-manager.js +852 -4
  90. package/dist/main/services/workbench-context.d.ts +67 -7
  91. package/dist/main/services/workbench-context.js +6 -1
  92. package/dist/main/services/workspace/workspace-service.js +7 -13
  93. package/dist/main/utils/ipc-registry.d.ts +1 -1
  94. package/dist/main/utils/ipc-registry.js +21 -4
  95. package/dist/main/utils/paths.d.ts +15 -0
  96. package/dist/main/utils/paths.js +19 -0
  97. package/dist/main/utils/sender-policy.d.ts +9 -3
  98. package/dist/main/utils/sender-policy.js +18 -4
  99. package/dist/main/utils/theme.d.ts +1 -1
  100. package/dist/main/utils/theme.js +1 -1
  101. package/dist/main/windows/main-window/create.d.ts +0 -6
  102. package/dist/main/windows/main-window/create.js +6 -80
  103. package/dist/main/windows/main-window/events.d.ts +1 -1
  104. package/dist/main/windows/main-window/events.js +1 -1
  105. package/dist/main/windows/service-host-window/create.d.ts +67 -0
  106. package/dist/main/windows/service-host-window/create.js +138 -0
  107. package/dist/native-host/common/common.js +368 -0
  108. package/dist/native-host/container/pageFrame.css +1 -0
  109. package/dist/native-host/render/render.js +9334 -0
  110. package/dist/native-host/service/service.js +6 -0
  111. package/dist/preload/index.d.ts +2 -0
  112. package/dist/preload/index.js +6 -0
  113. package/dist/preload/instrumentation/app-data.d.ts +18 -20
  114. package/dist/preload/instrumentation/app-data.js +23 -160
  115. package/dist/preload/instrumentation/wxml-extract.d.ts +1 -1
  116. package/dist/preload/instrumentation/wxml-extract.js +1 -1
  117. package/dist/preload/runtime/bridge.d.ts +3 -8
  118. package/dist/preload/runtime/bridge.js +2 -32
  119. package/dist/preload/runtime/custom-apis.js +20 -17
  120. package/dist/preload/runtime/host-toolbar-advertiser.d.ts +27 -0
  121. package/dist/preload/runtime/host-toolbar-advertiser.js +55 -0
  122. package/dist/preload/runtime/main-api-runner.d.ts +9 -0
  123. package/dist/preload/runtime/main-api-runner.js +85 -0
  124. package/dist/preload/runtime/native-host.d.ts +43 -0
  125. package/dist/preload/runtime/native-host.js +83 -0
  126. package/dist/preload/shared/expose.d.ts +10 -5
  127. package/dist/preload/shared/expose.js +30 -12
  128. package/dist/preload/shared/sid-registry.d.ts +11 -0
  129. package/dist/preload/shared/sid-registry.js +38 -0
  130. package/dist/preload/windows/host-toolbar.cjs +161 -0
  131. package/dist/preload/windows/host-toolbar.cjs.map +7 -0
  132. package/dist/preload/windows/host-toolbar.d.ts +2 -0
  133. package/dist/preload/windows/host-toolbar.js +12 -0
  134. package/dist/preload/windows/main.cjs +1935 -0
  135. package/dist/preload/windows/main.cjs.map +4 -4
  136. package/dist/preload/windows/simulator.cjs +925 -0
  137. package/dist/preload/windows/simulator.cjs.map +7 -0
  138. package/dist/preload/windows/simulator.js +244 -574
  139. package/dist/render-host/pageFrame.html +29 -0
  140. package/dist/render-host/preload.cjs +154 -0
  141. package/dist/render-host/render-inspect.js +295 -0
  142. package/dist/renderer/assets/index-CcJKzatF.js +50 -0
  143. package/dist/renderer/assets/{input-CCYS8Ave.js → input-QGx6FFX1.js} +2 -2
  144. package/dist/renderer/assets/ipc-transport-BT4QYQqu.css +1 -0
  145. package/dist/renderer/assets/{ipc-transport-Bn4KXvhu.js → ipc-transport-DvZvwK-Z.js} +2 -2
  146. package/dist/renderer/assets/{popover-CH4rwpdt.js → popover-BOH1If1J.js} +2 -2
  147. package/dist/renderer/assets/select-C7JQ8G5N.js +2 -0
  148. package/dist/renderer/assets/{settings-CMTB-t0x.js → settings-DpAbTJyF.js} +2 -2
  149. package/dist/renderer/assets/{settings-api-Csdngf9Z.js → settings-api-RD2IZF53.js} +2 -2
  150. package/dist/renderer/assets/{workbenchSettings-CODFCzOg.js → workbenchSettings-CNJX4Qna.js} +2 -2
  151. package/dist/renderer/entries/main/index.html +5 -5
  152. package/dist/renderer/entries/popover/index.html +5 -5
  153. package/dist/renderer/entries/settings/index.html +5 -5
  154. package/dist/renderer/entries/workbench-settings/index.html +4 -4
  155. package/dist/service-host/preload.cjs +254 -0
  156. package/dist/service-host/service.html +10 -0
  157. package/dist/service-host/sourcemap-rewrite.cjs +58 -0
  158. package/dist/service-host/sync-api-patch.js +20 -0
  159. package/dist/service-host/sync-impls/menu-button-geometry.js +8 -0
  160. package/dist/service-host/sync-impls/menu-button.js +16 -0
  161. package/dist/service-host/sync-impls/storage.js +50 -0
  162. package/dist/service-host/sync-impls/system-info.js +54 -0
  163. package/dist/shared/appdata-accumulator.d.ts +95 -0
  164. package/dist/shared/appdata-accumulator.js +213 -0
  165. package/dist/shared/bridge-channels.d.ts +378 -0
  166. package/dist/shared/bridge-channels.js +81 -0
  167. package/dist/shared/ipc-channels.d.ts +84 -1
  168. package/dist/shared/ipc-channels.js +90 -10
  169. package/dist/shared/ipc-schemas.d.ts +59 -2
  170. package/dist/shared/ipc-schemas.js +64 -3
  171. package/dist/shared/open-in-editor.d.ts +71 -0
  172. package/dist/shared/open-in-editor.js +138 -0
  173. package/dist/shared/simulator-api-metadata.d.ts +21 -0
  174. package/dist/shared/simulator-api-metadata.js +23 -0
  175. package/dist/shared/types.d.ts +2 -39
  176. package/dist/simulator/assets/device-shell-DsdcNEkt.css +1 -0
  177. package/dist/simulator/assets/device-shell-fH2cI-3q.js +2 -0
  178. package/dist/simulator/assets/jsx-runtime-P6ZegaOf.js +2 -0
  179. package/dist/simulator/assets/simulator-DHylZf9Z.js +10 -0
  180. package/dist/simulator/assets/simulator-mini-app-BDNu5n26.js +2 -0
  181. package/dist/simulator/device-shell/menu-button-geometry.js +8 -0
  182. package/dist/simulator/simulator.html +2 -112
  183. package/package.json +12 -12
  184. package/dist/main/utils/disposable.d.ts +0 -18
  185. package/dist/main/utils/disposable.js +0 -67
  186. package/dist/renderer/assets/index-BDMxXUfn.js +0 -50
  187. package/dist/renderer/assets/ipc-transport-Cu7tubyg.css +0 -1
  188. package/dist/renderer/assets/select-Ct4-sijm.js +0 -2
  189. 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
- * The simulator boots fast enough that `__diminaCustomApis.list()` can fire
8
- * its `sendToHost` request *before* the embedding main-window renderer has
9
- * attached its `ipc-message` proxy listener (`useCustomApiProxy`). `sendToHost`
10
- * is fire-and-forget — a request sent into that gap is lost, and the bridge
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 within one embedder attach cycle (~200ms) in
15
- * practice; the ceiling only bounds the leak if the proxy never attaches at
16
- * all, and is kept below `custom-api-boot.ts`'s `CUSTOM_API_LIST_TIMEOUT_MS`
17
- * so the retry exhausts before — not after — that outer timeout would fire.
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
- // The simulator <webview> is intentionally kept off the workbench sender-policy
22
- // white-list, so it cannot reach `ipcMain.handle` directly. Instead the bridge
23
- // asks the trusted main-window renderer to proxy the call: webview sends via
24
- // `ipcRenderer.sendToHost`, host does the `ipcInvoke`, and posts the result
25
- // back through `<webview>.send`. Requests and responses are correlated by id
26
- // so concurrent invokes do not tangle.
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
- ipcRenderer.sendToHost(SimulatorCustomApiBridgeChannel.Request, req);
51
+ sendRequest(req);
49
52
  });
50
53
  };
51
54
  /**
@@ -90,7 +93,7 @@ function buildBridge() {
90
93
  reject(reason);
91
94
  },
92
95
  });
93
- ipcRenderer.sendToHost(SimulatorCustomApiBridgeChannel.Request, { id, op: 'list' });
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
- * Prefers Electron's `contextBridge` (the path that works with
5
- * `contextIsolation: true`). When `contextBridge` is unavailable e.g. a
6
- * webview running without context isolation it falls back to assigning
7
- * `value` directly onto the preload realm's `window`.
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
- * Returns a disposer. It can only undo the fallback assignment (a
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
- * Prefers Electron's `contextBridge` (the path that works with
6
- * `contextIsolation: true`). When `contextBridge` is unavailable e.g. a
7
- * webview running without context isolation it falls back to assigning
8
- * `value` directly onto the preload realm's `window`.
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
- * Returns a disposer. It can only undo the fallback assignment (a
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 fellBack = false;
17
- try {
18
- contextBridge.exposeInMainWorld(key, value);
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
- catch (err) {
21
- console.warn('[devtools/expose] contextBridge.exposeInMainWorld failed, falling back to direct window assignment:', err);
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
- fellBack = true;
41
+ assignedToWindow = true;
24
42
  }
25
43
  return () => {
26
- if (!fellBack)
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