@dxos/app-framework 0.9.0 → 0.9.1-staging.ee54ba693a

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 (224) hide show
  1. package/dist/lib/browser/{capability-BOPAKKWG.mjs → capability-S44TE2H7.mjs} +9 -9
  2. package/dist/lib/browser/{chunk-66IXTIVK.mjs → chunk-3NQLTQCP.mjs} +6 -7
  3. package/dist/lib/browser/chunk-3NQLTQCP.mjs.map +7 -0
  4. package/dist/lib/browser/chunk-53HJHMS5.mjs +7 -0
  5. package/dist/lib/browser/chunk-53HJHMS5.mjs.map +7 -0
  6. package/dist/lib/browser/{chunk-Y66ELD4U.mjs → chunk-KRJ4KK2W.mjs} +36 -7
  7. package/dist/lib/browser/chunk-KRJ4KK2W.mjs.map +7 -0
  8. package/dist/lib/browser/{chunk-KZUDO43J.mjs → chunk-LUH4Y5F2.mjs} +31 -23
  9. package/dist/lib/browser/chunk-LUH4Y5F2.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-CO3XLNUX.mjs → chunk-NKVRSMFN.mjs} +18 -18
  11. package/dist/lib/browser/chunk-NKVRSMFN.mjs.map +7 -0
  12. package/dist/lib/browser/{chunk-DC3WRPBV.mjs → chunk-OO53M5UK.mjs} +45 -12
  13. package/dist/lib/browser/chunk-OO53M5UK.mjs.map +7 -0
  14. package/dist/lib/browser/{chunk-IW44C7UL.mjs → chunk-OPTS3ZSN.mjs} +1 -1
  15. package/dist/lib/browser/chunk-OPTS3ZSN.mjs.map +7 -0
  16. package/dist/lib/browser/{chunk-HFLKXMT7.mjs → chunk-U5MESPM5.mjs} +61 -45
  17. package/dist/lib/browser/chunk-U5MESPM5.mjs.map +7 -0
  18. package/dist/lib/browser/{chunk-XHS5KDNX.mjs → chunk-UGYCLOXE.mjs} +25 -25
  19. package/dist/lib/browser/chunk-UGYCLOXE.mjs.map +7 -0
  20. package/dist/lib/browser/{chunk-5GY3YOEL.mjs → chunk-VF37YTXJ.mjs} +5 -5
  21. package/dist/lib/browser/chunk-VF37YTXJ.mjs.map +7 -0
  22. package/dist/lib/browser/{chunk-FO3IYSLV.mjs → chunk-YUVQIOTB.mjs} +29 -37
  23. package/dist/lib/browser/chunk-YUVQIOTB.mjs.map +7 -0
  24. package/dist/lib/browser/cli/index.mjs +9 -9
  25. package/dist/lib/browser/cli/index.mjs.map +2 -2
  26. package/dist/lib/browser/common/activation-events.mjs +7 -7
  27. package/dist/lib/browser/common/capabilities.mjs +7 -7
  28. package/dist/lib/browser/config/index.mjs +8 -0
  29. package/dist/lib/browser/config/index.mjs.map +7 -0
  30. package/dist/lib/browser/core/activation-event.mjs +1 -1
  31. package/dist/lib/browser/core/capability.mjs +1 -1
  32. package/dist/lib/browser/core/plugin-manager.mjs +4 -4
  33. package/dist/lib/browser/core/plugin.mjs +12 -2
  34. package/dist/lib/browser/core/url-loader.mjs +3 -3
  35. package/dist/lib/browser/index.mjs +14 -10
  36. package/dist/lib/browser/index.mjs.map +1 -1
  37. package/dist/lib/browser/meta.json +1 -1
  38. package/dist/lib/browser/{process-manager-capability-GXNUO7AR.mjs → process-manager-capability-QK4BMKMN.mjs} +9 -9
  39. package/dist/lib/browser/testing/index.mjs +15 -15
  40. package/dist/lib/browser/testing/index.mjs.map +3 -3
  41. package/dist/lib/browser/testing/react.mjs +11 -11
  42. package/dist/lib/browser/testing/react.mjs.map +3 -3
  43. package/dist/lib/browser/ui/index.mjs +18 -10
  44. package/dist/lib/node-esm/{capability-KZWRTX7R.mjs → capability-3YRF77LV.mjs} +9 -9
  45. package/dist/lib/node-esm/chunk-2UPUZXGU.mjs +9 -0
  46. package/dist/lib/node-esm/chunk-2UPUZXGU.mjs.map +7 -0
  47. package/dist/lib/node-esm/{chunk-XIGPWXCQ.mjs → chunk-4SE7SX7N.mjs} +45 -12
  48. package/dist/lib/node-esm/chunk-4SE7SX7N.mjs.map +7 -0
  49. package/dist/lib/node-esm/{chunk-XOCUANHO.mjs → chunk-BMW6P6QA.mjs} +6 -7
  50. package/dist/lib/node-esm/chunk-BMW6P6QA.mjs.map +7 -0
  51. package/dist/lib/node-esm/{chunk-A5CHGAZE.mjs → chunk-DRT75WGD.mjs} +61 -45
  52. package/dist/lib/node-esm/chunk-DRT75WGD.mjs.map +7 -0
  53. package/dist/lib/node-esm/{chunk-XGBUKRCK.mjs → chunk-FKMVORZN.mjs} +31 -23
  54. package/dist/lib/node-esm/chunk-FKMVORZN.mjs.map +7 -0
  55. package/dist/lib/node-esm/{chunk-CTKEZHKF.mjs → chunk-GLH4LGHZ.mjs} +1 -1
  56. package/dist/lib/node-esm/chunk-GLH4LGHZ.mjs.map +7 -0
  57. package/dist/lib/node-esm/{chunk-SX5NVETP.mjs → chunk-IL7O7IRX.mjs} +25 -25
  58. package/dist/lib/node-esm/chunk-IL7O7IRX.mjs.map +7 -0
  59. package/dist/lib/node-esm/{chunk-FSVGKTF6.mjs → chunk-ND2HETHD.mjs} +36 -7
  60. package/dist/lib/node-esm/chunk-ND2HETHD.mjs.map +7 -0
  61. package/dist/lib/node-esm/{chunk-KFZEB6BV.mjs → chunk-TLKYZKPW.mjs} +5 -5
  62. package/dist/lib/node-esm/chunk-TLKYZKPW.mjs.map +7 -0
  63. package/dist/lib/node-esm/{chunk-WK7OIQKI.mjs → chunk-VCPGX7WN.mjs} +29 -37
  64. package/dist/lib/node-esm/chunk-VCPGX7WN.mjs.map +7 -0
  65. package/dist/lib/node-esm/{chunk-NULBHQYS.mjs → chunk-XSZMX53L.mjs} +18 -18
  66. package/dist/lib/node-esm/chunk-XSZMX53L.mjs.map +7 -0
  67. package/dist/lib/node-esm/cli/index.mjs +9 -9
  68. package/dist/lib/node-esm/cli/index.mjs.map +2 -2
  69. package/dist/lib/node-esm/common/activation-events.mjs +7 -7
  70. package/dist/lib/node-esm/common/capabilities.mjs +7 -7
  71. package/dist/lib/node-esm/config/index.mjs +9 -0
  72. package/dist/lib/node-esm/config/index.mjs.map +7 -0
  73. package/dist/lib/node-esm/core/activation-event.mjs +1 -1
  74. package/dist/lib/node-esm/core/capability.mjs +1 -1
  75. package/dist/lib/node-esm/core/plugin-manager.mjs +4 -4
  76. package/dist/lib/node-esm/core/plugin.mjs +12 -2
  77. package/dist/lib/node-esm/core/url-loader.mjs +3 -3
  78. package/dist/lib/node-esm/index.mjs +14 -10
  79. package/dist/lib/node-esm/index.mjs.map +1 -1
  80. package/dist/lib/node-esm/meta.json +1 -1
  81. package/dist/lib/node-esm/{process-manager-capability-TX5TA6YN.mjs → process-manager-capability-5S7WZ2JR.mjs} +9 -9
  82. package/dist/lib/node-esm/testing/index.mjs +15 -15
  83. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  84. package/dist/lib/node-esm/testing/react.mjs +11 -11
  85. package/dist/lib/node-esm/testing/react.mjs.map +3 -3
  86. package/dist/lib/node-esm/ui/index.mjs +18 -10
  87. package/dist/plugin/node-esm/index.mjs +414 -81
  88. package/dist/plugin/node-esm/index.mjs.map +4 -4
  89. package/dist/plugin/node-esm/meta.json +1 -1
  90. package/dist/types/src/cli/cli.d.ts +1 -1
  91. package/dist/types/src/common/activation-events.d.ts.map +1 -1
  92. package/dist/types/src/common/capabilities.d.ts +2 -2
  93. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  94. package/dist/types/src/config/index.d.ts +2 -0
  95. package/dist/types/src/config/index.d.ts.map +1 -0
  96. package/dist/types/src/core/activation-event.d.ts +9 -6
  97. package/dist/types/src/core/activation-event.d.ts.map +1 -1
  98. package/dist/types/src/core/capability.d.ts +9 -3
  99. package/dist/types/src/core/capability.d.ts.map +1 -1
  100. package/dist/types/src/core/edge-registry-plugin-provider.d.ts +6 -11
  101. package/dist/types/src/core/edge-registry-plugin-provider.d.ts.map +1 -1
  102. package/dist/types/src/core/plugin-manager.d.ts.map +1 -1
  103. package/dist/types/src/core/plugin-manifest.d.ts +25 -7
  104. package/dist/types/src/core/plugin-manifest.d.ts.map +1 -1
  105. package/dist/types/src/core/plugin.d.ts +89 -91
  106. package/dist/types/src/core/plugin.d.ts.map +1 -1
  107. package/dist/types/src/core/registry.d.ts +17 -57
  108. package/dist/types/src/core/registry.d.ts.map +1 -1
  109. package/dist/types/src/core/url-loader.d.ts +2 -2
  110. package/dist/types/src/core/url-loader.d.ts.map +1 -1
  111. package/dist/types/src/index.d.ts +1 -0
  112. package/dist/types/src/index.d.ts.map +1 -1
  113. package/dist/types/src/plugin-process-manager/history/capability.d.ts +1 -3
  114. package/dist/types/src/plugin-process-manager/history/capability.d.ts.map +1 -1
  115. package/dist/types/src/plugin-process-manager/meta.d.ts +32 -2
  116. package/dist/types/src/plugin-process-manager/meta.d.ts.map +1 -1
  117. package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts +1 -4
  118. package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts.map +1 -1
  119. package/dist/types/src/testing/harness.d.ts +1 -1
  120. package/dist/types/src/testing/harness.d.ts.map +1 -1
  121. package/dist/types/src/testing/react.d.ts +6 -5
  122. package/dist/types/src/testing/react.d.ts.map +1 -1
  123. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  124. package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -1
  125. package/dist/types/src/ui/components/App/App.stories.d.ts +2 -2
  126. package/dist/types/src/ui/components/App/App.stories.d.ts.map +1 -1
  127. package/dist/types/src/ui/components/PluginManager/PluginManagerProvider.d.ts +6 -0
  128. package/dist/types/src/ui/components/PluginManager/PluginManagerProvider.d.ts.map +1 -1
  129. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts +6 -10
  130. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts.map +1 -1
  131. package/dist/types/src/ui/components/Surface/SurfaceComponent.stories.d.ts.map +1 -1
  132. package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts +1 -1
  133. package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts.map +1 -1
  134. package/dist/types/src/ui/components/Surface/context.d.ts +6 -2
  135. package/dist/types/src/ui/components/Surface/context.d.ts.map +1 -1
  136. package/dist/types/src/ui/components/Surface/index.d.ts +11 -4
  137. package/dist/types/src/ui/components/Surface/index.d.ts.map +1 -1
  138. package/dist/types/src/ui/components/Surface/types.d.ts +52 -72
  139. package/dist/types/src/ui/components/Surface/types.d.ts.map +1 -1
  140. package/dist/types/src/ui/hooks/useApp.d.ts +1 -1
  141. package/dist/types/src/ui/hooks/useCapabilities.d.ts +17 -1
  142. package/dist/types/src/ui/hooks/useCapabilities.d.ts.map +1 -1
  143. package/dist/types/src/vite-plugin/composer/index.d.ts +11 -4
  144. package/dist/types/src/vite-plugin/composer/index.d.ts.map +1 -1
  145. package/dist/types/src/vite-plugin/import-map/index.d.ts.map +1 -1
  146. package/dist/types/src/vite-plugin/index.d.ts +1 -0
  147. package/dist/types/src/vite-plugin/index.d.ts.map +1 -1
  148. package/dist/types/src/vite-plugin/load.d.ts +16 -0
  149. package/dist/types/src/vite-plugin/load.d.ts.map +1 -0
  150. package/dist/types/src/vite-plugin/manifest.d.ts +16 -4
  151. package/dist/types/src/vite-plugin/manifest.d.ts.map +1 -1
  152. package/dist/types/src/vite-plugin/packages.d.ts.map +1 -1
  153. package/dist/types/tsconfig.tsbuildinfo +1 -1
  154. package/docs/registry-spec.md +331 -0
  155. package/moon.yml +1 -0
  156. package/package.json +50 -39
  157. package/src/cli/cli.ts +2 -2
  158. package/src/common/activation-events.ts +3 -3
  159. package/src/common/capabilities.ts +18 -18
  160. package/src/config/index.ts +5 -0
  161. package/src/core/activation-event.ts +15 -8
  162. package/src/core/capability.ts +18 -6
  163. package/src/core/edge-registry-plugin-provider.ts +41 -42
  164. package/src/core/plugin-manager.test.ts +133 -137
  165. package/src/core/plugin-manager.ts +25 -19
  166. package/src/core/plugin-manifest.test.ts +5 -5
  167. package/src/core/plugin-manifest.ts +13 -10
  168. package/src/core/plugin.ts +58 -114
  169. package/src/core/registry.ts +20 -60
  170. package/src/core/url-loader.test.ts +2 -2
  171. package/src/core/url-loader.ts +23 -19
  172. package/src/index.ts +1 -0
  173. package/src/testing/harness.ts +5 -3
  174. package/src/testing/react.test.tsx +4 -2
  175. package/src/testing/react.tsx +10 -9
  176. package/src/testing/service.ts +2 -2
  177. package/src/testing/withPluginManager.stories.tsx +4 -2
  178. package/src/testing/withPluginManager.tsx +3 -1
  179. package/src/ui/components/App/App.stories.tsx +2 -2
  180. package/src/ui/components/PluginManager/PluginManagerProvider.ts +7 -0
  181. package/src/ui/components/Surface/SurfaceComponent.stories.tsx +22 -22
  182. package/src/ui/components/Surface/SurfaceComponent.tsx +90 -79
  183. package/src/ui/components/Surface/SurfaceProfilerContext.tsx +1 -1
  184. package/src/ui/components/Surface/context.ts +6 -4
  185. package/src/ui/components/Surface/index.ts +14 -3
  186. package/src/ui/components/Surface/types.test.ts +43 -51
  187. package/src/ui/components/Surface/types.ts +99 -64
  188. package/src/ui/hooks/useApp.test.tsx +1 -1
  189. package/src/ui/hooks/useApp.tsx +2 -2
  190. package/src/ui/hooks/useCapabilities.ts +49 -2
  191. package/src/vite-plugin/boot-loader/BootLoader.solid-stories.tsx +11 -11
  192. package/src/vite-plugin/boot-loader/loader.ts +3 -3
  193. package/src/vite-plugin/composer/index.ts +134 -61
  194. package/src/vite-plugin/import-map/index.ts +23 -7
  195. package/src/vite-plugin/index.ts +1 -0
  196. package/src/vite-plugin/load.ts +57 -0
  197. package/src/vite-plugin/manifest.test.ts +3 -3
  198. package/src/vite-plugin/manifest.ts +21 -10
  199. package/src/vite-plugin/packages.ts +0 -2
  200. package/tsconfig.json +5 -2
  201. package/dist/lib/browser/chunk-5GY3YOEL.mjs.map +0 -7
  202. package/dist/lib/browser/chunk-66IXTIVK.mjs.map +0 -7
  203. package/dist/lib/browser/chunk-CO3XLNUX.mjs.map +0 -7
  204. package/dist/lib/browser/chunk-DC3WRPBV.mjs.map +0 -7
  205. package/dist/lib/browser/chunk-FO3IYSLV.mjs.map +0 -7
  206. package/dist/lib/browser/chunk-HFLKXMT7.mjs.map +0 -7
  207. package/dist/lib/browser/chunk-IW44C7UL.mjs.map +0 -7
  208. package/dist/lib/browser/chunk-KZUDO43J.mjs.map +0 -7
  209. package/dist/lib/browser/chunk-XHS5KDNX.mjs.map +0 -7
  210. package/dist/lib/browser/chunk-Y66ELD4U.mjs.map +0 -7
  211. package/dist/lib/node-esm/chunk-A5CHGAZE.mjs.map +0 -7
  212. package/dist/lib/node-esm/chunk-CTKEZHKF.mjs.map +0 -7
  213. package/dist/lib/node-esm/chunk-FSVGKTF6.mjs.map +0 -7
  214. package/dist/lib/node-esm/chunk-KFZEB6BV.mjs.map +0 -7
  215. package/dist/lib/node-esm/chunk-NULBHQYS.mjs.map +0 -7
  216. package/dist/lib/node-esm/chunk-SX5NVETP.mjs.map +0 -7
  217. package/dist/lib/node-esm/chunk-WK7OIQKI.mjs.map +0 -7
  218. package/dist/lib/node-esm/chunk-XGBUKRCK.mjs.map +0 -7
  219. package/dist/lib/node-esm/chunk-XIGPWXCQ.mjs.map +0 -7
  220. package/dist/lib/node-esm/chunk-XOCUANHO.mjs.map +0 -7
  221. /package/dist/lib/browser/{capability-BOPAKKWG.mjs.map → capability-S44TE2H7.mjs.map} +0 -0
  222. /package/dist/lib/browser/{process-manager-capability-GXNUO7AR.mjs.map → process-manager-capability-QK4BMKMN.mjs.map} +0 -0
  223. /package/dist/lib/node-esm/{capability-KZWRTX7R.mjs.map → capability-3YRF77LV.mjs.map} +0 -0
  224. /package/dist/lib/node-esm/{process-manager-capability-TX5TA6YN.mjs.map → process-manager-capability-5S7WZ2JR.mjs.map} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/common/capabilities.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Atom, type Registry } from '@effect-atom/atom-react';\nimport type * as Command$ from '@effect/cli/Command';\nimport * as Effect from 'effect/Effect';\nimport type * as Exit$ from 'effect/Exit';\nimport type * as Fiber$ from 'effect/Fiber';\nimport type * as Layer$ from 'effect/Layer';\nimport type * as ManagedRuntime$ from 'effect/ManagedRuntime';\nimport type * as Runtime$ from 'effect/Runtime';\nimport type { FC, PropsWithChildren } from 'react';\n\nimport type {\n OperationHandlerSet,\n LayerSpec as LayerSpec$,\n Operation as Operation$,\n Process as Process$,\n ServiceResolver as ServiceResolver$,\n Trace as Trace$,\n} from '@dxos/compute';\nimport type { ProcessManager as ProcessManager$ } from '@dxos/compute-runtime';\nimport { OperationInvoker as OperationInvoker$ } from '@dxos/operation';\n\nimport { Capability as Capability$, Plugin as Plugin$, type PluginManager as PluginManager$ } from '../core';\nimport type {\n HistoryTracker as HistoryTracker$,\n UndoMapping as UndoMapping$,\n UndoRegistry as UndoRegistry$,\n} from '../plugin-process-manager';\nimport type { Surface } from '../ui';\n\n/**\n * Null capability.\n * @category Capability\n */\nexport const Null = Capability$.make<null>('org.dxos.app-framework.capability.null');\n\n/**\n * @category Capability\n */\nexport const PluginManager = Capability$.make<PluginManager$.PluginManager>(\n 'org.dxos.app-framework.capability.pluginManager',\n);\n\n/**\n * @category Capability\n */\nexport const AtomRegistry = Capability$.make<Registry.Registry>('org.dxos.app-framework.capability.atomRegistry');\n\nexport type ReactContext = Readonly<{\n id: string;\n dependsOn?: string[];\n context: FC<PropsWithChildren>;\n}>;\n\n/**\n * @category Capability\n */\nexport const ReactContext = Capability$.make<ReactContext>('org.dxos.app-framework.capability.reactContext');\n\nexport type ReactRoot = Readonly<{ id: string; root: FC<PropsWithChildren> }>;\n\n/**\n * @category Capability\n */\nexport const ReactRoot = Capability$.make<ReactRoot>('org.dxos.app-framework.capability.reactRoot');\n\n/**\n * Surface definitions that can be either React components or Web Components.\n */\nexport type ReactSurface = Surface.Definition | readonly Surface.Definition[];\n\n/**\n * @category Capability\n */\nexport const ReactSurface = Capability$.make<ReactSurface>('org.dxos.app-framework.capability.reactSurface');\n\nexport type AnyCommand = Command$.Command<any, any, any, any>;\n\n/**\n * @category Capability\n */\nexport const Command = Capability$.make<AnyCommand>('org.dxos.app-framework.capability.command');\n\n/**\n * @category Capability\n */\nexport const Layer = Capability$.make<Layer$.Layer<any, any, any>>('org.dxos.app-framework.capability.layer');\n\n/**\n * Layer specification contributed by plugins.\n *\n * Plugins contribute {@link LayerSpec.LayerSpec} entries that are collected by the\n * process-manager module and composed into a {@link LayerStack} which backs the\n * {@link ProcessManagerRuntime}'s service resolver.\n *\n * @category Capability\n */\nexport const LayerSpec = Capability$.make<LayerSpec$.LayerSpec>('org.dxos.app-framework.capability.layerSpec');\n\n/**\n * Context passed to {@link TraceSinkFactory} implementations when the\n * process-manager capability materialises contributed sinks.\n */\nexport interface TraceSinkFactoryContext {\n /**\n * Service resolver backing the shared {@link ProcessManagerRuntime}. Use it\n * to resolve per-space (or per-process) services like `FeedTraceSink` when\n * building a routing sink.\n */\n readonly resolver: ServiceResolver$.ServiceResolver;\n}\n\n/**\n * Factory that builds a {@link Trace$.Sink} when the process-manager\n * capability is ready. Plugins that only need a static sink can ignore the\n * context (e.g. `() => myConsoleSink`); plugins that need per-space routing\n * can use {@link TraceSinkFactoryContext.resolver} to look up services.\n */\nexport type TraceSinkFactory = (ctx: TraceSinkFactoryContext) => Trace$.Sink;\n\n/**\n * Trace sink contribution.\n *\n * Plugins contribute {@link TraceSinkFactory} functions; the process-manager\n * capability invokes each factory with the runtime's\n * {@link ServiceResolver$.ServiceResolver}, collects the resulting\n * {@link Trace$.Sink}s, merges them via {@link Trace$.mergeSinks}, and\n * installs the merged sink as {@link Trace$.TraceSink} in the runtime layer\n * so every process writes to every contributed sink.\n *\n * @category Capability\n */\nexport const TraceSink = Capability$.make<TraceSinkFactory>('org.dxos.app-framework.capability.traceSink');\n\n/**\n * Service resolver backing the shared {@link ProcessManagerRuntime}.\n *\n * Contributed by the process-manager capability module. Consumers can combine\n * it with {@link ServiceResolver$.provide} to build space-scoped layers without\n * having to go through the process-manager runtime:\n *\n * @example\n * ```ts\n * const resolver = yield* Capability.get(Capabilities.ServiceResolver);\n * yield* effect.pipe(\n * Effect.provide(\n * ServiceResolver.provide({ space }, Database.Service).pipe(\n * Layer.provide(Layer.succeed(ServiceResolver.ServiceResolver, resolver)),\n * ),\n * ),\n * );\n * ```\n *\n * @category Capability\n */\nexport const ServiceResolver = Capability$.make<ServiceResolver$.ServiceResolver>(\n 'org.dxos.app-framework.capability.serviceResolver',\n);\n\n/**\n * Process monitor backing the shared {@link ProcessManagerRuntime}. Exposes the\n * live process tree (including inactive/terminated entries) via\n * {@link Process$.Monitor#processTreeAtom}.\n *\n * @category Capability\n */\nexport const ProcessMonitor = Capability$.make<Process$.Monitor>('org.dxos.app-framework.capability.processMonitor');\n\n/**\n * Services that are always available when running effects through a {@link ProcessManagerRuntime}.\n */\nexport type ProcessManagerRuntimeServices =\n | Capability$.Service\n | Plugin$.Service\n | ProcessManager$.ProcessManagerService\n | Operation$.Service\n | ProcessManager$.ProcessOperationInvoker.Service\n | ServiceResolver$.ServiceResolver;\n\n/**\n * Runtime that runs effects requiring a fixed set of capability-manager and\n * process-manager services.\n *\n * The shape mirrors {@link ManagedRuntime$.ManagedRuntime} but deliberately does\n * not expose `dispose` – lifecycle is driven by the host plugin manager.\n */\nexport interface ProcessManagerRuntime {\n runPromise<A, E>(\n effect: Effect.Effect<A, E, ProcessManagerRuntimeServices>,\n options?: { readonly signal?: AbortSignal },\n ): Promise<A>;\n runPromiseExit<A, E>(\n effect: Effect.Effect<A, E, ProcessManagerRuntimeServices>,\n options?: { readonly signal?: AbortSignal },\n ): Promise<Exit$.Exit<A, E>>;\n runFork<A, E>(\n effect: Effect.Effect<A, E, ProcessManagerRuntimeServices>,\n options?: Runtime$.RunForkOptions,\n ): Fiber$.RuntimeFiber<A, E>;\n runSync<A, E>(effect: Effect.Effect<A, E, ProcessManagerRuntimeServices>): A;\n}\n\n/**\n * @category Capability\n */\nexport const ProcessManagerRuntime = Capability$.make<ProcessManagerRuntime>(\n 'org.dxos.app-framework.capability.processManagerRuntime',\n);\n\nexport type ManagedRuntime = ManagedRuntime$.ManagedRuntime<any, any>;\n\n/**\n * @category Capability\n */\nexport const ManagedRuntime = Capability$.make<ManagedRuntime>('org.dxos.app-framework.capability.managedRuntime');\n\n//\n// Operation System Capabilities\n//\n\nexport const OperationHandler = Capability$.make<OperationHandlerSet.OperationHandlerSet>(\n 'org.dxos.app-framework.capability.operationHandler',\n);\n\nexport type UndoMapping = UndoMapping$.UndoMapping;\n\n/**\n * Undo mapping registration - contributed by plugins.\n * @category Capability\n */\nexport const UndoMapping = Capability$.make<UndoMapping[]>('org.dxos.app-framework.capability.undoMapping');\n\n/**\n * Operation invoker backed by the process manager. Spawns a process per\n * operation invocation; see {@link ProcessManager$.ProcessOperationInvoker}.\n */\nexport type OperationInvoker = OperationInvoker$.OperationInvoker;\n\n/**\n * Operation invoker - provided by the process-manager capability.\n * @category Capability\n */\nexport const OperationInvoker = Capability$.make<OperationInvoker>(\n 'org.dxos.app-framework.capability.operationInvoker',\n);\n\nexport type UndoRegistry = UndoRegistry$.UndoRegistry;\n\n/**\n * Undo registry - provided by ProcessManagerPlugin.\n * @category Capability\n */\nexport const UndoRegistry = Capability$.make<UndoRegistry>('org.dxos.app-framework.capability.undoRegistry');\n\nexport type HistoryTracker = HistoryTracker$.HistoryTracker;\n\n/**\n * History tracker - provided by ProcessManagerPlugin.\n * @category Capability\n */\nexport const HistoryTracker = Capability$.make<HistoryTracker>('org.dxos.app-framework.capability.historyTracker');\n\n//\n// Atom Capability Helpers\n//\n\n/**\n * Get the current value of an atom capability.\n * @example const settings = yield* Capabilities.getAtomValue(CommentCapabilities.Settings);\n */\nexport const getAtomValue = <T>(\n atomCapability: Capability$.InterfaceDef<Atom.Atom<T>>,\n): Effect.Effect<T, Error, Capability$.Service> =>\n Effect.gen(function* () {\n const registry = yield* Capability$.get(AtomRegistry);\n const atom = yield* Capability$.get(atomCapability);\n return registry.get(atom);\n });\n\n/**\n * Update an atom capability value (requires writable atom).\n * @example yield* Capabilities.updateAtomValue(CommentCapabilities.Settings, (s) => ({ ...s, foo: true }));\n */\nexport const updateAtomValue = <T>(\n atomCapability: Capability$.InterfaceDef<Atom.Writable<T>>,\n fn: (current: T) => T,\n): Effect.Effect<void, Error, Capability$.Service> =>\n Effect.gen(function* () {\n const registry = yield* Capability$.get(AtomRegistry);\n const atom = yield* Capability$.get(atomCapability);\n registry.set(atom, fn(registry.get(atom)));\n });\n\n/**\n * Subscribe to an atom capability.\n * @example const unsubscribe = yield* Capabilities.subscribeAtom(CommentCapabilities.Settings, (value) => ...);\n */\nexport const subscribeAtom = <T>(\n atomCapability: Capability$.InterfaceDef<Atom.Atom<T>>,\n callback: (value: T) => void,\n): Effect.Effect<() => void, Error, Capability$.Service> =>\n Effect.gen(function* () {\n const registry = yield* Capability$.get(AtomRegistry);\n const atom = yield* Capability$.get(atomCapability);\n return registry.subscribe(atom, () => callback(registry.get(atom)));\n });\n"],
