@dimina-kit/devtools 0.3.1 → 0.3.2-dev.20260522085907

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 (190) hide show
  1. package/README.md +297 -133
  2. package/dist/main/api.d.ts +6 -2
  3. package/dist/main/api.js +5 -2
  4. package/dist/main/app/app.d.ts +1 -1
  5. package/dist/main/app/app.js +84 -36
  6. package/dist/main/app/bootstrap.js +2 -1
  7. package/dist/main/app/launch.d.ts +2 -2
  8. package/dist/main/app/launch.js +10 -8
  9. package/dist/main/index.bundle.js +1567 -477
  10. package/dist/main/ipc/app.d.ts +2 -1
  11. package/dist/main/ipc/app.js +5 -4
  12. package/dist/main/ipc/index.d.ts +5 -4
  13. package/dist/main/ipc/index.js +5 -4
  14. package/dist/main/ipc/panels.d.ts +2 -1
  15. package/dist/main/ipc/panels.js +16 -13
  16. package/dist/main/ipc/popover.d.ts +4 -1
  17. package/dist/main/ipc/popover.js +15 -5
  18. package/dist/main/ipc/projects.d.ts +6 -1
  19. package/dist/main/ipc/projects.js +127 -6
  20. package/dist/main/ipc/session.d.ts +4 -1
  21. package/dist/main/ipc/session.js +34 -6
  22. package/dist/main/ipc/settings.d.ts +4 -1
  23. package/dist/main/ipc/settings.js +51 -23
  24. package/dist/main/ipc/simulator-module.d.ts +8 -0
  25. package/dist/main/ipc/simulator-module.js +19 -0
  26. package/dist/main/ipc/simulator.d.ts +2 -1
  27. package/dist/main/ipc/simulator.js +23 -18
  28. package/dist/main/ipc/toolbar.d.ts +2 -1
  29. package/dist/main/ipc/toolbar.js +3 -2
  30. package/dist/main/menu/index.js +11 -0
  31. package/dist/main/services/automation/exec.d.ts +2 -0
  32. package/dist/main/services/automation/exec.js +7 -9
  33. package/dist/main/services/automation/handlers/app.js +37 -51
  34. package/dist/main/services/automation/handlers/element.js +27 -41
  35. package/dist/main/services/automation/index.js +88 -13
  36. package/dist/main/services/default-adapter.js +3 -3
  37. package/dist/main/services/mcp/index.d.ts +1 -0
  38. package/dist/main/services/mcp/index.js +1 -0
  39. package/dist/main/services/mcp/server.d.ts +2 -1
  40. package/dist/main/services/mcp/server.js +10 -0
  41. package/dist/main/services/mcp/status.d.ts +10 -0
  42. package/dist/main/services/mcp/status.js +14 -0
  43. package/dist/main/services/mcp/target-manager.js +2 -1
  44. package/dist/main/services/module.d.ts +18 -0
  45. package/dist/main/services/module.js +2 -0
  46. package/dist/main/services/notifications/renderer-notifier.d.ts +5 -3
  47. package/dist/main/services/notifications/renderer-notifier.js +3 -6
  48. package/dist/main/services/projects/builtin-templates.d.ts +3 -0
  49. package/dist/main/services/projects/builtin-templates.js +24 -0
  50. package/dist/main/services/projects/create-project-service.d.ts +7 -0
  51. package/dist/main/services/projects/create-project-service.js +84 -0
  52. package/dist/main/services/projects/index.d.ts +7 -0
  53. package/dist/main/services/projects/index.js +9 -0
  54. package/dist/main/services/projects/local-provider.d.ts +3 -0
  55. package/dist/main/services/projects/local-provider.js +25 -0
  56. package/dist/main/services/projects/project-repository.d.ts +1 -1
  57. package/dist/main/services/projects/project-repository.js +3 -0
  58. package/dist/main/services/projects/templates.d.ts +21 -0
  59. package/dist/main/services/projects/templates.js +39 -0
  60. package/dist/main/services/projects/thumbnail.d.ts +8 -0
  61. package/dist/main/services/projects/thumbnail.js +37 -0
  62. package/dist/main/services/projects/types.d.ts +118 -0
  63. package/dist/main/services/projects/types.js +19 -0
  64. package/dist/main/services/settings/index.d.ts +11 -0
  65. package/dist/main/services/settings/index.js +18 -2
  66. package/dist/main/services/simulator/custom-apis.d.ts +10 -0
  67. package/dist/main/services/simulator/custom-apis.js +26 -0
  68. package/dist/main/services/simulator-storage/index.d.ts +22 -1
  69. package/dist/main/services/simulator-storage/index.js +334 -97
  70. package/dist/main/services/update/update-manager.d.ts +16 -1
  71. package/dist/main/services/update/update-manager.js +18 -15
  72. package/dist/main/services/views/view-manager.d.ts +7 -7
  73. package/dist/main/services/views/view-manager.js +53 -29
  74. package/dist/main/services/window-service.d.ts +24 -0
  75. package/dist/main/services/window-service.js +26 -0
  76. package/dist/main/services/workbench-context.d.ts +49 -2
  77. package/dist/main/services/workbench-context.js +15 -2
  78. package/dist/main/services/workspace/workspace-service.d.ts +9 -6
  79. package/dist/main/services/workspace/workspace-service.js +71 -11
  80. package/dist/main/simulator-apis.d.ts +23 -0
  81. package/dist/main/simulator-apis.js +24 -0
  82. package/dist/main/utils/disposable.d.ts +13 -0
  83. package/dist/main/utils/disposable.js +60 -0
  84. package/dist/main/utils/ipc-registry.d.ts +39 -0
  85. package/dist/main/utils/ipc-registry.js +109 -0
  86. package/dist/main/utils/ipc-schema.d.ts +28 -0
  87. package/dist/main/utils/ipc-schema.js +38 -0
  88. package/dist/main/utils/paths.d.ts +6 -0
  89. package/dist/main/utils/paths.js +6 -0
  90. package/dist/main/utils/sender-policy.d.ts +25 -0
  91. package/dist/main/utils/sender-policy.js +44 -0
  92. package/dist/main/utils/theme.d.ts +24 -0
  93. package/dist/main/utils/theme.js +38 -1
  94. package/dist/main/windows/main-window/create.d.ts +6 -0
  95. package/dist/main/windows/main-window/create.js +66 -10
  96. package/dist/main/windows/main-window/events.d.ts +2 -1
  97. package/dist/main/windows/main-window/events.js +25 -2
  98. package/dist/main/windows/navigation-hardening.d.ts +24 -0
  99. package/dist/main/windows/navigation-hardening.js +55 -0
  100. package/dist/main/windows/settings-window/create.js +11 -1
  101. package/dist/preload/index.d.ts +22 -0
  102. package/dist/preload/index.js +19 -0
  103. package/dist/preload/instrumentation/app-data.d.ts +32 -2
  104. package/dist/preload/instrumentation/app-data.js +253 -79
  105. package/dist/preload/instrumentation/index.d.ts +2 -2
  106. package/dist/preload/instrumentation/index.js +2 -2
  107. package/dist/preload/instrumentation/wxml.d.ts +16 -4
  108. package/dist/preload/instrumentation/wxml.js +188 -178
  109. package/dist/preload/miniapp-snapshot/host.d.ts +12 -0
  110. package/dist/preload/miniapp-snapshot/host.js +117 -0
  111. package/dist/preload/miniapp-snapshot/types.d.ts +62 -0
  112. package/dist/preload/miniapp-snapshot/types.js +15 -0
  113. package/dist/preload/runtime/bridge.js +5 -24
  114. package/dist/preload/runtime/custom-apis.d.ts +6 -0
  115. package/dist/preload/runtime/custom-apis.js +43 -0
  116. package/dist/preload/runtime/host.d.ts +1 -0
  117. package/dist/preload/runtime/host.js +13 -0
  118. package/dist/preload/shared/expose.d.ts +15 -0
  119. package/dist/preload/shared/expose.js +33 -0
  120. package/dist/preload/shared/page-iframe.d.ts +3 -0
  121. package/dist/preload/shared/page-iframe.js +6 -0
  122. package/dist/preload/shared/types.d.ts +2 -0
  123. package/dist/preload/windows/main.cjs +47 -0
  124. package/dist/preload/windows/main.cjs.map +7 -0
  125. package/dist/preload/windows/simulator.js +501 -272
  126. package/dist/renderer/assets/constants-DI382mTP.js +2 -0
  127. package/dist/renderer/assets/index-D8VFYBh-.js +46 -0
  128. package/dist/renderer/assets/{input-DxfYnzX_.js → input-CoWcfa8u.js} +2 -2
  129. package/dist/renderer/assets/ipc-transport-Cd2xPrsa.js +9 -0
  130. package/dist/renderer/assets/ipc-transport-DqbRdZNO.css +1 -0
  131. package/dist/renderer/assets/popover-Nq5gT9DO.js +2 -0
  132. package/dist/renderer/assets/select-By5KH-UG.js +2 -0
  133. package/dist/renderer/assets/{settings-DteGraEU.js → settings-Dj_N70qR.js} +2 -2
  134. package/dist/renderer/assets/settings-api-Do0_Smq1.js +2 -0
  135. package/dist/renderer/assets/workbenchSettings-CazSLGYt.js +8 -0
  136. package/dist/renderer/entries/main/index.html +13 -5
  137. package/dist/renderer/entries/popover/index.html +8 -5
  138. package/dist/renderer/entries/settings/index.html +7 -5
  139. package/dist/renderer/entries/workbench-settings/index.html +7 -4
  140. package/dist/shared/ipc-channels.d.ts +46 -13
  141. package/dist/shared/ipc-channels.js +60 -14
  142. package/dist/shared/ipc-schemas.d.ts +118 -0
  143. package/dist/shared/ipc-schemas.js +133 -0
  144. package/dist/shared/simulator-route.d.ts +72 -0
  145. package/dist/shared/simulator-route.js +169 -0
  146. package/dist/shared/types.d.ts +82 -8
  147. package/dist/simulator/assets/simulator-DJCozrU5.js +9 -0
  148. package/dist/simulator/simulator.html +6 -43
  149. package/package.json +18 -29
  150. package/templates/blank/app.js +6 -0
  151. package/templates/blank/app.json +11 -0
  152. package/templates/blank/app.wxss +5 -0
  153. package/templates/blank/pages/index/index.js +6 -0
  154. package/templates/blank/pages/index/index.json +3 -0
  155. package/templates/blank/pages/index/index.wxml +3 -0
  156. package/templates/blank/pages/index/index.wxss +11 -0
  157. package/templates/blank/project.config.json +13 -0
  158. package/templates/blank/sitemap.json +9 -0
  159. package/templates/taro-todo/app.js +1 -0
  160. package/templates/taro-todo/app.json +1 -0
  161. package/templates/taro-todo/app.wxss +1 -0
  162. package/templates/taro-todo/base.wxml +851 -0
  163. package/templates/taro-todo/common.js +1 -0
  164. package/templates/taro-todo/comp.js +1 -0
  165. package/templates/taro-todo/comp.json +1 -0
  166. package/templates/taro-todo/comp.wxml +2 -0
  167. package/templates/taro-todo/custom-wrapper.js +1 -0
  168. package/templates/taro-todo/custom-wrapper.json +1 -0
  169. package/templates/taro-todo/custom-wrapper.wxml +4 -0
  170. package/templates/taro-todo/pages/index/index.js +2 -0
  171. package/templates/taro-todo/pages/index/index.json +1 -0
  172. package/templates/taro-todo/pages/index/index.wxml +2 -0
  173. package/templates/taro-todo/pages/index/index.wxss +1 -0
  174. package/templates/taro-todo/project.config.json +44 -0
  175. package/templates/taro-todo/runtime.js +1 -0
  176. package/templates/taro-todo/taro.js +2 -0
  177. package/templates/taro-todo/utils.wxs +39 -0
  178. package/templates/taro-todo/vendors.js +2 -0
  179. package/dist/preload/instrumentation/disposable.d.ts +0 -11
  180. package/dist/preload/instrumentation/disposable.js +0 -15
  181. package/dist/preload/windows/main.d.ts +0 -6
  182. package/dist/preload/windows/main.js +0 -6
  183. package/dist/renderer/assets/index-D1p6crtf.js +0 -46
  184. package/dist/renderer/assets/ipc-transport-ClIvDcYY.js +0 -9
  185. package/dist/renderer/assets/ipc-transport-EiWxu_hG.css +0 -1
  186. package/dist/renderer/assets/popover-CtXcBJtM.js +0 -2
  187. package/dist/renderer/assets/select-DMfp49f1.js +0 -2
  188. package/dist/renderer/assets/settings-api-CY84UMpN.js +0 -2
  189. package/dist/renderer/assets/workbenchSettings-DjELLnSJ.js +0 -8
  190. package/dist/simulator/assets/simulator-C1eHXnuq.js +0 -9
