@dxos/plugin-deck 0.8.4-staging.60fe92afc8 → 0.9.1-main.c7dcc2e112

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 (158) hide show
  1. package/dist/lib/neutral/{DeckLayout-DEURA3KR.mjs → DeckLayout-VX2BP4Q2.mjs} +35 -22
  2. package/dist/lib/neutral/DeckLayout-VX2BP4Q2.mjs.map +7 -0
  3. package/dist/lib/neutral/DeckPlugin.mjs +2 -2
  4. package/dist/lib/neutral/DeckPlugin.mjs.map +4 -4
  5. package/dist/lib/neutral/{DeckSettings-W5I57OXM.mjs → DeckSettings-CQQZJ2YS.mjs} +3 -3
  6. package/dist/lib/neutral/DeckSettings-CQQZJ2YS.mjs.map +7 -0
  7. package/dist/lib/neutral/{add-toast-TNB6DXWU.mjs → add-toast-APKTCLIA.mjs} +2 -2
  8. package/dist/lib/neutral/{adjust-HNU5CCRO.mjs → adjust-7CZI4GK3.mjs} +3 -3
  9. package/dist/lib/neutral/{app-graph-builder-HMLT627T.mjs → app-graph-builder-6HTXRTU2.mjs} +5 -5
  10. package/dist/lib/neutral/app-graph-builder-6HTXRTU2.mjs.map +7 -0
  11. package/dist/lib/neutral/capabilities/index.mjs +8 -8
  12. package/dist/lib/neutral/{check-app-scheme-INSOF72J.mjs → check-app-scheme-HSAORHHX.mjs} +2 -2
  13. package/dist/lib/neutral/{chunk-BS4EOYMK.mjs → chunk-CL7JIOI5.mjs} +28 -14
  14. package/dist/lib/neutral/chunk-CL7JIOI5.mjs.map +7 -0
  15. package/dist/lib/neutral/{chunk-WAXJPQJI.mjs → chunk-DNG3L5QN.mjs} +31 -33
  16. package/dist/lib/neutral/chunk-DNG3L5QN.mjs.map +7 -0
  17. package/dist/lib/neutral/chunk-KY7LMF4D.mjs +46 -0
  18. package/dist/lib/neutral/chunk-KY7LMF4D.mjs.map +7 -0
  19. package/dist/lib/neutral/{chunk-324PPIZB.mjs → chunk-KZFJ4PBT.mjs} +4 -4
  20. package/dist/lib/neutral/chunk-KZFJ4PBT.mjs.map +7 -0
  21. package/dist/lib/neutral/{chunk-GBIGQKYW.mjs → chunk-NGX6RXNV.mjs} +4 -4
  22. package/dist/lib/neutral/chunk-NGX6RXNV.mjs.map +7 -0
  23. package/dist/lib/neutral/chunk-UZLAR4DR.mjs +8 -0
  24. package/dist/lib/neutral/{close-ASKR22A6.mjs → close-KJUCFIJ5.mjs} +3 -3
  25. package/dist/lib/neutral/components/index.mjs +1 -1
  26. package/dist/lib/neutral/containers/index.mjs +3 -3
  27. package/dist/lib/neutral/index.mjs +12 -2
  28. package/dist/lib/neutral/meta.json +1 -1
  29. package/dist/lib/neutral/meta.mjs +1 -1
  30. package/dist/lib/neutral/{notification-tracker-P36322BH.mjs → notification-tracker-CUDFRDCF.mjs} +9 -9
  31. package/dist/lib/neutral/{notification-tracker-P36322BH.mjs.map → notification-tracker-CUDFRDCF.mjs.map} +3 -3
  32. package/dist/lib/neutral/{open-5OYNO3RT.mjs → open-VU7YS3HB.mjs} +7 -7
  33. package/dist/lib/neutral/open-VU7YS3HB.mjs.map +7 -0
  34. package/dist/lib/neutral/operations/index.mjs +1 -1
  35. package/dist/lib/neutral/plugin.mjs +2 -2
  36. package/dist/lib/neutral/{react-root-HH5DEUOG.mjs → react-root-E6TAFHX6.mjs} +2 -2
  37. package/dist/lib/neutral/react-root-E6TAFHX6.mjs.map +7 -0
  38. package/dist/lib/neutral/{react-surface-3UVVCK3O.mjs → react-surface-O4POQWYL.mjs} +4 -5
  39. package/dist/lib/neutral/react-surface-O4POQWYL.mjs.map +7 -0
  40. package/dist/lib/neutral/{revert-workspace-B2QLT2C4.mjs → revert-workspace-24TKG3I7.mjs} +2 -2
  41. package/dist/lib/neutral/{scroll-into-view-B52C3PJO.mjs → scroll-into-view-3VXT6TWC.mjs} +2 -2
  42. package/dist/lib/neutral/{set-PA35ONXO.mjs → set-RFOLTI57.mjs} +3 -3
  43. package/dist/lib/neutral/{set-layout-mode-RPCCPQRB.mjs → set-layout-mode-AZ73W52Z.mjs} +2 -2
  44. package/dist/lib/neutral/{settings-EGNYUM4T.mjs → settings-6CDQEB6B.mjs} +3 -3
  45. package/dist/lib/neutral/settings-6CDQEB6B.mjs.map +7 -0
  46. package/dist/lib/neutral/{state-IIDXMQUO.mjs → state-D3YXB5NP.mjs} +3 -3
  47. package/dist/lib/neutral/{state-IIDXMQUO.mjs.map → state-D3YXB5NP.mjs.map} +2 -2
  48. package/dist/lib/neutral/{switch-workspace-LZF4KZXH.mjs → switch-workspace-TBPT23CZ.mjs} +4 -4
  49. package/dist/lib/neutral/switch-workspace-TBPT23CZ.mjs.map +7 -0
  50. package/dist/lib/neutral/translations.mjs +1 -1
  51. package/dist/lib/neutral/translations.mjs.map +3 -3
  52. package/dist/lib/neutral/types/index.mjs +11 -1
  53. package/dist/lib/neutral/{update-companion-YUCZZVGY.mjs → update-companion-5LCY6QME.mjs} +2 -2
  54. package/dist/lib/neutral/{update-complementary-7FZNB55J.mjs → update-complementary-HZ7QXZYE.mjs} +2 -2
  55. package/dist/lib/neutral/{update-dialog-FNQTSSAP.mjs → update-dialog-A7W3R5EI.mjs} +2 -2
  56. package/dist/lib/neutral/{update-plank-size-3YW4NXEY.mjs → update-plank-size-XHTYBLSD.mjs} +2 -2
  57. package/dist/lib/neutral/{update-popover-G2VUD7E6.mjs → update-popover-RDIHG73B.mjs} +2 -2
  58. package/dist/lib/neutral/{update-sidebar-KRHPUHUB.mjs → update-sidebar-GEI7USA5.mjs} +2 -2
  59. package/dist/lib/neutral/{url-handler-A6HLW4RB.mjs → url-handler-PUS4X33T.mjs} +10 -10
  60. package/dist/lib/neutral/url-handler-PUS4X33T.mjs.map +7 -0
  61. package/dist/types/dx.config.d.ts +28 -0
  62. package/dist/types/dx.config.d.ts.map +1 -0
  63. package/dist/types/src/capabilities/index.d.ts +8 -196
  64. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  65. package/dist/types/src/capabilities/react-surface.d.ts +2 -2
  66. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  67. package/dist/types/src/capabilities/state.d.ts +2 -2
  68. package/dist/types/src/components/Matrix/Matrix.stories.d.ts.map +1 -1
  69. package/dist/types/src/containers/Deck/Banner.d.ts.map +1 -1
  70. package/dist/types/src/containers/Deck/DeckViewport.d.ts.map +1 -1
  71. package/dist/types/src/containers/Deck/StatusBar.d.ts.map +1 -1
  72. package/dist/types/src/containers/DeckLayout/DeckLayout.stories.d.ts.map +1 -1
  73. package/dist/types/src/containers/DeckLayout/Popover.d.ts.map +1 -1
  74. package/dist/types/src/containers/Plank/PlankHeading.d.ts.map +1 -1
  75. package/dist/types/src/containers/Sidebar/ComplementarySidebar.d.ts.map +1 -1
  76. package/dist/types/src/meta.d.ts +28 -2
  77. package/dist/types/src/meta.d.ts.map +1 -1
  78. package/dist/types/src/operations/open.d.ts.map +1 -1
  79. package/dist/types/src/operations/switch-workspace.d.ts.map +1 -1
  80. package/dist/types/src/types/DeckCapabilities.d.ts +2 -2
  81. package/dist/types/src/types/DeckCapabilities.d.ts.map +1 -1
  82. package/dist/types/src/types/index.d.ts +1 -0
  83. package/dist/types/src/types/index.d.ts.map +1 -1
  84. package/dist/types/src/types/schema.d.ts +4 -2
  85. package/dist/types/src/types/schema.d.ts.map +1 -1
  86. package/dist/types/src/types/surface.d.ts +12 -0
  87. package/dist/types/src/types/surface.d.ts.map +1 -0
  88. package/dist/types/tsconfig.tsbuildinfo +1 -1
  89. package/dx.config.ts +35 -0
  90. package/package.json +39 -39
  91. package/src/DeckPlugin.test.ts +1 -1
  92. package/src/DeckPlugin.ts +1 -1
  93. package/src/capabilities/app-graph-builder.ts +4 -4
  94. package/src/capabilities/check-app-scheme.ts +3 -3
  95. package/src/capabilities/notification-tracker.ts +8 -8
  96. package/src/capabilities/react-root.tsx +1 -1
  97. package/src/capabilities/react-surface.tsx +3 -4
  98. package/src/capabilities/settings.ts +2 -2
  99. package/src/capabilities/state.ts +1 -1
  100. package/src/capabilities/url-handler.ts +7 -15
  101. package/src/components/DeckSettings/DeckSettings.tsx +2 -2
  102. package/src/components/Matrix/Matrix.stories.tsx +2 -1
  103. package/src/containers/Deck/Banner.tsx +5 -4
  104. package/src/containers/Deck/DeckViewport.tsx +3 -4
  105. package/src/containers/Deck/StatusBar.tsx +4 -2
  106. package/src/containers/DeckLayout/DeckLayout.stories.tsx +6 -9
  107. package/src/containers/DeckLayout/Fallback.tsx +1 -1
  108. package/src/containers/DeckLayout/Popover.tsx +37 -20
  109. package/src/containers/DeckLayout/Toast.tsx +1 -1
  110. package/src/containers/Plank/Plank.stories.tsx +2 -2
  111. package/src/containers/Plank/PlankControls.tsx +2 -2
  112. package/src/containers/Plank/PlankError.tsx +1 -1
  113. package/src/containers/Plank/PlankHeading.tsx +5 -6
  114. package/src/containers/Sidebar/ComplementarySidebar.tsx +6 -5
  115. package/src/containers/Sidebar/Sidebar.tsx +1 -1
  116. package/src/containers/Sidebar/SidebarButton.tsx +3 -3
  117. package/src/meta.ts +2 -27
  118. package/src/operations/open.ts +12 -10
  119. package/src/operations/switch-workspace.ts +2 -2
  120. package/src/translations.ts +1 -1
  121. package/src/types/DeckCapabilities.ts +5 -3
  122. package/src/types/DeckEvents.ts +1 -1
  123. package/src/types/DeckOperation.ts +1 -1
  124. package/src/types/index.ts +1 -0
  125. package/src/types/schema.ts +16 -12
  126. package/src/types/surface.ts +28 -0
  127. package/src/util/plank-url-params.ts +3 -3
  128. package/dist/lib/neutral/DeckLayout-DEURA3KR.mjs.map +0 -7
  129. package/dist/lib/neutral/DeckSettings-W5I57OXM.mjs.map +0 -7
  130. package/dist/lib/neutral/app-graph-builder-HMLT627T.mjs.map +0 -7
  131. package/dist/lib/neutral/chunk-324PPIZB.mjs.map +0 -7
  132. package/dist/lib/neutral/chunk-BS4EOYMK.mjs.map +0 -7
  133. package/dist/lib/neutral/chunk-GBIGQKYW.mjs.map +0 -7
  134. package/dist/lib/neutral/chunk-PYEY5SEC.mjs +0 -37
  135. package/dist/lib/neutral/chunk-PYEY5SEC.mjs.map +0 -7
  136. package/dist/lib/neutral/chunk-Q4W6B4IB.mjs +0 -8
  137. package/dist/lib/neutral/chunk-WAXJPQJI.mjs.map +0 -7
  138. package/dist/lib/neutral/open-5OYNO3RT.mjs.map +0 -7
  139. package/dist/lib/neutral/react-root-HH5DEUOG.mjs.map +0 -7
  140. package/dist/lib/neutral/react-surface-3UVVCK3O.mjs.map +0 -7
  141. package/dist/lib/neutral/settings-EGNYUM4T.mjs.map +0 -7
  142. package/dist/lib/neutral/switch-workspace-LZF4KZXH.mjs.map +0 -7
  143. package/dist/lib/neutral/url-handler-A6HLW4RB.mjs.map +0 -7
  144. /package/dist/lib/neutral/{add-toast-TNB6DXWU.mjs.map → add-toast-APKTCLIA.mjs.map} +0 -0
  145. /package/dist/lib/neutral/{adjust-HNU5CCRO.mjs.map → adjust-7CZI4GK3.mjs.map} +0 -0
  146. /package/dist/lib/neutral/{check-app-scheme-INSOF72J.mjs.map → check-app-scheme-HSAORHHX.mjs.map} +0 -0
  147. /package/dist/lib/neutral/{chunk-Q4W6B4IB.mjs.map → chunk-UZLAR4DR.mjs.map} +0 -0
  148. /package/dist/lib/neutral/{close-ASKR22A6.mjs.map → close-KJUCFIJ5.mjs.map} +0 -0
  149. /package/dist/lib/neutral/{revert-workspace-B2QLT2C4.mjs.map → revert-workspace-24TKG3I7.mjs.map} +0 -0
  150. /package/dist/lib/neutral/{scroll-into-view-B52C3PJO.mjs.map → scroll-into-view-3VXT6TWC.mjs.map} +0 -0
  151. /package/dist/lib/neutral/{set-PA35ONXO.mjs.map → set-RFOLTI57.mjs.map} +0 -0
  152. /package/dist/lib/neutral/{set-layout-mode-RPCCPQRB.mjs.map → set-layout-mode-AZ73W52Z.mjs.map} +0 -0
  153. /package/dist/lib/neutral/{update-companion-YUCZZVGY.mjs.map → update-companion-5LCY6QME.mjs.map} +0 -0
  154. /package/dist/lib/neutral/{update-complementary-7FZNB55J.mjs.map → update-complementary-HZ7QXZYE.mjs.map} +0 -0
  155. /package/dist/lib/neutral/{update-dialog-FNQTSSAP.mjs.map → update-dialog-A7W3R5EI.mjs.map} +0 -0
  156. /package/dist/lib/neutral/{update-plank-size-3YW4NXEY.mjs.map → update-plank-size-XHTYBLSD.mjs.map} +0 -0
  157. /package/dist/lib/neutral/{update-popover-G2VUD7E6.mjs.map → update-popover-RDIHG73B.mjs.map} +0 -0
  158. /package/dist/lib/neutral/{update-sidebar-KRHPUHUB.mjs.map → update-sidebar-GEI7USA5.mjs.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  meta
3
- } from "./chunk-PYEY5SEC.mjs";
3
+ } from "./chunk-KY7LMF4D.mjs";
4
4
  import "./chunk-J5LGTIGS.mjs";
