@dxos/app-framework 0.8.4-main.d05539e30a → 0.8.4-main.d9fc60f731

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 (177) hide show
  1. package/dist/lib/browser/{capability-K5XIVCQU.mjs → capability-JCUNWZ66.mjs} +7 -7
  2. package/dist/lib/browser/{chunk-5AHASNDW.mjs → chunk-2ZIYRDAF.mjs} +1 -1
  3. package/dist/lib/browser/{chunk-5AHASNDW.mjs.map → chunk-2ZIYRDAF.mjs.map} +1 -1
  4. package/dist/lib/browser/{chunk-QLML5QFJ.mjs → chunk-7MBI66M7.mjs} +12 -6
  5. package/dist/lib/browser/chunk-7MBI66M7.mjs.map +7 -0
  6. package/dist/lib/browser/{chunk-VJ5PFAWC.mjs → chunk-BMLCIFZW.mjs} +37 -16
  7. package/dist/lib/browser/chunk-BMLCIFZW.mjs.map +7 -0
  8. package/dist/lib/browser/{chunk-SLX73WRZ.mjs → chunk-DC3WRPBV.mjs} +14 -5
  9. package/dist/lib/browser/chunk-DC3WRPBV.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-BRK6GYNB.mjs → chunk-E5DTDNDY.mjs} +20 -19
  11. package/dist/lib/browser/chunk-E5DTDNDY.mjs.map +7 -0
  12. package/dist/lib/browser/{chunk-KLHQNYJ2.mjs → chunk-KZUDO43J.mjs} +2 -2
  13. package/dist/lib/browser/chunk-Q2GLJTVV.mjs +12 -0
  14. package/dist/lib/browser/chunk-Q2GLJTVV.mjs.map +7 -0
  15. package/dist/lib/browser/{chunk-UVTGHZQF.mjs → chunk-VBG5F5UF.mjs} +51 -88
  16. package/dist/lib/browser/chunk-VBG5F5UF.mjs.map +7 -0
  17. package/dist/lib/browser/cli/index.mjs +5 -5
  18. package/dist/lib/browser/common/activation-events.mjs +3 -3
  19. package/dist/lib/browser/common/capabilities.mjs +4 -4
  20. package/dist/lib/browser/core/plugin-manager.mjs +2 -2
  21. package/dist/lib/browser/core/plugin.mjs +3 -1
  22. package/dist/lib/browser/core/url-loader.mjs +2 -2
  23. package/dist/lib/browser/index.mjs +13 -14
  24. package/dist/lib/browser/index.mjs.map +3 -3
  25. package/dist/lib/browser/meta.json +1 -1
  26. package/dist/lib/browser/{process-manager-capability-JIWLN7SU.mjs → process-manager-capability-4FUA4TRP.mjs} +6 -6
  27. package/dist/lib/browser/testing/index.mjs +11 -10
  28. package/dist/lib/browser/testing/index.mjs.map +3 -3
  29. package/dist/lib/browser/testing/react.mjs +6 -6
  30. package/dist/lib/browser/ui/index.mjs +7 -9
  31. package/dist/lib/node-esm/{capability-RLKFFLTB.mjs → capability-7TCQK7ZP.mjs} +7 -7
  32. package/dist/lib/node-esm/{chunk-SFYCO3PT.mjs → chunk-4BX2AE47.mjs} +37 -16
  33. package/dist/lib/node-esm/chunk-4BX2AE47.mjs.map +7 -0
  34. package/dist/lib/node-esm/chunk-FPW45EZH.mjs +14 -0
  35. package/dist/lib/node-esm/chunk-FPW45EZH.mjs.map +7 -0
  36. package/dist/lib/node-esm/{chunk-LJNUFNDO.mjs → chunk-GEWHMHM7.mjs} +12 -6
  37. package/dist/lib/node-esm/chunk-GEWHMHM7.mjs.map +7 -0
  38. package/dist/lib/node-esm/{chunk-BYHYYJZH.mjs → chunk-KSH4OVMY.mjs} +20 -19
  39. package/dist/lib/node-esm/chunk-KSH4OVMY.mjs.map +7 -0
  40. package/dist/lib/node-esm/{chunk-PW2VYGOS.mjs → chunk-QBUGLR4H.mjs} +1 -1
  41. package/dist/lib/node-esm/{chunk-PW2VYGOS.mjs.map → chunk-QBUGLR4H.mjs.map} +1 -1
  42. package/dist/lib/node-esm/{chunk-42UNAKYO.mjs → chunk-XGBUKRCK.mjs} +2 -2
  43. package/dist/lib/node-esm/{chunk-6S45OMUP.mjs → chunk-XIGPWXCQ.mjs} +14 -5
  44. package/dist/lib/node-esm/chunk-XIGPWXCQ.mjs.map +7 -0
  45. package/dist/lib/node-esm/{chunk-JNT72ZCN.mjs → chunk-Y7JKXNDU.mjs} +51 -88
  46. package/dist/lib/node-esm/chunk-Y7JKXNDU.mjs.map +7 -0
  47. package/dist/lib/node-esm/cli/index.mjs +5 -5
  48. package/dist/lib/node-esm/common/activation-events.mjs +3 -3
  49. package/dist/lib/node-esm/common/capabilities.mjs +4 -4
  50. package/dist/lib/node-esm/core/plugin-manager.mjs +2 -2
  51. package/dist/lib/node-esm/core/plugin.mjs +3 -1
  52. package/dist/lib/node-esm/core/url-loader.mjs +2 -2
  53. package/dist/lib/node-esm/index.mjs +13 -14
  54. package/dist/lib/node-esm/index.mjs.map +3 -3
  55. package/dist/lib/node-esm/meta.json +1 -1
  56. package/dist/lib/node-esm/{process-manager-capability-PHKLO2BL.mjs → process-manager-capability-F23D62RN.mjs} +6 -6
  57. package/dist/lib/node-esm/testing/index.mjs +11 -10
  58. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  59. package/dist/lib/node-esm/testing/react.mjs +6 -6
  60. package/dist/lib/node-esm/ui/index.mjs +7 -9
  61. package/dist/plugin/node-esm/index.mjs +155 -77
  62. package/dist/plugin/node-esm/index.mjs.map +4 -4
  63. package/dist/plugin/node-esm/meta.json +1 -1
  64. package/dist/types/src/common/capabilities.d.ts +1 -1
  65. package/dist/types/src/common/index.d.ts +0 -1
  66. package/dist/types/src/common/index.d.ts.map +1 -1
  67. package/dist/types/src/common/translations.d.ts +1 -1
  68. package/dist/types/src/core/capability-manager.d.ts +4 -0
  69. package/dist/types/src/core/capability-manager.d.ts.map +1 -1
  70. package/dist/types/src/core/plugin-manager.d.ts.map +1 -1
  71. package/dist/types/src/core/plugin.d.ts +33 -6
  72. package/dist/types/src/core/plugin.d.ts.map +1 -1
  73. package/dist/types/src/plugin-process-manager/history/history-tracker.d.ts +15 -1
  74. package/dist/types/src/plugin-process-manager/history/history-tracker.d.ts.map +1 -1
  75. package/dist/types/src/plugin-process-manager/history/undo-mapping.d.ts +1 -1
  76. package/dist/types/src/plugin-process-manager/history/undo-mapping.d.ts.map +1 -1
  77. package/dist/types/src/plugin-process-manager/meta.d.ts +1 -1
  78. package/dist/types/src/plugin-process-manager/meta.d.ts.map +1 -1
  79. package/dist/types/src/plugin-process-manager/testing.d.ts.map +1 -1
  80. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  81. package/dist/types/src/ui/components/App/App.d.ts +34 -2
  82. package/dist/types/src/ui/components/App/App.d.ts.map +1 -1
  83. package/dist/types/src/ui/components/App/App.stories.d.ts.map +1 -1
  84. package/dist/types/src/ui/components/PluginManager/PluginManagerContext.stories.d.ts.map +1 -1
  85. package/dist/types/src/ui/components/Surface/types.d.ts.map +1 -1
  86. package/dist/types/src/ui/components/index.d.ts +0 -1
  87. package/dist/types/src/ui/components/index.d.ts.map +1 -1
  88. package/dist/types/src/ui/hooks/useApp.d.ts +1 -7
  89. package/dist/types/src/ui/hooks/useApp.d.ts.map +1 -1
  90. package/dist/types/src/ui/hooks/useCapabilities.d.ts.map +1 -1
  91. package/dist/types/src/ui/hooks/useProcessManagerRuntime.d.ts +6 -0
  92. package/dist/types/src/ui/hooks/useProcessManagerRuntime.d.ts.map +1 -1
  93. package/dist/types/src/vite-plugin/boot-loader/loader.d.ts +26 -23
  94. package/dist/types/src/vite-plugin/boot-loader/loader.d.ts.map +1 -1
  95. package/dist/types/src/vite-plugin/manifest.d.ts.map +1 -1
  96. package/dist/types/tsconfig.tsbuildinfo +1 -1
  97. package/package.json +40 -35
  98. package/src/common/capabilities.ts +1 -1
  99. package/src/common/index.ts +0 -1
  100. package/src/common/translations.ts +1 -1
  101. package/src/core/capability-manager.test.ts +3 -0
  102. package/src/core/capability-manager.ts +22 -1
  103. package/src/core/plugin-manager.test.ts +51 -21
  104. package/src/core/plugin-manager.ts +10 -5
  105. package/src/core/plugin.ts +44 -8
  106. package/src/core/url-loader.test.ts +2 -1
  107. package/src/plugin-process-manager/history/history-tracker.test.ts +39 -60
  108. package/src/plugin-process-manager/history/history-tracker.ts +32 -16
  109. package/src/plugin-process-manager/history/undo-mapping.ts +1 -1
  110. package/src/plugin-process-manager/history/undo-registry.test.ts +3 -1
  111. package/src/plugin-process-manager/meta.ts +6 -4
  112. package/src/plugin-process-manager/testing.ts +6 -5
  113. package/src/testing/react.test.tsx +3 -1
  114. package/src/testing/withPluginManager.tsx +4 -3
  115. package/src/ui/components/App/App.stories.tsx +9 -11
  116. package/src/ui/components/App/App.tsx +80 -17
  117. package/src/ui/components/PluginManager/PluginManagerContext.stories.tsx +9 -14
  118. package/src/ui/components/Surface/SurfaceComponent.stories.tsx +1 -1
  119. package/src/ui/components/Surface/SurfaceComponent.tsx +1 -1
  120. package/src/ui/components/Surface/types.test.ts +2 -2
  121. package/src/ui/components/Surface/types.ts +21 -0
  122. package/src/ui/components/index.ts +0 -1
  123. package/src/ui/hooks/useApp.test.tsx +3 -1
  124. package/src/ui/hooks/useApp.tsx +4 -18
  125. package/src/ui/hooks/useCapabilities.ts +1 -0
  126. package/src/ui/hooks/useProcessManagerRuntime.ts +12 -2
  127. package/src/vite-plugin/boot-loader/BootLoader.solid-stories.tsx +198 -0
  128. package/src/vite-plugin/boot-loader/loader-app/Loader.tsx +166 -0
  129. package/src/vite-plugin/boot-loader/loader-app/boot-loader.css +311 -0
  130. package/src/vite-plugin/boot-loader/loader-app/bridge.ts +25 -0
  131. package/src/vite-plugin/boot-loader/loader-app/entry.tsx +21 -0
  132. package/src/vite-plugin/boot-loader/loader-app/mount.tsx +70 -0
  133. package/src/vite-plugin/boot-loader/loader-app/store.test.ts +137 -0
  134. package/src/vite-plugin/boot-loader/loader-app/store.ts +149 -0
  135. package/src/vite-plugin/boot-loader/loader-app/tsconfig.json +11 -0
  136. package/src/vite-plugin/boot-loader/loader-app/types.ts +78 -0
  137. package/src/vite-plugin/boot-loader/loader.ts +133 -63
  138. package/src/vite-plugin/manifest.test.ts +19 -10
  139. package/src/vite-plugin/manifest.ts +9 -3
  140. package/tsconfig.json +6 -7
  141. package/dist/lib/browser/chunk-BRK6GYNB.mjs.map +0 -7
  142. package/dist/lib/browser/chunk-KFDF7KR3.mjs +0 -42
  143. package/dist/lib/browser/chunk-KFDF7KR3.mjs.map +0 -7
  144. package/dist/lib/browser/chunk-QLML5QFJ.mjs.map +0 -7
  145. package/dist/lib/browser/chunk-SLX73WRZ.mjs.map +0 -7
  146. package/dist/lib/browser/chunk-UVTGHZQF.mjs.map +0 -7
  147. package/dist/lib/browser/chunk-VJ5PFAWC.mjs.map +0 -7
  148. package/dist/lib/node-esm/chunk-6S45OMUP.mjs.map +0 -7
  149. package/dist/lib/node-esm/chunk-BYHYYJZH.mjs.map +0 -7
  150. package/dist/lib/node-esm/chunk-JNT72ZCN.mjs.map +0 -7
  151. package/dist/lib/node-esm/chunk-LJNUFNDO.mjs.map +0 -7
  152. package/dist/lib/node-esm/chunk-OUEMWPIW.mjs +0 -43
  153. package/dist/lib/node-esm/chunk-OUEMWPIW.mjs.map +0 -7
  154. package/dist/lib/node-esm/chunk-SFYCO3PT.mjs.map +0 -7
  155. package/dist/types/src/common/operations.d.ts +0 -19
  156. package/dist/types/src/common/operations.d.ts.map +0 -1
  157. package/dist/types/src/ui/components/Placeholder/Placeholder.d.ts +0 -64
  158. package/dist/types/src/ui/components/Placeholder/Placeholder.d.ts.map +0 -1
  159. package/dist/types/src/ui/components/Placeholder/Placeholder.stories.d.ts +0 -19
  160. package/dist/types/src/ui/components/Placeholder/Placeholder.stories.d.ts.map +0 -1
  161. package/dist/types/src/ui/components/Placeholder/index.d.ts +0 -2
  162. package/dist/types/src/ui/components/Placeholder/index.d.ts.map +0 -1
  163. package/dist/types/src/vite-plugin/boot-loader/BootLoader.stories.d.ts +0 -34
  164. package/dist/types/src/vite-plugin/boot-loader/BootLoader.stories.d.ts.map +0 -1
  165. package/src/common/operations.ts +0 -35
  166. package/src/ui/components/Placeholder/Placeholder.stories.tsx +0 -77
  167. package/src/ui/components/Placeholder/Placeholder.tsx +0 -155
  168. package/src/ui/components/Placeholder/index.ts +0 -5
  169. package/src/vite-plugin/boot-loader/BootLoader.stories.tsx +0 -270
  170. package/src/vite-plugin/boot-loader/boot-loader.css +0 -320
  171. package/src/vite-plugin/boot-loader/boot-loader.js +0 -325
  172. /package/dist/lib/browser/{capability-K5XIVCQU.mjs.map → capability-JCUNWZ66.mjs.map} +0 -0
  173. /package/dist/lib/browser/{chunk-KLHQNYJ2.mjs.map → chunk-KZUDO43J.mjs.map} +0 -0
  174. /package/dist/lib/browser/{process-manager-capability-JIWLN7SU.mjs.map → process-manager-capability-4FUA4TRP.mjs.map} +0 -0
  175. /package/dist/lib/node-esm/{capability-RLKFFLTB.mjs.map → capability-7TCQK7ZP.mjs.map} +0 -0
  176. /package/dist/lib/node-esm/{chunk-42UNAKYO.mjs.map → chunk-XGBUKRCK.mjs.map} +0 -0
  177. /package/dist/lib/node-esm/{process-manager-capability-PHKLO2BL.mjs.map → process-manager-capability-F23D62RN.mjs.map} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/plugin-process-manager/history/errors.ts", "../../../src/plugin-process-manager/history/undo-mapping.ts", "../../../src/plugin-process-manager/history/undo-registry.ts", "../../../src/plugin-process-manager/history/history-tracker.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { BaseError } from '@dxos/errors';\n\nexport class EmptyHistoryError extends BaseError.extend('EmptyHistoryError', 'Cannot undo: history is empty.') {}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport type { Operation } from '@dxos/compute';\n\n/**\n * Label type for translatable text (canonical definition in @dxos/app-toolkit).\n */\ntype Label = string | [string, { ns: string | readonly string[]; count?: number; defaultValue?: string }];\n\n/**\n * Extract the input type from an OperationDefinition.\n */\nexport type InputOf<T> = T extends Operation.Definition<infer I, any> ? I : never;\n\n/**\n * Extract the output type from an OperationDefinition.\n */\nexport type OutputOf<T> = T extends Operation.Definition<any, infer O> ? O : never;\n\n/**\n * Message provider for undo toast.\n * Can be a static Label or a function that derives the message from input/output.\n */\nexport type MessageProvider<Op extends Operation.Definition<any, any>> =\n | Label\n | ((input: InputOf<Op>, output: OutputOf<Op>) => Label);\n\n/**\n * Undo mapping that links a forward operation to its inverse.\n * Type parameters ensure deriveContext has correctly typed arguments.\n *\n * @template Op - The forward operation definition type.\n * @template Inv - The inverse operation definition type.\n */\nexport interface UndoMapping<\n Op extends Operation.Definition<any, any> = Operation.Definition<any, any>,\n Inv extends Operation.Definition<any, any> = Operation.Definition<any, any>,\n> {\n /** The forward operation. */\n readonly operation: Op;\n\n /** The inverse operation to invoke for undo. */\n readonly inverse: Inv;\n\n /**\n * Derives the input for the inverse operation from the forward operation's input and output.\n * @param input - The input that was passed to the forward operation.\n * @param output - The output that was returned by the forward operation.\n * @returns The input to pass to the inverse operation, or undefined to indicate the operation is not undoable.\n */\n readonly deriveContext: (input: InputOf<Op>, output: OutputOf<Op>) => InputOf<Inv> | undefined;\n\n /**\n * Optional message to show in the undo toast.\n * Can be a static Label or a function that derives the message from input/output.\n */\n readonly message?: MessageProvider<Op>;\n}\n\n/**\n * Props for creating an UndoMapping.\n */\nexport interface UndoMappingProps<\n Op extends Operation.Definition<any, any>,\n Inv extends Operation.Definition<any, any>,\n> {\n /** The forward operation. */\n operation: Op;\n\n /** The inverse operation to invoke for undo. */\n inverse: Inv;\n\n /**\n * Derives the input for the inverse operation from the forward operation's input and output.\n * Return undefined to indicate the operation is not undoable.\n */\n deriveContext: (input: InputOf<Op>, output: OutputOf<Op>) => InputOf<Inv> | undefined;\n\n /**\n * Optional message to show in the undo toast.\n * Can be a static Label or a function that derives the message from input/output.\n */\n message?: MessageProvider<Op>;\n}\n\n/**\n * Creates a type-safe undo mapping.\n *\n * @example\n * ```ts\n * // Static message\n * const mapping = UndoMapping.make({\n * operation: DeleteThread,\n * inverse: RestoreThread,\n * deriveContext: (input, output) => ({\n * thread: output.thread,\n * anchor: output.anchor,\n * }),\n * message: ['thread deleted label', { ns: '@dxos/plugin-thread' }],\n * });\n *\n * // Dynamic message based on input/output\n * const mapping = UndoMapping.make({\n * operation: RemoveObjects,\n * inverse: RestoreObjects,\n * deriveContext: (_input, output) => output,\n * message: (input, _output) =>\n * input.objects.length === 1\n * ? ['object deleted label', { ns: getTypename(input.objects[0]) }]\n * : ['objects deleted label', { ns: '@dxos/plugin-space' }],\n * });\n * ```\n */\nexport const make = <Op extends Operation.Definition<any, any>, Inv extends Operation.Definition<any, any>>(\n props: UndoMappingProps<Op, Inv>,\n): UndoMapping<Op, Inv> => props;\n\n/**\n * Resolves a message provider to a Label.\n */\nexport const resolveMessage = <Op extends Operation.Definition<any, any>>(\n message: MessageProvider<Op> | undefined,\n input: InputOf<Op>,\n output: OutputOf<Op>,\n): Label | undefined => {\n if (message === undefined) {\n return undefined;\n }\n if (typeof message === 'function') {\n return message(input, output);\n }\n return message;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport type { Operation } from '@dxos/compute';\n\nimport type * as UndoMapping from './undo-mapping';\n\n//\n// Public Interface\n//\n\n/**\n * Lookup result from UndoRegistry.\n */\nexport type UndoMappingResult = {\n inverse: Operation.Definition<any, any>;\n /** Returns undefined to indicate the operation is not undoable. */\n deriveContext: (input: any, output: any) => any | undefined;\n /** Message provider - may be a static Label or a function. */\n message?: UndoMapping.MessageProvider<Operation.Definition<any, any>>;\n};\n\n/**\n * UndoRegistry interface - looks up inverse operations.\n */\nexport interface UndoRegistry {\n lookup: (operation: Operation.Definition<any, any>) => UndoMappingResult | undefined;\n}\n\n//\n// Factory\n//\n\n/**\n * Creates an UndoRegistry that looks up inverse operations.\n */\nexport const make = (getMappings: () => UndoMapping.UndoMapping[]): UndoRegistry => {\n const lookup = (operation: Operation.Definition<any, any>): UndoMappingResult | undefined => {\n const mappings = getMappings();\n const mapping = mappings.find((m) => m.operation.meta.key === operation.meta.key);\n if (!mapping) {\n return undefined;\n }\n\n return {\n inverse: mapping.inverse,\n deriveContext: mapping.deriveContext,\n message: mapping.message,\n };\n };\n\n return { lookup };\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as PubSub from 'effect/PubSub';\nimport * as Stream from 'effect/Stream';\n\nimport { runAndForwardErrors } from '@dxos/effect';\nimport { log } from '@dxos/log';\nimport { OperationInvoker } from '@dxos/operation';\n\nimport { type Label } from '../../common';\nimport { EmptyHistoryError } from './errors';\nimport type { HistoryEntry } from './types';\nimport { resolveMessage } from './undo-mapping';\nimport type { UndoRegistry } from './undo-registry';\n\nconst HISTORY_LIMIT = 100;\n\n//\n// Public Interface\n//\n\n/**\n * Emitted when a new undoable action is recorded; consumed by the UI to surface an undo affordance\n * (e.g. the deck notification tracker's undo toast).\n */\nexport type UndoableEvent = {\n /** Message describing the undoable action. */\n message?: Label;\n};\n\n/**\n * HistoryTracker interface - tracks operation history and provides undo.\n */\nexport interface HistoryTracker {\n undo: () => Effect.Effect<void, Error>;\n undoPromise: () => Promise<{ error?: Error }>;\n canUndo: () => boolean;\n /** Stream of undoable actions, published as they are recorded. */\n undoable: PubSub.PubSub<UndoableEvent>;\n}\n\n//\n// Factory\n//\n\n/**\n * Creates a HistoryTracker that subscribes to (successful) invocation events, derives undoability from\n * the undo registry, maintains the undo stack, and publishes an {@link UndoableEvent} for each undoable\n * action so the UI can offer an undo affordance. The invoker itself is undo-agnostic.\n */\nexport const make = (\n invoker: OperationInvoker.OperationInvokerInternal,\n undoRegistry: UndoRegistry,\n): HistoryTracker => {\n const history: HistoryEntry[] = [];\n const undoable = Effect.runSync(PubSub.unbounded<UndoableEvent>());\n\n // Record an invocation; returns the undoable event to publish, or undefined if not undoable.\n const recordInvocation = (event: OperationInvoker.InvocationEvent): UndoableEvent | undefined => {\n const mapping = undoRegistry.lookup(event.operation);\n if (!mapping) {\n // Operation is not undoable.\n return undefined;\n }\n\n const inverseInput = mapping.deriveContext(event.input, event.output);\n if (inverseInput === undefined) {\n // Operation is conditionally not undoable (deriveContext returned undefined).\n return undefined;\n }\n\n const entry: HistoryEntry = {\n operation: event.operation,\n input: event.input,\n output: event.output,\n inverse: mapping.inverse,\n inverseInput,\n timestamp: event.timestamp,\n };\n\n history.push(entry);\n log('history entry added', { key: event.operation.meta.key, historyLength: history.length });\n\n // Trim history if it exceeds limit.\n if (history.length > HISTORY_LIMIT) {\n history.splice(0, history.length - HISTORY_LIMIT);\n }\n\n return { message: resolveMessage(mapping.message, event.input, event.output) };\n };\n\n // Fork a fiber to consume the invocation stream.\n Effect.runFork(\n Stream.fromPubSub(invoker.invocations).pipe(\n Stream.runForEach((event) =>\n Effect.gen(function* () {\n const undoableEvent = recordInvocation(event);\n if (undoableEvent) {\n yield* PubSub.publish(undoable, undoableEvent);\n }\n }),\n ),\n ),\n );\n\n const undo = (): Effect.Effect<void, Error> => {\n return Effect.gen(function* () {\n const entry = history.pop();\n if (!entry) {\n return yield* Effect.fail(new EmptyHistoryError());\n }\n\n log('undoing operation', { key: entry.operation.meta.key, inverseKey: entry.inverse.meta.key });\n\n // Use _invokeCore to skip event emission (avoid undo-of-undo loops).\n yield* invoker._invokeCore(entry.inverse, entry.inverseInput);\n\n log('undo completed', { key: entry.operation.meta.key });\n });\n };\n\n const undoPromise = async (): Promise<{ error?: Error }> => {\n return runAndForwardErrors(undo())\n .then(() => ({}))\n .catch((error) => {\n log.catch(error);\n return { error };\n });\n };\n\n const canUndo = (): boolean => {\n return history.length > 0;\n };\n\n return {\n undo,\n undoPromise,\n canUndo,\n undoable,\n };\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["BaseError", "EmptyHistoryError", "extend", "make", "props", "resolveMessage", "message", "input", "output", "undefined", "make", "getMappings", "lookup", "operation", "mappings", "mapping", "find", "m", "meta", "key", "undefined", "inverse", "deriveContext", "message", "make", "Effect", "PubSub", "Stream", "runAndForwardErrors", "log", "HISTORY_LIMIT", "undoable", "Effect", "runSync", "unbounded", "recordInvocation", "event", "undefined", "inverseInput", "entry", "input", "output", "inverse", "mapping", "timestamp", "history", "log", "key", "operation", "historyLength", "length", "undoableEvent", "publish", "undo", "fail", "inverseKey", "invoker", "_invokeCore", "meta", "error", "undoPromise", "canUndo"]
7
+ }
@@ -93,4 +93,4 @@ export {
93
93
  subscribeAtom,
94
94
  capabilities_exports
95
95
  };
