@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,13 +1,7 @@
1
- import { SimulatorChannel } from '../../shared/ipc-channels.js';
2
- import { sendToHost } from '../runtime/host.js';
3
1
  import { clearWxmlSnapshot, setWxmlSnapshot, unhighlightElement, } from '../runtime/bridge.js';
4
2
  import { WXML_DEBOUNCE_MS, WXML_RETRY_INTERVAL_MS, WXML_RETRY_TIMEOUT_MS, NAVIGATION_POLL_INTERVAL_MS, NAVIGATION_TIMEOUT_MS, } from '../shared/constants.js';
5
- import { createDisposableSet } from './disposable.js';
6
3
  import { walkInstance } from './wxml-extract.js';
7
- function findActivePageIframe() {
8
- const iframes = document.querySelectorAll('.dimina-native-webview__window');
9
- return iframes.length > 0 ? iframes[iframes.length - 1] : null;
10
- }
4
+ import { getActivePageIframe } from '../shared/page-iframe.js';
11
5
  function getVueAppFromIframe(iframe) {
12
6
  try {
13
7
  const doc = iframe.contentDocument;
@@ -27,197 +21,213 @@ function getVueAppFromIframe(iframe) {
27
21
  return null;
28
22
  }
29
23
  }
30
- let wxmlTimer;
31
- let currentObserver = null;
32
- let currentIframe = null;
33
- let topObserver = null;
34
- let retryTimer;
35
- let retryTimeout;
36
- let navigationWaitTimer;
37
- let navigationWaitTimeout;
38
- const disposables = createDisposableSet();
39
- function clearTimers() {
40
- if (wxmlTimer)
41
- clearTimeout(wxmlTimer);
42
- if (retryTimer)
43
- clearInterval(retryTimer);
44
- if (retryTimeout)
45
- clearTimeout(retryTimeout);
46
- if (navigationWaitTimer)
47
- clearInterval(navigationWaitTimer);
48
- if (navigationWaitTimeout)
49
- clearTimeout(navigationWaitTimeout);
50
- wxmlTimer = undefined;
51
- retryTimer = undefined;
52
- retryTimeout = undefined;
53
- navigationWaitTimer = undefined;
54
- navigationWaitTimeout = undefined;
55
- }
56
- function publishTree(tree) {
57
- if (tree) {
58
- const normalized = Array.isArray(tree)
59
- ? { tagName: '#fragment', attrs: {}, children: tree }
60
- : tree;
61
- setWxmlSnapshot(normalized, true);
62
- sendToHost(SimulatorChannel.Wxml, normalized);
63
- return;
64
- }
65
- clearWxmlSnapshot();
66
- unhighlightElement();
67
- }
68
- function sendWxmlTree() {
69
- const iframe = findActivePageIframe();
70
- if (!iframe) {
71
- publishTree(null);
72
- return;
73
- }
24
+ /** Compute the normalized WXML tree for the currently-active page, or `null`. */
25
+ function computeWxmlTree() {
26
+ const iframe = getActivePageIframe();
27
+ if (!iframe)
28
+ return null;
74
29
  const instance = getVueAppFromIframe(iframe);
75
- if (!instance) {
76
- publishTree(null);
77
- return;
78
- }
30
+ if (!instance)
31
+ return null;
79
32
  const tree = walkInstance(instance, 0);
80
- if (!tree) {
81
- publishTree(null);
82
- return;
83
- }
84
- publishTree(tree);
33
+ if (!tree)
34
+ return null;
35
+ return Array.isArray(tree)
36
+ ? { tagName: '#fragment', attrs: {}, children: tree }
37
+ : tree;
85
38
  }
86
- function observeIframe(iframe) {
87
- if (iframe === currentIframe)
88
- return;
89
- if (currentObserver) {
90
- currentObserver.disconnect();
91
- currentObserver = null;
92
- }
93
- if (navigationWaitTimer) {
94
- clearInterval(navigationWaitTimer);
39
+ /**
40
+ * The WXML snapshot data source.
41
+ *
42
+ * Observes the simulator page's Vue tree (retry-attach + MutationObserver +
43
+ * top-level navigation observer), recomputes a normalized {@link WxmlNode}
44
+ * tree on every (debounced) change, stores it internally, and calls `emit()`
45
+ * so the `miniappSnapshot` host publishes it. The source itself never touches
46
+ * IPC — the host owns the push/pull transport and the install-time publish.
47
+ *
48
+ * It keeps the `__simulatorData.getWxml()` automation surface working by
49
+ * mirroring each computed tree into the simulator bridge via
50
+ * `setWxmlSnapshot` / `clearWxmlSnapshot`.
51
+ */
52
+ export function createWxmlSource() {
53
+ let tree = null;
54
+ let emit = null;
55
+ let wxmlTimer;
56
+ let currentObserver = null;
57
+ let currentIframe = null;
58
+ let topObserver = null;
59
+ let retryTimer;
60
+ let retryTimeout;
61
+ let navigationWaitTimer;
62
+ let navigationWaitTimeout;
63
+ function clearTimers() {
64
+ if (wxmlTimer)
65
+ clearTimeout(wxmlTimer);
66
+ if (retryTimer)
67
+ clearInterval(retryTimer);
68
+ if (retryTimeout)
69
+ clearTimeout(retryTimeout);
70
+ if (navigationWaitTimer)
71
+ clearInterval(navigationWaitTimer);
72
+ if (navigationWaitTimeout)
73
+ clearTimeout(navigationWaitTimeout);
74
+ wxmlTimer = undefined;
75
+ retryTimer = undefined;
76
+ retryTimeout = undefined;
95
77
  navigationWaitTimer = undefined;
96
- }
97
- if (navigationWaitTimeout) {
98
- clearTimeout(navigationWaitTimeout);
99
78
  navigationWaitTimeout = undefined;
100
79
  }
101
- currentIframe = iframe;
102
- const doc = iframe.contentDocument;
103
- if (!doc?.body) {
104
- publishTree(null);
105
- return;
80
+ /**
81
+ * Recompute the tree, store it, mirror it to the automation bridge, and
82
+ * notify the host. The single update path shared by attach, navigation and
83
+ * MutationObserver callbacks.
84
+ */
85
+ function refresh() {
86
+ tree = computeWxmlTree();
87
+ if (tree) {
88
+ setWxmlSnapshot(tree, true);
89
+ }
90
+ else {
91
+ clearWxmlSnapshot();
92
+ unhighlightElement();
93
+ }
94
+ emit?.();
106
95
  }
107
- sendWxmlTree();
108
- currentObserver = new MutationObserver(() => {
109
- clearTimeout(wxmlTimer);
110
- wxmlTimer = setTimeout(sendWxmlTree, WXML_DEBOUNCE_MS);
111
- });
112
- currentObserver.observe(doc.body, { childList: true, subtree: true });
113
- }
114
- function tryAttach() {
115
- const iframe = findActivePageIframe();
116
- if (!iframe)
117
- return false;
118
- const instance = getVueAppFromIframe(iframe);
119
- if (!instance)
120
- return false;
121
- observeIframe(iframe);
122
- return true;
123
- }
124
- function scheduleAttach() {
125
- if (retryTimer)
126
- clearInterval(retryTimer);
127
- if (retryTimeout)
128
- clearTimeout(retryTimeout);
129
- retryTimer = setInterval(() => {
130
- if (tryAttach() && retryTimer) {
131
- clearInterval(retryTimer);
132
- retryTimer = undefined;
96
+ function observeIframe(iframe) {
97
+ if (iframe === currentIframe)
98
+ return;
99
+ if (currentObserver) {
100
+ currentObserver.disconnect();
101
+ currentObserver = null;
133
102
  }
134
- }, WXML_RETRY_INTERVAL_MS);
135
- retryTimeout = setTimeout(() => {
136
- if (retryTimer)
137
- clearInterval(retryTimer);
138
- retryTimer = undefined;
139
- }, WXML_RETRY_TIMEOUT_MS);
140
- }
141
- function observeTopLevel() {
142
- if (topObserver)
143
- return;
144
- topObserver = new MutationObserver(() => {
145
- const iframe = findActivePageIframe();
146
- if (!iframe) {
147
- publishTree(null);
103
+ if (navigationWaitTimer) {
104
+ clearInterval(navigationWaitTimer);
105
+ navigationWaitTimer = undefined;
106
+ }
107
+ if (navigationWaitTimeout) {
108
+ clearTimeout(navigationWaitTimeout);
109
+ navigationWaitTimeout = undefined;
110
+ }
111
+ currentIframe = iframe;
112
+ const doc = iframe.contentDocument;
113
+ if (!doc?.body) {
114
+ refresh();
148
115
  return;
149
116
  }
150
- if (iframe !== currentIframe) {
151
- if (navigationWaitTimer) {
152
- clearInterval(navigationWaitTimer);
153
- navigationWaitTimer = undefined;
117
+ refresh();
118
+ currentObserver = new MutationObserver(() => {
119
+ clearTimeout(wxmlTimer);
120
+ wxmlTimer = setTimeout(refresh, WXML_DEBOUNCE_MS);
121
+ });
122
+ currentObserver.observe(doc.body, { childList: true, subtree: true });
123
+ }
124
+ function tryAttach() {
125
+ const iframe = getActivePageIframe();
126
+ if (!iframe)
127
+ return false;
128
+ const instance = getVueAppFromIframe(iframe);
129
+ if (!instance)
130
+ return false;
131
+ observeIframe(iframe);
132
+ return true;
133
+ }
134
+ function scheduleAttach() {
135
+ if (retryTimer)
136
+ clearInterval(retryTimer);
137
+ if (retryTimeout)
138
+ clearTimeout(retryTimeout);
139
+ retryTimer = setInterval(() => {
140
+ if (tryAttach() && retryTimer) {
141
+ clearInterval(retryTimer);
142
+ retryTimer = undefined;
154
143
  }
155
- if (navigationWaitTimeout) {
156
- clearTimeout(navigationWaitTimeout);
157
- navigationWaitTimeout = undefined;
144
+ }, WXML_RETRY_INTERVAL_MS);
145
+ retryTimeout = setTimeout(() => {
146
+ if (retryTimer)
147
+ clearInterval(retryTimer);
148
+ retryTimer = undefined;
149
+ }, WXML_RETRY_TIMEOUT_MS);
150
+ }
151
+ function observeTopLevel() {
152
+ if (topObserver)
153
+ return;
154
+ topObserver = new MutationObserver(() => {
155
+ const iframe = getActivePageIframe();
156
+ if (!iframe) {
157
+ refresh();
158
+ return;
158
159
  }
159
- navigationWaitTimer = setInterval(() => {
160
- if (getVueAppFromIframe(iframe)) {
160
+ if (iframe !== currentIframe) {
161
+ if (navigationWaitTimer) {
162
+ clearInterval(navigationWaitTimer);
163
+ navigationWaitTimer = undefined;
164
+ }
165
+ if (navigationWaitTimeout) {
166
+ clearTimeout(navigationWaitTimeout);
167
+ navigationWaitTimeout = undefined;
168
+ }
169
+ navigationWaitTimer = setInterval(() => {
170
+ if (getVueAppFromIframe(iframe)) {
171
+ if (navigationWaitTimer) {
172
+ clearInterval(navigationWaitTimer);
173
+ navigationWaitTimer = undefined;
174
+ }
175
+ if (navigationWaitTimeout) {
176
+ clearTimeout(navigationWaitTimeout);
177
+ navigationWaitTimeout = undefined;
178
+ }
179
+ observeIframe(iframe);
180
+ }
181
+ }, NAVIGATION_POLL_INTERVAL_MS);
182
+ navigationWaitTimeout = setTimeout(() => {
161
183
  if (navigationWaitTimer) {
162
184
  clearInterval(navigationWaitTimer);
163
185
  navigationWaitTimer = undefined;
164
186
  }
165
- if (navigationWaitTimeout) {
166
- clearTimeout(navigationWaitTimeout);
167
- navigationWaitTimeout = undefined;
168
- }
169
- observeIframe(iframe);
170
- }
171
- }, NAVIGATION_POLL_INTERVAL_MS);
172
- navigationWaitTimeout = setTimeout(() => {
173
- if (navigationWaitTimer) {
174
- clearInterval(navigationWaitTimer);
175
- navigationWaitTimer = undefined;
187
+ navigationWaitTimeout = undefined;
188
+ }, NAVIGATION_TIMEOUT_MS);
189
+ }
190
+ });
191
+ if (document.body) {
192
+ topObserver.observe(document.body, { childList: true, subtree: true });
193
+ }
194
+ else {
195
+ document.addEventListener('DOMContentLoaded', () => {
196
+ if (document.body && topObserver) {
197
+ topObserver.observe(document.body, { childList: true, subtree: true });
176
198
  }
177
- navigationWaitTimeout = undefined;
178
- }, NAVIGATION_TIMEOUT_MS);
199
+ }, { once: true });
179
200
  }
180
- });
181
- if (document.body) {
182
- topObserver.observe(document.body, { childList: true, subtree: true });
183
201
  }
184
- else {
185
- document.addEventListener('DOMContentLoaded', () => {
186
- if (document.body && topObserver) {
187
- topObserver.observe(document.body, { childList: true, subtree: true });
202
+ return {
203
+ id: 'wxml',
204
+ snapshot: () => tree,
205
+ start(onChange) {
206
+ emit = onChange;
207
+ // If a page with a mounted Vue app is already present, observeIframe()
208
+ // computes & stores the tree synchronously and emits once. Otherwise the
209
+ // retry timer drives the first emit once a page mounts.
210
+ if (!tryAttach()) {
211
+ scheduleAttach();
188
212
  }
189
- }, { once: true });
190
- }
191
- }
192
- export function installWxmlInstrumentation() {
193
- if (!tryAttach()) {
194
- scheduleAttach();
195
- }
196
- observeTopLevel();
197
- disposables.add(() => {
198
- if (currentObserver) {
199
- currentObserver.disconnect();
200
- currentObserver = null;
201
- }
202
- });
203
- disposables.add(() => {
204
- if (topObserver) {
205
- topObserver.disconnect();
206
- topObserver = null;
207
- }
208
- });
209
- disposables.add(() => {
210
- currentIframe = null;
211
- clearTimers();
212
- });
213
- disposables.add(() => {
214
- clearWxmlSnapshot();
215
- unhighlightElement();
216
- });
217
- return () => {
218
- disposables.disposeAll();
213
+ observeTopLevel();
214
+ },
215
+ dispose() {
216
+ if (currentObserver) {
217
+ currentObserver.disconnect();
218
+ currentObserver = null;
219
+ }
220
+ if (topObserver) {
221
+ topObserver.disconnect();
222
+ topObserver = null;
223
+ }
224
+ currentIframe = null;
225
+ clearTimers();
226
+ clearWxmlSnapshot();
227
+ unhighlightElement();
228
+ tree = null;
229
+ emit = null;
230
+ },
219
231
  };
220
232
  }
221
- export const setupWxmlObserver = installWxmlInstrumentation;
222
- export { sendWxmlTree };
223
233
  //# sourceMappingURL=wxml.js.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * miniappSnapshot — preload-side host.
3
+ *
4
+ * The hub that owns every data source's lifecycle plus the push/pull
5
+ * transport. preload registers sources, then calls `install()` once.
6
+ *
7
+ * See `./types.ts` for the contract and `docs/miniapp-snapshot.md` for the
8
+ * architecture rationale.
9
+ */
10
+ import type { MiniappSnapshotHost } from './types.js';
11
+ export declare function createMiniappSnapshotHost(): MiniappSnapshotHost;
12
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1,117 @@
1
+ /**
2
+ * miniappSnapshot — preload-side host.
3
+ *
4
+ * The hub that owns every data source's lifecycle plus the push/pull
5
+ * transport. preload registers sources, then calls `install()` once.
6
+ *
7
+ * See `./types.ts` for the contract and `docs/miniapp-snapshot.md` for the
8
+ * architecture rationale.
9
+ */
10
+ import { contextBridge } from 'electron';
11
+ import { MiniappSnapshotChannel } from '../../shared/ipc-channels.js';
12
+ import { onHostMessage, sendToHost } from '../runtime/host.js';
13
+ /** Page-global key under which the automation accessor is exposed. */
14
+ const ACCESSOR_KEY = '__miniappSnapshot';
15
+ /**
16
+ * Expose `api` on the page global as `__miniappSnapshot`, preferring
17
+ * `contextBridge.exposeInMainWorld` and falling back to a direct `window`
18
+ * assignment when the context bridge is unavailable. Returns a disposer that
19
+ * restores the previous `window` state — mirroring `bridge.ts`.
20
+ */
21
+ function exposeApi(api) {
22
+ try {
23
+ contextBridge.exposeInMainWorld(ACCESSOR_KEY, api);
24
+ }
25
+ catch {
26
+ ;
27
+ window.__miniappSnapshot = api;
28
+ }
29
+ return () => {
30
+ const windowRef = window;
31
+ if (windowRef[ACCESSOR_KEY] === api) {
32
+ delete windowRef[ACCESSOR_KEY];
33
+ }
34
+ };
35
+ }
36
+ export function createMiniappSnapshotHost() {
37
+ const sources = [];
38
+ const byId = new Map();
39
+ let installed = false;
40
+ let disposed = false;
41
+ // Global, strictly-increasing publish counter shared across every source.
42
+ let seq = 0;
43
+ /**
44
+ * Read a fresh snapshot of `source` and push it over the Push channel with
45
+ * a freshly-allocated global `seq`. The single publish path shared by the
46
+ * initial install, runtime `emit()`, and renderer-initiated `pull`.
47
+ */
48
+ function publish(source) {
49
+ if (disposed)
50
+ return;
51
+ seq += 1;
52
+ const envelope = {
53
+ id: source.id,
54
+ seq,
55
+ ts: Date.now(),
56
+ data: source.snapshot(),
57
+ };
58
+ sendToHost(MiniappSnapshotChannel.Push, envelope);
59
+ }
60
+ function register(source) {
61
+ if (installed) {
62
+ throw new Error('MiniappSnapshotHost: register() called after install()');
63
+ }
64
+ if (byId.has(source.id)) {
65
+ throw new Error(`MiniappSnapshotHost: duplicate source id "${source.id}"`);
66
+ }
67
+ const erased = source;
68
+ byId.set(source.id, erased);
69
+ sources.push(erased);
70
+ }
71
+ function install() {
72
+ if (installed) {
73
+ throw new Error('MiniappSnapshotHost: install() called twice');
74
+ }
75
+ installed = true;
76
+ for (const source of sources) {
77
+ // Each source gets its own emit callback bound to that source, so
78
+ // emit() publishes exactly the calling source (fresh snapshot, fresh
79
+ // seq). After disposal `publish` is a no-op via the `disposed` guard.
80
+ source.start(() => publish(source));
81
+ // Fixed framework step: publish the initial snapshot immediately after
82
+ // start() — reload re-sync is install() re-running, not a per-source
83
+ // responsibility.
84
+ publish(source);
85
+ }
86
+ const disposePull = onHostMessage(MiniappSnapshotChannel.Pull, (...args) => {
87
+ const payload = args[0];
88
+ const id = payload?.id;
89
+ if (typeof id !== 'string')
90
+ return;
91
+ const source = byId.get(id);
92
+ if (!source)
93
+ return;
94
+ publish(source);
95
+ });
96
+ // Synchronous automation accessor — lets the main process / e2e / MCP
97
+ // read any panel's current snapshot via `executeJavaScript`. `get` reads
98
+ // `source.snapshot()` fresh on every call (never cached).
99
+ const api = {
100
+ get: (id) => byId.get(id)?.snapshot(),
101
+ ids: () => sources.map((source) => source.id),
102
+ };
103
+ const disposeApi = exposeApi(api);
104
+ return () => {
105
+ if (disposed)
106
+ return;
107
+ disposed = true;
108
+ disposePull();
109
+ disposeApi();
110
+ for (const source of sources) {
111
+ source.dispose();
112
+ }
113
+ };
114
+ }
115
+ return { register, install };
116
+ }
117
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1,62 @@
1
+ /**
2
+ * miniappSnapshot — preload-side contract.
3
+ *
4
+ * `miniappSnapshot` is the unified snapshot framework shared by devtools
5
+ * panels (AppData, WXML, …). preload is the single source of truth; the
6
+ * renderer is a pure projection of immutable full snapshots.
7
+ *
8
+ * This file is the CONTRACT only — it declares the interfaces every data
9
+ * source and the host must satisfy. The host implementation lives in
10
+ * `./host.ts`.
11
+ *
12
+ * See `docs/miniapp-snapshot.md` for the architecture rationale.
13
+ */
14
+ /** Identifier of one snapshot data source, e.g. 'appdata' | 'wxml'. */
15
+ export type SnapshotSourceId = string;
16
+ /**
17
+ * The transport unit: a full snapshot plus its metadata.
18
+ *
19
+ * - `seq` is a GLOBAL strictly-increasing integer shared across every
20
+ * source, so the renderer can drop stale envelopes and panels can be
21
+ * aligned to the same moment.
22
+ * - `ts` is `Date.now()` at publish time.
23
+ * - `data` is the full, immutable snapshot — the renderer replaces its
24
+ * state wholesale, never merges.
25
+ */
26
+ export interface SnapshotEnvelope<T = unknown> {
27
+ id: SnapshotSourceId;
28
+ seq: number;
29
+ ts: number;
30
+ data: T;
31
+ }
32
+ /** A preload-side data source that produces full snapshots of one panel's state. */
33
+ export interface MiniappSnapshotSource<T = unknown> {
34
+ readonly id: SnapshotSourceId;
35
+ /** Current full snapshot — the source of truth. Called fresh at each publish. */
36
+ snapshot(): T;
37
+ /** Begin observing. `emit` must be called by the source whenever its snapshot changes. */
38
+ start(emit: () => void): void;
39
+ /** Tear down observers. */
40
+ dispose(): void;
41
+ }
42
+ /**
43
+ * The hub: manages every data source's lifecycle plus the push/pull
44
+ * transport. preload registers sources, then calls `install()` once.
45
+ */
46
+ export interface MiniappSnapshotHost {
47
+ register<T>(source: MiniappSnapshotSource<T>): void;
48
+ /** Starts every source, publishes each initial snapshot, wires the pull channel. Returns a disposer. */
49
+ install(): () => void;
50
+ }
51
+ /**
52
+ * Synchronous automation accessor exposed on the page global as
53
+ * `__miniappSnapshot` by `install()`. Lets the main process / e2e / MCP read
54
+ * any registered panel's current snapshot via `webContents.executeJavaScript`.
55
+ */
56
+ export interface MiniappSnapshotApi {
57
+ /** Fresh `source.snapshot()` result for `id`, or `undefined` for an unknown id. */
58
+ get(id: SnapshotSourceId): unknown;
59
+ /** Registered source ids, in registration order. */
60
+ ids(): SnapshotSourceId[];
61
+ }
62
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * miniappSnapshot — preload-side contract.
3
+ *
4
+ * `miniappSnapshot` is the unified snapshot framework shared by devtools
5
+ * panels (AppData, WXML, …). preload is the single source of truth; the
6
+ * renderer is a pure projection of immutable full snapshots.
7
+ *
8
+ * This file is the CONTRACT only — it declares the interfaces every data
9
+ * source and the host must satisfy. The host implementation lives in
10
+ * `./host.ts`.
11
+ *
12
+ * See `docs/miniapp-snapshot.md` for the architecture rationale.
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=types.js.map
@@ -1,4 +1,5 @@
1
- import { contextBridge } from 'electron';
1
+ import { exposeOnMainWorld } from '../shared/expose.js';
2
+ import { getActivePageIframe } from '../shared/page-iframe.js';
2
3
  const state = {
3
4
  appdata: { gen: 0, ready: true, data: {} },
4
5
  storage: { gen: 0, ready: false, namespace: null, data: {} },
@@ -47,10 +48,6 @@ function clone(value) {
47
48
  return value;
48
49
  }
49
50
  }
50
- function getPageIframe() {
51
- const iframes = document.querySelectorAll('.dimina-native-webview__window');
52
- return iframes.length > 0 ? iframes[iframes.length - 1] : null;
53
- }
54
51
  function ensureOverlay(doc) {
55
52
  if (highlightOverlay && highlightOverlay.ownerDocument === doc)
56
53
  return highlightOverlay;
@@ -66,7 +63,7 @@ function ensureOverlay(doc) {
66
63
  function highlightElement(sid) {
67
64
  if (!sid)
68
65
  return null;
69
- const iframe = getPageIframe();
66
+ const iframe = getActivePageIframe();
70
67
  if (!iframe?.contentDocument)
71
68
  return null;
72
69
  const doc = iframe.contentDocument;
@@ -177,26 +174,10 @@ export function installSimulatorBridge() {
177
174
  if (!exposedApi) {
178
175
  exposedApi = buildApi();
179
176
  }
180
- try {
181
- contextBridge.exposeInMainWorld('__simulatorData', {
182
- ...exposedApi,
183
- getAppdata: () => clone(state.appdata.data),
184
- getAppdataSnapshot: () => clone(state.appdata),
185
- getStorageSnapshot: () => clone(state.storage),
186
- getWxml: () => clone(state.wxml.data),
187
- getWxmlSnapshot: () => clone(state.wxml),
188
- });
189
- }
190
- catch {
191
- ;
192
- window.__simulatorData = exposedApi;
193
- }
177
+ const dispose = exposeOnMainWorld('__simulatorData', exposedApi);
194
178
  return () => {
195
179
  resetBridgeState();
196
- const windowRef = window;
197
- if (windowRef.__simulatorData === exposedApi) {
198
- delete windowRef.__simulatorData;
199
- }
180
+ dispose();
200
181
  };
201
182
  }
202
183
  //# sourceMappingURL=bridge.js.map
@@ -0,0 +1,6 @@
1
+ export interface DiminaCustomApisBridge {
2
+ list(): Promise<string[]>;
3
+ invoke(name: string, params: unknown): Promise<unknown>;
4
+ }
5
+ export declare function installCustomApisBridge(): () => void;
6
+ //# sourceMappingURL=custom-apis.d.ts.map