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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/README.md +49 -59
  2. package/dist/main/api.d.ts +1 -2
  3. package/dist/main/api.js +5 -1
  4. package/dist/main/app/app.d.ts +15 -5
  5. package/dist/main/app/app.js +242 -122
  6. package/dist/main/app/bootstrap.d.ts +16 -0
  7. package/dist/main/app/bootstrap.js +20 -0
  8. package/dist/main/app/launch.d.ts +8 -4
  9. package/dist/main/app/launch.js +9 -4
  10. package/dist/main/index.bundle.js +5812 -1729
  11. package/dist/main/index.js +9 -1
  12. package/dist/main/ipc/app.d.ts +1 -1
  13. package/dist/main/ipc/bridge-router.d.ts +61 -0
  14. package/dist/main/ipc/bridge-router.js +1300 -0
  15. package/dist/main/ipc/panels.d.ts +1 -1
  16. package/dist/main/ipc/panels.js +6 -2
  17. package/dist/main/ipc/popover.d.ts +1 -1
  18. package/dist/main/ipc/project-fs.d.ts +1 -1
  19. package/dist/main/ipc/projects.d.ts +1 -1
  20. package/dist/main/ipc/session.d.ts +1 -1
  21. package/dist/main/ipc/settings.d.ts +1 -1
  22. package/dist/main/ipc/simulator-module.d.ts +6 -0
  23. package/dist/main/ipc/simulator-module.js +9 -1
  24. package/dist/main/ipc/simulator.d.ts +2 -2
  25. package/dist/main/ipc/simulator.js +49 -5
  26. package/dist/main/ipc/toolbar.d.ts +1 -1
  27. package/dist/main/ipc/views.d.ts +1 -1
  28. package/dist/main/ipc/views.js +40 -2
  29. package/dist/main/runtime/devtools-backend.d.ts +17 -0
  30. package/dist/main/runtime/devtools-backend.js +49 -0
  31. package/dist/main/runtime/miniapp-runtime.d.ts +39 -0
  32. package/dist/main/runtime/miniapp-runtime.js +17 -0
  33. package/dist/main/services/automation/exec.d.ts +27 -2
  34. package/dist/main/services/automation/exec.js +37 -3
  35. package/dist/main/services/automation/handlers/app.js +127 -11
  36. package/dist/main/services/automation/handlers/page.js +36 -19
  37. package/dist/main/services/automation/index.js +40 -13
  38. package/dist/main/services/automation/wait-active-page.d.ts +56 -0
  39. package/dist/main/services/automation/wait-active-page.js +71 -0
  40. package/dist/main/services/console-forward/index.d.ts +36 -0
  41. package/dist/main/services/console-forward/index.js +81 -0
  42. package/dist/main/services/dimina-resource-server.d.ts +7 -0
  43. package/dist/main/services/dimina-resource-server.js +99 -0
  44. package/dist/main/services/elements-forward/index.d.ts +66 -0
  45. package/dist/main/services/elements-forward/index.js +583 -0
  46. package/dist/main/services/layout/index.d.ts +22 -0
  47. package/dist/main/services/layout/index.js +25 -0
  48. package/dist/main/services/mcp/index.d.ts +1 -0
  49. package/dist/main/services/mcp/index.js +3 -0
  50. package/dist/main/services/mcp/server.d.ts +1 -1
  51. package/dist/main/services/mcp/server.js +1 -1
  52. package/dist/main/services/mcp/target-manager.d.ts +35 -0
  53. package/dist/main/services/mcp/target-manager.js +63 -1
  54. package/dist/main/services/mcp/tools/context-tools.js +15 -1
  55. package/dist/main/services/module.d.ts +1 -1
  56. package/dist/main/services/network-forward/index.d.ts +190 -0
  57. package/dist/main/services/network-forward/index.js +765 -0
  58. package/dist/main/services/notifications/renderer-notifier.d.ts +11 -0
  59. package/dist/main/services/notifications/renderer-notifier.js +7 -1
  60. package/dist/main/services/render-inspect/index.d.ts +41 -0
  61. package/dist/main/services/render-inspect/index.js +88 -0
  62. package/dist/main/services/safe-area/index.d.ts +17 -0
  63. package/dist/main/services/safe-area/index.js +59 -0
  64. package/dist/main/services/service-host-pool/pool.d.ts +197 -0
  65. package/dist/main/services/service-host-pool/pool.js +364 -0
  66. package/dist/main/services/simulator/custom-apis.d.ts +34 -0
  67. package/dist/main/services/simulator/custom-apis.js +22 -0
  68. package/dist/main/services/simulator-appdata/index.d.ts +35 -0
  69. package/dist/main/services/simulator-appdata/index.js +71 -0
  70. package/dist/main/services/simulator-current-page/index.d.ts +24 -0
  71. package/dist/main/services/simulator-current-page/index.js +19 -0
  72. package/dist/main/services/simulator-storage/index.d.ts +37 -2
  73. package/dist/main/services/simulator-storage/index.js +209 -32
  74. package/dist/main/services/simulator-storage/service-storage-ops.d.ts +40 -0
  75. package/dist/main/services/simulator-storage/service-storage-ops.js +67 -0
  76. package/dist/main/services/simulator-temp-files/index.d.ts +1 -1
  77. package/dist/main/services/simulator-temp-files/index.js +1 -1
  78. package/dist/main/services/simulator-wxml/index.d.ts +29 -0
  79. package/dist/main/services/simulator-wxml/index.js +28 -0
  80. package/dist/main/services/toolbar/toolbar-store.d.ts +3 -3
  81. package/dist/main/services/toolbar/toolbar-store.js +1 -18
  82. package/dist/main/services/views/devtools-tabs.d.ts +47 -0
  83. package/dist/main/services/views/devtools-tabs.js +95 -0
  84. package/dist/main/services/views/view-manager.d.ts +125 -0
  85. package/dist/main/services/views/view-manager.js +839 -4
  86. package/dist/main/services/workbench-context.d.ts +67 -7
  87. package/dist/main/services/workbench-context.js +6 -1
  88. package/dist/main/services/workspace/workspace-service.js +7 -13
  89. package/dist/main/utils/ipc-registry.d.ts +1 -1
  90. package/dist/main/utils/ipc-registry.js +21 -4
  91. package/dist/main/utils/paths.d.ts +15 -0
  92. package/dist/main/utils/paths.js +19 -0
  93. package/dist/main/utils/sender-policy.d.ts +9 -3
  94. package/dist/main/utils/sender-policy.js +18 -4
  95. package/dist/main/utils/theme.d.ts +1 -1
  96. package/dist/main/utils/theme.js +1 -1
  97. package/dist/main/windows/main-window/create.d.ts +0 -6
  98. package/dist/main/windows/main-window/create.js +11 -59
  99. package/dist/main/windows/main-window/events.d.ts +1 -1
  100. package/dist/main/windows/main-window/events.js +1 -1
  101. package/dist/main/windows/service-host-window/create.d.ts +52 -0
  102. package/dist/main/windows/service-host-window/create.js +112 -0
  103. package/dist/native-host/common/common.js +368 -0
  104. package/dist/native-host/container/pageFrame.css +1 -0
  105. package/dist/native-host/render/render.js +9334 -0
  106. package/dist/native-host/service/service.js +6 -0
  107. package/dist/preload/index.d.ts +2 -0
  108. package/dist/preload/index.js +6 -0
  109. package/dist/preload/instrumentation/app-data.d.ts +18 -20
  110. package/dist/preload/instrumentation/app-data.js +23 -160
  111. package/dist/preload/instrumentation/wxml-extract.d.ts +1 -1
  112. package/dist/preload/instrumentation/wxml-extract.js +1 -1
  113. package/dist/preload/runtime/bridge.d.ts +3 -8
  114. package/dist/preload/runtime/bridge.js +2 -32
  115. package/dist/preload/runtime/custom-apis.js +20 -17
  116. package/dist/preload/runtime/host-toolbar-advertiser.d.ts +27 -0
  117. package/dist/preload/runtime/host-toolbar-advertiser.js +55 -0
  118. package/dist/preload/runtime/main-api-runner.d.ts +9 -0
  119. package/dist/preload/runtime/main-api-runner.js +85 -0
  120. package/dist/preload/runtime/native-host.d.ts +43 -0
  121. package/dist/preload/runtime/native-host.js +83 -0
  122. package/dist/preload/shared/expose.d.ts +10 -5
  123. package/dist/preload/shared/expose.js +30 -12
  124. package/dist/preload/shared/sid-registry.d.ts +11 -0
  125. package/dist/preload/shared/sid-registry.js +38 -0
  126. package/dist/preload/windows/host-toolbar.cjs +161 -0
  127. package/dist/preload/windows/host-toolbar.cjs.map +7 -0
  128. package/dist/preload/windows/host-toolbar.d.ts +2 -0
  129. package/dist/preload/windows/host-toolbar.js +12 -0
  130. package/dist/preload/windows/main.cjs +1935 -0
  131. package/dist/preload/windows/main.cjs.map +4 -4
  132. package/dist/preload/windows/simulator.cjs +925 -0
  133. package/dist/preload/windows/simulator.cjs.map +7 -0
  134. package/dist/preload/windows/simulator.js +244 -574
  135. package/dist/render-host/pageFrame.html +29 -0
  136. package/dist/render-host/preload.cjs +154 -0
  137. package/dist/render-host/render-inspect.js +295 -0
  138. package/dist/renderer/assets/index-CcJKzatF.js +50 -0
  139. package/dist/renderer/assets/{input-CCYS8Ave.js → input-QGx6FFX1.js} +2 -2
  140. package/dist/renderer/assets/ipc-transport-BT4QYQqu.css +1 -0
  141. package/dist/renderer/assets/{ipc-transport-Bn4KXvhu.js → ipc-transport-DvZvwK-Z.js} +2 -2
  142. package/dist/renderer/assets/{popover-CH4rwpdt.js → popover-BOH1If1J.js} +2 -2
  143. package/dist/renderer/assets/select-C7JQ8G5N.js +2 -0
  144. package/dist/renderer/assets/{settings-CMTB-t0x.js → settings-DpAbTJyF.js} +2 -2
  145. package/dist/renderer/assets/{settings-api-Csdngf9Z.js → settings-api-RD2IZF53.js} +2 -2
  146. package/dist/renderer/assets/{workbenchSettings-CODFCzOg.js → workbenchSettings-CNJX4Qna.js} +2 -2
  147. package/dist/renderer/entries/main/index.html +5 -5
  148. package/dist/renderer/entries/popover/index.html +5 -5
  149. package/dist/renderer/entries/settings/index.html +5 -5
  150. package/dist/renderer/entries/workbench-settings/index.html +4 -4
  151. package/dist/service-host/preload.cjs +254 -0
  152. package/dist/service-host/service.html +10 -0
  153. package/dist/service-host/sourcemap-rewrite.cjs +58 -0
  154. package/dist/service-host/sync-api-patch.js +20 -0
  155. package/dist/service-host/sync-impls/menu-button.js +16 -0
  156. package/dist/service-host/sync-impls/storage.js +50 -0
  157. package/dist/service-host/sync-impls/system-info.js +54 -0
  158. package/dist/shared/appdata-accumulator.d.ts +95 -0
  159. package/dist/shared/appdata-accumulator.js +213 -0
  160. package/dist/shared/bridge-channels.d.ts +364 -0
  161. package/dist/shared/bridge-channels.js +54 -0
  162. package/dist/shared/ipc-channels.d.ts +84 -1
  163. package/dist/shared/ipc-channels.js +90 -10
  164. package/dist/shared/ipc-schemas.d.ts +59 -2
  165. package/dist/shared/ipc-schemas.js +64 -3
  166. package/dist/shared/open-in-editor.d.ts +71 -0
  167. package/dist/shared/open-in-editor.js +138 -0
  168. package/dist/shared/simulator-api-metadata.d.ts +21 -0
  169. package/dist/shared/simulator-api-metadata.js +23 -0
  170. package/dist/shared/types.d.ts +2 -39
  171. package/dist/simulator/assets/device-shell-DsdcNEkt.css +1 -0
  172. package/dist/simulator/assets/device-shell-vwYSOVrh.js +2 -0
  173. package/dist/simulator/assets/jsx-runtime-P6ZegaOf.js +2 -0
  174. package/dist/simulator/assets/simulator-DddliUL5.js +10 -0
  175. package/dist/simulator/assets/simulator-mini-app-BDNu5n26.js +2 -0
  176. package/dist/simulator/device-shell/menu-button-geometry.js +8 -0
  177. package/dist/simulator/simulator.html +2 -112
  178. package/package.json +8 -9
  179. package/dist/main/utils/disposable.d.ts +0 -18
  180. package/dist/main/utils/disposable.js +0 -67
  181. package/dist/renderer/assets/index-BDMxXUfn.js +0 -50
  182. package/dist/renderer/assets/ipc-transport-Cu7tubyg.css +0 -1
  183. package/dist/renderer/assets/select-Ct4-sijm.js +0 -2
  184. package/dist/simulator/assets/simulator-B4e3c6_O.js +0 -9
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __copyProps = (to, from, except, desc) => {
7
9
  if (from && typeof from === "object" || typeof from === "function") {
@@ -11,12 +13,1929 @@ var __copyProps = (to, from, except, desc) => {
11
13
  }
12
14
  return to;
13
15
  };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
14
24
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
25
 
16
26
  // src/preload/windows/main.ts
17
27
  var main_exports = {};
18
28
  module.exports = __toCommonJS(main_exports);
19
29
  var import_electron = require("electron");
30
+
31
+ // src/shared/bridge-channels.ts
32
+ var BRIDGE_CHANNELS = {
33
+ SPAWN: "dmb:spawn",
34
+ DISPOSE: "dmb:dispose",
35
+ PAGE_OPEN: "dmb:page:open",
36
+ PAGE_CLOSE: "dmb:page:close",
37
+ PAGE_LIFECYCLE: "dmb:page:lifecycle",
38
+ NAV_CALLBACK: "dmb:nav:callback",
39
+ SERVICE_INVOKE: "dmb:service:invoke",
40
+ SERVICE_PUBLISH: "dmb:service:publish",
41
+ RENDER_INVOKE: "dmb:render:invoke",
42
+ RENDER_PUBLISH: "dmb:render:publish",
43
+ TO_SERVICE: "dmb:to-service",
44
+ TO_RENDER: "dmb:to-render",
45
+ SIMULATOR_API: "dmb:simulator-api",
46
+ /** simulator → main: ack of an API_CALL request (carries success/fail args). */
47
+ API_RESPONSE: "dmb:api:response",
48
+ /**
49
+ * simulator webview preload → main (sendSync): "is native-host mode on?".
50
+ * The guest preload can't read the launch `process.env`, so it asks main
51
+ * (which can) at install time. Reply is `e.returnValue = boolean`.
52
+ */
53
+ NATIVE_HOST_ENABLED: "dmb:native-host-enabled",
54
+ /**
55
+ * simulator (DeviceShell) → main: the visible top-of-stack page bridgeId.
56
+ * Main has no z-order concept — the active page lives only in DeviceShell's
57
+ * ShellState — so devtools panels / automation that must target "the current
58
+ * page's render webContents" resolve it through this signal. Fire-and-forget.
59
+ */
60
+ ACTIVE_PAGE: "dmb:active-page",
61
+ /**
62
+ * simulator (DeviceShell) → main: the FULL ordered page stack (bottom→top)
63
+ * whenever it changes. Main has no stack of its own (it only learns the
64
+ * active bridgeId via ACTIVE_PAGE), so automation's `App.getPageStack` needs
65
+ * this to report multi-page stacks. Fire-and-forget.
66
+ */
67
+ PAGE_STACK: "dmb:page-stack"
68
+ };
69
+ var SIMULATOR_EVENTS = {
70
+ DOM_READY: "simulator:dom-ready",
71
+ NAV_BAR: "simulator:navigation-bar",
72
+ NAV_ACTION: "simulator:nav-action",
73
+ TAB_ACTION: "simulator:tab-action",
74
+ /** main → simulator: invoke a wx.* API on the simulator-resident MiniApp. */
75
+ API_CALL: "simulator:api-call",
76
+ /**
77
+ * main → simulator: the renderer toolbar picked a different device. Carries a
78
+ * NativeDeviceInfo; DeviceShell resizes the bezel + re-renders status bar /
79
+ * notch. The race-free INITIAL device rides NativeHostConfig.device (read
80
+ * synchronously at preload bridge-install); this event covers live changes.
81
+ */
82
+ DEVICE_CHANGE: "simulator:device-change"
83
+ };
84
+
85
+ // src/preload/runtime/main-api-runner.ts
86
+ function makeBaseContext() {
87
+ const fakeRect = { width: 390, height: 844, x: 0, y: 0, top: 0, left: 0, right: 390, bottom: 844 };
88
+ const fakeRoot = {
89
+ getBoundingClientRect: () => fakeRect
90
+ };
91
+ return {
92
+ appId: "",
93
+ createCallbackFunction: () => void 0,
94
+ parent: {
95
+ el: {
96
+ querySelector: () => fakeRoot
97
+ },
98
+ getStatusBarRect: () => ({ height: 0 })
99
+ }
100
+ };
101
+ }
102
+ function runApiAsync(handlers, name, params) {
103
+ const handler = handlers[name];
104
+ if (!handler) {
105
+ return Promise.resolve({ ok: false, errMsg: `${name}:fail no handler` });
106
+ }
107
+ return new Promise((resolve) => {
108
+ let resolved = false;
109
+ const finish = (verdict) => {
110
+ if (resolved) return;
111
+ resolved = true;
112
+ resolve(verdict);
113
+ };
114
+ const SUCCESS = /* @__PURE__ */ Symbol("main-cb-success");
115
+ const FAIL = /* @__PURE__ */ Symbol("main-cb-fail");
116
+ const COMPLETE = /* @__PURE__ */ Symbol("main-cb-complete");
117
+ const base = makeBaseContext();
118
+ const ctx = {
119
+ ...base,
120
+ createCallbackFunction(id) {
121
+ if (id === void 0 || id === null) return void 0;
122
+ return (...args) => {
123
+ const arg = args[0];
124
+ if (id === SUCCESS) {
125
+ finish({ ok: true, result: arg });
126
+ } else if (id === FAIL) {
127
+ const errMsg = arg && typeof arg === "object" && "errMsg" in arg ? String(arg.errMsg) : `${name}:fail`;
128
+ finish({ ok: false, errMsg, result: arg });
129
+ }
130
+ };
131
+ }
132
+ };
133
+ const userParams = params && typeof params === "object" && !Array.isArray(params) ? { ...params } : {};
134
+ const hadSuccess = userParams.success !== void 0 && userParams.success !== null;
135
+ const hadFail = userParams.fail !== void 0 && userParams.fail !== null;
136
+ const hadComplete = userParams.complete !== void 0 && userParams.complete !== null;
137
+ userParams.success = SUCCESS;
138
+ userParams.fail = FAIL;
139
+ if (hadComplete) userParams.complete = COMPLETE;
140
+ try {
141
+ const ret = handler.call(ctx, userParams);
142
+ if (ret && typeof ret.then === "function") {
143
+ Promise.resolve(ret).then(
144
+ (r) => finish({ ok: true, result: r }),
145
+ (err) => {
146
+ const msg = err instanceof Error ? err.message : String(err);
147
+ finish({ ok: false, errMsg: `${name}:fail ${msg}` });
148
+ }
149
+ );
150
+ return;
151
+ }
152
+ if (!hadSuccess && !hadFail) {
153
+ finish({ ok: true, result: ret });
154
+ }
155
+ } catch (err) {
156
+ const msg = err instanceof Error ? err.message : String(err);
157
+ finish({ ok: false, errMsg: `${name}:fail ${msg}` });
158
+ }
159
+ });
160
+ }
161
+
162
+ // src/simulator/simulator-api-helpers.ts
163
+ function bindCallbacks(ctx, opts) {
164
+ return {
165
+ onSuccess: ctx.createCallbackFunction(opts.success),
166
+ onFail: ctx.createCallbackFunction(opts.fail),
167
+ onComplete: ctx.createCallbackFunction(opts.complete)
168
+ };
169
+ }
170
+ function notSupportedApi(apiName) {
171
+ return function(opts = {}) {
172
+ const { onFail, onComplete } = bindCallbacks(this, opts);
173
+ onFail?.({ errMsg: `${apiName}:fail not supported in simulator` });
174
+ onComplete?.();
175
+ };
176
+ }
177
+
178
+ // src/simulator/simulator-api-storage.ts
179
+ function setStorageSync({ key, data }) {
180
+ const storageKey = `${this.appId}_${key}`;
181
+ const dataString = typeof data === "object" ? JSON.stringify(data) : String(data);
182
+ localStorage.setItem(storageKey, dataString);
183
+ }
184
+ function getStorageSync({ key }) {
185
+ const storageKey = `${this.appId}_${key}`;
186
+ const raw = localStorage.getItem(storageKey);
187
+ if (raw === null) return { data: "" };
188
+ try {
189
+ return { data: JSON.parse(raw) };
190
+ } catch {
191
+ return { data: raw };
192
+ }
193
+ }
194
+ function removeStorageSync({ key }) {
195
+ const storageKey = `${this.appId}_${key}`;
196
+ localStorage.removeItem(storageKey);
197
+ }
198
+ function clearStorageSync() {
199
+ const prefix = `${this.appId}_`;
200
+ const keysToRemove = [];
201
+ for (let i = 0; i < localStorage.length; i++) {
202
+ const k = localStorage.key(i);
203
+ if (k && k.startsWith(prefix)) keysToRemove.push(k);
204
+ }
205
+ keysToRemove.forEach((k) => localStorage.removeItem(k));
206
+ }
207
+ function getStorageInfoSync() {
208
+ const prefix = `${this.appId}_`;
209
+ const keys = [];
210
+ let currentSize = 0;
211
+ for (let i = 0; i < localStorage.length; i++) {
212
+ const fullKey = localStorage.key(i);
213
+ if (fullKey && fullKey.startsWith(prefix)) {
214
+ keys.push(fullKey.substring(prefix.length));
215
+ const item = localStorage.getItem(fullKey);
216
+ currentSize += item ? item.length * 2 : 0;
217
+ }
218
+ }
219
+ return { keys, currentSize, limitSize: 10 * 1024 * 1024 };
220
+ }
221
+ function setStorage({ key, data, success, fail, complete }) {
222
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
223
+ try {
224
+ const storageKey = `${this.appId}_${key}`;
225
+ const dataString = typeof data === "object" ? JSON.stringify(data) : String(data);
226
+ localStorage.setItem(storageKey, dataString);
227
+ onSuccess?.({ errMsg: "setStorage:ok" });
228
+ } catch (e) {
229
+ onFail?.({ errMsg: `setStorage:fail ${e.message}` });
230
+ }
231
+ onComplete?.();
232
+ }
233
+ function getStorage({ key, success, fail, complete }) {
234
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
235
+ const storageKey = `${this.appId}_${key}`;
236
+ const raw = localStorage.getItem(storageKey);
237
+ if (raw === null) {
238
+ onFail?.({ errMsg: "getStorage:fail data not found" });
239
+ } else {
240
+ let data;
241
+ try {
242
+ data = JSON.parse(raw);
243
+ } catch {
244
+ data = raw;
245
+ }
246
+ onSuccess?.({ data, errMsg: "getStorage:ok" });
247
+ }
248
+ onComplete?.();
249
+ }
250
+ function removeStorage({ key, success, fail, complete }) {
251
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
252
+ try {
253
+ const storageKey = `${this.appId}_${key}`;
254
+ localStorage.removeItem(storageKey);
255
+ onSuccess?.({ errMsg: "removeStorage:ok" });
256
+ } catch (e) {
257
+ onFail?.({ errMsg: `removeStorage:fail ${e.message}` });
258
+ }
259
+ onComplete?.();
260
+ }
261
+ function clearStorage({ success, complete } = {}) {
262
+ const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
263
+ const prefix = `${this.appId}_`;
264
+ const keysToRemove = [];
265
+ for (let i = 0; i < localStorage.length; i++) {
266
+ const k = localStorage.key(i);
267
+ if (k && k.startsWith(prefix)) keysToRemove.push(k);
268
+ }
269
+ keysToRemove.forEach((k) => localStorage.removeItem(k));
270
+ onSuccess?.({ errMsg: "clearStorage:ok" });
271
+ onComplete?.();
272
+ }
273
+ function getStorageInfo({ success, complete } = {}) {
274
+ const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
275
+ const prefix = `${this.appId}_`;
276
+ const keys = [];
277
+ let currentSize = 0;
278
+ for (let i = 0; i < localStorage.length; i++) {
279
+ const fullKey = localStorage.key(i);
280
+ if (fullKey && fullKey.startsWith(prefix)) {
281
+ keys.push(fullKey.substring(prefix.length));
282
+ const item = localStorage.getItem(fullKey);
283
+ currentSize += item ? item.length * 2 : 0;
284
+ }
285
+ }
286
+ onSuccess?.({ keys, currentSize, limitSize: 10 * 1024 * 1024, errMsg: "getStorageInfo:ok" });
287
+ onComplete?.();
288
+ }
289
+
290
+ // src/simulator/simulator-api-device.ts
291
+ function hideKeyboard({ success, complete } = {}) {
292
+ const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
293
+ if (document.activeElement && typeof document.activeElement.blur === "function") {
294
+ ;
295
+ document.activeElement.blur();
296
+ }
297
+ onSuccess?.({ errMsg: "hideKeyboard:ok" });
298
+ onComplete?.();
299
+ }
300
+ function adjustPosition({ success, complete } = {}) {
301
+ const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
302
+ onSuccess?.({ errMsg: "adjustPosition:ok" });
303
+ onComplete?.();
304
+ }
305
+ function makePhoneCall({ phoneNumber, success, fail, complete }) {
306
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
307
+ try {
308
+ window.open(`tel:${phoneNumber}`);
309
+ onSuccess?.({ errMsg: "makePhoneCall:ok" });
310
+ } catch (error) {
311
+ onFail?.({ errMsg: `makePhoneCall:fail ${error.message}` });
312
+ }
313
+ onComplete?.();
314
+ }
315
+ var chooseContact = notSupportedApi("chooseContact");
316
+ var addPhoneContact = notSupportedApi("addPhoneContact");
317
+ function vibrateShort({ success, complete } = {}) {
318
+ const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
319
+ if (navigator.vibrate) navigator.vibrate(15);
320
+ onSuccess?.({ errMsg: "vibrateShort:ok" });
321
+ onComplete?.();
322
+ }
323
+ function vibrateLong({ success, complete } = {}) {
324
+ const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
325
+ if (navigator.vibrate) navigator.vibrate(400);
326
+ onSuccess?.({ errMsg: "vibrateLong:ok" });
327
+ onComplete?.();
328
+ }
329
+ var scanCode = notSupportedApi("scanCode");
330
+
331
+ // src/simulator/event-bridge.ts
332
+ function bindDomEvents(target, eventMap, fire, buildPayload) {
333
+ const registered = [];
334
+ for (const [domName, miniName] of Object.entries(eventMap)) {
335
+ const listener = (domEvent) => {
336
+ fire(buildPayload(miniName, domEvent));
337
+ };
338
+ target.addEventListener(domName, listener);
339
+ registered.push([domName, listener]);
340
+ }
341
+ return () => {
342
+ for (const [domName, listener] of registered) {
343
+ target.removeEventListener(domName, listener);
344
+ }
345
+ registered.length = 0;
346
+ };
347
+ }
348
+
349
+ // src/simulator/temp-files.ts
350
+ var tempFiles = /* @__PURE__ */ new Map();
351
+ var activeSink = null;
352
+ function cryptoRandomId() {
353
+ const c = globalThis.crypto;
354
+ if (c && typeof c.randomUUID === "function") return c.randomUUID();
355
+ return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
356
+ }
357
+ function createTempFilePath(blob) {
358
+ const path2 = `difile://_tmp/${cryptoRandomId()}`;
359
+ tempFiles.set(path2, blob);
360
+ activeSink?.write(path2, blob);
361
+ return path2;
362
+ }
363
+ async function resolveTempFilePath(path2) {
364
+ const cached = tempFiles.get(path2);
365
+ if (cached) return cached;
366
+ const response = await fetch(path2);
367
+ if (!response.ok) {
368
+ throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 ${path2}`);
369
+ }
370
+ const blob = await response.blob();
371
+ tempFiles.set(path2, blob);
372
+ return blob;
373
+ }
374
+ function getTempFileName(path2, blob, fallback = "file") {
375
+ const named = blob;
376
+ if (typeof named.name === "string" && named.name.trim()) {
377
+ return named.name;
378
+ }
379
+ try {
380
+ const url = new URL(path2, window.location.href);
381
+ const segment = url.pathname.split("/").filter(Boolean).pop();
382
+ if (segment) return decodeURIComponent(segment);
383
+ } catch {
384
+ }
385
+ return fallback;
386
+ }
387
+
388
+ // src/simulator/simulator-api-media.ts
389
+ function chooseImage({ count = 9, sourceType, camera, success, fail, complete }) {
390
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
391
+ const normalizedCount = normalizeChooseMediaCount(count);
392
+ const normalizedSourceType = normalizeStringArray(sourceType, ["album", "camera"]);
393
+ const input = document.createElement("input");
394
+ input.type = "file";
395
+ input.accept = "image/*";
396
+ input.multiple = normalizedCount > 1;
397
+ if (normalizedSourceType.length === 1 && normalizedSourceType[0] === "camera") {
398
+ input.setAttribute("capture", camera === "front" ? "user" : "environment");
399
+ }
400
+ input.style.display = "none";
401
+ document.body.appendChild(input);
402
+ input.addEventListener("change", () => {
403
+ const files = Array.from(input.files || []).slice(0, normalizedCount);
404
+ if (files.length === 0) {
405
+ onFail?.({ errMsg: "chooseImage:fail cancel" });
406
+ onComplete?.();
407
+ input.remove();
408
+ return;
409
+ }
410
+ const tempFilePaths = files.map((f) => createTempFilePath(f));
411
+ const tempFiles2 = files.map((f, i) => ({ path: tempFilePaths[i], size: f.size }));
412
+ onSuccess?.({ tempFilePaths, tempFiles: tempFiles2, errMsg: "chooseImage:ok" });
413
+ onComplete?.();
414
+ input.remove();
415
+ });
416
+ input.click();
417
+ }
418
+ function previewImage({ urls, current, success, complete }) {
419
+ const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
420
+ if (!urls || urls.length === 0) {
421
+ onComplete?.();
422
+ return;
423
+ }
424
+ const overlay = document.createElement("div");
425
+ overlay.style.cssText = "position:fixed;inset:0;z-index:99999;background:rgba(0,0,0,.85);display:flex;align-items:center;justify-content:center;cursor:pointer;";
426
+ const img = document.createElement("img");
427
+ img.src = current || urls[0] || "";
428
+ img.style.cssText = "max-width:90%;max-height:90%;object-fit:contain;";
429
+ overlay.appendChild(img);
430
+ overlay.addEventListener("click", () => overlay.remove());
431
+ document.body.appendChild(overlay);
432
+ onSuccess?.({ errMsg: "previewImage:ok" });
433
+ onComplete?.();
434
+ }
435
+ function compressImage({ src, quality = 80, success, fail, complete }) {
436
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
437
+ const img = new Image();
438
+ img.crossOrigin = "anonymous";
439
+ img.onload = () => {
440
+ try {
441
+ const canvas = document.createElement("canvas");
442
+ canvas.width = img.naturalWidth;
443
+ canvas.height = img.naturalHeight;
444
+ const ctx = canvas.getContext("2d");
445
+ ctx.drawImage(img, 0, 0);
446
+ canvas.toBlob(
447
+ (blob) => {
448
+ if (blob) {
449
+ const tempFilePath = createTempFilePath(blob);
450
+ onSuccess?.({ tempFilePath, errMsg: "compressImage:ok" });
451
+ } else {
452
+ onFail?.({ errMsg: "compressImage:fail compression error" });
453
+ }
454
+ onComplete?.();
455
+ },
456
+ "image/jpeg",
457
+ quality / 100
458
+ );
459
+ } catch (error) {
460
+ onFail?.({ errMsg: `compressImage:fail ${error.message}` });
461
+ onComplete?.();
462
+ }
463
+ };
464
+ img.onerror = () => {
465
+ onFail?.({ errMsg: "compressImage:fail image load error" });
466
+ onComplete?.();
467
+ };
468
+ img.src = src;
469
+ }
470
+ function saveImageToPhotosAlbum({ filePath, success, fail, complete }) {
471
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
472
+ try {
473
+ const a = document.createElement("a");
474
+ a.href = filePath;
475
+ a.download = "image";
476
+ a.click();
477
+ onSuccess?.({ errMsg: "saveImageToPhotosAlbum:ok" });
478
+ } catch (error) {
479
+ onFail?.({ errMsg: `saveImageToPhotosAlbum:fail ${error.message}` });
480
+ }
481
+ onComplete?.();
482
+ }
483
+ function getImageInfo({ src, success, fail, complete }) {
484
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
485
+ const img = new Image();
486
+ img.crossOrigin = "anonymous";
487
+ img.onload = () => {
488
+ onSuccess?.({
489
+ width: img.naturalWidth,
490
+ height: img.naturalHeight,
491
+ path: src,
492
+ orientation: "up",
493
+ type: "unknown",
494
+ errMsg: "getImageInfo:ok"
495
+ });
496
+ onComplete?.();
497
+ };
498
+ img.onerror = () => {
499
+ onFail?.({ errMsg: "getImageInfo:fail image load error" });
500
+ onComplete?.();
501
+ };
502
+ img.src = src;
503
+ }
504
+ var VIDEO_METADATA_TIMEOUT_MS = 5e3;
505
+ var VIDEO_THUMBNAIL_TIMEOUT_MS = 500;
506
+ function normalizeStringArray(value, fallback) {
507
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : fallback;
508
+ }
509
+ function normalizeChooseMediaCount(value) {
510
+ const n = Number(value);
511
+ if (!Number.isFinite(n)) return 9;
512
+ return Math.max(1, Math.min(20, Math.floor(n)));
513
+ }
514
+ function getChooseMediaAccept(mediaType) {
515
+ const wantsMix = mediaType.includes("mix");
516
+ const wantsImage = wantsMix || mediaType.includes("image");
517
+ const wantsVideo = wantsMix || mediaType.includes("video");
518
+ if (wantsImage && wantsVideo) return "image/*,video/*";
519
+ return wantsVideo ? "video/*" : "image/*";
520
+ }
521
+ function getChooseMediaResultType(files) {
522
+ const types = new Set(files.map((file) => file.fileType));
523
+ if (types.size > 1) return "mix";
524
+ return files[0]?.fileType ?? "image";
525
+ }
526
+ function readImageMetadata(src) {
527
+ return new Promise((resolve) => {
528
+ const img = new Image();
529
+ img.onload = () => resolve({ width: img.naturalWidth || 0, height: img.naturalHeight || 0 });
530
+ img.onerror = () => resolve({ width: 0, height: 0 });
531
+ img.src = src;
532
+ });
533
+ }
534
+ function readVideoMetadata(src) {
535
+ return new Promise((resolve) => {
536
+ const video = document.createElement("video");
537
+ let settled = false;
538
+ let seekTimer;
539
+ const finish = (metadata) => {
540
+ if (settled) return;
541
+ settled = true;
542
+ clearTimeout(timer);
543
+ if (seekTimer) clearTimeout(seekTimer);
544
+ video.onloadedmetadata = null;
545
+ video.onseeked = null;
546
+ video.onerror = null;
547
+ video.removeAttribute("src");
548
+ video.load();
549
+ resolve(metadata);
550
+ };
551
+ const drawThumbnail = (width, height) => {
552
+ return new Promise((resolveThumb) => {
553
+ let resolved = false;
554
+ const done = (value) => {
555
+ if (resolved) return;
556
+ resolved = true;
557
+ resolveThumb(value);
558
+ };
559
+ let canvas;
560
+ try {
561
+ canvas = document.createElement("canvas");
562
+ canvas.width = width || 1;
563
+ canvas.height = height || 1;
564
+ const ctx = canvas.getContext("2d");
565
+ ctx?.drawImage(video, 0, 0, canvas.width, canvas.height);
566
+ } catch {
567
+ done("");
568
+ return;
569
+ }
570
+ const toDataUrlFallback = () => {
571
+ try {
572
+ done(canvas.toDataURL("image/jpeg", 0.8));
573
+ } catch {
574
+ done("");
575
+ }
576
+ };
577
+ const fallbackTimer = setTimeout(toDataUrlFallback, VIDEO_THUMBNAIL_TIMEOUT_MS);
578
+ try {
579
+ canvas.toBlob(
580
+ (blob) => {
581
+ clearTimeout(fallbackTimer);
582
+ if (settled || resolved) return;
583
+ if (blob) {
584
+ done(createTempFilePath(blob));
585
+ } else {
586
+ toDataUrlFallback();
587
+ }
588
+ },
589
+ "image/jpeg",
590
+ 0.8
591
+ );
592
+ } catch {
593
+ clearTimeout(fallbackTimer);
594
+ toDataUrlFallback();
595
+ }
596
+ });
597
+ };
598
+ const timer = setTimeout(() => finish({ width: 0, height: 0, duration: 0, thumbTempFilePath: "" }), VIDEO_METADATA_TIMEOUT_MS);
599
+ video.preload = "metadata";
600
+ video.muted = true;
601
+ video.onloadedmetadata = () => {
602
+ const width = video.videoWidth || 0;
603
+ const height = video.videoHeight || 0;
604
+ const duration = Number.isFinite(video.duration) ? video.duration : 0;
605
+ const metadata = { width, height, duration, thumbTempFilePath: "" };
606
+ if (!width || !height || duration <= 0) {
607
+ finish(metadata);
608
+ return;
609
+ }
610
+ video.onseeked = async () => {
611
+ if (seekTimer) {
612
+ clearTimeout(seekTimer);
613
+ seekTimer = void 0;
614
+ }
615
+ const thumbTempFilePath = await drawThumbnail(width, height);
616
+ finish({ ...metadata, thumbTempFilePath });
617
+ };
618
+ seekTimer = setTimeout(() => finish(metadata), VIDEO_THUMBNAIL_TIMEOUT_MS);
619
+ try {
620
+ video.currentTime = Math.min(0.1, Math.max(0, duration - 0.01));
621
+ } catch {
622
+ finish(metadata);
623
+ }
624
+ };
625
+ video.onerror = () => finish({ width: 0, height: 0, duration: 0, thumbTempFilePath: "" });
626
+ video.src = src;
627
+ });
628
+ }
629
+ async function buildChooseMediaTempFile(file) {
630
+ const tempFilePath = createTempFilePath(file);
631
+ const fileType = file.type.startsWith("video") ? "video" : "image";
632
+ if (fileType === "video") {
633
+ const metadata2 = await readVideoMetadata(tempFilePath);
634
+ return {
635
+ tempFilePath,
636
+ size: file.size,
637
+ duration: metadata2.duration,
638
+ height: metadata2.height,
639
+ width: metadata2.width,
640
+ thumbTempFilePath: metadata2.thumbTempFilePath,
641
+ fileType,
642
+ originalFileObj: file
643
+ };
644
+ }
645
+ const metadata = await readImageMetadata(tempFilePath);
646
+ return {
647
+ tempFilePath,
648
+ size: file.size,
649
+ duration: 0,
650
+ height: metadata.height,
651
+ width: metadata.width,
652
+ thumbTempFilePath: "",
653
+ fileType,
654
+ originalFileObj: file
655
+ };
656
+ }
657
+ function chooseMedia({ count = 9, mediaType = ["image", "video"], sourceType = ["album", "camera"], camera = "back", success, fail, complete }) {
658
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
659
+ const normalizedCount = normalizeChooseMediaCount(count);
660
+ const normalizedMediaType = normalizeStringArray(mediaType, ["image", "video"]);
661
+ const normalizedSourceType = normalizeStringArray(sourceType, ["album", "camera"]);
662
+ const input = document.createElement("input");
663
+ input.type = "file";
664
+ input.accept = getChooseMediaAccept(normalizedMediaType);
665
+ input.multiple = normalizedCount > 1;
666
+ if (normalizedSourceType.length === 1 && normalizedSourceType[0] === "camera") {
667
+ input.setAttribute("capture", camera === "front" ? "user" : "environment");
668
+ }
669
+ input.style.display = "none";
670
+ document.body.appendChild(input);
671
+ input.addEventListener("change", async () => {
672
+ const files = Array.from(input.files || []).slice(0, normalizedCount);
673
+ if (files.length === 0) {
674
+ onFail?.({ errMsg: "chooseMedia:fail cancel" });
675
+ onComplete?.();
676
+ input.remove();
677
+ return;
678
+ }
679
+ try {
680
+ const tempFiles2 = await Promise.all(files.map(buildChooseMediaTempFile));
681
+ onSuccess?.({
682
+ tempFiles: tempFiles2,
683
+ type: getChooseMediaResultType(tempFiles2),
684
+ failedCount: 0,
685
+ errMsg: "chooseMedia:ok"
686
+ });
687
+ } catch (error) {
688
+ onFail?.({ errMsg: `chooseMedia:fail ${error.message}` });
689
+ } finally {
690
+ onComplete?.();
691
+ input.remove();
692
+ }
693
+ });
694
+ input.click();
695
+ }
696
+ function chooseVideo({ sourceType, camera, success, fail, complete }) {
697
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
698
+ const normalizedSourceType = normalizeStringArray(sourceType, ["album", "camera"]);
699
+ const input = document.createElement("input");
700
+ input.type = "file";
701
+ input.accept = "video/*";
702
+ if (normalizedSourceType.length === 1 && normalizedSourceType[0] === "camera") {
703
+ input.setAttribute("capture", camera === "front" ? "user" : "environment");
704
+ }
705
+ input.style.display = "none";
706
+ document.body.appendChild(input);
707
+ input.addEventListener("change", async () => {
708
+ const files = Array.from(input.files || []);
709
+ if (files.length === 0) {
710
+ onFail?.({ errMsg: "chooseVideo:fail cancel" });
711
+ onComplete?.();
712
+ input.remove();
713
+ return;
714
+ }
715
+ const file = files[0];
716
+ const tempFilePath = createTempFilePath(file);
717
+ const metadata = await readVideoMetadata(tempFilePath);
718
+ onSuccess?.({
719
+ tempFilePath,
720
+ duration: metadata.duration,
721
+ size: file.size,
722
+ width: metadata.width,
723
+ height: metadata.height,
724
+ errMsg: "chooseVideo:ok"
725
+ });
726
+ onComplete?.();
727
+ input.remove();
728
+ });
729
+ input.click();
730
+ }
731
+ var AUDIO_EVENT_MAP = {
732
+ play: "play",
733
+ pause: "pause",
734
+ ended: "ended",
735
+ error: "error",
736
+ timeupdate: "timeUpdate",
737
+ waiting: "waiting",
738
+ seeking: "seeking",
739
+ seeked: "seeked",
740
+ canplay: "canplay"
741
+ };
742
+ var _newAudioInstances = /* @__PURE__ */ new Map();
743
+ var _audioEventDisposers = /* @__PURE__ */ new Map();
744
+ var _audioFire = /* @__PURE__ */ new Map();
745
+ function audioSnapshot(audio, event) {
746
+ return {
747
+ event,
748
+ currentTime: audio.currentTime || 0,
749
+ duration: Number.isFinite(audio.duration) ? audio.duration : 0,
750
+ buffered: audio.buffered.length ? audio.buffered.end(audio.buffered.length - 1) : 0,
751
+ paused: audio.paused
752
+ };
753
+ }
754
+ function audioCreate({ audioId }) {
755
+ _newAudioInstances.set(audioId, new Audio());
756
+ }
757
+ function audioListen({ audioId, success }) {
758
+ const audio = _newAudioInstances.get(audioId);
759
+ const fire = this.createCallbackFunction(success);
760
+ if (!audio || !fire) return;
761
+ _audioFire.set(audioId, fire);
762
+ _audioEventDisposers.get(audioId)?.();
763
+ const dispose = bindDomEvents(
764
+ audio,
765
+ AUDIO_EVENT_MAP,
766
+ fire,
767
+ (event) => audioSnapshot(audio, event)
768
+ );
769
+ _audioEventDisposers.set(audioId, dispose);
770
+ }
771
+ function audioSetProp({ audioId, prop, value, startTime, loop, volume, playbackRate, autoplay }) {
772
+ const audio = _newAudioInstances.get(audioId);
773
+ if (!audio) return;
774
+ switch (prop) {
775
+ case "src":
776
+ audio.src = value;
777
+ if (startTime != null) audio.currentTime = startTime;
778
+ if (loop != null) audio.loop = loop;
779
+ if (volume != null) audio.volume = Math.max(0, Math.min(1, volume));
780
+ if (playbackRate != null) audio.playbackRate = playbackRate;
781
+ if (autoplay) audio.play().catch(() => {
782
+ });
783
+ break;
784
+ case "startTime":
785
+ audio.currentTime = Number(value) || 0;
786
+ break;
787
+ case "autoplay":
788
+ audio.autoplay = !!value;
789
+ break;
790
+ case "loop":
791
+ audio.loop = !!value;
792
+ break;
793
+ case "volume":
794
+ audio.volume = Math.max(0, Math.min(1, Number(value) || 0));
795
+ break;
796
+ case "playbackRate":
797
+ audio.playbackRate = Number(value) || 1;
798
+ break;
799
+ }
800
+ }
801
+ function audioPlay({ audioId, src }) {
802
+ const audio = _newAudioInstances.get(audioId);
803
+ if (!audio) return;
804
+ if (src && audio.src !== src) audio.src = src;
805
+ audio.play().catch(() => {
806
+ });
807
+ }
808
+ function audioPause({ audioId }) {
809
+ _newAudioInstances.get(audioId)?.pause();
810
+ }
811
+ function audioStop({ audioId }) {
812
+ const audio = _newAudioInstances.get(audioId);
813
+ if (!audio) return;
814
+ audio.pause();
815
+ audio.currentTime = 0;
816
+ _audioFire.get(audioId)?.(audioSnapshot(audio, "stop"));
817
+ }
818
+ function audioSeek({ audioId, position }) {
819
+ const audio = _newAudioInstances.get(audioId);
820
+ if (!audio) return;
821
+ audio.currentTime = position;
822
+ }
823
+ function audioDestroy({ audioId }) {
824
+ _audioEventDisposers.get(audioId)?.();
825
+ _audioEventDisposers.delete(audioId);
826
+ _audioFire.delete(audioId);
827
+ const audio = _newAudioInstances.get(audioId);
828
+ if (!audio) return;
829
+ audio.pause();
830
+ audio.removeAttribute("src");
831
+ audio.load();
832
+ _newAudioInstances.delete(audioId);
833
+ }
834
+
835
+ // src/shared/vpath.ts
836
+ var import_node_os = __toESM(require("node:os"), 1);
837
+ var import_node_path = __toESM(require("node:path"), 1);
838
+ var DIFILE_PREFIX = "difile://";
839
+ function sandboxBase() {
840
+ const env = typeof process !== "undefined" && process.env && process.env.DIMINA_HOME || "";
841
+ if (env) {
842
+ return import_node_path.default.join(env, "files");
843
+ }
844
+ return import_node_path.default.join(import_node_os.default.homedir(), ".dimina", "files");
845
+ }
846
+ function resolveVPath(url) {
847
+ if (typeof url !== "string") return null;
848
+ if (!url.startsWith(DIFILE_PREFIX)) return null;
849
+ const raw = url.slice(DIFILE_PREFIX.length);
850
+ if (raw.length === 0) return null;
851
+ let decoded;
852
+ try {
853
+ decoded = decodeURIComponent(raw);
854
+ } catch {
855
+ return null;
856
+ }
857
+ if (decoded.includes("\0")) return null;
858
+ decoded = decoded.replace(/^[/\\]+/, "");
859
+ if (decoded.length === 0) return null;
860
+ const segments = decoded.split(/[/\\]+/);
861
+ if (segments.some((s) => s === ".." || s === ".")) return null;
862
+ let kind;
863
+ let writable;
864
+ if (decoded.startsWith("_tmp/")) {
865
+ kind = "tmp";
866
+ writable = false;
867
+ } else if (decoded.startsWith("_store/")) {
868
+ kind = "store";
869
+ writable = false;
870
+ } else {
871
+ kind = "usr";
872
+ writable = true;
873
+ }
874
+ if (kind === "tmp") {
875
+ return { kind, writable };
876
+ }
877
+ const base = sandboxBase();
878
+ const joined = import_node_path.default.join(base, decoded);
879
+ const normalized = import_node_path.default.normalize(joined);
880
+ if (normalized !== base && !normalized.startsWith(base + import_node_path.default.sep)) return null;
881
+ return { kind, writable, realPath: normalized };
882
+ }
883
+
884
+ // src/simulator/simulator-api-fs.ts
885
+ async function _tmpBytes(url) {
886
+ try {
887
+ const blob = await resolveTempFilePath(url);
888
+ const ab = await blob.arrayBuffer();
889
+ return Buffer.from(new Uint8Array(ab));
890
+ } catch (err) {
891
+ const msg = err instanceof Error ? err.message : String(err);
892
+ throw new Error(`ENOENT: no such file (${url}): ${msg}`, { cause: err });
893
+ }
894
+ }
895
+ var _fs = typeof require !== "undefined" ? require("fs") : null;
896
+ var _path = typeof require !== "undefined" ? require("path") : null;
897
+ var _crypto = typeof require !== "undefined" ? require("crypto") : null;
898
+ function _fsResolveOrFail(p, apiName, onFail) {
899
+ const v = resolveVPath(p);
900
+ if (!v) {
901
+ onFail?.({ errMsg: `${apiName}:fail invalid or unsafe path` });
902
+ return null;
903
+ }
904
+ return v;
905
+ }
906
+ function _denyWrite(apiName, onFail) {
907
+ onFail?.({ errMsg: `${apiName}:fail permission denied` });
908
+ }
909
+ function fsAccess({ path: path2, success, fail, complete }) {
910
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
911
+ if (!_fs) {
912
+ onFail?.({ errMsg: "fsAccess:fail not available in browser context" });
913
+ onComplete?.();
914
+ return;
915
+ }
916
+ const v = _fsResolveOrFail(path2, "fsAccess", onFail);
917
+ if (!v) {
918
+ onComplete?.();
919
+ return;
920
+ }
921
+ if (v.kind === "tmp") {
922
+ _tmpBytes(path2).then(
923
+ () => {
924
+ onSuccess?.({ errMsg: "fsAccess:ok" });
925
+ onComplete?.();
926
+ },
927
+ (err) => {
928
+ onFail?.({ errMsg: `fsAccess:fail ${err.message}` });
929
+ onComplete?.();
930
+ }
931
+ );
932
+ return;
933
+ }
934
+ if (!v.realPath) {
935
+ onFail?.({ errMsg: "fsAccess:fail invalid path" });
936
+ onComplete?.();
937
+ return;
938
+ }
939
+ _fs.access(v.realPath, _fs.constants.F_OK, (err) => {
940
+ if (err) {
941
+ onFail?.({ errMsg: `fsAccess:fail ${err.message}` });
942
+ } else {
943
+ onSuccess?.({ errMsg: "fsAccess:ok" });
944
+ }
945
+ onComplete?.();
946
+ });
947
+ }
948
+ function fsStat({ path: path2, recursive = false, success, fail, complete }) {
949
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
950
+ if (!_fs) {
951
+ onFail?.({ errMsg: "fsStat:fail not available in browser context" });
952
+ onComplete?.();
953
+ return;
954
+ }
955
+ const v = _fsResolveOrFail(path2, "fsStat", onFail);
956
+ if (!v) {
957
+ onComplete?.();
958
+ return;
959
+ }
960
+ if (v.kind === "tmp") {
961
+ _tmpBytes(path2).then(
962
+ (buf) => {
963
+ onSuccess?.({
964
+ stats: {
965
+ size: buf.length,
966
+ mode: 0,
967
+ lastAccessedTime: 0,
968
+ lastModifiedTime: 0,
969
+ isFile: true,
970
+ isDirectory: false
971
+ },
972
+ errMsg: "fsStat:ok"
973
+ });
974
+ onComplete?.();
975
+ },
976
+ (err) => {
977
+ onFail?.({ errMsg: `fsStat:fail ${err.message}` });
978
+ onComplete?.();
979
+ }
980
+ );
981
+ return;
982
+ }
983
+ if (!v.realPath) {
984
+ onFail?.({ errMsg: "fsStat:fail invalid path" });
985
+ onComplete?.();
986
+ return;
987
+ }
988
+ const resolved = v.realPath;
989
+ if (recursive) {
990
+ const statsMap = {};
991
+ const walkDir = (dir, cb) => {
992
+ _fs.readdir(dir, { withFileTypes: true }, (err, entries) => {
993
+ if (err) {
994
+ cb(err);
995
+ return;
996
+ }
997
+ let pending = entries.length;
998
+ if (pending === 0) {
999
+ cb(null);
1000
+ return;
1001
+ }
1002
+ for (const entry of entries) {
1003
+ const full = _path.join(dir, entry.name);
1004
+ _fs.stat(full, (statErr, s) => {
1005
+ if (!statErr) {
1006
+ statsMap[full] = {
1007
+ size: s.size,
1008
+ mode: s.mode,
1009
+ lastAccessedTime: s.atimeMs,
1010
+ lastModifiedTime: s.mtimeMs,
1011
+ isFile: s.isFile(),
1012
+ isDirectory: s.isDirectory()
1013
+ };
1014
+ }
1015
+ if (entry.isDirectory()) {
1016
+ walkDir(full, () => {
1017
+ if (--pending === 0) cb(null);
1018
+ });
1019
+ } else {
1020
+ if (--pending === 0) cb(null);
1021
+ }
1022
+ });
1023
+ }
1024
+ });
1025
+ };
1026
+ walkDir(resolved, (err) => {
1027
+ if (err) {
1028
+ onFail?.({ errMsg: `fsStat:fail ${err.message}` });
1029
+ } else {
1030
+ onSuccess?.({ stats: statsMap, errMsg: "fsStat:ok" });
1031
+ }
1032
+ onComplete?.();
1033
+ });
1034
+ } else {
1035
+ _fs.stat(resolved, (err, s) => {
1036
+ if (err) {
1037
+ onFail?.({ errMsg: `fsStat:fail ${err.message}` });
1038
+ } else {
1039
+ onSuccess?.({
1040
+ stats: {
1041
+ size: s.size,
1042
+ mode: s.mode,
1043
+ lastAccessedTime: s.atimeMs,
1044
+ lastModifiedTime: s.mtimeMs,
1045
+ isFile: s.isFile(),
1046
+ isDirectory: s.isDirectory()
1047
+ },
1048
+ errMsg: "fsStat:ok"
1049
+ });
1050
+ }
1051
+ onComplete?.();
1052
+ });
1053
+ }
1054
+ }
1055
+ function fsReadFile({ filePath, encoding, success, fail, complete }) {
1056
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1057
+ if (!_fs) {
1058
+ onFail?.({ errMsg: "fsReadFile:fail not available in browser context" });
1059
+ onComplete?.();
1060
+ return;
1061
+ }
1062
+ const v = _fsResolveOrFail(filePath, "fsReadFile", onFail);
1063
+ if (!v) {
1064
+ onComplete?.();
1065
+ return;
1066
+ }
1067
+ if (v.kind === "tmp") {
1068
+ _tmpBytes(filePath).then(
1069
+ (buf) => {
1070
+ const data = encoding ? buf.toString(encoding) : buf;
1071
+ onSuccess?.({ data, errMsg: "fsReadFile:ok" });
1072
+ onComplete?.();
1073
+ },
1074
+ (err) => {
1075
+ onFail?.({ errMsg: `fsReadFile:fail ${err.message}` });
1076
+ onComplete?.();
1077
+ }
1078
+ );
1079
+ return;
1080
+ }
1081
+ if (!v.realPath) {
1082
+ onFail?.({ errMsg: "fsReadFile:fail invalid path" });
1083
+ onComplete?.();
1084
+ return;
1085
+ }
1086
+ _fs.readFile(v.realPath, encoding || null, (err, data) => {
1087
+ if (err) {
1088
+ onFail?.({ errMsg: `fsReadFile:fail ${err.message}` });
1089
+ } else {
1090
+ onSuccess?.({ data, errMsg: "fsReadFile:ok" });
1091
+ }
1092
+ onComplete?.();
1093
+ });
1094
+ }
1095
+ function fsWriteFile({ filePath, data, encoding = "utf8", success, fail, complete }) {
1096
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1097
+ if (!_fs) {
1098
+ onFail?.({ errMsg: "fsWriteFile:fail not available in browser context" });
1099
+ onComplete?.();
1100
+ return;
1101
+ }
1102
+ const v = _fsResolveOrFail(filePath, "fsWriteFile", onFail);
1103
+ if (!v) {
1104
+ onComplete?.();
1105
+ return;
1106
+ }
1107
+ if (!v.writable || !v.realPath) {
1108
+ _denyWrite("fsWriteFile", onFail);
1109
+ onComplete?.();
1110
+ return;
1111
+ }
1112
+ _fs.mkdir(_path.dirname(v.realPath), { recursive: true }, (mkdirErr) => {
1113
+ if (mkdirErr) {
1114
+ onFail?.({ errMsg: `fsWriteFile:fail ${mkdirErr.message}` });
1115
+ onComplete?.();
1116
+ return;
1117
+ }
1118
+ _fs.writeFile(v.realPath, data, { encoding }, (err) => {
1119
+ if (err) {
1120
+ onFail?.({ errMsg: `fsWriteFile:fail ${err.message}` });
1121
+ } else {
1122
+ onSuccess?.({ errMsg: "fsWriteFile:ok" });
1123
+ }
1124
+ onComplete?.();
1125
+ });
1126
+ });
1127
+ }
1128
+ function fsAppendFile({ filePath, data, encoding = "utf8", success, fail, complete }) {
1129
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1130
+ if (!_fs) {
1131
+ onFail?.({ errMsg: "fsAppendFile:fail not available in browser context" });
1132
+ onComplete?.();
1133
+ return;
1134
+ }
1135
+ const v = _fsResolveOrFail(filePath, "fsAppendFile", onFail);
1136
+ if (!v) {
1137
+ onComplete?.();
1138
+ return;
1139
+ }
1140
+ if (!v.writable || !v.realPath) {
1141
+ _denyWrite("fsAppendFile", onFail);
1142
+ onComplete?.();
1143
+ return;
1144
+ }
1145
+ _fs.appendFile(v.realPath, data, { encoding }, (err) => {
1146
+ if (err) {
1147
+ onFail?.({ errMsg: `fsAppendFile:fail ${err.message}` });
1148
+ } else {
1149
+ onSuccess?.({ errMsg: "fsAppendFile:ok" });
1150
+ }
1151
+ onComplete?.();
1152
+ });
1153
+ }
1154
+ function fsCopyFile({ srcPath, destPath, success, fail, complete }) {
1155
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1156
+ if (!_fs) {
1157
+ onFail?.({ errMsg: "fsCopyFile:fail not available in browser context" });
1158
+ onComplete?.();
1159
+ return;
1160
+ }
1161
+ const vSrc = _fsResolveOrFail(srcPath, "fsCopyFile", onFail);
1162
+ if (!vSrc) {
1163
+ onComplete?.();
1164
+ return;
1165
+ }
1166
+ const vDest = _fsResolveOrFail(destPath, "fsCopyFile", onFail);
1167
+ if (!vDest) {
1168
+ onComplete?.();
1169
+ return;
1170
+ }
1171
+ if (!vDest.writable || !vDest.realPath) {
1172
+ _denyWrite("fsCopyFile", onFail);
1173
+ onComplete?.();
1174
+ return;
1175
+ }
1176
+ if (vSrc.kind === "tmp") {
1177
+ _tmpBytes(srcPath).then(
1178
+ (buf) => {
1179
+ _fs.mkdir(_path.dirname(vDest.realPath), { recursive: true }, (mkdirErr) => {
1180
+ if (mkdirErr) {
1181
+ onFail?.({ errMsg: `fsCopyFile:fail ${mkdirErr.message}` });
1182
+ onComplete?.();
1183
+ return;
1184
+ }
1185
+ _fs.writeFile(vDest.realPath, buf, (err) => {
1186
+ if (err) onFail?.({ errMsg: `fsCopyFile:fail ${err.message}` });
1187
+ else onSuccess?.({ errMsg: "fsCopyFile:ok" });
1188
+ onComplete?.();
1189
+ });
1190
+ });
1191
+ },
1192
+ (err) => {
1193
+ onFail?.({ errMsg: `fsCopyFile:fail ${err.message}` });
1194
+ onComplete?.();
1195
+ }
1196
+ );
1197
+ return;
1198
+ }
1199
+ if (!vSrc.realPath) {
1200
+ onFail?.({ errMsg: "fsCopyFile:fail invalid src path" });
1201
+ onComplete?.();
1202
+ return;
1203
+ }
1204
+ _fs.copyFile(vSrc.realPath, vDest.realPath, (err) => {
1205
+ if (err) {
1206
+ onFail?.({ errMsg: `fsCopyFile:fail ${err.message}` });
1207
+ } else {
1208
+ onSuccess?.({ errMsg: "fsCopyFile:ok" });
1209
+ }
1210
+ onComplete?.();
1211
+ });
1212
+ }
1213
+ function fsRename({ oldPath, newPath, success, fail, complete }) {
1214
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1215
+ if (!_fs) {
1216
+ onFail?.({ errMsg: "fsRename:fail not available in browser context" });
1217
+ onComplete?.();
1218
+ return;
1219
+ }
1220
+ const vOld = _fsResolveOrFail(oldPath, "fsRename", onFail);
1221
+ if (!vOld) {
1222
+ onComplete?.();
1223
+ return;
1224
+ }
1225
+ const vNew = _fsResolveOrFail(newPath, "fsRename", onFail);
1226
+ if (!vNew) {
1227
+ onComplete?.();
1228
+ return;
1229
+ }
1230
+ if (!vOld.writable || !vOld.realPath) {
1231
+ _denyWrite("fsRename", onFail);
1232
+ onComplete?.();
1233
+ return;
1234
+ }
1235
+ if (!vNew.writable || !vNew.realPath) {
1236
+ _denyWrite("fsRename", onFail);
1237
+ onComplete?.();
1238
+ return;
1239
+ }
1240
+ _fs.rename(vOld.realPath, vNew.realPath, (err) => {
1241
+ if (err) {
1242
+ onFail?.({ errMsg: `fsRename:fail ${err.message}` });
1243
+ } else {
1244
+ onSuccess?.({ errMsg: "fsRename:ok" });
1245
+ }
1246
+ onComplete?.();
1247
+ });
1248
+ }
1249
+ function fsUnlink({ filePath, success, fail, complete }) {
1250
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1251
+ if (!_fs) {
1252
+ onFail?.({ errMsg: "fsUnlink:fail not available in browser context" });
1253
+ onComplete?.();
1254
+ return;
1255
+ }
1256
+ const v = _fsResolveOrFail(filePath, "fsUnlink", onFail);
1257
+ if (!v) {
1258
+ onComplete?.();
1259
+ return;
1260
+ }
1261
+ if (!v.writable || !v.realPath) {
1262
+ _denyWrite("fsUnlink", onFail);
1263
+ onComplete?.();
1264
+ return;
1265
+ }
1266
+ _fs.unlink(v.realPath, (err) => {
1267
+ if (err) {
1268
+ onFail?.({ errMsg: `fsUnlink:fail ${err.message}` });
1269
+ } else {
1270
+ onSuccess?.({ errMsg: "fsUnlink:ok" });
1271
+ }
1272
+ onComplete?.();
1273
+ });
1274
+ }
1275
+ function fsMkdir({ dirPath, recursive = false, success, fail, complete }) {
1276
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1277
+ if (!_fs) {
1278
+ onFail?.({ errMsg: "fsMkdir:fail not available in browser context" });
1279
+ onComplete?.();
1280
+ return;
1281
+ }
1282
+ const v = _fsResolveOrFail(dirPath, "fsMkdir", onFail);
1283
+ if (!v) {
1284
+ onComplete?.();
1285
+ return;
1286
+ }
1287
+ if (!v.writable || !v.realPath) {
1288
+ _denyWrite("fsMkdir", onFail);
1289
+ onComplete?.();
1290
+ return;
1291
+ }
1292
+ _fs.mkdir(v.realPath, { recursive }, (err) => {
1293
+ if (err) {
1294
+ onFail?.({ errMsg: `fsMkdir:fail ${err.message}` });
1295
+ } else {
1296
+ onSuccess?.({ errMsg: "fsMkdir:ok" });
1297
+ }
1298
+ onComplete?.();
1299
+ });
1300
+ }
1301
+ function fsRmdir({ dirPath, recursive = false, success, fail, complete }) {
1302
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1303
+ if (!_fs) {
1304
+ onFail?.({ errMsg: "fsRmdir:fail not available in browser context" });
1305
+ onComplete?.();
1306
+ return;
1307
+ }
1308
+ const v = _fsResolveOrFail(dirPath, "fsRmdir", onFail);
1309
+ if (!v) {
1310
+ onComplete?.();
1311
+ return;
1312
+ }
1313
+ if (!v.writable || !v.realPath) {
1314
+ _denyWrite("fsRmdir", onFail);
1315
+ onComplete?.();
1316
+ return;
1317
+ }
1318
+ const rmFn = _fs.rm ?? _fs.rmdir;
1319
+ rmFn(v.realPath, { recursive }, (err) => {
1320
+ if (err) {
1321
+ onFail?.({ errMsg: `fsRmdir:fail ${err.message}` });
1322
+ } else {
1323
+ onSuccess?.({ errMsg: "fsRmdir:ok" });
1324
+ }
1325
+ onComplete?.();
1326
+ });
1327
+ }
1328
+ function fsReaddir({ dirPath, success, fail, complete }) {
1329
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1330
+ if (!_fs) {
1331
+ onFail?.({ errMsg: "fsReaddir:fail not available in browser context" });
1332
+ onComplete?.();
1333
+ return;
1334
+ }
1335
+ const v = _fsResolveOrFail(dirPath, "fsReaddir", onFail);
1336
+ if (!v) {
1337
+ onComplete?.();
1338
+ return;
1339
+ }
1340
+ if (v.kind === "tmp" || v.kind === "store") {
1341
+ onFail?.({ errMsg: `fsReaddir:fail ${v.kind} is a flat namespace (no dir tree)` });
1342
+ onComplete?.();
1343
+ return;
1344
+ }
1345
+ if (!v.realPath) {
1346
+ onFail?.({ errMsg: "fsReaddir:fail invalid path" });
1347
+ onComplete?.();
1348
+ return;
1349
+ }
1350
+ _fs.readdir(v.realPath, (err, files) => {
1351
+ if (err) {
1352
+ onFail?.({ errMsg: `fsReaddir:fail ${err.message}` });
1353
+ } else {
1354
+ onSuccess?.({ files, errMsg: "fsReaddir:ok" });
1355
+ }
1356
+ onComplete?.();
1357
+ });
1358
+ }
1359
+ function fsGetFileInfo({ filePath, digestAlgorithm, success, fail, complete }) {
1360
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1361
+ if (!_fs) {
1362
+ onFail?.({ errMsg: "fsGetFileInfo:fail not available in browser context" });
1363
+ onComplete?.();
1364
+ return;
1365
+ }
1366
+ const v = _fsResolveOrFail(filePath, "fsGetFileInfo", onFail);
1367
+ if (!v) {
1368
+ onComplete?.();
1369
+ return;
1370
+ }
1371
+ if (v.kind === "tmp") {
1372
+ _tmpBytes(filePath).then(
1373
+ (buf) => {
1374
+ const result = { size: buf.length, errMsg: "fsGetFileInfo:ok" };
1375
+ if (digestAlgorithm) {
1376
+ try {
1377
+ const hash = _crypto.createHash(digestAlgorithm === "md5" ? "md5" : "sha1");
1378
+ hash.update(buf);
1379
+ result.digest = hash.digest("hex");
1380
+ } catch {
1381
+ }
1382
+ }
1383
+ onSuccess?.(result);
1384
+ onComplete?.();
1385
+ },
1386
+ (err) => {
1387
+ onFail?.({ errMsg: `fsGetFileInfo:fail ${err.message}` });
1388
+ onComplete?.();
1389
+ }
1390
+ );
1391
+ return;
1392
+ }
1393
+ if (!v.realPath) {
1394
+ onFail?.({ errMsg: "fsGetFileInfo:fail invalid path" });
1395
+ onComplete?.();
1396
+ return;
1397
+ }
1398
+ const resolved = v.realPath;
1399
+ _fs.stat(resolved, (err, s) => {
1400
+ if (err) {
1401
+ onFail?.({ errMsg: `fsGetFileInfo:fail ${err.message}` });
1402
+ onComplete?.();
1403
+ return;
1404
+ }
1405
+ const result = { size: s.size, errMsg: "fsGetFileInfo:ok" };
1406
+ if (digestAlgorithm) {
1407
+ try {
1408
+ const hash = _crypto.createHash(digestAlgorithm === "md5" ? "md5" : "sha1");
1409
+ const stream = _fs.createReadStream(resolved);
1410
+ stream.on("data", (chunk) => hash.update(chunk));
1411
+ stream.on("end", () => {
1412
+ result.digest = hash.digest("hex");
1413
+ onSuccess?.(result);
1414
+ onComplete?.();
1415
+ });
1416
+ stream.on("error", (hashErr) => {
1417
+ onFail?.({ errMsg: `fsGetFileInfo:fail ${hashErr.message}` });
1418
+ onComplete?.();
1419
+ });
1420
+ return;
1421
+ } catch {
1422
+ }
1423
+ }
1424
+ onSuccess?.(result);
1425
+ onComplete?.();
1426
+ });
1427
+ }
1428
+ function fsSaveFile({ tempFilePath, filePath: _filePath, success, fail, complete }) {
1429
+ void _filePath;
1430
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1431
+ if (!_fs) {
1432
+ onFail?.({ errMsg: "fsSaveFile:fail not available in browser context" });
1433
+ onComplete?.();
1434
+ return;
1435
+ }
1436
+ const src = _fsResolveOrFail(tempFilePath, "fsSaveFile", onFail);
1437
+ if (!src) {
1438
+ onComplete?.();
1439
+ return;
1440
+ }
1441
+ const ext = _path.extname(tempFilePath) || "";
1442
+ const id = _crypto.randomUUID() + ext;
1443
+ const savedFilePath = `difile://_store/${id}`;
1444
+ const destResolved = resolveVPath(savedFilePath);
1445
+ if (!destResolved || !destResolved.realPath) {
1446
+ onFail?.({ errMsg: "fsSaveFile:fail unable to allocate destination" });
1447
+ onComplete?.();
1448
+ return;
1449
+ }
1450
+ const destReal = destResolved.realPath;
1451
+ function writeBytesToStore(bytes) {
1452
+ _fs.mkdir(_path.dirname(destReal), { recursive: true }, (mkdirErr) => {
1453
+ if (mkdirErr) {
1454
+ onFail?.({ errMsg: `fsSaveFile:fail ${mkdirErr.message}` });
1455
+ onComplete?.();
1456
+ return;
1457
+ }
1458
+ _fs.writeFile(destReal, bytes, (err) => {
1459
+ if (err) onFail?.({ errMsg: `fsSaveFile:fail ${err.message}` });
1460
+ else onSuccess?.({ savedFilePath, errMsg: "fsSaveFile:ok" });
1461
+ onComplete?.();
1462
+ });
1463
+ });
1464
+ }
1465
+ if (src.kind === "tmp") {
1466
+ _tmpBytes(tempFilePath).then(
1467
+ writeBytesToStore,
1468
+ (err) => {
1469
+ onFail?.({ errMsg: `fsSaveFile:fail ${err.message}` });
1470
+ onComplete?.();
1471
+ }
1472
+ );
1473
+ return;
1474
+ }
1475
+ if (!src.realPath) {
1476
+ onFail?.({ errMsg: "fsSaveFile:fail invalid src path" });
1477
+ onComplete?.();
1478
+ return;
1479
+ }
1480
+ _fs.mkdir(_path.dirname(destReal), { recursive: true }, (mkdirErr) => {
1481
+ if (mkdirErr) {
1482
+ onFail?.({ errMsg: `fsSaveFile:fail ${mkdirErr.message}` });
1483
+ onComplete?.();
1484
+ return;
1485
+ }
1486
+ _fs.copyFile(src.realPath, destReal, (err) => {
1487
+ if (err) {
1488
+ onFail?.({ errMsg: `fsSaveFile:fail ${err.message}` });
1489
+ } else {
1490
+ onSuccess?.({ savedFilePath, errMsg: "fsSaveFile:ok" });
1491
+ }
1492
+ onComplete?.();
1493
+ });
1494
+ });
1495
+ }
1496
+ function fsGetSavedFileList({ success, fail, complete } = {}) {
1497
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1498
+ if (!_fs) {
1499
+ onFail?.({ errMsg: "fsGetSavedFileList:fail not available in browser context" });
1500
+ onComplete?.();
1501
+ return;
1502
+ }
1503
+ const storeVpath = resolveVPath("difile://_store/");
1504
+ const storeDir = storeVpath?.realPath;
1505
+ if (!storeDir) {
1506
+ onSuccess?.({ fileList: [], errMsg: "fsGetSavedFileList:ok" });
1507
+ onComplete?.();
1508
+ return;
1509
+ }
1510
+ _fs.readdir(storeDir, (err, files) => {
1511
+ if (err) {
1512
+ onSuccess?.({ fileList: [], errMsg: "fsGetSavedFileList:ok" });
1513
+ onComplete?.();
1514
+ return;
1515
+ }
1516
+ let pending = files.length;
1517
+ if (pending === 0) {
1518
+ onSuccess?.({ fileList: [], errMsg: "fsGetSavedFileList:ok" });
1519
+ onComplete?.();
1520
+ return;
1521
+ }
1522
+ const fileList = [];
1523
+ for (const name of files) {
1524
+ const full = _path.join(storeDir, name);
1525
+ _fs.stat(full, (statErr, s) => {
1526
+ if (!statErr) {
1527
+ fileList.push({
1528
+ filePath: `difile://_store/${name}`,
1529
+ size: s.size,
1530
+ createTime: s.birthtimeMs
1531
+ });
1532
+ }
1533
+ if (--pending === 0) {
1534
+ onSuccess?.({ fileList, errMsg: "fsGetSavedFileList:ok" });
1535
+ onComplete?.();
1536
+ }
1537
+ });
1538
+ }
1539
+ });
1540
+ }
1541
+ function fsRemoveSavedFile({ filePath, success, fail, complete }) {
1542
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1543
+ if (!_fs) {
1544
+ onFail?.({ errMsg: "fsRemoveSavedFile:fail not available in browser context" });
1545
+ onComplete?.();
1546
+ return;
1547
+ }
1548
+ const v = _fsResolveOrFail(filePath, "fsRemoveSavedFile", onFail);
1549
+ if (!v) {
1550
+ onComplete?.();
1551
+ return;
1552
+ }
1553
+ if (v.kind !== "store" || !v.realPath) {
1554
+ onFail?.({ errMsg: "fsRemoveSavedFile:fail only _store/ entries may be removed" });
1555
+ onComplete?.();
1556
+ return;
1557
+ }
1558
+ _fs.unlink(v.realPath, (err) => {
1559
+ if (err) {
1560
+ onFail?.({ errMsg: `fsRemoveSavedFile:fail ${err.message}` });
1561
+ } else {
1562
+ onSuccess?.({ errMsg: "fsRemoveSavedFile:ok" });
1563
+ }
1564
+ onComplete?.();
1565
+ });
1566
+ }
1567
+ function fsTruncate({ filePath, length = 0, success, fail, complete }) {
1568
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1569
+ if (!_fs) {
1570
+ onFail?.({ errMsg: "fsTruncate:fail not available in browser context" });
1571
+ onComplete?.();
1572
+ return;
1573
+ }
1574
+ const v = _fsResolveOrFail(filePath, "fsTruncate", onFail);
1575
+ if (!v) {
1576
+ onComplete?.();
1577
+ return;
1578
+ }
1579
+ if (!v.writable || !v.realPath) {
1580
+ _denyWrite("fsTruncate", onFail);
1581
+ onComplete?.();
1582
+ return;
1583
+ }
1584
+ _fs.truncate(v.realPath, length, (err) => {
1585
+ if (err) {
1586
+ onFail?.({ errMsg: `fsTruncate:fail ${err.message}` });
1587
+ } else {
1588
+ onSuccess?.({ errMsg: "fsTruncate:ok" });
1589
+ }
1590
+ onComplete?.();
1591
+ });
1592
+ }
1593
+ var fsUnzip = notSupportedApi("fsUnzip");
1594
+
1595
+ // src/simulator/simulator-api-network.ts
1596
+ function downloadFile({ url, header = {}, filePath, success, fail, complete }) {
1597
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1598
+ fetch(url, { headers: header }).then(async (response) => {
1599
+ if (!response.ok) throw new Error(response.statusText);
1600
+ const blob = await response.blob();
1601
+ const tempFilePath = createTempFilePath(blob);
1602
+ onSuccess?.({
1603
+ tempFilePath,
1604
+ filePath: filePath || tempFilePath,
1605
+ statusCode: response.status,
1606
+ errMsg: "downloadFile:ok"
1607
+ });
1608
+ }).catch((error) => {
1609
+ onFail?.({ errMsg: `downloadFile:fail ${error.message}` });
1610
+ }).finally(() => {
1611
+ onComplete?.();
1612
+ });
1613
+ }
1614
+ var uploadRequests = /* @__PURE__ */ new Map();
1615
+ var uploadPendingResolves = /* @__PURE__ */ new Set();
1616
+ var uploadAbortedBeforeStart = /* @__PURE__ */ new Set();
1617
+ var nextUploadId = 1;
1618
+ function createUploadId() {
1619
+ return `upload_${Date.now()}_${nextUploadId++}`;
1620
+ }
1621
+ function parseResponseHeaders(raw) {
1622
+ const headers = {};
1623
+ for (const line of raw.trim().split(/[\r\n]+/)) {
1624
+ if (!line) continue;
1625
+ const index = line.indexOf(":");
1626
+ if (index <= 0) continue;
1627
+ const key = line.slice(0, index).trim();
1628
+ const value = line.slice(index + 1).trim();
1629
+ if (key) headers[key] = value;
1630
+ }
1631
+ return headers;
1632
+ }
1633
+ function appendFormData(form, formData) {
1634
+ for (const [key, value] of Object.entries(formData)) {
1635
+ if (value == null) continue;
1636
+ if (value instanceof Blob) {
1637
+ form.append(key, value);
1638
+ } else if (typeof value === "object") {
1639
+ form.append(key, JSON.stringify(value));
1640
+ } else {
1641
+ form.append(key, String(value));
1642
+ }
1643
+ }
1644
+ }
1645
+ function uploadFile({
1646
+ url,
1647
+ filePath,
1648
+ name,
1649
+ header = {},
1650
+ formData = {},
1651
+ timeout,
1652
+ uploadId = createUploadId(),
1653
+ progress,
1654
+ headersReceived,
1655
+ success,
1656
+ fail,
1657
+ complete
1658
+ }) {
1659
+ const { onSuccess, onFail, onComplete } = bindCallbacks(this, { success, fail, complete });
1660
+ const onProgress = this.createCallbackFunction(progress);
1661
+ const onHeadersReceived = this.createCallbackFunction(headersReceived);
1662
+ const cleanup = () => {
1663
+ uploadRequests.delete(uploadId);
1664
+ uploadPendingResolves.delete(uploadId);
1665
+ uploadAbortedBeforeStart.delete(uploadId);
1666
+ };
1667
+ const finishFail = (message) => {
1668
+ cleanup();
1669
+ const result = { errMsg: `uploadFile:fail ${message}` };
1670
+ onFail?.(result);
1671
+ onComplete?.(result);
1672
+ };
1673
+ uploadPendingResolves.add(uploadId);
1674
+ void resolveTempFilePath(filePath).then((blob) => {
1675
+ uploadPendingResolves.delete(uploadId);
1676
+ if (uploadAbortedBeforeStart.has(uploadId)) {
1677
+ finishFail("abort");
1678
+ return;
1679
+ }
1680
+ const xhr = new XMLHttpRequest();
1681
+ let settled = false;
1682
+ let deliveredHeaders = false;
1683
+ uploadRequests.set(uploadId, xhr);
1684
+ const finishSuccess = () => {
1685
+ if (settled) return;
1686
+ settled = true;
1687
+ const headers = parseResponseHeaders(xhr.getAllResponseHeaders());
1688
+ cleanup();
1689
+ const result = {
1690
+ data: typeof xhr.response === "string" ? xhr.response : xhr.responseText,
1691
+ statusCode: xhr.status,
1692
+ header: headers,
1693
+ errMsg: "uploadFile:ok"
1694
+ };
1695
+ onSuccess?.(result);
1696
+ onComplete?.(result);
1697
+ };
1698
+ const finishXhrFail = (message) => {
1699
+ if (settled) return;
1700
+ settled = true;
1701
+ finishFail(message);
1702
+ };
1703
+ const emitHeaders = () => {
1704
+ if (deliveredHeaders) return;
1705
+ deliveredHeaders = true;
1706
+ onHeadersReceived?.({ header: parseResponseHeaders(xhr.getAllResponseHeaders()) });
1707
+ };
1708
+ xhr.open("POST", url, true);
1709
+ if (timeout === void 0) {
1710
+ xhr.timeout = 6e4;
1711
+ } else if (Number(timeout) > 0) {
1712
+ xhr.timeout = Number(timeout);
1713
+ }
1714
+ for (const [key, value] of Object.entries(header)) {
1715
+ if (/^(referer|content-type)$/i.test(key)) continue;
1716
+ xhr.setRequestHeader(key, String(value));
1717
+ }
1718
+ xhr.upload.onprogress = (event) => {
1719
+ const totalBytesExpectedToSend = event.lengthComputable ? event.total : blob.size;
1720
+ const progressValue = totalBytesExpectedToSend > 0 ? Math.round(event.loaded / totalBytesExpectedToSend * 100) : 0;
1721
+ onProgress?.({
1722
+ progress: Math.max(0, Math.min(100, progressValue)),
1723
+ totalBytesSent: event.loaded,
1724
+ totalBytesExpectedToSend
1725
+ });
1726
+ };
1727
+ xhr.onreadystatechange = () => {
1728
+ if (xhr.readyState >= XMLHttpRequest.HEADERS_RECEIVED) emitHeaders();
1729
+ };
1730
+ xhr.onload = () => {
1731
+ emitHeaders();
1732
+ finishSuccess();
1733
+ };
1734
+ xhr.onerror = () => finishXhrFail("network error");
1735
+ xhr.ontimeout = () => finishXhrFail("timeout");
1736
+ xhr.onabort = () => finishXhrFail("abort");
1737
+ const body = new FormData();
1738
+ appendFormData(body, formData);
1739
+ body.append(name, blob, getTempFileName(filePath, blob, name || "file"));
1740
+ xhr.send(body);
1741
+ }).catch((error) => {
1742
+ finishFail(error.message);
1743
+ });
1744
+ }
1745
+ function uploadFileAbort({ uploadId } = {}) {
1746
+ if (!uploadId) return;
1747
+ const xhr = uploadRequests.get(uploadId);
1748
+ if (xhr) {
1749
+ xhr.abort();
1750
+ return;
1751
+ }
1752
+ if (uploadPendingResolves.has(uploadId)) {
1753
+ uploadAbortedBeforeStart.add(uploadId);
1754
+ }
1755
+ }
1756
+
1757
+ // src/simulator/simulator-api.ts
1758
+ function canIUse({ success, complete }) {
1759
+ const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
1760
+ onSuccess?.(true);
1761
+ onComplete?.();
1762
+ return true;
1763
+ }
1764
+ function getWindowInfo({ success, complete } = {}) {
1765
+ const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
1766
+ const { wb, di, pixelRatio, screenWidth, screenHeight, windowWidth, windowHeight } = readWindowMetrics(this);
1767
+ const bar = this.parent?.getStatusBarRect?.() ?? { height: 0 };
1768
+ const statusBarHeight = di["statusBarHeight"] ?? bar.height;
1769
+ const info = {
1770
+ pixelRatio,
1771
+ screenWidth,
1772
+ screenHeight,
1773
+ windowWidth,
1774
+ windowHeight,
1775
+ statusBarHeight,
1776
+ safeArea: {
1777
+ width: wb.width,
1778
+ height: wb.height - statusBarHeight,
1779
+ top: statusBarHeight,
1780
+ bottom: wb.height,
1781
+ left: 0,
1782
+ right: wb.width
1783
+ }
1784
+ };
1785
+ onSuccess?.(info);
1786
+ onComplete?.();
1787
+ return info;
1788
+ }
1789
+ function getSystemSetting({ success, complete } = {}) {
1790
+ const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
1791
+ const info = {
1792
+ bluetoothEnabled: false,
1793
+ locationEnabled: true,
1794
+ wifiEnabled: true,
1795
+ deviceOrientation: "portrait"
1796
+ };
1797
+ onSuccess?.(info);
1798
+ onComplete?.();
1799
+ return info;
1800
+ }
1801
+ function readWindowMetrics(miniApp) {
1802
+ const wb = miniApp.parent?.el?.querySelector(".dimina-native-webview__root")?.getBoundingClientRect() ?? { width: 375, height: 812 };
1803
+ const di = window.__deviceInfo || {};
1804
+ return {
1805
+ wb,
1806
+ di,
1807
+ pixelRatio: di["pixelRatio"] || window.devicePixelRatio || 2,
1808
+ screenWidth: di["screenWidth"] || wb.width,
1809
+ screenHeight: di["screenHeight"] || wb.height,
1810
+ windowWidth: wb.width,
1811
+ windowHeight: wb.height
1812
+ };
1813
+ }
1814
+ function buildSystemInfo(miniApp) {
1815
+ const { wb, di, pixelRatio, screenWidth, screenHeight, windowWidth, windowHeight } = readWindowMetrics(miniApp);
1816
+ const statusBarHeight = di["statusBarHeight"] ?? 0;
1817
+ const safeAreaBottom = di["safeAreaBottom"] ?? 0;
1818
+ return {
1819
+ brand: di["brand"] || "devtools",
1820
+ model: di["model"] || "devtools",
1821
+ pixelRatio,
1822
+ screenWidth,
1823
+ screenHeight,
1824
+ windowWidth,
1825
+ windowHeight,
1826
+ statusBarHeight,
1827
+ language: "zh_CN",
1828
+ version: "8.0.5",
1829
+ system: di["system"] || "iOS 16.0",
1830
+ platform: di["platform"] || "ios",
1831
+ fontSizeSetting: 16,
1832
+ SDKVersion: "3.0.0",
1833
+ deviceOrientation: "portrait",
1834
+ safeArea: {
1835
+ width: wb.width,
1836
+ height: wb.height - statusBarHeight - safeAreaBottom,
1837
+ top: statusBarHeight,
1838
+ bottom: wb.height - safeAreaBottom,
1839
+ left: 0,
1840
+ right: wb.width
1841
+ }
1842
+ };
1843
+ }
1844
+ function getSystemInfoAsync(opts) {
1845
+ const { success, complete } = opts;
1846
+ const { onSuccess, onComplete } = bindCallbacks(this, { success, complete });
1847
+ onSuccess?.(buildSystemInfo(this));
1848
+ onComplete?.();
1849
+ }
1850
+ function getSystemInfo(opts) {
1851
+ getSystemInfoAsync.call(this, opts);
1852
+ }
1853
+ function getSystemInfoSync() {
1854
+ return buildSystemInfo(this);
1855
+ }
1856
+ function getAccountInfoSync() {
1857
+ return {
1858
+ miniProgram: {
1859
+ appId: this.appId || "",
1860
+ envVersion: "develop",
1861
+ version: ""
1862
+ }
1863
+ };
1864
+ }
1865
+ var simulatorApis = {
1866
+ // Base
1867
+ canIUse,
1868
+ getSystemInfo,
1869
+ getSystemInfoAsync,
1870
+ getSystemInfoSync,
1871
+ getWindowInfo,
1872
+ getSystemSetting,
1873
+ // Network
1874
+ downloadFile,
1875
+ uploadFile,
1876
+ uploadFileAbort,
1877
+ // Storage (sync)
1878
+ setStorageSync,
1879
+ getStorageSync,
1880
+ removeStorageSync,
1881
+ clearStorageSync,
1882
+ getStorageInfoSync,
1883
+ // Storage (async)
1884
+ setStorage,
1885
+ getStorage,
1886
+ removeStorage,
1887
+ clearStorage,
1888
+ getStorageInfo,
1889
+ // Open API
1890
+ getAccountInfoSync,
1891
+ // Device
1892
+ hideKeyboard,
1893
+ adjustPosition,
1894
+ makePhoneCall,
1895
+ chooseContact,
1896
+ addPhoneContact,
1897
+ vibrateShort,
1898
+ vibrateLong,
1899
+ scanCode,
1900
+ // Media: Image
1901
+ chooseImage,
1902
+ previewImage,
1903
+ compressImage,
1904
+ saveImageToPhotosAlbum,
1905
+ getImageInfo,
1906
+ // Media: Video
1907
+ chooseMedia,
1908
+ chooseVideo,
1909
+ // Media: Audio (service-apis/audio)
1910
+ audioCreate,
1911
+ audioListen,
1912
+ audioSetProp,
1913
+ audioPlay,
1914
+ audioPause,
1915
+ audioStop,
1916
+ audioSeek,
1917
+ audioDestroy,
1918
+ // Filesystem (service-apis/file)
1919
+ fsAccess,
1920
+ fsStat,
1921
+ fsReadFile,
1922
+ fsWriteFile,
1923
+ fsAppendFile,
1924
+ fsCopyFile,
1925
+ fsRename,
1926
+ fsUnlink,
1927
+ fsMkdir,
1928
+ fsRmdir,
1929
+ fsReaddir,
1930
+ fsGetFileInfo,
1931
+ fsSaveFile,
1932
+ fsGetSavedFileList,
1933
+ fsRemoveSavedFile,
1934
+ fsTruncate,
1935
+ fsUnzip
1936
+ };
1937
+
1938
+ // src/preload/windows/main.ts
20
1939
  var api = {
21
1940
  ipc: {
22
1941
  invoke: (channel, ...args) => import_electron.ipcRenderer.invoke(channel, ...args),
@@ -40,6 +1959,22 @@ var api = {
40
1959
  }
41
1960
  };
42
1961
  import_electron.contextBridge.exposeInMainWorld("devtools", api);
1962
+ import_electron.ipcRenderer.on(SIMULATOR_EVENTS.API_CALL, (_event, payload) => {
1963
+ void runApiAsync(
1964
+ simulatorApis,
1965
+ payload.name,
1966
+ payload.params
1967
+ ).then((verdict) => {
1968
+ const ack = {
1969
+ appSessionId: payload.appSessionId,
1970
+ requestId: payload.requestId,
1971
+ ok: verdict.ok,
1972
+ result: verdict.result,
1973
+ errMsg: verdict.errMsg
1974
+ };
1975
+ import_electron.ipcRenderer.send(BRIDGE_CHANNELS.API_RESPONSE, ack);
1976
+ });
1977
+ });
43
1978
  if (process.env.NODE_ENV === "test") {
44
1979
  import_electron.contextBridge.exposeInMainWorld("__testIpc", {
45
1980
  emit: (channel, ...args) => {