@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/core/plugin-manager.ts", "../../../src/core/capability-manager.ts", "../../../src/core/registry.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom, Registry } from '@effect-atom/atom-react';\nimport * as Array from 'effect/Array';\nimport * as Cause from 'effect/Cause';\nimport * as Deferred from 'effect/Deferred';\nimport * as Duration from 'effect/Duration';\nimport * as Effect from 'effect/Effect';\nimport * as Fiber from 'effect/Fiber';\nimport * as Function from 'effect/Function';\nimport * as HashSet from 'effect/HashSet';\nimport * as PubSub from 'effect/PubSub';\nimport * as Ref from 'effect/Ref';\n\nimport { runAndForwardErrors } from '@dxos/effect';\nimport { Performance } from '@dxos/effect';\nimport { BaseError } from '@dxos/errors';\nimport { log } from '@dxos/log';\n\nimport * as ActivationEvent from './activation-event';\nimport * as Capability from './capability';\nimport * as CapabilityManager from './capability-manager';\nimport * as Plugin from './plugin';\n// Imported with a `PluginRegistry` alias because the unrelated `@effect-atom/atom-react`\n// `Registry` is already imported above; from outside this file the namespace is\n// re-exported as `Registry` via `./index.ts`.\nimport * as PluginRegistry from './registry';\n\n/**\n * Tagged error for failures during the constructor-launched core/enabled\n * `enable()` chain. Surfaces via {@link PluginManager.activate}'s wait on\n * `_initialization` so a caller blocked on initialization gets a typed\n * failure (with the original error preserved as `cause`) instead of an\n * untyped `Error`.\n */\nexport class PluginInitializationError extends BaseError.extend(\n 'PluginInitializationError',\n 'Plugin manager initialization failed',\n) {}\n\n/**\n * Tagged error raised when a plugin exceeds its configured load or activation\n * timeout. The plugin manager records the failure on the `failed` atom and\n * auto-disables the plugin so that one stuck remote does not stall app boot.\n * `context.id` is the plugin id, `context.phase` is `'load'` or `'activation'`.\n */\nexport class PluginTimeoutError extends BaseError.extend('PluginTimeoutError', 'Plugin operation timed out') {}\n\n/** Phase of the plugin lifecycle in which the failure was observed. */\nexport type PluginFailurePhase = 'load' | 'activation';\n\n/** Why the plugin entered a failed state. */\nexport type PluginFailureReason = 'timeout' | 'error';\n\n/**\n * Record of a plugin that failed to load or activate. Surfaced via the\n * {@link PluginManager.failed} atom so registry / UI consumers can flag\n * unhealthy plugins (e.g. a remote host that has gone offline) rather than\n * leaving the app in a half-broken state.\n */\nexport type PluginFailure = {\n readonly id: string;\n readonly phase: PluginFailurePhase;\n readonly reason: PluginFailureReason;\n readonly error: Error;\n /** `Date.now()` when the failure was recorded. */\n readonly timestamp: number;\n};\n\n/** Default deadline for resolving a lazy plugin's dynamic import. */\nconst DEFAULT_LOAD_TIMEOUT = Duration.seconds(30);\n\n/** Default deadline for a single module's `activate()` body. */\nconst DEFAULT_ACTIVATION_TIMEOUT = Duration.seconds(30);\n\n/**\n * Identifier denoting a Manager.\n */\nexport const ManagerTypeId: unique symbol = Symbol.for('@dxos/app-framework/Manager');\nexport type ManagerTypeId = typeof ManagerTypeId;\n\n/**\n * Loader result that carries optional metadata about how the plugin was sourced.\n *\n * `dev: true` marks a plugin as session-only and triggers shadow-on-id-collision\n * inside the manager: if a plugin with the same id is already registered (a\n * builtin, or a previously-installed plugin from the registry), the dev plugin\n * temporarily takes over that id slot. The original is restored when the dev\n * plugin is removed (or on page reload, since dev plugins aren't persisted).\n */\nexport type LoadedPlugin = {\n plugin: Plugin.Plugin;\n /** True when the plugin came from a dev source. See type doc for semantics. */\n dev?: boolean;\n};\n\nexport type ManagerOptions = {\n pluginLoader: (id: string) => Effect.Effect<LoadedPlugin, Error>;\n plugins?: Plugin.Plugin[];\n enabled?: string[];\n registry?: Registry.Registry;\n /**\n * Backend for the plugin registry catalog. When omitted the manager exposes a\n * no-op `pluginRegistry` (empty list, no versions endpoint). Implementations\n * live in app-framework alongside the interface (e.g.\n * `EdgeRegistryPluginProvider`); the host app instantiates one and passes it in.\n */\n pluginRegistryProvider?: PluginRegistry.PluginProvider;\n /**\n * Hook called when a plugin is removed via {@link PluginManager.remove}. Used by the\n * host app to clean up persisted state (e.g. evict offline-cached plugin assets).\n * Failures are logged and swallowed; removal still succeeds even if the hook fails.\n */\n onRemove?: (id: string) => Effect.Effect<void, unknown>;\n /**\n * Maximum time allowed for a lazy plugin's dynamic `import()` to resolve.\n * Plugins that exceed this are flagged on the {@link PluginManager.failed}\n * atom and auto-disabled so a stuck remote host can't stall app boot.\n * Defaults to 30 seconds; pass `Duration.infinity` to disable.\n */\n loadTimeout?: Duration.DurationInput;\n /**\n * Maximum time allowed for a single module's `activate()` Effect to settle.\n * Modules that exceed this fail with {@link PluginTimeoutError}; the owning\n * plugin is recorded on `failed` and auto-disabled. Defaults to 30 seconds;\n * pass `Duration.infinity` to disable.\n */\n activationTimeout?: Duration.DurationInput;\n};\n\nexport type ActivationMessage = {\n event: string;\n state: 'activating' | 'activated' | 'error';\n /** Module ID when the message pertains to a specific module activation. */\n module?: string;\n error?: Error;\n};\n\n/**\n * Interface for the Plugin Manager.\n */\nexport interface PluginManager {\n readonly [ManagerTypeId]: ManagerTypeId;\n readonly activation: PubSub.PubSub<ActivationMessage>;\n readonly capabilities: CapabilityManager.CapabilityManager;\n readonly registry: Registry.Registry;\n /**\n * Cached registry catalog state plus pass-throughs for `listVersions` /\n * `getPlugin`. Always present — the host supplies a `pluginRegistryProvider`\n * via {@link ManagerOptions} for real backends, or it falls back to a no-op\n * implementation that yields an empty catalog.\n */\n readonly pluginRegistry: PluginRegistry.Manager;\n\n readonly plugins: Atom.Atom<readonly Plugin.Plugin[]>;\n readonly core: Atom.Atom<readonly string[]>;\n readonly enabled: Atom.Atom<readonly string[]>;\n readonly modules: Atom.Atom<readonly Plugin.PluginModule[]>;\n readonly active: Atom.Atom<readonly string[]>;\n readonly eventsFired: Atom.Atom<readonly string[]>;\n readonly pendingReset: Atom.Atom<readonly string[]>;\n /**\n * Plugins that failed to load or activate. Subscribers (e.g. the registry\n * UI) can use this to flag unhealthy entries; a plugin id appears here at\n * most once with its most recent failure.\n */\n readonly failed: Atom.Atom<readonly PluginFailure[]>;\n /**\n * Ids of currently-registered plugins that came from a dev source (loaded\n * via {@link LoadedPlugin} with `dev: true`). Subscribers can use this to\n * badge dev-overridden plugins or to derive the id of the active dev plugin\n * for an \"uninstall dev plugin\" affordance.\n */\n readonly devPluginIds: Atom.Atom<readonly string[]>;\n\n getPlugins(): readonly Plugin.Plugin[];\n getCore(): readonly string[];\n getEnabled(): readonly string[];\n getModules(): readonly Plugin.PluginModule[];\n getActive(): readonly string[];\n getEventsFired(): readonly string[];\n getPendingReset(): readonly string[];\n getFailed(): readonly PluginFailure[];\n getDevPluginIds(): readonly string[];\n\n /**\n * Clears the failure record for a plugin so it can be retried. Returns\n * whether a failure record existed and was removed.\n */\n clearFailure(id: string): boolean;\n\n /**\n * Loads a plugin via the plugin loader and registers it without enabling it.\n * Returns the loaded plugin so callers can enable it by its canonical id\n * (which may differ from the locator used to load it, e.g. URL loaders).\n */\n add(id: string): Effect.Effect<Plugin.Plugin, Error>;\n\n /**\n * Enables a plugin.\n *\n * Default behavior auto-resolves the plugin's declared `dependsOn` closure:\n * missing entries that exist in the plugin registry catalog are installed via\n * {@link add}, then enabled in dependency-first order. Set `resolveDependencies`\n * to `false` to enable only the named plugin and skip the closure walk\n * entirely — useful when substituting an alternative plugin that satisfies\n * the dependent's capability needs in its own way.\n */\n enable(id: string, opts?: { resolveDependencies?: boolean }): Effect.Effect<boolean, Error>;\n\n /**\n * Removes a plugin from the manager (disables then unregisters).\n *\n * Honors the same cascade option as {@link disable}.\n */\n remove(id: string, opts?: { cascade?: boolean }): Effect.Effect<boolean, Error>;\n\n /**\n * Disables a plugin.\n *\n * By default, cascades to currently-enabled dependents (transitively, leaves\n * first) so disabling a depended-upon plugin never leaves its dependents\n * stranded. Pass `cascade: false` to disable only the named plugin and leave\n * its dependents enabled-but-broken — VS Code-style disable parity for\n * callers that want the escape hatch (e.g. when swapping in an alternative\n * implementation that satisfies the dependents' needs in its own way).\n *\n * Fails with {@link Plugin.PluginDependencyError} (`reason: 'core-dependent'`)\n * when cascading would require disabling a core plugin; UI flows should\n * surface their own confirmation before calling `disable` with the default.\n */\n disable(id: string, opts?: { cascade?: boolean }): Effect.Effect<boolean, Error>;\n\n /**\n * Returns the plugin ids that the given plugin declares as dependencies.\n *\n * Walks `meta.dependsOn` from both registered plugins and the plugin registry\n * catalog so callers can preview the closure for a plugin that isn't yet\n * installed. With `transitive: true` (default), returns the full dependency\n * closure in dependency-first order (deps before dependents). Without it,\n * returns the direct declarations only.\n */\n getDependencies(id: string, opts?: { transitive?: boolean }): readonly string[];\n\n /**\n * Returns the plugin ids that declare the given plugin as a dependency.\n *\n * Walks `meta.dependsOn` over registered plugins. With `transitive: true`\n * (default), returns the full reverse closure. With `enabledOnly: true`,\n * filters to currently-enabled dependents — used by UI flows to preview what\n * a cascading disable would touch.\n */\n getDependents(id: string, opts?: { transitive?: boolean; enabledOnly?: boolean }): readonly string[];\n // TODO(wittjosiah): Improve error typing.\n activate(\n event: ActivationEvent.ActivationEvent | string,\n params?: { before?: string; after?: string },\n ): Effect.Effect<boolean, Error>;\n deactivate(id: string): Effect.Effect<boolean, Error>;\n reset(event: ActivationEvent.ActivationEvent | string): Effect.Effect<boolean, Error>;\n\n /**\n * Shuts down the manager by deactivating all active modules in reverse activation order,\n * clearing all capabilities, and resetting lifecycle bookkeeping.\n * Plugins, core, enabled, and modules remain intact so the manager can be reused.\n */\n shutdown(): Effect.Effect<boolean, Error>;\n}\n\n/**\n * Type guard to check if a value is a PluginManager.\n */\nexport const isManager = (value: unknown): value is PluginManager => {\n return typeof value === 'object' && value !== null && ManagerTypeId in value;\n};\n\n/**\n * Internal implementation of PluginManager.\n */\nclass ManagerImpl implements PluginManager {\n readonly [ManagerTypeId]: ManagerTypeId = ManagerTypeId;\n readonly activation = Effect.runSync(PubSub.unbounded<ActivationMessage>());\n readonly capabilities: CapabilityManager.CapabilityManager;\n readonly registry: Registry.Registry;\n readonly pluginRegistry: PluginRegistry.Manager;\n\n private readonly _pluginsAtom: Atom.Writable<Plugin.Plugin[]>;\n private readonly _coreAtom: Atom.Writable<string[]>;\n private readonly _enabledAtom: Atom.Writable<string[]>;\n private readonly _modulesAtom: Atom.Writable<Plugin.PluginModule[]>;\n private readonly _activeAtom: Atom.Writable<string[]>;\n private readonly _eventsFiredAtom: Atom.Writable<string[]>;\n private readonly _pendingResetAtom: Atom.Writable<string[]>;\n private readonly _failedAtom: Atom.Writable<PluginFailure[]>;\n private readonly _pluginLoader: ManagerOptions['pluginLoader'];\n private readonly _onRemove: ManagerOptions['onRemove'];\n private readonly _loadTimeout: Duration.DurationInput;\n private readonly _activationTimeout: Duration.DurationInput;\n private readonly _capabilities = new Map<string, Capability.Any[]>();\n private readonly _moduleMemoMap = new Map<Plugin.PluginModule['id'], Deferred.Deferred<Capability.Any[], Error>>();\n private readonly _moduleSemaphores = new Map<Plugin.PluginModule['id'], Effect.Semaphore>();\n // Coalesces concurrent `_resolveLazyPlugin` calls per plugin id. Without\n // this, two callers entering `enable(id)` before the swap completes would\n // each invoke `mod.default(options)` and produce distinct module objects,\n // defeating `_addModule`'s reference-equality dedupe and racing the\n // `_pluginsAtom` swap.\n private readonly _resolvingPlugins = new Map<string, Deferred.Deferred<Plugin.Plugin, Plugin.LazyPluginError>>();\n // Tracks dev-source plugins (loaded via a Vite dev server) keyed by id.\n // When `shadow` is present, the entry has displaced an existing plugin —\n // `remove` reinstates it and re-enables iff `wasEnabled`. Entries without a\n // shadow are dev plugins with no underlying registry/builtin to restore.\n // The atom mirrors the map's keys for UI subscribers (they don't need the\n // shadow internals); the two stay in sync via {@link _markDev}/{@link _unmarkDev}.\n private readonly _devPlugins = new Map<string, { shadow?: { plugin: Plugin.Plugin; wasEnabled: boolean } }>();\n private readonly _devPluginIdsAtom: Atom.Writable<string[]>;\n private readonly _activatingEvents = Effect.runSync(Ref.make<string[]>([]));\n private readonly _activatingModules = Effect.runSync(Ref.make<string[]>([]));\n private readonly _inFlightFibers = Effect.runSync(Ref.make<Array<Fiber.Fiber<unknown, unknown>>>([]));\n private readonly _shutdownSemaphore = Effect.runSync(Effect.makeSemaphore(1));\n private readonly _shuttingDown = Effect.runSync(Ref.make(false));\n // Tracks the constructor-launched core/enabled `enable()` calls so that\n // `activate` can wait for module registration before dispatching events.\n // Lazy plugins make `enable` asynchronous (a dynamic `import()` happens\n // inside it), so without this synchronization an `activate` triggered\n // immediately after `make` could fire on an empty module set. Failures\n // are wrapped in `PluginInitializationError` so awaiters get a tagged\n // error rather than the wide `Error` produced by the underlying chain.\n private readonly _initialization = Effect.runSync(Deferred.make<void, PluginInitializationError>());\n\n constructor({\n pluginLoader,\n plugins = [],\n enabled = [],\n registry,\n pluginRegistryProvider,\n onRemove,\n loadTimeout = DEFAULT_LOAD_TIMEOUT,\n activationTimeout = DEFAULT_ACTIVATION_TIMEOUT,\n }: ManagerOptions) {\n // Core plugins are derived from `meta.tags.includes('system')`; the set is\n // a snapshot of the initial `plugins` array (later `add()` calls do not\n // promote plugins to core).\n const core: string[] = plugins.filter(({ meta }) => meta.tags?.includes('system')).map(({ meta }) => meta.id);\n this.registry = registry ?? Registry.make();\n this.capabilities = CapabilityManager.make({\n registry: this.registry,\n });\n this.pluginRegistry = new PluginRegistry.Manager(pluginRegistryProvider, this.registry);\n\n this._pluginLoader = pluginLoader;\n this._onRemove = onRemove;\n this._loadTimeout = loadTimeout;\n this._activationTimeout = activationTimeout;\n this._pluginsAtom = Atom.make(plugins).pipe(Atom.keepAlive);\n this._coreAtom = Atom.make(core).pipe(Atom.keepAlive);\n this._enabledAtom = Atom.make(enabled).pipe(Atom.keepAlive);\n this._modulesAtom = Atom.make<Plugin.PluginModule[]>([]).pipe(Atom.keepAlive);\n this._activeAtom = Atom.make<string[]>([]).pipe(Atom.keepAlive);\n this._eventsFiredAtom = Atom.make<string[]>([]).pipe(Atom.keepAlive);\n this._pendingResetAtom = Atom.make<string[]>([]).pipe(Atom.keepAlive);\n this._failedAtom = Atom.make<PluginFailure[]>([]).pipe(Atom.keepAlive);\n this._devPluginIdsAtom = Atom.make<string[]>([]).pipe(Atom.keepAlive);\n plugins.forEach((plugin) => this._addPlugin(plugin));\n // Dedupe before mapping to `enable` — `core` and `enabled` may overlap (an\n // app-supplied plugin can be in both), and concurrent `enable(id)` calls\n // for the same id are not idempotent (each would re-run the lazy resolve\n // and double-register modules). `new Set([...])` preserves first-seen\n // order which matches the natural core-before-enabled precedence.\n const initialIds = [...new Set([...core, ...enabled])];\n void Effect.all(initialIds.map((id) => this.enable(id)))\n .pipe(\n Effect.mapError((cause) => new PluginInitializationError({ cause })),\n Effect.tap(() => Deferred.succeed(this._initialization, undefined)),\n Effect.tapErrorCause((cause) => Deferred.failCause(this._initialization, cause)),\n )\n .pipe(runAndForwardErrors);\n }\n\n get plugins(): Atom.Atom<readonly Plugin.Plugin[]> {\n return this._pluginsAtom;\n }\n\n get core(): Atom.Atom<readonly string[]> {\n return this._coreAtom;\n }\n\n /**\n * Ids of plugins that are currently enabled.\n */\n get enabled(): Atom.Atom<readonly string[]> {\n return this._enabledAtom;\n }\n\n /**\n * Modules of plugins which are currently enabled.\n */\n get modules(): Atom.Atom<readonly Plugin.PluginModule[]> {\n return this._modulesAtom;\n }\n\n /**\n * Ids of modules which are currently active.\n */\n get active(): Atom.Atom<readonly string[]> {\n return this._activeAtom;\n }\n\n /**\n * Ids of events which have been fired.\n */\n get eventsFired(): Atom.Atom<readonly string[]> {\n return this._eventsFiredAtom;\n }\n\n /**\n * Ids of modules which are pending reset.\n */\n get pendingReset(): Atom.Atom<readonly string[]> {\n return this._pendingResetAtom;\n }\n\n /**\n * Plugins that failed to load or activate.\n */\n get failed(): Atom.Atom<readonly PluginFailure[]> {\n return this._failedAtom;\n }\n\n /**\n * Ids of currently-registered plugins that came from a dev source.\n */\n get devPluginIds(): Atom.Atom<readonly string[]> {\n return this._devPluginIdsAtom;\n }\n\n getPlugins(): readonly Plugin.Plugin[] {\n return this._get(this._pluginsAtom);\n }\n\n getCore(): readonly string[] {\n return this._get(this._coreAtom);\n }\n\n getEnabled(): readonly string[] {\n return this._get(this._enabledAtom);\n }\n\n getModules(): readonly Plugin.PluginModule[] {\n return this._get(this._modulesAtom);\n }\n\n getActive(): readonly string[] {\n return this._get(this._activeAtom);\n }\n\n getEventsFired(): readonly string[] {\n return this._get(this._eventsFiredAtom);\n }\n\n getPendingReset(): readonly string[] {\n return this._get(this._pendingResetAtom);\n }\n\n getFailed(): readonly PluginFailure[] {\n return this._get(this._failedAtom);\n }\n\n getDevPluginIds(): readonly string[] {\n return this._get(this._devPluginIdsAtom);\n }\n\n /**\n * Marks `id` as dev-sourced. If the plugin displaced an existing one, pass\n * the shadow snapshot so `remove` can restore it. Repeat calls (e.g. a dev\n * plugin reload) preserve the original shadow target — restoration always\n * unwinds back to the real underlying plugin, never an intermediate dev build.\n */\n private _markDev(id: string, shadow?: { plugin: Plugin.Plugin; wasEnabled: boolean }): void {\n if (this._devPlugins.has(id)) {\n return;\n }\n this._devPlugins.set(id, { shadow });\n this._update(this._devPluginIdsAtom, (ids) => (ids.includes(id) ? ids : [...ids, id]));\n }\n\n /** Drops the dev-plugin entry and returns its shadow data (if any) for restoration. */\n private _unmarkDev(id: string): { plugin: Plugin.Plugin; wasEnabled: boolean } | undefined {\n const entry = this._devPlugins.get(id);\n this._devPlugins.delete(id);\n this._update(this._devPluginIdsAtom, (ids) => ids.filter((existing) => existing !== id));\n return entry?.shadow;\n }\n\n getDependencies(id: string, opts?: { transitive?: boolean }): readonly string[] {\n const transitive = opts?.transitive !== false;\n if (!transitive) {\n return this._directDependencies(id);\n }\n const walk = this._computeDependencyClosure(id);\n // Drop the target itself; callers asked for its dependencies, not the\n // closure including the root.\n return walk.order.filter((depId) => depId !== id);\n }\n\n getDependents(id: string, opts?: { transitive?: boolean; enabledOnly?: boolean }): readonly string[] {\n return this._collectDependents(id, {\n transitive: opts?.transitive !== false,\n enabledOnly: opts?.enabledOnly === true,\n });\n }\n\n clearFailure(id: string): boolean {\n const current = this._get(this._failedAtom);\n if (!current.some((failure) => failure.id === id)) {\n return false;\n }\n this._set(\n this._failedAtom,\n current.filter((failure) => failure.id !== id),\n );\n return true;\n }\n\n /**\n * Adds a plugin to the manager via the plugin loader.\n * The plugin is registered but not enabled; call `enable` separately to activate it.\n * @param id The id of the plugin.\n */\n add(id: string): Effect.Effect<Plugin.Plugin, Error> {\n return Effect.gen(this, function* () {\n log('add plugin', { id });\n const { plugin, dev = false } = yield* this._pluginLoader(id);\n const pluginId = plugin.meta.id;\n const existing = this._getPlugin(pluginId);\n\n if (dev && existing && existing !== plugin) {\n // Shadow path: a plugin with this id is already registered (a builtin,\n // a registry install, or a previous dev load). Disable it, stash it,\n // and swap the dev plugin into the same id slot. The dialog will call\n // `enable(pluginId)` next, which activates the dev plugin's modules.\n // `_markDev` is a no-op when the id is already tracked, so a dev-plugin\n // reload (after editing source) keeps the *original* shadow target —\n // removal restores the real underlying plugin, not an intermediate build.\n const wasEnabled = this._get(this._enabledAtom).includes(pluginId);\n if (wasEnabled) {\n yield* this.disable(pluginId);\n }\n this._markDev(pluginId, { plugin: existing, wasEnabled });\n this._update(this._pluginsAtom, (plugins) => plugins.map((p) => (p.meta.id === pluginId ? plugin : p)));\n } else {\n this._addPlugin(plugin);\n if (dev) {\n this._markDev(pluginId);\n }\n }\n\n return plugin;\n });\n }\n\n /**\n * Enables a plugin.\n * @param id The id of the plugin.\n * @param opts See {@link PluginManager.enable}.\n */\n enable(id: string, opts?: { resolveDependencies?: boolean }): Effect.Effect<boolean, Error> {\n const resolveDependencies = opts?.resolveDependencies !== false;\n return Effect.gen(this, function* () {\n log('enable plugin', { id, resolveDependencies });\n\n if (!resolveDependencies) {\n return yield* this._enableOne(id);\n }\n\n // If the root id is unknown to both the registered set and the catalog,\n // fall back to the silent `_enableOne` path (which returns `false`).\n // This preserves the prior contract for persisted `enabled` entries\n // whose plugins are no longer bundled, instead of recording a confusing\n // \"missing self-dependency\" failure.\n if (!this._getPlugin(id) && !this._getCatalogEntry(id)) {\n return yield* this._enableOne(id);\n }\n\n // Compute the transitive closure across registered plugins and catalog\n // entries. Missing or cyclic entries are recorded as failures and the\n // target plugin is left disabled.\n const walk = this._computeDependencyClosure(id);\n if (walk.cycle) {\n this._recordFailure(\n id,\n 'load',\n new Plugin.PluginDependencyError({ context: { id, reason: 'cycle', path: walk.cycle } }),\n );\n return false;\n }\n if (walk.missing.length > 0) {\n this._recordFailure(\n id,\n 'load',\n new Plugin.PluginDependencyError({ context: { id, reason: 'missing', missing: walk.missing } }),\n );\n return false;\n }\n\n // Install any catalog-only entries before enabling them. `add` may also\n // discover further declared deps once the plugin's real meta is loaded;\n // we re-walk after each install to absorb those.\n let queue = walk.toInstall.slice();\n const installed = new Set<string>();\n while (queue.length > 0) {\n const next = queue.shift()!;\n if (installed.has(next) || this._getPlugin(next)) {\n continue;\n }\n const installResult = yield* this.add(next).pipe(Effect.either);\n if (installResult._tag === 'Left') {\n this._recordFailure(\n id,\n 'load',\n new Plugin.PluginDependencyError({\n context: { id, reason: 'install-failed', dependency: next },\n cause: installResult.left,\n }),\n );\n return false;\n }\n installed.add(next);\n const rewalk = this._computeDependencyClosure(id);\n if (rewalk.cycle) {\n this._recordFailure(\n id,\n 'load',\n new Plugin.PluginDependencyError({ context: { id, reason: 'cycle', path: rewalk.cycle } }),\n );\n return false;\n }\n if (rewalk.missing.length > 0) {\n this._recordFailure(\n id,\n 'load',\n new Plugin.PluginDependencyError({ context: { id, reason: 'missing', missing: rewalk.missing } }),\n );\n return false;\n }\n queue = rewalk.toInstall.filter((depId) => !installed.has(depId));\n }\n\n // Enable in dependency-first order. `_enableOne` is idempotent on the\n // enabled atom so previously-enabled deps short-circuit.\n const order = this._computeDependencyClosure(id).order;\n let succeeded = false;\n for (const depId of order) {\n const ok = yield* this._enableOne(depId);\n if (depId === id) {\n succeeded = ok;\n }\n }\n return succeeded;\n });\n }\n\n /**\n * Enables a single plugin without consulting its declared dependencies.\n * Used by {@link enable} as the leaf step after closure resolution, and\n * directly when callers pass `{ resolveDependencies: false }`.\n *\n * The underlying operations (`_addModule`, `_setPendingResetByModule`,\n * `activate`) are all idempotent, so this method is safe to call multiple\n * times for the same id. The constructor's bootstrap path relies on this:\n * the persisted `enabled` ids are written into `_enabledAtom` up front, so\n * the very first `enable(id)` for those plugins sees `alreadyEnabled`-style\n * state but still needs to perform the module registration and activation.\n */\n private _enableOne(id: string): Effect.Effect<boolean, Error> {\n return Effect.gen(this, function* () {\n const stub = this._getPlugin(id);\n if (!stub) {\n return false;\n }\n\n // Clear any prior failure record so a retry starts from a clean slate.\n // The failure stays on the atom only if this attempt also fails.\n this.clearFailure(id);\n\n const plugin = yield* this._resolveLazyPlugin(stub);\n\n this._update(this._enabledAtom, (enabled) => (enabled.includes(id) ? enabled : [...enabled, id]));\n\n plugin.modules.forEach((module) => {\n this._addModule(module);\n this._setPendingResetByModule(module);\n });\n\n log('pending reset', { events: [...this.getPendingReset()] });\n yield* Effect.all(\n this.getPendingReset().map((event) => this.activate(event)),\n { concurrency: 'unbounded' },\n );\n\n return true;\n });\n }\n\n /**\n * Resolves a lazy plugin stub (returned by {@link Plugin.lazy}) to its\n * loaded form and swaps it into `_pluginsAtom`. Returns the input unchanged\n * when the plugin is already resolved, so callers can `yield*` this\n * unconditionally. The lazy stub carries `meta` synchronously but its\n * `modules` list is empty until the loader resolves; the swap ensures\n * subsequent enable/disable operations see the resolved plugin.\n *\n * Concurrent calls for the same id are coalesced via `_resolvingPlugins`:\n * the first caller starts the resolution, every subsequent caller awaits\n * the same `Deferred`. On failure we publish a `lazy:<id>` error message\n * and skip the atom swap so the failure is observable to the activation\n * subscriber and a retry can be attempted.\n */\n private _resolveLazyPlugin(plugin: Plugin.Plugin): Effect.Effect<Plugin.Plugin, Plugin.LazyPluginError> {\n return Effect.gen(this, function* () {\n if (!Plugin.isLazy(plugin)) {\n return plugin;\n }\n const id = plugin.meta.id;\n\n const existing = this._resolvingPlugins.get(id);\n if (existing) {\n return yield* Deferred.await(existing);\n }\n const deferred = yield* Deferred.make<Plugin.Plugin, Plugin.LazyPluginError>();\n this._resolvingPlugins.set(id, deferred);\n\n return yield* Effect.gen(this, function* () {\n log('resolving lazy plugin', { id });\n yield* PubSub.publish(this.activation, { event: '', state: 'activating', module: `lazy:${id}` });\n const resolvedPlugin = yield* Plugin.resolveLazy(plugin).pipe(\n // Cap how long a remote import can hang. Without this the host can\n // sit on a pending dynamic `import()` indefinitely if the plugin's\n // server is unreachable, which stalls every caller awaiting\n // `enable(id)` and (transitively) the manager's initialization.\n Effect.timeoutFail({\n duration: this._loadTimeout,\n onTimeout: () =>\n new Plugin.LazyPluginError({\n context: { id, reason: 'load-failed' },\n cause: new PluginTimeoutError({ context: { id, phase: 'load' as PluginFailurePhase } }),\n }),\n }),\n );\n this._update(this._pluginsAtom, (plugins) => plugins.map((p) => (p.meta.id === id ? resolvedPlugin : p)));\n yield* PubSub.publish(this.activation, { event: '', state: 'activated', module: `lazy:${id}` });\n return resolvedPlugin;\n }).pipe(\n Effect.tapError((error) =>\n Effect.gen(this, function* () {\n yield* PubSub.publish(this.activation, { event: '', state: 'error', module: `lazy:${id}`, error });\n this._recordFailure(id, 'load', error);\n this._scheduleAutoDisable(id);\n }),\n ),\n Effect.tap((value) => Deferred.succeed(deferred, value)),\n Effect.tapErrorCause((cause) => Deferred.failCause(deferred, cause)),\n Effect.ensuring(Effect.sync(() => this._resolvingPlugins.delete(id))),\n );\n });\n }\n\n /**\n * Removes a plugin from the manager.\n * @param id The id of the plugin.\n * @param opts See {@link PluginManager.remove}.\n */\n remove(id: string, opts?: { cascade?: boolean }): Effect.Effect<boolean, Error> {\n return Effect.gen(this, function* () {\n log('remove plugin', { id });\n const wasDev = this._devPlugins.has(id);\n const disabled = yield* this.disable(id, opts);\n if (!disabled) {\n return false;\n }\n\n this._removePlugin(id);\n if (this._onRemove) {\n this._runForkedFiber(\n this._onRemove(id).pipe(\n Effect.tapError((error) => Effect.sync(() => log.warn('plugin remove hook failed', { id, error }))),\n Effect.ignore,\n ),\n );\n }\n\n // If a dev plugin was shadowing an existing plugin, reinstate the\n // original now that the dev plugin is gone. Re-enable only if the\n // original was enabled at shadow time — preserving the user's intent\n // for plugins they had explicitly disabled before iterating on a dev\n // build.\n if (wasDev) {\n const shadow = this._unmarkDev(id);\n if (shadow) {\n this._addPlugin(shadow.plugin);\n if (shadow.wasEnabled) {\n yield* this.enable(id);\n }\n }\n }\n return true;\n });\n }\n\n /**\n * Disables a plugin.\n * @param id The id of the plugin.\n * @param opts See {@link PluginManager.disable}.\n */\n disable(id: string, { cascade = true }: { cascade?: boolean } = {}): Effect.Effect<boolean, Error> {\n return Effect.gen(this, function* () {\n log('disable plugin', { id, cascade });\n if (this._get(this._coreAtom).includes(id)) {\n return false;\n }\n\n const plugin = this._getPlugin(id);\n if (!plugin) {\n return false;\n }\n\n if (cascade) {\n const enabledDependents = this._collectDependents(id, { transitive: true, enabledOnly: true });\n if (enabledDependents.length > 0) {\n const coreDependent = enabledDependents.find((dependentId) =>\n this._get(this._coreAtom).includes(dependentId),\n );\n if (coreDependent) {\n return yield* Effect.fail(\n new Plugin.PluginDependencyError({\n context: { id, reason: 'core-dependent', coreDependent },\n }),\n );\n }\n // Disable transitive dependents first (leaves before root). The\n // walk returns them in dependents-before-deps order — exactly what\n // we want for teardown.\n for (const dependentId of enabledDependents) {\n yield* this._disableOne(dependentId);\n }\n }\n }\n\n yield* this._disableOne(id);\n return true;\n });\n }\n\n /**\n * Disables a single plugin without consulting its dependents. Used by\n * {@link disable} after the dependents pass has run (or been skipped via\n * `cascade: false`).\n */\n private _disableOne(id: string): Effect.Effect<boolean, Error> {\n return Effect.gen(this, function* () {\n if (this._get(this._coreAtom).includes(id)) {\n return false;\n }\n const plugin = this._getPlugin(id);\n if (!plugin) {\n return false;\n }\n const enabledIndex = this._get(this._enabledAtom).findIndex((enabled) => enabled === id);\n if (enabledIndex !== -1) {\n this._update(this._enabledAtom, (enabled) => enabled.filter((item) => item !== id));\n yield* this.deactivate(id);\n plugin.modules.forEach((module) => {\n this._removeModule(module.id);\n });\n }\n return true;\n });\n }\n\n /**\n * Activates plugins based on the activation event.\n * @param event The activation event.\n * @returns Whether the activation was successful.\n */\n activate(\n event: ActivationEvent.ActivationEvent | string,\n params?: { before?: string; after?: string },\n ): Effect.Effect<boolean, Error> {\n const key = typeof event === 'string' ? event : ActivationEvent.eventKey(event);\n return Effect.gen(this, function* () {\n if (yield* this._isShuttingDown()) {\n log('skipping activation during shutdown', { key, ...params });\n return false;\n }\n\n // Wait for the constructor's core/enabled `enable()` chain — including\n // any async dynamic imports for lazy plugins — to finish registering\n // modules. Without this, dispatching to an empty module set is the\n // observable symptom of the race.\n yield* Deferred.await(this._initialization);\n\n return yield* Effect.withFiberRuntime<boolean, Error>((fiber) =>\n this._activateEvent(key, params, fiber).pipe(\n together(\n Effect.sleep(Duration.seconds(15)).pipe(\n Effect.andThen(Effect.sync(() => log.warn('event activation is taking a long time', { event: key }))),\n ),\n ),\n Performance.addTrackEntry({\n name: typeof event === 'string' ? event : ActivationEvent.eventKey(event),\n devtools: {\n dataType: 'track-entry',\n track: 'Event Activation',\n trackGroup: 'Composer',\n color: 'primary',\n },\n }),\n ),\n );\n });\n }\n\n /**\n * Deactivates all of the modules for a plugin.\n * @param id The id of the plugin.\n * @returns Whether the deactivation was successful.\n */\n deactivate(id: string): Effect.Effect<boolean, Error> {\n return Effect.gen(this, function* () {\n const plugin = this._getPlugin(id);\n if (!plugin) {\n return false;\n }\n\n const modules = plugin.modules;\n const results = yield* Effect.all(\n modules.map((module) => this._deactivateModule(module)),\n { concurrency: 'unbounded' },\n );\n return results.every((result) => result);\n });\n }\n\n /**\n * Re-activates the modules that were activated by the event.\n * @param event The activation event.\n * @returns Whether the reset was successful.\n */\n reset(event: ActivationEvent.ActivationEvent | string): Effect.Effect<boolean, Error> {\n return Effect.gen(this, function* () {\n const key = typeof event === 'string' ? event : ActivationEvent.eventKey(event);\n log('reset', { key });\n const modules = this._getActiveModulesByEvent(key);\n const results = yield* Effect.all(\n modules.map((module) => this._deactivateModule(module)),\n { concurrency: 'unbounded' },\n );\n\n if (results.every((result) => result)) {\n return yield* this.activate(key);\n } else {\n return false;\n }\n });\n }\n\n shutdown(): Effect.Effect<boolean, Error> {\n return this._shutdownSemaphore.withPermits(1)(\n Effect.gen(this, function* () {\n yield* Ref.set(this._shuttingDown, true);\n log('shutdown');\n\n yield* this._interruptInFlightActivations();\n\n const activeIds = [...this._get(this._activeAtom)].reverse();\n const allModules = this._get(this._modulesAtom);\n const modulesToDeactivate = activeIds\n .map((id) => allModules.find((module) => module.id === id))\n .filter((module): module is Plugin.PluginModule => module != null);\n\n for (const module of modulesToDeactivate) {\n yield* this._deactivateModule(module);\n }\n\n this._set(this._eventsFiredAtom, []);\n this._set(this._pendingResetAtom, []);\n this._moduleMemoMap.clear();\n yield* Ref.set(this._activatingEvents, []);\n yield* Ref.set(this._activatingModules, []);\n\n log('shutdown complete');\n return true;\n }).pipe(Effect.ensuring(Ref.set(this._shuttingDown, false))),\n );\n }\n\n //\n // State helpers\n //\n\n private _get<T>(atom: Atom.Atom<T>): T {\n return this.registry.get(atom);\n }\n\n private _set<T>(atom: Atom.Writable<T>, value: T): void {\n this.registry.set(atom, value);\n }\n\n private _update<T>(atom: Atom.Writable<T>, updater: (current: T) => T): void {\n this._set(atom, updater(this._get(atom)));\n }\n\n private _isShuttingDown(): Effect.Effect<boolean> {\n return Ref.get(this._shuttingDown);\n }\n\n private _getPlugin(id: string): Plugin.Plugin | undefined {\n return this._get(this._pluginsAtom).find((plugin) => plugin.meta.id === id);\n }\n\n private _getPluginIdForModule(moduleId: string): string | undefined {\n return this._get(this._pluginsAtom).find((plugin) => plugin.modules.some((module) => module.id === moduleId))?.meta\n .id;\n }\n\n /** Looks up an id in the cached registry catalog, returning the entry or `undefined`. */\n private _getCatalogEntry(id: string): PluginRegistry.Plugin | undefined {\n return this._get(this.pluginRegistry.plugins).entries.find((entry) => entry.id === id);\n }\n\n /**\n * Returns the direct `dependsOn` declarations for an id, drawing from the\n * registered plugin's meta when available and falling back to the registry\n * catalog entry. Unknown ids return an empty list (callers detect \"missing\"\n * separately).\n */\n private _directDependencies(id: string): string[] {\n const plugin = this._getPlugin(id);\n if (plugin) {\n return [...(plugin.meta.dependsOn ?? [])];\n }\n const catalog = this._getCatalogEntry(id);\n return catalog?.dependsOn ? [...catalog.dependsOn] : [];\n }\n\n /**\n * Computes the transitive dependency closure for an id.\n *\n * Walks {@link _directDependencies} (registered plugins ∪ catalog entries).\n * Returns:\n * - `order`: closure including the root in dependency-first topological order.\n * - `missing`: ids in the closure that are neither registered nor in the catalog.\n * - `toInstall`: ids in the closure that are in the catalog but not yet registered.\n * - `cycle`: when a cycle is detected, the cycle path; otherwise `undefined`.\n */\n private _computeDependencyClosure(id: string): {\n order: string[];\n missing: string[];\n toInstall: string[];\n cycle?: string[];\n } {\n const order: string[] = [];\n const visited = new Set<string>();\n const onStack = new Set<string>();\n const stackPath: string[] = [];\n const missing: string[] = [];\n const toInstall: string[] = [];\n let cycle: string[] | undefined;\n\n const knownIds = new Set<string>([\n ...this._get(this._pluginsAtom).map((plugin) => plugin.meta.id),\n ...this._get(this.pluginRegistry.plugins).entries.map((entry) => entry.id),\n ]);\n\n const visit = (currentId: string): void => {\n if (cycle) {\n return;\n }\n if (visited.has(currentId)) {\n return;\n }\n if (onStack.has(currentId)) {\n const cycleStart = stackPath.indexOf(currentId);\n cycle = [...stackPath.slice(cycleStart), currentId];\n return;\n }\n onStack.add(currentId);\n stackPath.push(currentId);\n\n if (!knownIds.has(currentId)) {\n missing.push(currentId);\n } else if (!this._getPlugin(currentId)) {\n toInstall.push(currentId);\n }\n\n for (const depId of this._directDependencies(currentId)) {\n visit(depId);\n if (cycle) {\n break;\n }\n }\n\n onStack.delete(currentId);\n stackPath.pop();\n if (!cycle) {\n visited.add(currentId);\n order.push(currentId);\n }\n };\n\n visit(id);\n return { order, missing, toInstall, cycle };\n }\n\n /**\n * Walks the reverse `dependsOn` edges across registered plugins. With\n * `enabledOnly`, filters the result to currently-enabled ids. Returns\n * dependents in dependents-before-deps order so callers (cascade-disable)\n * can iterate and tear down leaves first.\n */\n private _collectDependents(id: string, opts: { transitive: boolean; enabledOnly: boolean }): string[] {\n const direct = this._get(this._pluginsAtom)\n .filter((plugin) => plugin.meta.dependsOn?.some((dep) => dep === id))\n .map((plugin) => plugin.meta.id);\n\n if (!opts.transitive) {\n return opts.enabledOnly\n ? direct.filter((dependentId) => this._get(this._enabledAtom).includes(dependentId))\n : direct;\n }\n\n const result: string[] = [];\n const visited = new Set<string>();\n const visit = (currentId: string): void => {\n if (visited.has(currentId)) {\n return;\n }\n visited.add(currentId);\n const parents = this._get(this._pluginsAtom)\n .filter((plugin) => plugin.meta.dependsOn?.some((dep) => dep === currentId))\n .map((plugin) => plugin.meta.id);\n for (const parentId of parents) {\n visit(parentId);\n if (parentId !== id && !result.includes(parentId)) {\n result.push(parentId);\n }\n }\n };\n visit(id);\n\n return opts.enabledOnly\n ? result.filter((dependentId) => this._get(this._enabledAtom).includes(dependentId))\n : result;\n }\n\n /**\n * Records a failure for a plugin. Latest failure wins so the registry UI\n * always sees the most recent reason. Walks the `cause` chain when checking\n * for timeouts: lazy-load timeouts arrive wrapped in `LazyPluginError` (the\n * timeout is the cause), but the operator-visible reason should still be\n * `'timeout'`.\n */\n private _recordFailure(id: string, phase: PluginFailurePhase, error: Error): void {\n const reason: PluginFailureReason = isTimeoutCause(error) ? 'timeout' : 'error';\n const failure: PluginFailure = { id, phase, reason, error, timestamp: Date.now() };\n log.warn('plugin failed', { id, phase, reason, error: error.message });\n this._update(this._failedAtom, (current) => [...current.filter((entry) => entry.id !== id), failure]);\n }\n\n /**\n * Fire-and-forget disable of a failed plugin. Forked because a failure can\n * happen mid-activation chain — yielding a `disable` inline would deadlock\n * on the shared semaphores. Core plugins are skipped (the host opted into\n * them being non-removable; the failure record is enough signal).\n */\n private _scheduleAutoDisable(id: string): void {\n if (this._get(this._coreAtom).includes(id)) {\n return;\n }\n if (!this._get(this._enabledAtom).includes(id)) {\n return;\n }\n this._runForkedFiber(\n this.disable(id).pipe(\n Effect.tapError((error) => Effect.sync(() => log.warn('auto-disable failed', { id, error }))),\n Effect.ignore,\n ),\n );\n }\n\n private _getActiveModules(): Plugin.PluginModule[] {\n const active = this._get(this._activeAtom);\n return this._get(this._modulesAtom).filter((module) => active.includes(module.id));\n }\n\n private _getInactiveModules(): Plugin.PluginModule[] {\n const active = this._get(this._activeAtom);\n return this._get(this._modulesAtom).filter((module) => !active.includes(module.id));\n }\n\n private _getActiveModulesByEvent(key: string): Plugin.PluginModule[] {\n return this._getActiveModules().filter((module) =>\n ActivationEvent.getEvents(module.activatesOn).map(ActivationEvent.eventKey).includes(key),\n );\n }\n\n private _getInactiveModulesByEvent(key: string): Plugin.PluginModule[] {\n return this._getInactiveModules().filter((module) =>\n ActivationEvent.getEvents(module.activatesOn).map(ActivationEvent.eventKey).includes(key),\n );\n }\n\n private _setPendingResetByModule(module: Plugin.PluginModule): void {\n const activationEvents = ActivationEvent.getEvents(module.activatesOn)\n .map(ActivationEvent.eventKey)\n .filter((key) => this._get(this._eventsFiredAtom).includes(key));\n\n const pendingReset = Array.fromIterable(new Set(activationEvents)).filter((event) => {\n const pending = this._get(this._pendingResetAtom);\n return !pending.includes(event);\n });\n if (pendingReset.length > 0) {\n log('pending reset', { events: pendingReset });\n this._update(this._pendingResetAtom, (current) => [...current, ...pendingReset]);\n }\n }\n\n private _clearPendingReset(key: string): void {\n const pendingIndex = this._get(this._pendingResetAtom).findIndex((event) => event === key);\n if (pendingIndex !== -1) {\n this._update(this._pendingResetAtom, (pending) => pending.filter((event) => event !== key));\n }\n }\n\n //\n // Fiber helpers\n //\n\n private _interruptInFlightActivations(): Effect.Effect<void> {\n return Effect.gen(this, function* () {\n const inFlightFibers = yield* Ref.get(this._inFlightFibers);\n yield* Effect.forEach(inFlightFibers, (fiber) => Fiber.interrupt(fiber), {\n concurrency: 'unbounded',\n });\n });\n }\n\n private _trackFiber(\n ref: Ref.Ref<Array<Fiber.Fiber<unknown, unknown>>>,\n fiber: Fiber.Fiber<unknown, unknown>,\n ): Effect.Effect<void> {\n return Ref.update(ref, (fibers) => [...fibers, fiber]);\n }\n\n private _untrackFiber(\n ref: Ref.Ref<Array<Fiber.Fiber<unknown, unknown>>>,\n fiber: Fiber.Fiber<unknown, unknown>,\n ): Effect.Effect<void> {\n return Ref.update(ref, (fibers) => fibers.filter((trackedFiber) => trackedFiber !== fiber));\n }\n\n /**\n * Spawns an effect on the default runtime and registers the resulting fiber in\n * `_inFlightFibers` so {@link shutdown} can interrupt it. Used from sync entry\n * points like {@link remove} where there is no enclosing Effect to fork from;\n * inside an Effect chain prefer the existing track/await/untrack pattern.\n */\n private _runForkedFiber<E>(effect: Effect.Effect<void, E>): void {\n const fiber = Effect.runFork(effect);\n Effect.runSync(this._trackFiber(this._inFlightFibers, fiber));\n Effect.runFork(Fiber.await(fiber).pipe(Effect.andThen(() => this._untrackFiber(this._inFlightFibers, fiber))));\n }\n\n //\n // Registration helpers\n //\n\n private _addPlugin(plugin: Plugin.Plugin): void {\n log('add plugin', { id: plugin.meta.id });\n // TODO(wittjosiah): Find a way to add a warning for duplicate plugins that doesn't cause log spam.\n this._update(this._pluginsAtom, (plugins) => (plugins.includes(plugin) ? plugins : [...plugins, plugin]));\n }\n\n private _removePlugin(id: string): void {\n log('remove plugin', { id });\n this._update(this._pluginsAtom, (plugins) => plugins.filter((plugin) => plugin.meta.id !== id));\n }\n\n private _addModule(module: Plugin.PluginModule): void {\n log('add module', { id: module.id });\n // TODO(wittjosiah): Find a way to add a warning for duplicate modules that doesn't cause log spam.\n this._update(this._modulesAtom, (modules) => (modules.includes(module) ? modules : [...modules, module]));\n }\n\n private _removeModule(id: string): void {\n log('remove module', { id });\n this._update(this._modulesAtom, (modules) => modules.filter((module) => module.id !== id));\n }\n\n //\n // Activation helpers\n //\n\n private _activateEvent(\n key: string,\n params: { before?: string; after?: string } | undefined,\n fiber: Fiber.Fiber<unknown, unknown>,\n ): Effect.Effect<boolean, Error> {\n return Effect.gen(this, function* () {\n yield* this._trackFiber(this._inFlightFibers, fiber);\n log('activating', { key, ...params });\n yield* Ref.update(this._activatingEvents, (activating) => Array.append(activating, key));\n this._clearPendingReset(key);\n\n const activatingEvents = yield* this._activatingEvents;\n const activatingModules = yield* this._activatingModules;\n const modules = this._getModulesForActivation(key, activatingEvents, activatingModules);\n if (modules.length === 0) {\n log('no modules to activate', { key });\n if (!this._get(this._eventsFiredAtom).includes(key)) {\n this._update(this._eventsFiredAtom, (events) => [...events, key]);\n }\n return false;\n }\n\n return yield* this._activateModulesForEvent(key, modules, activatingEvents);\n }).pipe(\n Effect.ensuring(\n Effect.all([\n this._untrackFiber(this._inFlightFibers, fiber),\n Ref.update(this._activatingEvents, (activating) => Array.filter(activating, (event) => event !== key)),\n ]),\n ),\n );\n }\n\n private _activateModulesForEvent(\n key: string,\n modules: Plugin.PluginModule[],\n activatingEvents: string[],\n ): Effect.Effect<boolean, Error> {\n const activatingModuleIds = modules.map((module) => module.id);\n return Effect.gen(this, function* () {\n yield* Ref.update(this._activatingModules, (activating) => Array.appendAll(activating, activatingModuleIds));\n\n log.info('activation wave', { event: key, modules: activatingModuleIds });\n performance.mark(`event:${key}:start`);\n yield* PubSub.publish(this.activation, { event: key, state: 'activating' });\n\n yield* this._activateRelatedEvents(key, this._getBeforeEvents(modules, activatingEvents), 'before');\n\n const capabilities = yield* this._loadCapabilitiesForModules(key, modules);\n yield* this._contributeCapabilitiesForModules(modules, capabilities);\n\n yield* this._activateRelatedEvents(key, this._getAfterEvents(modules, activatingEvents), 'after');\n\n if (!this._get(this._eventsFiredAtom).includes(key)) {\n this._update(this._eventsFiredAtom, (events) => [...events, key]);\n }\n\n performance.mark(`event:${key}:end`);\n performance.measure(`event:${key}`, `event:${key}:start`, `event:${key}:end`);\n yield* PubSub.publish(this.activation, { event: key, state: 'activated' });\n log('activated', { key });\n\n return true;\n }).pipe(\n Effect.ensuring(\n Ref.update(this._activatingModules, (activating) =>\n Array.filter(activating, (module) => !activatingModuleIds.includes(module)),\n ),\n ),\n );\n }\n\n private _getModulesForActivation(\n key: string,\n activatingEvents: string[],\n activatingModules: string[],\n ): Plugin.PluginModule[] {\n return this._getInactiveModulesByEvent(key).filter((module) => {\n const allOf = ActivationEvent.isAllOf(module.activatesOn);\n if (!allOf) {\n return true;\n }\n\n // Check to see if all of the events in the `allOf` have been fired.\n // An event can be considered \"fired\" if it is in the `eventsFired` list or if it is currently being activated.\n const events = ActivationEvent.getEvents(module.activatesOn).filter(\n (event) => ActivationEvent.eventKey(event) !== key,\n );\n return (\n events.every(\n (event) =>\n this._get(this._eventsFiredAtom).includes(ActivationEvent.eventKey(event)) ||\n activatingEvents.includes(ActivationEvent.eventKey(event)),\n ) && !activatingModules.includes(module.id)\n );\n });\n }\n\n private _getBeforeEvents(\n modules: Plugin.PluginModule[],\n activatingEvents: string[],\n ): ActivationEvent.ActivationEvent[] {\n return Function.pipe(\n modules,\n Array.flatMap((module) => module.firesBeforeActivation ?? []),\n HashSet.fromIterable,\n HashSet.toValues,\n Array.filter((event) => !activatingEvents.includes(ActivationEvent.eventKey(event))),\n );\n }\n\n private _getAfterEvents(\n modules: Plugin.PluginModule[],\n activatingEvents: string[],\n ): ActivationEvent.ActivationEvent[] {\n return Function.pipe(\n modules,\n Array.flatMap((module) => module.firesAfterActivation ?? []),\n HashSet.fromIterable,\n HashSet.toValues,\n Array.filter((event) => !activatingEvents.includes(ActivationEvent.eventKey(event))),\n );\n }\n\n private _activateRelatedEvents(\n key: string,\n events: ActivationEvent.ActivationEvent[],\n phase: 'before' | 'after',\n ): Effect.Effect<void, Error> {\n const logLabel = phase === 'before' ? 'firesBeforeActivation' : 'firesAfterActivation';\n const eventKey = phase === 'before' ? 'beforeEvents' : 'afterEvents';\n return Function.pipe(\n events,\n Array.map((event) => this.activate(event, phase === 'before' ? { before: key } : { after: key })),\n Effect.allWith({ concurrency: 'unbounded' }),\n together(\n Effect.sleep(Duration.seconds(10)).pipe(\n Effect.andThen(\n Effect.sync(() =>\n log.warn(`${logLabel} is taking a long time`, {\n event: key,\n [eventKey]: events.map(ActivationEvent.eventKey),\n }),\n ),\n ),\n ),\n ),\n Effect.asVoid,\n );\n }\n\n //\n // Module lifecycle helpers\n //\n\n private _loadCapabilitiesForModules(\n key: string,\n modules: Plugin.PluginModule[],\n ): Effect.Effect<Capability.Any[][], Error> {\n return Function.pipe(\n modules,\n Array.map((mod) => this._loadModule(mod, key)),\n Effect.allWith({ concurrency: 'unbounded' }),\n Effect.catchAll((error) => {\n return Effect.gen(this, function* () {\n yield* PubSub.publish(this.activation, { event: key, state: 'error', error });\n return yield* Effect.fail(error);\n });\n }),\n );\n }\n\n private _contributeCapabilitiesForModules(\n modules: Plugin.PluginModule[],\n capabilities: Capability.Any[][],\n ): Effect.Effect<void, Error> {\n return Function.pipe(\n modules,\n Array.zip(capabilities),\n Array.map(([module, capabilitySet]) => this._contributeCapabilities(module, capabilitySet)),\n // TODO(wittjosiah): This currently can't be run in parallel, and inserting\n // any yield between contributions (`Effect.yieldNow()`, `Effect.sleep(0)`)\n // races the `allOf` activation-event resolver — observed as a System\n // Error dialog on warm reloads. Contributions must stay strictly\n // synchronous within an event; React paint slots have to be found at\n // event boundaries higher up the call chain.\n Effect.all,\n Effect.asVoid,\n );\n }\n\n private _getModuleSemaphore(moduleId: Plugin.PluginModule['id']): Effect.Semaphore {\n let semaphore = this._moduleSemaphores.get(moduleId);\n if (!semaphore) {\n semaphore = Effect.runSync(Effect.makeSemaphore(1));\n this._moduleSemaphores.set(moduleId, semaphore);\n }\n return semaphore;\n }\n\n // `parentEvent` is the activation event that first triggered this module\n // load — included in `activating`/`activated` PubSub messages so subscribers\n // (e.g. the boot loader's status listener) can associate a module with its\n // triggering event in the trace. The same module may be referenced by\n // multiple events, but module loads are memoized via `_moduleMemoMap`, so\n // only the first event to need it will appear here; later events await the\n // cached deferred without re-publishing.\n private _loadModule = (module: Plugin.PluginModule, parentEvent: string): Effect.Effect<Capability.Any[], Error> =>\n Effect.gen(this, function* () {\n const semaphore = this._getModuleSemaphore(module.id);\n\n // Atomically check-and-set under per-module semaphore to prevent race conditions.\n const deferredToAwait = yield* Effect.gen(this, function* () {\n const existing = this._moduleMemoMap.get(module.id);\n if (existing) {\n return existing;\n }\n\n // First caller - create deferred, store it, and start loading in background.\n const deferred = yield* Deferred.make<Capability.Any[], Error>();\n this._moduleMemoMap.set(module.id, deferred);\n\n const loadEffect = Effect.gen(this, function* () {\n log('loading module', { module: module.id, parentEvent });\n performance.mark(`module:${module.id}:start`);\n yield* PubSub.publish(this.activation, { event: parentEvent, state: 'activating', module: module.id });\n const pluginId = this._getPluginIdForModule(module.id);\n const [duration, capabilities] = yield* module.activate().pipe(\n Effect.provideService(Capability.Service, this.capabilities),\n Effect.provideService(Plugin.Service, this),\n // Cap activation so a single misbehaving module can't hold the\n // event chain open. On timeout the failure is recorded against\n // the plugin and surfaced as `PluginTimeoutError`.\n Effect.timeoutFail({\n duration: this._activationTimeout,\n onTimeout: () =>\n new PluginTimeoutError({\n context: { id: pluginId ?? module.id, module: module.id, phase: 'activation' as PluginFailurePhase },\n }),\n }),\n Effect.timed,\n );\n const normalized = capabilities == null ? [] : Array.isArray(capabilities) ? capabilities : [capabilities];\n const elapsed = Duration.toMillis(duration);\n performance.mark(`module:${module.id}:end`);\n performance.measure(`module:${module.id}`, `module:${module.id}:start`, `module:${module.id}:end`);\n yield* PubSub.publish(this.activation, { event: parentEvent, state: 'activated', module: module.id });\n log('loaded module', {\n module: module.id,\n parentEvent,\n elapsed,\n failed: false,\n });\n return normalized as Capability.Any[];\n }).pipe(\n Effect.withSpan('PluginManager._loadModule'),\n together(\n Effect.sleep(Duration.seconds(10)).pipe(\n Effect.andThen(\n Effect.sync(() => log.warn(`module is taking a long time to activate`, { module: module.id })),\n ),\n ),\n ),\n Performance.addTrackEntry({\n name: module.id,\n devtools: {\n dataType: 'track-entry',\n track: 'Module Activation',\n trackGroup: 'Composer',\n color: 'primary',\n },\n }),\n );\n\n // Fork the load to run in background, completing the deferred when done.\n const fiber = yield* Effect.forkDaemon(\n loadEffect.pipe(\n Effect.tap((result) => Deferred.succeed(deferred, result)),\n Effect.catchAllCause((cause) => {\n const error = Cause.squash(cause);\n const errorMessage = error instanceof Error ? error.message : String(error);\n const missingCapability = errorMessage.match(/No capability found for ([^\\s\\[]+)/)?.[1];\n log.error('module failed to activate', {\n module: module.id,\n parentEvent,\n missingCapability,\n registeredCapabilities: this.capabilities.listRegisteredIdentifiers(),\n error: errorMessage,\n stack: error instanceof Error ? error.stack : undefined,\n isDefect: !Cause.isFailure(cause),\n });\n const normalizedError = error instanceof Error ? error : new Error(String(error));\n const pluginId = this._getPluginIdForModule(module.id);\n if (pluginId !== undefined) {\n this._recordFailure(pluginId, 'activation', normalizedError);\n this._scheduleAutoDisable(pluginId);\n }\n return Deferred.fail(deferred, normalizedError);\n }),\n ),\n );\n yield* this._trackFiber(this._inFlightFibers, fiber);\n yield* Effect.forkDaemon(\n Fiber.await(fiber).pipe(Effect.andThen(() => this._untrackFiber(this._inFlightFibers, fiber))),\n );\n\n return deferred;\n }).pipe(semaphore.withPermits(1));\n\n // Wait for result outside the semaphore so multiple waiters can proceed concurrently.\n return yield* Deferred.await(deferredToAwait);\n });\n\n private _contributeCapabilities(\n module: Plugin.PluginModule,\n capabilities: Capability.Any[],\n ): Effect.Effect<void, Error> {\n return Effect.gen(this, function* () {\n capabilities.forEach((capability) => {\n this.capabilities.contribute({ module: module.id, ...capability });\n });\n this._update(this._activeAtom, (active) => [...active, module.id]);\n this._capabilities.set(module.id, capabilities);\n });\n }\n\n private _deactivateModule(module: Plugin.PluginModule): Effect.Effect<boolean, Error> {\n return Effect.gen(this, function* () {\n const id = module.id;\n log('deactivating', { id });\n this._moduleMemoMap.delete(id);\n\n const capabilities = this._capabilities.get(id);\n if (capabilities) {\n for (const capability of capabilities) {\n this.capabilities.remove(capability.interface, capability.implementation);\n const program = capability.deactivate?.() ?? Effect.succeed(undefined);\n yield* program;\n }\n this._capabilities.delete(id);\n }\n\n const activeIndex = this._get(this._activeAtom).findIndex((event) => event === id);\n if (activeIndex !== -1) {\n this._update(this._activeAtom, (active) => active.filter((event) => event !== id));\n }\n\n log('deactivated', { id });\n return true;\n });\n }\n}\n\n/**\n * Creates a new Plugin Manager instance.\n */\nexport const make = (options: ManagerOptions): PluginManager => new ManagerImpl(options);\n\n/**\n * True when `error` (or anything along its `cause` chain) is a\n * {@link PluginTimeoutError}. Lazy-load timeouts wrap the timeout inside\n * `LazyPluginError`, so a shallow check on the outer error misses them.\n * Bounded depth so a circular chain can't loop forever.\n */\nconst isTimeoutCause = (error: unknown, depth = 0): boolean => {\n if (depth > 5 || !(error instanceof Error)) {\n return false;\n }\n if (PluginTimeoutError.is(error)) {\n return true;\n }\n return isTimeoutCause((error as Error & { cause?: unknown }).cause, depth + 1);\n};\n\n/**\n * Runs an effect concurrently with another effect.\n * If the first effect completes, the second effect is interrupted.\n */\n// TODO(dmaretskyi): Effect.race > Effect.asVoid\nconst together =\n <R1>(togetherEffect: Effect.Effect<void, never, R1>) =>\n <A, E, R2>(effect: Effect.Effect<A, E, R2>): Effect.Effect<A, E, R1 | R2> =>\n Effect.gen(function* () {\n const togetherFiber = yield* Effect.fork(togetherEffect);\n const result = yield* effect;\n yield* Fiber.interrupt(togetherFiber);\n return result;\n });\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom, type Registry } from '@effect-atom/atom-react';\nimport * as Deferred from 'effect/Deferred';\nimport * as Effect from 'effect/Effect';\n\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\n\nimport type * as Capability from './capability';\n\ntype CapabilityEntry<T> = {\n moduleId: string;\n implementation: T;\n};\n\n/**\n * Options for creating a capability manager.\n * @internal\n */\nexport type CapabilityManagerOptions = {\n registry: Registry.Registry;\n};\n\n/**\n * Interface for the Capability Manager.\n * Provides methods for contributing, removing, and accessing capabilities.\n */\nexport interface CapabilityManager {\n contribute<T>(args: { module: string; interface: Capability.InterfaceDef<T>; implementation: T }): void;\n\n remove<T>(interfaceDef: Capability.InterfaceDef<T>, implementation: T): void;\n\n /**\n * Get the Atom reference to the available capabilities for a given interface.\n * Primarily useful for deriving other Atom values based on the capabilities or\n * for subscribing to changes in the capabilities.\n * @returns An atom reference to the available capabilities.\n */\n atom<T>(interfaceDef: Capability.InterfaceDef<T>): Atom.Atom<T[]>;\n\n /**\n * Get capabilities from the capability manager.\n * @returns An array of capabilities.\n */\n getAll<T>(interfaceDef: Capability.InterfaceDef<T>): T[];\n\n /**\n * Requests a single capability from the capability manager.\n * @returns The capability.\n * @throws If no capability is found.\n */\n get<T>(interfaceDef: Capability.InterfaceDef<T>): T;\n\n /**\n * Waits for a capability to be available.\n * @returns The capability.\n */\n waitFor<T>(interfaceDef: Capability.InterfaceDef<T>): Effect.Effect<T, Error>;\n\n /**\n * Get capabilities grouped by the module that contributed them.\n * @returns An atom containing a record from module ID to capability implementations.\n */\n atomByModule<T>(interfaceDef: Capability.InterfaceDef<T>): Atom.Atom<Record<string, T[]>>;\n\n /**\n * Lists capability interface identifiers that currently have at least one contribution.\n */\n listRegisteredIdentifiers(): string[];\n}\n\n/**\n * Internal implementation of CapabilityManager.\n */\nclass CapabilityManagerImpl implements CapabilityManager {\n private readonly _registry: Registry.Registry;\n\n private readonly _registeredIdentifiers = new Set<string>();\n\n private readonly _capabilityEntries = Atom.family<string, Atom.Writable<CapabilityEntry<unknown>[]>>(() => {\n return Atom.make<CapabilityEntry<unknown>[]>([]).pipe(Atom.keepAlive);\n });\n\n readonly _capabilities = Atom.family<string, Atom.Atom<unknown[]>>((id: string) => {\n return Atom.make((get) => {\n const current = get(this._capabilityEntries(id));\n return current.map((c) => c.implementation);\n }).pipe(Atom.keepAlive);\n });\n\n readonly _capabilitiesByModule = Atom.family<string, Atom.Atom<Record<string, unknown[]>>>((id: string) => {\n return Atom.make((get) => {\n const entries = get(this._capabilityEntries(id));\n const result: Record<string, unknown[]> = {};\n for (const entry of entries) {\n (result[entry.moduleId] ??= []).push(entry.implementation);\n }\n return result;\n }).pipe(Atom.keepAlive);\n });\n\n readonly _capability = Atom.family<string, Atom.Atom<unknown>>((id: string) => {\n return Atom.make((get) => {\n const current = get(this._capabilities(id));\n invariant(current.length > 0, `No capability found for ${id}`);\n return current[0];\n });\n });\n\n constructor({ registry }: CapabilityManagerOptions) {\n this._registry = registry;\n }\n\n contribute<T>({\n module: moduleId,\n interface: interfaceDef,\n implementation,\n }: {\n module: string;\n interface: Capability.InterfaceDef<T>;\n implementation: T;\n }): void {\n const current = this._registry.get(this._capabilityEntries(interfaceDef.identifier));\n const isDuplicate = current.some((c) => c.moduleId === moduleId && c.implementation === implementation);\n if (isDuplicate) {\n log('capability already contributed, skipping', { id: interfaceDef.identifier, moduleId });\n return;\n }\n\n const entry: CapabilityEntry<T> = { moduleId, implementation };\n this._registry.set(this._capabilityEntries(interfaceDef.identifier), [...current, entry]);\n this._registeredIdentifiers.add(interfaceDef.identifier);\n log('capability contributed', {\n id: interfaceDef.identifier,\n moduleId,\n count: current.length,\n });\n }\n\n remove<T>(interfaceDef: Capability.InterfaceDef<T>, implementation: T): void {\n const current = this._registry.get(this._capabilityEntries(interfaceDef.identifier));\n if (current.length === 0) {\n return;\n }\n\n const next = current.filter((c) => c.implementation !== implementation);\n if (next.length !== current.length) {\n this._registry.set(this._capabilityEntries(interfaceDef.identifier), next);\n if (next.length === 0) {\n this._registeredIdentifiers.delete(interfaceDef.identifier);\n }\n log('capability removed', { id: interfaceDef.identifier, count: current.length });\n } else {\n log.warn('capability not removed', { id: interfaceDef.identifier });\n }\n }\n\n atom<T>(interfaceDef: Capability.InterfaceDef<T>): Atom.Atom<T[]> {\n // NOTE: This the type-checking for capabilities is done at the time of contribution.\n return this._capabilities(interfaceDef.identifier) as Atom.Atom<T[]>;\n }\n\n getAll<T>(interfaceDef: Capability.InterfaceDef<T>): T[] {\n return this._registry.get(this.atom(interfaceDef));\n }\n\n get<T>(interfaceDef: Capability.InterfaceDef<T>): T {\n const capabilities = this.getAll(interfaceDef);\n if (capabilities.length === 0) {\n log('capability not available', {\n requested: interfaceDef.identifier,\n registered: this.listRegisteredIdentifiers(),\n });\n invariant(capabilities.length > 0, `No capability found for ${interfaceDef.identifier}`);\n }\n return capabilities[0];\n }\n\n listRegisteredIdentifiers(): string[] {\n return [...this._registeredIdentifiers].sort();\n }\n\n waitFor<T>(interfaceDef: Capability.InterfaceDef<T>): Effect.Effect<T, Error> {\n return Effect.gen(this, function* () {\n const [capability] = this.getAll(interfaceDef);\n if (capability) {\n return capability;\n }\n\n const deferred = yield* Deferred.make<T, Error>();\n const cancel = this._registry.subscribe(this.atom(interfaceDef), (capabilities) => {\n if (capabilities.length > 0) {\n Effect.runSync(Deferred.succeed(deferred, capabilities[0]));\n }\n });\n const result = yield* Deferred.await(deferred);\n cancel();\n return result;\n });\n }\n\n atomByModule<T>(interfaceDef: Capability.InterfaceDef<T>): Atom.Atom<Record<string, T[]>> {\n return this._capabilitiesByModule(interfaceDef.identifier) as Atom.Atom<Record<string, T[]>>;\n }\n}\n\n/**\n * Creates a new Capability Manager instance.\n */\nexport const make = (options: CapabilityManagerOptions): CapabilityManager => new CapabilityManagerImpl(options);\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { Atom, type Registry as AtomRegistry } from '@effect-atom/atom-react';\nimport * as Effect from 'effect/Effect';\n\nimport { runAndForwardErrors } from '@dxos/effect';\nimport { log } from '@dxos/log';\n\n/**\n * A registry plugin entry as seen by the plugin manager layer.\n * Populated from the registry catalog; represents the latest available version of a plugin.\n *\n * Independently defined from @dxos/protocols PluginEntry — similar shape but not the same type.\n * Implementations of {@link PluginProvider} (e.g. {@link EdgeRegistryPluginProvider})\n * are responsible for mapping their wire-format entries to this shape.\n */\nexport type Plugin = {\n id: string;\n name: string;\n description?: string;\n homePage?: string;\n source?: string;\n screenshots?: string[];\n tags?: string[];\n icon?: string;\n iconHue?: string;\n /**\n * IDs of plugins this entry declares as runtime dependencies. Mirrors\n * {@link Plugin.Meta.dependsOn}. Surfaced in the catalog so the manager can\n * resolve and auto-install transitive deps before they are first loaded.\n */\n dependsOn?: string[];\n /** URL to dynamic-import the latest version of this plugin module. */\n moduleUrl: string;\n /** GitHub repository slug, e.g. `owner/name`. Used to fetch version history. */\n repo: string;\n /**\n * Latest known version string, e.g. `v1.2.0`.\n * Corresponds to releaseTag in the wire-format PluginEntry; named `version` here\n * because the plugin manager layer speaks versions, not release tags.\n */\n version: string;\n};\n\n/**\n * A single installable version of a registry plugin.\n */\nexport type PluginVersion = {\n /** Version string, e.g. `v1.2.0`. */\n tag: string;\n /** URL to dynamic-import this specific version of the plugin module. */\n moduleUrl: string;\n /** Unix ms of when this version was published (optional; omitted when unknown). */\n releasedAt?: number;\n};\n\n/**\n * Abstraction over the plugin registry catalog backend.\n * Implementations may call Edge, a local cache, or a stub.\n *\n * The interface itself is transport-agnostic; concrete implementations live\n * alongside it in this package (see {@link EdgeRegistryPluginProvider}) so we\n * avoid `app-framework ↔ edge-client` cycles, but they only need to satisfy\n * this shape — callers can substitute their own.\n */\nexport interface PluginProvider {\n /**\n * Returns all healthy registry plugins (latest version of each).\n */\n listPlugins(): Effect.Effect<readonly Plugin[], Error>;\n\n /**\n * Returns all known versions of a plugin identified by its GitHub repo slug.\n * Until the backend implements a versions endpoint, implementations MUST\n * return at least one entry representing the current/latest release.\n */\n listVersions(repo: string): Effect.Effect<readonly PluginVersion[], Error>;\n\n /**\n * Returns a single plugin entry for the given repo.\n * If `version` is omitted, returns the latest.\n * Fails if the specified version is not found.\n */\n getPlugin(repo: string, version?: string): Effect.Effect<Plugin, Error>;\n}\n\n/**\n * Atomic snapshot of the registry catalog as observed by the host.\n * Exposed via {@link Manager.plugins} so consumers can subscribe reactively\n * (loading state, list contents, last error).\n */\nexport type PluginsState = {\n entries: readonly Plugin[];\n loading: boolean;\n error: Error | null;\n};\n\n/**\n * Default no-op provider used when no `PluginProvider` is supplied at construction\n * time (e.g. tests, stories, environments without an Edge connection).\n *\n * `listPlugins` returns an empty list (so `Manager.plugins` settles to a stable\n * empty state). `listVersions` and `getPlugin` fail with an explicit error so\n * callers know they need to configure a real provider.\n */\nconst NULL_PROVIDER: PluginProvider = {\n listPlugins: () => Effect.succeed([] as readonly Plugin[]),\n listVersions: () => Effect.fail(new Error('No plugin registry provider configured')),\n getPlugin: () => Effect.fail(new Error('No plugin registry provider configured')),\n};\n\n/**\n * Owns the cached registry catalog state and forwards `listVersions` / `getPlugin`\n * calls to the underlying {@link PluginProvider}. Lives on the `PluginManager`\n * (as `manager.pluginRegistry`) so consumers can reach it through the manager\n * without a separate capability lookup.\n *\n * On construction the manager kicks off a background fetch via `provider.listPlugins()`\n * and writes the result into the {@link plugins} atom. Subscribers see `loading: true`\n * during the fetch and `loading: false` once it settles.\n */\nexport class Manager {\n readonly plugins: Atom.Writable<PluginsState>;\n readonly #provider: PluginProvider;\n\n constructor(provider: PluginProvider | undefined, atomRegistry: AtomRegistry.Registry) {\n this.#provider = provider ?? NULL_PROVIDER;\n const initialLoading = provider !== undefined;\n this.plugins = Atom.make<PluginsState>({ entries: [], loading: initialLoading, error: null }).pipe(Atom.keepAlive);\n\n if (provider !== undefined) {\n // Fire-and-forget initial load. Errors are surfaced via the atom's `error` field.\n void runAndForwardErrors(\n provider.listPlugins().pipe(\n Effect.match({\n onSuccess: (entries) => atomRegistry.set(this.plugins, { entries, loading: false, error: null }),\n onFailure: (error) => {\n log.catch(error);\n atomRegistry.set(this.plugins, { entries: [], loading: false, error });\n },\n }),\n ),\n );\n }\n }\n\n /** Forwards to the underlying provider. */\n listPlugins(): Effect.Effect<readonly Plugin[], Error> {\n return this.#provider.listPlugins();\n }\n\n /** Forwards to the underlying provider. */\n listVersions(repo: string): Effect.Effect<readonly PluginVersion[], Error> {\n return this.#provider.listVersions(repo);\n }\n\n /** Forwards to the underlying provider. */\n getPlugin(repo: string, version?: string): Effect.Effect<Plugin, Error> {\n return this.#provider.getPlugin(repo, version);\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["make", "Atom", "Registry", "Array", "Cause", "Deferred", "Duration", "Effect", "Fiber", "Function", "HashSet", "PubSub", "Ref", "runAndForwardErrors", "Performance", "BaseError", "log", "make", "Atom", "Deferred", "Effect", "invariant", "log", "_registeredIdentifiers", "_capabilityEntries", "pipe", "_capabilities", "family", "id", "current", "c", "keepAlive", "_capabilitiesByModule", "get", "result", "entry", "entries", "_capability", "length", "contribute", "moduleId", "isDuplicate", "implementation", "interfaceDef", "identifier", "count", "remove", "_registry", "set", "next", "atom", "getAll", "capabilities", "requested", "registered", "listRegisteredIdentifiers", "waitFor", "capability", "deferred", "runSync", "cancel", "atomByModule", "Atom", "Effect", "runAndForwardErrors", "log", "__dxlog_file", "listVersions", "getPlugin", "fail", "Error", "initialLoading", "provider", "plugins", "entries", "loading", "error", "pipe", "keepAlive", "onFailure", "atomRegistry", "__dxlog_file", "DEFAULT_LOAD_TIMEOUT", "seconds", "activation", "Effect", "capabilities", "registry", "pluginRegistry", "_pluginsAtom", "_coreAtom", "_enabledAtom", "_modulesAtom", "_activeAtom", "_eventsFiredAtom", "_pendingResetAtom", "_failedAtom", "_pluginLoader", "_onRemove", "_loadTimeout", "_activationTimeout", "_capabilities", "_moduleMemoMap", "_moduleSemaphores", "Map", "_activatingEvents", "_activatingModules", "_inFlightFibers", "runSync", "make", "_shutdownSemaphore", "makeSemaphore", "_shuttingDown", "CapabilityManager", "onRemove", "loadTimeout", "Atom", "enabled", "pipe", "keepAlive", "_devPluginIdsAtom", "plugins", "plugin", "_addPlugin", "core", "tap", "Deferred", "succeed", "_initialization", "undefined", "tapErrorCause", "failCause", "runAndForwardErrors", "getPlugins", "getCore", "getEnabled", "getModules", "getActive", "getEventsFired", "getPendingReset", "getFailed", "getDevPluginIds", "id", "_update", "shadow", "getDependencies", "transitive", "_directDependencies", "walk", "_computeDependencyClosure", "getDependents", "opts", "enabledOnly", "clearFailure", "current", "some", "log", "pluginId", "meta", "existing", "_getPlugin", "dev", "disable", "_markDev", "wasEnabled", "gen", "resolveDependencies", "_enableOne", "_recordFailure", "Plugin", "context", "reason", "path", "missing", "length", "queue", "shift", "installed", "next", "PluginDependencyError", "dependency", "cause", "installResult", "add", "rewalk", "cycle", "depId", "succeeded", "ok", "stub", "modules", "_setPendingResetByModule", "concurrency", "isLazy", "deferred", "module", "resolvedPlugin", "onTimeout", "PluginTimeoutError", "phase", "event", "error", "value", "disabled", "_removePlugin", "_runForkedFiber", "enable", "cascade", "enabledDependents", "coreDependent", "_get", "enabledIndex", "filter", "item", "deactivate", "forEach", "_removeModule", "_isShuttingDown", "key", "Performance", "addTrackEntry", "name", "devtools", "dataType", "track", "trackGroup", "color", "every", "results", "map", "shutdown", "_interruptInFlightActivations", "activeIds", "reverse", "allModules", "modulesToDeactivate", "_deactivateModule", "Ref", "set", "_set", "atom", "updater", "_getPluginIdForModule", "moduleId", "_getCatalogEntry", "dependsOn", "Set", "onStack", "stackPath", "toInstall", "knownIds", "visit", "currentId", "visited", "slice", "cycleStart", "push", "order", "direct", "dependentId", "includes", "result", "has", "parentId", "failure", "timestamp", "warn", "entry", "_getActiveModules", "_getInactiveModules", "_getActiveModulesByEvent", "_getInactiveModulesByEvent", "Array", "fromIterable", "pendingReset", "_clearPendingReset", "pendingIndex", "pending", "inFlightFibers", "_trackFiber", "fibers", "fiber", "_untrackFiber", "await", "_addModule", "activatingEvents", "activatingModules", "_getModulesForActivation", "events", "_activateModulesForEvent", "activating", "activatingModuleIds", "performance", "mark", "publish", "_contributeCapabilitiesForModules", "_activateRelatedEvents", "PubSub", "ensuring", "update", "ActivationEvent", "allOf", "_getBeforeEvents", "_getAfterEvents", "after", "together", "sleep", "eventKey", "catchAll", "_getModuleSemaphore", "semaphore", "deferredToAwait", "loadEffect", "parentEvent", "Service", "timed", "normalized", "elapsed", "failed", "withSpan", "errorMessage", "message", "String", "missingCapability", "registeredCapabilities", "stack", "Error", "isDefect", "normalizedError", "_scheduleAutoDisable", "withPermits", "_contributeCapabilities", "capability", "get", "program", "activeIndex", "active", "isTimeoutCause", "effect", "togetherFiber"]
7
+ }
@@ -21,6 +21,7 @@ __export(plugin_exports, {
21
21
  isPluginModule: () => isPluginModule,
22
22
  lazy: () => lazy,
23
23
  make: () => make,
24
+ makeMeta: () => makeMeta,
24
25
  reset: () => reset,
25
26
  resolveLazy: () => resolveLazy,
26
27
  shutdown: () => shutdown
@@ -31,6 +32,7 @@ import * as Option from "effect/Option";
31
32
  import * as Pipeable from "effect/Pipeable";
32
33
  import { BaseError } from "@dxos/errors";
33
34
  import { invariant } from "@dxos/invariant";
35
+ import { DXN } from "@dxos/keys";
34
36
  var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-framework/src/core/plugin.ts";
35
37
  var Service = class extends Context.Tag("@dxos/app-framework/PluginManager")() {
36
38
  };
@@ -59,6 +61,11 @@ var PluginModuleImpl = class {
59
61
  this.activate = options.activate;
60
62
  }
61
63
  };
64
+ var makeMeta = (options) => ({
65
+ ...options,
66
+ id: DXN.getName(options.key),
67
+ version: DXN.getVersion(options.key)
68
+ });
62
69
  var PluginTypeId = /* @__PURE__ */ Symbol.for("@dxos/app-framework/Plugin");
63
70
  var isPlugin = (value) => {
64
71
  return typeof value === "object" && value !== null && PluginTypeId in value;
@@ -105,13 +112,14 @@ function addModule(moduleOptionsOrBuilder, moduleOptions) {
105
112
  }
106
113
  var resolveModule = (meta, module, options) => {
107
114
  const moduleOptions = typeof module === "function" ? module(options) : module;
115
+ const pluginName = meta.id;
108
116
  const id = Option.fromNullable(moduleOptions.id).pipe(Option.match({
109
117
  onNone: () => {
110
118
  const exportName = getModuleTag(moduleOptions.activate);
111
- 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}`"] });
112
- return computeModuleId(meta.id, exportName);
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}`"] });
120
+ return computeModuleId(pluginName, exportName);
113
121
  },
114
- onSome: (id2) => computeModuleId(meta.id, id2)
122
+ onSome: (id2) => computeModuleId(pluginName, id2)
115
123
  }));
116
124
  return new PluginModuleImpl({
117
125
  ...moduleOptions,
@@ -120,7 +128,7 @@ var resolveModule = (meta, module, options) => {
120
128
  };
121
129
  function make(builder) {
122
130
  const meta = builder.meta;
123
- 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.`"] });
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.`"] });
124
132
  const factory = (options) => {
125
133
  const modules = builder.modules.map((module) => resolveModule(meta, module, options));
126
134
  return new PluginImpl(meta, modules);
@@ -203,6 +211,7 @@ export {
203
211
  shutdown,
204
212
  PluginModuleTypeId,
205
213
  isPluginModule,
214
+ makeMeta,
206
215
  PluginTypeId,
207
216
  isPlugin,
208
217
  define,
@@ -215,4 +224,4 @@ export {
215
224
  resolveLazy,
216
225
  plugin_exports
217
226
  };
218
- //# sourceMappingURL=chunk-SLX73WRZ.mjs.map
227
+ //# sourceMappingURL=chunk-DC3WRPBV.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": ";;;;;;;;AAAA;;;;;;;;;;;;;;;;;;;;AAIA,YAAYA,aAAa;AACzB,YAAYC,YAAY;AACxB,YAAYC,YAAY;AACxB,YAAYC,cAAc;AAE1B,SAASC,iBAAiB;AAC1B,SAASC,iBAAiB;AAC1B,SAASC,WAAW;AAMpB,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;EAyGA;;AAaEJ,IAAQK,WAAQC,CAAAA,aAAW;EAC3BC,GAAAA;EACC,IAAA,IAAA,QAAA,QAAA,GAAA;EAEH,SAAA,IAAA,WAAA,QAAA,GAAA;;;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,MAAO,QAAA,YAAA;AAC1B,QAAMV,gBAAYiB,OAAAA,WAAaJ,aAAsB,OACnDK,OAAa,IAAA;QACXC,aAAQ,KAAA;aACAC,oBAAaC,cAAWC,EAAAA,EAAAA,KAAaT,aAAcT;YACzDmB,MAAAA;AACA,YAAA,aAAuBP,aAAYI,cAAAA,QAAAA;AACrC,gBAAA,YAAA,uCAAA,KAAA,EAAA,IAAA,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,KAAA,GAAA,QAAA,GAAA,CAAA,cAAA,kDAAA,EAAA,CAAA;AACAI,aAASxB,gBAAOyB,YAAgBT,UAAYhB;IAC9C;IAEF,QAAWD,CAAAA,QAAAA,gBAAiB,YAAAC,GAAA;;SAAoBA,IAAAA,iBAAAA;IAAG,GAAA;IACrD;EASA,CAAA;;AAEE,SAAA,KAAA,SAAA;AACAuB,QAAAA,OAAWb,QAAKgB;YAGRf,CAAAA,KAAAA,WAAUgB,SAAgBC,KAAKC,EAAAA,GAAAA,UAAWC,KAAAA,EAAAA,qCAA4BxB,EAAAA,YAAAA,YAAAA,GAAAA,cAAAA,GAAAA,KAAAA,GAAAA,MAAAA,GAAAA,CAAAA,sCAAAA,sDAAAA,EAAAA,CAAAA;QAC5E,UAAWyB,CAAAA,YAAWrB;AACxB,UAAA,UAAA,QAAA,QAAA,IAAA,CAAA,WAAA,cAAA,MAAA,QAAA,OAAA,CAAA;AAEA,WAAOsB,IAAOC,WAAOC,MAAS,OAAA;;AAAO,SAAA,OAAA,OAAA,SAAA;IACvC;EAEE,CAAA;AACF;;AA8CI,IAAMC,OAAO,CAAIJ,MAAAA,WAAWrB;QAC5BsB,UAAOI,CAAAA,YAAeD;UACpBE,OAAO,IAAA,WAAA,MAAA,CAAA,CAAA;0BAAEC,MAAAA,SAAAA;aAAQhC;QAAQ;QACzBiC;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;QACjBC,EAAAA,QAAKL,QAAAA,IAAAA,OAAAA,OAAAA;QACLM,MAAQC,OAAcC,kBAAAA;;sBAA6B9C,IAAAA,gBAAAA;eAAI+C;QAAsB;QAAGC,QAAOH;MAAM;MAC/F,OAAA;IACKJ,CAAAA;;cAC6CQ,OAAS,IAAA,YAAA,YAAA;kBAAEjD,YAAAA,IAAAA,gBAAAA;eAAI+C;QAA0B;QAAE,QAAA;MAC7F;IACA,CAAA,CAAMG;EACN;QACE,SAAO,IAAOR,QAAOS,OAASL;gBAAkBG,MAAS,GAAA;kBAAEjD,YAAAA,IAAAA,gBAAAA;eAAI+C;QAAyB;QAAE,QAAA;MAC5F;IACIG,CAAAA,CAAAA;;aAEsBD,KAAAA,OAAS,IAAA;kBAAEjD,YAAAA,IAAAA,gBAAAA;eAAI+C;QAAyBK;QAA2B,QAAA;QAAE,YAAA,OAAA,KAAA;MAE/F;IACA,CAAA,CAAA;EACC;;;",
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
+ }
@@ -1,6 +1,3 @@
1
- import {
2
- UndoOperation
3
- } from "./chunk-KFDF7KR3.mjs";
4
1
  import {
5
2
  __export
6
3
  } from "./chunk-J5LGTIGS.mjs";
@@ -56,6 +53,7 @@ __export(history_tracker_exports, {
56
53
  make: () => make3
57
54
  });
58
55
  import * as Effect from "effect/Effect";
56
+ import * as PubSub from "effect/PubSub";
59
57
  import * as Stream from "effect/Stream";
60
58
  import { runAndForwardErrors } from "@dxos/effect";
61
59
  import { log } from "@dxos/log";
@@ -63,17 +61,15 @@ var __dxlog_file = "/__w/dxos/dxos/packages/sdk/app-framework/src/plugin-process
63
61
  var HISTORY_LIMIT = 100;
64
62
  var make3 = (invoker, undoRegistry) => {
65
63
  const history = [];
66
- const handleInvocation = (event) => {
64
+ const undoable = Effect.runSync(PubSub.unbounded());
65
+ const recordInvocation = (event) => {
67
66
  const mapping = undoRegistry.lookup(event.operation);
68
67
  if (!mapping) {
69
- return;
68
+ return void 0;
70
69
  }
71
70
  const inverseInput = mapping.deriveContext(event.input, event.output);
72
71
  if (inverseInput === void 0) {
73
- log("operation not undoable", {
74
- key: event.operation.meta.key
75
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 29, S: void 0 });
76
- return;
72
+ return void 0;
77
73
  }
78
74
  const entry = {
79
75
  operation: event.operation,
@@ -91,12 +87,16 @@ var make3 = (invoker, undoRegistry) => {
91
87
  if (history.length > HISTORY_LIMIT) {
92
88
  history.splice(0, history.length - HISTORY_LIMIT);
93
89
  }
94
- const resolvedMessage = resolveMessage(mapping.message, event.input, event.output);
95
- Effect.runFork(invoker.invoke(UndoOperation.ShowUndo, {
96
- message: resolvedMessage
97
- }));
90
+ return {
91
+ message: resolveMessage(mapping.message, event.input, event.output)
92
+ };
98
93
  };
99
- Effect.runFork(Stream.fromPubSub(invoker.invocations).pipe(Stream.runForEach((event) => Effect.sync(() => handleInvocation(event)))));
94
+ Effect.runFork(Stream.fromPubSub(invoker.invocations).pipe(Stream.runForEach((event) => Effect.gen(function* () {
95
+ const undoableEvent = recordInvocation(event);
96
+ if (undoableEvent) {
97
+ yield* PubSub.publish(undoable, undoableEvent);
98
+ }
99
+ }))));
100
100
  const undo = () => {
101
101
  return Effect.gen(function* () {
102
102
  const entry = history.pop();
@@ -106,16 +106,16 @@ var make3 = (invoker, undoRegistry) => {
106
106
  log("undoing operation", {
107
107
  key: entry.operation.meta.key,
108
108
  inverseKey: entry.inverse.meta.key
109
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 65, S: this });
109
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 68, S: this });
110
110
  yield* invoker._invokeCore(entry.inverse, entry.inverseInput);
111
111
  log("undo completed", {
112
112
  key: entry.operation.meta.key
113
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 71, S: this });
113
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 74, S: this });
114
114
  });
115
115
  };
116
116
  const undoPromise = async () => {
117
117
  return runAndForwardErrors(undo()).then(() => ({})).catch((error) => {
118
- log.catch(error, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 78, S: void 0 });
118
+ log.catch(error, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 81, S: void 0 });
119
119
  return {
120
120
  error
121
121
  };
@@ -127,7 +127,8 @@ var make3 = (invoker, undoRegistry) => {
127
127
  return {
128
128
  undo,
129
129
  undoPromise,
130
- canUndo
130
+ canUndo,
131
+ undoable
131
132
  };
132
133
  };
133
134
 
@@ -139,4 +140,4 @@ export {
139
140
  make3 as make2,
140
141
  history_tracker_exports
141
142
  };
142
- //# sourceMappingURL=chunk-BRK6GYNB.mjs.map
143
+ //# sourceMappingURL=chunk-E5DTDNDY.mjs.map
@@ -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": ";;;;;AAIA,SAASA,iBAAiB;AAEnB,IAAMC,oBAAN,cAAgCD,UAAUE,OAAO,qBAAqB,gCAAA,EAAA;AAAmC;;;ACNhH;;;;;AAmHO,IAAMC,OAAO,CAClBC,UACyBA;AAKpB,IAAMC,iBAAiB,CAC5BC,SACAC,OACAC,WAAAA;AAEA,MAAIF,YAAYG,QAAW;AACzB,WAAOA;EACT;AACA,MAAI,OAAOH,YAAY,YAAY;AACjC,WAAOA,QAAQC,OAAOC,MAAAA;EACxB;AACA,SAAOF;AACT;;;ACtIA;;cAAAI;;AAqCO,IAAMA,QAAO,CAACC,gBAAAA;AACnB,QAAMC,SAAS,CAACC,cAAAA;AACd,UAAMC,WAAWH,YAAAA;AACjB,UAAMI,UAAUD,SAASE,KAAK,CAACC,MAAMA,EAAEJ,UAAUK,KAAKC,QAAQN,UAAUK,KAAKC,GAAG;AAChF,QAAI,CAACJ,SAAS;AACZ,aAAOK;IACT;AAEA,WAAO;MACLC,SAASN,QAAQM;MACjBC,eAAeP,QAAQO;MACvBC,SAASR,QAAQQ;IACnB;EACF;AAEA,SAAO;IAAEX;EAAO;AAClB;;;ACrDA;;cAAAY;;AAIA,YAAYC,YAAY;AACxB,YAAYC,YAAY;AACxB,YAAYC,YAAY;AAExB,SAASC,2BAA2B;AACpC,SAASC,WAAW;AASpB,IAAA,eAAMC;AA2BN,IAAA,gBAAU;AAaFC,IAAAA,QAAWC,CAAAA,SAAOC,iBAAeC;AAEvC,QAAA,UAAA,CAAA;AACA,QAAMC,WAAAA,eAAoBC,iBAAAA,CAAAA;QAExB,mBAAc,CAAA,UAAA;UACZ,UAAA,aAAA,OAA6B,MAAA,SAAA;QAC7B,CAAA,SAAOC;AAGT,aAAMC;IACN;UACE,eAAA,QAAA,cAAA,MAAA,OAAA,MAAA,MAAA;QACA,iBAAOD,QAAAA;AAGT,aAAME;;UAEJC,QAAOJ;MACPK,WAAQL,MAAMK;MACdC,OAAAA,MAASC;MACTL,QAAAA,MAAAA;MACAM,SAAAA,QAAiBA;MACnB;MAEAC,WAAaN,MAAAA;IACbO;YAA6BC,KAAKX,KAAMY;QAAoBC,uBAAuBC;MAAO,KAAA,MAAA,UAAA,KAAA;MAE1F,eAAA,QAAA;IACA,GAAA,EAAA,YAAYA,YAASpB,GAAAA,cAAe,GAAA,IAAA,GAAA,OAAA,CAAA;AAEpC,QAAA,QAAA,SAAA,eAAA;AAEA,cAAO,OAAA,GAAA,QAAA,SAAA,aAAA;;AAAsE,WAAA;MAC/E,SAAA,eAAA,QAAA,SAAA,MAAA,OAAA,MAAA,MAAA;IAEA;EACAE;iBAKYmB,kBAAe,QAAA,WAAA,EAAA,KAAA,kBAAA,CAAA,UAAA,WAAA,aAAA;UACjB,gBAAcC,iBAAkBD,KAAAA;AAClC,QAAA,eAAA;AACF,aAAA,eAAA,UAAA,aAAA;IAKAE;EACJ,CAAA,CAAA,CAAA,CAAA;eACE,MAAMd;WACDA,WAAO,aAAA;YACV,QAAO,QAAOP,IAAOsB;AACvB,UAAA,CAAA,OAAA;AAEI,eAAA,OAAqB,YAAA,IAAA,kBAAA,CAAA;;UAAiCC,qBAAkBb;QAAiB,KAAA,MAAA,UAAA,KAAA;QAE7F,YAAA,MAAA,QAAA,KAAA;MACA,GAAA,EAAA,YAAOc,YAAQC,GAAYlB,cAAa,GAAEA,IAAAA,GAAAA,KAAMD,CAAAA;aAExBS,QAAWC,YAAUU,MAAQ,SAAA,MAAA,YAAA;AAAC,UAAA,kBAAA;QACxD,KAAA,MAAA,UAAA,KAAA;MACF,GAAA,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,IAAA,GAAA,KAAA,CAAA;IAEA,CAAA;;sBAIgBC,YAAAA;WACV,oBAAO,KAAA,CAAA,EAAA,KAAA,OAAA,CAAA,EAAA,EAAA,MAAA,CAAA,UAAA;UAAEA,MAAAA,OAAAA,QAAAA,EAAAA,YAAAA,YAAAA,GAAAA,cAAAA,GAAAA,IAAAA,GAAAA,OAAAA,CAAAA;AAAM,aAAA;QACjB;MACJ;IAEA,CAAA;;AAEA,QAAA,UAAA,MAAA;AAEA,WAAO,QAAA,SAAA;;SAELC;IACAC;IACA9B;IACF;IACA;;;",
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
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isPlugin
3
- } from "./chunk-SLX73WRZ.mjs";
3
+ } from "./chunk-DC3WRPBV.mjs";
4
4
  import {
5
5
  __export
6
6
  } from "./chunk-J5LGTIGS.mjs";
@@ -419,4 +419,4 @@ export {
419
419
  uninstall,
420
420
  url_loader_exports
421
421
  };
422
- //# sourceMappingURL=chunk-KLHQNYJ2.mjs.map
422
+ //# sourceMappingURL=chunk-KZUDO43J.mjs.map
@@ -0,0 +1,12 @@
1
+ // src/common/translations.ts
2
+ import * as Schema from "effect/Schema";
3
+ var Label = Schema.Union(Schema.String, Schema.mutable(Schema.Tuple(Schema.String, Schema.mutable(Schema.Struct({
4
+ ns: Schema.Union(Schema.String, Schema.Array(Schema.String)),
5
+ count: Schema.optional(Schema.Number),
6
+ defaultValue: Schema.optional(Schema.String)
7
+ })))));
8
+
9
+ export {
10
+ Label
11
+ };
12
+ //# sourceMappingURL=chunk-Q2GLJTVV.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/common/translations.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\n/**\n * A Label represents translatable text - either a simple string or a tuple of [key, options].\n */\nexport const Label = Schema.Union(\n Schema.String,\n Schema.mutable(\n Schema.Tuple(\n Schema.String,\n Schema.mutable(\n Schema.Struct({\n ns: Schema.Union(Schema.String, Schema.Array(Schema.String)),\n count: Schema.optional(Schema.Number),\n defaultValue: Schema.optional(Schema.String),\n }),\n ),\n ),\n ),\n);\nexport type Label = Schema.Schema.Type<typeof Label>;\n"],
5
+ "mappings": ";AAIA,YAAYA,YAAY;AAKjB,IAAMC,QAAeC,aACnBC,eACAC,eACEC,aACEF,eACAC,eACEE,cAAO;EACZC,IAAWL,aAAaC,eAAeK,aAAaL,aAAM,CAAA;EAC1DM,OAAcC,gBAAgBC,aAAM;EACpCC,cAAqBF,gBAAgBP,aAAM;AAC7C,CAAA,CAAA,CAAA,CAAA,CAAA;",
6
+ "names": ["Schema", "Label", "Union", "String", "mutable", "Tuple", "Struct", "ns", "Array", "count", "optional", "Number", "defaultValue"]
7
+ }