5
+ "mappings": ";;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,YAAYA,YAAY;AA+BjB,IAAMC,OAAOC,mBAAYC,KAAW,wCAAA;AAKpC,IAAMC,gBAAgBF,mBAAYC,KACvC,iDAAA;AAMK,IAAME,eAAeH,mBAAYC,KAAwB,gDAAA;AAWzD,IAAMG,eAAeJ,mBAAYC,KAAmB,gDAAA;AAOpD,IAAMI,YAAYL,mBAAYC,KAAgB,6CAAA;AAU9C,IAAMK,eAAeN,mBAAYC,KAAmB,gDAAA;AAOpD,IAAMM,UAAUP,mBAAYC,KAAiB,2CAAA;AAK7C,IAAMO,QAAQR,mBAAYC,KAAkC,yCAAA;AAW5D,IAAMQ,YAAYT,mBAAYC,KAA2B,6CAAA;AAmCzD,IAAMS,YAAYV,mBAAYC,KAAuB,6CAAA;AAuBrD,IAAMU,kBAAkBX,mBAAYC,KACzC,mDAAA;AAUK,IAAMW,iBAAiBZ,mBAAYC,KAAuB,kDAAA;AAuC1D,IAAMY,wBAAwBb,mBAAYC,KAC/C,yDAAA;AAQK,IAAMa,iBAAiBd,mBAAYC,KAAqB,kDAAA;AAMxD,IAAMc,mBAAmBf,mBAAYC,KAC1C,oDAAA;AASK,IAAMe,cAAchB,mBAAYC,KAAoB,+CAAA;AAYpD,IAAMgB,mBAAmBjB,mBAAYC,KAC1C,oDAAA;AASK,IAAMiB,eAAelB,mBAAYC,KAAmB,gDAAA;AAQpD,IAAMkB,iBAAiBnB,mBAAYC,KAAqB,kDAAA;AAUxD,IAAMmB,eAAe,CAC1BC,mBAEOC,WAAI,aAAA;AACT,QAAMC,WAAW,OAAOvB,mBAAYwB,IAAIrB,YAAAA;AACxC,QAAMsB,OAAO,OAAOzB,mBAAYwB,IAAIH,cAAAA;AACpC,SAAOE,SAASC,IAAIC,IAAAA;AACtB,CAAA;AAMK,IAAMC,kBAAkB,CAC7BL,gBACAM,OAEOL,WAAI,aAAA;AACT,QAAMC,WAAW,OAAOvB,mBAAYwB,IAAIrB,YAAAA;AACxC,QAAMsB,OAAO,OAAOzB,mBAAYwB,IAAIH,cAAAA;AACpCE,WAASK,IAAIH,MAAME,GAAGJ,SAASC,IAAIC,IAAAA,CAAAA,CAAAA;AACrC,CAAA;AAMK,IAAMI,gBAAgB,CAC3BR,gBACAS,aAEOR,WAAI,aAAA;AACT,QAAMC,WAAW,OAAOvB,mBAAYwB,IAAIrB,YAAAA;AACxC,QAAMsB,OAAO,OAAOzB,mBAAYwB,IAAIH,cAAAA;AACpC,SAAOE,SAASQ,UAAUN,MAAM,MAAMK,SAASP,SAASC,IAAIC,IAAAA,CAAAA,CAAAA;AAC9D,CAAA;",
6
+ "names": ["Effect", "Null", "Capability$", "make", "PluginManager", "AtomRegistry", "ReactContext", "ReactRoot", "ReactSurface", "Command", "Layer", "LayerSpec", "TraceSink", "ServiceResolver", "ProcessMonitor", "ProcessManagerRuntime", "ManagedRuntime", "OperationHandler", "UndoMapping", "OperationInvoker", "UndoRegistry", "HistoryTracker", "getAtomValue", "atomCapability", "gen", "registry", "get", "atom", "updateAtomValue", "fn", "set", "subscribeAtom", "callback", "subscribe"]
7
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getModuleTag
3
- } from "./chunk-IW44C7UL.mjs";
3
+ } from "./chunk-OPTS3ZSN.mjs";
4
4
  import {
5
5
  __export
6
6
  } from "./chunk-J5LGTIGS.mjs";
