@dimina-kit/devtools 0.4.0-dev.20260828161241 → 0.4.0-dev.20260907055341

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 (277) hide show
  1. package/README.md +52 -729
  2. package/dist/main/app/app.d.ts +27 -7
  3. package/dist/main/app/app.js +285 -681
  4. package/dist/main/app/editor-view.d.ts +21 -0
  5. package/dist/main/app/editor-view.js +71 -0
  6. package/dist/main/app/global-mirrors.d.ts +23 -0
  7. package/dist/main/app/global-mirrors.js +37 -0
  8. package/dist/main/app/host-sidebar-default.d.ts +19 -0
  9. package/dist/main/app/host-sidebar-default.js +44 -0
  10. package/dist/main/app/menu-setup.d.ts +13 -0
  11. package/dist/main/app/menu-setup.js +49 -0
  12. package/dist/main/app/open-project-ipc.d.ts +13 -0
  13. package/dist/main/app/open-project-ipc.js +21 -0
  14. package/dist/main/app/project-list-surface.d.ts +31 -0
  15. package/dist/main/app/project-list-surface.js +20 -0
  16. package/dist/main/app/project-window.d.ts +36 -0
  17. package/dist/main/app/project-window.js +93 -0
  18. package/dist/main/app/servers.d.ts +17 -0
  19. package/dist/main/app/servers.js +60 -0
  20. package/dist/main/app/ui-extension-targets.d.ts +42 -0
  21. package/dist/main/app/ui-extension-targets.js +101 -0
  22. package/dist/main/app/window-close-reveal.harness.d.ts +34 -0
  23. package/dist/main/app/window-close-reveal.harness.js +65 -0
  24. package/dist/main/app/window-events.d.ts +15 -0
  25. package/dist/main/app/window-events.js +45 -0
  26. package/dist/main/app/window-runtime-services.d.ts +41 -0
  27. package/dist/main/app/window-runtime-services.js +178 -0
  28. package/dist/main/app/workbench-modules.d.ts +24 -0
  29. package/dist/main/app/workbench-modules.js +51 -0
  30. package/dist/main/app/workbench-window.d.ts +85 -0
  31. package/dist/main/app/workbench-window.js +310 -0
  32. package/dist/main/index.bundle.js +10669 -9096
  33. package/dist/main/ipc/app.d.ts +4 -1
  34. package/dist/main/ipc/app.js +4 -3
  35. package/dist/main/ipc/device-picker.d.ts +16 -0
  36. package/dist/main/ipc/device-picker.js +27 -0
  37. package/dist/main/ipc/index.d.ts +1 -0
  38. package/dist/main/ipc/index.js +1 -0
  39. package/dist/main/ipc/internal-devtools.d.ts +2 -1
  40. package/dist/main/ipc/internal-devtools.js +4 -3
  41. package/dist/main/ipc/popover.d.ts +4 -1
  42. package/dist/main/ipc/popover.js +25 -9
  43. package/dist/main/ipc/project-create.d.ts +2 -1
  44. package/dist/main/ipc/project-create.js +6 -5
  45. package/dist/main/ipc/project-fs.d.ts +3 -1
  46. package/dist/main/ipc/project-fs.js +17 -17
  47. package/dist/main/ipc/projects.d.ts +3 -3
  48. package/dist/main/ipc/projects.js +13 -12
  49. package/dist/main/ipc/session.d.ts +4 -1
  50. package/dist/main/ipc/session.js +16 -11
  51. package/dist/main/ipc/settings.d.ts +4 -1
  52. package/dist/main/ipc/settings.js +12 -19
  53. package/dist/main/ipc/simulator-module.d.ts +5 -0
  54. package/dist/main/ipc/simulator-module.js +9 -5
  55. package/dist/main/ipc/simulator.d.ts +4 -1
  56. package/dist/main/ipc/simulator.js +12 -18
  57. package/dist/main/ipc/tooltip.d.ts +2 -1
  58. package/dist/main/ipc/tooltip.js +8 -7
  59. package/dist/main/ipc/views.d.ts +4 -1
  60. package/dist/main/ipc/views.js +20 -9
  61. package/dist/main/runtime/devtools-backend-before-quit.harness.d.ts +2 -20
  62. package/dist/main/runtime/devtools-backend-before-quit.harness.js +14 -283
  63. package/dist/main/runtime/devtools-backend.js +14 -3
  64. package/dist/main/runtime/devtools-runtime-mock.harness.d.ts +21 -0
  65. package/dist/main/runtime/devtools-runtime-mock.harness.js +313 -0
  66. package/dist/main/services/app-services.d.ts +62 -0
  67. package/dist/main/services/app-services.js +64 -0
  68. package/dist/main/services/automation/connection-target.d.ts +36 -0
  69. package/dist/main/services/automation/connection-target.js +29 -0
  70. package/dist/main/services/automation/console-bridge.d.ts +28 -0
  71. package/dist/main/services/automation/console-bridge.js +91 -0
  72. package/dist/main/services/automation/handlers/app.js +4 -4
  73. package/dist/main/services/automation/handlers/element.js +55 -21
  74. package/dist/main/services/automation/index.d.ts +12 -1
  75. package/dist/main/services/automation/index.js +54 -133
  76. package/dist/main/services/default-adapter.js +1 -1
  77. package/dist/main/services/fs-bridge-protocol.d.ts +61 -0
  78. package/dist/main/services/fs-bridge-protocol.js +34 -0
  79. package/dist/main/services/fs-watch-sse.d.ts +8 -1
  80. package/dist/main/services/fs-watch-sse.js +19 -5
  81. package/dist/main/services/mcp/connection-owner.d.ts +38 -0
  82. package/dist/main/services/mcp/connection-owner.js +79 -0
  83. package/dist/main/services/mcp/index.d.ts +3 -1
  84. package/dist/main/services/mcp/index.js +4 -3
  85. package/dist/main/services/mcp/opened-project.d.ts +88 -0
  86. package/dist/main/services/mcp/opened-project.js +60 -0
  87. package/dist/main/services/mcp/target-manager.d.ts +71 -23
  88. package/dist/main/services/mcp/target-manager.js +269 -142
  89. package/dist/main/services/mcp/target-selection.d.ts +47 -0
  90. package/dist/main/services/mcp/target-selection.js +71 -0
  91. package/dist/main/services/mcp/tools/context-tools.js +20 -5
  92. package/dist/main/services/mcp/tools/project-tools.d.ts +29 -6
  93. package/dist/main/services/mcp/tools/project-tools.js +37 -25
  94. package/dist/main/services/module.d.ts +13 -5
  95. package/dist/main/services/notifications/renderer-notifier.d.ts +28 -4
  96. package/dist/main/services/notifications/renderer-notifier.js +15 -3
  97. package/dist/main/services/projects/local-provider.js +2 -0
  98. package/dist/main/services/projects/project-repository.d.ts +31 -1
  99. package/dist/main/services/projects/project-repository.js +144 -20
  100. package/dist/main/services/projects/types.d.ts +31 -8
  101. package/dist/main/services/safe-area/index.d.ts +19 -5
  102. package/dist/main/services/safe-area/index.js +38 -13
  103. package/dist/main/services/simulator/ui-extensions.d.ts +8 -0
  104. package/dist/main/services/simulator/ui-extensions.js +16 -6
  105. package/dist/main/services/simulator-storage/index.d.ts +12 -1
  106. package/dist/main/services/simulator-storage/index.js +22 -7
  107. package/dist/main/services/simulator-storage/window-scope.d.ts +20 -0
  108. package/dist/main/services/simulator-storage/window-scope.js +20 -0
  109. package/dist/main/services/views/host-slot-port-channel.d.ts +20 -3
  110. package/dist/main/services/views/host-slot-port-channel.js +33 -5
  111. package/dist/main/services/views/managed-web-contents-view.js +21 -1
  112. package/dist/main/services/views/native-simulator-view.js +13 -16
  113. package/dist/main/services/views/overlay-panels-view.d.ts +13 -0
  114. package/dist/main/services/views/overlay-panels-view.js +31 -0
  115. package/dist/main/services/views/view-manager.d.ts +1 -1
  116. package/dist/main/services/views/view-manager.js +3 -0
  117. package/dist/main/services/window-contexts/context-router.d.ts +36 -0
  118. package/dist/main/services/window-contexts/context-router.js +55 -0
  119. package/dist/main/services/workbench-coi-host.d.ts +52 -0
  120. package/dist/main/services/workbench-coi-host.js +227 -0
  121. package/dist/main/services/workbench-coi-server.js +75 -133
  122. package/dist/main/services/workbench-coi-shutdown.d.ts +40 -0
  123. package/dist/main/services/workbench-coi-shutdown.js +69 -0
  124. package/dist/main/services/workbench-coi-static.d.ts +23 -0
  125. package/dist/main/services/workbench-coi-static.js +87 -0
  126. package/dist/main/services/workbench-context.d.ts +27 -3
  127. package/dist/main/services/workbench-context.js +10 -5
  128. package/dist/main/services/workspace/compile-mode-adapter.d.ts +18 -0
  129. package/dist/main/services/workspace/compile-mode-adapter.js +57 -0
  130. package/dist/main/services/workspace/compile-mode-store.d.ts +25 -0
  131. package/dist/main/services/workspace/compile-mode-store.js +71 -0
  132. package/dist/main/services/workspace/workspace-compile-modes.d.ts +59 -0
  133. package/dist/main/services/workspace/workspace-compile-modes.js +93 -0
  134. package/dist/main/services/workspace/workspace-referer.d.ts +17 -0
  135. package/dist/main/services/workspace/workspace-referer.js +26 -0
  136. package/dist/main/services/workspace/workspace-service.d.ts +4 -0
  137. package/dist/main/services/workspace/workspace-service.js +51 -84
  138. package/dist/main/services/workspace/workspace-thumbnails.d.ts +22 -0
  139. package/dist/main/services/workspace/workspace-thumbnails.js +67 -0
  140. package/dist/main/utils/ipc-context-source.d.ts +40 -0
  141. package/dist/main/utils/ipc-context-source.js +23 -0
  142. package/dist/main/utils/ipc-registry.d.ts +42 -36
  143. package/dist/main/utils/ipc-registry.js +117 -50
  144. package/dist/main/utils/sender-policy.d.ts +9 -0
  145. package/dist/main/utils/sender-policy.js +26 -3
  146. package/dist/main/utils/theme.d.ts +3 -2
  147. package/dist/main/utils/theme.js +3 -2
  148. package/dist/main/windows/main-window/create.d.ts +16 -0
  149. package/dist/main/windows/main-window/create.js +19 -11
  150. package/dist/main/windows/main-window/events.d.ts +1 -1
  151. package/dist/main/windows/main-window/events.js +26 -13
  152. package/dist/main/windows/main-window/index.d.ts +1 -1
  153. package/dist/main/windows/main-window/index.js +1 -1
  154. package/dist/native-host/common/common.js +94 -73
  155. package/dist/native-host/render/render.js +4079 -3171
  156. package/dist/native-host/service/service.js +2 -2
  157. package/dist/preload/runtime/native-host.d.ts +4 -0
  158. package/dist/preload/runtime/temp-files.js +9 -2
  159. package/dist/preload/runtime/wait-for-slot-root.d.ts +7 -4
  160. package/dist/preload/runtime/wait-for-slot-root.js +36 -8
  161. package/dist/preload/windows/host-dialog-runtime.cjs +10 -3
  162. package/dist/preload/windows/host-dialog-runtime.cjs.map +2 -2
  163. package/dist/preload/windows/host-sidebar-runtime.cjs +10 -3
  164. package/dist/preload/windows/host-sidebar-runtime.cjs.map +2 -2
  165. package/dist/preload/windows/host-toolbar-runtime.cjs +10 -3
  166. package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
  167. package/dist/preload/windows/main.cjs +181 -4
  168. package/dist/preload/windows/main.cjs.map +4 -4
  169. package/dist/preload/windows/simulator.cjs +10 -0
  170. package/dist/preload/windows/simulator.cjs.map +2 -2
  171. package/dist/preload/windows/simulator.js +10 -0
  172. package/dist/render-host/pageFrame.html +1 -1
  173. package/dist/render-host/preload.cjs +16 -4
  174. package/dist/renderer/assets/button-CB2MWjHY.js +2 -0
  175. package/dist/renderer/assets/constants-CkoGPQTS.js +2 -0
  176. package/dist/renderer/assets/constants-zQZ2-y21.js +2 -0
  177. package/dist/renderer/assets/{createLucideIcon-Bqi8hpdi.js → createLucideIcon-cZ9FlZZw.js} +2 -2
  178. package/dist/renderer/assets/devicePicker-H2eIO4e1.js +2 -0
  179. package/dist/renderer/assets/dialog-pHzEA8Vx.js +46 -0
  180. package/dist/renderer/assets/dist-B5HADirS.js +2 -0
  181. package/dist/renderer/assets/{dist-DKWdE1TK.js → dist-DIFlRMKe.js} +2 -2
  182. package/dist/renderer/assets/hostSidebarDefault-DRWh6OCt.js +2 -0
  183. package/dist/renderer/assets/index-CEL_XFge.js +2 -0
  184. package/dist/renderer/assets/{input-Ct3alvkq.js → input-CAObw95L.js} +2 -2
  185. package/dist/renderer/assets/ipc-channels-overlays-gIPUFnqc.js +2 -0
  186. package/dist/renderer/assets/jsx-runtime-DICEQH_0.css +1 -0
  187. package/dist/renderer/assets/{jsx-runtime-DGLHmmOq.js → jsx-runtime-DIw5wnYl.js} +1 -1
  188. package/dist/renderer/assets/plus-BQ9u5EbL.js +2 -0
  189. package/dist/renderer/assets/popover-Cw7G2Ctp.js +2 -0
  190. package/dist/renderer/assets/presets-DMZOb9ay.js +2 -0
  191. package/dist/renderer/assets/project-api-YTOr_Yvo.js +2 -0
  192. package/dist/renderer/assets/{projectCreateDialog-Bbjz75bP.js → projectCreateDialog-BmLqiYxn.js} +2 -2
  193. package/dist/renderer/assets/search-BMvuYF48.js +2 -0
  194. package/dist/renderer/assets/select-nFP95TxM.js +2 -0
  195. package/dist/renderer/assets/settings-CnpVfSWt.js +2 -0
  196. package/dist/renderer/assets/settings-api-Ccsf-Nsj.js +2 -0
  197. package/dist/renderer/assets/settings-tab-bar-CAzrv32m.js +2 -0
  198. package/dist/renderer/assets/smartphone-Bb2GdIKy.js +2 -0
  199. package/dist/renderer/assets/tabs-CPKN3Mmq.js +2 -0
  200. package/dist/renderer/assets/{tooltip-B_-_YVbw.js → tooltip-D6AxXRk5.js} +2 -2
  201. package/dist/renderer/assets/types-Bh0hA7El.js +2 -0
  202. package/dist/renderer/assets/updateDialog-CwndJ0Bl.js +2 -0
  203. package/dist/renderer/assets/{utils-kfQov6Pa.js → utils-sEB5OZEQ.js} +2 -2
  204. package/dist/renderer/assets/view-api-B-2zPBR5.js +2 -0
  205. package/dist/renderer/assets/view-ids-BfaDVV5P.js +2 -0
  206. package/dist/renderer/assets/workbench-BLJ0wKsg.js +5 -0
  207. package/dist/renderer/assets/{workbenchSettings-CV4LVA9b.js → workbenchSettings-YD0Ctbm_.js} +3 -3
  208. package/dist/renderer/entries/device-picker/index.html +28 -0
  209. package/dist/renderer/entries/host-sidebar-default/index.html +6 -5
  210. package/dist/renderer/entries/main/index.html +16 -17
  211. package/dist/renderer/entries/popover/index.html +16 -10
  212. package/dist/renderer/entries/project-create-dialog/index.html +12 -12
  213. package/dist/renderer/entries/settings/index.html +10 -10
  214. package/dist/renderer/entries/tooltip/index.html +5 -5
  215. package/dist/renderer/entries/update-dialog/index.html +10 -10
  216. package/dist/renderer/entries/workbench/index.html +49 -0
  217. package/dist/renderer/entries/workbench-settings/index.html +12 -11
  218. package/dist/service-host/host-env-update.cjs +23 -0
  219. package/dist/service-host/preload.cjs +24 -49
  220. package/dist/service-host/service-message-queue.cjs +71 -0
  221. package/dist/service-host/sync-impls/system-info.js +31 -9
  222. package/dist/shared/compile-mode-state.d.ts +73 -0
  223. package/dist/shared/compile-mode-state.js +100 -0
  224. package/dist/shared/compile-modes.d.ts +152 -0
  225. package/dist/shared/compile-modes.js +237 -0
  226. package/dist/shared/ipc-channels-overlays.d.ts +8 -2
  227. package/dist/shared/ipc-channels-overlays.js +19 -2
  228. package/dist/shared/ipc-channels.d.ts +5 -10
  229. package/dist/shared/ipc-channels.js +17 -14
  230. package/dist/shared/ipc-schemas.d.ts +76 -24
  231. package/dist/shared/ipc-schemas.js +55 -10
  232. package/dist/shared/project-window-types.d.ts +42 -0
  233. package/dist/shared/project-window-types.js +2 -0
  234. package/dist/shared/types.d.ts +43 -17
  235. package/dist/shared/view-ids.d.ts +1 -0
  236. package/dist/shared/view-ids.js +3 -1
  237. package/dist/simulator/assets/bridge-channels-B3JAmRfl.js +2 -0
  238. package/dist/simulator/assets/device-shell-ATEhHV2_.css +1 -0
  239. package/dist/simulator/assets/device-shell-pxnZZp10.js +431 -0
  240. package/dist/simulator/assets/simulator-Dwp7lnvu.js +10 -0
  241. package/dist/simulator/assets/simulator-mini-app-DFo7fhi5.js +2 -0
  242. package/dist/simulator/assets/simulator-ui-B2ddJB1R.js +2 -0
  243. package/dist/simulator/simulator.html +3 -3
  244. package/dist/simulator/temp-files.d.ts +6 -0
  245. package/dist/simulator/temp-files.js +46 -4
  246. package/dist/simulator/types.d.ts +7 -0
  247. package/dist/vscode-workbench/assets/__vite-browser-external-JIkWewFf.js +1 -0
  248. package/dist/vscode-workbench/assets/{dist-CMfmHflW.js → dist-CXG-u1VB.js} +3 -3
  249. package/dist/vscode-workbench/assets/{iconv-lite-umd-Bx8CgaZq.js → iconv-lite-umd-Dxx9Qyb4.js} +1 -1
  250. package/dist/vscode-workbench/assets/{index-CdG6YWhW.js → index-6VJMsaWj.js} +460 -460
  251. package/dist/vscode-workbench/assets/{jschardet-M0qgd2lN.js → jschardet-Ba3D16vt.js} +1 -1
  252. package/dist/vscode-workbench/index.html +1 -1
  253. package/package.json +11 -8
  254. package/dist/renderer/assets/button-D5Q2wkXq.js +0 -2
  255. package/dist/renderer/assets/constants-D7DfVqMp.js +0 -2
  256. package/dist/renderer/assets/constants-D8zsejFq.js +0 -2
  257. package/dist/renderer/assets/dialog-e1TecTOY.js +0 -46
  258. package/dist/renderer/assets/hostSidebarDefault-B3yLfy8j.js +0 -2
  259. package/dist/renderer/assets/index-CsPD68N_.js +0 -5
  260. package/dist/renderer/assets/ipc-channels-overlays-LsDzGAtV.js +0 -2
  261. package/dist/renderer/assets/jsx-runtime-2vXHouwr.css +0 -1
  262. package/dist/renderer/assets/popover-Dix5cm_b.js +0 -2
  263. package/dist/renderer/assets/project-api-k7Oq9iaq.js +0 -2
  264. package/dist/renderer/assets/select-acGb0AmJ.js +0 -2
  265. package/dist/renderer/assets/settings-CQrTMr43.js +0 -2
  266. package/dist/renderer/assets/settings-api-CrUQ9rYV.js +0 -2
  267. package/dist/renderer/assets/settings-tab-bar-Cw1kVIf2.js +0 -2
  268. package/dist/renderer/assets/types-CsEKtFyr.js +0 -2
  269. package/dist/renderer/assets/updateDialog-NsF8223A.js +0 -2
  270. package/dist/renderer/assets/view-api-CLn3rcQE.js +0 -2
  271. package/dist/simulator/assets/bridge-channels-zhsumfky.js +0 -2
  272. package/dist/simulator/assets/device-shell-CmtM1QxP.js +0 -2
  273. package/dist/simulator/assets/device-shell-iFZo1igL.css +0 -1
  274. package/dist/simulator/assets/simulator-CIobn3Mh.js +0 -10
  275. package/dist/simulator/assets/simulator-mini-app-CRe6n9br.js +0 -2
  276. package/dist/simulator/assets/simulator-ui-C_cP602X.js +0 -2
  277. package/dist/vscode-workbench/assets/__vite-browser-external-Bc1vizTf.js +0 -1
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Single owner of one open project's compile modes: the only thing allowed
3
+ * to read/write the persisted file and to advance the in-memory snapshot.
4
+ * `apply()` calls are serialized through a queue so two commands issued
5
+ * back-to-back never interleave their persists, and persist-before-adopt
6
+ * means a write that fails on disk is never visible in `get()` or broadcast
7
+ * to `onChange` listeners — memory never runs ahead of what's on disk.
8
+ */
9
+ import { type CompileModeChange, type CompileModeCommand, type CompileModeSnapshot, type MintId } from '../../../shared/compile-mode-state.js';
10
+ import type { CompileModes } from '../../../shared/types.js';
11
+ export type { CompileModeChange, CompileModeSnapshot };
12
+ export interface CompileModeStore {
13
+ readonly projectPath: string;
14
+ get(): CompileModeSnapshot;
15
+ apply(command: CompileModeCommand): Promise<CompileModeChange>;
16
+ onChange(listener: (change: CompileModeChange) => void): () => void;
17
+ dispose(): void;
18
+ }
19
+ export declare function openCompileModeStore(input: {
20
+ projectPath: string;
21
+ load(): Promise<unknown>;
22
+ persist(stored: CompileModes): Promise<void>;
23
+ mintId?: MintId;
24
+ }): Promise<CompileModeStore>;
25
+ //# sourceMappingURL=compile-mode-store.d.ts.map
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Single owner of one open project's compile modes: the only thing allowed
3
+ * to read/write the persisted file and to advance the in-memory snapshot.
4
+ * `apply()` calls are serialized through a queue so two commands issued
5
+ * back-to-back never interleave their persists, and persist-before-adopt
6
+ * means a write that fails on disk is never visible in `get()` or broadcast
7
+ * to `onChange` listeners — memory never runs ahead of what's on disk.
8
+ */
9
+ import { applyCompileModeCommand, stateFromStored, storedFromState, } from '../../../shared/compile-mode-state.js';
10
+ let nextIdCounter = 0;
11
+ function defaultMintId() {
12
+ nextIdCounter += 1;
13
+ return `compile-mode-${nextIdCounter}`;
14
+ }
15
+ export async function openCompileModeStore(input) {
16
+ const mintId = input.mintId ?? defaultMintId;
17
+ const raw = await input.load();
18
+ let revision = 0;
19
+ let state = stateFromStored(raw, mintId);
20
+ let disposed = false;
21
+ const listeners = new Set();
22
+ // Serializes apply() calls: each call chains onto this promise so the next
23
+ // command's persist only starts after the previous one has fully settled.
24
+ let queue = Promise.resolve();
25
+ function get() {
26
+ return { revision, state };
27
+ }
28
+ // Not `async` on purpose: an async function wrapping a returned promise
29
+ // adds an extra microtask hop before a caller's `.then` fires, which is
30
+ // enough to let the queue's OWN downstream continuation (chaining the next
31
+ // apply()) run ahead of a caller that is racing to inspect order — this
32
+ // function must return `run` itself so a caller's `.then` is attached
33
+ // directly to it, same as the queue's internal continuation.
34
+ function apply(command) {
35
+ if (disposed) {
36
+ return Promise.reject(new Error('compile-mode store disposed'));
37
+ }
38
+ const run = queue.then(() => runApply(command));
39
+ // Keep the queue alive even if this command rejects, so a later apply()
40
+ // still runs instead of being stuck behind a broken link forever.
41
+ queue = run.then(() => undefined, () => undefined);
42
+ return run;
43
+ }
44
+ async function runApply(command) {
45
+ if (disposed) {
46
+ throw new Error('compile-mode store disposed');
47
+ }
48
+ const result = applyCompileModeCommand(state, command, mintId);
49
+ if (result.state === state) {
50
+ // No-op: nothing to persist or broadcast.
51
+ return { revision, state, relaunch: false };
52
+ }
53
+ await input.persist(storedFromState(result.state));
54
+ state = result.state;
55
+ revision += 1;
56
+ const change = { revision, state, relaunch: result.relaunch };
57
+ for (const listener of listeners)
58
+ listener(change);
59
+ return change;
60
+ }
61
+ function onChange(listener) {
62
+ listeners.add(listener);
63
+ return () => listeners.delete(listener);
64
+ }
65
+ function dispose() {
66
+ disposed = true;
67
+ listeners.clear();
68
+ }
69
+ return { projectPath: input.projectPath, get, apply, onChange, dispose };
70
+ }
71
+ //# sourceMappingURL=compile-mode-store.js.map
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Wires a `CompileModeStore` into `WorkspaceService` for whichever project is
3
+ * currently open. Extracted out of workspace-service.ts to keep that file
4
+ * under the repo's file-length ratchet — this is the sole owner of the
5
+ * store's lifecycle (open/replace/dispose); `WorkspaceService` only forwards
6
+ * to it.
7
+ */
8
+ import { type CompileModeCommand } from '../../../shared/compile-mode-state.js';
9
+ import type { CompileConfig } from '../../../shared/types.js';
10
+ import type { ProjectsProvider } from '../projects/types.js';
11
+ import { type CompileModeChange, type CompileModeSnapshot, type CompileModeStore } from './compile-mode-store.js';
12
+ export interface CompileModeManager {
13
+ /**
14
+ * Creates and returns a store for `projectPath` as a standalone handle —
15
+ * it does NOT touch the current store or subscribe to `onChange`. The
16
+ * caller owns the handle until it either passes it to `adopt` or disposes
17
+ * it itself (e.g. because the open it belongs to was superseded).
18
+ */
19
+ open(projectPath: string): Promise<CompileModeStore>;
20
+ /**
21
+ * Makes `store` the current one: disposes whatever was current (and its
22
+ * subscription) first, then wires `store` up. The current store must only
23
+ * ever change here, alongside the session it belongs to — never as a side
24
+ * effect of merely opening one.
25
+ */
26
+ adopt(store: CompileModeStore): void;
27
+ /** Disposes the current store, if any. Safe to call when none is open. */
28
+ disposeCurrent(): void;
29
+ /**
30
+ * `projectPath` omitted returns the currently open project's snapshot
31
+ * (for callers, like the popover, that don't track a project path of
32
+ * their own); given, it must match the open store's project or this
33
+ * throws — a caller that DOES know the path never silently reads another
34
+ * project's modes.
35
+ */
36
+ getCompileModeState(projectPath?: string): CompileModeSnapshot;
37
+ applyCompileModeCommand(command: CompileModeCommand): Promise<CompileModeChange>;
38
+ getCompileConfig(projectPath: string): Promise<CompileConfig>;
39
+ /** Untouched by the store redesign — a direct provider passthrough. */
40
+ saveCompileConfig(projectPath: string, config: CompileConfig): Promise<void>;
41
+ }
42
+ export declare function createCompileModeManager(provider: ProjectsProvider, onChange: (change: CompileModeChange) => void): CompileModeManager;
43
+ /**
44
+ * Opens a store handle for `projectPath` right after a compile succeeds,
45
+ * WITHOUT making it current — the caller decides whether to `adopt` it once
46
+ * it has confirmed (under the op lock) that its open is still the latest
47
+ * one; a superseded open disposes the handle itself instead. On failure,
48
+ * closes `session` (best-effort) and returns the error message. A session
49
+ * that compiled but whose store failed to open must not be left running, so
50
+ * this centralizes that cleanup for callers.
51
+ */
52
+ export declare function openCompileModeStoreAfterCompile(manager: CompileModeManager, projectPath: string, session: {
53
+ close(): Promise<void>;
54
+ }): Promise<{
55
+ store: CompileModeStore;
56
+ } | {
57
+ error: string;
58
+ }>;
59
+ //# sourceMappingURL=workspace-compile-modes.d.ts.map
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Wires a `CompileModeStore` into `WorkspaceService` for whichever project is
3
+ * currently open. Extracted out of workspace-service.ts to keep that file
4
+ * under the repo's file-length ratchet — this is the sole owner of the
5
+ * store's lifecycle (open/replace/dispose); `WorkspaceService` only forwards
6
+ * to it.
7
+ */
8
+ import { selectedMode } from '../../../shared/compile-mode-state.js';
9
+ import { compileConfigFromMode } from '../../../shared/compile-modes.js';
10
+ import * as repo from '../projects/project-repository.js';
11
+ import { createCompileModeAdapter } from './compile-mode-adapter.js';
12
+ import { openCompileModeStore, } from './compile-mode-store.js';
13
+ export function createCompileModeManager(provider, onChange) {
14
+ const adapter = createCompileModeAdapter(provider);
15
+ let store = null;
16
+ let unsubscribe = null;
17
+ function disposeCurrent() {
18
+ unsubscribe?.();
19
+ unsubscribe = null;
20
+ store?.dispose();
21
+ store = null;
22
+ }
23
+ async function open(projectPath) {
24
+ return openCompileModeStore({
25
+ projectPath,
26
+ load: () => adapter.getCompileModes(projectPath),
27
+ persist: (stored) => adapter.saveCompileModes(projectPath, stored),
28
+ });
29
+ }
30
+ function adopt(handle) {
31
+ disposeCurrent();
32
+ store = handle;
33
+ unsubscribe = handle.onChange(onChange);
34
+ }
35
+ function getCompileModeState(projectPath) {
36
+ if (!store || (projectPath !== undefined && projectPath !== store.projectPath)) {
37
+ throw new Error(`no compile-mode store open for ${projectPath ?? ''}`);
38
+ }
39
+ return store.get();
40
+ }
41
+ function applyCompileModeCommand(command) {
42
+ if (!store)
43
+ return Promise.reject(new Error('no compile-mode store open'));
44
+ return store.apply(command);
45
+ }
46
+ // Mirrors project-repository.ts's own getCompileConfig: 普通编译 (and any
47
+ // selected mode that left its start page blank) resolves to an empty
48
+ // startPage, filled in here with the project's real entry page rather than
49
+ // a mini-program-only literal.
50
+ async function getCompileConfig(projectPath) {
51
+ if (store && store.projectPath === projectPath) {
52
+ const config = compileConfigFromMode(selectedMode(store.get().state));
53
+ if (config.startPage)
54
+ return config;
55
+ return { ...config, startPage: repo.getProjectPages(projectPath).entryPagePath };
56
+ }
57
+ return adapter.getCompileConfig(projectPath);
58
+ }
59
+ return {
60
+ open,
61
+ adopt,
62
+ disposeCurrent,
63
+ getCompileModeState,
64
+ applyCompileModeCommand,
65
+ getCompileConfig,
66
+ saveCompileConfig: adapter.saveCompileConfig,
67
+ };
68
+ }
69
+ /**
70
+ * Opens a store handle for `projectPath` right after a compile succeeds,
71
+ * WITHOUT making it current — the caller decides whether to `adopt` it once
72
+ * it has confirmed (under the op lock) that its open is still the latest
73
+ * one; a superseded open disposes the handle itself instead. On failure,
74
+ * closes `session` (best-effort) and returns the error message. A session
75
+ * that compiled but whose store failed to open must not be left running, so
76
+ * this centralizes that cleanup for callers.
77
+ */
78
+ export async function openCompileModeStoreAfterCompile(manager, projectPath, session) {
79
+ try {
80
+ const store = await manager.open(projectPath);
81
+ return { store };
82
+ }
83
+ catch (err) {
84
+ try {
85
+ await session.close();
86
+ }
87
+ catch (closeErr) {
88
+ console.warn('[workspace] closing session after compile-mode store open failure (non-fatal):', closeErr);
89
+ }
90
+ return { error: err instanceof Error ? err.message : String(err) };
91
+ }
92
+ }
93
+ //# sourceMappingURL=workspace-compile-modes.js.map
@@ -0,0 +1,17 @@
1
+ import type { ProjectSession } from '../../../shared/types.js';
2
+ /**
3
+ * The forced `servicewechat.com` Referer is stored per project partition, so
4
+ * every workspace call must name the project it is acting for. Both helpers
5
+ * therefore take the session and project path explicitly: a workspace that
6
+ * reached for its own mutable `currentSession` after resetting it would clear
7
+ * nothing, and one that passed no project at all would be asking to wipe a
8
+ * partition that belongs to whichever project happens to be open elsewhere.
9
+ */
10
+ /** Forces this project's Referer. No-op for a session without a usable appId. */
11
+ export declare function applyRefererForSession(session: ProjectSession, projectPath: string): void;
12
+ /**
13
+ * Clears only this project's own entry. Call BEFORE the caller resets its
14
+ * session/path state, otherwise there is no partition left to name.
15
+ */
16
+ export declare function clearRefererForSession(session: ProjectSession | null, projectPath: string): void;
17
+ //# sourceMappingURL=workspace-referer.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { clearSimulatorServicewechatReferer, setSimulatorServicewechatReferer, } from '../simulator/referer.js';
2
+ /**
3
+ * The forced `servicewechat.com` Referer is stored per project partition, so
4
+ * every workspace call must name the project it is acting for. Both helpers
5
+ * therefore take the session and project path explicitly: a workspace that
6
+ * reached for its own mutable `currentSession` after resetting it would clear
7
+ * nothing, and one that passed no project at all would be asking to wipe a
8
+ * partition that belongs to whichever project happens to be open elsewhere.
9
+ */
10
+ /** Forces this project's Referer. No-op for a session without a usable appId. */
11
+ export function applyRefererForSession(session, projectPath) {
12
+ const appInfo = session.appInfo;
13
+ if (!appInfo || typeof appInfo.appId !== 'string' || appInfo.appId.length === 0)
14
+ return;
15
+ setSimulatorServicewechatReferer(appInfo.appId, typeof appInfo.version === 'string' ? appInfo.version : undefined, projectPath);
16
+ }
17
+ /**
18
+ * Clears only this project's own entry. Call BEFORE the caller resets its
19
+ * session/path state, otherwise there is no partition left to name.
20
+ */
21
+ export function clearRefererForSession(session, projectPath) {
22
+ if (!session)
23
+ return;
24
+ clearSimulatorServicewechatReferer(session.appInfo.appId, projectPath);
25
+ }
26
+ //# sourceMappingURL=workspace-referer.js.map
@@ -1,4 +1,6 @@
1
1
  import type { AppInfo, CompileConfig, ProjectSession } from '../../../shared/types.js';