96
- //# sourceMappingURL=chunk-PW2VYGOS.mjs.map
96
+ //# sourceMappingURL=chunk-QBUGLR4H.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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 LayerSpec as LayerSpec$,\n Operation as Operation$,\n OperationHandlerSet,\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.plugin-manager',\n);\n\n/**\n * @category Capability\n */\nexport const AtomRegistry = Capability$.make<Registry.Registry>('org.dxos.app-framework.capability.atom-registry');\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.react-context');\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.react-root');\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.common.react-surface');\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.layer-spec');\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.trace-sink');\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, QueueService).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.service-resolver',\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.process-monitor');\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.process-manager-runtime',\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.managed-runtime');\n\n//\n// Operation System Capabilities\n//\n\nexport const OperationHandler = Capability$.make<OperationHandlerSet.OperationHandlerSet>(\n 'org.dxos.app-framework.capability.operation-handler',\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.undo-mapping');\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.operation-invoker',\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.undo-registry');\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.history-tracker');\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(ThreadCapabilities.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(ThreadCapabilities.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(ThreadCapabilities.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"],
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 LayerSpec as LayerSpec$,\n Operation as Operation$,\n OperationHandlerSet,\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.plugin-manager',\n);\n\n/**\n * @category Capability\n */\nexport const AtomRegistry = Capability$.make<Registry.Registry>('org.dxos.app-framework.capability.atom-registry');\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.react-context');\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.react-root');\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.common.react-surface');\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.layer-spec');\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.trace-sink');\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, Feed.FeedService).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.service-resolver',\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.process-monitor');\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.process-manager-runtime',\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.managed-runtime');\n\n//\n// Operation System Capabilities\n//\n\nexport const OperationHandler = Capability$.make<OperationHandlerSet.OperationHandlerSet>(\n 'org.dxos.app-framework.capability.operation-handler',\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.undo-mapping');\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.operation-invoker',\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.undo-registry');\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.history-tracker');\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(ThreadCapabilities.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(ThreadCapabilities.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(ThreadCapabilities.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
5
  "mappings": ";;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,YAAYA,YAAY;AA+BjB,IAAMC,OAAOC,mBAAYC,KAAW,wCAAA;AAKpC,IAAMC,gBAAgBF,mBAAYC,KACvC,kDAAA;AAMK,IAAME,eAAeH,mBAAYC,KAAwB,iDAAA;AAWzD,IAAMG,eAAeJ,mBAAYC,KAAmB,iDAAA;AAOpD,IAAMI,YAAYL,mBAAYC,KAAgB,8CAAA;AAU9C,IAAMK,eAAeN,mBAAYC,KAAmB,6CAAA;AAOpD,IAAMM,UAAUP,mBAAYC,KAAiB,2CAAA;AAK7C,IAAMO,QAAQR,mBAAYC,KAAkC,yCAAA;AAW5D,IAAMQ,YAAYT,mBAAYC,KAA2B,8CAAA;AAmCzD,IAAMS,YAAYV,mBAAYC,KAAuB,8CAAA;AAuBrD,IAAMU,kBAAkBX,mBAAYC,KACzC,oDAAA;AAUK,IAAMW,iBAAiBZ,mBAAYC,KAAuB,mDAAA;AAuC1D,IAAMY,wBAAwBb,mBAAYC,KAC/C,2DAAA;AAQK,IAAMa,iBAAiBd,mBAAYC,KAAqB,mDAAA;AAMxD,IAAMc,mBAAmBf,mBAAYC,KAC1C,qDAAA;AASK,IAAMe,cAAchB,mBAAYC,KAAoB,gDAAA;AAYpD,IAAMgB,mBAAmBjB,mBAAYC,KAC1C,qDAAA;AASK,IAAMiB,eAAelB,mBAAYC,KAAmB,iDAAA;AAQpD,IAAMkB,iBAAiBnB,mBAAYC,KAAqB,mDAAA;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
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
7
  }
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
2
  import {
3
3
  isPlugin
4
- } from "./chunk-6S45OMUP.mjs";
4
+ } from "./chunk-XIGPWXCQ.mjs";
5
5
  import {
6
6
  __export
7
7
  } from "./chunk-HSLMI22Q.mjs";