@@ -1,6 +1,8 @@
1
1
  import { BrowserWindow } from 'electron';
2
2
  import path from 'path';
3
+ import { mainPreloadPath } from '../../utils/paths.js';
3
4
  import { themeBg } from '../../utils/theme.js';
5
+ import { applyNavigationHardening } from '../navigation-hardening.js';
4
6
  export async function createSettingsWindow(parent, rendererDir) {
5
7
  const win = new BrowserWindow({
6
8
  width: 420,
@@ -10,8 +12,16 @@ export async function createSettingsWindow(parent, rendererDir) {
10
12
  parent: parent ?? undefined,
11
13
  title: '开发工具设置',
12
14
  backgroundColor: themeBg(),
13
- webPreferences: { nodeIntegration: true, contextIsolation: false },
15
+ webPreferences: {
16
+ nodeIntegration: false,
17
+ contextIsolation: true,
18
+ sandbox: false,
19
+ preload: mainPreloadPath,
20
+ },
14
21
  });
22
+ // Standalone settings window loads mainPreloadPath, so the same
23
+ // navigation rules as the main window apply — see navigation-hardening.ts.
24
+ applyNavigationHardening(win.webContents, rendererDir);
15
25
  await win.loadFile(path.join(rendererDir, 'entries/workbench-settings/index.html'));
16
26
  return win;
17
27
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Public preload API surface for `@dimina-kit/devtools/preload`.
3
+ *
4
+ * External consumers compose their own simulator <webview> preload by
5
+ * importing the `install*` helpers from here. The built-in simulator
6
+ * preload at `windows/simulator.ts` is one such composition.
7
+ *
8
+ * NOTE: do NOT add main-window preload concerns (contextBridge / ipc
9
+ * exposure) to this file — that lives in `windows/main.ts` and is
10
+ * bundled by esbuild, never re-exported through this barrel.
11
+ */
12
+ export { installConsoleInstrumentation } from './instrumentation/console.js';
13
+ export { createAppDataSource } from './instrumentation/app-data.js';
14
+ export type { AppDataSnapshot } from './instrumentation/app-data.js';
15
+ export { createWxmlSource } from './instrumentation/wxml.js';
16
+ export { createMiniappSnapshotHost } from './miniapp-snapshot/host.js';
17
+ export type { MiniappSnapshotHost, MiniappSnapshotSource, SnapshotEnvelope, SnapshotSourceId, } from './miniapp-snapshot/types.js';
18
+ export { installSimulatorBridge } from './runtime/bridge.js';
19
+ export { installCustomApisBridge } from './runtime/custom-apis.js';
20
+ export type { DiminaCustomApisBridge } from './runtime/custom-apis.js';
21
+ export { setupApiCompatHook } from './shared/api-compat.js';
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Public preload API surface for `@dimina-kit/devtools/preload`.
3
+ *
4
+ * External consumers compose their own simulator <webview> preload by
5
+ * importing the `install*` helpers from here. The built-in simulator
6
+ * preload at `windows/simulator.ts` is one such composition.
7
+ *
8
+ * NOTE: do NOT add main-window preload concerns (contextBridge / ipc
9
+ * exposure) to this file — that lives in `windows/main.ts` and is
10
+ * bundled by esbuild, never re-exported through this barrel.
11
+ */
12
+ export { installConsoleInstrumentation } from './instrumentation/console.js';
13
+ export { createAppDataSource } from './instrumentation/app-data.js';
14
+ export { createWxmlSource } from './instrumentation/wxml.js';
15
+ export { createMiniappSnapshotHost } from './miniapp-snapshot/host.js';
16
+ export { installSimulatorBridge } from './runtime/bridge.js';
17
+ export { installCustomApisBridge } from './runtime/custom-apis.js';
18
+ export { setupApiCompatHook } from './shared/api-compat.js';
19
+ //# sourceMappingURL=index.js.map
@@ -1,3 +1,33 @@
1
- export declare function installAppDataInstrumentation(): () => void;
2
- export declare function sendAllAppData(): void;
1
+ import type { MiniappSnapshotSource } from '../miniapp-snapshot/types.js';
2
+ /**
3
+ * The AppData snapshot — the full, cumulative panel state.
4
+ *
5
+ * - `bridges` lists every page bridge in chronological (insertion) order, each
6
+ * carrying its page route (`pagePath`), so renderer tabs render in a stable
7
+ * sequence.
8
+ * - `entries` maps `bridgeId → (componentPath | moduleId) → setData state`.
9
+ */
10
+ export interface AppDataSnapshot {
11
+ bridges: Array<{
12
+ id: string;
13
+ pagePath: string | null;
14
+ }>;
15
+ entries: Record<string, Record<string, unknown>>;
16
+ }
17
+ /**
18
+ * The AppData snapshot data source.
19
+ *
20
+ * Instruments `window.Worker` (incoming `message` decoding + outgoing
21
+ * `postMessage` interception) and installs `window.__simulatorHook.appData`,
22
+ * accumulating per-(bridgeId, moduleId) setData state in an internal cache.
23
+ * Every cache mutation — an accepted `ub`/`page_*` worker message, or a
24
+ * `pageUnload` evicting a bridge — calls `emit()` so the `miniappSnapshot`
25
+ * host republishes the full snapshot. The source itself never touches IPC:
26
+ * the host owns push, pull and the install-time publish.
27
+ *
28
+ * It keeps the `__simulatorData.getAppdata()` automation surface working by
29
+ * mirroring the flat cache into the simulator bridge via `setAppDataSnapshot`
30
+ * / `clearAppDataSnapshot`.
31
+ */
32
+ export declare function createAppDataSource(): MiniappSnapshotSource<AppDataSnapshot>;
3
33
  //# sourceMappingURL=app-data.d.ts.map
@@ -1,15 +1,14 @@
1
- import { SimulatorChannel, BridgeChannel } from '../../shared/ipc-channels.js';
2
- import { sendToHost } from '../runtime/host.js';
3
- import { simulatorBridge, clearAppDataSnapshot, setAppDataSnapshot, } from '../runtime/bridge.js';
4
- import { createDisposableSet } from './disposable.js';
5
- const appDataCache = new Map();
6
- function publishSnapshot() {
7
- const data = {};
8
- for (const [key, value] of appDataCache) {
9
- data[key] = value;
10
- }
11
- setAppDataSnapshot(data);
12
- }
1
+ import { clearAppDataSnapshot, setAppDataSnapshot, } from '../runtime/bridge.js';
2
+ // dimina runtime emits two kinds of service→main messages relevant to the
3
+ // AppData panel:
4
+ // • update batches `{type:'ub', body:{bridgeId, updates:[{moduleId,data}]}}`
5
+ // where each `data` is a partial setData patch.
6
+ // • instance init: type === instance id (prefixed `page_`/`component_`),
7
+ // body `{bridgeId, path, data}` with the COMPLETE initial state.
8
+ //
9
+ // Policy: surface PAGE entries only. Component entries are dropped — they
10
+ // sometimes flow on a bridge id distinct from their owning page's and never
11
+ // receive pageUnload, which would manifest as ghost tabs in the panel.
13
12
  function decodeWorkerMessage(message) {
14
13
  let payload = message;
15
14
  if (typeof payload === 'string') {
@@ -20,84 +19,259 @@ function decodeWorkerMessage(message) {
20
19
  return null;
21
20
  }
22
21
  }
23
- const record = payload;
24
- if (record?.type !== 'u' || !record.body)
22
+ if (!payload || typeof payload !== 'object')
25
23
  return null;
26
- return record.body;
27
- }
28
- function createInstrumentedWorker(OriginalWorker) {
29
- function InstrumentedWorker(scriptURL, options) {
30
- const resolvedScriptURL = scriptURL instanceof URL
31
- ? scriptURL
32
- : new URL(scriptURL, window.location.href);
33
- const worker = Reflect.construct(OriginalWorker, [resolvedScriptURL, options], new.target ?? InstrumentedWorker);
34
- worker.addEventListener('message', (event) => {
35
- const body = decodeWorkerMessage(event.data);
36
- if (!body)
37
- return;
38
- window.__simulatorHook?.appData({
24
+ const record = payload;
25
+ if (record.type === 'ub') {
26
+ const body = record.body;
27
+ if (!body || typeof body !== 'object')
28
+ return null;
29
+ if (typeof body.bridgeId !== 'string' || !Array.isArray(body.updates))
30
+ return null;
31
+ const out = [];
32
+ for (const u of body.updates) {
33
+ if (!u || typeof u.moduleId !== 'string')
34
+ continue;
35
+ if (!u.moduleId.startsWith('page_'))
36
+ continue;
37
+ out.push({ mode: 'patch', bridgeId: body.bridgeId, moduleId: u.moduleId, data: u.data });
38
+ }
39
+ return out.length > 0 ? out : null;
40
+ }
41
+ if (typeof record.type === 'string' && record.type.startsWith('page_')) {
42
+ const body = record.body;
43
+ if (!body || typeof body !== 'object')
44
+ return null;
45
+ if (typeof body.bridgeId !== 'string' || typeof body.path !== 'string')
46
+ return null;
47
+ if (!body.data || typeof body.data !== 'object')
48
+ return null;
49
+ return [{
50
+ mode: 'init',
39
51
  bridgeId: body.bridgeId,
40
- moduleId: body.moduleId,
52
+ moduleId: record.type,
53
+ componentPath: body.path,
41
54
  data: body.data,
42
- });
43
- });
44
- return worker;
55
+ }];
45
56
  }
46
- Object.setPrototypeOf(InstrumentedWorker, OriginalWorker);
47
- Object.defineProperty(InstrumentedWorker, 'prototype', {
48
- value: OriginalWorker.prototype,
49
- });
50
- return InstrumentedWorker;
57
+ return null;
51
58
  }
52
- export function installAppDataInstrumentation() {
53
- const disposables = createDisposableSet();
54
- const originalHook = window.__simulatorHook;
55
- const originalDescriptor = Object.getOwnPropertyDescriptor(window, 'Worker');
56
- const OriginalWorker = window.Worker;
57
- window.__simulatorHook = {
58
- appData: (body) => {
59
- const record = body;
60
- if (record?.bridgeId && record?.moduleId) {
61
- const key = `${record.bridgeId}/${record.moduleId}`;
62
- appDataCache.set(key, record.data);
63
- publishSnapshot();
64
- }
65
- sendToHost(SimulatorChannel.AppData, body);
66
- },
59
+ // main→worker direction: container signals page teardown so cache can evict.
60
+ function decodeOutgoingMessage(message) {
61
+ let payload = message;
62
+ if (typeof payload === 'string') {
63
+ try {
64
+ payload = JSON.parse(payload);
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ }
70
+ if (!payload || typeof payload !== 'object')
71
+ return null;
72
+ const r = payload;
73
+ if (typeof r.type !== 'string')
74
+ return null;
75
+ return {
76
+ type: r.type,
77
+ bridgeId: typeof r.body?.bridgeId === 'string' ? r.body.bridgeId : undefined,
67
78
  };
68
- Object.defineProperty(window, 'Worker', {
69
- configurable: true,
70
- writable: true,
71
- value: createInstrumentedWorker(OriginalWorker),
72
- });
73
- publishSnapshot();
74
- disposables.add(() => {
75
- if (originalDescriptor) {
76
- Object.defineProperty(window, 'Worker', originalDescriptor);
79
+ }
80
+ /**
81
+ * The AppData snapshot data source.
82
+ *
83
+ * Instruments `window.Worker` (incoming `message` decoding + outgoing
84
+ * `postMessage` interception) and installs `window.__simulatorHook.appData`,
85
+ * accumulating per-(bridgeId, moduleId) setData state in an internal cache.
86
+ * Every cache mutation — an accepted `ub`/`page_*` worker message, or a
87
+ * `pageUnload` evicting a bridge — calls `emit()` so the `miniappSnapshot`
88
+ * host republishes the full snapshot. The source itself never touches IPC:
89
+ * the host owns push, pull and the install-time publish.
90
+ *
91
+ * It keeps the `__simulatorData.getAppdata()` automation surface working by
92
+ * mirroring the flat cache into the simulator bridge via `setAppDataSnapshot`
93
+ * / `clearAppDataSnapshot`.
94
+ */
95
+ export function createAppDataSource() {
96
+ const appDataCache = new Map();
97
+ // Bridges in insertion order — drives the `bridges` array in snapshots so
98
+ // renderer tabs render in a stable, chronological sequence.
99
+ const bridgeOrder = [];
100
+ // Page path per bridge: set from `page_*` init's body.path. Component init
101
+ // also carries a path but it's the component's own path, not the page route.
102
+ const bridgePagePath = new Map();
103
+ let emit = null;
104
+ let installed = false;
105
+ let originalHook;
106
+ let originalDescriptor;
107
+ let OriginalWorker;
108
+ function recordBridge(bridgeId) {
109
+ if (!bridgeOrder.includes(bridgeId))
110
+ bridgeOrder.push(bridgeId);
111
+ }
112
+ function buildSnapshot() {
113
+ const bridges = [];
114
+ for (const id of bridgeOrder) {
115
+ bridges.push({ id, pagePath: bridgePagePath.get(id) ?? null });
77
116
  }
78
- else {
79
- window.Worker = OriginalWorker;
117
+ const entries = {};
118
+ for (const [key, entry] of appDataCache) {
119
+ const slash = key.indexOf('/');
120
+ if (slash < 0)
121
+ continue;
122
+ const bridgeId = key.slice(0, slash);
123
+ const moduleId = key.slice(slash + 1);
124
+ if (!entries[bridgeId])
125
+ entries[bridgeId] = {};
126
+ const displayKey = entry.componentPath ?? moduleId;
127
+ entries[bridgeId][displayKey] = entry.data;
80
128
  }
81
- });
82
- disposables.add(() => {
83
- if (originalHook) {
84
- window.__simulatorHook = originalHook;
129
+ return { bridges, entries };
130
+ }
131
+ // Mirror the flat cache into the `__simulatorData.getAppdata()` automation
132
+ // surface so MCP / e2e reads keep working after the snapshot migration.
133
+ function publishSnapshot() {
134
+ const data = {};
135
+ for (const [key, entry] of appDataCache) {
136
+ data[key] = entry.data;
85
137
  }
86
- else {
87
- delete window.__simulatorHook;
138
+ setAppDataSnapshot(data);
139
+ }
140
+ function clearBridge(bridgeId) {
141
+ const prefix = `${bridgeId}/`;
142
+ for (const key of [...appDataCache.keys()]) {
143
+ if (key.startsWith(prefix))
144
+ appDataCache.delete(key);
88
145
  }
89
- });
90
- disposables.add(() => {
91
- appDataCache.clear();
92
- clearAppDataSnapshot();
146
+ const idx = bridgeOrder.indexOf(bridgeId);
147
+ if (idx >= 0)
148
+ bridgeOrder.splice(idx, 1);
149
+ bridgePagePath.delete(bridgeId);
93
150
  publishSnapshot();
94
- });
95
- return () => {
96
- disposables.disposeAll();
151
+ // The eviction is a cache mutation — notify the host so the renderer can
152
+ // drop the evicted bridge's tab immediately.
153
+ emit?.();
154
+ }
155
+ function applyAppData(body) {
156
+ const record = body;
157
+ if (!record?.bridgeId || !record?.moduleId)
158
+ return;
159
+ // R6: drop ub patches whose bridge has never been initialised. dimina
160
+ // dispatches pageUnload to the service worker, which fires onUnload —
161
+ // and onUnload's setData (e.g. console-test's stopTimer) produces a
162
+ // late `ub` that arrives AFTER our clearBridge. Without this gate the
163
+ // late patch would resurrect the unloaded bridge as a ghost tab.
164
+ if (record.mode !== 'init' && !bridgePagePath.has(record.bridgeId))
165
+ return;
166
+ const key = `${record.bridgeId}/${record.moduleId}`;
167
+ const prev = appDataCache.get(key);
168
+ const incoming = (record.data && typeof record.data === 'object'
169
+ ? record.data
170
+ : {});
171
+ // init = full-state replace; patch = merge into previous (setData semantics)
172
+ const merged = record.mode === 'init'
173
+ ? { ...incoming }
174
+ : { ...(prev?.data ?? {}), ...incoming };
175
+ const componentPath = record.componentPath ?? prev?.componentPath;
176
+ const next = componentPath !== undefined
177
+ ? { componentPath, data: merged }
178
+ : { data: merged };
179
+ appDataCache.set(key, next);
180
+ recordBridge(record.bridgeId);
181
+ if (record.mode === 'init'
182
+ && record.moduleId.startsWith('page_')
183
+ && record.componentPath) {
184
+ bridgePagePath.set(record.bridgeId, record.componentPath);
185
+ }
186
+ publishSnapshot();
187
+ emit?.();
188
+ }
189
+ function instrumentPostMessage(worker) {
190
+ const orig = worker.postMessage.bind(worker);
191
+ worker.postMessage = function (msg, ...rest) {
192
+ const decoded = decodeOutgoingMessage(msg);
193
+ if (decoded?.type === 'pageUnload' && decoded.bridgeId) {
194
+ clearBridge(decoded.bridgeId);
195
+ }
196
+ return orig(msg, ...rest);
197
+ };
198
+ }
199
+ function createInstrumentedWorker(Original) {
200
+ function InstrumentedWorker(scriptURL, options) {
201
+ const resolvedScriptURL = scriptURL instanceof URL
202
+ ? scriptURL
203
+ : new URL(scriptURL, window.location.href);
204
+ const worker = Reflect.construct(Original, [resolvedScriptURL, options], new.target ?? InstrumentedWorker);
205
+ instrumentPostMessage(worker);
206
+ worker.addEventListener('message', (event) => {
207
+ const entries = decodeWorkerMessage(event.data);
208
+ if (!entries)
209
+ return;
210
+ for (const entry of entries) {
211
+ const hookBody = {
212
+ bridgeId: entry.bridgeId,
213
+ moduleId: entry.moduleId,
214
+ data: entry.data,
215
+ mode: entry.mode,
216
+ };
217
+ if (entry.mode === 'init')
218
+ hookBody.componentPath = entry.componentPath;
219
+ window.__simulatorHook?.appData(hookBody);
220
+ }
221
+ });
222
+ return worker;
223
+ }
224
+ Object.setPrototypeOf(InstrumentedWorker, Original);
225
+ Object.defineProperty(InstrumentedWorker, 'prototype', {
226
+ value: Original.prototype,
227
+ });
228
+ return InstrumentedWorker;
229
+ }
230
+ return {
231
+ id: 'appdata',
232
+ snapshot: () => buildSnapshot(),
233
+ start(onChange) {
234
+ if (installed)
235
+ return;
236
+ installed = true;
237
+ emit = onChange;
238
+ originalHook = window.__simulatorHook;
239
+ originalDescriptor = Object.getOwnPropertyDescriptor(window, 'Worker');
240
+ OriginalWorker = window.Worker;
241
+ window.__simulatorHook = {
242
+ appData: (body) => applyAppData(body),
243
+ };
244
+ Object.defineProperty(window, 'Worker', {
245
+ configurable: true,
246
+ writable: true,
247
+ value: createInstrumentedWorker(OriginalWorker),
248
+ });
249
+ },
250
+ dispose() {
251
+ if (!installed)
252
+ return;
253
+ installed = false;
254
+ if (originalDescriptor) {
255
+ Object.defineProperty(window, 'Worker', originalDescriptor);
256
+ }
257
+ else if (OriginalWorker) {
258
+ window.Worker = OriginalWorker;
259
+ }
260
+ if (originalHook) {
261
+ window.__simulatorHook = originalHook;
262
+ }
263
+ else {
264
+ delete window.__simulatorHook;
265
+ }
266
+ originalDescriptor = undefined;
267
+ OriginalWorker = undefined;
268
+ originalHook = undefined;
269
+ appDataCache.clear();
270
+ bridgeOrder.length = 0;
271
+ bridgePagePath.clear();
272
+ clearAppDataSnapshot();
273
+ emit = null;
274
+ },
97
275
  };
98
276
  }
99
- export function sendAllAppData() {
100
- publishSnapshot();
101
- sendToHost(BridgeChannel.AppDataGetAllResponse, simulatorBridge.appdata.data);
102
- }
103
277
  //# sourceMappingURL=app-data.js.map
@@ -1,4 +1,4 @@
1
1
  export { installConsoleInstrumentation } from './console.js';
2
- export { installAppDataInstrumentation, sendAllAppData } from './app-data.js';
3
- export { installWxmlInstrumentation, sendWxmlTree, setupWxmlObserver } from './wxml.js';
2
+ export { createAppDataSource, type AppDataSnapshot } from './app-data.js';
3
+ export { createWxmlSource } from './wxml.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,4 @@
1
1
  export { installConsoleInstrumentation } from './console.js';
2
- export { installAppDataInstrumentation, sendAllAppData } from './app-data.js';
3
- export { installWxmlInstrumentation, sendWxmlTree, setupWxmlObserver } from './wxml.js';
2
+ export { createAppDataSource } from './app-data.js';
3
+ export { createWxmlSource } from './wxml.js';
4
4
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,17 @@
1
- declare function sendWxmlTree(): void;
2
- export declare function installWxmlInstrumentation(): () => void;
3
- export declare const setupWxmlObserver: typeof installWxmlInstrumentation;
4
- export { sendWxmlTree };
1
+ import { type WxmlNode } from '../runtime/bridge.js';
2
+ import type { MiniappSnapshotSource } from '../miniapp-snapshot/types.js';
3
+ /**
4
+ * The WXML snapshot data source.
5
+ *
6
+ * Observes the simulator page's Vue tree (retry-attach + MutationObserver +
7
+ * top-level navigation observer), recomputes a normalized {@link WxmlNode}
8
+ * tree on every (debounced) change, stores it internally, and calls `emit()`
9
+ * so the `miniappSnapshot` host publishes it. The source itself never touches
10
+ * IPC — the host owns the push/pull transport and the install-time publish.
11
+ *
12
+ * It keeps the `__simulatorData.getWxml()` automation surface working by
13
+ * mirroring each computed tree into the simulator bridge via
14
+ * `setWxmlSnapshot` / `clearWxmlSnapshot`.
15
+ */
16
+ export declare function createWxmlSource(): MiniappSnapshotSource<WxmlNode | null>;
5
17
  //# sourceMappingURL=wxml.d.ts.map