@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.
- package/README.md +297 -133
- package/dist/main/api.d.ts +6 -2
- package/dist/main/api.js +5 -2
- package/dist/main/app/app.d.ts +1 -1
- package/dist/main/app/app.js +84 -36
- package/dist/main/app/bootstrap.js +2 -1
- package/dist/main/app/launch.d.ts +2 -2
- package/dist/main/app/launch.js +10 -8
- package/dist/main/index.bundle.js +1567 -477
- package/dist/main/ipc/app.d.ts +2 -1
- package/dist/main/ipc/app.js +5 -4
- package/dist/main/ipc/index.d.ts +5 -4
- package/dist/main/ipc/index.js +5 -4
- package/dist/main/ipc/panels.d.ts +2 -1
- package/dist/main/ipc/panels.js +16 -13
- package/dist/main/ipc/popover.d.ts +4 -1
- package/dist/main/ipc/popover.js +15 -5
- package/dist/main/ipc/projects.d.ts +6 -1
- package/dist/main/ipc/projects.js +127 -6
- package/dist/main/ipc/session.d.ts +4 -1
- package/dist/main/ipc/session.js +34 -6
- package/dist/main/ipc/settings.d.ts +4 -1
- package/dist/main/ipc/settings.js +51 -23
- package/dist/main/ipc/simulator-module.d.ts +8 -0
- package/dist/main/ipc/simulator-module.js +19 -0
- package/dist/main/ipc/simulator.d.ts +2 -1
- package/dist/main/ipc/simulator.js +23 -18
- package/dist/main/ipc/toolbar.d.ts +2 -1
- package/dist/main/ipc/toolbar.js +3 -2
- package/dist/main/menu/index.js +11 -0
- package/dist/main/services/automation/exec.d.ts +2 -0
- package/dist/main/services/automation/exec.js +7 -9
- package/dist/main/services/automation/handlers/app.js +37 -51
- package/dist/main/services/automation/handlers/element.js +27 -41
- package/dist/main/services/automation/index.js +88 -13
- package/dist/main/services/default-adapter.js +3 -3
- package/dist/main/services/mcp/index.d.ts +1 -0
- package/dist/main/services/mcp/index.js +1 -0
- package/dist/main/services/mcp/server.d.ts +2 -1
- package/dist/main/services/mcp/server.js +10 -0
- package/dist/main/services/mcp/status.d.ts +10 -0
- package/dist/main/services/mcp/status.js +14 -0
- package/dist/main/services/mcp/target-manager.js +2 -1
- package/dist/main/services/module.d.ts +18 -0
- package/dist/main/services/module.js +2 -0
- package/dist/main/services/notifications/renderer-notifier.d.ts +5 -3
- package/dist/main/services/notifications/renderer-notifier.js +3 -6
- package/dist/main/services/projects/builtin-templates.d.ts +3 -0
- package/dist/main/services/projects/builtin-templates.js +24 -0
- package/dist/main/services/projects/create-project-service.d.ts +7 -0
- package/dist/main/services/projects/create-project-service.js +84 -0
- package/dist/main/services/projects/index.d.ts +7 -0
- package/dist/main/services/projects/index.js +9 -0
- package/dist/main/services/projects/local-provider.d.ts +3 -0
- package/dist/main/services/projects/local-provider.js +25 -0
- package/dist/main/services/projects/project-repository.d.ts +1 -1
- package/dist/main/services/projects/project-repository.js +3 -0
- package/dist/main/services/projects/templates.d.ts +21 -0
- package/dist/main/services/projects/templates.js +39 -0
- package/dist/main/services/projects/thumbnail.d.ts +8 -0
- package/dist/main/services/projects/thumbnail.js +37 -0
- package/dist/main/services/projects/types.d.ts +118 -0
- package/dist/main/services/projects/types.js +19 -0
- package/dist/main/services/settings/index.d.ts +11 -0
- package/dist/main/services/settings/index.js +18 -2
- package/dist/main/services/simulator/custom-apis.d.ts +10 -0
- package/dist/main/services/simulator/custom-apis.js +26 -0
- package/dist/main/services/simulator-storage/index.d.ts +22 -1
- package/dist/main/services/simulator-storage/index.js +334 -97
- package/dist/main/services/update/update-manager.d.ts +16 -1
- package/dist/main/services/update/update-manager.js +18 -15
- package/dist/main/services/views/view-manager.d.ts +7 -7
- package/dist/main/services/views/view-manager.js +53 -29
- package/dist/main/services/window-service.d.ts +24 -0
- package/dist/main/services/window-service.js +26 -0
- package/dist/main/services/workbench-context.d.ts +49 -2
- package/dist/main/services/workbench-context.js +15 -2
- package/dist/main/services/workspace/workspace-service.d.ts +9 -6
- package/dist/main/services/workspace/workspace-service.js +71 -11
- package/dist/main/simulator-apis.d.ts +23 -0
- package/dist/main/simulator-apis.js +24 -0
- package/dist/main/utils/disposable.d.ts +13 -0
- package/dist/main/utils/disposable.js +60 -0
- package/dist/main/utils/ipc-registry.d.ts +39 -0
- package/dist/main/utils/ipc-registry.js +109 -0
- package/dist/main/utils/ipc-schema.d.ts +28 -0
- package/dist/main/utils/ipc-schema.js +38 -0
- package/dist/main/utils/paths.d.ts +6 -0
- package/dist/main/utils/paths.js +6 -0
- package/dist/main/utils/sender-policy.d.ts +25 -0
- package/dist/main/utils/sender-policy.js +44 -0
- package/dist/main/utils/theme.d.ts +24 -0
- package/dist/main/utils/theme.js +38 -1
- package/dist/main/windows/main-window/create.d.ts +6 -0
- package/dist/main/windows/main-window/create.js +66 -10
- package/dist/main/windows/main-window/events.d.ts +2 -1
- package/dist/main/windows/main-window/events.js +25 -2
- package/dist/main/windows/navigation-hardening.d.ts +24 -0
- package/dist/main/windows/navigation-hardening.js +55 -0
- package/dist/main/windows/settings-window/create.js +11 -1
- package/dist/preload/index.d.ts +22 -0
- package/dist/preload/index.js +19 -0
- package/dist/preload/instrumentation/app-data.d.ts +32 -2
- package/dist/preload/instrumentation/app-data.js +253 -79
- package/dist/preload/instrumentation/index.d.ts +2 -2
- package/dist/preload/instrumentation/index.js +2 -2
- package/dist/preload/instrumentation/wxml.d.ts +16 -4
- package/dist/preload/instrumentation/wxml.js +188 -178
- package/dist/preload/miniapp-snapshot/host.d.ts +12 -0
- package/dist/preload/miniapp-snapshot/host.js +117 -0
- package/dist/preload/miniapp-snapshot/types.d.ts +62 -0
- package/dist/preload/miniapp-snapshot/types.js +15 -0
- package/dist/preload/runtime/bridge.js +5 -24
- package/dist/preload/runtime/custom-apis.d.ts +6 -0
- package/dist/preload/runtime/custom-apis.js +43 -0
- package/dist/preload/runtime/host.d.ts +1 -0
- package/dist/preload/runtime/host.js +13 -0
- package/dist/preload/shared/expose.d.ts +15 -0
- package/dist/preload/shared/expose.js +33 -0
- package/dist/preload/shared/page-iframe.d.ts +3 -0
- package/dist/preload/shared/page-iframe.js +6 -0
- package/dist/preload/shared/types.d.ts +2 -0
- package/dist/preload/windows/main.cjs +47 -0
- package/dist/preload/windows/main.cjs.map +7 -0
- package/dist/preload/windows/simulator.js +501 -272
- package/dist/renderer/assets/constants-DI382mTP.js +2 -0
- package/dist/renderer/assets/index-D8VFYBh-.js +46 -0
- package/dist/renderer/assets/{input-DxfYnzX_.js → input-CoWcfa8u.js} +2 -2
- package/dist/renderer/assets/ipc-transport-Cd2xPrsa.js +9 -0
- package/dist/renderer/assets/ipc-transport-DqbRdZNO.css +1 -0
- package/dist/renderer/assets/popover-Nq5gT9DO.js +2 -0
- package/dist/renderer/assets/select-By5KH-UG.js +2 -0
- package/dist/renderer/assets/{settings-DteGraEU.js → settings-Dj_N70qR.js} +2 -2
- package/dist/renderer/assets/settings-api-Do0_Smq1.js +2 -0
- package/dist/renderer/assets/workbenchSettings-CazSLGYt.js +8 -0
- package/dist/renderer/entries/main/index.html +13 -5
- package/dist/renderer/entries/popover/index.html +8 -5
- package/dist/renderer/entries/settings/index.html +7 -5
- package/dist/renderer/entries/workbench-settings/index.html +7 -4
- package/dist/shared/ipc-channels.d.ts +46 -13
- package/dist/shared/ipc-channels.js +60 -14
- package/dist/shared/ipc-schemas.d.ts +118 -0
- package/dist/shared/ipc-schemas.js +133 -0
- package/dist/shared/simulator-route.d.ts +72 -0
- package/dist/shared/simulator-route.js +169 -0
- package/dist/shared/types.d.ts +82 -8
- package/dist/simulator/assets/simulator-DJCozrU5.js +9 -0
- package/dist/simulator/simulator.html +6 -43
- package/package.json +18 -29
- package/templates/blank/app.js +6 -0
- package/templates/blank/app.json +11 -0
- package/templates/blank/app.wxss +5 -0
- package/templates/blank/pages/index/index.js +6 -0
- package/templates/blank/pages/index/index.json +3 -0
- package/templates/blank/pages/index/index.wxml +3 -0
- package/templates/blank/pages/index/index.wxss +11 -0
- package/templates/blank/project.config.json +13 -0
- package/templates/blank/sitemap.json +9 -0
- package/templates/taro-todo/app.js +1 -0
- package/templates/taro-todo/app.json +1 -0
- package/templates/taro-todo/app.wxss +1 -0
- package/templates/taro-todo/base.wxml +851 -0
- package/templates/taro-todo/common.js +1 -0
- package/templates/taro-todo/comp.js +1 -0
- package/templates/taro-todo/comp.json +1 -0
- package/templates/taro-todo/comp.wxml +2 -0
- package/templates/taro-todo/custom-wrapper.js +1 -0
- package/templates/taro-todo/custom-wrapper.json +1 -0
- package/templates/taro-todo/custom-wrapper.wxml +4 -0
- package/templates/taro-todo/pages/index/index.js +2 -0
- package/templates/taro-todo/pages/index/index.json +1 -0
- package/templates/taro-todo/pages/index/index.wxml +2 -0
- package/templates/taro-todo/pages/index/index.wxss +1 -0
- package/templates/taro-todo/project.config.json +44 -0
- package/templates/taro-todo/runtime.js +1 -0
- package/templates/taro-todo/taro.js +2 -0
- package/templates/taro-todo/utils.wxs +39 -0
- package/templates/taro-todo/vendors.js +2 -0
- package/dist/preload/instrumentation/disposable.d.ts +0 -11
- package/dist/preload/instrumentation/disposable.js +0 -15
- package/dist/preload/windows/main.d.ts +0 -6
- package/dist/preload/windows/main.js +0 -6
- package/dist/renderer/assets/index-D1p6crtf.js +0 -46
- package/dist/renderer/assets/ipc-transport-ClIvDcYY.js +0 -9
- package/dist/renderer/assets/ipc-transport-EiWxu_hG.css +0 -1
- package/dist/renderer/assets/popover-CtXcBJtM.js +0 -2
- package/dist/renderer/assets/select-DMfp49f1.js +0 -2
- package/dist/renderer/assets/settings-api-CY84UMpN.js +0 -2
- package/dist/renderer/assets/workbenchSettings-DjELLnSJ.js +0 -8
- 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
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
30
|
+
if (!instance)
|
|
31
|
+
return null;
|
|
79
32
|
const tree = walkInstance(instance, 0);
|
|
80
|
-
if (!tree)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
33
|
+
if (!tree)
|
|
34
|
+
return null;
|
|
35
|
+
return Array.isArray(tree)
|
|
36
|
+
? { tagName: '#fragment', attrs: {}, children: tree }
|
|
37
|
+
: tree;
|
|
85
38
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
160
|
-
if (
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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 {
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
197
|
-
if (windowRef.__simulatorData === exposedApi) {
|
|
198
|
-
delete windowRef.__simulatorData;
|
|
199
|
-
}
|
|
180
|
+
dispose();
|
|
200
181
|
};
|
|
201
182
|
}
|
|
202
183
|
//# sourceMappingURL=bridge.js.map
|