5
5
  export {
6
6
  meta
@@ -89,13 +89,13 @@ var notification_tracker_default = Capability.makeModule(Effect.fnUntraced(funct
89
89
  title: [
90
90
  "plugin-failure.title",
91
91
  {
92
- ns: meta.id
92
+ ns: meta.profile.key
93
93
  }
94
94
  ],
95
95
  description: [
96
96
  "plugin-failure.description",
97
97
  {
98
- ns: meta.id
98
+ ns: meta.profile.key
99
99
  }
100
100
  ],
101
101
  icon: "ph--warning--regular",
@@ -103,13 +103,13 @@ var notification_tracker_default = Capability.makeModule(Effect.fnUntraced(funct
103
103
  actionLabel: [
104
104
  "plugin-failure-action.label",
105
105
  {
106
- ns: meta.id
106
+ ns: meta.profile.key
107
107
  }
108
108
  ],
109
109
  actionAlt: [
110
110
  "plugin-failure-action.alt",
111
111
  {
112
- ns: meta.id
112
+ ns: meta.profile.key
113
113
  }
114
114
  ],
115
115
  onAction: () => void invoker.invokePromise(SettingsOperation.OpenPluginRegistry)
@@ -133,26 +133,26 @@ var notification_tracker_default = Capability.makeModule(Effect.fnUntraced(funct
133
133
  title: message ?? [
134
134
  "undo-available.label",
135
135
  {
136
- ns: meta.id
136
+ ns: meta.profile.key
137
137
  }
138
138
  ],
139
139
  duration: UNDO_TOAST_DURATION,
140
140
  actionLabel: [
141
141
  "undo-action.label",
142
142
  {
143
- ns: meta.id
143
+ ns: meta.profile.key
144
144
  }
145
145
  ],
146
146
  actionAlt: [
147
147
  "undo-action.alt",
148
148
  {
149
- ns: meta.id
149
+ ns: meta.profile.key
150
150
  }
151
151
  ],
152
152
  closeLabel: [
153
153
  "undo-close.label",
154
154
  {
155
- ns: meta.id
155
+ ns: meta.profile.key
156
156
  }
157
157
  ],
158
158
  onAction: onUndo
@@ -179,4 +179,4 @@ var notification_tracker_default = Capability.makeModule(Effect.fnUntraced(funct
179
179
  export {
180
180
  notification_tracker_default as default
181
181
  };
182
- //# sourceMappingURL=notification-tracker-P36322BH.mjs.map
182
+ //# sourceMappingURL=notification-tracker-CUDFRDCF.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/capabilities/notification-tracker.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Fiber from 'effect/Fiber';\nimport * as Stream from 'effect/Stream';\n\nimport { Capabilities, Capability, type PluginManager } from '@dxos/app-framework';\nimport { type LayoutOperation, SettingsOperation } from '@dxos/app-toolkit';\nimport { Process } from '@dxos/compute';\n\nimport { meta } from '#meta';\nimport { DeckCapabilities } from '#types';\n\nconst NOTIFY_TOAST_DURATION = 5_000;\nconst ERROR_TOAST_DURATION = 10_000;\nconst UNDO_TOAST_DURATION = 10_000;\n\n/**\n * The single producer of toasts driven by operation invocations:\n * - Per-invoke notifications ride the process monitor: each invocation spawns a process carrying the\n * caller's `notify` config on its params; this tracker watches process state transitions and toasts\n * on start / success / failure.\n * - Undo toasts come from the history tracker's `undoable` stream (it owns the undo registry lookup);\n * the toast action triggers `historyTracker.undoPromise()`.\n */\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const capabilities = yield* Capability.Service;\n const registry = yield* Capability.get(Capabilities.AtomRegistry);\n const ephemeralAtom = yield* Capability.get(DeckCapabilities.EphemeralState);\n const monitor = yield* Capability.get(Capabilities.ProcessMonitor);\n const manager = yield* Capability.get(Capabilities.PluginManager);\n const invoker = yield* Capability.get(Capabilities.OperationInvoker);\n\n const addToast = (toast: LayoutOperation.Toast) => {\n const state = registry.get(ephemeralAtom);\n registry.set(ephemeralAtom, { ...state, toasts: [...state.toasts, toast] });\n };\n\n //\n // Notifications — driven by the process monitor.\n //\n\n // Tracks the last-seen state per process so we only toast on transitions.\n const lastState = new Map<Process.ID, Process.State>();\n\n const handleProcesses = (processes: readonly Process.Info[]) => {\n const seen = new Set<Process.ID>();\n for (const process of processes) {\n seen.add(process.pid);\n const previous = lastState.get(process.pid);\n lastState.set(process.pid, process.state);\n if (previous === process.state) {\n continue;\n }\n\n const notify = process.params.notify;\n if (!notify) {\n continue;\n }\n\n // Transition into RUNNING (the first snapshot may be a pre-RUNNING state like IDLE/HYBERNATING).\n if (previous !== Process.State.RUNNING && process.state === Process.State.RUNNING && notify.start) {\n addToast({ id: `notify-start-${process.pid}`, title: notify.start, duration: NOTIFY_TOAST_DURATION });\n } else if (process.state === Process.State.SUCCEEDED && notify.success) {\n addToast({ id: `notify-success-${process.pid}`, title: notify.success, duration: NOTIFY_TOAST_DURATION });\n } else if (process.state === Process.State.FAILED && notify.error) {\n addToast({\n id: `notify-error-${process.pid}`,\n title: notify.error,\n ...(process.error ? { description: process.error } : {}),\n icon: 'ph--warning--regular',\n duration: ERROR_TOAST_DURATION,\n });\n }\n }\n\n // Drop bookkeeping for processes that have left the tree.\n for (const pid of lastState.keys()) {\n if (!seen.has(pid)) {\n lastState.delete(pid);\n }\n }\n };\n\n const unsubscribeMonitor = registry.subscribe(monitor.processTreeAtom, handleProcesses);\n\n //\n // Plugin failures — show one toast when any plugin fails to activate, with a link to the registry.\n //\n\n let hasShownFailureToast = false;\n\n const handleFailures = (failures: readonly PluginManager.PluginFailure[]) => {\n if (failures.length === 0) {\n hasShownFailureToast = false;\n return;\n }\n if (hasShownFailureToast) {\n return;\n }\n hasShownFailureToast = true;\n // Replace any stale plugin-failure toast so at most one is ever visible.\n const toast: LayoutOperation.Toast = {\n id: 'plugin-failure',\n title: ['plugin-failure.title', { ns: meta.id }],\n description: ['plugin-failure.description', { ns: meta.id }],\n icon: 'ph--warning--regular',\n duration: ERROR_TOAST_DURATION,\n actionLabel: ['plugin-failure-action.label', { ns: meta.id }],\n actionAlt: ['plugin-failure-action.alt', { ns: meta.id }],\n onAction: () => void invoker.invokePromise(SettingsOperation.OpenPluginRegistry),\n };\n const state = registry.get(ephemeralAtom);\n registry.set(ephemeralAtom, {\n ...state,\n toasts: [...state.toasts.filter((t) => t.id !== 'plugin-failure'), toast],\n });\n };\n\n const unsubscribeFailures = registry.subscribe(manager.failed, handleFailures);\n\n //\n // Undo — driven by the history tracker's `undoable` stream (it owns the registry lookup).\n //\n\n const showUndoToast = (message: LayoutOperation.Toast['title'], onUndo: () => void) => {\n const undoId = `notify-undo-${crypto.randomUUID()}`;\n const state = registry.get(ephemeralAtom);\n // Replace the previous undo toast (only the most recent action can be undone).\n const toasts = state.currentUndoId\n ? state.toasts.filter((toast) => toast.id !== state.currentUndoId)\n : state.toasts;\n const toast: LayoutOperation.Toast = {\n id: undoId,\n title: message ?? ['undo-available.label', { ns: meta.id }],\n duration: UNDO_TOAST_DURATION,\n actionLabel: ['undo-action.label', { ns: meta.id }],\n actionAlt: ['undo-action.alt', { ns: meta.id }],\n closeLabel: ['undo-close.label', { ns: meta.id }],\n onAction: onUndo,\n };\n registry.set(ephemeralAtom, { ...state, currentUndoId: undoId, toasts: [...toasts, toast] });\n };\n\n // The history tracker is contributed on ProcessManagerReady, possibly after this module activates;\n // `waitFor` resolves it once available, then we observe its undoable stream.\n const undoFiber = Effect.runFork(\n Effect.gen(function* () {\n const historyTracker = yield* Capability.waitFor(Capabilities.HistoryTracker);\n yield* Stream.fromPubSub(historyTracker.undoable).pipe(\n Stream.runForEach((event) =>\n Effect.sync(() => showUndoToast(event.message, () => void historyTracker.undoPromise())),\n ),\n );\n }).pipe(Effect.provideService(Capability.Service, capabilities)),\n );\n\n // Track all subscriptions so they are torn down when the module deactivates.\n return Capability.contributes(Capabilities.Null, null, () =>\n Effect.gen(function* () {\n unsubscribeMonitor();\n unsubscribeFailures();\n yield* Fiber.interrupt(undoFiber);\n }),\n );\n }),\n);\n"],
5
- "mappings": "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",
6
- "names": ["Effect", "Fiber", "Stream", "Capabilities", "Capability", "SettingsOperation", "Process", "meta", "DeckCapabilities", "NOTIFY_TOAST_DURATION", "ERROR_TOAST_DURATION", "UNDO_TOAST_DURATION", "makeModule", "fnUntraced", "capabilities", "Service", "registry", "get", "AtomRegistry", "ephemeralAtom", "EphemeralState", "monitor", "ProcessMonitor", "manager", "PluginManager", "invoker", "OperationInvoker", "addToast", "toast", "state", "set", "toasts", "lastState", "Map", "handleProcesses", "processes", "seen", "Set", "process", "add", "pid", "previous", "notify", "params", "State", "RUNNING", "start", "id", "title", "duration", "SUCCEEDED", "success", "FAILED", "error", "description", "icon", "keys", "has", "delete", "unsubscribeMonitor", "subscribe", "processTreeAtom", "hasShownFailureToast", "handleFailures", "failures", "length", "ns", "actionLabel", "actionAlt", "onAction", "invokePromise", "OpenPluginRegistry", "filter", "t", "unsubscribeFailures", "failed", "showUndoToast", "message", "onUndo", "undoId", "crypto", "randomUUID", "currentUndoId", "closeLabel", "undoFiber", "runFork", "gen", "historyTracker", "waitFor", "HistoryTracker", "fromPubSub", "undoable", "pipe", "runForEach", "event", "sync", "undoPromise", "provideService", "contributes", "Null", "interrupt"]
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Fiber from 'effect/Fiber';\nimport * as Stream from 'effect/Stream';\n\nimport { Capabilities, Capability, type PluginManager } from '@dxos/app-framework';\nimport { type LayoutOperation, SettingsOperation } from '@dxos/app-toolkit';\nimport { Process } from '@dxos/compute';\n\nimport { meta } from '#meta';\nimport { DeckCapabilities } from '#types';\n\nconst NOTIFY_TOAST_DURATION = 5_000;\nconst ERROR_TOAST_DURATION = 10_000;\nconst UNDO_TOAST_DURATION = 10_000;\n\n/**\n * The single producer of toasts driven by operation invocations:\n * - Per-invoke notifications ride the process monitor: each invocation spawns a process carrying the\n * caller's `notify` config on its params; this tracker watches process state transitions and toasts\n * on start / success / failure.\n * - Undo toasts come from the history tracker's `undoable` stream (it owns the undo registry lookup);\n * the toast action triggers `historyTracker.undoPromise()`.\n */\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const capabilities = yield* Capability.Service;\n const registry = yield* Capability.get(Capabilities.AtomRegistry);\n const ephemeralAtom = yield* Capability.get(DeckCapabilities.EphemeralState);\n const monitor = yield* Capability.get(Capabilities.ProcessMonitor);\n const manager = yield* Capability.get(Capabilities.PluginManager);\n const invoker = yield* Capability.get(Capabilities.OperationInvoker);\n\n const addToast = (toast: LayoutOperation.Toast) => {\n const state = registry.get(ephemeralAtom);\n registry.set(ephemeralAtom, { ...state, toasts: [...state.toasts, toast] });\n };\n\n //\n // Notifications — driven by the process monitor.\n //\n\n // Tracks the last-seen state per process so we only toast on transitions.\n const lastState = new Map<Process.ID, Process.State>();\n\n const handleProcesses = (processes: readonly Process.Info[]) => {\n const seen = new Set<Process.ID>();\n for (const process of processes) {\n seen.add(process.pid);\n const previous = lastState.get(process.pid);\n lastState.set(process.pid, process.state);\n if (previous === process.state) {\n continue;\n }\n\n const notify = process.params.notify;\n if (!notify) {\n continue;\n }\n\n // Transition into RUNNING (the first snapshot may be a pre-RUNNING state like IDLE/HYBERNATING).\n if (previous !== Process.State.RUNNING && process.state === Process.State.RUNNING && notify.start) {\n addToast({ id: `notify-start-${process.pid}`, title: notify.start, duration: NOTIFY_TOAST_DURATION });\n } else if (process.state === Process.State.SUCCEEDED && notify.success) {\n addToast({ id: `notify-success-${process.pid}`, title: notify.success, duration: NOTIFY_TOAST_DURATION });\n } else if (process.state === Process.State.FAILED && notify.error) {\n addToast({\n id: `notify-error-${process.pid}`,\n title: notify.error,\n ...(process.error ? { description: process.error } : {}),\n icon: 'ph--warning--regular',\n duration: ERROR_TOAST_DURATION,\n });\n }\n }\n\n // Drop bookkeeping for processes that have left the tree.\n for (const pid of lastState.keys()) {\n if (!seen.has(pid)) {\n lastState.delete(pid);\n }\n }\n };\n\n const unsubscribeMonitor = registry.subscribe(monitor.processTreeAtom, handleProcesses);\n\n //\n // Plugin failures — show one toast when any plugin fails to activate, with a link to the registry.\n //\n\n let hasShownFailureToast = false;\n\n const handleFailures = (failures: readonly PluginManager.PluginFailure[]) => {\n if (failures.length === 0) {\n hasShownFailureToast = false;\n return;\n }\n if (hasShownFailureToast) {\n return;\n }\n hasShownFailureToast = true;\n // Replace any stale plugin-failure toast so at most one is ever visible.\n const toast: LayoutOperation.Toast = {\n id: 'plugin-failure',\n title: ['plugin-failure.title', { ns: meta.profile.key }],\n description: ['plugin-failure.description', { ns: meta.profile.key }],\n icon: 'ph--warning--regular',\n duration: ERROR_TOAST_DURATION,\n actionLabel: ['plugin-failure-action.label', { ns: meta.profile.key }],\n actionAlt: ['plugin-failure-action.alt', { ns: meta.profile.key }],\n onAction: () => void invoker.invokePromise(SettingsOperation.OpenPluginRegistry),\n };\n const state = registry.get(ephemeralAtom);\n registry.set(ephemeralAtom, {\n ...state,\n toasts: [...state.toasts.filter((t) => t.id !== 'plugin-failure'), toast],\n });\n };\n\n const unsubscribeFailures = registry.subscribe(manager.failed, handleFailures);\n\n //\n // Undo — driven by the history tracker's `undoable` stream (it owns the registry lookup).\n //\n\n const showUndoToast = (message: LayoutOperation.Toast['title'], onUndo: () => void) => {\n const undoId = `notify-undo-${crypto.randomUUID()}`;\n const state = registry.get(ephemeralAtom);\n // Replace the previous undo toast (only the most recent action can be undone).\n const toasts = state.currentUndoId\n ? state.toasts.filter((toast) => toast.id !== state.currentUndoId)\n : state.toasts;\n const toast: LayoutOperation.Toast = {\n id: undoId,\n title: message ?? ['undo-available.label', { ns: meta.profile.key }],\n duration: UNDO_TOAST_DURATION,\n actionLabel: ['undo-action.label', { ns: meta.profile.key }],\n actionAlt: ['undo-action.alt', { ns: meta.profile.key }],\n closeLabel: ['undo-close.label', { ns: meta.profile.key }],\n onAction: onUndo,\n };\n registry.set(ephemeralAtom, { ...state, currentUndoId: undoId, toasts: [...toasts, toast] });\n };\n\n // The history tracker is contributed on ProcessManagerReady, possibly after this module activates;\n // `waitFor` resolves it once available, then we observe its undoable stream.\n const undoFiber = Effect.runFork(\n Effect.gen(function* () {\n const historyTracker = yield* Capability.waitFor(Capabilities.HistoryTracker);\n yield* Stream.fromPubSub(historyTracker.undoable).pipe(\n Stream.runForEach((event) =>\n Effect.sync(() => showUndoToast(event.message, () => void historyTracker.undoPromise())),\n ),\n );\n }).pipe(Effect.provideService(Capability.Service, capabilities)),\n );\n\n // Track all subscriptions so they are torn down when the module deactivates.\n return Capability.contributes(Capabilities.Null, null, () =>\n Effect.gen(function* () {\n unsubscribeMonitor();\n unsubscribeFailures();\n yield* Fiber.interrupt(undoFiber);\n }),\n );\n }),\n);\n"],
5
+ "mappings": "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",
6
+ "names": ["Effect", "Fiber", "Stream", "Capabilities", "Capability", "SettingsOperation", "Process", "meta", "DeckCapabilities", "NOTIFY_TOAST_DURATION", "ERROR_TOAST_DURATION", "UNDO_TOAST_DURATION", "makeModule", "fnUntraced", "capabilities", "Service", "registry", "get", "AtomRegistry", "ephemeralAtom", "EphemeralState", "monitor", "ProcessMonitor", "manager", "PluginManager", "invoker", "OperationInvoker", "addToast", "toast", "state", "set", "toasts", "lastState", "Map", "handleProcesses", "processes", "seen", "Set", "process", "add", "pid", "previous", "notify", "params", "State", "RUNNING", "start", "id", "title", "duration", "SUCCEEDED", "success", "FAILED", "error", "description", "icon", "keys", "has", "delete", "unsubscribeMonitor", "subscribe", "processTreeAtom", "hasShownFailureToast", "handleFailures", "failures", "length", "ns", "profile", "key", "actionLabel", "actionAlt", "onAction", "invokePromise", "OpenPluginRegistry", "filter", "t", "unsubscribeFailures", "failed", "showUndoToast", "message", "onUndo", "undoId", "crypto", "randomUUID", "currentUndoId", "closeLabel", "undoFiber", "runFork", "gen", "historyTracker", "waitFor", "HistoryTracker", "fromPubSub", "undoable", "pipe", "runForEach", "event", "sync", "undoPromise", "provideService", "contributes", "Null", "interrupt"]
7
7
  }
@@ -6,17 +6,17 @@ import {
6
6
  } from "./chunk-GLB73Q6U.mjs";
7
7
  import {
8
8
  DeckCapabilities_exports
9
- } from "./chunk-BS4EOYMK.mjs";
9
+ } from "./chunk-CL7JIOI5.mjs";
10
10
  import {
11
11
  computeActiveUpdates
12
- } from "./chunk-GBIGQKYW.mjs";
12
+ } from "./chunk-NGX6RXNV.mjs";
13
13
  import "./chunk-J5LGTIGS.mjs";
14
14
 
15
15
  // src/operations/open.ts
16
16
  import * as Effect from "effect/Effect";
17
17
  import * as Option from "effect/Option";
18
18
  import { Capabilities, Capability } from "@dxos/app-framework";
19
- import { AppCapabilities, LayoutOperation, createEdgeExistenceChecker, expandPath, validateNavigationTarget } from "@dxos/app-toolkit";
19
+ import { AppCapabilities, LayoutOperation, NotFound } from "@dxos/app-toolkit";
20
20
  import { Operation } from "@dxos/compute";
21
21
  import { Context } from "@dxos/context";
22
22
  import { Database, EID, Obj } from "@dxos/echo";
@@ -41,13 +41,13 @@ var handler = LayoutOperation.Open.pipe(Operation.withHandler(Effect.fnUntraced(
41
41
  }
42
42
  return Database.load(space.db.makeRef(id)).pipe(Effect.as(true), Effect.catchTag("EntityNotFoundError", () => Effect.succeed(false)), Effect.catchAll(() => Effect.succeed(false)));
43
43
  } : void 0;
44
- const checkRemoteExistence = client ? createEdgeExistenceChecker((spaceId, body) => client.edge.http.execQuery(new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 37 }), spaceId, body)) : void 0;
44
+ const checkRemoteExistence = client ? NotFound.createEdgeExistenceChecker((spaceId, body) => client.edge.http.execQuery(new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 37 }), spaceId, body)) : void 0;
45
45
  if (input.navigation === "immediate") {
46
46
  for (const subjectId of input.subject) {
47
- expandPath(graph, subjectId);
47
+ NotFound.expandPath(graph, subjectId);
48
48
  }
49
49
  }
50
- const validatedSubjects = yield* Effect.all(input.subject.map((subjectId) => input.navigation === "immediate" ? Effect.succeed(subjectId) : validateNavigationTarget({
50
+ const validatedSubjects = yield* Effect.all(input.subject.map((subjectId) => input.navigation === "immediate" ? Effect.succeed(subjectId) : NotFound.validateNavigationTarget({
51
51
  graph,
52
52
  subjectId,
53
53
  pathResolvers,
@@ -156,4 +156,4 @@ var open_default = handler;
156
156
  export {
157
157
  open_default as default
158
158
  };
159
- //# sourceMappingURL=open-5OYNO3RT.mjs.map
159
+ //# sourceMappingURL=open-VU7YS3HB.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/operations/open.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport { AppCapabilities, LayoutOperation, NotFound } from '@dxos/app-toolkit';\nimport { Operation } from '@dxos/compute';\nimport { Context } from '@dxos/context';\nimport { Database, EID, Obj } from '@dxos/echo';\nimport { log } from '@dxos/log';\nimport { AttentionCapabilities } from '@dxos/plugin-attention';\nimport { ClientCapabilities } from '@dxos/plugin-client';\nimport { Graph } from '@dxos/plugin-graph';\nimport { ObservabilityOperation } from '@dxos/plugin-observability';\n\nimport { openSubjectsOnActiveDeck } from '../layout';\nimport { DeckCapabilities } from '../types';\nimport { computeActiveUpdates } from '../util';\nimport { updateActiveDeck } from './helpers';\n\nconst handler: Operation.WithHandler<typeof LayoutOperation.Open> = LayoutOperation.Open.pipe(\n Operation.withHandler(\n Effect.fnUntraced(function* (input) {\n log('LayoutOperation.Open handler start');\n const { graph } = yield* Capability.get(AppCapabilities.AppGraph);\n const attention = yield* Capability.get(AttentionCapabilities.Attention);\n\n // Validate navigation targets, redirecting to 404 if not found.\n const capabilities = yield* Capability.Service;\n const pathResolvers = capabilities.getAll(AppCapabilities.NavigationPathResolver);\n const client = yield* Capability.get(ClientCapabilities.Client).pipe(\n Effect.catchAll(() => Effect.succeed(undefined)),\n );\n // Existence checkers for the resolved EID: local (load + catchTag) first, then remote (edge).\n const checkLocalExistence = client\n ? (id: EID.EID) => {\n const spaceId = EID.getSpaceId(id);\n const space = spaceId ? client.spaces.get(spaceId) : undefined;\n if (!space) {\n return Effect.succeed(false);\n }\n return Database.load(space.db.makeRef(id)).pipe(\n Effect.as(true),\n Effect.catchTag('EntityNotFoundError', () => Effect.succeed(false)),\n Effect.catchAll(() => Effect.succeed(false)),\n );\n }\n : undefined;\n const checkRemoteExistence = client\n ? NotFound.createEdgeExistenceChecker((spaceId, body) =>\n client.edge.http.execQuery(new Context(), spaceId, body),\n )\n : undefined;\n\n // Immediate: skip 404 / resolver checks but still expand the path (same as validate’s first step).\n if (input.navigation === 'immediate') {\n for (const subjectId of input.subject) {\n NotFound.expandPath(graph, subjectId);\n }\n }\n\n const validatedSubjects = yield* Effect.all(\n input.subject.map((subjectId) =>\n input.navigation === 'immediate'\n ? Effect.succeed(subjectId)\n : NotFound.validateNavigationTarget({\n graph,\n subjectId,\n pathResolvers,\n checkLocalExistence,\n checkRemoteExistence,\n }),\n ),\n );\n input = { ...input, subject: validatedSubjects };\n\n {\n const state = yield* Capabilities.getAtomValue(DeckCapabilities.State);\n if (input.workspace && state.activeDeck !== input.workspace) {\n yield* Operation.invoke(LayoutOperation.SwitchWorkspace, { subject: input.workspace });\n }\n }\n\n // Dedup subjects against the active deck using DXN identity.\n // The same object can appear under different graph paths (e.g., via collections vs types).\n // Resolve each subject's DXN and, if it matches an already-open deck item, remap the\n // subject to the existing deck entry so that openEntry's exact-match check succeeds.\n // Only needed in multi (deck) mode; solo mode replaces the single visible item anyway.\n {\n const deck = yield* DeckCapabilities.getDeck();\n const active = !deck.solo && deck.initialized ? deck.active : [];\n if (active.length > 0 && input.subject.length > 0) {\n const resolveDXN = (qualifiedPath: string) =>\n Effect.reduce(pathResolvers, Option.none<string>(), (acc, resolver) =>\n Option.isSome(acc)\n ? Effect.succeed(acc)\n : resolver(qualifiedPath).pipe(\n Effect.map((opt) => Option.map(opt, (dxn) => dxn.toString())),\n Effect.catchAll(() => Effect.succeed(Option.none<string>())),\n ),\n );\n\n // Build DXN → deck item ID map for active items.\n const deckDxnMap = new Map<string, string>();\n yield* Effect.all(\n active.map((deckId) =>\n resolveDXN(deckId).pipe(\n Effect.map((opt) => {\n if (Option.isSome(opt)) {\n deckDxnMap.set(opt.value, deckId);\n }\n }),\n ),\n ),\n { concurrency: 'unbounded' },\n );\n\n // Remap subjects whose DXN matches an existing deck item.\n if (deckDxnMap.size > 0) {\n const remapped = yield* Effect.all(\n input.subject.map((subjectId) =>\n resolveDXN(subjectId).pipe(\n Effect.map((opt) => {\n if (Option.isSome(opt)) {\n const existing = deckDxnMap.get(opt.value);\n if (existing && existing !== subjectId) {\n return existing;\n }\n }\n return subjectId;\n }),\n ),\n ),\n { concurrency: 'unbounded' },\n );\n input = { ...input, subject: remapped };\n }\n }\n }\n\n // Compute the next active deck state and apply it.\n // In solo or uninitialized mode the subject list replaces the deck entirely.\n // In multi (deck) mode, subjects are merged via openSubjectsOnActiveDeck which\n // uses stack semantics (truncate after pivot, then push new entries).\n let previouslyOpenIds: Set<string>;\n {\n const deck = yield* DeckCapabilities.getDeck();\n previouslyOpenIds = new Set<string>(deck.solo ? [deck.solo] : deck.active);\n const next =\n deck.solo || !deck.initialized\n ? [...input.subject]\n : openSubjectsOnActiveDeck(deck.active, input.subject, {\n pivotId: input.pivotId,\n key: input.key,\n });\n\n const { deckUpdates, toAttend: _toAttend } = computeActiveUpdates({ next, deck, attention });\n yield* Capabilities.updateAtomValue(DeckCapabilities.State, (state) => updateActiveDeck(state, deckUpdates));\n }\n\n // Schedule side-effects for the newly opened items: scroll into view, expose in\n // the navigation sidebar, and emit observability events.\n // When nothing is newly opened (subject was already visible), the fallback\n // `input.subject[0]` still triggers scroll and expose so the user is taken there.\n {\n const deck = yield* DeckCapabilities.getDeck();\n const ids = deck.solo ? [deck.solo] : deck.active;\n const newlyOpen = ids.filter((i: string) => !previouslyOpenIds.has(i));\n\n if (input.scrollIntoView !== false && (newlyOpen[0] ?? input.subject[0])) {\n yield* Operation.schedule(LayoutOperation.ScrollIntoView, {\n subject: newlyOpen[0] ?? input.subject[0],\n });\n }\n\n if (newlyOpen[0] ?? input.subject[0]) {\n yield* Operation.schedule(LayoutOperation.Expose, { subject: newlyOpen[0] ?? input.subject[0] });\n }\n\n for (const subjectId of newlyOpen) {\n const typename = Option.match(Graph.getNode(graph, subjectId), {\n onNone: () => undefined,\n onSome: (node) => {\n const active = node.data;\n return Obj.isObject(active) ? Obj.getTypename(active) : undefined;\n },\n });\n yield* Operation.schedule(ObservabilityOperation.SendEvent, {\n name: 'navigation.activate',\n properties: { subjectId, typename },\n });\n }\n }\n\n return validatedSubjects;\n }),\n ),\n);\n\nexport default handler;\n"],
5
+ "mappings": "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",
6
+ "names": ["Effect", "Option", "Capabilities", "Capability", "AppCapabilities", "LayoutOperation", "NotFound", "Operation", "Context", "Database", "EID", "Obj", "log", "AttentionCapabilities", "ClientCapabilities", "Graph", "ObservabilityOperation", "LayoutOperation", "graph", "Capability", "get", "AppCapabilities", "AttentionCapabilities", "capabilities", "Service", "client", "ClientCapabilities", "checkLocalExistence", "id", "spaces", "space", "Effect", "succeed", "load", "makeRef", "undefined", "checkRemoteExistence", "NotFound", "createEdgeExistenceChecker", "spaceId", "body", "execQuery", "Context", "input", "expandPath", "subjectId", "pathResolvers", "subject", "Operation", "invoke", "SwitchWorkspace", "workspace", "active", "length", "resolveDXN", "qualifiedPath", "reduce", "deckDxnMap", "Map", "isSome", "opt", "set", "deckId", "concurrency", "Option", "value", "existing", "deck", "next", "openSubjectsOnActiveDeck", "pivotId", "key", "deckUpdates", "attention", "newlyOpen", "schedule", "ScrollIntoView", "onNone", "onSome", "node", "isObject", "properties", "typename"]
7
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DeckOperationHandlerSet
3
- } from "../chunk-Q4W6B4IB.mjs";
3
+ } from "../chunk-UZLAR4DR.mjs";
4
4
  import "../chunk-J5LGTIGS.mjs";
5
5
  export {
6
6
  DeckOperationHandlerSet
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  DeckOperationHandlerSet
3
- } from "./chunk-Q4W6B4IB.mjs";
3
+ } from "./chunk-UZLAR4DR.mjs";
4
4
  import {
5
5
  meta
6
- } from "./chunk-PYEY5SEC.mjs";
6
+ } from "./chunk-KY7LMF4D.mjs";
7
7
  import "./chunk-J5LGTIGS.mjs";
8
8
 
9
9
  // src/plugin.ts
@@ -8,7 +8,7 @@ import { DeckLayout } from "#containers";
8
8
  import { useDeckState } from "#hooks";
9
9
  import { meta } from "#meta";
10
10
  var react_root_default = Capability.makeModule(() => Effect.succeed(Capability.contributes(Capabilities.ReactRoot, {
11
- id: meta.id,
11
+ id: meta.profile.key,
12
12
  root: () => {
13
13
  const { state, updateEphemeral } = useDeckState();
14
14
  const handleDismissToast = useCallback((id) => {
@@ -41,4 +41,4 @@ var react_root_default = Capability.makeModule(() => Effect.succeed(Capability.c
41
41
  export {
42
42
  react_root_default as default
43
43
  };
44
- //# sourceMappingURL=react-root-HH5DEUOG.mjs.map
44
+ //# sourceMappingURL=react-root-E6TAFHX6.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/capabilities/react-root.tsx"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport React, { useCallback } from 'react';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\n\nimport { DeckLayout } from '#containers';\nimport { useDeckState } from '#hooks';\nimport { meta } from '#meta';\n\nexport default Capability.makeModule(() =>\n Effect.succeed(\n Capability.contributes(Capabilities.ReactRoot, {\n id: meta.profile.key,\n root: () => {\n const { state, updateEphemeral } = useDeckState();\n\n const handleDismissToast = useCallback(\n (id: string) => {\n if (!state.toasts.some((toast) => toast.id === id)) {\n return;\n }\n // Allow time for the toast exit animation (animate-toast-hide, 100ms) before unmounting.\n // TODO(burdon): Factor out and unregister timeout.\n setTimeout(() => {\n // Re-resolve the toast by id inside the update: the toast list may have changed during\n // the delay, so a captured index would point at the wrong (or a missing) entry.\n updateEphemeral((s) => {\n const toastToRemove = s.toasts.find((toast) => toast.id === id);\n if (!toastToRemove) {\n return s;\n }\n const newCurrentUndoId = toastToRemove.id === s.currentUndoId ? undefined : s.currentUndoId;\n return {\n ...s,\n currentUndoId: newCurrentUndoId,\n toasts: s.toasts.filter((toast) => toast.id !== id),\n };\n });\n }, 150);\n },\n [state.toasts, updateEphemeral],\n );\n\n return <DeckLayout onDismissToast={handleDismissToast} />;\n },\n }),\n ),\n);\n"],
5
+ "mappings": ";;;AAIA,YAAYA,YAAY;AACxB,OAAOC,SAASC,mBAAmB;AAEnC,SAASC,cAAcC,kBAAkB;AAEzC,SAASC,kBAAkB;AAC3B,SAASC,oBAAoB;AAC7B,SAASC,YAAY;AAErB,IAAA,qBAAeH,WAAWI,WAAW,MAC5BC,eACLL,WAAWM,YAAYP,aAAaQ,WAAW;EAC7CC,IAAIL,KAAKM,QAAQC;EACjBC,MAAM,MAAA;AACJ,UAAM,EAAEC,OAAOC,gBAAe,IAAKX,aAAAA;AAEnC,UAAMY,qBAAqBhB,YACzB,CAACU,OAAAA;AACC,UAAI,CAACI,MAAMG,OAAOC,KAAK,CAACC,UAAUA,MAAMT,OAAOA,EAAAA,GAAK;AAClD;MACF;AAGAU,iBAAW,MAAA;AAGTL,wBAAgB,CAACM,MAAAA;AACf,gBAAMC,gBAAgBD,EAAEJ,OAAOM,KAAK,CAACJ,UAAUA,MAAMT,OAAOA,EAAAA;AAC5D,cAAI,CAACY,eAAe;AAClB,mBAAOD;UACT;AACA,gBAAMG,mBAAmBF,cAAcZ,OAAOW,EAAEI,gBAAgBC,SAAYL,EAAEI;AAC9E,iBAAO;YACL,GAAGJ;YACHI,eAAeD;YACfP,QAAQI,EAAEJ,OAAOU,OAAO,CAACR,UAAUA,MAAMT,OAAOA,EAAAA;UAClD;QACF,CAAA;MACF,GAAG,GAAA;IACL,GACA;MAACI,MAAMG;MAAQF;KAAgB;AAGjC,WAAO,sBAAA,cAACZ,YAAAA;MAAWyB,gBAAgBZ;;EACrC;AACF,CAAA,CAAA,CAAA;",
6
+ "names": ["Effect", "React", "useCallback", "Capabilities", "Capability", "DeckLayout", "useDeckState", "meta", "makeModule", "succeed", "contributes", "ReactRoot", "id", "profile", "key", "root", "state", "updateEphemeral", "handleDismissToast", "toasts", "some", "toast", "setTimeout", "s", "toastToRemove", "find", "newCurrentUndoId", "currentUndoId", "undefined", "filter", "onDismissToast"]
7
+ }
@@ -5,14 +5,14 @@ import * as Effect from "effect/Effect";
5
5
  import React from "react";
6
6
  import { Capabilities, Capability } from "@dxos/app-framework";
7
7
  import { Surface, useSettingsState } from "@dxos/app-framework/ui";
8
- import { NOT_FOUND_PATH } from "@dxos/app-toolkit";
8
+ import { NotFound } from "@dxos/app-toolkit";
9
9
  import { AppSurface, NotFoundArticle } from "@dxos/app-toolkit/ui";
10
10
  import { DeckSettings } from "#components";
11
11
  import { meta } from "#meta";
12
12
  var react_surface_default = Capability.makeModule(() => Effect.succeed(Capability.contributes(Capabilities.ReactSurface, [
13
13
  Surface.create({
14
14
  id: "pluginSettings",
15
- filter: AppSurface.settings(AppSurface.Article, meta.id),
15
+ filter: AppSurface.settings(AppSurface.Article, meta.profile.key),
16
16
  component: ({ data: { subject } }) => {
17
17
  const { settings, updateSettings } = useSettingsState(subject.atom);
18
18
  return /* @__PURE__ */ React.createElement(DeckSettings, {
@@ -23,12 +23,11 @@ var react_surface_default = Capability.makeModule(() => Effect.succeed(Capabilit
23
23
  }),
24
24
  Surface.create({
25
25
  id: "notFound",
26
- role: "article",
27
- filter: (data) => data.attendableId === NOT_FOUND_PATH,
26
+ filter: Surface.makeFilter(AppSurface.Article, (data) => data.attendableId === NotFound.NOT_FOUND_PATH),
28
27
  component: () => /* @__PURE__ */ React.createElement(NotFoundArticle, null)
29
28
  })
30
29
  ])));
31
30
  export {
32
31
  react_surface_default as default
33
32
  };
34
- //# sourceMappingURL=react-surface-3UVVCK3O.mjs.map
33
+ //# sourceMappingURL=react-surface-O4POQWYL.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/capabilities/react-surface.tsx"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport React from 'react';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport { Surface, useSettingsState } from '@dxos/app-framework/ui';\nimport { NotFound } from '@dxos/app-toolkit';\nimport { AppSurface, NotFoundArticle } from '@dxos/app-toolkit/ui';\n\nimport { DeckSettings } from '#components';\nimport { meta } from '#meta';\nimport { type Settings } from '#types';\n\nexport default Capability.makeModule(() =>\n Effect.succeed(\n Capability.contributes(Capabilities.ReactSurface, [\n Surface.create({\n id: 'pluginSettings',\n filter: AppSurface.settings(AppSurface.Article, meta.profile.key),\n component: ({ data: { subject } }) => {\n const { settings, updateSettings } = useSettingsState<Settings.Settings>(subject.atom);\n return <DeckSettings settings={settings} onSettingsChange={updateSettings} />;\n },\n }),\n Surface.create({\n id: 'notFound',\n filter: Surface.makeFilter(AppSurface.Article, (data) => data.attendableId === NotFound.NOT_FOUND_PATH),\n component: () => <NotFoundArticle />,\n }),\n ]),\n ),\n);\n"],
5
+ "mappings": ";;;AAIA,YAAYA,YAAY;AACxB,OAAOC,WAAW;AAElB,SAASC,cAAcC,kBAAkB;AACzC,SAASC,SAASC,wBAAwB;AAC1C,SAASC,gBAAgB;AACzB,SAASC,YAAYC,uBAAuB;AAE5C,SAASC,oBAAoB;AAC7B,SAASC,YAAY;AAGrB,IAAA,wBAAeP,WAAWQ,WAAW,MAC5BC,eACLT,WAAWU,YAAYX,aAAaY,cAAc;EAChDV,QAAQW,OAAO;IACbC,IAAI;IACJC,QAAQV,WAAWW,SAASX,WAAWY,SAAST,KAAKU,QAAQC,GAAG;IAChEC,WAAW,CAAC,EAAEC,MAAM,EAAEC,QAAO,EAAE,MAAE;AAC/B,YAAM,EAAEN,UAAUO,eAAc,IAAKpB,iBAAoCmB,QAAQE,IAAI;AACrF,aAAO,sBAAA,cAACjB,cAAAA;QAAaS;QAAoBS,kBAAkBF;;IAC7D;EACF,CAAA;EACArB,QAAQW,OAAO;IACbC,IAAI;IACJC,QAAQb,QAAQwB,WAAWrB,WAAWY,SAAS,CAACI,SAASA,KAAKM,iBAAiBvB,SAASwB,cAAc;IACtGR,WAAW,MAAM,sBAAA,cAACd,iBAAAA,IAAAA;EACpB,CAAA;CACD,CAAA,CAAA;",
6
+ "names": ["Effect", "React", "Capabilities", "Capability", "Surface", "useSettingsState", "NotFound", "AppSurface", "NotFoundArticle", "DeckSettings", "meta", "makeModule", "succeed", "contributes", "ReactSurface", "create", "id", "filter", "settings", "Article", "profile", "key", "component", "data", "subject", "updateSettings", "atom", "onSettingsChange", "makeFilter", "attendableId", "NOT_FOUND_PATH"]
7
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DeckCapabilities_exports
3
- } from "./chunk-BS4EOYMK.mjs";
3
+ } from "./chunk-CL7JIOI5.mjs";
4
4
  import "./chunk-J5LGTIGS.mjs";
5
5
 
6
6
  // src/operations/revert-workspace.ts
@@ -18,4 +18,4 @@ var revert_workspace_default = handler;
18
18
  export {
19
19
  revert_workspace_default as default
20
20
  };
21
- //# sourceMappingURL=revert-workspace-B2QLT2C4.mjs.map
21
+ //# sourceMappingURL=revert-workspace-24TKG3I7.mjs.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DeckCapabilities_exports
3
- } from "./chunk-BS4EOYMK.mjs";
3
+ } from "./chunk-CL7JIOI5.mjs";
4
4
  import "./chunk-J5LGTIGS.mjs";
5
5
 
6
6
  // src/operations/scroll-into-view.ts
@@ -18,4 +18,4 @@ var scroll_into_view_default = handler;
18
18
  export {
19
19
  scroll_into_view_default as default
20
20
  };
21
- //# sourceMappingURL=scroll-into-view-B52C3PJO.mjs.map
21
+ //# sourceMappingURL=scroll-into-view-3VXT6TWC.mjs.map
@@ -3,10 +3,10 @@ import {
3
3
  } from "./chunk-GLB73Q6U.mjs";
4
4
  import {
5
5
  DeckCapabilities_exports
6
- } from "./chunk-BS4EOYMK.mjs";
6
+ } from "./chunk-CL7JIOI5.mjs";
7
7
  import {
8
8
  computeActiveUpdates
9
- } from "./chunk-GBIGQKYW.mjs";
9
+ } from "./chunk-NGX6RXNV.mjs";
10
10
  import "./chunk-J5LGTIGS.mjs";
11
11
 
12
12
  // src/operations/set.ts
@@ -34,4 +34,4 @@ var set_default = handler;
34
34
  export {
35
35
  set_default as default
36
36
  };
37
- //# sourceMappingURL=set-PA35ONXO.mjs.map
37
+ //# sourceMappingURL=set-RFOLTI57.mjs.map
@@ -5,7 +5,7 @@ import {
5
5
  DeckCapabilities_exports,
6
6
  getMode,
7
7
  isLayoutMode
8
- } from "./chunk-BS4EOYMK.mjs";
8
+ } from "./chunk-CL7JIOI5.mjs";
9
9
  import "./chunk-J5LGTIGS.mjs";
10
10
 
11
11
  // src/operations/set-layout-mode.ts
@@ -82,4 +82,4 @@ var set_layout_mode_default = handler;
82
82
  export {
83
83
  set_layout_mode_default as default
84
84
  };
85
- //# sourceMappingURL=set-layout-mode-RPCCPQRB.mjs.map
85
+ //# sourceMappingURL=set-layout-mode-AZ73W52Z.mjs.map
@@ -9,7 +9,7 @@ import { meta } from "#meta";
9
9
  import { DeckCapabilities, Settings } from "#types";
10
10
  var settings_default = Capability.makeModule(() => Effect.sync(() => {
11
11
  const settingsAtom = createKvsStore({
12
- key: meta.id,
12
+ key: meta.profile.key,
13
13
  schema: Settings.Settings,
14
14
  defaultValue: () => ({
15
15
  showHints: false,
@@ -21,7 +21,7 @@ var settings_default = Capability.makeModule(() => Effect.sync(() => {
21
21
  return [
22
22
  Capability.contributes(DeckCapabilities.Settings, settingsAtom),
23
23
  Capability.contributes(AppCapabilities.Settings, {
24
- prefix: meta.id,
24
+ prefix: meta.profile.key,
25
25
  schema: Settings.Settings,
26
26
  atom: settingsAtom
27
27
  })
@@ -30,4 +30,4 @@ var settings_default = Capability.makeModule(() => Effect.sync(() => {
30
30
  export {
31
31
  settings_default as default
32
32
  };
33
- //# sourceMappingURL=settings-EGNYUM4T.mjs.map
33
+ //# sourceMappingURL=settings-6CDQEB6B.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/capabilities/settings.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capability } from '@dxos/app-framework';\nimport { AppCapabilities } from '@dxos/app-toolkit';\nimport { createKvsStore } from '@dxos/effect';\n\nimport { meta } from '#meta';\nimport { DeckCapabilities, Settings } from '#types';\n\nexport default Capability.makeModule(() =>\n Effect.sync(() => {\n const settingsAtom = createKvsStore({\n key: meta.profile.key,\n schema: Settings.Settings,\n defaultValue: () => ({\n showHints: false,\n enableDeck: false,\n enableNativeRedirect: false,\n encapsulatedPlanks: false,\n }),\n });\n\n return [\n Capability.contributes(DeckCapabilities.Settings, settingsAtom),\n Capability.contributes(AppCapabilities.Settings, {\n prefix: meta.profile.key,\n schema: Settings.Settings,\n atom: settingsAtom,\n }),\n ];\n }),\n);\n"],
5
+ "mappings": ";;;AAIA,YAAYA,YAAY;AAExB,SAASC,kBAAkB;AAC3B,SAASC,uBAAuB;AAChC,SAASC,sBAAsB;AAE/B,SAASC,YAAY;AACrB,SAASC,kBAAkBC,gBAAgB;AAE3C,IAAA,mBAAeL,WAAWM,WAAW,MAC5BC,YAAK,MAAA;AACV,QAAMC,eAAeN,eAAe;IAClCO,KAAKN,KAAKO,QAAQD;IAClBE,QAAQN,SAASA;IACjBO,cAAc,OAAO;MACnBC,WAAW;MACXC,YAAY;MACZC,sBAAsB;MACtBC,oBAAoB;IACtB;EACF,CAAA;AAEA,SAAO;IACLhB,WAAWiB,YAAYb,iBAAiBC,UAAUG,YAAAA;IAClDR,WAAWiB,YAAYhB,gBAAgBI,UAAU;MAC/Ca,QAAQf,KAAKO,QAAQD;MACrBE,QAAQN,SAASA;MACjBc,MAAMX;IACR,CAAA;;AAEJ,CAAA,CAAA;",
6
+ "names": ["Effect", "Capability", "AppCapabilities", "createKvsStore", "meta", "DeckCapabilities", "Settings", "makeModule", "sync", "settingsAtom", "key", "profile", "schema", "defaultValue", "showHints", "enableDeck", "enableNativeRedirect", "encapsulatedPlanks", "contributes", "prefix", "atom"]
7
+ }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  sanitizePersistedState
3
- } from "./chunk-GBIGQKYW.mjs";
3
+ } from "./chunk-NGX6RXNV.mjs";
4
4
  import "./chunk-J5LGTIGS.mjs";
5
5
 
6
6
  // src/capabilities/state.ts
@@ -42,7 +42,7 @@ var defaultDeckEphemeralState = {
42
42
  var state_default = Capability.makeModule(Effect.fnUntraced(function* () {
43
43
  const registry = yield* Capability.get(Capabilities.AtomRegistry);
44
44
  const stateAtom = createKvsStore({
45
- key: `${meta.id}.state`,
45
+ key: `${meta.profile.key}.state`,
46
46
  schema: StoredDeckState,
47
47
  defaultValue: () => ({
48
48
  ...defaultDeckState
@@ -83,4 +83,4 @@ var state_default = Capability.makeModule(Effect.fnUntraced(function* () {
83
83
  export {
84
84
  state_default as default
85
85
  };
86
- //# sourceMappingURL=state-IIDXMQUO.mjs.map
86
+ //# sourceMappingURL=state-D3YXB5NP.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/capabilities/state.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom } from '@effect-atom/atom-react';\nimport * as Effect from 'effect/Effect';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport { AppCapabilities } from '@dxos/app-toolkit';\nimport { createKvsStore } from '@dxos/effect';\nimport { invariant } from '@dxos/invariant';\n\nimport { meta } from '#meta';\nimport { DeckCapabilities, type EphemeralDeckState, StoredDeckState, defaultDeck, getMode } from '#types';\n\nimport { sanitizePersistedState } from '../util';\n\n/** Default persisted state. */\nconst defaultDeckState: StoredDeckState = {\n sidebarState: 'expanded',\n complementarySidebarState: 'collapsed',\n complementarySidebarPanel: undefined,\n activeDeck: 'default',\n previousDeck: 'default',\n decks: {\n default: { ...defaultDeck },\n },\n previousMode: {},\n};\n\n/** Default ephemeral state. */\nconst defaultDeckEphemeralState: EphemeralDeckState = {\n dialogContent: null,\n dialogOpen: false,\n dialogBlockAlign: undefined,\n dialogType: undefined,\n popoverContent: null,\n popoverAnchor: undefined,\n popoverAnchorId: undefined,\n popoverOpen: false,\n toasts: [],\n currentUndoId: undefined,\n scrollIntoView: undefined,\n};\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const registry = yield* Capability.get(Capabilities.AtomRegistry);\n\n // Persisted state using KVS store.\n const stateAtom = createKvsStore({\n key: `${meta.id}.state`,\n schema: StoredDeckState,\n defaultValue: () => ({ ...defaultDeckState }),\n });\n\n // Ephemeral state (not persisted, but kept alive to prevent GC resets).\n const ephemeralAtom = Atom.make<EphemeralDeckState>({ ...defaultDeckEphemeralState }).pipe(Atom.keepAlive);\n\n // Sanitize persisted state on startup (see sanitizePersistedState for details).\n const currentState = registry.get(stateAtom);\n const sanitizedState = sanitizePersistedState(currentState);\n if (sanitizedState !== currentState) {\n registry.set(stateAtom, sanitizedState);\n }\n\n // Create derived layout atom (read-only) from both state atoms.\n const layoutAtom = Atom.make((get) => {\n const state = get(stateAtom);\n const ephemeral = get(ephemeralAtom);\n const deck = state.decks[state.activeDeck];\n invariant(deck, `Deck not found: ${state.activeDeck}`);\n return {\n mode: getMode(deck),\n dialogOpen: ephemeral.dialogOpen,\n sidebarOpen: state.sidebarState === 'expanded',\n complementarySidebarOpen: state.complementarySidebarState === 'expanded',\n workspace: state.activeDeck,\n active: deck.solo ? [deck.solo] : deck.active,\n inactive: deck.inactive,\n scrollIntoView: ephemeral.scrollIntoView,\n } satisfies AppCapabilities.Layout;\n }).pipe(Atom.keepAlive);\n\n return [\n Capability.contributes(DeckCapabilities.State, stateAtom),\n Capability.contributes(DeckCapabilities.EphemeralState, ephemeralAtom),\n Capability.contributes(AppCapabilities.Layout, layoutAtom),\n ];\n }),\n);\n"],
5
- "mappings": ";;;;;;AAIA,SAASA,YAAY;AACrB,YAAYC,YAAY;AAExB,SAASC,cAAcC,kBAAkB;AACzC,SAASC,uBAAuB;AAChC,SAASC,sBAAsB;AAC/B,SAASC,iBAAiB;AAE1B,SAASC,YAAY;AACrB,SAASC,kBAA2CC,iBAAiBC,aAAaC,eAAe;AAIjG,IAAA,eAAA;AAG6B,IAAA,mBAAA;EAC3BC,cAAAA;EACAC,2BAAY;EACZC,2BAAc;EACdC,YAAO;gBACI;;IAAiB,SAAA;MAC5B,GAAA;IACAC;EACF;EAEA,cAAA,CAAA;;AAGc,IAAA,4BAAA;EACZC,eAAAA;EACAC,YAAYC;EACZC,kBAAgB;EAChBC,YAAAA;EACAC,gBAAAA;EACAC,eAAa;EACbC,iBAAU;EACVC,aAAAA;EACAC,QAAAA,CAAAA;EACF,eAAA;EAEA,gBAAeC;;IAIX,gBAAA,WAAA,WAAmC,kBAAA,aAAA;AACnC,QAAMC,WAAAA,OAAYC,WAAe,IAAA,aAAA,YAAA;QAE/BC,YAAQC,eAAAA;IACRC,KAAAA,GAAAA,KAAAA,EAAc;YAAS;kBAAoB,OAAA;MAC7C,GAAA;IAEA;EACA,CAAA;AAAmF,QAAGC,gBAAmB,KAAA,KAAA;IAEzG,GAAA;EACA,CAAA,EAAA,KAAMC,KAAAA,SAAeC;AAErB,QAAIC,eAAAA,SAAmBF,IAAAA,SAAc;QACnCC,iBAAaP,uBAAWQ,YAAAA;AAC1B,MAAA,mBAAA,cAAA;AAEA,aAAA,IAAA,WAAA,cAAA;EACA;QAEE,aAAMC,KAAYC,KAAIC,CAAAA,QAAAA;AACtB,UAAMC,QAAOC,IAAAA,SAAYA;AACzBC,UAAAA,YAAiB,IAAA,aAAkBD;AACnC,UAAA,OAAO,MAAA,MAAA,MAAA,UAAA;cACCE,MAAAA,mBAAQH,MAAAA,UAAAA,IAAAA,EAAAA,YAAAA,YAAAA,GAAAA,cAAAA,GAAAA,IAAAA,GAAAA,MAAAA,GAAAA,CAAAA,QAAAA,uCAAAA,EAAAA,CAAAA;WACdI;MACAC,MAAAA,QAAaJ,IAAAA;MACbK,YAAAA,UAAAA;MACAC,aAAWN,MAAM5B,iBAAU;MAC3BmC,0BAAoB,MAAA,8BAAA;iBAAMC,MAAI;cAAIT,KAAKQ,OAAM;QAC7CE,KAAAA;MACAxB,IAAAA,KAAAA;MACF,UAAA,KAAA;MACMyB,gBAAc,UAAA;IAEtB;UACExB,KAAAA,SAAWyB;SACXzB;IACAA,WAAWyB,YAAYC,iBAAgBC,OAAQC,SAAAA;IAChD,WAAA,YAAA,iBAAA,gBAAA,aAAA;IAEH,WAAA,YAAA,gBAAA,QAAA,UAAA;;;",
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom } from '@effect-atom/atom-react';\nimport * as Effect from 'effect/Effect';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport { AppCapabilities } from '@dxos/app-toolkit';\nimport { createKvsStore } from '@dxos/effect';\nimport { invariant } from '@dxos/invariant';\n\nimport { meta } from '#meta';\nimport { DeckCapabilities, type EphemeralDeckState, StoredDeckState, defaultDeck, getMode } from '#types';\n\nimport { sanitizePersistedState } from '../util';\n\n/** Default persisted state. */\nconst defaultDeckState: StoredDeckState = {\n sidebarState: 'expanded',\n complementarySidebarState: 'collapsed',\n complementarySidebarPanel: undefined,\n activeDeck: 'default',\n previousDeck: 'default',\n decks: {\n default: { ...defaultDeck },\n },\n previousMode: {},\n};\n\n/** Default ephemeral state. */\nconst defaultDeckEphemeralState: EphemeralDeckState = {\n dialogContent: null,\n dialogOpen: false,\n dialogBlockAlign: undefined,\n dialogType: undefined,\n popoverContent: null,\n popoverAnchor: undefined,\n popoverAnchorId: undefined,\n popoverOpen: false,\n toasts: [],\n currentUndoId: undefined,\n scrollIntoView: undefined,\n};\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const registry = yield* Capability.get(Capabilities.AtomRegistry);\n\n // Persisted state using KVS store.\n const stateAtom = createKvsStore({\n key: `${meta.profile.key}.state`,\n schema: StoredDeckState,\n defaultValue: () => ({ ...defaultDeckState }),\n });\n\n // Ephemeral state (not persisted, but kept alive to prevent GC resets).\n const ephemeralAtom = Atom.make<EphemeralDeckState>({ ...defaultDeckEphemeralState }).pipe(Atom.keepAlive);\n\n // Sanitize persisted state on startup (see sanitizePersistedState for details).\n const currentState = registry.get(stateAtom);\n const sanitizedState = sanitizePersistedState(currentState);\n if (sanitizedState !== currentState) {\n registry.set(stateAtom, sanitizedState);\n }\n\n // Create derived layout atom (read-only) from both state atoms.\n const layoutAtom = Atom.make((get) => {\n const state = get(stateAtom);\n const ephemeral = get(ephemeralAtom);\n const deck = state.decks[state.activeDeck];\n invariant(deck, `Deck not found: ${state.activeDeck}`);\n return {\n mode: getMode(deck),\n dialogOpen: ephemeral.dialogOpen,\n sidebarOpen: state.sidebarState === 'expanded',\n complementarySidebarOpen: state.complementarySidebarState === 'expanded',\n workspace: state.activeDeck,\n active: deck.solo ? [deck.solo] : deck.active,\n inactive: deck.inactive,\n scrollIntoView: ephemeral.scrollIntoView,\n } satisfies AppCapabilities.Layout;\n }).pipe(Atom.keepAlive);\n\n return [\n Capability.contributes(DeckCapabilities.State, stateAtom),\n Capability.contributes(DeckCapabilities.EphemeralState, ephemeralAtom),\n Capability.contributes(AppCapabilities.Layout, layoutAtom),\n ];\n }),\n);\n"],
5
+ "mappings": ";;;;;;AAIA,SAASA,YAAY;AACrB,YAAYC,YAAY;AAExB,SAASC,cAAcC,kBAAkB;AACzC,SAASC,uBAAuB;AAChC,SAASC,sBAAsB;AAC/B,SAASC,iBAAiB;AAE1B,SAASC,YAAY;AACrB,SAASC,kBAA2CC,iBAAiBC,aAAaC,eAAe;AAIjG,IAAA,eAAA;AAG6B,IAAA,mBAAA;EAC3BC,cAAAA;EACAC,2BAAY;EACZC,2BAAc;EACdC,YAAO;gBACI;;IAAiB,SAAA;MAC5B,GAAA;IACAC;EACF;EAEA,cAAA,CAAA;;AAGc,IAAA,4BAAA;EACZC,eAAAA;EACAC,YAAYC;EACZC,kBAAgB;EAChBC,YAAAA;EACAC,gBAAAA;EACAC,eAAa;EACbC,iBAAU;EACVC,aAAAA;EACAC,QAAAA,CAAAA;EACF,eAAA;EAEA,gBAAeC;;IAIX,gBAAA,WAAA,WAAmC,kBAAA,aAAA;AACnC,QAAMC,WAAAA,OAAYC,WAAe,IAAA,aAAA,YAAA;QAE/BC,YAAQC,eAAAA;IACRC,KAAAA,GAAAA,KAAAA,QAAqB,GAAA;YAAE;kBAAoB,OAAA;MAC7C,GAAA;IAEA;EACA,CAAA;AAAmF,QAAGC,gBAAmB,KAAA,KAAA;IAEzG,GAAA;EACA,CAAA,EAAA,KAAMC,KAAAA,SAAeC;AAErB,QAAIC,eAAAA,SAAmBF,IAAAA,SAAc;QACnCC,iBAAaP,uBAAWQ,YAAAA;AAC1B,MAAA,mBAAA,cAAA;AAEA,aAAA,IAAA,WAAA,cAAA;EACA;QAEE,aAAMC,KAAYC,KAAIC,CAAAA,QAAAA;AACtB,UAAMC,QAAOC,IAAAA,SAAYA;AACzBC,UAAAA,YAAiB,IAAA,aAAkBD;AACnC,UAAA,OAAO,MAAA,MAAA,MAAA,UAAA;cACCE,MAAAA,mBAAQH,MAAAA,UAAAA,IAAAA,EAAAA,YAAAA,YAAAA,GAAAA,cAAAA,GAAAA,IAAAA,GAAAA,MAAAA,GAAAA,CAAAA,QAAAA,uCAAAA,EAAAA,CAAAA;WACdI;MACAC,MAAAA,QAAaJ,IAAAA;MACbK,YAAAA,UAAAA;MACAC,aAAWN,MAAM5B,iBAAU;MAC3BmC,0BAAoB,MAAA,8BAAA;iBAAMC,MAAI;cAAIT,KAAKQ,OAAM;QAC7CE,KAAAA;MACAxB,IAAAA,KAAAA;MACF,UAAA,KAAA;MACMyB,gBAAc,UAAA;IAEtB;UACExB,KAAAA,SAAWyB;SACXzB;IACAA,WAAWyB,YAAYC,iBAAgBC,OAAQC,SAAAA;IAChD,WAAA,YAAA,iBAAA,gBAAA,aAAA;IAEH,WAAA,YAAA,gBAAA,QAAA,UAAA;;;",
6
6
  "names": ["Atom", "Effect", "Capabilities", "Capability", "AppCapabilities", "createKvsStore", "invariant", "meta", "DeckCapabilities", "StoredDeckState", "defaultDeck", "getMode", "complementarySidebarPanel", "activeDeck", "previousDeck", "decks", "previousMode", "dialogBlockAlign", "dialogType", "undefined", "popoverContent", "popoverAnchor", "popoverAnchorId", "popoverOpen", "toasts", "currentUndoId", "scrollIntoView", "Capability", "stateAtom", "createKvsStore", "schema", "StoredDeckState", "defaultValue", "pipe", "currentState", "registry", "sanitizedState", "ephemeral", "get", "ephemeralAtom", "deck", "state", "invariant", "getMode", "dialogOpen", "sidebarOpen", "complementarySidebarOpen", "workspace", "active", "solo", "inactive", "Atom", "contributes", "AppCapabilities", "Layout", "layoutAtom"]
7
7
  }
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  DeckCapabilities_exports,
3
3
  defaultDeck
4
- } from "./chunk-BS4EOYMK.mjs";
4
+ } from "./chunk-CL7JIOI5.mjs";
5
5
  import "./chunk-J5LGTIGS.mjs";
6
6
 
7
7
  // src/operations/switch-workspace.ts
8
8
  import * as Effect from "effect/Effect";
9
9
  import { Capabilities, Capability } from "@dxos/app-framework";
10
- import { AppCapabilities, isPinnedWorkspace, LayoutOperation } from "@dxos/app-toolkit";
10
+ import { AppCapabilities, LayoutOperation, Paths } from "@dxos/app-toolkit";
11
11
  import { Operation } from "@dxos/compute";
12
12
  import { invariant } from "@dxos/invariant";
13
13
  import { Graph, Node } from "@dxos/plugin-graph";
@@ -16,7 +16,7 @@ var handler = LayoutOperation.SwitchWorkspace.pipe(Operation.withHandler(Effect.
16
16
  const { graph } = yield* Capability.get(AppCapabilities.AppGraph);
17
17
  {
18
18
  const state = yield* Capabilities.getAtomValue(DeckCapabilities_exports.State);
19
- const shouldUpdatePrevious = !isPinnedWorkspace(state.activeDeck);
19
+ const shouldUpdatePrevious = !Paths.isPinnedWorkspace(state.activeDeck);
20
20
  yield* Capabilities.updateAtomValue(DeckCapabilities_exports.State, (state2) => {
21
21
  const newDecks = state2.decks[input.subject] ? state2.decks : {
22
22
  ...state2.decks,
@@ -57,4 +57,4 @@ var switch_workspace_default = handler;
57
57
  export {
58
58
  switch_workspace_default as default
59
59
  };
60
- //# sourceMappingURL=switch-workspace-LZF4KZXH.mjs.map
60
+ //# sourceMappingURL=switch-workspace-TBPT23CZ.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/operations/switch-workspace.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport { AppCapabilities, LayoutOperation, Paths } from '@dxos/app-toolkit';\nimport { Operation } from '@dxos/compute';\nimport { invariant } from '@dxos/invariant';\nimport { Graph, Node } from '@dxos/plugin-graph';\n\nimport { DeckCapabilities, defaultDeck } from '../types';\n\nconst handler: Operation.WithHandler<typeof LayoutOperation.SwitchWorkspace> = LayoutOperation.SwitchWorkspace.pipe(\n Operation.withHandler(\n Effect.fnUntraced(function* (input) {\n const { graph } = yield* Capability.get(AppCapabilities.AppGraph);\n\n {\n const state = yield* Capabilities.getAtomValue(DeckCapabilities.State);\n // TODO(wittjosiah): This is a hack to prevent the previous deck from being set for pinned items.\n // Ideally this should be worked into the data model in a generic way.\n const shouldUpdatePrevious = !Paths.isPinnedWorkspace(state.activeDeck);\n\n yield* Capabilities.updateAtomValue(DeckCapabilities.State, (state) => {\n const newDecks = state.decks[input.subject]\n ? state.decks\n : { ...state.decks, [input.subject]: { ...defaultDeck } };\n return {\n ...state,\n previousDeck: shouldUpdatePrevious ? state.activeDeck : state.previousDeck,\n activeDeck: input.subject,\n decks: newDecks,\n };\n });\n }\n\n {\n const state = yield* Capabilities.getAtomValue(DeckCapabilities.State);\n const deck = state.decks[input.subject];\n invariant(deck, `Deck not found: ${input.subject}`);\n\n const first = deck.solo ? deck.solo : deck.active[0];\n if (first) {\n yield* Operation.schedule(LayoutOperation.ScrollIntoView, { subject: first });\n } else {\n const [item] = Graph.getConnections(graph, input.subject, 'child').filter(\n (node) => !Node.isActionLike(node) && !node.properties.disposition,\n );\n if (item) {\n // Use `invoke` (synchronous) rather than `schedule` (fire-and-forget) so\n // that the implicit \"open first child\" finishes BEFORE this handler\n // returns. Otherwise, a caller that follows `SwitchWorkspace` with its\n // own `SetLayoutMode`/`Open` (e.g. WelcomePlugin DefaultContent) has\n // its `solo`/`active` clobbered by this scheduled Open when it later\n // races behind the caller's state writes.\n yield* Operation.invoke(LayoutOperation.Open, { subject: [item.id] });\n }\n }\n }\n }),\n ),\n);\n\nexport default handler;\n"],
5
+ "mappings": ";;;;;;;AAIA,YAAYA,YAAY;AAExB,SAASC,cAAcC,kBAAkB;AACzC,SAASC,iBAAiBC,iBAAiBC,aAAa;AACxD,SAASC,iBAAiB;AAC1B,SAASC,iBAAiB;AAC1B,SAASC,OAAOC,YAAY;AAI5B,IAAA,eAA+EC;IAKzE,UAAA,gBAAA,gBAAA,KAAA,UAAA,YAAA,kBAAA,WAAA,OAAA;QACE,EAAA,MAAMC,IAAQ,OAAOC,WAAAA,IAAaC,gBAAaC,QAAAA;;AAE/C,UAAA,QAAA,OAAA,aAAA,aAAA,yBAAA,KAAA;UAIE,uBAAuBC,CAAAA,MAAMC,kBACzBL,MAAMI,UACN;wBAAWA,gBAAK,yBAAA,OAAA,CAAAJ,WAAA;YAAGK,WAAMC,OAAU,MAAA,MAAA,OAAA,IAAAN,OAAA,QAAA;kBAAKO;QAAY,CAAA,MAAA,OAAA,GAAA;UAAE,GAAA;QAC1D;;aAEEC;QACAC,GAAAA;QACAL,cAAOM,uBAAAA,OAAAA,aAAAA,OAAAA;QACT,YAAA,MAAA;QACF,OAAA;MACF;IAEA,CAAA;;;AAGEC,UAAAA,QAAUC,OAAO,aAAgB,aAAQN,yBAAS,KAAA;AAElD,UAAMO,OAAAA,MAAaC,MAAI,MAAQA,OAAOF;AACtC,cAAIC,MAAO,mBAAA,MAAA,OAAA,IAAA,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,IAAA,GAAA,MAAA,GAAA,CAAA,QAAA,oCAAA,EAAA,CAAA;UACT,QAAOE,KAAAA,OAAUC,KAASjB,OAAAA,KAAAA,OAAgBkB,CAAAA;eAAkBX;AAAe,aAAA,UAAA,SAAA,gBAAA,gBAAA;QACtE,SAAA;MACL,CAAA;WAGA;YACE,CAAA,IAAA,IAAA,MAAA,eAAA,OAAA,MAAA,SAAA,OAAA,EAAA,OAAA,CAAA,SAAyE,CAAA,KAAA,aAAA,IAAA,KAAA,CAAA,KAAA,WAAA,WAAA;UACzE,MAAA;yBAKiE,OAAA,gBAAA,MAAA;mBAAC;YAAC,KAAA;UACrE;QACF,CAAA;MACF;IACF;EAIJ;;;",
6
+ "names": ["Effect", "Capabilities", "Capability", "AppCapabilities", "LayoutOperation", "Paths", "Operation", "invariant", "Graph", "Node", "LayoutOperation", "state", "Capabilities", "getAtomValue", "DeckCapabilities", "decks", "input", "subject", "defaultDeck", "previousDeck", "activeDeck", "newDecks", "invariant", "deck", "first", "solo", "Operation", "schedule", "ScrollIntoView"]
7
+ }
@@ -5,7 +5,7 @@ import { meta } from "#meta";
5
5
  var translations = [
6
6
  {
7
7
  "en-US": {
8
- [meta.id]: {
8
+ [meta.profile.key]: {
9
9
  "plugin.name": "Deck",
10
10
  "settings.title": "Deck settings",
11
11
  "main-header.label": "Main header",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/translations.ts"],
4
- "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Resource } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\n\nexport const translations = [\n {\n 'en-US': {\n [meta.id]: {\n 'plugin.name': 'Deck',\n 'settings.title': 'Deck settings',\n 'main-header.label': 'Main header',\n 'open-navigation-sidebar.label': 'Open sidebar',\n 'collapse-navigation-sidebar.label': 'Close sidebar',\n 'open-complementary-sidebar.label': 'Open context sidebar',\n 'close-complementary-sidebar.label': 'Close context sidebar',\n 'sidebar.title': 'Navigation sidebar',\n 'complementary-sidebar.title': 'Context sidebar',\n 'plugin-error.message': 'Content failed to render.',\n 'content-fallback.message': 'Unsupported',\n 'content-fallback.description':\n 'No plugin had a response for the address you navigated to. Double-check the URL, and ensure you’ve enabled a plugin that supports the object.',\n 'toggle-fullscreen.label': 'Toggle fullscreen',\n 'undo-available.label': 'Click to undo previous action.',\n 'undo-action.label': 'Undo',\n 'undo-action.alt': 'Undo previous action',\n 'undo-close.label': 'Dismiss',\n 'error-fallback.message': 'Unable to open this object',\n 'error-fallback.copy.label': 'Copy',\n 'plank-heading-fallback.label': 'Untitled',\n 'actions-menu.label': 'Options',\n 'settings.deck.label': 'Disable deck',\n 'pending.heading': 'Loading…',\n 'insert-plank.label': 'Open',\n 'resize.label': 'Drag to resize',\n 'pin-start.label': 'Pin to the left sidebar',\n 'pin-end.label': 'Pin to the right sidebar',\n 'increment-start.label': 'Move to the left',\n 'increment-end.label': 'Move to the right',\n 'show-deck-plank.label': 'Return to deck',\n 'show-solo-plank.label': 'Maximize',\n 'exit-fullscreen.label': 'Exit fullscreen',\n 'show-fullscreen-plank.label': 'Fullscreen',\n 'close.label': 'Close',\n 'minify.label': 'Minify',\n 'open-companion.label': 'Open companion',\n 'close-companion.label': 'Close companion',\n 'close-current.label': 'Close current plank',\n 'close-others.label': 'Close other planks',\n 'close-all.label': 'Close all planks',\n 'close-navigation-sidebar.button': 'Close',\n 'companion-plank-heading-fallback.label': 'Related',\n 'popover-no-preview.message': 'No preview available.',\n 'plugin-failure.title': 'A plugin failed to activate',\n 'plugin-failure.description': 'See Plugin Registry for details.',\n 'plugin-failure-action.label': 'Open Registry',\n 'plugin-failure-action.alt': 'Open Plugin Registry',\n },\n },\n },\n] as const satisfies Resource[];\n"],
5
- "mappings": ";;;AAMA,SAASA,YAAY;AAEd,IAAMC,eAAe;EAC1B;IACE,SAAS;MACP,CAACD,KAAKE,EAAE,GAAG;QACT,eAAe;QACf,kBAAkB;QAClB,qBAAqB;QACrB,iCAAiC;QACjC,qCAAqC;QACrC,oCAAoC;QACpC,qCAAqC;QACrC,iBAAiB;QACjB,+BAA+B;QAC/B,wBAAwB;QACxB,4BAA4B;QAC5B,gCACE;QACF,2BAA2B;QAC3B,wBAAwB;QACxB,qBAAqB;QACrB,mBAAmB;QACnB,oBAAoB;QACpB,0BAA0B;QAC1B,6BAA6B;QAC7B,gCAAgC;QAChC,sBAAsB;QACtB,uBAAuB;QACvB,mBAAmB;QACnB,sBAAsB;QACtB,gBAAgB;QAChB,mBAAmB;QACnB,iBAAiB;QACjB,yBAAyB;QACzB,uBAAuB;QACvB,yBAAyB;QACzB,yBAAyB;QACzB,yBAAyB;QACzB,+BAA+B;QAC/B,eAAe;QACf,gBAAgB;QAChB,wBAAwB;QACxB,yBAAyB;QACzB,uBAAuB;QACvB,sBAAsB;QACtB,mBAAmB;QACnB,mCAAmC;QACnC,0CAA0C;QAC1C,8BAA8B;QAC9B,wBAAwB;QACxB,8BAA8B;QAC9B,+BAA+B;QAC/B,6BAA6B;MAC/B;IACF;EACF;;",
6
- "names": ["meta", "translations", "id"]
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Resource } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\n\nexport const translations = [\n {\n 'en-US': {\n [meta.profile.key]: {\n 'plugin.name': 'Deck',\n 'settings.title': 'Deck settings',\n 'main-header.label': 'Main header',\n 'open-navigation-sidebar.label': 'Open sidebar',\n 'collapse-navigation-sidebar.label': 'Close sidebar',\n 'open-complementary-sidebar.label': 'Open context sidebar',\n 'close-complementary-sidebar.label': 'Close context sidebar',\n 'sidebar.title': 'Navigation sidebar',\n 'complementary-sidebar.title': 'Context sidebar',\n 'plugin-error.message': 'Content failed to render.',\n 'content-fallback.message': 'Unsupported',\n 'content-fallback.description':\n 'No plugin had a response for the address you navigated to. Double-check the URL, and ensure you’ve enabled a plugin that supports the object.',\n 'toggle-fullscreen.label': 'Toggle fullscreen',\n 'undo-available.label': 'Click to undo previous action.',\n 'undo-action.label': 'Undo',\n 'undo-action.alt': 'Undo previous action',\n 'undo-close.label': 'Dismiss',\n 'error-fallback.message': 'Unable to open this object',\n 'error-fallback.copy.label': 'Copy',\n 'plank-heading-fallback.label': 'Untitled',\n 'actions-menu.label': 'Options',\n 'settings.deck.label': 'Disable deck',\n 'pending.heading': 'Loading…',\n 'insert-plank.label': 'Open',\n 'resize.label': 'Drag to resize',\n 'pin-start.label': 'Pin to the left sidebar',\n 'pin-end.label': 'Pin to the right sidebar',\n 'increment-start.label': 'Move to the left',\n 'increment-end.label': 'Move to the right',\n 'show-deck-plank.label': 'Return to deck',\n 'show-solo-plank.label': 'Maximize',\n 'exit-fullscreen.label': 'Exit fullscreen',\n 'show-fullscreen-plank.label': 'Fullscreen',\n 'close.label': 'Close',\n 'minify.label': 'Minify',\n 'open-companion.label': 'Open companion',\n 'close-companion.label': 'Close companion',\n 'close-current.label': 'Close current plank',\n 'close-others.label': 'Close other planks',\n 'close-all.label': 'Close all planks',\n 'close-navigation-sidebar.button': 'Close',\n 'companion-plank-heading-fallback.label': 'Related',\n 'popover-no-preview.message': 'No preview available.',\n 'plugin-failure.title': 'A plugin failed to activate',\n 'plugin-failure.description': 'See Plugin Registry for details.',\n 'plugin-failure-action.label': 'Open Registry',\n 'plugin-failure-action.alt': 'Open Plugin Registry',\n },\n },\n },\n] as const satisfies Resource[];\n"],
5
+ "mappings": ";;;AAMA,SAASA,YAAY;AAEd,IAAMC,eAAe;EAC1B;IACE,SAAS;MACP,CAACD,KAAKE,QAAQC,GAAG,GAAG;QAClB,eAAe;QACf,kBAAkB;QAClB,qBAAqB;QACrB,iCAAiC;QACjC,qCAAqC;QACrC,oCAAoC;QACpC,qCAAqC;QACrC,iBAAiB;QACjB,+BAA+B;QAC/B,wBAAwB;QACxB,4BAA4B;QAC5B,gCACE;QACF,2BAA2B;QAC3B,wBAAwB;QACxB,qBAAqB;QACrB,mBAAmB;QACnB,oBAAoB;QACpB,0BAA0B;QAC1B,6BAA6B;QAC7B,gCAAgC;QAChC,sBAAsB;QACtB,uBAAuB;QACvB,mBAAmB;QACnB,sBAAsB;QACtB,gBAAgB;QAChB,mBAAmB;QACnB,iBAAiB;QACjB,yBAAyB;QACzB,uBAAuB;QACvB,yBAAyB;QACzB,yBAAyB;QACzB,yBAAyB;QACzB,+BAA+B;QAC/B,eAAe;QACf,gBAAgB;QAChB,wBAAwB;QACxB,yBAAyB;QACzB,uBAAuB;QACvB,sBAAsB;QACtB,mBAAmB;QACnB,mCAAmC;QACnC,0CAA0C;QAC1C,8BAA8B;QAC9B,wBAAwB;QACxB,8BAA8B;QAC9B,+BAA+B;QAC/B,6BAA6B;MAC/B;IACF;EACF;;",
6
+ "names": ["meta", "translations", "profile", "key"]
7
7
  }
@@ -6,14 +6,19 @@ import {
6
6
  DeckOperation_exports,
7
7
  DeckState,
8
8
  EphemeralDeckState,
9
+ Hints,
10
+ Keyshortcuts,
9
11
  PLANK_COMPANION_TYPE,
10
12
  PlankSizing,
11
13
  Settings_exports,
14
+ StatusBar,
15
+ StatusBarFooter,
12
16
  StoredDeckState,
17
+ VersionInfo,
13
18
  defaultDeck,
14
19
  getMode,
15
20
  isLayoutMode
16
- } from "../chunk-BS4EOYMK.mjs";
21
+ } from "../chunk-CL7JIOI5.mjs";
17
22
  import "../chunk-J5LGTIGS.mjs";
18
23
  export {
19
24
  DECK_COMPANION_TYPE,
@@ -23,10 +28,15 @@ export {
23
28
  DeckOperation_exports as DeckOperation,
24
29
  DeckState,
25
30
  EphemeralDeckState,
31
+ Hints,
32
+ Keyshortcuts,
26
33
  PLANK_COMPANION_TYPE,
27
34
  PlankSizing,
28
35
  Settings_exports as Settings,
36
+ StatusBar,
37
+ StatusBarFooter,
29
38
  StoredDeckState,
39
+ VersionInfo,
30
40
  defaultDeck,
31
41
  getMode,
32
42
  isLayoutMode