@dxos/app-framework 0.10.0 → 0.11.1

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 (294) hide show
  1. package/.storybook/main.mts +1 -1
  2. package/.storybook/preview.mts +2 -2
  3. package/CHANGELOG.md +120 -0
  4. package/TASKS.md +11 -0
  5. package/dist/lib/chunk-SurfaceManager.mjs +960 -0
  6. package/dist/lib/chunk-SurfaceManager.mjs.map +1 -0
  7. package/dist/lib/chunk-capability.mjs +15 -0
  8. package/dist/lib/chunk-capability.mjs.map +1 -0
  9. package/dist/lib/{browser/chunk-FJ4765WW.mjs → chunk-context.mjs} +4 -5
  10. package/dist/lib/chunk-context.mjs.map +1 -0
  11. package/dist/lib/chunk-history-tracker.mjs +160 -0
  12. package/dist/lib/chunk-history-tracker.mjs.map +1 -0
  13. package/dist/lib/chunk-plugin-manager.mjs +1390 -0
  14. package/dist/lib/chunk-plugin-manager.mjs.map +1 -0
  15. package/dist/lib/chunk-plugin-manifest.mjs +125 -0
  16. package/dist/lib/chunk-plugin-manifest.mjs.map +1 -0
  17. package/dist/lib/chunk-process-manager-capability.mjs +126 -0
  18. package/dist/lib/chunk-process-manager-capability.mjs.map +1 -0
  19. package/dist/lib/chunk-rolldown-runtime.mjs +13 -0
  20. package/dist/lib/chunk-url-loader.mjs +347 -0
  21. package/dist/lib/chunk-url-loader.mjs.map +1 -0
  22. package/dist/lib/cli.mjs +78 -0
  23. package/dist/lib/cli.mjs.map +1 -0
  24. package/dist/lib/common/activation-events.mjs +35 -0
  25. package/dist/lib/common/activation-events.mjs.map +1 -0
  26. package/dist/lib/common/capabilities.mjs +184 -0
  27. package/dist/lib/common/capabilities.mjs.map +1 -0
  28. package/dist/lib/config.mjs +2 -0
  29. package/dist/lib/core/activation-event.mjs +55 -0
  30. package/dist/lib/core/activation-event.mjs.map +1 -0
  31. package/dist/lib/core/capability.mjs +189 -0
  32. package/dist/lib/core/capability.mjs.map +1 -0
  33. package/dist/lib/core/plugin-manager.mjs +2 -0
  34. package/dist/lib/core/plugin.mjs +340 -0
  35. package/dist/lib/core/plugin.mjs.map +1 -0
  36. package/dist/lib/core/url-loader.mjs +2 -0
  37. package/dist/lib/index.mjs +134 -0
  38. package/dist/lib/index.mjs.map +1 -0
  39. package/dist/lib/testing/react.mjs +70 -0
  40. package/dist/lib/testing/react.mjs.map +1 -0
  41. package/dist/lib/testing.mjs +399 -0
  42. package/dist/lib/testing.mjs.map +1 -0
  43. package/dist/lib/ui.mjs +636 -0
  44. package/dist/lib/ui.mjs.map +1 -0
  45. package/dist/lib/vite-plugin.mjs +986 -0
  46. package/dist/lib/vite-plugin.mjs.map +1 -0
  47. package/dist/plugin/node-esm/index.mjs +4 -3
  48. package/dist/plugin/node-esm/index.mjs.map +3 -3
  49. package/dist/plugin/node-esm/meta.json +1 -1
  50. package/dist/types/src/common/Role.d.ts +31 -0
  51. package/dist/types/src/common/Role.d.ts.map +1 -0
  52. package/dist/types/src/common/Role.test.d.ts +2 -0
  53. package/dist/types/src/common/Role.test.d.ts.map +1 -0
  54. package/dist/types/src/common/capabilities.d.ts +11 -2
  55. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  56. package/dist/types/src/common/index.d.ts +1 -0
  57. package/dist/types/src/common/index.d.ts.map +1 -1
  58. package/dist/types/src/core/capability-manager.d.ts +1 -1
  59. package/dist/types/src/core/capability-manager.d.ts.map +1 -1
  60. package/dist/types/src/core/capability.d.ts +38 -5
  61. package/dist/types/src/core/capability.d.ts.map +1 -1
  62. package/dist/types/src/core/plugin-manager.d.ts +1 -1
  63. package/dist/types/src/core/plugin-manager.d.ts.map +1 -1
  64. package/dist/types/src/core/plugin.d.ts +14 -1
  65. package/dist/types/src/core/plugin.d.ts.map +1 -1
  66. package/dist/types/src/core/registry.d.ts +1 -1
  67. package/dist/types/src/core/registry.d.ts.map +1 -1
  68. package/dist/types/src/plugin-process-manager/history/capability.d.ts +1 -1
  69. package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts +1 -1
  70. package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts.map +1 -1
  71. package/dist/types/src/testing/StorybookErrorFallback.d.ts +15 -0
  72. package/dist/types/src/testing/StorybookErrorFallback.d.ts.map +1 -0
  73. package/dist/types/src/testing/harness.d.ts +1 -1
  74. package/dist/types/src/testing/harness.d.ts.map +1 -1
  75. package/dist/types/src/testing/index.d.ts +2 -0
  76. package/dist/types/src/testing/index.d.ts.map +1 -1
  77. package/dist/types/src/testing/react.d.ts +4 -4
  78. package/dist/types/src/testing/react.d.ts.map +1 -1
  79. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  80. package/dist/types/src/testing/withPluginManager.stories.d.ts +6 -0
  81. package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -1
  82. package/dist/types/src/testing/withSurfaceDebug.d.ts +10 -0
  83. package/dist/types/src/testing/withSurfaceDebug.d.ts.map +1 -0
  84. package/dist/types/src/ui/components/App/App.d.ts +0 -32
  85. package/dist/types/src/ui/components/App/App.d.ts.map +1 -1
  86. package/dist/types/src/ui/components/App/index.d.ts +1 -0
  87. package/dist/types/src/ui/components/App/index.d.ts.map +1 -1
  88. package/dist/types/src/ui/components/App/loader.d.ts +35 -0
  89. package/dist/types/src/ui/components/App/loader.d.ts.map +1 -0
  90. package/dist/types/src/ui/components/HomeSection/HomeSection.d.ts +26 -0
  91. package/dist/types/src/ui/components/HomeSection/HomeSection.d.ts.map +1 -0
  92. package/dist/types/src/ui/components/HomeSection/HomeSection.stories.d.ts +15 -0
  93. package/dist/types/src/ui/components/HomeSection/HomeSection.stories.d.ts.map +1 -0
  94. package/dist/types/src/ui/components/HomeSection/index.d.ts +2 -0
  95. package/dist/types/src/ui/components/HomeSection/index.d.ts.map +1 -0
  96. package/dist/types/src/ui/components/NamePopover/NamePopover.d.ts +14 -0
  97. package/dist/types/src/ui/components/NamePopover/NamePopover.d.ts.map +1 -0
  98. package/dist/types/src/ui/components/NamePopover/index.d.ts +2 -0
  99. package/dist/types/src/ui/components/NamePopover/index.d.ts.map +1 -0
  100. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts +21 -9
  101. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts.map +1 -1
  102. package/dist/types/src/ui/components/Surface/SurfaceComponent.stories.d.ts +4 -1
  103. package/dist/types/src/ui/components/Surface/SurfaceComponent.stories.d.ts.map +1 -1
  104. package/dist/types/src/ui/components/Surface/SurfaceComponent.test.d.ts +2 -0
  105. package/dist/types/src/ui/components/Surface/SurfaceComponent.test.d.ts.map +1 -0
  106. package/dist/types/src/ui/components/Surface/SurfaceDebug.d.ts +40 -0
  107. package/dist/types/src/ui/components/Surface/SurfaceDebug.d.ts.map +1 -0
  108. package/dist/types/src/ui/components/Surface/SurfaceManager.d.ts +23 -0
  109. package/dist/types/src/ui/components/Surface/SurfaceManager.d.ts.map +1 -0
  110. package/dist/types/src/ui/components/Surface/SurfaceManagerContext.d.ts +11 -0
  111. package/dist/types/src/ui/components/Surface/SurfaceManagerContext.d.ts.map +1 -0
  112. package/dist/types/src/ui/components/Surface/SurfaceMetrics.d.ts +72 -0
  113. package/dist/types/src/ui/components/Surface/SurfaceMetrics.d.ts.map +1 -0
  114. package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts.map +1 -1
  115. package/dist/types/src/ui/components/Surface/index.d.ts +20 -25
  116. package/dist/types/src/ui/components/Surface/index.d.ts.map +1 -1
  117. package/dist/types/src/ui/components/Surface/types.d.ts +56 -52
  118. package/dist/types/src/ui/components/Surface/types.d.ts.map +1 -1
  119. package/dist/types/src/ui/components/index.d.ts +2 -0
  120. package/dist/types/src/ui/components/index.d.ts.map +1 -1
  121. package/dist/types/src/ui/hooks/useApp.d.ts.map +1 -1
  122. package/dist/types/tsconfig.tsbuildinfo +1 -1
  123. package/moon.yml +25 -18
  124. package/package.json +58 -73
  125. package/src/common/Role.test.ts +41 -0
  126. package/src/common/Role.ts +54 -0
  127. package/src/common/capabilities.ts +17 -2
  128. package/src/common/index.ts +1 -0
  129. package/src/core/capability-manager.test.ts +1 -1
  130. package/src/core/capability-manager.ts +1 -1
  131. package/src/core/capability.ts +45 -6
  132. package/src/core/plugin-manager.test.ts +38 -3
  133. package/src/core/plugin-manager.ts +18 -1
  134. package/src/core/plugin.ts +16 -1
  135. package/src/core/registry.ts +1 -1
  136. package/src/plugin-process-manager/process-manager-capability.ts +25 -2
  137. package/src/testing/StorybookErrorFallback.tsx +40 -0
  138. package/src/testing/harness.ts +1 -1
  139. package/src/testing/index.ts +2 -0
  140. package/src/testing/react.test.tsx +2 -1
  141. package/src/testing/react.tsx +14 -8
  142. package/src/testing/withPluginManager.stories.tsx +16 -1
  143. package/src/testing/withPluginManager.tsx +13 -2
  144. package/src/testing/withSurfaceDebug.tsx +22 -0
  145. package/src/ui/components/App/App.tsx +7 -35
  146. package/src/ui/components/App/index.ts +1 -0
  147. package/src/ui/components/App/loader.ts +39 -0
  148. package/src/ui/components/HomeSection/HomeSection.stories.tsx +43 -0
  149. package/src/ui/components/HomeSection/HomeSection.tsx +69 -0
  150. package/src/ui/components/HomeSection/index.ts +5 -0
  151. package/src/ui/components/NamePopover/NamePopover.tsx +70 -0
  152. package/src/ui/components/NamePopover/index.ts +5 -0
  153. package/src/ui/components/Surface/DESIGN.md +136 -0
  154. package/src/ui/components/Surface/SurfaceComponent.stories.tsx +70 -41
  155. package/src/ui/components/Surface/SurfaceComponent.test.tsx +403 -0
  156. package/src/ui/components/Surface/SurfaceComponent.tsx +209 -189
  157. package/src/ui/components/Surface/SurfaceDebug.tsx +435 -0
  158. package/src/ui/components/Surface/SurfaceManager.ts +95 -0
  159. package/src/ui/components/Surface/SurfaceManagerContext.ts +23 -0
  160. package/src/ui/components/Surface/SurfaceMetrics.ts +202 -0
  161. package/src/ui/components/Surface/SurfaceProfilerContext.tsx +12 -2
  162. package/src/ui/components/Surface/index.ts +24 -22
  163. package/src/ui/components/Surface/types.test.ts +47 -54
  164. package/src/ui/components/Surface/types.ts +66 -91
  165. package/src/ui/components/index.ts +2 -0
  166. package/src/ui/hooks/useApp.tsx +7 -3
  167. package/src/vite-plugin/boot-loader/loader-app/boot-loader.css +1 -1
  168. package/tsconfig.json +3 -0
  169. package/vite.config.ts +26 -0
  170. package/dist/lib/browser/capability-S44TE2H7.mjs +0 -35
  171. package/dist/lib/browser/capability-S44TE2H7.mjs.map +0 -7
  172. package/dist/lib/browser/chunk-3NQLTQCP.mjs +0 -47
  173. package/dist/lib/browser/chunk-3NQLTQCP.mjs.map +0 -7
  174. package/dist/lib/browser/chunk-53HJHMS5.mjs +0 -7
  175. package/dist/lib/browser/chunk-53HJHMS5.mjs.map +0 -7
  176. package/dist/lib/browser/chunk-FJ4765WW.mjs.map +0 -7
  177. package/dist/lib/browser/chunk-J5LGTIGS.mjs +0 -10
  178. package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +0 -7
  179. package/dist/lib/browser/chunk-KRJ4KK2W.mjs +0 -505
  180. package/dist/lib/browser/chunk-KRJ4KK2W.mjs.map +0 -7
  181. package/dist/lib/browser/chunk-LUH4Y5F2.mjs +0 -430
  182. package/dist/lib/browser/chunk-LUH4Y5F2.mjs.map +0 -7
  183. package/dist/lib/browser/chunk-NKVRSMFN.mjs +0 -95
  184. package/dist/lib/browser/chunk-NKVRSMFN.mjs.map +0 -7
  185. package/dist/lib/browser/chunk-OO53M5UK.mjs +0 -260
  186. package/dist/lib/browser/chunk-OO53M5UK.mjs.map +0 -7
  187. package/dist/lib/browser/chunk-OPTS3ZSN.mjs +0 -83
  188. package/dist/lib/browser/chunk-OPTS3ZSN.mjs.map +0 -7
  189. package/dist/lib/browser/chunk-Q2GLJTVV.mjs +0 -12
  190. package/dist/lib/browser/chunk-Q2GLJTVV.mjs.map +0 -7
  191. package/dist/lib/browser/chunk-SYXIYT6T.mjs +0 -143
  192. package/dist/lib/browser/chunk-SYXIYT6T.mjs.map +0 -7
  193. package/dist/lib/browser/chunk-U5MESPM5.mjs +0 -603
  194. package/dist/lib/browser/chunk-U5MESPM5.mjs.map +0 -7
  195. package/dist/lib/browser/chunk-UGYCLOXE.mjs +0 -1471
  196. package/dist/lib/browser/chunk-UGYCLOXE.mjs.map +0 -7
  197. package/dist/lib/browser/chunk-VF37YTXJ.mjs +0 -28
  198. package/dist/lib/browser/chunk-VF37YTXJ.mjs.map +0 -7
  199. package/dist/lib/browser/chunk-YUVQIOTB.mjs +0 -60
  200. package/dist/lib/browser/chunk-YUVQIOTB.mjs.map +0 -7
  201. package/dist/lib/browser/cli/index.mjs +0 -74
  202. package/dist/lib/browser/cli/index.mjs.map +0 -7
  203. package/dist/lib/browser/common/activation-events.mjs +0 -20
  204. package/dist/lib/browser/common/activation-events.mjs.map +0 -7
  205. package/dist/lib/browser/common/capabilities.mjs +0 -56
  206. package/dist/lib/browser/common/capabilities.mjs.map +0 -7
  207. package/dist/lib/browser/config/index.mjs +0 -8
  208. package/dist/lib/browser/config/index.mjs.map +0 -7
  209. package/dist/lib/browser/core/activation-event.mjs +0 -20
  210. package/dist/lib/browser/core/activation-event.mjs.map +0 -7
  211. package/dist/lib/browser/core/capability.mjs +0 -32
  212. package/dist/lib/browser/core/capability.mjs.map +0 -7
  213. package/dist/lib/browser/core/plugin-manager.mjs +0 -19
  214. package/dist/lib/browser/core/plugin-manager.mjs.map +0 -7
  215. package/dist/lib/browser/core/plugin.mjs +0 -51
  216. package/dist/lib/browser/core/plugin.mjs.map +0 -7
  217. package/dist/lib/browser/core/url-loader.mjs +0 -24
  218. package/dist/lib/browser/core/url-loader.mjs.map +0 -7
  219. package/dist/lib/browser/index.mjs +0 -98
  220. package/dist/lib/browser/index.mjs.map +0 -7
  221. package/dist/lib/browser/meta.json +0 -1
  222. package/dist/lib/browser/process-manager-capability-QK4BMKMN.mjs +0 -132
  223. package/dist/lib/browser/process-manager-capability-QK4BMKMN.mjs.map +0 -7
  224. package/dist/lib/browser/testing/index.mjs +0 -359
  225. package/dist/lib/browser/testing/index.mjs.map +0 -7
  226. package/dist/lib/browser/testing/react.mjs +0 -78
  227. package/dist/lib/browser/testing/react.mjs.map +0 -7
  228. package/dist/lib/browser/ui/index.mjs +0 -60
  229. package/dist/lib/browser/ui/index.mjs.map +0 -7
  230. package/dist/lib/node-esm/capability-3YRF77LV.mjs +0 -36
  231. package/dist/lib/node-esm/capability-3YRF77LV.mjs.map +0 -7
  232. package/dist/lib/node-esm/chunk-2UPUZXGU.mjs +0 -9
  233. package/dist/lib/node-esm/chunk-2UPUZXGU.mjs.map +0 -7
  234. package/dist/lib/node-esm/chunk-37Z53PXZ.mjs +0 -10
  235. package/dist/lib/node-esm/chunk-37Z53PXZ.mjs.map +0 -7
  236. package/dist/lib/node-esm/chunk-4SE7SX7N.mjs +0 -261
  237. package/dist/lib/node-esm/chunk-4SE7SX7N.mjs.map +0 -7
  238. package/dist/lib/node-esm/chunk-BMW6P6QA.mjs +0 -48
  239. package/dist/lib/node-esm/chunk-BMW6P6QA.mjs.map +0 -7
  240. package/dist/lib/node-esm/chunk-COHOWGGJ.mjs +0 -144
  241. package/dist/lib/node-esm/chunk-COHOWGGJ.mjs.map +0 -7
  242. package/dist/lib/node-esm/chunk-DRT75WGD.mjs +0 -604
  243. package/dist/lib/node-esm/chunk-DRT75WGD.mjs.map +0 -7
  244. package/dist/lib/node-esm/chunk-FKMVORZN.mjs +0 -431
  245. package/dist/lib/node-esm/chunk-FKMVORZN.mjs.map +0 -7
  246. package/dist/lib/node-esm/chunk-FPW45EZH.mjs +0 -14
  247. package/dist/lib/node-esm/chunk-FPW45EZH.mjs.map +0 -7
  248. package/dist/lib/node-esm/chunk-GLH4LGHZ.mjs +0 -84
  249. package/dist/lib/node-esm/chunk-GLH4LGHZ.mjs.map +0 -7
  250. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
  251. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
  252. package/dist/lib/node-esm/chunk-IL7O7IRX.mjs +0 -1472
  253. package/dist/lib/node-esm/chunk-IL7O7IRX.mjs.map +0 -7
  254. package/dist/lib/node-esm/chunk-ND2HETHD.mjs +0 -506
  255. package/dist/lib/node-esm/chunk-ND2HETHD.mjs.map +0 -7
  256. package/dist/lib/node-esm/chunk-TLKYZKPW.mjs +0 -29
  257. package/dist/lib/node-esm/chunk-TLKYZKPW.mjs.map +0 -7
  258. package/dist/lib/node-esm/chunk-VCPGX7WN.mjs +0 -62
  259. package/dist/lib/node-esm/chunk-VCPGX7WN.mjs.map +0 -7
  260. package/dist/lib/node-esm/chunk-XSZMX53L.mjs +0 -96
  261. package/dist/lib/node-esm/chunk-XSZMX53L.mjs.map +0 -7
  262. package/dist/lib/node-esm/cli/index.mjs +0 -75
  263. package/dist/lib/node-esm/cli/index.mjs.map +0 -7
  264. package/dist/lib/node-esm/common/activation-events.mjs +0 -21
  265. package/dist/lib/node-esm/common/activation-events.mjs.map +0 -7
  266. package/dist/lib/node-esm/common/capabilities.mjs +0 -57
  267. package/dist/lib/node-esm/common/capabilities.mjs.map +0 -7
  268. package/dist/lib/node-esm/config/index.mjs +0 -9
  269. package/dist/lib/node-esm/config/index.mjs.map +0 -7
  270. package/dist/lib/node-esm/core/activation-event.mjs +0 -21
  271. package/dist/lib/node-esm/core/activation-event.mjs.map +0 -7
  272. package/dist/lib/node-esm/core/capability.mjs +0 -33
  273. package/dist/lib/node-esm/core/capability.mjs.map +0 -7
  274. package/dist/lib/node-esm/core/plugin-manager.mjs +0 -20
  275. package/dist/lib/node-esm/core/plugin-manager.mjs.map +0 -7
  276. package/dist/lib/node-esm/core/plugin.mjs +0 -52
  277. package/dist/lib/node-esm/core/plugin.mjs.map +0 -7
  278. package/dist/lib/node-esm/core/url-loader.mjs +0 -25
  279. package/dist/lib/node-esm/core/url-loader.mjs.map +0 -7
  280. package/dist/lib/node-esm/index.mjs +0 -99
  281. package/dist/lib/node-esm/index.mjs.map +0 -7
  282. package/dist/lib/node-esm/meta.json +0 -1
  283. package/dist/lib/node-esm/process-manager-capability-5S7WZ2JR.mjs +0 -133
  284. package/dist/lib/node-esm/process-manager-capability-5S7WZ2JR.mjs.map +0 -7
  285. package/dist/lib/node-esm/testing/index.mjs +0 -360
  286. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  287. package/dist/lib/node-esm/testing/react.mjs +0 -79
  288. package/dist/lib/node-esm/testing/react.mjs.map +0 -7
  289. package/dist/lib/node-esm/ui/index.mjs +0 -61
  290. package/dist/lib/node-esm/ui/index.mjs.map +0 -7
  291. package/dist/types/src/ui/components/Surface/SurfaceInfo.d.ts +0 -11
  292. package/dist/types/src/ui/components/Surface/SurfaceInfo.d.ts.map +0 -1
  293. package/src/ui/components/Surface/SurfaceInfo.tsx +0 -106
  294. package/vitest.config.ts +0 -14