@@ -9,13 +9,18 @@ import {
9
9
  var plugin_exports = {};
10
10
  __export(plugin_exports, {
11
11
  LazyPluginError: () => LazyPluginError,
12
+ Meta: () => Meta,
12
13
  PluginDependencyError: () => PluginDependencyError,
13
14
  PluginModuleTypeId: () => PluginModuleTypeId,
14
15
  PluginTypeId: () => PluginTypeId,
16
+ Profile: () => Profile,
17
+ Release: () => Release,
15
18
  Service: () => Service,
16
19
  activate: () => activate,
17
20
  addModule: () => addModule,
18
21
  define: () => define,
22
+ getMetaFromConfig: () => getMetaFromConfig,
23
+ getURI: () => getURI,
19
24
  isLazy: () => isLazy,
20
25
  isPlugin: () => isPlugin,
21
26
  isPluginModule: () => isPluginModule,
@@ -30,9 +35,11 @@ import * as Context from "effect/Context";
30
35
  import * as Effect from "effect/Effect";
31
36
  import * as Option from "effect/Option";
32
37
  import * as Pipeable from "effect/Pipeable";
38
+ import * as Schema from "effect/Schema";
33
39
  import { BaseError } from "@dxos/errors";
34
40
  import { invariant } from "@dxos/invariant";
35
41
  import { DXN } from "@dxos/keys";
42
+ import { PluginProfileSchema, PluginReleaseSchema } from "@dxos/protocols";
36
43
  var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-framework/src/core/plugin.ts";
37
44
  var Service = class extends Context.Tag("@dxos/app-framework/PluginManager")() {
38
45
  };
@@ -61,11 +68,32 @@ var PluginModuleImpl = class {
61
68
  this.activate = options.activate;
62
69
  }
63
70
  };
64
- var makeMeta = (options) => ({
65
- ...options,
66
- id: DXN.getName(options.key),
67
- version: DXN.getVersion(options.key)
71
+ var Profile = Schema.Struct({
72
+ ...PluginProfileSchema.fields,
73
+ author: Schema.optional(Schema.String)
68
74
  });
75
+ var Release = PluginReleaseSchema;
76
+ var Meta = Schema.Struct({
77
+ profile: Profile,
78
+ release: Schema.optional(Release)
79
+ });
80
+ var makeMeta = (options) => {
81
+ const { key, ...rest } = options;
82
+ return {
83
+ profile: {
84
+ ...rest,
85
+ key: DXN.getName(key)
86
+ }
87
+ };
88
+ };
89
+ var getURI = (meta) => DXN.make(meta.profile.key, meta.release?.version);
90
+ var getMetaFromConfig = ({ plugin }) => {
91
+ const { key, ...rest } = plugin;
92
+ return makeMeta({
93
+ key: DXN.make(key),
94
+ ...rest
95
+ });
96
+ };
69
97
  var PluginTypeId = /* @__PURE__ */ Symbol.for("@dxos/app-framework/Plugin");
70
98
  var isPlugin = (value) => {
71
99
  return typeof value === "object" && value !== null && PluginTypeId in value;
@@ -112,11 +140,11 @@ function addModule(moduleOptionsOrBuilder, moduleOptions) {
112
140
  }
113
141
  var resolveModule = (meta, module, options) => {
114
142
  const moduleOptions = typeof module === "function" ? module(options) : module;
115
- const pluginName = meta.id;
143
+ const pluginName = meta.profile.key;
116
144
  const id = Option.fromNullable(moduleOptions.id).pipe(Option.match({
117
145
  onNone: () => {
118
146
  const exportName = getModuleTag(moduleOptions.activate);
119
- invariant(exportName, `Plugin module missing name. Plugin: ${meta.id}`, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 148, S: void 0, A: ["exportName", "`Plugin module missing name. Plugin: ${meta.id}`"] });
147
+ invariant(exportName, `Plugin module missing name. Plugin: ${meta.profile.key}`, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 174, S: void 0, A: ["exportName", "`Plugin module missing name. Plugin: ${meta.profile.key}`"] });
120
148
  return computeModuleId(pluginName, exportName);
121
149
  },
122
150
  onSome: (id2) => computeModuleId(pluginName, id2)
@@ -128,7 +156,7 @@ var resolveModule = (meta, module, options) => {
128
156
  };
129
157
  function make(builder) {
130
158
  const meta = builder.meta;
131
- invariant(!meta.dependsOn?.includes(meta.id), `Plugin ${meta.id} declares itself as a dependency.`, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 161, S: this, A: ["!meta.dependsOn?.includes(meta.id)", "`Plugin ${meta.id} declares itself as a dependency.`"] });
159
+ invariant(!meta.profile.dependsOn?.includes(meta.profile.key), `Plugin ${meta.profile.key} declares itself as a dependency.`, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 187, S: this, A: ["!meta.profile.dependsOn?.includes(meta.profile.key)", "`Plugin ${meta.profile.key} declares itself as a dependency.`"] });
132
160
  const factory = (options) => {
133
161
  const modules = builder.modules.map((module) => resolveModule(meta, module, options));
134
162
  return new PluginImpl(meta, modules);
@@ -163,7 +191,7 @@ var resolveLazy = (plugin) => Effect.gen(function* () {
163
191
  if (!isLazy(plugin)) {
164
192
  return plugin;
165
193
  }
166
- const id = plugin.meta.id;
194
+ const id = plugin.meta.profile.key;
167
195
  const { loader, options } = plugin[LazyTag];
168
196
  const mod = yield* Effect.tryPromise({
169
197
  try: loader,
@@ -192,12 +220,12 @@ var resolveLazy = (plugin) => Effect.gen(function* () {
192
220
  }
193
221
  }));
194
222
  }
195
- if (result.meta.id !== id) {
223
+ if (result.meta.profile.key !== id) {
196
224
  return yield* Effect.fail(new LazyPluginError({
197
225
  context: {
198
226
  id,
199
227
  reason: "meta-mismatch",
200
- returnedId: result.meta.id
228
+ returnedId: result.meta.profile.key
201
229
  }
202
230
  }));
203
231
  }
@@ -211,7 +239,12 @@ export {
211
239
  shutdown,
212
240
  PluginModuleTypeId,
213
241
  isPluginModule,
242
+ Profile,
243
+ Release,
244
+ Meta,
214
245
  makeMeta,
246
+ getURI,
247
+ getMetaFromConfig,
215
248
  PluginTypeId,
216
249
  isPlugin,
217
250
  define,
@@ -224,4 +257,4 @@ export {
224
257
  resolveLazy,
225
258
  plugin_exports
226
259
  };
227
- //# sourceMappingURL=chunk-DC3WRPBV.mjs.map
260
+ //# sourceMappingURL=chunk-OO53M5UK.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/core/plugin.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport * as Pipeable from 'effect/Pipeable';\nimport * as Schema from 'effect/Schema';\n\nimport { BaseError } from '@dxos/errors';\nimport { invariant } from '@dxos/invariant';\nimport { DXN } from '@dxos/keys';\nimport { Config2, PluginProfileSchema, PluginReleaseSchema } from '@dxos/protocols';\n\nimport type * as ActivationEvent from './activation-event';\nimport * as Capability from './capability';\nimport type * as PluginManager from './plugin-manager';\n\n//\n// Plugin Service Layer\n//\n\n/**\n * Effect Context.Tag for accessing PluginManager via the Effect layer system.\n * This allows lifecycle operations to access the plugin manager without having it passed as an argument.\n */\nexport class Service extends Context.Tag('@dxos/app-framework/PluginManager')<Service, PluginManager.PluginManager>() {}\n\n//\n// Lifecycle Functions\n//\n\n/**\n * Activates plugins based on the activation event.\n * Accesses the PluginManager via the Effect layer system.\n * @param event The activation event.\n * @returns Whether the activation was successful.\n */\nexport const activate = (event: ActivationEvent.ActivationEvent): Effect.Effect<boolean, Error, Service> =>\n Effect.flatMap(Service, (manager) => manager.activate(event));\n\n/**\n * Re-activates the modules that were activated by the event.\n * Accesses the PluginManager via the Effect layer system.\n * @param event The activation event.\n * @returns Whether the reset was successful.\n */\nexport const reset = (event: ActivationEvent.ActivationEvent): Effect.Effect<boolean, Error, Service> =>\n Effect.flatMap(Service, (manager) => manager.reset(event));\n\n/**\n * Shuts down the plugin manager, deactivating all active modules and clearing lifecycle state.\n * Accesses the PluginManager via the Effect layer system.\n */\nexport const shutdown = (): Effect.Effect<boolean, Error, Service> =>\n Effect.flatMap(Service, (manager) => manager.shutdown());\n\n/**\n * Computes a module ID from plugin ID and export name.\n */\nconst computeModuleId = (pluginId: string, moduleName: string): string => {\n return `${pluginId}.module.${moduleName}`;\n};\n\n/**\n * Identifier denoting a PluginModule.\n */\nexport const PluginModuleTypeId: unique symbol = Symbol.for('@dxos/app-framework/PluginModule');\nexport type PluginModuleTypeId = typeof PluginModuleTypeId;\n\n/**\n * Type guard to check if a value is a PluginModule.\n */\nexport const isPluginModule = (value: unknown): value is PluginModule => {\n return typeof value === 'object' && value !== null && PluginModuleTypeId in value;\n};\n\n/**\n * A unit of containment of modular functionality that can be provided to an application.\n * Activation of a module is async allowing for code to split and loaded lazily.\n */\nexport interface PluginModule {\n readonly [PluginModuleTypeId]: PluginModuleTypeId;\n /**\n * Unique id of the module.\n */\n id: string;\n\n /**\n * Events for which the module will be activated.\n */\n activatesOn: ActivationEvent.Events;\n\n /**\n * Events that this module fires *before* its own activation runs.\n *\n * When this module is asked to activate (via {@link activatesOn}), the\n * plugin manager first activates every event listed here, ensuring any\n * other modules that contribute to those events have completed before\n * this module's {@link activate} body executes. These events are fired\n * by the framework on this module's behalf — the module does not need\n * to wait for some other code to fire them.\n *\n * The module is marked as needing reset if a module activated by one\n * of these events is later removed.\n *\n * Read as: \"this module fires these events before [its] activation\".\n */\n firesBeforeActivation?: ActivationEvent.ActivationEvent[];\n\n /**\n * Events that this module fires *after* its own activation completes.\n *\n * Once this module's {@link activate} body has finished executing, the\n * plugin manager activates every event listed here, causing any modules\n * listening on those events to run. These events are fired by the\n * framework on this module's behalf as part of this module's lifecycle.\n *\n * Read as: \"this module fires these events after [its] activation\".\n */\n firesAfterActivation?: ActivationEvent.ActivationEvent[];\n\n /**\n * Called when the module is activated.\n * CapabilityManager is accessed via the Effect layer system (Capability.Service).\n * PluginManager is accessed via Plugin.Service.\n * @param props Optional props passed to the module.\n * @returns The capabilities of the module.\n */\n activate: (props?: any) => Effect.Effect<Capability.ModuleReturn, Error, Capability.Service | Service | never>;\n}\n\nexport type PluginModuleOptions = Omit<PluginModule, 'id' | typeof PluginModuleTypeId> & { id?: string };\n\nclass PluginModuleImpl implements PluginModule {\n readonly [PluginModuleTypeId]: PluginModuleTypeId = PluginModuleTypeId;\n readonly id: PluginModule['id'];\n readonly activatesOn: PluginModule['activatesOn'];\n readonly firesBeforeActivation?: PluginModule['firesBeforeActivation'];\n readonly firesAfterActivation?: PluginModule['firesAfterActivation'];\n readonly activate: PluginModule['activate'];\n\n constructor(options: Omit<PluginModule, typeof PluginModuleTypeId>) {\n this.id = options.id;\n this.activatesOn = options.activatesOn;\n this.firesBeforeActivation = options.firesBeforeActivation;\n this.firesAfterActivation = options.firesAfterActivation;\n this.activate = options.activate;\n }\n}\n\n/**\n * Runtime plugin metadata, derived from the `@dxos/protocols` registry schemas (protocols owns the\n * config + registry schemas; the runtime projection lives here).\n *\n * - {@link Profile}: version-independent identity + display + provenance — the wire `PluginProfileSchema`\n * (which carries `key`, the display fields, `dependsOn`, `spec`) plus `author` (resolved at runtime\n * from the publisher's handle/DID for registry plugins, or self-declared for bundled).\n * - {@link Release}: a specific hosted release — the wire `PluginReleaseSchema` (version, moduleUrl, dependencies).\n * - {@link Meta}: a resolved single-release view — `{ profile, release? }`, both nested. `release` is\n * unset for bundled plugins (compiled in) and set for registry plugins.\n */\nexport const Profile = Schema.Struct({\n ...PluginProfileSchema.fields,\n author: Schema.optional(Schema.String),\n});\nexport type Profile = Schema.Schema.Type<typeof Profile>;\n\nexport const Release = PluginReleaseSchema;\nexport type Release = Schema.Schema.Type<typeof Release>;\n\nexport const Meta = Schema.Struct({\n profile: Profile,\n release: Schema.optional(Release),\n});\nexport type Meta = Schema.Schema.Type<typeof Meta>;\n\n/** Options for {@link makeMeta}: the {@link Profile} content fields plus the canonical DXN `key`. */\nexport type MakeMetaOptions = {\n key: DXN.DXN;\n name: string;\n description?: string;\n author?: string;\n homePage?: string;\n source?: string;\n tags?: readonly string[];\n dependsOn?: readonly string[];\n spec?: string;\n icon?: Config2.Icon;\n screenshots?: ReadonlyArray<Config2.Screenshot>;\n};\n\n/** Constructs a bundled-plugin {@link Meta} from a canonical DXN. `profile.key` is the bare NSID derived from `key`. */\nexport const makeMeta = (options: MakeMetaOptions): Meta => {\n const { key, ...rest } = options;\n return { profile: { ...rest, key: DXN.getName(key) } };\n};\n\n/** Returns the plugin's canonical DXN URI, constructed from `meta.profile.key` and `meta.release?.version`. */\nexport const getURI = (meta: Meta): DXN.DXN => DXN.make(meta.profile.key, meta.release?.version);\n\n/**\n * Derives a runtime {@link Meta} from a loaded `dx.config.ts` (the `@dxos/protocols` `Config2.Config`).\n * Maps the flat authoring config to the nested profile; bundled plugins have no `release`.\n */\nexport const getMetaFromConfig = ({ plugin }: Config2.Config): Meta => {\n const { key, ...rest } = plugin;\n return makeMeta({ key: DXN.make(key), ...rest });\n};\n\n/**\n * Identifier denoting a Plugin.\n */\nexport const PluginTypeId: unique symbol = Symbol.for('@dxos/app-framework/Plugin');\nexport type PluginTypeId = typeof PluginTypeId;\n\n/**\n * Type guard to check if a value is a Plugin.\n */\nexport const isPlugin = (value: unknown): value is Plugin => {\n return typeof value === 'object' && value !== null && PluginTypeId in value;\n};\n\n/**\n * A collection of modules that are be enabled/disabled as a unit.\n * Plugins provide things such as components, state, actions, etc. to the application.\n */\n// TODO(burdon): Convert to ECHO schema.\nexport interface Plugin {\n readonly [PluginTypeId]: PluginTypeId;\n readonly meta: Readonly<Meta>;\n readonly modules: ReadonlyArray<PluginModule>;\n}\n\n/**\n * Internal implementation of Plugin.\n * @internal\n */\nclass PluginImpl implements Plugin {\n readonly [PluginTypeId]: PluginTypeId = PluginTypeId;\n\n constructor(\n private readonly _meta: Meta,\n private readonly _modules: PluginModule[],\n ) {}\n\n get meta(): Readonly<Meta> {\n return this._meta;\n }\n\n get modules(): ReadonlyArray<PluginModule> {\n return this._modules;\n }\n}\n\n/**\n * Builder interface for creating plugins incrementally.\n */\nexport interface PluginBuilder<T = void> extends Pipeable.Pipeable {\n readonly meta: Meta;\n readonly modules: ReadonlyArray<PluginModuleOptions | ((options: T) => PluginModuleOptions)>;\n addModule(moduleOptions: PluginModuleOptions | ((options: T) => PluginModuleOptions)): PluginBuilder<T>;\n}\n\n/**\n * Builder implementation for creating plugins incrementally.\n */\nclass PluginBuilderImpl<T = void> implements PluginBuilder<T> {\n readonly meta: Meta;\n private readonly _modules: Array<PluginModuleOptions | ((options: T) => PluginModuleOptions)> = [];\n\n constructor(meta: Meta) {\n this.meta = meta;\n }\n\n get modules(): ReadonlyArray<PluginModuleOptions | ((options: T) => PluginModuleOptions)> {\n return this._modules;\n }\n\n addModule(moduleOptions: PluginModuleOptions | ((options: T) => PluginModuleOptions)): PluginBuilder<T> {\n this._modules.push(moduleOptions);\n return this;\n }\n\n pipe() {\n // eslint-disable-next-line prefer-rest-params\n return Pipeable.pipeArguments(this, arguments);\n }\n}\n\n/**\n * Creates a new PluginBuilder to start building a plugin.\n */\nexport const define = <T = void>(meta: Meta): PluginBuilder<T> => new PluginBuilderImpl<T>(meta);\n\n/**\n * Adds a module to a plugin builder.\n * Supports both pipeline and direct call styles.\n * Modules can be either PluginModuleOptions or functions that receive options.\n */\nexport function addModule<T>(\n moduleOptions: PluginModuleOptions | ((options: T) => PluginModuleOptions),\n): (builder: PluginBuilder<T>) => PluginBuilder<T>;\nexport function addModule<T>(\n builder: PluginBuilder<T>,\n moduleOptions: PluginModuleOptions | ((options: T) => PluginModuleOptions),\n): PluginBuilder<T>;\nexport function addModule<T>(\n moduleOptionsOrBuilder: PluginModuleOptions | ((options: T) => PluginModuleOptions) | PluginBuilder<T>,\n moduleOptions?: PluginModuleOptions | ((options: T) => PluginModuleOptions),\n): ((builder: PluginBuilder<T>) => PluginBuilder<T>) | PluginBuilder<T> {\n // If second arg is provided, it's the direct call style: addModule(builder, moduleOptions)\n if (moduleOptions !== undefined) {\n return (moduleOptionsOrBuilder as PluginBuilder<T>).addModule(moduleOptions);\n }\n // Otherwise it's pipeline style: addModule(moduleOptions) returns a function\n const moduleOpts = moduleOptionsOrBuilder as PluginModuleOptions | ((options: T) => PluginModuleOptions);\n return (builder: PluginBuilder<T>) => builder.addModule(moduleOpts);\n}\n\nexport type PluginFactory<T = void> = ((options: T) => Plugin) & { meta: Meta };\n\n/**\n * Resolves a module from either PluginModuleOptions or a function that returns PluginModuleOptions.\n */\nconst resolveModule = (\n meta: Meta,\n module: PluginModuleOptions | ((options: any) => PluginModuleOptions),\n options?: any,\n): PluginModuleImpl => {\n const moduleOptions = typeof module === 'function' ? module(options) : module;\n const pluginName = meta.profile.key;\n const id = Option.fromNullable(moduleOptions.id).pipe(\n Option.match({\n onNone: () => {\n const exportName = Capability.getModuleTag(moduleOptions.activate);\n invariant(exportName, `Plugin module missing name. Plugin: ${meta.profile.key}`);\n return computeModuleId(pluginName, exportName);\n },\n onSome: (id) => computeModuleId(pluginName, id),\n }),\n );\n return new PluginModuleImpl({ ...moduleOptions, id });\n};\n\n/**\n * Creates a Plugin from a builder.\n * Supports both pipeline and direct call styles.\n * Always returns a factory function (options: T) => Plugin.\n * When T is void, the function takes no arguments: () => Plugin.\n */\nexport function make<T>(builder: PluginBuilder<T>): PluginFactory<T>;\nexport function make<T>(builder: PluginBuilder<T>): PluginFactory<T> {\n const meta = builder.meta;\n // `dependsOn` entries and `key` are both bare NSIDs, so compare directly.\n invariant(\n !meta.profile.dependsOn?.includes(meta.profile.key),\n `Plugin ${meta.profile.key} declares itself as a dependency.`,\n );\n\n const factory = (options: T) => {\n const modules = builder.modules.map((module) => resolveModule(meta, module, options));\n return new PluginImpl(meta, modules);\n };\n\n return Object.assign(factory, { meta });\n}\n\n//\n// Lazy plugin loading\n//\n\n/**\n * Symbol used to tag lazy plugin stubs with their loader closure.\n * Hidden from enumeration so plugin manager iteration / serialization paths\n * don't trip over it.\n */\nconst LazyTag: unique symbol = Symbol.for('@dxos/app-framework/Plugin/Lazy');\n\n/**\n * Async loader for a lazy plugin's real implementation.\n * The default export of the loaded module must be a `PluginFactory<T>` —\n * i.e. the same shape `Plugin.make` produces.\n */\nexport type LazyLoader<T = void> = () => Promise<{ default: PluginFactory<T> }>;\n\n/** Internal: payload carried on a lazy stub. */\ntype LazyPayload = { loader: LazyLoader<any>; options: unknown };\n\n/**\n * Defines a lazy plugin whose body is loaded on first enable.\n *\n * The returned factory produces a stub `Plugin` that exposes `meta`\n * synchronously (so callers can read `Plugin.meta.profile.key` for free) but defers\n * loading the real plugin's modules until the manager calls\n * `Plugin.resolveLazy`. This lets the plugin's main entry point ship as a\n * tiny meta-only chunk — the heavy capabilities, schema, React surfaces,\n * etc. live behind the dynamic `import()` and become a separate Rollup\n * chunk that is only fetched when the plugin is enabled.\n *\n * @example\n * ```ts\n * // plugin-markdown/src/index.ts\n * import { Plugin } from '@dxos/app-framework';\n * import { meta } from './meta';\n *\n * export const MarkdownPlugin = Plugin.lazy(meta, () => import('./MarkdownPlugin'));\n *\n * // plugin-markdown/src/MarkdownPlugin.tsx\n * export const MarkdownPlugin = Plugin.define(meta).pipe(...heavy modules..., Plugin.make);\n * export default MarkdownPlugin;\n * ```\n */\nexport const lazy = <T = void>(meta: Meta, loader: LazyLoader<T>): PluginFactory<T> => {\n const factory = (options: T): Plugin => {\n const stub = new PluginImpl(meta, []);\n Object.defineProperty(stub, LazyTag, {\n value: { loader, options } satisfies LazyPayload,\n enumerable: false,\n });\n return stub;\n };\n return Object.assign(factory, { meta });\n};\n\n/**\n * Type guard for lazy plugin stubs produced by {@link lazy}.\n */\nexport const isLazy = (plugin: Plugin): boolean => LazyTag in plugin;\n\n/**\n * Tagged error for failures during lazy plugin resolution. `context.id` is\n * the lazy plugin's `meta.profile.key`; `context.reason` discriminates the failure\n * mode (`'load-failed' | 'missing-default' | 'invalid-plugin' |\n * 'meta-mismatch'`) so callers can route on it.\n */\nexport class LazyPluginError extends BaseError.extend('LazyPluginError', 'Failed to resolve lazy plugin') {}\n\n/**\n * Tagged error for plugin-level dependency resolution failures.\n *\n * `context.id` is the plugin id the manager was acting on. `context.reason`\n * discriminates the failure mode:\n * - `'missing'` — declared dep is neither registered nor in the catalog.\n * `context.missing` lists offending ids.\n * - `'install-failed'` — dep was found in the catalog but `add()` failed.\n * `cause` carries the original error.\n * - `'cycle'` — closure walk detected a cycle. `context.path` is the cycle path.\n * - `'core-dependent'` — cascade-disable would have to disable a core plugin.\n * `context.coreDependent` is the blocking id.\n */\nexport class PluginDependencyError extends BaseError.extend(\n 'PluginDependencyError',\n 'Plugin dependency resolution failed',\n) {}\n\n/**\n * Resolves a lazy plugin stub to its real plugin.\n * Returns the plugin unchanged if it is not lazy. Failures surface as\n * {@link LazyPluginError} with `context.reason` indicating the failure mode\n * and (for loader failures) `cause` set to the original error.\n */\nexport const resolveLazy = (plugin: Plugin): Effect.Effect<Plugin, LazyPluginError> =>\n Effect.gen(function* () {\n if (!isLazy(plugin)) {\n return plugin;\n }\n const id = plugin.meta.profile.key;\n const { loader, options } = (plugin as unknown as { [LazyTag]: LazyPayload })[LazyTag];\n const mod = yield* Effect.tryPromise({\n try: loader,\n catch: (error) => new LazyPluginError({ context: { id, reason: 'load-failed' }, cause: error }),\n });\n if (!mod || typeof mod.default !== 'function') {\n return yield* Effect.fail(new LazyPluginError({ context: { id, reason: 'missing-default' } }));\n }\n const result = mod.default(options);\n if (!isPlugin(result)) {\n return yield* Effect.fail(new LazyPluginError({ context: { id, reason: 'invalid-plugin' } }));\n }\n if (result.meta.profile.key !== id) {\n return yield* Effect.fail(\n new LazyPluginError({ context: { id, reason: 'meta-mismatch', returnedId: result.meta.profile.key } }),\n );\n }\n return result;\n });\n"],
5
+ "mappings": ";;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,YAAYA,aAAa;AACzB,YAAYC,YAAY;AACxB,YAAYC,YAAY;AACxB,YAAYC,cAAc;AAC1B,YAAYC,YAAY;AAExB,SAASC,iBAAiB;AAC1B,SAASC,iBAAiB;AAC1B,SAASC,WAAW;AACpB,SAAkBC,qBAAqBC,2BAA2B;AAMlE,IAAE,eAAA;AAUA,IAAA,UAAA,cAAA,YAAA,mCAAA,EAAA,EAAA;AACF;;;;AAiCA,IAAA,kBAAA,CAAA,UAAA,eAAA;AAEA,SAAA,GAAA,QAAA,WAAA,UAAA;;;AAWE,IAAA,iBAAA,CAAA,UAAA;AA2DF,SAAMC,OAAAA,UAAAA,YAAAA,UAAAA,QAAAA,sBAAAA;;IAEKC,yBAAuB;EACvBC,CAAAA,kBAAyC,IAAA;EACzCC;EACAC;EACAC;EAET;;cAEOH,SAAW;AAChB,SAAKC,KAAAA,QAAAA;AACL,SAAKC,cAAAA,QAAoB;AACzB,SAAKC,wBAAmBA,QAAQ;AAClC,SAAA,uBAAA,QAAA;AACF,SAAA,WAAA,QAAA;EAEA;;AAaEC,IAAQC,UAAgBA,cAAa;EACpC,GAAA,oBAAA;EAGH,QAAaC,gBAAUC,aAAAA;AAGvB,CAAA;AACEC,IAASC,UAAAA;AACTC,IAASL,OAAOM,cAASL;EACxB,SAAA;EAkBH,SAAA,gBAAA,OAAA;;AAGS,IAAA,WAAA,CAAA,YAAA;QAAEE,EAAAA,KAAS,GAAA,KAAA,IAAA;;aAAgBI;MAAiB,GAAA;MAAE,KAAA,IAAA,QAAA,GAAA;IACrD;EAEF;AAGA;;AAMSC,IAAAA,oBAAS,CAAA,EAAA,OAAA,MAAA;QAAEC,EAAAA,KAASC,GAAAA,KAAKD,IAAAA;SAASE,SAAI;IAAC,KAAA,IAAA,KAAA,GAAA;IAC9C,GAAA;EAEF,CAAA;;;AAWE,IAAA,WAAA,CAAA,UAAA;AAaF,SAAA,OAAA,UAAA,YAAA,UAAA,QAAA,gBAAA;;;EAKW;EAET;eACmBC,IAAAA;cACAC,OAAAA,UAAAA;AAChB,SAAA,QAAA;AAECC,SAAAA,WAAuB;;EAE3B,IAAA,OAAA;AAEIC,WAAAA,KAAuC;;EAE3C,IAAA,UAAA;AACF,WAAA,KAAA;EAWA;;AAKmBF,IAAAA,oBAAAA,MAAkF;EAEnG;aACOC,CAAAA;EACP,YAAA,MAAA;AAEIC,SAAAA,OAAsF;;EAE1F,IAAA,UAAA;AAEAC,WAAUC,KAAAA;;YAER,eAAW;AACb,SAAA,SAAA,KAAA,aAAA;AAEAC,WAAO;;SAEL;AAEJ,WAAA,uBAAA,MAAA,SAAA;EAEA;;AAqBE,IAAA,SAAA,CAAA,SAAA,IAAA,kBAAA,IAAA;AACA,SAAID,UAAkBE,wBAAW,eAAA;AAEjC,MAAA,kBAAA,QAAA;AACA,WAAA,uBAAA,UAAA,aAAA;EACA;AAEF,QAAA,aAAA;AAIA,SAAA,CAAA,YAAA,QAAA,UAAA,UAAA;;AASE,IAAMC,gBAAaN,CAAAA,MAAKX,QAAW,YAAA;AACnC,QAAMT,gBAAY2B,OAAAA,WAAaJ,aAAsB,OACnDK,OAAa,IAAA;QACXC,aAAQ,KAAA,QAAA;aACAC,oBAAaC,cAAWC,EAAAA,EAAAA,KAAaT,aAAcnB;YACzD6B,MAAAA;AACA,YAAA,aAAuBP,aAAYI,cAAAA,QAAAA;AACrC,gBAAA,YAAA,uCAAA,KAAA,QAAA,GAAA,IAAA,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,KAAA,GAAA,QAAA,GAAA,CAAA,cAAA,2DAAA,EAAA,CAAA;AACAI,aAASlC,gBAAOmC,YAAgBT,UAAY1B;IAC9C;IAEF,QAAWD,CAAAA,QAAAA,gBAAiB,YAAAC,GAAA;;SAAoBA,IAAAA,iBAAAA;IAAG,GAAA;IACrD;EASA,CAAA;;AAEE,SAAA,KAAA,SAAA;AACAiC,QAAAA,OACGb,QAAKX;YAKAY,CAAAA,KAAAA,QAAUe,WAAe,SAAMC,KAAAA,QAAWC,GAAAA,GAAAA,UAAoBD,KAAQE,QAAAA,GAAAA,qCAAAA,EAAAA,YAAAA,YAAAA,GAAAA,cAAAA,GAAAA,KAAAA,GAAAA,MAAAA,GAAAA,CAAAA,uDAAAA,+DAAAA,EAAAA,CAAAA;QAC5E,UAAWC,CAAAA,YAAWpB;AACxB,UAAA,UAAA,QAAA,QAAA,IAAA,CAAA,WAAA,cAAA,MAAA,QAAA,OAAA,CAAA;AAEA,WAAOqB,IAAOC,WAAOC,MAAS,OAAA;;AAAO,SAAA,OAAA,OAAA,SAAA;IACvC;EAEE,CAAA;AACF;;AA8CI,IAAMC,OAAO,CAAIJ,MAAAA,WAAWpB;QAC5BqB,UAAOI,CAAAA,YAAeD;UACpBE,OAAO,IAAA,WAAA,MAAA,CAAA,CAAA;0BAAEC,MAAAA,SAAAA;aAAQR;QAAQ;QACzBS;MACF;MACA,YAAOJ;IACT,CAAA;AACA,WAAOH;;AAA8B,SAAA,OAAA,OAAA,SAAA;IACrC;EAEF,CAAA;;;AAaA,IAAA,kBAAA,cAAA,UAAA,OAAA,mBAAA,+BAAA,EAAA;;AAkBA,IAAA,wBAAA,cAAA,UAAA,OAAA,yBAAA,qCAAA,EAAA;;IASM,cAAOQ,CAAAA,WAAAA,WAAAA,aAAAA;AACT,MAAA,CAAA,OAAA,MAAA,GAAA;AACA,WAAWA;EACX;AACA,QAAMC,KAAAA,OAAM,KAAOC,QAAOC;QACxBC,EAAAA,QAAKN,QAAAA,IAAAA,OAAAA,OAAAA;QACLO,MAAQC,OAAcC,kBAAAA;;sBAA6BxD,IAAAA,gBAAAA;eAAIyD;QAAsB;QAAGC,QAAOH;MAAM;MAC/F,OAAA;IACKL,CAAAA;;cAC6CS,OAAS,IAAA,YAAA,YAAA;kBAAE3D,YAAAA,IAAAA,gBAAAA;eAAIyD;QAA0B;QAAE,QAAA;MAC7F;IACA,CAAA,CAAMG;EACN;QACE,SAAO,IAAOT,QAAOU,OAASL;gBAAkBG,MAAS,GAAA;kBAAE3D,YAAAA,IAAAA,gBAAAA;eAAIyD;QAAyB;QAAE,QAAA;MAC5F;IACIG,CAAAA,CAAAA;;aAEsBD,KAAAA,QAAS,QAAA,IAAA;kBAAE3D,YAAAA,IAAAA,gBAAAA;eAAIyD;QAAyBK;QAAoC,QAAA;QAAE,YAAA,OAAA,KAAA,QAAA;MAExG;IACA,CAAA,CAAA;EACC;;;",
6
+ "names": ["Context", "Effect", "Option", "Pipeable", "Schema", "BaseError", "invariant", "DXN", "PluginProfileSchema", "PluginReleaseSchema", "PluginModuleImpl", "id", "activatesOn", "firesBeforeActivation", "firesAfterActivation", "activate", "author", "Schema", "Release", "PluginReleaseSchema", "profile", "Profile", "release", "optional", "DXN", "makeMeta", "key", "make", "rest", "_meta", "_modules", "meta", "modules", "addModule", "moduleOptions", "pipe", "undefined", "pluginName", "fromNullable", "Option", "onNone", "exportName", "Capability", "getModuleTag", "invariant", "onSome", "computeModuleId", "builder", "module", "resolveModule", "options", "PluginImpl", "Object", "assign", "factory", "stub", "defineProperty", "value", "loader", "enumerable", "plugin", "mod", "Effect", "tryPromise", "try", "catch", "error", "LazyPluginError", "reason", "cause", "context", "result", "fail", "returnedId"]
7
+ }
@@ -80,4 +80,4 @@ export {
80
80
  makeModule,
81
81
  capability_exports
82
82
  };
83
- //# sourceMappingURL=chunk-IW44C7UL.mjs.map
83
+ //# sourceMappingURL=chunk-OPTS3ZSN.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/core/capability.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Atom } from '@effect-atom/atom-react';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nimport type { DXN } from '@dxos/keys';\n\nimport type * as CapabilityManager from './capability-manager';\nimport type * as Plugin from './plugin';\n\n//\n// Capability Service Layer\n//\n\n/**\n * Effect Context.Tag for accessing CapabilityManager via the Effect layer system.\n * This allows capability modules to access the capability manager without having it passed as an argument.\n */\nexport class Service extends Context.Tag('@dxos/app-framework/CapabilityManager')<\n Service,\n CapabilityManager.CapabilityManager\n>() {}\n\n/**\n * Get a single capability from the capability manager.\n * @param interfaceDef The interface definition of the capability.\n * @returns The capability implementation.\n * @throws If no capability is found.\n */\n// TODO(wittjosiah): Add custom tagged errors (Data.TaggedError) for app-framework to enable\n// type-safe error handling with Effect. Consider CapabilityNotFoundError, ModuleActivationError, etc.\nexport const get = <T>(interfaceDef: InterfaceDef<T>): Effect.Effect<T, Error, Service> =>\n Effect.flatMap(Service, (manager) =>\n Effect.try({\n try: () => manager.get(interfaceDef),\n catch: (error) => (error instanceof Error ? error : new Error(String(error))),\n }),\n );\n\n/**\n * Get all capabilities from the capability manager for a given interface.\n * @param interfaceDef The interface definition of the capability.\n * @returns An array of capability implementations.\n */\nexport const getAll = <T>(interfaceDef: InterfaceDef<T>): Effect.Effect<T[], never, Service> =>\n Effect.map(Service, (manager) => manager.getAll(interfaceDef));\n\n/**\n * Wait for a capability to be available.\n * @param interfaceDef The interface definition of the capability.\n * @returns The capability implementation once available.\n */\nexport const waitFor = <T>(interfaceDef: InterfaceDef<T>): Effect.Effect<T, Error, Service> =>\n Effect.flatMap(Service, (manager) => manager.waitFor(interfaceDef));\n\n/**\n * Get the Atom reference to capabilities for reactive access.\n * @param interfaceDef The interface definition of the capability.\n * @returns An Atom containing the array of capability implementations.\n */\nexport const atom = <T>(interfaceDef: InterfaceDef<T>): Effect.Effect<Atom.Atom<T[]>, never, Service> =>\n Effect.map(Service, (manager) => manager.atom(interfaceDef));\n\n/**\n * Get capabilities grouped by the module that contributed them.\n * @param interfaceDef The interface definition of the capability.\n * @returns An Atom containing a record from module ID to capability implementations.\n */\nexport const atomByModule = <T>(\n interfaceDef: InterfaceDef<T>,\n): Effect.Effect<Atom.Atom<Record<string, T[]>>, never, Service> =>\n Effect.map(Service, (manager) => manager.atomByModule(interfaceDef));\n\n/**\n * Constructs a layer that will request its interface implementation from the capability manager.\n */\nexport const asLayer = <T, I>(interfaceDef: InterfaceDef<T>, tag: Context.Tag<I, T>): Layer.Layer<I, never, Service> =>\n Layer.effect(tag, get(interfaceDef).pipe(Effect.orDie));\n\nconst InterfaceDefTypeId: unique symbol = Symbol.for('InterfaceDefTypeId');\n\n/**\n * Symbol used to tag lazy capability functions with their module ID.\n */\nexport const ModuleTag: unique symbol = Symbol.for('@dxos/app-framework/ModuleTag');\n\n/**\n * The interface definition of a capability.\n */\nexport type InterfaceDef<T> = {\n [InterfaceDefTypeId]: T;\n identifier: string;\n};\n\nexport namespace InterfaceDef {\n export type Implementation<I extends InterfaceDef<any>> = I extends InterfaceDef<infer T> ? T : never;\n}\n\n/**\n * Helper to define the interface of a capability.\n * Static NSID strings are validated at compile time via {@link DXN.Name}.\n */\nexport const make: {\n <T, S extends string = string>(\n identifier: [DXN.Name<S>] extends [never] ? `Invalid NSID \"${S}\": final segment must be camelCase (no hyphens)` : S,\n ): InterfaceDef<T>;\n} = <T>(identifier: string): InterfaceDef<T> => {\n return { identifier } as InterfaceDef<T>;\n};\n\n/**\n * A unique string identifier with a Typescript type associated with it.\n * When a capability is contributed to the application an implementation of the interface is provided.\n */\nexport type Capability<T> = {\n /**\n * The interface definition of the capability.\n */\n readonly interface: InterfaceDef<T>;\n\n /**\n * The implementation of the capability.\n */\n readonly implementation: T;\n\n /**\n * Called when the capability is deactivated.\n */\n readonly deactivate?: () => Effect.Effect<void, Error>;\n};\n\nexport type Any = Capability<any>;\n\n/**\n * Union type representing all valid return types for a capability module.\n * Supports single capabilities, arrays, and tuples of different capability types.\n */\nexport type ModuleReturn = void | Any | Any[] | readonly Any[] | [Any, ...Any[]] | readonly [Any, ...Any[]];\n\n/**\n * Helper to define the implementation of a capability.\n * Returns the opaque base type so callers cannot discriminate on capability kind,\n * keeping d.ts emit portable across packages.\n */\nexport const contributes = <I extends InterfaceDef<any>>(\n interfaceDef: I,\n implementation: Capability<InterfaceDef.Implementation<I>>['implementation'],\n deactivate?: Capability<InterfaceDef.Implementation<I>>['deactivate'],\n): Any => {\n return {\n interface: interfaceDef,\n implementation,\n deactivate,\n } satisfies Capability<I>;\n};\n\ntype LoadCapability<Props, Capabilities extends ModuleReturn = ModuleReturn> = () => Promise<{\n default: (props: Props) => Effect.Effect<Capabilities, Error, Service | Plugin.Service | never>;\n}>;\ntype LoadCapabilities<Props, Capabilities extends ModuleReturn = ModuleReturn> = () => Promise<{\n default: (props: Props) => Effect.Effect<Capabilities, Error, Service | Plugin.Service | never>;\n}>;\n\ntype NormalizeReturn<R> = R extends readonly (infer A)[]\n ? A[]\n : R extends (infer A)[]\n ? A[]\n : R extends Any\n ? [R]\n : Any[];\n\nexport type LazyCapability<Props = void, Capabilities extends ModuleReturn = ModuleReturn, E extends Error = Error> = (\n props: Props,\n) => Effect.Effect<NormalizeReturn<Capabilities>, E, Service | Plugin.Service | never>;\n\n/**\n * Helper to define a lazily loaded implementation of a capability.\n * Supports single capabilities, arrays, and tuples of different capability types.\n * @param name The export name (e.g., 'AppGraphBuilder') - used to auto-compute module IDs.\n * @param loader The lazy loader function.\n * @returns A lazy capability function with ModuleTag symbol attached.\n */\nexport const lazy = <T = void, R extends ModuleReturn = ModuleReturn>(\n name: string,\n c: LoadCapability<T, R> | LoadCapabilities<T, R>,\n): LazyCapability<T> => {\n const lazyFn = (props: T) =>\n Effect.gen(function* () {\n const { default: getCapability } = yield* Effect.promise(() => c());\n const result = yield* getCapability(props);\n const normalized = result == null ? [] : Array.isArray(result) ? Array.from(result) : [result];\n return normalized as NormalizeReturn<R>;\n });\n\n // Props (T) are preserved so callers pass correctly-typed options, but the contributed\n // Capabilities type is widened to the opaque base. The concrete capability type often traces to a\n // module-internal source path that TypeScript cannot name in declaration files (TS2883); the base\n // type is portable. The contributed type is checked at Capability.contributes regardless.\n return Object.assign(lazyFn, { [ModuleTag]: name }) as LazyCapability<T>;\n};\n\n/**\n * Gets the module tag (export name) from a lazy capability function.\n * @param capability The lazy capability function.\n * @returns The module tag if present, undefined otherwise.\n */\n// TODO(wittjosiah): Stricter type for capability.\nexport const getModuleTag = (capability: unknown): string | undefined => {\n return capability && typeof capability === 'function' && ModuleTag in capability\n ? String(capability[ModuleTag])\n : undefined;\n};\n\n/**\n * Helper to define a capability module with explicit typing.\n * Wraps the default export function to provide better type inference and make the pattern explicit.\n *\n * This helper provides explicit typing for the module activation function,\n * making it clear that the function should:\n * - Access CapabilityManager via the Effect layer system (Capability.get, Capability.getAll, etc.)\n * - Return a capability, array of capabilities, or tuple of different capability types (sync or async)\n *\n * Supports returning multiple capabilities of different types as a tuple, which will be normalized\n * to an array at runtime for compatibility with the plugin system.\n *\n * @example\n * ```ts\n * // Module without options - single capability\n * export default Capability.makeModule(\n * Effect.fnUntraced(function* () {\n * const client = yield* Capability.get(ClientCapabilities.Client);\n * return contributes(Capabilities.SettingsStore, store);\n * })\n * );\n *\n * // Module with multiple capabilities\n * export default Capability.makeModule(\n * Effect.fnUntraced(function* () {\n * return [\n * contributes(Capabilities.SettingsStore, store),\n * contributes(Capabilities.Translations, translations),\n * ];\n * })\n * );\n *\n * // Module with required options (context accessed via layer)\n * export default Capability.makeModule(\n * Effect.fnUntraced(function* (props: { observability: boolean }) {\n * const invoker = yield* Capability.get(Capabilities.OperationInvoker);\n * return contributes(Capabilities.OperationHandler, ...);\n * })\n * );\n * ```\n */\nexport const makeModule = <\n TProps = void,\n TReturn extends ModuleReturn = ModuleReturn,\n E extends Error = Error,\n R extends Service | Plugin.Service | never = Service,\n>(\n fn: (props: TProps) => Effect.Effect<TReturn, E, R>,\n): ((props: TProps) => Effect.Effect<TReturn, E, R>) => fn;\n"],
5
+ "mappings": ";;;;;AAAA;;;;;;;;;;;;;;;;AAKA,YAAYA,aAAa;AACzB,YAAYC,YAAY;AACxB,YAAYC,WAAW;AAehB,IAAMC,UAAN,cAA8BC,YAAI,uCAAA,EAAA,EAAA;AAGpC;AAUE,IAAMC,MAAM,CAAIC,iBACdC,eAAQJ,SAAS,CAACK,YAChBC,WAAI;EACTA,KAAK,MAAMD,QAAQH,IAAIC,YAAAA;EACvBI,OAAO,CAACC,UAAWA,iBAAiBC,QAAQD,QAAQ,IAAIC,MAAMC,OAAOF,KAAAA,CAAAA;AACvE,CAAA,CAAA;AAQG,IAAMG,SAAS,CAAIR,iBACjBS,WAAIZ,SAAS,CAACK,YAAYA,QAAQM,OAAOR,YAAAA,CAAAA;AAO3C,IAAMU,UAAU,CAAIV,iBAClBC,eAAQJ,SAAS,CAACK,YAAYA,QAAQQ,QAAQV,YAAAA,CAAAA;AAOhD,IAAMW,OAAO,CAAIX,iBACfS,WAAIZ,SAAS,CAACK,YAAYA,QAAQS,KAAKX,YAAAA,CAAAA;AAOzC,IAAMY,eAAe,CAC1BZ,iBAEOS,WAAIZ,SAAS,CAACK,YAAYA,QAAQU,aAAaZ,YAAAA,CAAAA;AAKjD,IAAMa,UAAU,CAAOb,cAA+Bc,QACrDC,aAAOD,KAAKf,IAAIC,YAAAA,EAAcgB,KAAYC,YAAK,CAAA;AAOhD,IAAMC,YAA2BC,uBAAOC,IAAI,+BAAA;AAkB5C,IAAMC,OAIT,CAAIC,eAAAA;AACN,SAAO;IAAEA;EAAW;AACtB;AAoCO,IAAMC,cAAc,CACzBC,cACAC,gBACAC,eAAAA;AAEA,SAAO;IACLC,WAAWH;IACXC;IACAC;EACF;AACF;AA4BO,IAAME,OAAO,CAClBC,MACAC,MAAAA;AAEA,QAAMC,SAAS,CAACC,UACPC,WAAI,aAAA;AACT,UAAM,EAAEC,SAASC,cAAa,IAAK,OAAcC,eAAQ,MAAMN,EAAAA,CAAAA;AAC/D,UAAMO,SAAS,OAAOF,cAAcH,KAAAA;AACpC,UAAMM,aAAaD,UAAU,OAAO,CAAA,IAAKE,MAAMC,QAAQH,MAAAA,IAAUE,MAAME,KAAKJ,MAAAA,IAAU;MAACA;;AACvF,WAAOC;EACT,CAAA;AAMF,SAAOI,OAAOC,OAAOZ,QAAQ;IAAE,CAACb,SAAAA,GAAYW;EAAK,CAAA;AACnD;AAQO,IAAMe,eAAe,CAACC,eAAAA;AAC3B,SAAOA,cAAc,OAAOA,eAAe,cAAc3B,aAAa2B,aAClEC,OAAOD,WAAW3B,SAAAA,CAAU,IAC5B6B;AACN;AA2CO,IAAMC,aAAa,CAMxBC,OACsDA;",
6
+ "names": ["Context", "Effect", "Layer", "Service", "Tag", "get", "interfaceDef", "flatMap", "manager", "try", "catch", "error", "Error", "String", "getAll", "map", "waitFor", "atom", "atomByModule", "asLayer", "tag", "effect", "pipe", "orDie", "ModuleTag", "Symbol", "for", "make", "identifier", "contributes", "interfaceDef", "implementation", "deactivate", "interface", "lazy", "name", "c", "lazyFn", "props", "gen", "default", "getCapability", "promise", "result", "normalized", "Array", "isArray", "from", "Object", "assign", "getModuleTag", "capability", "String", "undefined", "makeModule", "fn"]
7
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  capabilities_exports
3
- } from "./chunk-CO3XLNUX.mjs";
3
+ } from "./chunk-NKVRSMFN.mjs";
4
4
 
5
5
  // src/helpers.ts
6
6
  var topologicalSort = (nodes) => {
@@ -42,6 +42,7 @@ import { createContext, useContext } from "react";
42
42
  import { raise } from "@dxos/debug";
43
43
  var PluginManagerContext = createContext(void 0);
44
44
  var usePluginManager = () => useContext(PluginManagerContext) ?? raise(new Error("Missing PluginManagerContext"));
45
+ var useOptionalPluginManager = () => useContext(PluginManagerContext);
45
46
  var PluginManagerProvider = PluginManagerContext.Provider;
46
47
 
47
48
  // src/ui/components/Surface/context.ts
@@ -54,7 +55,7 @@ import React3, { Fragment, Profiler, Suspense, forwardRef as forwardRef2, memo,
54
55
  import { log } from "@dxos/log";
55
56
  import { ErrorBoundary } from "@dxos/react-error-boundary";
56
57
  import { useDefaultValue } from "@dxos/react-hooks";
57
- import { byPosition } from "@dxos/util";
58
+ import { Position } from "@dxos/util";
58
59
 
59
60
  // src/ui/components/Surface/SurfaceInfo.tsx
60
61
  import React, { cloneElement, forwardRef, useCallback, useLayoutEffect, useState } from "react";
@@ -263,7 +264,7 @@ var emptySnapshot = () => EMPTY_SNAPSHOT;
263
264
 
264
265
  // src/ui/components/Surface/SurfaceComponent.tsx
265
266
  var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-framework/src/ui/components/Surface/SurfaceComponent.tsx";
266
- var DEBUG = import.meta.env.VITE_DEBUG;
267
+ var DEBUG = import.meta.env?.VITE_DEBUG;
267
268
  var DEFAULT_PLACEHOLDER = /* @__PURE__ */ React3.createElement(Fragment, null);
268
269
  var WebComponentWrapper = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef2(({ id, role, data, limit, definition, ...rest }, forwardedRef) => {
269
270
  const containerRef = useRef2(null);
@@ -409,15 +410,15 @@ var SurfaceContextProvider = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef2(({
409
410
  }))));
410
411
  }));
411
412
  SurfaceContextProvider.displayName = "SurfaceContextProvider";
412
- var SurfaceComponent = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef2(({ id: _id, role, type, data: dataProp, limit, placeholder = DEFAULT_PLACEHOLDER, ...rest }, forwardedRef) => {
413
+ var SurfaceComponent = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef2(({ id: _id, type, data: dataProp, limit, placeholder = DEFAULT_PLACEHOLDER, ...rest }, forwardedRef) => {
413
414
  const data = useDefaultValue(dataProp, () => ({}));
414
415
  const surfaces = useSurfaces();
415
- const effectiveRole = role ?? type?.role;
416
+ const effectiveRole = type?.role;
416
417
  if (effectiveRole == null) {
417
418
  if (DEBUG) {
418
- log.warn("Surface has neither `role` nor `type` prop", {
419
+ log.warn("Surface is missing required `type` prop", {
419
420
  id: _id
420
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 194, S: void 0 });
421
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 193, S: void 0 });
421
422
  }
422
423
  return null;
423
424
  }
@@ -430,7 +431,7 @@ var SurfaceComponent = /* @__PURE__ */ memo(/* @__PURE__ */ forwardRef2(({ id: _
430
431
  log.warn("no candidates for surface", {
431
432
  role: effectiveRole,
432
433
  data
433
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 207, S: void 0 });
434
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 206, S: void 0 });
434
435
  return null;
435
436
  }
436
437
  return /* @__PURE__ */ React3.createElement(Suspense, {
@@ -459,14 +460,14 @@ var ErrorFallback = ({ error }) => {
459
460
  }, message));
460
461
  };
461
462
  var findCandidates = (surfaces, { role, data }) => {
462
- return Object.values(surfaces).filter((definition) => Array.isArray(definition.role) ? definition.role.includes(role) : definition.role === role).filter(({ filter }) => filter ? filter(data ?? {}, role) : true).toSorted(byPosition);
463
+ return Object.values(surfaces).filter((definition) => Array.isArray(definition.role) ? definition.role.includes(role) : definition.role === role).filter(({ filter }) => filter ? filter(data ?? {}, role) : true).toSorted(Position.compare);
463
464
  };
464
465
  var useSurfaces = () => {
465
466
  const manager = usePluginManager();
466
467
  const surfacesByModule = useAtomValue(manager.capabilities.atomByModule(capabilities_exports.ReactSurface));
467
468
  return useMemo2(() => {
468
469
  const result = [];
469
- for (const [moduleId, surfaces] of Object.entries(surfacesByModule)) {
470
+ for (const [_moduleId, surfaces] of Object.entries(surfacesByModule)) {
470
471
  for (const def of surfaces.flat()) {
471
472
  result.push(def);
472
473
  }
@@ -476,24 +477,49 @@ var useSurfaces = () => {
476
477
  surfacesByModule
477
478
  ]);
478
479
  };
479
- function isSurfaceAvailable(capabilityManager, { role, type, data }) {
480
- const effectiveRole = role ?? type?.role;
480
+ function isSurfaceAvailable(capabilityManager, args) {
481
+ const effectiveRole = args.type?.role;
481
482
  if (effectiveRole == null) {
482
483
  return false;
483
484
  }
484
485
  const surfaces = capabilityManager.getAll(capabilities_exports.ReactSurface);
485
486
  const candidates = findCandidates(surfaces.flat(), {
486
487
  role: effectiveRole,
487
- data
488
+ data: args.data
488
489
  });
489
490
  return candidates.length > 0;
490
491
  }
491
492
 
492
493
  // src/ui/components/Surface/types.ts
494
+ import { log as log2 } from "@dxos/log";
495
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/sdk/app-framework/src/ui/components/Surface/types.ts";
493
496
  var isSurfaceFilter = (value) => typeof value === "object" && value !== null && Array.isArray(value.bindings);
494
- var makeType = (role) => ({
495
- role
496
- });
497
+ var makeType = (nsid) => {
498
+ if (typeof nsid !== "string" || !/^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z][a-zA-Z0-9]{0,62})$/.test(nsid)) {
499
+ throw new Error(`Invalid role NSID: "${nsid}". Must be a dotted name with a camelCase final segment (no hyphens in the last segment).`);
500
+ }
501
+ return {
502
+ role: nsid
503
+ };
504
+ };
505
+ var makeFilter = (token, guard) => {
506
+ const boundGuard = guard == null ? () => true : (data) => {
507
+ try {
508
+ return guard(data);
509
+ } catch (err) {
510
+ log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 39, S: void 0 });
511
+ return false;
512
+ }
513
+ };
514
+ return {
515
+ bindings: [
516
+ {
517
+ role: token.role,
518
+ guard: boundGuard
519
+ }
520
+ ]
521
+ };
522
+ };
497
523
  var expandBindings = (filter) => {
498
524
  const bindings = filter.bindings;
499
525
  const roles = Array.from(new Set(bindings.map((binding) => binding.role)));
@@ -517,40 +543,28 @@ var validateLocalId = (id) => {
517
543
  };
518
544
  function create(definition) {
519
545
  validateLocalId(definition.id);
520
- if (isSurfaceFilter(definition.filter)) {
521
- const { id, filter, component, position } = definition;
522
- const { role, guard } = expandBindings(filter);
523
- return {
524
- kind: "react",
525
- id,
526
- role,
527
- position,
528
- component,
529
- filter: guard
530
- };
531
- }
546
+ const { id, filter, component, position } = definition;
547
+ const { role, guard } = expandBindings(filter);
532
548
  return {
533
- ...definition,
534
- kind: "react"
549
+ kind: "react",
550
+ id,
551
+ role,
552
+ position,
553
+ component,
554
+ filter: guard
535
555
  };
536
556
  }
537
557
  function createWeb(definition) {
538
558
  validateLocalId(definition.id);
539
- if (isSurfaceFilter(definition.filter)) {
540
- const { id, filter, tagName, position } = definition;
541
- const { role, guard } = expandBindings(filter);
542
- return {
543
- kind: "web-component",
544
- id,
545
- role,
546
- position,
547
- tagName,
548
- filter: guard
549
- };
550
- }
559
+ const { id, filter, tagName, position } = definition;
560
+ const { role, guard } = expandBindings(filter);
551
561
  return {
552
- ...definition,
553
- kind: "web-component"
562
+ kind: "web-component",
563
+ id,
564
+ role,
565
+ position,
566
+ tagName,
567
+ filter: guard
554
568
  };
555
569
  }
556
570
 
@@ -562,6 +576,7 @@ function createWeb(definition) {
562
576
  Surface2.Surface = SurfaceComponent;
563
577
  Surface2.isAvailable = isSurfaceAvailable;
564
578
  Surface2.makeType = makeType;
579
+ Surface2.makeFilter = makeFilter;
565
580
  Surface2.isFilter = isSurfaceFilter;
566
581
  Surface2.ProfilerProvider = SurfaceProfilerProvider;
567
582
  Surface2.useProfilerCallback = useSurfaceProfilerCallback;
@@ -580,8 +595,9 @@ export {
580
595
  topologicalSort,
581
596
  useSurface,
582
597
  usePluginManager,
598
+ useOptionalPluginManager,
583
599
  PluginManagerProvider,
584
600
  SurfaceComponent,
585
601
  Surface
586
602
  };
587
- //# sourceMappingURL=chunk-HFLKXMT7.mjs.map
603
+ //# sourceMappingURL=chunk-U5MESPM5.mjs.map