@@ -420,4 +420,4 @@ export {
420
420
  uninstall,
421
421
  url_loader_exports
422
422
  };
423
- //# sourceMappingURL=chunk-42UNAKYO.mjs.map
423
+ //# sourceMappingURL=chunk-XGBUKRCK.mjs.map
@@ -22,6 +22,7 @@ __export(plugin_exports, {
22
22
  isPluginModule: () => isPluginModule,
23
23
  lazy: () => lazy,
24
24
  make: () => make,
25
+ makeMeta: () => makeMeta,
25
26
  reset: () => reset,
26
27
  resolveLazy: () => resolveLazy,
27
28
  shutdown: () => shutdown
@@ -32,6 +33,7 @@ import * as Option from "effect/Option";
32
33
  import * as Pipeable from "effect/Pipeable";
33
34
  import { BaseError } from "@dxos/errors";
34
35
  import { invariant } from "@dxos/invariant";
36
+ import { DXN } from "@dxos/keys";
35
37
  var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-framework/src/core/plugin.ts";
36
38
  var Service = class extends Context.Tag("@dxos/app-framework/PluginManager")() {
37
39
  };
@@ -60,6 +62,11 @@ var PluginModuleImpl = class {
60
62
  this.activate = options.activate;
61
63
  }
62
64
  };
65
+ var makeMeta = (options) => ({
66
+ ...options,
67
+ id: DXN.getName(options.key),
68
+ version: DXN.getVersion(options.key)
69
+ });
63
70
  var PluginTypeId = /* @__PURE__ */ Symbol.for("@dxos/app-framework/Plugin");
64
71
  var isPlugin = (value) => {
65
72
  return typeof value === "object" && value !== null && PluginTypeId in value;
@@ -106,13 +113,14 @@ function addModule(moduleOptionsOrBuilder, moduleOptions) {
106
113
  }
107
114
  var resolveModule = (meta, module, options) => {
108
115
  const moduleOptions = typeof module === "function" ? module(options) : module;
116
+ const pluginName = meta.id;
109
117
  const id = Option.fromNullable(moduleOptions.id).pipe(Option.match({
110
118
  onNone: () => {
111
119
  const exportName = getModuleTag(moduleOptions.activate);
112
- invariant(exportName, `Plugin module missing name. Plugin: ${meta.id}`, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 131, S: void 0, A: ["exportName", "`Plugin module missing name. Plugin: ${meta.id}`"] });
113
- return computeModuleId(meta.id, exportName);
120
+ 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}`"] });
121
+ return computeModuleId(pluginName, exportName);
114
122
  },
115
- onSome: (id2) => computeModuleId(meta.id, id2)
123
+ onSome: (id2) => computeModuleId(pluginName, id2)
116
124
  }));
117
125
  return new PluginModuleImpl({
118
126
  ...moduleOptions,
@@ -121,7 +129,7 @@ var resolveModule = (meta, module, options) => {
121
129
  };
122
130
  function make(builder) {
123
131
  const meta = builder.meta;
124
- invariant(!meta.dependsOn?.includes(meta.id), `Plugin ${meta.id} declares itself as a dependency.`, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 143, S: this, A: ["!meta.dependsOn?.includes(meta.id)", "`Plugin ${meta.id} declares itself as a dependency.`"] });
132
+ 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.`"] });
125
133
  const factory = (options) => {
126
134
  const modules = builder.modules.map((module) => resolveModule(meta, module, options));
127
135
  return new PluginImpl(meta, modules);
@@ -204,6 +212,7 @@ export {
204
212
  shutdown,
205
213
  PluginModuleTypeId,
206
214
  isPluginModule,
215
+ makeMeta,
207
216
  PluginTypeId,
208
217
  isPlugin,
209
218
  define,
@@ -216,4 +225,4 @@ export {
216
225
  resolveLazy,
217
226
  plugin_exports
218
227
  };
219
- //# sourceMappingURL=chunk-6S45OMUP.mjs.map
228
+ //# sourceMappingURL=chunk-XIGPWXCQ.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';\n\nimport { BaseError } from '@dxos/errors';\nimport { invariant } from '@dxos/invariant';\nimport { DXN } from '@dxos/keys';\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\nexport type Meta = {\n /**\n * Bare NSID (the name portion of {@link key}, e.g. `org.dxos.plugin.example`).\n * Stable across versions; used for module-id namespacing, i18n namespaces,\n * enable/disable, and registry lookups. Derived from `key` by {@link makeMeta} —\n * do not set directly.\n */\n id: string;\n\n /**\n * Canonical identity DXN, including version when published\n * (e.g. `dxn:org.dxos.plugin.example:0.8.3`). The validated source of truth\n * from which {@link id} and {@link version} are derived.\n *\n * @example DXN.make('org.dxos.plugin.example', '0.8.3')\n */\n key: DXN.DXN;\n\n /**\n * Human-readable name.\n */\n name: string;\n\n /**\n * Semver version string of the plugin, typically the publishing package's\n * `package.json` version. Derived from the version segment of {@link key} by\n * {@link makeMeta} — do not set directly.\n */\n version?: string;\n\n /**\n * Short description of plugin functionality.\n */\n description?: string;\n\n /**\n * Name of the author or organization that created the plugin.\n */\n // TODO(burdon): DID or domain name?\n author?: string;\n\n /**\n * URL of home page.\n */\n homePage?: string;\n\n /**\n * URL of source code.\n */\n source?: string;\n\n /**\n * Relative path (inside the published package) to the plugin's bundled MDL\n * specification file — e.g. `'PLUGIN.mdl'` or `'docs/PLUGIN.mdl'`. The file\n * is shipped via the package's `files` entry and resolved by registry\n * surfaces to render an in-app viewer and/or external link.\n */\n spec?: string;\n\n /**\n * URL of screenshot.\n */\n screenshots?: string[];\n\n /**\n * Tags to help categorize the plugin.\n */\n tags?: string[];\n\n /**\n * A grep-able symbol string which can be resolved to an icon asset by @ch-ui/icons, via @ch-ui/vite-plugin-icons.\n */\n icon?: string;\n\n /**\n * Icon hue (ChromaticPalette).\n */\n iconHue?: string;\n\n /**\n * IDs of plugins this plugin functionally depends on.\n *\n * Treated as a convenience by the default `PluginManager` flow:\n * - Enabling this plugin auto-enables the transitive closure of `dependsOn`\n * (installing missing entries from the plugin registry when possible).\n * - Disabling a depended-upon plugin surfaces dependents to the caller; the\n * `PluginManager.disable` API supports an opt-in cascade.\n *\n * Not an invariant: low-level `PluginManager` APIs accept opt-outs\n * (`resolveDependencies: false`, `ignoreDependents: true`) so a caller may\n * substitute an alternative implementation that satisfies the dependent's\n * capability needs in its own way.\n */\n dependsOn?: string[];\n};\n\n/**\n * Options for {@link makeMeta}: a {@link Meta} minus the fields derived from `key`.\n * Identity and version are specified solely through the `key` DXN — `id` and\n * `version` cannot be passed directly.\n */\nexport type MakeMetaOptions = Omit<Meta, 'id' | 'version'>;\n\n/**\n * Constructs a plugin {@link Meta} from a single canonical DXN. The `key` DXN is\n * the one source of truth; `id` (bare NSID) and `version` (semver) are derived\n * from it so each datum has exactly one home and cannot drift out of sync.\n *\n * @example\n * export const meta = Plugin.makeMeta({\n * key: DXN.make('org.dxos.plugin.example', '0.8.3'),\n * name: 'Example',\n * });\n */\nexport const makeMeta = (options: MakeMetaOptions): Meta => ({\n ...options,\n id: DXN.getName(options.key),\n version: DXN.getVersion(options.key),\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.id;\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.id}`);\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 `id` are both bare NSIDs, so compare directly.\n invariant(!meta.dependsOn?.includes(meta.id), `Plugin ${meta.id} declares itself as a dependency.`);\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.id` 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.id`; `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.id;\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.id !== id) {\n return yield* Effect.fail(\n new LazyPluginError({ context: { id, reason: 'meta-mismatch', returnedId: result.meta.id } }),\n );\n }\n return result;\n });\n"],
5
+ "mappings": "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",
6
+ "names": ["Context", "Effect", "Option", "Pipeable", "BaseError", "invariant", "DXN", "PluginModuleImpl", "id", "activatesOn", "firesBeforeActivation", "firesAfterActivation", "activate", "getName", "options", "version", "_meta", "_modules", "meta", "modules", "addModule", "moduleOptions", "pipe", "undefined", "pluginName", "fromNullable", "Option", "onNone", "exportName", "Capability", "getModuleTag", "invariant", "onSome", "computeModuleId", "dependsOn", "builder", "map", "module", "resolveModule", "PluginImpl", "Object", "assign", "factory", "stub", "defineProperty", "value", "loader", "enumerable", "plugin", "mod", "Effect", "try", "catch", "error", "LazyPluginError", "reason", "cause", "context", "result", "fail", "returnedId"]
7
+ }
@@ -3,22 +3,22 @@ import {
3
3
  PluginManagerProvider,
4
4
  topologicalSort,
5
5
  usePluginManager
6
- } from "./chunk-LJNUFNDO.mjs";
6
+ } from "./chunk-GEWHMHM7.mjs";
7
7
  import {
8
8
  PluginManagerContext
9
9
  } from "./chunk-37Z53PXZ.mjs";
10
10
  import {
11
11
  capabilities_exports
12
- } from "./chunk-PW2VYGOS.mjs";
12
+ } from "./chunk-QBUGLR4H.mjs";
13
13
  import {
14
14
  activation_events_exports
15
15
  } from "./chunk-KFZEB6BV.mjs";
16
16
  import {
17
17
  plugin_manager_exports
18
- } from "./chunk-SFYCO3PT.mjs";
18
+ } from "./chunk-4BX2AE47.mjs";
19
19
 
20
20
  // src/ui/components/App/App.tsx
21
- import React2, { useEffect as useEffect3 } from "react";
21
+ import React2, { useEffect as useEffect3, useLayoutEffect } from "react";
22
22
 
23
23
  // src/ui/hooks/useApp.tsx
24
24
  import { RegistryContext } from "@effect-atom/atom-react";
@@ -35,13 +35,13 @@ import { useAsyncEffect, useDefaultValue } from "@dxos/react-hooks";
35
35
  import { ContextProtocolProvider } from "@dxos/web-context-react";
36
36
  var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-framework/src/ui/hooks/useApp.tsx";
37
37
  var ENABLED_KEY = "org.dxos.app-framework.enabled";
38
- var useApp = ({ pluginManager, pluginLoader: pluginLoaderProp, onPluginRemove, pluginRegistryProvider, plugins: pluginsProp, defaults: defaultsProp, setupEvents: setupEventsProp, placeholder, fallback = ErrorFallback, cacheEnabled = false, safeMode = false, debounce = 0, timeout = 3e4 }) => {
38
+ var useApp = ({ pluginManager, pluginLoader: pluginLoaderProp, onPluginRemove, pluginRegistryProvider, plugins: pluginsProp, defaults: defaultsProp, setupEvents: setupEventsProp, fallback = ErrorFallback, cacheEnabled = false, safeMode = false, debounce = 0, timeout = 3e4 }) => {
39
39
  const plugins = useDefaultValue(pluginsProp, () => []);
40
40
  const defaults = useDefaultValue(defaultsProp, () => []);
41
41
  const setupEvents = useDefaultValue(setupEventsProp, () => []);
42
42
  const pluginLoader = useMemo(() => pluginLoaderProp ?? ((id) => Effect.sync(() => {
43
43
  const plugin = plugins.find((plugin2) => plugin2.meta.id === id);
44
- invariant(plugin, `Plugin not found: ${id}`, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 49, S: void 0, A: ["plugin", "`Plugin not found: ${id}`"] });
44
+ invariant(plugin, `Plugin not found: ${id}`, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 48, S: void 0, A: ["plugin", "`Plugin not found: ${id}`"] });
45
45
  return {
46
46
  plugin
47
47
  };
@@ -76,7 +76,7 @@ var useApp = ({ pluginManager, pluginLoader: pluginLoaderProp, onPluginRemove, p
76
76
  });
77
77
  log("useApp: useMemo created/reused manager", {
78
78
  provided: !!pluginManager
79
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 83, S: void 0 });
79
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 82, S: void 0 });
80
80
  return mgr;
81
81
  }, [
82
82
  pluginManager,
@@ -103,7 +103,7 @@ var useApp = ({ pluginManager, pluginLoader: pluginLoaderProp, onPluginRemove, p
103
103
  manager
104
104
  ]);
105
105
  useAsyncEffect(async () => {
106
- log("useApp: effect mount", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 112, S: void 0 });
106
+ log("useApp: effect mount", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 111, S: void 0 });
107
107
  manager.capabilities.contribute({
108
108
  interface: capabilities_exports.PluginManager,
109
109
  implementation: manager,
@@ -176,13 +176,13 @@ var useApp = ({ pluginManager, pluginLoader: pluginLoaderProp, onPluginRemove, p
176
176
  eventsFired: manager.getEventsFired(),
177
177
  activeModules: manager.getActive(),
178
178
  pendingReset: manager.getPendingReset()
179
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 219, S: void 0 });
179
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 218, S: void 0 });
180
180
  void runAndForwardErrors(Fiber.interrupt(fiber));
181
181
  setError(new Error(`Startup timed out after ${timeout}ms`));
182
182
  }
183
183
  }, timeout);
184
184
  return () => {
185
- log("useApp: effect cleanup", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 229, S: void 0 });
185
+ log("useApp: effect cleanup", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 228, S: void 0 });
186
186
  clearTimeout(timeoutId);
187
187
  void runAndForwardErrors(Fiber.interrupt(fiber));
188
188
  if (!isExternalManager) {
@@ -205,7 +205,6 @@ var useApp = ({ pluginManager, pluginLoader: pluginLoaderProp, onPluginRemove, p
205
205
  }, /* @__PURE__ */ React.createElement(RegistryContext.Provider, {
206
206
  value: manager.registry
207
207
  }, /* @__PURE__ */ React.createElement(App, {
208
- placeholder,
209
208
  ready,
210
209
  error,
211
210
  debounce,
@@ -213,7 +212,6 @@ var useApp = ({ pluginManager, pluginLoader: pluginLoaderProp, onPluginRemove, p
213
212
  }))))), [
214
213
  fallback,
215
214
  manager,
216
- placeholder,
217
215
  ready,
218
216
  error
219
217
  ]);
@@ -254,7 +252,7 @@ var useCapabilities = (interfaceDef) => {
254
252
  };
255
253
  var useCapability = (interfaceDef) => {
256
254
  const capabilities = useCapabilities(interfaceDef);
257
- invariant2(capabilities.length > 0, `No capability found for ${interfaceDef.identifier}`, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 22, S: void 0, A: ["capabilities.length > 0", "`No capability found for ${interfaceDef.identifier}`"] });
255
+ invariant2(capabilities.length > 0, `No capability found for ${interfaceDef.identifier}`, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 23, S: void 0, A: ["capabilities.length > 0", "`No capability found for ${interfaceDef.identifier}`"] });
258
256
  return capabilities[0];