2
+ import type { CompileModeCommand } from '../../../shared/compile-mode-state.js';
3
+ import type { CompileModeChange, CompileModeSnapshot } from './compile-mode-store.js';
2
4
  import type { WorkbenchContext } from '../workbench-context.js';
3
5
  import type { Project, ProjectPages, ProjectSettings } from '../projects/project-repository.js';
4
6
  import type { ProjectPatch } from '../projects/types.js';
@@ -57,6 +59,8 @@ export interface WorkspaceService {
57
59
  getProjectPages(projectPath: string): ProjectPages;
58
60
  getCompileConfig(projectPath: string): Promise<CompileConfig>;
59
61
  saveCompileConfig(projectPath: string, config: CompileConfig): Promise<void>;
62
+ getCompileModeState(projectPath?: string): CompileModeSnapshot;
63
+ applyCompileModeCommand(command: CompileModeCommand): Promise<CompileModeChange>;
60
64
  getProjectSettings(projectPath: string): ProjectSettings;
61
65
  updateProjectSettings(projectPath: string, patch: Partial<ProjectSettings>): void;
62
66
  }
@@ -1,10 +1,11 @@
1
+ import { createCompileModeManager, openCompileModeStoreAfterCompile } from './workspace-compile-modes.js';
1
2
  import { rejectInvalidAppId, validateProjectDirSafe } from './open-project-guards.js';