@@ -0,0 +1,986 @@
1
+ import { getMetaFromConfig } from "./core/plugin.mjs";
2
+ import "./chunk-plugin-manifest.mjs";
3
+ import * as babel from "@babel/core";
4
+ import babelPresetTypeScript from "@babel/preset-typescript";
5
+ import babelPresetSolid from "babel-preset-solid";
6
+ import { build } from "esbuild";
7
+ import path, { basename, dirname, join } from "@dxos/node-std/path";
8
+ import { fileURLToPath, pathToFileURL } from "node:url";
9
+ import { existsSync, readFileSync, readdirSync, statSync } from "@dxos/node-std/fs";
10
+ import * as Schema from "effect/Schema";
11
+ import { Config2, PLUGIN_ENTRY_FILENAME } from "@dxos/protocols";
12
+ import { randomUUID } from "@dxos/node-std/crypto";
13
+ import { rm, writeFile } from "@dxos/node-std/fs/promises";
14
+ import { init, parse } from "cjs-module-lexer";
15
+ import { createRequire } from "node:module";
16
+ //#region src/vite-plugin/boot-loader/loader-app/boot-loader.css?raw
17
+ var boot_loader_default = "/*\n * Boot loader stylesheet — injected into the host's `<head>` by `bootLoaderPlugin`\n * so the full-screen backdrop paints before any JS bundle is fetched. The Solid\n * `Loader` renders the ring + status into the `#boot-loader` backdrop; this\n * sheet styles both. Class/id names here form a contract with `Loader.tsx`,\n * guarded by `BootLoader.solid-stories.tsx` (it mounts the real component).\n */\n\nbody {\n margin: 0;\n overflow: hidden;\n}\n\n/*\n * Defaults match `@dxos/ui-theme`'s `--color-base-surface`, which resolves to\n * Tailwind's `neutral-50` / `neutral-950` in light / dark mode respectively\n * (see `packages/ui/ui-theme/src/css/theme/surfaces.css`). Hosts can override\n * with the `--boot-loader-bg-*` / `--boot-loader-fg-*` custom properties on\n * `:root` if they need a different palette. Keeping the boot loader's\n * background identical to the app's `body` eliminates the flash on handoff\n * to the rendered React shell.\n */\n#boot-loader {\n --color-composer-100: rgb(5 40 61);\n --color-composer-200: rgb(10 75 105);\n --color-composer-300: rgb(1 122 183);\n --color-composer-400: rgb(6 197 253);\n\n /*\n * Caps the disc / mark at the design pixel sizes on roomy viewports while\n * shrinking proportionally on narrow ones (`vmin` follows the smaller of\n * width / height) so neither the ring nor the mark crops on phones.\n */\n --boot-loader-disc-size: min(384px, 80vmin);\n /*\n * Match the React `Placeholder`'s logo box (`h-[300px] w-[300px]` at the\n * `stage >= 1` keyframe) so the brand mark doesn't visibly jump size when\n * the loader hands off — the responsive cap keeps the same 300/384 ratio\n * (≈78%) at any viewport width.\n */\n --boot-loader-mark-size: min(300px, 62.5vmin);\n --boot-loader-status-gap: 32px;\n\n position: fixed;\n inset: 0;\n z-index: 10;\n font-size: 13px;\n font-family:\n ui-sans-serif,\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n 'Segoe UI',\n sans-serif;\n /*\n * Dismissal outro — `mountLoader` toggles `data-dismissing` on this element\n * when the host calls `__bootLoader.ready()`; the loader cross-fades out over\n * the real app shell rendering beneath it, and removes itself once this\n * opacity transition completes (a fallback timer covers reduced-motion).\n */\n transition: opacity 500ms ease-out;\n}\n\n#boot-loader {\n background: var(--boot-loader-bg-light, #fafafa);\n color: var(--boot-loader-fg-light, #0a0a0a);\n --boot-loader-accent: var(--boot-loader-accent-light, var(--color-composer-200));\n}\n\n@media (prefers-color-scheme: dark) {\n #boot-loader {\n background: var(--boot-loader-bg-dark, #0a0a0a);\n color: var(--boot-loader-fg-dark, #f0f0f0);\n --boot-loader-accent: var(--boot-loader-accent-dark, var(--color-composer-300));\n }\n}\n\n#boot-loader[data-dismissing] {\n opacity: 0;\n}\n\n/* Gently shrink the disc + mark as the loader fades, echoing the prior handoff. */\n#boot-loader[data-dismissing] #boot-loader-disc {\n transform: translate(-50%, -50%) scale(0.92);\n transition: transform 500ms ease-out;\n}\n\n/*\n * Stack the ring (the SVG `#boot-loader-ring`) and the brand mark in the same\n * grid cell so the mark sits centered inside the circle.\n */\n#boot-loader-disc {\n position: absolute;\n top: 50%;\n left: 50%;\n display: grid;\n place-items: center;\n width: var(--boot-loader-disc-size);\n height: var(--boot-loader-disc-size);\n transform: translate(-50%, -50%);\n}\n\n#boot-loader-disc > * {\n grid-column: 1;\n grid-row: 1;\n}\n\n/*\n * Default to grayscale so the mark reads as a quiet monochrome silhouette\n * before any host-driven progress lands; the brand palette swaps in once\n * `Loader.tsx` sets `data-host-driven` on the disc (the first\n * `__bootLoader.progress()` call). Hover keeps a parallel reveal affordance\n * for inspection in the storybook. The 1000ms ease lets the grayscale → color\n * transition play through the activation phase rather than snapping.\n */\n#boot-loader-mark {\n width: var(--boot-loader-mark-size);\n height: var(--boot-loader-mark-size);\n display: flex;\n align-items: center;\n justify-content: center;\n filter: grayscale(100%);\n transition: filter 1000ms ease-out;\n}\n\n/*\n * `grayscale(0%)` (identity) rather than `none` — `filter: none` changes\n * the filter function list and most engines treat that as a discrete\n * transition (snap, not ease). Keeping `grayscale(...)` on both sides of\n * the rule lets the browser interpolate the percentage smoothly.\n */\n#boot-loader-disc[data-host-driven] #boot-loader-mark,\n#boot-loader-mark:hover {\n filter: grayscale(0%);\n}\n\n#boot-loader-mark svg {\n width: 100%;\n height: 100%;\n /*\n * The host SVG carries its own brand-palette fills, so we don't apply a\n * `color` cascade here. SVGs that intentionally use `fill=\"currentColor\"`\n * still pick up the loader's text colour via `#boot-loader`'s `color`.\n */\n}\n\n/*\n * Circular determinate progress — a single SVG `<path>` arc that sweeps\n * anticlockwise from 12 o'clock, its angle growing with progress (the `d` is\n * recomputed by the component each tick). There is no static track;\n * `stroke-linecap: round` rounds the trailing edge, and `marker-end` paints the\n * leading-edge dot. Stroke width is in viewBox units so it scales with the disc.\n */\n#boot-loader-ring {\n width: var(--boot-loader-disc-size);\n height: var(--boot-loader-disc-size);\n overflow: visible;\n /*\n * Fade the arc linearly from the head (the marker, fully opaque) back to the\n * tail (12 o'clock, transparent). A conic-gradient mask does this along the\n * curve — `Loader.tsx` writes the eased progress into `--boot-loader-arc`\n * (0–100), and the arc occupies the conic range `(100 - arc)%`…`100%`, so the\n * head sits at `(100 - arc)%` (opaque) and the tail at `100%` (transparent).\n * NOTE: We start at -1.16deg so that we don't mask the marker.\n */\n --boot-loader-arc: 0;\n mask: conic-gradient(\n from -1.16deg at 50% 50%,\n transparent 0,\n transparent calc((100 - var(--boot-loader-arc)) * 1%),\n #000 calc((100 - var(--boot-loader-arc)) * 1%),\n transparent 100%\n );\n -webkit-mask: conic-gradient(\n from -1.16deg at 50% 50%,\n transparent 0,\n transparent calc((100 - var(--boot-loader-arc)) * 1%),\n #000 calc((100 - var(--boot-loader-arc)) * 1%),\n transparent 100%\n );\n}\n\n/*\n * The leading-edge dot's layer — same geometry as `#boot-loader-ring` but with no\n * mask, so the dot renders as a full circle (the ring's conic fade mask would\n * otherwise bisect it where it sits on the mask's transparent→opaque edge).\n */\n#boot-loader-ring-head {\n width: var(--boot-loader-disc-size);\n height: var(--boot-loader-disc-size);\n overflow: visible;\n}\n\n.boot-loader-ring-progress {\n fill: none;\n stroke: var(--boot-loader-accent);\n /* viewBox units: ~1.9px on the 384px disc, scaling down on smaller viewports. */\n stroke-width: 0.5;\n opacity: 0.5;\n stroke-linecap: butt;\n overflow: visible;\n /* Dashed line: dash + gap lengths in viewBox units (~2 units ≈ 7.7px @384px). */\n /* stroke-dasharray: 2 1; */\n}\n\n/* The `marker-end` dot at the arc's leading edge. */\n.boot-loader-ring-marker {\n fill: var(--boot-loader-accent);\n stroke: none;\n overflow: visible;\n /* opacity: 0.5; */\n}\n\n#boot-loader-status {\n position: absolute;\n top: 50%;\n left: 0;\n right: 0;\n /* \n * Sit just below the centered disc — half the disc plus the configured gap.\n */\n transform: translate(0, calc(var(--boot-loader-disc-size) / 2 + var(--boot-loader-status-gap)));\n /*\n * Slightly de-emphasised vs body text so the brand mark + ring stay the\n * dominant focus, but high enough to remain legible on both light and dark\n * backgrounds without a custom palette.\n */\n opacity: 0.5;\n /*\n * Terminal-style log viewport (3 rows at the default `line-height`) over\n * a vertically-stacked track of every status the driver has emitted. The\n * track is bottom-anchored via `justify-content: flex-end` so the newest\n * line always sits on the last visible row, older lines stack above it,\n * and anything that doesn't fit is clipped at the top by\n * `overflow: hidden`. The driver runs a FLIP-style transform animation\n * per append so each new line slides up from below the bottom edge —\n * independent of any `scroll-behavior` smooth-scroll support, which\n * Playwright/headless Chrome strips even from spec-compliant\n * `scrollTo({ behavior: 'smooth' })` calls.\n */\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n height: 4.5em;\n line-height: 1.5;\n letter-spacing: 0.01em;\n /* \n * Fixed-width digits so the `(i/n)` counter on range-bearing status\n * updates (\"Loading plugins (12/80)\") doesn't jitter as the index\n * ticks through different glyph widths. \n */\n font-variant-numeric: tabular-nums;\n text-align: center;\n overflow: hidden;\n}\n\n#boot-loader-status-fade {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 32px;\n background: linear-gradient(to bottom, var(--boot-loader-bg-light, #fafafa), transparent);\n z-index: 1;\n}\n@media (prefers-color-scheme: dark) {\n #boot-loader-status-fade {\n background: linear-gradient(to bottom, var(--boot-loader-bg-dark, #0a0a0a), transparent);\n }\n}\n\n#boot-loader-rss {\n background: var(--boot-loader-bg-light, #fafafa);\n text-wrap: balance;\n}\n@media (prefers-color-scheme: dark) {\n #boot-loader-rss {\n background: var(--boot-loader-bg-dark, #0a0a0a);\n }\n}\n\n/*\n * Track of every appended `.boot-loader-status-line`.\n */\n#boot-loader-status-track {\n display: flex;\n flex-direction: column;\n /*\n * Resting transform is `translateY(0)` — the bottom-anchored flex parent\n * already positions the newest line on the last visible row. On each append\n * `Loader.tsx` runs a one-shot FLIP: snap to `translateY(<lineHeight>px)` with\n * no transition (placing the new line just below the viewport), force a\n * reflow, then animate back to 0 so the track rises by one line-height and the\n * new entry slides up into the bottom row.\n */\n transform: translateY(0);\n transition: transform 500ms ease-out;\n}\n\n/* Honour reduced-motion preferences explicitly — `transition` doesn't auto-respect it. */\n@media (prefers-reduced-motion: reduce) {\n #boot-loader-status-track {\n transition: none;\n }\n}\n\n.boot-loader-status-line {\n flex: 0 0 auto;\n height: 1.5em;\n white-space: nowrap;\n}\n";
18
+ //#endregion
19
+ //#region src/vite-plugin/boot-loader/loader-app/bridge.ts?raw
20
+ var bridge_default = "//\n// Copyright 2026 DXOS.org\n//\n\nimport { type LoaderStore } from './store';\nimport { type BootLoaderApi } from './types';\n\n/**\n * Wrap a reactive {@link LoaderStore} as the imperative `window.__bootLoader`\n * facade the host app drives. `status` / `progress` write into the store;\n * `ready` plays the graceful dismissal outro; `dismiss` is the immediate-remove\n * backstop for the fast-load path (and a no-op once an outro is already in\n * flight, so a late `dismiss()` from the framework never cuts the animation).\n */\nexport const createBridge = (store: LoaderStore, dismissNow: () => void): BootLoaderApi => ({\n status: (payload) => store.pushStatus(payload),\n progress: (fraction) => store.setProgress(fraction),\n ready: () => store.ready(),\n dismiss: () => {\n if (store.phase() === 'dismissing') {\n return;\n }\n dismissNow();\n },\n});\n";
21
+ //#endregion
22
+ //#region src/vite-plugin/boot-loader/loader-app/entry.tsx?raw
23
+ var entry_default = "//\n// Copyright 2026 DXOS.org\n//\n\nimport { mountLoader } from './mount';\nimport { DEFAULT_ROOT_ID } from './types';\n\n//\n// Production entry — bundled to a self-contained IIFE by `bootLoaderPlugin` and\n// inlined into `index.html` ahead of the app bundle. Mounts the loader into the\n// static backdrop using the config the plugin baked in just before this script\n// (including the backdrop id, so the id has a single source). The storybook\n// does NOT use this entry; it imports `mountLoader` directly so Vite compiles\n// the Solid source with HMR.\n//\n\nconst config = window.__BOOT_LOADER_CONFIG__ ?? {};\nconst el = document.getElementById(config.rootId ?? DEFAULT_ROOT_ID);\nif (el) {\n mountLoader(el, config);\n}\n";
24
+ //#endregion
25
+ //#region src/vite-plugin/boot-loader/loader-app/Loader.tsx?raw
26
+ var Loader_default = "//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Component, For, createEffect, createSignal, onCleanup, onMount } from 'solid-js';\n\nimport { type LoaderStore } from './store';\n\n// Ring geometry in the SVG's `0 0 100 100` viewBox. The radius leaves a couple\n// of units of padding so the stroke, its round cap, and the end marker aren't\n// clipped at the viewBox edge.\nconst RING_RADIUS = 48;\nconst RING_CENTER = 50;\n// Leading-edge marker: a small dot drawn at the arc's head in an unmasked layer.\nconst MARKER_RADIUS = 1; // viewBox units → ~3.8px on the 384px disc\n\n/**\n * Read an element's *current animated* translateY (px) from its live transform\n * matrix — the interpolated value mid-transition, not the last-written property.\n * Used by the status FLIP so successive appends chain off the in-flight position\n * instead of yanking the track back to a fixed invert target.\n */\nconst readTranslateY = (element: HTMLElement): number => {\n const computed = getComputedStyle(element).transform;\n if (!computed || computed === 'none') {\n return 0;\n }\n const match = computed.match(/matrix.*\\(([^)]+)\\)/);\n if (!match) {\n return 0;\n }\n const values = match[1].split(',');\n // 2D `matrix(a, b, c, d, tx, ty)` → ty at index 5; 3D `matrix3d(...)` → ty at 13.\n if (values.length === 6) {\n return Number.parseFloat(values[5]) || 0;\n }\n if (values.length === 16) {\n return Number.parseFloat(values[13]) || 0;\n }\n return 0;\n};\n\nexport type LoaderProps = {\n /** Reactive source of truth for progress, status lines, and lifecycle phase. */\n store: LoaderStore;\n /** Inline SVG markup for the brand mark rendered inside the ring. */\n markSvg?: string;\n};\n\n/**\n * The boot loader, authored as a single Solid component — the one source of\n * truth for the loader DOM. `bootLoaderPlugin` bundles this (Solid runtime\n * inlined) into `index.html`; the storybook mounts the very same component, so\n * the two can no longer drift. The DOM structure, ids, and classes mirror\n * `boot-loader.css`.\n *\n * The full-screen backdrop (`#boot-loader`) is injected as static markup so it\n * paints from CSS before this bundle executes; this component renders the disc\n * and status log *into* that backdrop. The dismissal outro (fading `#boot-loader`)\n * and its teardown are owned by {@link mountLoader}, which has the host element.\n */\nexport const Loader: Component<LoaderProps> = (props) => {\n let trackRef: HTMLDivElement | undefined;\n let previousCount = props.store.lines().length;\n\n // FLIP-style slide on each appended line: snap the track down by one\n // line-height (chained off any in-flight translate) with no transition, force\n // a reflow, then animate back to translateY(0) so the new entry rises from\n // below the bottom-anchored viewport. Range ticks (length unchanged) skip it.\n createEffect(() => {\n const count = props.store.lines().length;\n const track = trackRef;\n if (track && count > previousCount) {\n const currentY = readTranslateY(track);\n const lineHeight = track.lastElementChild?.getBoundingClientRect().height ?? 0;\n track.style.transition = 'none';\n track.style.transform = `translateY(${currentY + lineHeight}px)`;\n void track.offsetHeight;\n track.style.transition = '';\n track.style.transform = 'translateY(0)';\n }\n previousCount = count;\n });\n\n // Eased display progress. A `<path>`'s `d` can't be CSS-transitioned, so the\n // arc would snap on every store tick; instead we ease a displayed value toward\n // the store's progress with a requestAnimationFrame loop (~per-frame lerp) and\n // recompute the path each frame. This restores the compositor-smooth growth\n // the old `transition: stroke-dashoffset` gave, while keeping the path +\n // `marker-end` (the marker rides the arc's recomputed end automatically).\n const [shown, setShown] = createSignal(props.store.progress());\n let raf: number | undefined;\n const animate = () => {\n const target = props.store.progress();\n const current = shown();\n // Snap when within a hair to settle; otherwise lerp ~18% of the gap/frame.\n const next = Math.abs(target - current) < 0.05 ? target : current + (target - current) * 0.18;\n if (next !== current) {\n setShown(next);\n }\n raf = requestAnimationFrame(animate);\n };\n\n onMount(() => {\n raf = requestAnimationFrame(animate);\n });\n\n onCleanup(() => {\n if (raf != null) {\n cancelAnimationFrame(raf);\n }\n });\n\n // Determinate ring as an SVG `<path>` arc: an anticlockwise sweep starting at\n // 12 o'clock whose angle grows with the eased `shown()` progress. The sweep is\n // capped just shy of a full turn so the single arc command never degenerates at\n // 100%. The leading-edge dot is its `head` point, rendered separately (below) in\n // an *unmasked* layer — drawing it via `marker-end` on this path would put it\n // under the ring's conic fade mask, whose hard edge bisects the dot into a\n // half-circle.\n const arc = () => {\n const fraction = Math.min(shown() / 100, 0.9999);\n const sweep = fraction * 2 * Math.PI;\n const start = -Math.PI / 2; // 12 o'clock\n const end = start - sweep; // anticlockwise (decreasing angle)\n const x0 = RING_CENTER + RING_RADIUS * Math.cos(start);\n const y0 = RING_CENTER + RING_RADIUS * Math.sin(start);\n const headX = RING_CENTER + RING_RADIUS * Math.cos(end);\n const headY = RING_CENTER + RING_RADIUS * Math.sin(end);\n const largeArc = sweep > Math.PI ? 1 : 0;\n // sweep-flag 0 = anticlockwise (negative-angle) direction.\n return { d: `M ${x0} ${y0} A ${RING_RADIUS} ${RING_RADIUS} 0 ${largeArc} 0 ${headX} ${headY}`, headX, headY };\n };\n\n // Once host-driven, the brand mark eases grayscale → colour and stays there.\n const isHostDriven = () => props.store.phase() !== 'creep';\n\n return (\n <>\n <div id='boot-loader-disc' data-host-driven={isHostDriven() ? '' : undefined}>\n <svg\n id='boot-loader-ring'\n viewBox='0 0 100 100'\n aria-hidden='true'\n style={{ '--boot-loader-arc': String(shown()) }}\n >\n {shown() > 0 ? <path class='boot-loader-ring-progress' d={arc().d} /> : null}\n </svg>\n {/* Leading-edge dot in its own unmasked layer (see `arc()`), so the ring's fade mask\n never clips it. Stacked over `#boot-loader-ring` via the disc grid. */}\n {shown() > 0 ? (\n <svg id='boot-loader-ring-head' viewBox='0 0 100 100' aria-hidden='true'>\n <circle class='boot-loader-ring-marker' cx={arc().headX} cy={arc().headY} r={MARKER_RADIUS} />\n </svg>\n ) : null}\n {props.markSvg ? <div id='boot-loader-mark' innerHTML={props.markSvg} /> : null}\n </div>\n <div id='boot-loader-status'>\n <div id='boot-loader-status-fade' />\n <div id='boot-loader-status-track' ref={trackRef}>\n <For each={props.store.lines()}>{(line) => <div class='boot-loader-status-line'>{line.text}</div>}</For>\n </div>\n </div>\n </>\n );\n};\n";
27
+ //#endregion
28
+ //#region src/vite-plugin/boot-loader/loader-app/mount.tsx?raw
29
+ var mount_default = "//\n// Copyright 2026 DXOS.org\n//\n\nimport { createEffect } from 'solid-js';\nimport { render } from 'solid-js/web';\n\nimport { createBridge } from './bridge';\nimport { Loader } from './Loader';\nimport { createLoaderStore } from './store';\nimport { type BootLoaderConfig } from './types';\n\n/** Fallback teardown if the outro's `transitionend` never fires (e.g. no opacity transition). */\nconst OUTRO_FALLBACK_MS = 800;\n\n/**\n * Mount the boot loader into a host element (`#boot-loader`, the static backdrop\n * the plugin injects — or any container in the storybook) and install the\n * `window.__bootLoader` facade. Renders the disc + status into the host, toggles\n * `data-dismissing` on it for the outro, and removes everything once the outro\n * completes.\n *\n * Returns a disposer that tears the loader down immediately (idempotent).\n */\nexport const mountLoader = (el: HTMLElement, config: BootLoaderConfig = {}): (() => void) => {\n const store = createLoaderStore(config.status);\n\n let removed = false;\n // Forward-declared so `remove` can dispose the Solid render created below.\n let disposeRender: (() => void) | undefined;\n\n const remove = (): void => {\n if (removed) {\n return;\n }\n removed = true;\n el.removeEventListener('transitionend', handleTransitionEnd);\n store.dispose();\n disposeRender?.();\n el.remove();\n if (window.__bootLoader === api) {\n delete window.__bootLoader;\n }\n };\n\n const handleTransitionEnd = (event: TransitionEvent): void => {\n if (event.propertyName === 'opacity' && store.phase() === 'dismissing') {\n remove();\n }\n };\n el.addEventListener('transitionend', handleTransitionEnd);\n\n disposeRender = render(() => {\n // Drive the backdrop's outro from the host element (Solid owns the host's\n // children; the host attribute is toggled imperatively within this owner).\n createEffect(() => {\n const dismissing = store.phase() === 'dismissing';\n el.toggleAttribute('data-dismissing', dismissing);\n if (dismissing) {\n setTimeout(remove, OUTRO_FALLBACK_MS);\n }\n });\n return <Loader store={store} markSvg={config.markSvg} />;\n }, el);\n\n const api = createBridge(store, remove);\n window.__bootLoader = api;\n\n return remove;\n};\n";
30
+ //#endregion
31
+ //#region src/vite-plugin/boot-loader/loader-app/store.ts?raw
32
+ var store_default = "//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Accessor, createSignal } from 'solid-js';\n\nimport { type StatusPayload } from './types';\n\n//\n// Creep tuning. The ring auto-creeps toward a moving ceiling so a long\n// activation silence never reads as a frozen disc. See the original\n// hand-written driver for the rationale behind each constant.\n//\n\n/** Creep timer cadence, in milliseconds. */\nexport const CREEP_TICK_MS = 100;\n/** State-1 ease rate — a gentle \"we're alive\" hint before real progress lands. */\nexport const STATE_1_RATE = 0.05;\n/** State-1 asymptote (percent) the creep eases toward before host progress. */\nexport const STATE_1_ASYMPTOTE = 40;\n/** State-2 ease rate — bridges the gap between sparse host `progress()` calls. */\nexport const STATE_2_RATE = 0.05;\n/** State-2 lead (percent) the ceiling sits ahead of the last host value. */\nexport const STATE_2_BUMP = 15;\n/** Hard ceiling the auto-creep never crosses (host must drive the rest). */\nexport const ABSOLUTE_CEILING = 90;\n\n/** Loader lifecycle phase. */\nexport type Phase = 'creep' | 'host' | 'dismissing';\n\n/** A single rendered status line; `id` keys the `<For>` and survives in-place range ticks. */\nexport type StatusLine = {\n id: number;\n text: string;\n event?: string;\n module?: string;\n};\n\n/**\n * Asymptotic ease — `next = raw + (ceiling - raw) * rate`, clamped so it never\n * overshoots (or regresses past) the ceiling. Pure; unit-tested.\n */\nexport const easeToward = (raw: number, ceiling: number, rate: number): number =>\n raw >= ceiling - 0.1 ? raw : raw + (ceiling - raw) * rate;\n\n/**\n * Clamp a host-supplied fraction to a percent in [0, 100]. Invalid / negative /\n * non-finite values collapse to 0 rather than poisoning the CSS var. Pure;\n * unit-tested.\n */\nexport const clampPercent = (fraction?: number): number =>\n typeof fraction !== 'number' || !Number.isFinite(fraction) || fraction < 0 ? 0 : Math.min(1, fraction) * 100;\n\n/** Display text for a payload — appends the `(index/total)` suffix when a range is present. */\nexport const displayText = (payload: StatusPayload): string =>\n payload.range ? `${payload.humanized} (${payload.range.index}/${payload.range.total})` : payload.humanized;\n\n/**\n * Reactive loader store — owns the progress percent, the status-line log, and\n * the lifecycle phase, plus the auto-creep timer. All DOM-free, so the creep\n * math and status reduction are testable as plain functions; `Loader.tsx` binds\n * the accessors to the DOM and `bridge.ts` wraps the mutators as the imperative\n * `window.__bootLoader` facade.\n */\nexport type LoaderStore = {\n /** Progress as a percent in [0, 100] (the CSS `--boot-loader-bar-progress` value). */\n progress: Accessor<number>;\n /** Appended status lines, newest last. */\n lines: Accessor<StatusLine[]>;\n /** Current lifecycle phase. */\n phase: Accessor<Phase>;\n /** Apply a status update (append, or replace-in-place for range ticks). */\n pushStatus: (payload: StatusPayload) => void;\n /** Enter host-driven progress with `fraction` ∈ [0, 1]; never regresses. */\n setProgress: (fraction?: number) => void;\n /** Snap to 100%, stop the creep, and enter the dismissing phase. */\n ready: () => void;\n /** Stop the creep timer (call on teardown). */\n dispose: () => void;\n};\n\nexport const createLoaderStore = (initialStatus?: string): LoaderStore => {\n const [progress, setProgressPct] = createSignal(0);\n const [lines, setLines] = createSignal<StatusLine[]>(initialStatus ? [{ id: 0, text: initialStatus }] : []);\n const [phase, setPhase] = createSignal<Phase>('creep');\n\n let creepCeiling = STATE_1_ASYMPTOTE;\n let creepRate = STATE_1_RATE;\n let nextId = initialStatus ? 1 : 0;\n let timer: ReturnType<typeof setInterval> | null = null;\n\n const startCreep = (): void => {\n if (timer == null) {\n timer = setInterval(() => setProgressPct((raw) => easeToward(raw, creepCeiling, creepRate)), CREEP_TICK_MS);\n }\n };\n\n const stopCreep = (): void => {\n if (timer != null) {\n clearInterval(timer);\n timer = null;\n }\n };\n\n const pushStatus = (payload: StatusPayload): void => {\n const text = displayText(payload);\n setLines((current) => {\n const previous = current.at(-1);\n // Dedup back-to-back identical transitions (same text + structured fields).\n if (\n previous &&\n previous.text === text &&\n (previous.event ?? null) === (payload.event ?? null) &&\n (previous.module ?? null) === (payload.module ?? null)\n ) {\n return current;\n }\n // Range tick — replace the current line in place rather than appending,\n // so a counted phase produces one entry with an updating suffix.\n if (payload.range && previous) {\n return [...current.slice(0, -1), { ...previous, text }];\n }\n return [...current, { id: nextId++, text, event: payload.event, module: payload.module }];\n });\n };\n\n const setProgress = (fraction?: number): void => {\n setPhase('host');\n const pct = clampPercent(fraction);\n // The ring never regresses: hold the current value if the host reports lower.\n setProgressPct((current) => Math.max(current, pct));\n // Switch the creep to its state-2 cadence and lead the host value by a bump.\n creepRate = STATE_2_RATE;\n creepCeiling = Math.min(Math.max(creepCeiling, pct + STATE_2_BUMP), ABSOLUTE_CEILING);\n startCreep();\n };\n\n const ready = (): void => {\n stopCreep();\n setProgressPct(100);\n setPhase('dismissing');\n };\n\n const dispose = (): void => stopCreep();\n\n startCreep();\n\n return { progress, lines, phase, pushStatus, setProgress, ready, dispose };\n};\n";
33
+ //#endregion
34
+ //#region src/vite-plugin/boot-loader/loader-app/types.ts?raw
35
+ var types_default = "//\n// Copyright 2026 DXOS.org\n//\n\n/**\n * Status payload accepted by `window.__bootLoader.status(...)`. The caller owns\n * formatting — `humanized` is the exact text rendered — while `event` / `module`\n * carry the structured activation ids for the boot trace, and `range` drives an\n * in-place `(index/total)` counter for long counted phases.\n */\nexport type StatusPayload = {\n /**\n * Raw activation event key (e.g. `dxos.org/plugin/observability/activate`)\n * when the transition is event-level.\n */\n event?: string;\n\n /**\n * Raw module id (e.g. `org.dxos.plugin.observability.module.ReactSurface`)\n * when the transition is module-level.\n */\n module?: string;\n\n /** Exact text to display (e.g. \"Activating Observability: react-surface\"). */\n humanized: string;\n\n /**\n * Optional `(index/total)` tick. When present the loader replaces the current\n * line in place (\"Loading plugins (12/80)\") instead of appending a new entry —\n * keeps the visible log compact during long counted phases.\n */\n range?: { index: number; total: number };\n};\n\n/**\n * Imperative facade exposed on `window.__bootLoader`, installed by the inlined\n * loader bundle and driven by the host app (the React relay forwards `useApp`'s\n * startup progress through it).\n */\nexport type BootLoaderApi = {\n /** Update the visible status line. */\n status: (payload: StatusPayload) => void;\n /** Enter host-driven progress — `fraction` ∈ [0, 1]. */\n progress: (fraction?: number) => void;\n /** Play the dismissal outro, then remove the loader DOM (graceful path). */\n ready: () => void;\n /** Remove the loader DOM immediately (fast-load backstop / terminal). */\n dismiss: () => void;\n};\n\n/**\n * Config baked into `index.html` by `bootLoaderPlugin` ahead of the loader\n * bundle, so the compiled app stays static (compiled once, independent of the\n * host's brand mark / initial status).\n */\nexport type BootLoaderConfig = {\n /**\n * Id of the static backdrop element the plugin injects and the loader mounts\n * into — the single coupling between `transformIndexHtml` and the app. The\n * plugin owns the authoritative value and passes it here so `entry.tsx` reads\n * it rather than hardcoding (the CSS selector mirrors it — see `boot-loader.css`).\n */\n rootId?: string;\n /** Inline SVG markup for the brand mark rendered inside the ring. */\n markSvg?: string;\n /** Initial status text rendered before the host fires its first `status(...)`. */\n status?: string;\n};\n\n/** Fallback backdrop id when no config is present (kept in sync with `loader.ts` + the CSS). */\nexport const DEFAULT_ROOT_ID = 'boot-loader';\n\ndeclare global {\n interface Window {\n __bootLoader?: BootLoaderApi;\n __BOOT_LOADER_CONFIG__?: BootLoaderConfig;\n }\n}\n";
36
+ //#endregion
37
+ //#region src/vite-plugin/boot-loader/loader.ts
38
+ var VIRTUAL_NS = "boot-loader-app";
39
+ var MODULES = {
40
+ entry: {
41
+ contents: entry_default,
42
+ tsx: true
43
+ },
44
+ mount: {
45
+ contents: mount_default,
46
+ tsx: true
47
+ },
48
+ Loader: {
49
+ contents: Loader_default,
50
+ tsx: true
51
+ },
52
+ bridge: {
53
+ contents: bridge_default,
54
+ tsx: false
55
+ },
56
+ store: {
57
+ contents: store_default,
58
+ tsx: false
59
+ },
60
+ types: {
61
+ contents: types_default,
62
+ tsx: false
63
+ }
64
+ };
65
+ var resolveDir = dirname(fileURLToPath(import.meta.url));
66
+ /**
67
+ * Compile the loader-app from its inlined raw sources into a single
68
+ * self-contained IIFE (Solid runtime bundled in) suitable for inlining into
69
+ * `index.html`. Mirrors dx-compile's Solid pipeline: `@babel/preset-typescript`
70
+ * strips types, then `babel-preset-solid` compiles JSX into reactive primitives.
71
+ */
72
+ var compileLoaderBundle = async () => {
73
+ const virtualSolid = () => ({
74
+ name: "boot-loader-app-virtual",
75
+ setup: (esbuild) => {
76
+ esbuild.onResolve({ filter: /^\.\// }, (args) => {
77
+ const name = args.path.replace(/^\.\//, "").replace(/\.(tsx?|jsx?)$/, "");
78
+ return name in MODULES ? {
79
+ path: name,
80
+ namespace: VIRTUAL_NS
81
+ } : void 0;
82
+ });
83
+ esbuild.onLoad({
84
+ filter: /.*/,
85
+ namespace: VIRTUAL_NS
86
+ }, async (args) => {
87
+ const module = MODULES[args.path];
88
+ const result = await babel.transformAsync(module.contents, {
89
+ filename: `${args.path}.${module.tsx ? "tsx" : "ts"}`,
90
+ babelrc: false,
91
+ configFile: false,
92
+ presets: [[babelPresetSolid, {
93
+ generate: "dom",
94
+ hydratable: false
95
+ }], [babelPresetTypeScript, { allowDeclareFields: true }]]
96
+ });
97
+ if (!result?.code) throw new Error(`babel-preset-solid returned no code for ${args.path}`);
98
+ return {
99
+ contents: result.code,
100
+ loader: "js",
101
+ resolveDir
102
+ };
103
+ });
104
+ }
105
+ });
106
+ return (await build({
107
+ stdin: {
108
+ contents: "import './entry';",
109
+ loader: "ts",
110
+ resolveDir,
111
+ sourcefile: "boot-loader-entry.ts"
112
+ },
113
+ bundle: true,
114
+ format: "iife",
115
+ platform: "browser",
116
+ target: "es2020",
117
+ minify: true,
118
+ write: false,
119
+ legalComments: "none",
120
+ define: { "process.env.NODE_ENV": "\"production\"" },
121
+ plugins: [virtualSolid()]
122
+ })).outputFiles[0].text;
123
+ };
124
+ var bundlePromise;
125
+ var getLoaderBundle = () => bundlePromise ??= compileLoaderBundle();
126
+ /**
127
+ * Vite plugin that injects a Solid "boot loader" app into the host app's
128
+ * `index.html`.
129
+ *
130
+ * The full-screen backdrop paints on the very first frame from an inline
131
+ * `<style>` (before any JS bundle is fetched), so the user sees the loading
132
+ * surface immediately on cold load instead of a blank document. A compiled,
133
+ * self-contained Solid IIFE — inlined ahead of the app bundle — then renders
134
+ * the determinate progress ring + status log into that backdrop and exposes the
135
+ * host-facing driver on `window.__bootLoader`.
136
+ *
137
+ * The host app drives the loader (the React relay forwards `useApp`'s startup
138
+ * progress):
139
+ * - `window.__bootLoader.status(payload)` updates the status line per phase.
140
+ * - `window.__bootLoader.progress(fraction)` grows the determinate ring (0–1).
141
+ * - `window.__bootLoader.ready()` plays the dismissal outro, then self-removes.
142
+ * - `window.__bootLoader.dismiss()` removes the loader immediately (fast path).
143
+ *
144
+ * Inject order (all at the start of `<body>`, except the stylesheet):
145
+ * - `<style>` → `<head>` (parses before any bundled stylesheet).
146
+ * - `<div id="boot-loader">` → the static backdrop the CSS styles instantly.
147
+ * - inline `<script>` config (`window.__BOOT_LOADER_CONFIG__`) → before the bundle.
148
+ * - inline `<script>` loader bundle → renders the Solid app into the backdrop.
149
+ *
150
+ * Keeping the loader a sibling of `#root` (rather than a child) means
151
+ * `createRoot(document.getElementById('root')).render(...)` does not fight the
152
+ * loader for ownership; the framework explicitly dismisses after the first
153
+ * React commit for a deterministic handoff.
154
+ *
155
+ * Color tokens are exposed as CSS custom properties (`--boot-loader-bg-light`,
156
+ * etc.) in `boot-loader.css`, so consumers can override them at the document
157
+ * level without re-parameterizing this plugin.
158
+ */
159
+ var bootLoaderPlugin = ({ status, markSvg, include = ["index.html"] } = {}) => {
160
+ return {
161
+ name: "app-framework:boot-loader",
162
+ async transformIndexHtml(_html, ctx) {
163
+ const filename = basename(ctx.filename ?? "index.html");
164
+ if (!include.includes(filename)) return;
165
+ const bundle = await getLoaderBundle();
166
+ const rootId = "boot-loader";
167
+ return [
168
+ {
169
+ tag: "style",
170
+ injectTo: "head",
171
+ children: boot_loader_default
172
+ },
173
+ {
174
+ tag: "div",
175
+ injectTo: "body-prepend",
176
+ attrs: {
177
+ "id": rootId,
178
+ "role": "status",
179
+ "aria-live": "polite",
180
+ "aria-label": "Initializing"
181
+ },
182
+ children: ""
183
+ },
184
+ {
185
+ tag: "script",
186
+ injectTo: "body-prepend",
187
+ children: `window.__BOOT_LOADER_CONFIG__=${JSON.stringify({
188
+ rootId,
189
+ markSvg,
190
+ status
191
+ })};`
192
+ },
193
+ {
194
+ tag: "script",
195
+ injectTo: "body-prepend",
196
+ children: bundle
197
+ }
198
+ ];
199
+ }
200
+ };
201
+ };
202
+ //#endregion
203
+ //#region src/vite-plugin/load.ts
204
+ var CONFIG_BASENAMES = [
205
+ "dx.config.ts",
206
+ "dx.config.mjs",
207
+ "dx.config.js"
208
+ ];
209
+ var decodeConfig2 = Schema.decodeUnknownSync(Config2.Config);
210
+ /**
211
+ * Resolves the first `dx.config.{ts,mjs,js}` found under `dir`, or `undefined` if none exist.
212
+ * Pass the result to {@link loadDxConfig}.
213
+ */
214
+ var findDxConfigFile = (dir) => CONFIG_BASENAMES.map((basename) => join(dir, basename)).find((candidate) => existsSync(candidate));
215
+ /**
216
+ * Loads and validates a `dx.config.ts` (or `.mjs`/`.js`) file at the given `filePath`.
217
+ *
218
+ * Transpiles the file with esbuild — leaving its bare imports (`@dxos/protocols`, `@dxos/app-framework`, …)
219
+ * external so they resolve from the project's `node_modules` — imports the result, then decodes the
220
+ * default export against the `Config2` schema (a malformed config throws a `Schema` parse error).
221
+ * Node-only (esbuild + filesystem); used by `composerPlugin` and `dx registry publish`.
222
+ */
223
+ var loadDxConfig = async (filePath) => {
224
+ const result = await build({
225
+ entryPoints: [filePath],
226
+ bundle: true,
227
+ format: "esm",
228
+ platform: "node",
229
+ write: false,
230
+ packages: "external",
231
+ logLevel: "silent"
232
+ });
233
+ const tempPath = join(filePath, "..", `.dx.config.${randomUUID()}.mjs`);
234
+ try {
235
+ await writeFile(tempPath, result.outputFiles[0].text, "utf-8");
236
+ return decodeConfig2((await import(pathToFileURL(tempPath).href)).default);
237
+ } finally {
238
+ await rm(tempPath, { force: true });
239
+ }
240
+ };
241
+ //#endregion
242
+ //#region src/vite-plugin/manifest.ts
243
+ /**
244
+ * Name of the asset written alongside the built module bundle.
245
+ * The DXOS community registry resolves each published plugin by fetching this file
246
+ * from the repo's latest GitHub Release, so authors should not rename it.
247
+ */
248
+ var MANIFEST_ASSET_NAME = "manifest.json";
249
+ /**
250
+ * Canonical entry filename (re-exported from `@dxos/protocols`) so vite-plugin
251
+ * consumers don't have to reach into the protocols package directly.
252
+ */
253
+ var ENTRY_FILENAME = PLUGIN_ENTRY_FILENAME;
254
+ /**
255
+ * Flattens a runtime {@link Plugin.Meta}'s `profile` and augments it with the build-time fields
256
+ * needed to emit `manifest.json`: the package `version` (from the publishing project's `package.json`)
257
+ * and an optional resolved `dependencies` snapshot. Produces the {@link BuildMeta} that `composerPlugin`
258
+ * serializes.
259
+ */
260
+ var toBuildMeta = (meta, version, dependencies) => ({
261
+ ...meta.profile,
262
+ version,
263
+ ...dependencies ? { dependencies } : {}
264
+ });
265
+ /**
266
+ * Serializes a plugin's public metadata + bundle layout into the format consumed
267
+ * by the host loader (see `UrlLoader.make` and `PluginManifest.parse`).
268
+ *
269
+ * The host fetches this manifest, resolves every entry in `assets` against the
270
+ * manifest URL, and persists them via the platform `PluginAssetCache` so the
271
+ * plugin works offline. For production builds the entry module is always
272
+ * {@link ENTRY_FILENAME} and must appear in `assets`. For dev-server manifests
273
+ * pass `devEntry` (a path relative to the manifest URL) — the host then imports
274
+ * the entry directly from the dev server and skips offline caching, since the
275
+ * full asset graph isn't enumerable until build time.
276
+ *
277
+ * Exported from a vite-free module so tests and tooling can validate manifests
278
+ * without paying the cost of loading vite + esbuild.
279
+ */
280
+ var serializeManifest = (meta, { assets, devEntry }) => {
281
+ return JSON.stringify({
282
+ ...meta,
283
+ assets,
284
+ ...devEntry !== void 0 ? { devEntry } : {}
285
+ }, null, 2);
286
+ };
287
+ var DEFAULT_PACKAGES = [
288
+ "@dxos/async",
289
+ "@dxos/codec-protobuf",
290
+ "@dxos/context",
291
+ "@dxos/crypto",
292
+ "@dxos/debug",
293
+ "@dxos/display-name",
294
+ "@dxos/effect",
295
+ "@dxos/effect-atom-solid",
296
+ "@dxos/errors",
297
+ "@dxos/feed-store",
298
+ "@dxos/graph",
299
+ "@dxos/hypercore",
300
+ "@dxos/invariant",
301
+ "@dxos/keyboard",
302
+ "@dxos/keys",
303
+ "@dxos/kv-store",
304
+ "@dxos/log",
305
+ "@dxos/merkle-search-tree",
306
+ "@dxos/random",
307
+ "@dxos/random-access-storage",
308
+ "@dxos/timeframe",
309
+ "@dxos/tracing",
310
+ "@dxos/util",
311
+ "@dxos/web-context",
312
+ "@dxos/web-context-react",
313
+ "@dxos/web-context-solid",
314
+ "@dxos/echo",
315
+ "@dxos/echo-client",
316
+ "@dxos/echo-host",
317
+ "@dxos/echo-protocol",
318
+ "@dxos/echo-query",
319
+ "@dxos/echo-react",
320
+ "@dxos/echo-solid",
321
+ "@dxos/feed",
322
+ "@dxos/index-core",
323
+ "@dxos/credentials",
324
+ "@dxos/keyring",
325
+ "@dxos/edge-client",
326
+ "@dxos/messaging",
327
+ "@dxos/network-manager",
328
+ "@dxos/rpc",
329
+ "@dxos/rpc-tunnel",
330
+ "@dxos/teleport",
331
+ "@dxos/teleport-extension-automerge-replicator",
332
+ "@dxos/teleport-extension-gossip",
333
+ "@dxos/teleport-extension-object-sync",
334
+ "@dxos/teleport-extension-replicator",
335
+ "@dxos/websocket-rpc",
336
+ "@dxos/ai",
337
+ "@dxos/assistant",
338
+ "@dxos/assistant-toolkit",
339
+ "@dxos/compute",
340
+ "@dxos/conductor",
341
+ "@dxos/functions",
342
+ "@dxos/functions-runtime",
343
+ "@dxos/mcp-client",
344
+ "@dxos/operation",
345
+ "@dxos/protocols",
346
+ "@dxos/devtools",
347
+ "@dxos/app-framework",
348
+ "@dxos/app-graph",
349
+ "@dxos/app-solid",
350
+ "@dxos/app-toolkit",
351
+ "@dxos/client",
352
+ "@dxos/client-protocol",
353
+ "@dxos/client-services",
354
+ "@dxos/config",
355
+ "@dxos/migrations",
356
+ "@dxos/observability",
357
+ "@dxos/react-client",
358
+ "@dxos/react-edge-client",
359
+ "@dxos/schema",
360
+ "@dxos/types",
361
+ "@dxos/lit-grid",
362
+ "@dxos/lit-ui",
363
+ "@dxos/react-hooks",
364
+ "@dxos/react-ui",
365
+ "@dxos/react-ui-attention",
366
+ "@dxos/react-ui-audio",
367
+ "@dxos/react-ui-board",
368
+ "@dxos/react-ui-calendar",
369
+ "@dxos/react-ui-canvas",
370
+ "@dxos/react-ui-canvas-compute",
371
+ "@dxos/react-ui-canvas-editor",
372
+ "@dxos/react-ui-chat",
373
+ "@dxos/react-ui-components",
374
+ "@dxos/react-ui-dnd",
375
+ "@dxos/react-ui-editor",
376
+ "@dxos/react-ui-experimental",
377
+ "@dxos/react-ui-form",
378
+ "@dxos/react-ui-gameboard",
379
+ "@dxos/react-ui-geo",
380
+ "@dxos/react-ui-graph",
381
+ "@dxos/react-ui-grid",
382
+ "@dxos/react-ui-list",
383
+ "@dxos/react-ui-markdown",
384
+ "@dxos/react-ui-masonry",
385
+ "@dxos/react-ui-menu",
386
+ "@dxos/react-ui-mosaic",
387
+ "@dxos/react-ui-pickers",
388
+ "@dxos/react-ui-list",
389
+ "@dxos/react-ui-syntax-highlighter",
390
+ "@dxos/react-ui-table",
391
+ "@dxos/react-ui-tabs",
392
+ "@dxos/react-ui-thread",
393
+ "@dxos/solid-ui",
394
+ "@dxos/solid-ui-geo",
395
+ "@dxos/ui",
396
+ "@dxos/ui-editor",
397
+ "@dxos/ui-theme",
398
+ "@dxos/ui-types",
399
+ ...[
400
+ "@effect-atom/atom",
401
+ "@effect-atom/atom-react",
402
+ "@effect/platform",
403
+ "effect",
404
+ "lit",
405
+ "react",
406
+ "react-dom",
407
+ "solid-js"
408
+ ]
409
+ ];
410
+ /**
411
+ * True when the given bare specifier (or one of its subpaths) is provided by the
412
+ * Composer host at runtime and must not be re-bundled by a plugin.
413
+ *
414
+ * Matches only packages listed in {@link DEFAULT_PACKAGES} — the same list
415
+ * {@link importMapPlugin} consumes — so externalization cannot claim a package
416
+ * the host isn't actually mapping. Unknown `@dxos/*` packages fall through to
417
+ * normal bundling, which is the correct default for plugin-owned or yet-to-be
418
+ * shared workspace packages.
419
+ */
420
+ var isSharedPackage = (id) => DEFAULT_PACKAGES.some((pkg) => id === pkg || id.startsWith(`${pkg}/`));
421
+ //#endregion
422
+ //#region src/vite-plugin/composer/index.ts
423
+ var JSX_DEV_RUNTIME = "react/jsx-dev-runtime";
424
+ /** Reads `version` from the project's `package.json`; falls back to `0.0.0`. */
425
+ var readPackageVersion = (dir) => {
426
+ try {
427
+ return JSON.parse(readFileSync(join(dir, "package.json"), "utf-8")).version ?? "0.0.0";
428
+ } catch {
429
+ return "0.0.0";
430
+ }
431
+ };
432
+ /**
433
+ * Snapshot the project's declared `dependencies`, resolving each to its concrete
434
+ * installed version (read from `node_modules/<name>/package.json`) so the manifest
435
+ * records exactly what the plugin was built against — the host derives SDK
436
+ * compatibility from the `@dxos/*` subset. Falls back to the declared spec when a
437
+ * dependency can't be resolved on disk.
438
+ */
439
+ var readResolvedDependencies = (dir) => {
440
+ try {
441
+ const declared = JSON.parse(readFileSync(join(dir, "package.json"), "utf-8")).dependencies;
442
+ if (!declared) return;
443
+ const resolved = {};
444
+ for (const name of Object.keys(declared)) try {
445
+ const version = JSON.parse(readFileSync(join(dir, "node_modules", name, "package.json"), "utf-8")).version;
446
+ resolved[name] = typeof version === "string" ? version : declared[name];
447
+ } catch {
448
+ resolved[name] = declared[name];
449
+ }
450
+ return Object.keys(resolved).length > 0 ? resolved : void 0;
451
+ } catch {
452
+ return;
453
+ }
454
+ };
455
+ /**
456
+ * Whether an import should be externalized by the plugin bundle.
457
+ * Uses the shared-package predicate directly so plugins automatically pick up any
458
+ * new `@dxos/*` (non-plugin) package the host provides, without a code change here.
459
+ */
460
+ var isExternal = (id) => id !== JSX_DEV_RUNTIME && isSharedPackage(id);
461
+ /**
462
+ * Banner injected at the top of every plugin bundle.
463
+ *
464
+ * Why: rolldown emits ESM `import` for externalized deps, but when a *bundled* module
465
+ * is CJS and contains `require('react')` (or any other external), rolldown keeps the
466
+ * `require(...)` call in the output and relies on a runtime `require` function. The
467
+ * browser doesn't have `require`, so rolldown's fallback shim throws:
468
+ * `Calling `require` for "react" in an environment that doesn't expose the `require`
469
+ * function`.
470
+ *
471
+ * The full dependency graphs of non-trivial plugins unavoidably drag in CJS-only
472
+ * helpers (`use-sync-external-store` via xstate / zustand / preact-signals / … ),
473
+ * and waiting for every one of those packages to ship ESM isn't realistic. Instead
474
+ * we install a tiny module-local `require` at the top of the bundle that looks up
475
+ * a handful of well-known host-provided modules by name and returns their already
476
+ * ESM-imported namespaces. Rolldown's own shim honours an existing `require`
477
+ * before falling through to the throw path, so this entirely removes the runtime
478
+ * error without changing how externalization itself works.
479
+ *
480
+ * Keep the list aligned with the externals that CJS code actually reaches for;
481
+ * adding entries here is safe (unused imports get tree-shaken), but the list is
482
+ * deliberately small to keep the banner noise-free.
483
+ */
484
+ var REQUIRE_SHIM_BANNER = [
485
+ "// --- composer-plugin: CJS require shim ---",
486
+ "// See @dxos/app-framework/vite-plugin/composer-plugin.ts for rationale.",
487
+ "import * as __composerReact from 'react';",
488
+ "import * as __composerReactDom from 'react-dom';",
489
+ "import * as __composerReactJsxRuntime from 'react/jsx-runtime';",
490
+ "const __composerRequireShim = new Map([",
491
+ " ['react', __composerReact.default ?? __composerReact],",
492
+ " ['react-dom', __composerReactDom.default ?? __composerReactDom],",
493
+ " ['react/jsx-runtime', __composerReactJsxRuntime],",
494
+ "]);",
495
+ "// Module-local binding: rolldown's CJS fallback does a `typeof require` check",
496
+ "// and uses whichever `require` is in lexical scope. Declaring this as `const`",
497
+ "// (instead of `globalThis.require ??=`) keeps each bundle's shim isolated from",
498
+ "// the host page and from other plugins sharing the window.",
499
+ "const require = (id) => {",
500
+ " if (__composerRequireShim.has(id)) return __composerRequireShim.get(id);",
501
+ " throw new Error('composer-plugin: unsupported CJS require at runtime: ' + id);",
502
+ "};",
503
+ "// --- end CJS require shim ---"
504
+ ].join("\n");
505
+ /**
506
+ * Vite plugin for **external Composer plugin projects**. Configures the build to produce
507
+ * an ESM bundle that externalizes all framework dependencies, which the Composer host app
508
+ * provides at runtime via import map.
509
+ *
510
+ * Handles:
511
+ * 1. Build config — lib mode entry point, ES format output, rollup externals, code-split chunks.
512
+ * 2. Dev externalization — marks shared deps as external during `vite serve` and strips
513
+ * the `/@id/` prefix that Vite's import analysis adds to external bare specifiers.
514
+ * 3. JSX dev runtime shim — bridges `react/jsx-dev-runtime` (used by React refresh in dev)
515
+ * to `react/jsx-runtime` (which is what the externalized React provides).
516
+ * 4. Manifest emit — when `meta` is supplied, writes `manifest.json` next to the bundled
517
+ * module listing every emitted asset (entry, CSS, chunks, etc.) so the host can eagerly
518
+ * cache them for offline use.
519
+ */
520
+ var composerPlugin = (options) => {
521
+ const entry = options?.entry ?? "src/plugin.tsx";
522
+ const port = options?.port ?? 3967;
523
+ const projectRoot = process.cwd();
524
+ const metaPromise = options?.meta ? Promise.resolve(options.meta) : Promise.resolve(options?.config ?? findDxConfigFile(projectRoot)).then((configFile) => configFile ? loadDxConfig(configFile).then((config) => toBuildMeta(getMetaFromConfig(config), readPackageVersion(projectRoot), readResolvedDependencies(projectRoot))) : void 0);
525
+ const resolved = /* @__PURE__ */ new Set();
526
+ let base = "/";
527
+ const plugins = [
528
+ {
529
+ name: "composer-plugin",
530
+ config: () => ({
531
+ server: {
532
+ port,
533
+ cors: true
534
+ },
535
+ preview: { port },
536
+ build: {
537
+ sourcemap: true,
538
+ target: "esnext",
539
+ lib: {
540
+ entry,
541
+ formats: ["es"],
542
+ fileName: () => ENTRY_FILENAME
543
+ },
544
+ rolldownOptions: {
545
+ external: (id) => isExternal(id),
546
+ output: {
547
+ chunkFileNames: "chunks/[name]-[hash].js",
548
+ assetFileNames: "assets/[name]-[hash][extname]",
549
+ banner: REQUIRE_SHIM_BANNER
550
+ }
551
+ }
552
+ }
553
+ })
554
+ },
555
+ {
556
+ name: "composer-plugin:externalize",
557
+ enforce: "pre",
558
+ apply: "serve",
559
+ config: () => ({ optimizeDeps: { exclude: DEFAULT_PACKAGES } }),
560
+ resolveId: (id) => {
561
+ if (isExternal(id)) {
562
+ resolved.add(id);
563
+ return {
564
+ id,
565
+ external: true
566
+ };
567
+ }
568
+ },
569
+ load: (id) => {
570
+ if (resolved.has(id)) return { code: "export default {};" };
571
+ },
572
+ configResolved: (config) => {
573
+ base = config.base ?? "/";
574
+ config.plugins.push({
575
+ name: "composer-plugin:strip-prefix",
576
+ transform: (code) => {
577
+ if (resolved.size === 0) return;
578
+ const escaped = [...resolved].map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
579
+ const pattern = new RegExp(`${base}@id/(${escaped})`, "g");
580
+ if (pattern.test(code)) return code.replace(pattern, (_, dep) => dep);
581
+ }
582
+ });
583
+ }
584
+ },
585
+ {
586
+ name: "composer-plugin:jsx-dev-shim",
587
+ enforce: "pre",
588
+ apply: "serve",
589
+ resolveId: (id) => id === JSX_DEV_RUNTIME ? `\0${JSX_DEV_RUNTIME}` : void 0,
590
+ load: (id) => id === `\0${JSX_DEV_RUNTIME}` ? [
591
+ "import { jsx, jsxs, Fragment } from \"react/jsx-runtime\";",
592
+ "export { Fragment };",
593
+ "export function jsxDEV(type, props, key, isStaticChildren) {",
594
+ " return isStaticChildren ? jsxs(type, props, key) : jsx(type, props, key);",
595
+ "}"
596
+ ].join("\n") : void 0
597
+ },
598
+ (
599
+ // @vitejs/plugin-react's JSX transform prepends a runtime check to every module:
600
+ {
601
+ name: "composer-plugin:react-refresh-shim",
602
+ enforce: "pre",
603
+ apply: "serve",
604
+ transform(code, id) {
605
+ if (!id.endsWith(entry.replace(/^\.?\//, "/"))) return;
606
+ return {
607
+ code: [
608
+ "// composer-plugin: no-op React Refresh shim so cross-origin plugin modules",
609
+ "// don't throw the @vitejs/plugin-react preamble check at dynamic-import time.",
610
+ "if (typeof window !== \"undefined\") {",
611
+ " window.$RefreshReg$ = window.$RefreshReg$ || (() => {});",
612
+ " window.$RefreshSig$ = window.$RefreshSig$ || (() => (type) => type);",
613
+ " window.__vite_plugin_react_preamble_installed__ = true;",
614
+ "}",
615
+ ""
616
+ ].join("\n") + code,
617
+ map: null
618
+ };
619
+ }
620
+ })
621
+ ];
622
+ plugins.push({
623
+ name: "composer-plugin:emit-manifest",
624
+ apply: "build",
625
+ enforce: "post",
626
+ async generateBundle(_options, bundle) {
627
+ const meta = await metaPromise;
628
+ if (!meta) return;
629
+ const assets = Object.keys(bundle).filter((name) => name !== "manifest.json" && !name.endsWith(".map")).sort();
630
+ this.emitFile({
631
+ type: "asset",
632
+ fileName: MANIFEST_ASSET_NAME,
633
+ source: serializeManifest(meta, { assets })
634
+ });
635
+ }
636
+ });
637
+ plugins.push({
638
+ name: "composer-plugin:serve-manifest",
639
+ apply: "serve",
640
+ async configureServer(server) {
641
+ const meta = await metaPromise;
642
+ if (!meta) return;
643
+ const body = serializeManifest(meta, {
644
+ assets: [],
645
+ devEntry: entry.replace(/^\.?\//, "")
646
+ });
647
+ server.middlewares.use(`/${MANIFEST_ASSET_NAME}`, (req, res, next) => {
648
+ if (req.url && req.url !== "/" && req.url !== "") return next();
649
+ res.setHeader("Access-Control-Allow-Origin", "*");
650
+ res.setHeader("Content-Type", "application/json");
651
+ res.setHeader("Cache-Control", "no-store");
652
+ res.statusCode = 200;
653
+ res.end(body);
654
+ });
655
+ }
656
+ });
657
+ return plugins;
658
+ };
659
+ //#endregion
660
+ //#region src/vite-plugin/import-map/index.ts
661
+ var require = createRequire(import.meta.url);
662
+ /** Strips vite query strings (e.g. `?v=123`) from resolved module IDs. */
663
+ var trimQueryString = (id) => id.replace(/\?.*$/, "");
664
+ /**
665
+ * Determines whether a resolved file is an ESM module by checking file extension
666
+ * first (.mjs/.cjs), then walking up to the nearest package.json for `"type": "module"`.
667
+ */
668
+ var resolvedIdIsEsmModule = (resolvedId) => {
669
+ const file = trimQueryString(resolvedId);
670
+ if (file.endsWith(".mjs") || file.endsWith(".mts")) return true;
671
+ if (file.endsWith(".cjs") || file.endsWith(".cts")) return false;
672
+ let directory = path.dirname(file);
673
+ while (directory !== path.dirname(directory)) {
674
+ const packageJsonPath = path.join(directory, "package.json");
675
+ if (existsSync(packageJsonPath)) try {
676
+ return JSON.parse(readFileSync(packageJsonPath, "utf8")).type === "module";
677
+ } catch {
678
+ return false;
679
+ }
680
+ directory = path.dirname(directory);
681
+ }
682
+ return false;
683
+ };
684
+ /**
685
+ * Walks up from a resolved file path to find the package.json whose `"name"` matches
686
+ * the given package name. Returns the path to that package.json, or undefined.
687
+ */
688
+ var findPackageJsonPath = (resolvedId, packageName) => {
689
+ let directory = path.dirname(trimQueryString(resolvedId));
690
+ while (directory !== path.dirname(directory)) {
691
+ const packageJsonPath = path.join(directory, "package.json");
692
+ if (existsSync(packageJsonPath)) try {
693
+ if (JSON.parse(readFileSync(packageJsonPath, "utf8")).name === packageName) return packageJsonPath;
694
+ } catch {}
695
+ directory = path.dirname(directory);
696
+ }
697
+ };
698
+ /** Resolves a package name to its package.json path using Node's require.resolve. */
699
+ var resolvePackageJsonPath = (packageName) => {
700
+ try {
701
+ return findPackageJsonPath(require.resolve(packageName), packageName);
702
+ } catch {
703
+ return;
704
+ }
705
+ };
706
+ /**
707
+ * Resolves a package name to its package.json via vite's own resolver, which handles
708
+ * workspace-linked packages whose `exports` field omits `./package.json` (so
709
+ * `require.resolve` can't find it). Falls back to `require.resolve`.
710
+ */
711
+ var resolvePackageJsonPathViaContext = async (ctx, packageName) => {
712
+ try {
713
+ const resolved = await ctx.resolve(packageName);
714
+ if (resolved) {
715
+ const viaResolved = findPackageJsonPath(resolved.id, packageName);
716
+ if (viaResolved) return viaResolved;
717
+ }
718
+ } catch {}
719
+ return resolvePackageJsonPath(packageName);
720
+ };
721
+ /**
722
+ * Subpath exports that should be excluded from the import map.
723
+ * These are node-only entrypoints (vite plugins, native addons) that shouldn't be pre-bundled for the browser.
724
+ *
725
+ * TODO(wittjosiah): Replace these hand-maintained lists (plus {@link GLOBALLY_EXCLUDED_SUBPATHS}
726
+ * and {@link BUILD_TOOL_SUBPATH}) with a structural check — e.g. honour an `agent`/`node`-only
727
+ * export condition in package.json, or probe each subpath's resolved file for `node:*` imports
728
+ * at build time — so every new server-only entrypoint doesn't require a code change here.
729
+ */
730
+ var importMapExcludedSubpaths = {
731
+ "@dxos/app-framework": /* @__PURE__ */ new Set(["vite-plugin"]),
732
+ "@dxos/lit-grid": /* @__PURE__ */ new Set(["testing"]),
733
+ "@dxos/react-ui-mosaic": /* @__PURE__ */ new Set(["playwright"]),
734
+ "@dxos/react-ui-table": /* @__PURE__ */ new Set(["playwright"]),
735
+ "@dxos/ui-theme": /* @__PURE__ */ new Set(["plugin"]),
736
+ "solid-js": /* @__PURE__ */ new Set(["web/storage"]),
737
+ "effect": /* @__PURE__ */ new Set([".index"])
738
+ };
739
+ /**
740
+ * Subpaths common to many packages that should always be excluded.
741
+ * `./playwright` subdirectories house e2e test harnesses that pull in
742
+ * `@playwright/test` (a node-only package that breaks the browser bundle).
743
+ * `./testing` subpaths similarly expose node-only test helpers (e.g.
744
+ * `@dxos/edge-client/testing` pulls `@dxos/node-std/http` which has no
745
+ * browser analogue) and aren't part of the plugin-facing surface.
746
+ */
747
+ var GLOBALLY_EXCLUDED_SUBPATHS = /* @__PURE__ */ new Set(["playwright", "testing"]);
748
+ /**
749
+ * Regex for subpaths that are always node-only build tooling — vite, esbuild, and
750
+ * rollup plugins. These use `node:*` imports and will blow up the browser bundle if
751
+ * they end up in the import map.
752
+ */
753
+ var BUILD_TOOL_SUBPATH = /^(vite-plugin|esbuild-plugin|rollup-plugin|plugin)$/;
754
+ /**
755
+ * Asset subpaths (CSS, PCSS, images, etc.) that the host already loads via its own
756
+ * bundle — for example `@dxos/react-ui-form` pulls in `@dxos/lit-ui/dx-tag-picker.pcss`
757
+ * on startup, so the stylesheet is already attached to the DOM by the time a remote
758
+ * plugin runs. Community plugins should still be able to _import_ those specifiers
759
+ * (rolldown leaves the `import "…"` statements in the output when the package is
760
+ * externalized), so the import map maps them to a no-op empty ES module. The
761
+ * resulting browser fetch is a cheap no-op; the styles are never re-downloaded
762
+ * and never re-injected.
763
+ */
764
+ var ASSET_SUBPATH = /\.(css|pcss|scss|sass|less|json|node|wasm|html|svg|png|jpe?g|gif|webp|ico)$/;
765
+ var isAssetSubpath = (specifier) => ASSET_SUBPATH.test(specifier);
766
+ /**
767
+ * Walks `baseDir` and returns every file that matches the pattern `${baseDir}/<rest>${extension}`.
768
+ * Used to expand wildcard exports like `./proto/*` → `./dist/src/proto/gen/*.js` into their
769
+ * full set of bare specifiers.
770
+ */
771
+ var walkDirectoryForExtension = (baseDir, extension) => {
772
+ if (!existsSync(baseDir)) return [];
773
+ const results = [];
774
+ const walk = (dir) => {
775
+ let entries;
776
+ try {
777
+ entries = readdirSync(dir);
778
+ } catch {
779
+ return;
780
+ }
781
+ for (const entry of entries) {
782
+ const full = path.join(dir, entry);
783
+ let stat;
784
+ try {
785
+ stat = statSync(full);
786
+ } catch {
787
+ continue;
788
+ }
789
+ if (stat.isDirectory()) walk(full);
790
+ else if (entry.endsWith(extension)) results.push(path.relative(baseDir, full).slice(0, -extension.length));
791
+ }
792
+ };
793
+ walk(baseDir);
794
+ return results;
795
+ };
796
+ /** Resolves an `exports` value to a single target path for pattern expansion. */
797
+ var pickPatternTarget = (value) => {
798
+ if (typeof value === "string") return value;
799
+ if (value && typeof value === "object") {
800
+ const obj = value;
801
+ const preferred = obj.browser ?? obj.import ?? obj.default ?? obj.module;
802
+ return typeof preferred === "string" ? preferred : void 0;
803
+ }
804
+ };
805
+ /**
806
+ * Expands a wildcard export like `./proto/*` into concrete subpath specifiers by walking
807
+ * the target directory. Returns `<packageName>/<subpath>` strings.
808
+ */
809
+ var expandWildcardExport = (packageName, packageJsonDir, exportKey, exportValue) => {
810
+ const target = pickPatternTarget(exportValue);
811
+ if (!target || !target.includes("*")) return [];
812
+ const keyStarIndex = exportKey.indexOf("*");
813
+ const targetStarIndex = target.indexOf("*");
814
+ if (keyStarIndex === -1 || targetStarIndex === -1) return [];
815
+ const keyPrefix = exportKey.slice(2, keyStarIndex);
816
+ const targetPrefix = target.slice(2, targetStarIndex);
817
+ const targetSuffix = target.slice(targetStarIndex + 1);
818
+ return walkDirectoryForExtension(path.resolve(packageJsonDir, targetPrefix), targetSuffix || ".js").map((relativeNoExt) => `${packageName}/${keyPrefix}${relativeNoExt}`);
819
+ };
820
+ /**
821
+ * Reads a package's `exports` field and returns all subpath entrypoints as bare specifiers
822
+ * (e.g. `@dxos/client`, `@dxos/client/echo`, `@dxos/lit-ui/dx-tag-picker.pcss`,
823
+ * `@dxos/protocols/proto/dxos/echo/metadata`). Wildcard patterns are expanded by walking
824
+ * the corresponding output directory. Falls back to just the package name if exports is
825
+ * absent or simple.
826
+ */
827
+ var getPackageEntrypoints = (packageName, packageJsonPath) => {
828
+ const exportsField = JSON.parse(readFileSync(packageJsonPath, "utf8")).exports;
829
+ if (!exportsField || typeof exportsField === "string" || Array.isArray(exportsField)) return [packageName];
830
+ const exportKeys = Object.keys(exportsField);
831
+ if (!exportKeys.some((key) => key.startsWith("."))) return [packageName];
832
+ const excluded = importMapExcludedSubpaths[packageName];
833
+ const packageJsonDir = path.dirname(packageJsonPath);
834
+ const modules = exportKeys.flatMap((key) => {
835
+ if (key === ".") return [packageName];
836
+ if (!key.startsWith("./") || key === "./package.json") return [];
837
+ if (key.endsWith(".d.ts")) return [];
838
+ if (key.includes("*")) return expandWildcardExport(packageName, packageJsonDir, key, exportsField[key]);
839
+ const subpath = key.slice(2);
840
+ if (excluded?.has(subpath) || GLOBALLY_EXCLUDED_SUBPATHS.has(subpath) || BUILD_TOOL_SUBPATH.test(subpath)) return [];
841
+ return [`${packageName}/${subpath}`];
842
+ });
843
+ return modules.length > 0 ? modules : [packageName];
844
+ };
845
+ /**
846
+ * Statically analyzes a CJS file to extract named exports using cjs-module-lexer.
847
+ * Follows re-exports (e.g. react's index.js re-exports from cjs/react.development.js)
848
+ * and deduplicates. Filters out `default` and `__esModule` pseudo-exports.
849
+ */
850
+ var getCjsNamedExports = (filePath, seen = /* @__PURE__ */ new Set()) => {
851
+ const normalized = trimQueryString(filePath);
852
+ if (seen.has(normalized)) return [];
853
+ seen.add(normalized);
854
+ try {
855
+ const { exports: directExports, reexports } = parse(readFileSync(normalized, "utf8"));
856
+ const reexportedNames = reexports.flatMap((reexport) => {
857
+ const resolved = path.resolve(path.dirname(normalized), reexport);
858
+ const found = [
859
+ resolved,
860
+ `${resolved}.js`,
861
+ `${resolved}.cjs`
862
+ ].find((candidate) => existsSync(candidate));
863
+ return found ? getCjsNamedExports(found, seen) : [];
864
+ });
865
+ return [.../* @__PURE__ */ new Set([...directExports, ...reexportedNames])].filter((name) => name !== "default" && name !== "__esModule");
866
+ } catch {
867
+ return [];
868
+ }
869
+ };
870
+ /**
871
+ * Vite plugin for the **host app** (Composer). Generates a browser import map so that
872
+ * shared packages are loaded once and reused by both the host and any remote plugins.
873
+ *
874
+ * In production, emits a dedicated chunk per specifier via virtual wrapper modules,
875
+ * then injects a `<script type="importmap">` tag into the HTML with the chunk URLs.
876
+ *
877
+ * Virtual wrappers are needed because directly emitting chunks for CJS packages loses
878
+ * their named exports due to Rollup's interop. The wrapper re-exports them explicitly.
879
+ *
880
+ * TODO: Restore dev-mode support. The previous dev path mapped each bare specifier to
881
+ * its absolute `/@fs/` file path during `buildStart`, which forced `this.resolve()` for
882
+ * hundreds of subpath entrypoints and raced with Vite's optimize-deps static scan —
883
+ * producing non-deterministic chunk content (~34 chunks drifting per warm-start) and
884
+ * triggering Vite 8.0.10's `runOptimizer` / `commitProcessing` crashes (`fileHash` /
885
+ * `browserHash` undefined on partial-discovery batches). Plugin is currently gated to
886
+ * `apply: 'build'` to avoid both. A working dev-mode implementation would need to
887
+ * resolve specifiers without participating in the optimize-deps phase — candidates:
888
+ * - defer resolution to `transformIndexHtml` (after the optimizer settles)
889
+ * - read resolved paths from `environment.depsOptimizer.metadata` rather than calling
890
+ * `this.resolve()` ourselves
891
+ * - resolve via `require.resolve` directly, bypassing the Vite plugin pipeline entirely
892
+ */
893
+ var importMapPlugin = (options) => {
894
+ const packages = options?.packages ?? DEFAULT_PACKAGES;
895
+ const WRAPPER_PREFIX = "\0import-map:";
896
+ const chunkRefIds = {};
897
+ const resolvedIds = {};
898
+ let imports = {};
899
+ let modules = [];
900
+ let importMapIsDev = false;
901
+ let base = "/";
902
+ let root = process.cwd();
903
+ return [{
904
+ name: "import-map:get-chunk-ref-ids",
905
+ apply: "build",
906
+ configResolved(config) {
907
+ base = config.base ?? "/";
908
+ root = config.root;
909
+ },
910
+ async buildStart() {
911
+ importMapIsDev = this.environment.mode === "dev";
912
+ await init();
913
+ modules = [...new Set((await Promise.all(packages.map(async (packageName) => {
914
+ const packageJsonPath = await resolvePackageJsonPathViaContext(this, packageName);
915
+ if (!packageJsonPath) {
916
+ this.warn(`Unable to locate package.json for import map package: ${packageName}`);
917
+ return [packageName];
918
+ }
919
+ return getPackageEntrypoints(packageName, packageJsonPath);
920
+ }))).flat())];
921
+ for (const specifier of modules) {
922
+ if (isAssetSubpath(specifier)) {
923
+ imports[specifier] = "data:text/javascript;charset=utf-8,export%20%7B%7D%3B";
924
+ continue;
925
+ }
926
+ const resolved = await this.resolve(specifier, path.join(root, "index.html"));
927
+ if (!resolved) {
928
+ this.warn(`Import map: unable to resolve "${specifier}"; omitting from import map.`);
929
+ continue;
930
+ }
931
+ if (importMapIsDev) {
932
+ const filePath = trimQueryString(resolved.id);
933
+ imports[specifier] = filePath.startsWith("/") ? `/@fs${filePath}` : filePath;
934
+ } else {
935
+ resolvedIds[specifier] = resolved.id;
936
+ chunkRefIds[specifier] = this.emitFile({
937
+ type: "chunk",
938
+ id: `${WRAPPER_PREFIX}${specifier}`,
939
+ preserveSignature: "strict"
940
+ });
941
+ }
942
+ }
943
+ },
944
+ resolveId(id) {
945
+ if (id.startsWith(WRAPPER_PREFIX)) return id;
946
+ },
947
+ load(id) {
948
+ if (!id.startsWith(WRAPPER_PREFIX)) return;
949
+ const specifier = id.slice(12);
950
+ const keepalive = `export const __dxosImportMapKeepalive = ${JSON.stringify(specifier)};`;
951
+ const resolvedId = resolvedIds[specifier];
952
+ if (!resolvedId) return `export * from ${JSON.stringify(specifier)};\n${keepalive}\n`;
953
+ const filePath = trimQueryString(resolvedId);
954
+ if (filePath.endsWith(".cjs") || !filePath.endsWith(".mjs") && !resolvedIdIsEsmModule(filePath)) {
955
+ const named = getCjsNamedExports(filePath);
956
+ if (named.length > 0) return `export { default, ${named.join(", ")} } from ${JSON.stringify(filePath)};\n${keepalive}\n`;
957
+ }
958
+ return `export * from ${JSON.stringify(filePath)};\n${keepalive}\n`;
959
+ },
960
+ generateBundle() {
961
+ if (importMapIsDev) return;
962
+ imports = {
963
+ ...imports,
964
+ ...Object.fromEntries(modules.filter((specifier) => chunkRefIds[specifier] !== void 0).map((specifier) => [specifier, `${base}${this.getFileName(chunkRefIds[specifier])}`]))
965
+ };
966
+ }
967
+ }, {
968
+ name: "import-map:transform-index-html",
969
+ apply: "build",
970
+ enforce: "post",
971
+ transformIndexHtml(html) {
972
+ return {
973
+ html,
974
+ tags: [{
975
+ tag: "script",
976
+ attrs: { type: "importmap" },
977
+ children: JSON.stringify({ imports }, null, 2)
978
+ }]
979
+ };
980
+ }
981
+ }];
982
+ };
983
+ //#endregion
984
+ export { DEFAULT_PACKAGES, ENTRY_FILENAME, MANIFEST_ASSET_NAME, bootLoaderPlugin, composerPlugin, findDxConfigFile, importMapPlugin, isSharedPackage, loadDxConfig, serializeManifest };
985
+
986
+ //# sourceMappingURL=vite-plugin.mjs.map