259
257
  };
260
258
  var useAtomCapability = (atomCapability) => {
@@ -332,8 +330,9 @@ var useLoading = (ready, debounce = 0) => {
332
330
 
333
331
  // src/ui/hooks/useProcessManagerRuntime.ts
334
332
  import * as Effect2 from "effect/Effect";
333
+ import * as Layer from "effect/Layer";
335
334
  import { use, useCallback as useCallback3, useMemo as useMemo2 } from "react";
336
- import { ServiceResolver } from "@dxos/compute";
335
+ import { Operation, ServiceResolver } from "@dxos/compute";
337
336
  import { unwrapExit } from "@dxos/effect";
338
337
  var useProcessManagerRuntime = () => useCapability(capabilities_exports.ProcessManagerRuntime);
339
338
  var useSpaceCallback = (spaceId, tags, fn, deps) => {
@@ -342,9 +341,11 @@ var useSpaceCallback = (spaceId, tags, fn, deps) => {
342
341
  if (spaceId === void 0) {
343
342
  throw new TypeError("Space not provided to useSpaceCallback");
344
343
  }
345
- const layer = ServiceResolver.provide({
344
+ const layer = Layer.merge(ServiceResolver.provide({
346
345
  space: spaceId
347
- }, ...tags);
346
+ }, ...tags), Operation.withInvocationOptions({
347
+ spaceId
348
+ }));
348
349
  return runtime.runPromise(fn().pipe(Effect2.provide(layer)));
349
350
  }, [
350
351
  runtime,
@@ -394,56 +395,13 @@ var useSettingsState = (atom) => {
394
395
 
395
396
  // src/ui/components/App/App.tsx
396
397
  var FIRST_INTERACTIVE_MARK = "app-framework:first-interactive";
397
- var App = ({ placeholder: Placeholder2, ready, error, debounce, progress }) => {
398
+ var App = ({ ready, error, debounce, progress }) => {
398
399
  const reactContexts = useCapabilities(capabilities_exports.ReactContext);
399
400
  const reactRoots = useCapabilities(capabilities_exports.ReactRoot);
400
401
  const stage = useLoading(ready, debounce);
401
402
  const placeholderDismissed = stage >= LoadingState.Done;
402
403
  useEffect3(() => {
403
- if (!placeholderDismissed) {
404
- return;
405
- }
406
- if (performance.getEntriesByName(FIRST_INTERACTIVE_MARK).length === 0) {
407
- performance.mark(FIRST_INTERACTIVE_MARK);
408
- }
409
- window.__bootLoader?.dismiss?.();
410
- }, [
411
- placeholderDismissed
412
- ]);
413
- if (error) {
414
- throw error;
415
- }
416
- if (!placeholderDismissed) {
417
- if (!Placeholder2) {
418
- return null;
419
- }
420
- return /* @__PURE__ */ React2.createElement(Placeholder2, {
421
- stage,
422
- progress
423
- });
424
- }
425
- const ComposedContext = composeContexts(reactContexts);
426
- return /* @__PURE__ */ React2.createElement(ComposedContext, null, reactRoots.map(({ id, root: Component }) => /* @__PURE__ */ React2.createElement(Component, {
427
- key: id
428
- })));
429
- };
430
- var composeContexts = (contexts) => {
431
- if (contexts.length === 0) {
432
- return ({ children }) => /* @__PURE__ */ React2.createElement(React2.Fragment, null, children);
433
- }
434
- return topologicalSort(contexts).map(({ context }) => context).reduce((Acc, Next) => ({ children }) => /* @__PURE__ */ React2.createElement(Acc, null, /* @__PURE__ */ React2.createElement(Next, null, children)));
435
- };
436
-
437
- // src/ui/components/Placeholder/Placeholder.tsx
438
- import React3, { useEffect as useEffect4, useLayoutEffect, useRef as useRef3 } from "react";
439
- import { ThemeProvider } from "@dxos/react-ui";
440
- import { defaultTx, mx } from "@dxos/ui-theme";
441
- var Placeholder = ({ stage = 1, progress, logo }) => {
442
- if (location.search === "?throw") {
443
- throw new Error("Test error");
444
- }
445
- useEffect4(() => {
446
- if (stage >= 2) {
404
+ if (stage >= LoadingState.FadeOut) {
447
405
  return;
448
406
  }
449
407
  const fraction = progress?.progress ?? 0;
@@ -463,36 +421,42 @@ var Placeholder = ({ stage = 1, progress, logo }) => {
463
421
  progress?.humanizedName
464
422
  ]);
465
423
  useLayoutEffect(() => {
466
- if (stage >= 2) {
467
- window.__bootLoader?.dismiss();
424
+ if (stage >= LoadingState.FadeOut) {
425
+ window.__bootLoader?.ready();
468
426
  }
469
427
  }, [
470
428
  stage
471
429
  ]);
472
- const stageRef = useRef3(stage);
473
- stageRef.current = stage;
474
- useEffect4(() => {
475
- return () => {
476
- if (stageRef.current >= 3) {
477
- window.__bootLoader?.dismiss();
478
- }
479
- };
480
- }, []);
481
- if (stage < 2) {
430
+ useEffect3(() => {
431
+ if (!placeholderDismissed) {
432
+ return;
433
+ }
434
+ if (performance.getEntriesByName(FIRST_INTERACTIVE_MARK).length === 0) {
435
+ performance.mark(FIRST_INTERACTIVE_MARK);
436
+ }
437
+ window.__bootLoader?.dismiss();
438
+ }, [
439
+ placeholderDismissed
440
+ ]);
441
+ if (location.search === "?throw") {
442
+ throw new Error("Test error");
443
+ }
444
+ if (error) {
445
+ throw error;
446
+ }
447
+ if (!placeholderDismissed) {
482
448
  return null;
483
449
  }
484
- const logoClassName = mx("h-[300px] w-[300px] scale-600 transition-all duration-500 ease-in-out filter grayscale opacity-0", stage >= 1 && "scale-100 grayscale-0 opacity-70", stage >= 2 && "scale-50 opacity-0");
485
- return /* @__PURE__ */ React3.createElement(ThemeProvider, {
486
- tx: defaultTx
487
- }, /* @__PURE__ */ React3.createElement("div", {
488
- className: "relative dx-container h-dvh flex flex-col"
489
- }, /* @__PURE__ */ React3.createElement("div", {
490
- className: "flex flex-col grow justify-center items-center"
491
- }, typeof logo === "function" ? logo({
492
- className: logoClassName
493
- }) : logo ? /* @__PURE__ */ React3.createElement("div", {
494
- className: logoClassName
495
- }, logo) : null)));
450
+ const ComposedContext = composeContexts(reactContexts);
451
+ return /* @__PURE__ */ React2.createElement(ComposedContext, null, reactRoots.map(({ id, root: Component }) => /* @__PURE__ */ React2.createElement(Component, {
452
+ key: id
453
+ })));
454
+ };
455
+ var composeContexts = (contexts) => {
456
+ if (contexts.length === 0) {
457
+ return ({ children }) => /* @__PURE__ */ React2.createElement(React2.Fragment, null, children);
458
+ }
459
+ return topologicalSort(contexts).map(({ context }) => context).reduce((Acc, Next) => ({ children }) => /* @__PURE__ */ React2.createElement(Acc, null, /* @__PURE__ */ React2.createElement(Next, null, children)));
496
460
  };
497
461
 
498
462
  export {
@@ -508,7 +472,6 @@ export {
508
472
  useSpaceCallback,
509
473
  useSpaceService,
510
474
  useSettingsState,
511
- App,
512
- Placeholder
475
+ App
513
476
  };
514
- //# sourceMappingURL=chunk-JNT72ZCN.mjs.map
477
+ //# sourceMappingURL=chunk-Y7JKXNDU.mjs.map