2
3
  import * as repo from '../projects/project-repository.js';
3
4
  import { reportRebuildStatus } from './rebuild-status.js';
4
- import { DEFAULT_COMPILE_CONFIG } from '../projects/types.js';
5
- import { clearSimulatorServicewechatReferer, setSimulatorServicewechatReferer, } from '../simulator/referer.js';
5
+ import { applyRefererForSession, clearRefererForSession } from './workspace-referer.js';
6
6
  import { loadWorkbenchSettings } from '../settings/index.js';
7
7
  import { createOpLock } from './op-lock.js';
8
+ import { createThumbnailOps } from './workspace-thumbnails.js';
8
9
  /** Build a workspace service bound to the given workbench context. */
9
10
  export function createWorkspaceService(ctx) {
10
11
  let currentSession = null;
@@ -69,7 +70,7 @@ export function createWorkspaceService(ctx) {
69
70
  try {
70
71
  if (!opLock.isOwner(mySeq))
71
72
  return true;
72
- clearSimulatorServicewechatReferer();
73
+ clearRefererForSession(currentSession, currentProjectPath);
73
74
  // Switching projects tears down the embedded workbench editor (mirrors one
74
75
  // project's disk; saves would else hit the wrong project) AND the native
75
76
  // simulator (its 'destroyed' hook owns the bridge session). Back-to-list
@@ -81,6 +82,8 @@ export function createWorkspaceService(ctx) {
81
82
  // Invalidate the outgoing onLog generation before teardown so the dying
82
83
  // worker's buffered lines can't pollute the incoming compile timeline.
83
84
  logGeneration++;
85
+ // Dies with the outgoing session — no-op when none is open.
86
+ compileModes.disposeCurrent();
84
87
  await disposeSession();
85
88
  currentProjectPath = '';
86
89
  lastClosedProjectPath = '';
@@ -91,17 +94,22 @@ export function createWorkspaceService(ctx) {
91
94
  }
92
95
  }
93
96
  /**
94
- * openProject critical section 2 — commit the new session under the lock, only
95
- * if still the latest request. Returns false when superseded (caller discards
96
- * the freshly-opened session instead of clobbering the newer one).
97
+ * openProject critical section 2 — commit the new session (and its
98
+ * compile-mode store handle) under the lock, only if still the latest
99
+ * request. Returns false when superseded (caller discards the
100
+ * freshly-opened session and store instead of clobbering the newer
101
+ * request's). `compileModes.adopt` must only run here, alongside
102
+ * `currentSession`/`currentProjectPath`, so the "current store" and
103
+ * "current session" always switch together.
97
104
  */
98
- async function runOpenCommit(mySeq, session, projectPath) {
105
+ async function runOpenCommit(mySeq, session, projectPath, store) {
99
106
  const release = await opLock.acquire();
100
107
  try {
101
108
  if (!opLock.isOwner(mySeq))
102
109
  return false;
103
110
  currentSession = session;
104
111
  currentProjectPath = projectPath;
112
+ compileModes.adopt(store);
105
113
  return true;
106
114
  }
107
115
  finally {
@@ -136,22 +144,26 @@ export function createWorkspaceService(ctx) {
136
144
  return { session };
137
145
  }
138
146
  catch (err) {
139
- clearSimulatorServicewechatReferer();
147
+ // No appId resolved for this attempt; the outgoing project's own entry
148
+ // was already cleared by runOpenTeardown, so there is nothing to clear.
140
149
  return { error: String(err) };
141
150
  }
142
151
  }
143
- function applyRefererFromSession(session) {
144
- const appInfo = session.appInfo;
145
- if (appInfo && typeof appInfo.appId === 'string' && appInfo.appId.length > 0) {
146
- setSimulatorServicewechatReferer(appInfo.appId, typeof appInfo.version === 'string' ? appInfo.version : undefined);
147
- }
148
- }
149
152
  // Delegate to the host-injected (or default LocalProjectsProvider)
150
153
  // ProjectsProvider on the context. When the host omits an optional method,
151
154
  // we apply a safe documented default — never silently fall back to
152
155
  // `repo.*`, because a remote provider's project paths are not on the local
153
156
  // filesystem.
154
157
  const provider = ctx.projectsProvider;
158
+ // Owner of whichever project's compile modes are currently open; disposed/
159
+ // replaced alongside the session (teardown, openProject failures, close).
160
+ const compileModes = createCompileModeManager(provider, (change) => ctx.notify.compileModesChanged(change));
161
+ const thumbnails = createThumbnailOps({
162
+ ctx,
163
+ provider,
164
+ getSession: () => currentSession,
165
+ getProjectPath: () => currentProjectPath,
166
+ });
155
167
  return {
156
168
  listProjects: async () => provider.listProjects(),
157
169
  addProject: async (dirPath) => provider.addProject(dirPath),
@@ -236,15 +248,27 @@ export function createWorkspaceService(ctx) {
236
248
  return { success: false, error: compiled.error };
237
249
  }
238
250
  const session = compiled.session;
251
+ // Opened right after compile as a standalone handle — not yet current;
252
+ // every failure branch below disposes THIS handle, never the current
253
+ // store, since this open may no longer own "current" by the time it
254
+ // gets here.
255
+ const opened = await openCompileModeStoreAfterCompile(compileModes, projectPath, session);
256
+ if ('error' in opened) {
257
+ sendStatus('error', opened.error);
258
+ return { success: false, error: opened.error };
259
+ }
260
+ const store = opened.store;
239
261
  const appIdError = await rejectInvalidAppId(session);
240
262
  if (appIdError) {
263
+ store.dispose();
241
264
  sendStatus('error', appIdError);
242
265
  return { success: false, error: appIdError };
243
266
  }
244
- if (!(await runOpenCommit(mySeq, session, projectPath))) {
245
- // Superseded during the compile above — discard the freshly-opened
246
- // session (close its live compile/dev-server) rather than clobber the
247
- // newer request.
267
+ if (!(await runOpenCommit(mySeq, session, projectPath, store))) {
268
+ // Superseded — discard the freshly-opened session and its own store
269
+ // handle rather than clobber the newer request's (already-adopted)
270
+ // current store.
271
+ store.dispose();
248
272
  try {
249
273
  await session.close();
250
274
  }
@@ -258,7 +282,7 @@ export function createWorkspaceService(ctx) {
258
282
  provider.updateLastOpened(projectPath);
259
283
  });
260
284
  bestEffort('sendStatus', () => sendStatus('ready', '编译完成'));
261
- bestEffort('applyReferer', () => applyRefererFromSession(session));
285
+ bestEffort('applyReferer', () => applyRefererForSession(session, projectPath));
262
286
  return {
263
287
  success: true,
264
288
  port: session.port,
@@ -292,7 +316,8 @@ export function createWorkspaceService(ctx) {
292
316
  // Invalidate the active session's onLog BEFORE teardown starts — lines
293
317
  // flushed by the dying compile worker must not reach the panel.
294
318
  logGeneration++;
295
- clearSimulatorServicewechatReferer();
319
+ compileModes.disposeCurrent(); // dies with the session
320
+ clearRefererForSession(currentSession, currentProjectPath);
296
321
  await disposeSession();
297
322
  // Record the root being torn down BEFORE clearing it, so a teardown/
298
323
  // debounced write already in flight can still be accepted against it.
@@ -314,73 +339,15 @@ export function createWorkspaceService(ctx) {
314
339
  getLastClosedProjectPath: () => lastClosedProjectPath,
315
340
  hasActiveSession: () => currentSession !== null,
316
341
  isClosing: () => closing,
317
- async captureThumbnail(projectPath) {
318
- if (!currentSession || projectPath !== currentProjectPath)
319
- return null;
320
- const simulatorWc = ctx.views.getSimulatorWebContents();
321
- if (!simulatorWc)
322
- return null;
323
- if (ctx.views.getSimulatorProjectPath() !== projectPath)
324
- return null;
325
- const session = currentSession;
326
- // Capture the active render-host guest (the mini-program content); the
327
- // simulator WCV only holds the device-shell chrome. In native-host with no
328
- // active guest (not mounted / mid page-switch / destroyed) return null
329
- // rather than persist a device-shell frame as the page — that wrong-content
330
- // frame is the bug this path exists to avoid. Non-native-host: the sim WCV.
331
- const bridge = ctx.bridge;
332
- const nativeHost = bridge?.isNativeHost() ?? false;
333
- const renderGuest = nativeHost ? (bridge?.getActiveRenderWc() ?? null) : null;
334
- if (nativeHost && !renderGuest)
335
- return null;
336
- const captureTarget = renderGuest ?? simulatorWc;
337
- // A destroyed target means teardown is in flight (no valid frame) — return
338
- // null rather than let capturePage() throw indistinguishably into the catch.
339
- if (captureTarget.isDestroyed())
340
- return null;
341
- try {
342
- const image = await captureTarget.capturePage();
343
- if (currentSession !== session
344
- || currentProjectPath !== projectPath
345
- || ctx.views.getSimulatorWebContents() !== simulatorWc
346
- || ctx.views.getSimulatorProjectPath() !== projectPath
347
- // Captured target must still be the live one: a guest that navigated
348
- // mid-capture would otherwise persist a frame from the wrong page.
349
- || (nativeHost ? (bridge?.getActiveRenderWc() ?? null) : simulatorWc) !== captureTarget) {
350
- return null;
351
- }
352
- const dataUrl = `data:image/png;base64,${image.toPNG().toString('base64')}`;
353
- if (provider.saveThumbnail) {
354
- await provider.saveThumbnail(projectPath, dataUrl);
355
- }
356
- // Always hand the renderer back the freshly-captured frame so the
357
- // UI updates immediately even if the host's saveThumbnail is
358
- // async or stores out-of-band.
359
- return dataUrl;
360
- }
361
- catch {
362
- return null;
363
- }
364
- },
365
- async getThumbnail(projectPath) {
366
- if (provider.getThumbnail) {
367
- return (await provider.getThumbnail(projectPath)) ?? null;
368
- }
369
- return null;
370
- },
342
+ captureThumbnail: thumbnails.captureThumbnail,
343
+ getThumbnail: thumbnails.getThumbnail,
371
344
  // `getProjectPages` reads the project's own `app.json` from disk and is
372
345
  // independent of the project registry — it stays on the repo helper.
373
346
  getProjectPages: (projectPath) => repo.getProjectPages(projectPath),
374
- getCompileConfig: async (projectPath) => (provider.getCompileConfig
375
- ? await provider.getCompileConfig(projectPath)
376
- : DEFAULT_COMPILE_CONFIG),
377
- saveCompileConfig: async (projectPath, config) => {
378
- if (provider.saveCompileConfig) {
379
- await provider.saveCompileConfig(projectPath, config);
380
- }
381
- // No persistence when the host opts out; the renderer's edits then
382
- // do not survive a reload, matching the documented contract.
383
- },
347
+ getCompileConfig: (projectPath) => compileModes.getCompileConfig(projectPath),
348
+ saveCompileConfig: (projectPath, config) => compileModes.saveCompileConfig(projectPath, config),
349
+ getCompileModeState: (projectPath) => compileModes.getCompileModeState(projectPath),
350
+ applyCompileModeCommand: (command) => compileModes.applyCompileModeCommand(command),
384
351
  // Per-project settings (uploadWithSourceMap etc.) live in the project's
385
352
  // own `project.config.json`, not the registry — keep direct repo calls.
386
353
  getProjectSettings: (projectPath) => repo.getProjectSettings(projectPath),
@@ -0,0 +1,22 @@
1
+ import type { ProjectSession } from '../../../shared/types.js';
2
+ import type { BridgeRouterHandle } from '../../ipc/bridge-router.js';
3
+ import type { ViewManager } from '../views/view-manager.js';
4
+ import type { ProjectsProvider } from '../projects/types.js';
5
+ import type { WorkspaceService } from './workspace-service.js';
6
+ /**
7
+ * `captureThumbnail`/`getThumbnail` split out of WorkspaceService purely to keep
8
+ * workspace-service.ts under the repo's file-length gate — the semantics (session/
9
+ * project-path ownership, provider round-trip) still belong entirely to that service.
10
+ * Takes a narrow slice of WorkbenchContext (views + bridge) rather than the whole
11
+ * grab-bag type, so this split doesn't grow the WorkbenchContext-import ratchet.
12
+ */
13
+ export declare function createThumbnailOps(input: {
14
+ ctx: {
15
+ views: Pick<ViewManager, 'getSimulatorWebContents' | 'getSimulatorProjectPath'>;
16
+ bridge?: BridgeRouterHandle;
17
+ };
18
+ provider: ProjectsProvider;
19
+ getSession(): ProjectSession | null;
20
+ getProjectPath(): string;
21
+ }): Pick<WorkspaceService, 'captureThumbnail' | 'getThumbnail'>;
22
+ //# sourceMappingURL=workspace-thumbnails.d.ts.map
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `captureThumbnail`/`getThumbnail` split out of WorkspaceService purely to keep
3
+ * workspace-service.ts under the repo's file-length gate — the semantics (session/
4
+ * project-path ownership, provider round-trip) still belong entirely to that service.
5
+ * Takes a narrow slice of WorkbenchContext (views + bridge) rather than the whole
6
+ * grab-bag type, so this split doesn't grow the WorkbenchContext-import ratchet.
7
+ */
8
+ export function createThumbnailOps(input) {
9
+ const { ctx, provider, getSession, getProjectPath } = input;
10
+ return {
11
+ async captureThumbnail(projectPath) {
12
+ if (!getSession() || projectPath !== getProjectPath())
13
+ return null;
14
+ const simulatorWc = ctx.views.getSimulatorWebContents();
15
+ if (!simulatorWc)
16
+ return null;
17
+ if (ctx.views.getSimulatorProjectPath() !== projectPath)
18
+ return null;
19
+ const session = getSession();
20
+ // Capture the active render-host guest (the mini-program content); the
21
+ // simulator WCV only holds the device-shell chrome. In native-host with no
22
+ // active guest (not mounted / mid page-switch / destroyed) return null
23
+ // rather than persist a device-shell frame as the page — that wrong-content
24
+ // frame is the bug this path exists to avoid. Non-native-host: the sim WCV.
25
+ const bridge = ctx.bridge;
26
+ const nativeHost = bridge?.isNativeHost() ?? false;
27
+ const renderGuest = nativeHost ? (bridge?.getActiveRenderWc() ?? null) : null;
28
+ if (nativeHost && !renderGuest)
29
+ return null;
30
+ const captureTarget = renderGuest ?? simulatorWc;
31
+ // A destroyed target means teardown is in flight (no valid frame) — return
32
+ // null rather than let capturePage() throw indistinguishably into the catch.
33
+ if (captureTarget.isDestroyed())
34
+ return null;
35
+ try {
36
+ const image = await captureTarget.capturePage();
37
+ if (getSession() !== session
38
+ || getProjectPath() !== projectPath
39
+ || ctx.views.getSimulatorWebContents() !== simulatorWc
40
+ || ctx.views.getSimulatorProjectPath() !== projectPath
41
+ // Captured target must still be the live one: a guest that navigated
42
+ // mid-capture would otherwise persist a frame from the wrong page.
43
+ || (nativeHost ? (bridge?.getActiveRenderWc() ?? null) : simulatorWc) !== captureTarget) {
44
+ return null;
45
+ }
46
+ const dataUrl = `data:image/png;base64,${image.toPNG().toString('base64')}`;
47
+ if (provider.saveThumbnail) {
48
+ await provider.saveThumbnail(projectPath, dataUrl);
49
+ }
50
+ // Always hand the renderer back the freshly-captured frame so the
51
+ // UI updates immediately even if the host's saveThumbnail is
52
+ // async or stores out-of-band.
53
+ return dataUrl;
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ },
59
+ async getThumbnail(projectPath) {
60
+ if (provider.getThumbnail) {
61
+ return (await provider.getThumbnail(projectPath)) ?? null;
62
+ }
63
+ return null;
64
+ },
65
+ };
66
+ }
67
+ //# sourceMappingURL=workspace-thumbnails.js.map