@opengeni/react 0.46.1 → 0.52.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/README.md +158 -14
  2. package/dist/artifacts-document.d.ts +3 -0
  3. package/dist/artifacts-document.js +17 -0
  4. package/dist/artifacts-document.js.map +1 -0
  5. package/dist/artifacts-presentation.d.ts +3 -0
  6. package/dist/artifacts-presentation.js +17 -0
  7. package/dist/artifacts-presentation.js.map +1 -0
  8. package/dist/artifacts-spreadsheet.d.ts +3 -0
  9. package/dist/artifacts-spreadsheet.js +17 -0
  10. package/dist/artifacts-spreadsheet.js.map +1 -0
  11. package/dist/artifacts.d.ts +2 -0
  12. package/dist/artifacts.js +170 -0
  13. package/dist/artifacts.js.map +1 -0
  14. package/dist/chunk-6BBWWOOU.js +82 -0
  15. package/dist/chunk-6BBWWOOU.js.map +1 -0
  16. package/dist/{chunk-HFO4ERGQ.js → chunk-724BW4TW.js} +586 -35
  17. package/dist/chunk-724BW4TW.js.map +1 -0
  18. package/dist/chunk-7I2KB3OK.js +3895 -0
  19. package/dist/chunk-7I2KB3OK.js.map +1 -0
  20. package/dist/chunk-7WCLAEFV.js +2828 -0
  21. package/dist/chunk-7WCLAEFV.js.map +1 -0
  22. package/dist/{chunk-U3CSCMWA.js → chunk-FK6VG4LL.js} +9 -13
  23. package/dist/chunk-FK6VG4LL.js.map +1 -0
  24. package/dist/{chunk-SRFUT2ZU.js → chunk-FWS3KC3Z.js} +120 -64
  25. package/dist/chunk-FWS3KC3Z.js.map +1 -0
  26. package/dist/{chunk-EKZH6IDG.js → chunk-HDBG7XGO.js} +62 -1
  27. package/dist/chunk-HDBG7XGO.js.map +1 -0
  28. package/dist/chunk-HUIKIDM5.js +2148 -0
  29. package/dist/chunk-HUIKIDM5.js.map +1 -0
  30. package/dist/{chunk-LGVMUIRV.js → chunk-JAGDUCZQ.js} +1053 -390
  31. package/dist/chunk-JAGDUCZQ.js.map +1 -0
  32. package/dist/{chunk-LWR4MXSS.js → chunk-JR3QFY6B.js} +420 -35
  33. package/dist/chunk-JR3QFY6B.js.map +1 -0
  34. package/dist/chunk-JVYQRRC4.js +53 -0
  35. package/dist/chunk-JVYQRRC4.js.map +1 -0
  36. package/dist/chunk-KCGXPP5V.js +157 -0
  37. package/dist/chunk-KCGXPP5V.js.map +1 -0
  38. package/dist/{chunk-EB67J347.js → chunk-KZ73RL76.js} +111 -31
  39. package/dist/chunk-KZ73RL76.js.map +1 -0
  40. package/dist/chunk-PEI6RANI.js +3234 -0
  41. package/dist/chunk-PEI6RANI.js.map +1 -0
  42. package/dist/{chunk-3PB7MIT6.js → chunk-ROIRTM37.js} +220 -72
  43. package/dist/chunk-ROIRTM37.js.map +1 -0
  44. package/dist/chunk-VZTQ73XT.js +86 -0
  45. package/dist/chunk-VZTQ73XT.js.map +1 -0
  46. package/dist/{chunk-VCBFUSUZ.js → chunk-WSK7G5LE.js} +72 -4
  47. package/dist/chunk-WSK7G5LE.js.map +1 -0
  48. package/dist/{chunk-FGZUCXZF.js → chunk-WYA65Y3F.js} +16 -16
  49. package/dist/chunk-WYA65Y3F.js.map +1 -0
  50. package/dist/{chunk-6EDV6YFE.js → chunk-X4S56Y2H.js} +147 -35
  51. package/dist/chunk-X4S56Y2H.js.map +1 -0
  52. package/dist/client.d.ts +7 -1
  53. package/dist/clipboard.d.ts +1 -0
  54. package/dist/clipboard.js +7 -0
  55. package/dist/clipboard.js.map +1 -0
  56. package/dist/commands/index.d.ts +3 -3
  57. package/dist/commands/registry.d.ts +1 -1
  58. package/dist/commands/types.d.ts +1 -1
  59. package/dist/components/approval-surface.d.ts +2 -2
  60. package/dist/components/artifacts/artifact-surface.d.ts +18 -0
  61. package/dist/components/artifacts/document-editor.d.ts +172 -0
  62. package/dist/components/artifacts/editable-artifact-ui.d.ts +13 -0
  63. package/dist/components/artifacts/editable-artifact-workbench.d.ts +49 -0
  64. package/dist/components/artifacts/editable-document.d.ts +24 -0
  65. package/dist/components/artifacts/editable-presentation.d.ts +24 -0
  66. package/dist/components/artifacts/editable-spreadsheet.d.ts +32 -0
  67. package/dist/components/artifacts/index.d.ts +8 -0
  68. package/dist/components/artifacts/presentation-editor.d.ts +297 -0
  69. package/dist/components/artifacts/spreadsheet-canvas.d.ts +120 -0
  70. package/dist/components/artifacts/spreadsheet-grid.d.ts +113 -0
  71. package/dist/components/browser-viewer.d.ts +29 -0
  72. package/dist/components/chat-composer.d.ts +13 -8
  73. package/dist/components/code-editor.d.ts +25 -3
  74. package/dist/components/command-palette.d.ts +2 -2
  75. package/dist/components/composer-transcription-control.d.ts +4 -2
  76. package/dist/components/composer.d.ts +29 -15
  77. package/dist/components/computer-viewer.d.ts +23 -0
  78. package/dist/components/copy-button.d.ts +2 -2
  79. package/dist/components/desktop-viewer.d.ts +25 -21
  80. package/dist/components/diff-view.d.ts +1 -1
  81. package/dist/components/enrollment-consent.d.ts +1 -1
  82. package/dist/components/enrollment-device-flow.d.ts +1 -1
  83. package/dist/components/file-browser.d.ts +2 -2
  84. package/dist/components/fleet-tile.d.ts +1 -1
  85. package/dist/components/generated-video-player.d.ts +10 -0
  86. package/dist/components/human-input-form.d.ts +1 -1
  87. package/dist/components/human-input-surface.d.ts +2 -2
  88. package/dist/components/interactive-workbench-viewers.d.ts +2 -0
  89. package/dist/components/machine-card.d.ts +2 -2
  90. package/dist/components/machine-dock-bar.d.ts +3 -3
  91. package/dist/components/machine-health-pill.d.ts +2 -2
  92. package/dist/components/machine-input-display.d.ts +1 -1
  93. package/dist/components/machine-metrics.d.ts +2 -2
  94. package/dist/components/machine-status-pill.d.ts +4 -4
  95. package/dist/components/machines/health.d.ts +1 -1
  96. package/dist/components/machines/machine-detail.d.ts +5 -3
  97. package/dist/components/machines/metric-history-chart.d.ts +1 -1
  98. package/dist/components/machines/metric-sparkline.d.ts +2 -2
  99. package/dist/components/machines/series.d.ts +2 -2
  100. package/dist/components/machines-dashboard.d.ts +5 -5
  101. package/dist/components/markdown.d.ts +1 -1
  102. package/dist/components/message-timeline.d.ts +22 -5
  103. package/dist/components/model-picker.d.ts +2 -2
  104. package/dist/components/model-policy-picker.d.ts +7 -7
  105. package/dist/components/pierre-diff.d.ts +1 -1
  106. package/dist/components/pierre-file.d.ts +1 -1
  107. package/dist/components/queue-draft-policy.d.ts +1 -1
  108. package/dist/components/queue-surface-implementation.d.ts +3 -3
  109. package/dist/components/queue-surface-state.d.ts +4 -4
  110. package/dist/components/queue-surface.d.ts +5 -5
  111. package/dist/components/sandbox-files.d.ts +5 -5
  112. package/dist/components/sandbox-terminal.d.ts +50 -4
  113. package/dist/components/sandbox-workspace.d.ts +30 -10
  114. package/dist/components/session-chrome.d.ts +4 -4
  115. package/dist/components/session-status.d.ts +2 -2
  116. package/dist/components/timeline-annotation-selection.d.ts +9 -0
  117. package/dist/components/timeline-annotations-dialog.d.ts +16 -0
  118. package/dist/components/timeline-annotations.d.ts +13 -0
  119. package/dist/components/tooltip.d.ts +4 -4
  120. package/dist/components/user-message-body.d.ts +2 -2
  121. package/dist/components/workbench-changes.d.ts +2 -2
  122. package/dist/components/workspace-dock.d.ts +3 -1
  123. package/dist/composer.d.ts +11 -11
  124. package/dist/composer.js +7 -7
  125. package/dist/hooks/internal.d.ts +7 -1
  126. package/dist/hooks/use-attached-browsers.d.ts +21 -0
  127. package/dist/hooks/use-available-models.d.ts +2 -2
  128. package/dist/hooks/use-billing-usage.d.ts +1 -1
  129. package/dist/hooks/use-browser-frame-stream.d.ts +28 -0
  130. package/dist/hooks/use-browser-identities.d.ts +26 -0
  131. package/dist/hooks/use-browser-session.d.ts +28 -0
  132. package/dist/hooks/use-browser-sessions.d.ts +32 -0
  133. package/dist/hooks/use-codex-accounts.d.ts +3 -3
  134. package/dist/hooks/use-composer.d.ts +36 -9
  135. package/dist/hooks/use-computer-frame-stream.d.ts +24 -0
  136. package/dist/hooks/use-computer-session.d.ts +28 -0
  137. package/dist/hooks/use-computer-sessions.d.ts +28 -0
  138. package/dist/hooks/use-desktop-stream.d.ts +1 -1
  139. package/dist/hooks/use-environments.d.ts +11 -5
  140. package/dist/hooks/use-file-attachments.d.ts +1 -1
  141. package/dist/hooks/use-goal.d.ts +2 -2
  142. package/dist/hooks/use-human-input.d.ts +2 -2
  143. package/dist/hooks/use-last-started-turn-policy.d.ts +2 -2
  144. package/dist/hooks/use-machine-chip.d.ts +2 -2
  145. package/dist/hooks/use-machines.d.ts +10 -3
  146. package/dist/hooks/use-packs.d.ts +7 -2
  147. package/dist/hooks/use-rigs.d.ts +1 -1
  148. package/dist/hooks/use-sandbox-files.d.ts +25 -4
  149. package/dist/hooks/use-sandbox-git.d.ts +13 -5
  150. package/dist/hooks/use-sandbox-terminal.d.ts +1 -1
  151. package/dist/hooks/use-scheduled-tasks.d.ts +1 -1
  152. package/dist/hooks/use-session-capabilities.d.ts +5 -4
  153. package/dist/hooks/use-session-control.d.ts +1 -1
  154. package/dist/hooks/use-session-events.d.ts +2 -2
  155. package/dist/hooks/use-session-lineage.d.ts +1 -1
  156. package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
  157. package/dist/hooks/use-session.d.ts +2 -2
  158. package/dist/hooks/use-slash-commands.d.ts +1 -1
  159. package/dist/hooks/use-terminal-stream.d.ts +8 -2
  160. package/dist/hooks/use-transcription.d.ts +2 -2
  161. package/dist/hooks/use-turn-queue.d.ts +2 -2
  162. package/dist/hooks/use-video-artifact-playback.d.ts +9 -0
  163. package/dist/hooks/use-voice-input.d.ts +6 -4
  164. package/dist/hooks/use-workspace-capture.d.ts +1 -1
  165. package/dist/hooks/use-workspace-edit.d.ts +1 -1
  166. package/dist/hooks/use-workspace-sessions.d.ts +1 -1
  167. package/dist/hooks/use-workspaces.d.ts +1 -1
  168. package/dist/index.d.ts +158 -154
  169. package/dist/index.js +1718 -908
  170. package/dist/index.js.map +1 -1
  171. package/dist/interaction.d.ts +23 -0
  172. package/dist/interaction.js +36 -0
  173. package/dist/interaction.js.map +1 -0
  174. package/dist/interactive-workbench-viewers-KHNOHWQE.js +13 -0
  175. package/dist/interactive-workbench-viewers-KHNOHWQE.js.map +1 -0
  176. package/dist/lib/composer-responsive-context.d.ts +9 -0
  177. package/dist/lib/relay-wire.d.ts +4 -0
  178. package/dist/lib/sandbox-liveness.d.ts +9 -0
  179. package/dist/lib/terminal-capability.d.ts +5 -0
  180. package/dist/lib/use-portal-token-style.d.ts +14 -3
  181. package/dist/lib/xterm-theme.d.ts +1 -1
  182. package/dist/machines.d.ts +30 -30
  183. package/dist/machines.js +3 -3
  184. package/dist/provider.d.ts +4 -4
  185. package/dist/{queue-surface-implementation-J4XJFKRW.js → queue-surface-implementation-2KVJTYXH.js} +117 -64
  186. package/dist/queue-surface-implementation-2KVJTYXH.js.map +1 -0
  187. package/dist/realtime/dropdown-menu.d.ts +8 -8
  188. package/dist/realtime/realtime-control.d.ts +15 -6
  189. package/dist/realtime.d.ts +4 -4
  190. package/dist/realtime.js +30 -33
  191. package/dist/realtime.js.map +1 -1
  192. package/dist/session-context.d.ts +19 -1
  193. package/dist/session-ui.d.ts +14 -14
  194. package/dist/session-ui.js +6 -5
  195. package/dist/session.d.ts +28 -28
  196. package/dist/session.js +5 -5
  197. package/dist/timeline/activity-rail.d.ts +6 -3
  198. package/dist/timeline/disclosure-context.d.ts +1 -1
  199. package/dist/timeline/fleet-decision-projection.d.ts +1 -1
  200. package/dist/timeline/fleet-decision-row.d.ts +3 -3
  201. package/dist/timeline/index.d.ts +19 -19
  202. package/dist/timeline/parsers.d.ts +6 -3
  203. package/dist/timeline/projection.d.ts +3 -3
  204. package/dist/timeline/registry.d.ts +10 -1
  205. package/dist/timeline/screenshot-lightbox.d.ts +2 -2
  206. package/dist/timeline/shared.d.ts +21 -10
  207. package/dist/timeline/tool-diff.d.ts +2 -2
  208. package/dist/timeline/tool-renderers.d.ts +1 -1
  209. package/dist/timeline/turn-summary.d.ts +3 -3
  210. package/dist/timeline/types.d.ts +42 -2
  211. package/dist/timeline-annotation-selection-3L7LHGG2.js +187 -0
  212. package/dist/timeline-annotation-selection-3L7LHGG2.js.map +1 -0
  213. package/dist/timeline-annotations-dialog-U7EVLR75.js +196 -0
  214. package/dist/timeline-annotations-dialog-U7EVLR75.js.map +1 -0
  215. package/dist/voice-recording-store.d.ts +8 -2
  216. package/package.json +52 -7
  217. package/src/artifacts-document.ts +31 -0
  218. package/src/artifacts-presentation.ts +36 -0
  219. package/src/artifacts-spreadsheet.ts +21 -0
  220. package/src/artifacts.ts +86 -0
  221. package/src/client.ts +90 -1
  222. package/src/clipboard.ts +2 -0
  223. package/src/components/artifacts/artifact-surface.tsx +93 -0
  224. package/src/components/artifacts/document-editor.tsx +2255 -0
  225. package/src/components/artifacts/editable-artifact-ui.tsx +89 -0
  226. package/src/components/artifacts/editable-artifact-workbench.tsx +203 -0
  227. package/src/components/artifacts/editable-document.tsx +657 -0
  228. package/src/components/artifacts/editable-presentation.tsx +1020 -0
  229. package/src/components/artifacts/editable-spreadsheet.tsx +733 -0
  230. package/src/components/artifacts/index.ts +99 -0
  231. package/src/components/artifacts/presentation-editor.tsx +3148 -0
  232. package/src/components/artifacts/spreadsheet-canvas.ts +799 -0
  233. package/src/components/artifacts/spreadsheet-grid.tsx +2129 -0
  234. package/src/components/browser-viewer.tsx +1592 -0
  235. package/src/components/chat-composer.tsx +25 -2
  236. package/src/components/code-editor.tsx +90 -31
  237. package/src/components/command-palette.tsx +1 -1
  238. package/src/components/composer-transcription-control.tsx +51 -22
  239. package/src/components/composer.tsx +49 -23
  240. package/src/components/computer-viewer.tsx +1139 -0
  241. package/src/components/copy-button.tsx +1 -1
  242. package/src/components/desktop-viewer.tsx +103 -75
  243. package/src/components/file-browser.tsx +39 -17
  244. package/src/components/generated-video-player.tsx +89 -0
  245. package/src/components/human-input-form.tsx +2 -2
  246. package/src/components/interactive-workbench-viewers.ts +2 -0
  247. package/src/components/machine-card.tsx +1 -1
  248. package/src/components/machine-input-display.ts +3 -0
  249. package/src/components/machines/machine-detail.tsx +39 -15
  250. package/src/components/machines-dashboard.tsx +7 -6
  251. package/src/components/message-timeline.tsx +327 -37
  252. package/src/components/model-picker.tsx +2 -2
  253. package/src/components/model-policy-picker.tsx +16 -15
  254. package/src/components/queue-surface-implementation.tsx +135 -75
  255. package/src/components/queue-surface-state.tsx +2 -2
  256. package/src/components/sandbox-files.tsx +142 -62
  257. package/src/components/sandbox-terminal.tsx +119 -35
  258. package/src/components/sandbox-workspace.tsx +394 -228
  259. package/src/components/session-chrome.tsx +67 -27
  260. package/src/components/timeline-annotation-selection.tsx +221 -0
  261. package/src/components/timeline-annotations-dialog.tsx +213 -0
  262. package/src/components/timeline-annotations.tsx +84 -0
  263. package/src/components/tooltip.tsx +13 -16
  264. package/src/components/user-message-body.tsx +1 -1
  265. package/src/components/workbench-changes.tsx +192 -35
  266. package/src/components/workspace-dock.tsx +13 -5
  267. package/src/composer.ts +3 -0
  268. package/src/hooks/internal.ts +132 -38
  269. package/src/hooks/use-attached-browsers.ts +152 -0
  270. package/src/hooks/use-browser-frame-stream.ts +316 -0
  271. package/src/hooks/use-browser-identities.ts +225 -0
  272. package/src/hooks/use-browser-session.ts +476 -0
  273. package/src/hooks/use-browser-sessions.ts +281 -0
  274. package/src/hooks/use-codex-accounts.ts +4 -4
  275. package/src/hooks/use-composer.ts +769 -24
  276. package/src/hooks/use-computer-frame-stream.ts +311 -0
  277. package/src/hooks/use-computer-session.ts +442 -0
  278. package/src/hooks/use-computer-sessions.ts +245 -0
  279. package/src/hooks/use-environments.ts +24 -5
  280. package/src/hooks/use-file-attachments.ts +70 -32
  281. package/src/hooks/use-goal.ts +17 -5
  282. package/src/hooks/use-machine-chip.ts +5 -3
  283. package/src/hooks/use-machines.ts +79 -3
  284. package/src/hooks/use-packs.ts +51 -0
  285. package/src/hooks/use-sandbox-files.ts +382 -88
  286. package/src/hooks/use-sandbox-git.ts +208 -46
  287. package/src/hooks/use-sandbox-terminal.ts +3 -2
  288. package/src/hooks/use-session-capabilities.ts +94 -70
  289. package/src/hooks/use-session-events.ts +18 -4
  290. package/src/hooks/use-terminal-stream.ts +102 -23
  291. package/src/hooks/use-transcription.ts +4 -14
  292. package/src/hooks/use-turn-queue.ts +17 -5
  293. package/src/hooks/use-video-artifact-playback.ts +28 -0
  294. package/src/hooks/use-voice-input.ts +163 -19
  295. package/src/hooks/use-windowed-sections.ts +9 -7
  296. package/src/hooks/use-workspace-edit.ts +2 -1
  297. package/src/index.ts +21 -6
  298. package/src/interaction.ts +71 -0
  299. package/src/lib/composer-responsive-context.ts +15 -0
  300. package/src/lib/relay-wire.ts +4 -0
  301. package/src/lib/sandbox-liveness.ts +11 -0
  302. package/src/lib/terminal-capability.ts +10 -0
  303. package/src/lib/use-portal-token-style.ts +60 -15
  304. package/src/provider.tsx +52 -7
  305. package/src/realtime/dropdown-menu.tsx +15 -19
  306. package/src/realtime/realtime-control.tsx +16 -5
  307. package/src/session-context.ts +90 -0
  308. package/src/timeline/activity-rail.tsx +31 -6
  309. package/src/timeline/index.ts +4 -1
  310. package/src/timeline/parsers.ts +46 -20
  311. package/src/timeline/projection.ts +233 -13
  312. package/src/timeline/registry.ts +19 -0
  313. package/src/timeline/screenshot-lightbox.tsx +30 -9
  314. package/src/timeline/shared.tsx +59 -11
  315. package/src/timeline/tool-renderers.tsx +421 -24
  316. package/src/timeline/turn-summary.tsx +2 -2
  317. package/src/timeline/types.ts +58 -2
  318. package/src/voice-recording-store.ts +15 -0
  319. package/styles/compiled.css +5298 -0
  320. package/styles/compiled.d.ts +2 -0
  321. package/styles/effective-tokens.css +27 -0
  322. package/styles/index.css +18 -0
  323. package/styles/responsive.css +208 -0
  324. package/styles/responsive.d.ts +2 -0
  325. package/styles/tokens.css +50 -17
  326. package/dist/chunk-3PB7MIT6.js.map +0 -1
  327. package/dist/chunk-6EDV6YFE.js.map +0 -1
  328. package/dist/chunk-EB67J347.js.map +0 -1
  329. package/dist/chunk-EKZH6IDG.js.map +0 -1
  330. package/dist/chunk-FGZUCXZF.js.map +0 -1
  331. package/dist/chunk-HFO4ERGQ.js.map +0 -1
  332. package/dist/chunk-JB5725BI.js +0 -48
  333. package/dist/chunk-JB5725BI.js.map +0 -1
  334. package/dist/chunk-LGVMUIRV.js.map +0 -1
  335. package/dist/chunk-LWR4MXSS.js.map +0 -1
  336. package/dist/chunk-SRFUT2ZU.js.map +0 -1
  337. package/dist/chunk-U3CSCMWA.js.map +0 -1
  338. package/dist/chunk-VCBFUSUZ.js.map +0 -1
  339. package/dist/fleet-decision-projection-SLNZMS42.js +0 -241
  340. package/dist/fleet-decision-projection-SLNZMS42.js.map +0 -1
  341. package/dist/queue-surface-implementation-J4XJFKRW.js.map +0 -1
@@ -2,6 +2,7 @@ import type {
2
2
  CreateVariableSetRequest,
3
3
  UpdateVariableSetRequest,
4
4
  VariableSet,
5
+ VariableSetSecret,
5
6
  VariableSetVariableMetadata,
6
7
  } from "@opengeni/sdk";
7
8
  import { useCallback, useMemo } from "react";
@@ -21,7 +22,12 @@ export type UseVariableSetsResult = {
21
22
  create: (request: CreateVariableSetRequest) => Promise<VariableSet | null>;
22
23
  update: (variableSetId: string, request: UpdateVariableSetRequest) => Promise<VariableSet | null>;
23
24
  remove: (variableSetId: string) => Promise<boolean>;
24
- /** Set/rotate a variable. Values are write-only — reads expose metadata only. */
25
+ /**
26
+ * Read one exact value through the dedicated permissioned API. The hook never
27
+ * puts plaintext in its polled variable-set cache.
28
+ */
29
+ readVariable: (variableSetId: string, name: string) => Promise<VariableSetSecret | null>;
30
+ /** Set/rotate a variable. Generic reads expose metadata only. */
25
31
  setVariable: (
26
32
  variableSetId: string,
27
33
  name: string,
@@ -35,8 +41,9 @@ export type UseVariableSetsResult = {
35
41
 
36
42
  /**
37
43
  * Variable sets (named, encrypted variable sets attached to sessions
38
- * and scheduled tasks). Variable values are write-only end to end: this hook
39
- * never sees a value after it is sent.
44
+ * and scheduled tasks). Generic reads stay metadata-only. A dedicated,
45
+ * permissioned method can retrieve one value and returns it directly without
46
+ * adding plaintext to hook state or polling caches.
40
47
  */
41
48
  export function useVariableSets(options: UseVariableSetsOptions = {}): UseVariableSetsResult {
42
49
  const { client, workspaceId } = useOpenGeni(options);
@@ -89,6 +96,12 @@ export function useVariableSets(options: UseVariableSetsOptions = {}): UseVariab
89
96
  [client, workspaceId, run, refresh],
90
97
  );
91
98
 
99
+ const readVariable = useCallback(
100
+ async (variableSetId: string, name: string): Promise<VariableSetSecret | null> =>
101
+ await run(() => client.getVariableSetVariable(workspaceId, variableSetId, name)),
102
+ [client, workspaceId, run],
103
+ );
104
+
92
105
  const setVariable = useCallback(
93
106
  async (
94
107
  variableSetId: string,
@@ -128,6 +141,7 @@ export function useVariableSets(options: UseVariableSetsOptions = {}): UseVariab
128
141
  create,
129
142
  update,
130
143
  remove,
144
+ readVariable,
131
145
  setVariable,
132
146
  deleteVariable,
133
147
  mutating,
@@ -139,7 +153,9 @@ export function useVariableSets(options: UseVariableSetsOptions = {}): UseVariab
139
153
  /** @deprecated use UseVariableSetsOptions */
140
154
  export type UseEnvironmentsOptions = UseVariableSetsOptions;
141
155
  /** @deprecated use UseVariableSetsResult */
142
- export type UseEnvironmentsResult = UseVariableSetsResult & { environments: VariableSet[] };
156
+ export type UseEnvironmentsResult = UseVariableSetsResult & {
157
+ environments: VariableSet[];
158
+ };
143
159
  /** @deprecated use useVariableSets */
144
160
  export function useEnvironments(options: UseEnvironmentsOptions = {}): UseEnvironmentsResult {
145
161
  const legacyClient = useMemo(() => {
@@ -158,6 +174,9 @@ export function useEnvironments(options: UseEnvironmentsOptions = {}): UseEnviro
158
174
  options.client.deleteEnvironmentVariable ?? options.client.deleteVariableSetVariable,
159
175
  };
160
176
  }, [options.client]);
161
- const result = useVariableSets({ ...options, ...(legacyClient ? { client: legacyClient } : {}) });
177
+ const result = useVariableSets({
178
+ ...options,
179
+ ...(legacyClient ? { client: legacyClient } : {}),
180
+ });
162
181
  return { ...result, environments: result.variableSets };
163
182
  }
@@ -1,5 +1,5 @@
1
1
  import type { FileAsset, FileResourceRef } from "@opengeni/sdk";
2
- import { useCallback, useRef, useState } from "react";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
3
  import {
4
4
  useEmbeddedFileAttachments,
5
5
  type EmbeddedFileAttachmentClientOverride,
@@ -87,12 +87,64 @@ export function useFileAttachments(
87
87
  // Keep the source File per attachment id so a failed upload can be retried
88
88
  // in place. Cleared on remove/clear so it never outlives its attachment.
89
89
  const sources = useRef<Map<string, File>>(new Map());
90
+ // Object URLs must be owned synchronously: React may discard an attachment
91
+ // state update when its component unmounts in the same batch that minted the
92
+ // preview. The registry remains available to cleanup even before a render.
93
+ const previewUrls = useRef<Map<string, string>>(new Map());
94
+ const revokePreview = useCallback((id: string) => {
95
+ const previewUrl = previewUrls.current.get(id);
96
+ if (!previewUrl) return;
97
+ previewUrls.current.delete(id);
98
+ URL.revokeObjectURL(previewUrl);
99
+ }, []);
100
+ const revokeAllPreviews = useCallback(() => {
101
+ const urls = [...previewUrls.current.values()];
102
+ previewUrls.current.clear();
103
+ for (const previewUrl of urls) URL.revokeObjectURL(previewUrl);
104
+ }, []);
105
+ // Ready-file reconciliation uses functional state updaters, which React may
106
+ // evaluate during a concurrent render that later suspends or is abandoned.
107
+ // Diff only committed attachment sets here so URL revocation cannot run from
108
+ // render-phase code while the previously committed DOM still uses a preview.
109
+ const committedAttachmentIds = useRef<Set<string>>(new Set());
110
+ useEffect(() => {
111
+ const currentIds = new Set(attachments.map((attachment) => attachment.id));
112
+ for (const id of committedAttachmentIds.current) {
113
+ if (!currentIds.has(id)) revokePreview(id);
114
+ }
115
+ committedAttachmentIds.current = currentIds;
116
+ }, [attachments, revokePreview]);
117
+ // Upload promises are not cancellable at this layer. Fence their settlements
118
+ // when the hook changes client/workspace or unmounts so an old tenant/session
119
+ // cannot mutate the next attachment queue (or an already-unmounted component).
120
+ const scopeGeneration = useRef(0);
121
+ const previousScope = useRef({ client, workspaceId });
122
+
123
+ useEffect(() => {
124
+ const previous = previousScope.current;
125
+ if (previous.client === client && previous.workspaceId === workspaceId) return;
126
+ previousScope.current = { client, workspaceId };
127
+ scopeGeneration.current += 1;
128
+ sources.current.clear();
129
+ revokeAllPreviews();
130
+ setAttachments([]);
131
+ }, [client, revokeAllPreviews, workspaceId]);
132
+
133
+ useEffect(
134
+ () => () => {
135
+ scopeGeneration.current += 1;
136
+ sources.current.clear();
137
+ revokeAllPreviews();
138
+ },
139
+ [revokeAllPreviews],
140
+ );
90
141
 
91
142
  // Run (or re-run) the upload for one already-tracked attachment id. Sets it
92
143
  // back to `uploading`, then resolves to `ready` (with the asset) or `failed`
93
144
  // (with the error message).
94
145
  const startUpload = useCallback(
95
146
  (id: string, file: File) => {
147
+ const generation = scopeGeneration.current;
96
148
  void client
97
149
  .uploadFile(workspaceId, {
98
150
  filename: file.name || "file",
@@ -100,6 +152,7 @@ export function useFileAttachments(
100
152
  data: file,
101
153
  })
102
154
  .then((asset) => {
155
+ if (scopeGeneration.current !== generation) return;
103
156
  // Retry bytes are useful only until durable finalization succeeds.
104
157
  // Drop the source File immediately; restored/ready attachments must
105
158
  // never retain browser-local byte authority.
@@ -121,6 +174,7 @@ export function useFileAttachments(
121
174
  );
122
175
  })
123
176
  .catch((error: unknown) => {
177
+ if (scopeGeneration.current !== generation) return;
124
178
  setAttachments((current) =>
125
179
  current.map((attachment) =>
126
180
  attachment.id === id
@@ -143,6 +197,7 @@ export function useFileAttachments(
143
197
  const id = crypto.randomUUID();
144
198
  sources.current.set(id, file);
145
199
  const previewUrl = isImage(file) ? URL.createObjectURL(file) : undefined;
200
+ if (previewUrl) previewUrls.current.set(id, previewUrl);
146
201
  setAttachments((current) => [
147
202
  ...current,
148
203
  {
@@ -232,11 +287,6 @@ export function useFileAttachments(
232
287
  // only authority restored across page/device boundaries.
233
288
  };
234
289
  });
235
- for (const [fileId, attachment] of existingReady) {
236
- if (!incoming.has(fileId) && attachment.previewUrl) {
237
- URL.revokeObjectURL(attachment.previewUrl);
238
- }
239
- }
240
290
  // A server restoration is authoritative for finalized assets, but an
241
291
  // upload that has not finalized still belongs to the local actor. Keep
242
292
  // those unresolved entries while replacing the ready set exactly.
@@ -246,46 +296,34 @@ export function useFileAttachments(
246
296
  [workspaceId],
247
297
  );
248
298
 
249
- const remove = useCallback((id: string) => {
250
- sources.current.delete(id);
251
- setAttachments((current) => {
252
- const removed = current.find((attachment) => attachment.id === id);
253
- if (removed?.previewUrl) {
254
- URL.revokeObjectURL(removed.previewUrl);
255
- }
256
- return current.filter((attachment) => attachment.id !== id);
257
- });
258
- }, []);
299
+ const remove = useCallback(
300
+ (id: string) => {
301
+ sources.current.delete(id);
302
+ revokePreview(id);
303
+ setAttachments((current) => current.filter((attachment) => attachment.id !== id));
304
+ },
305
+ [revokePreview],
306
+ );
259
307
 
260
308
  const removeReadyFiles = useCallback((fileIds: Iterable<string>) => {
261
309
  const accepted = new Set(fileIds);
262
310
  if (accepted.size === 0) return;
263
311
  setAttachments((current) =>
264
312
  current.filter((attachment) => {
265
- const removeAccepted =
313
+ return !(
266
314
  attachment.status === "ready" &&
267
315
  attachment.file !== undefined &&
268
- accepted.has(attachment.file.id);
269
- if (removeAccepted) {
270
- sources.current.delete(attachment.id);
271
- if (attachment.previewUrl) URL.revokeObjectURL(attachment.previewUrl);
272
- }
273
- return !removeAccepted;
316
+ accepted.has(attachment.file.id)
317
+ );
274
318
  }),
275
319
  );
276
320
  }, []);
277
321
 
278
322
  const clear = useCallback(() => {
279
323
  sources.current.clear();
280
- setAttachments((current) => {
281
- for (const attachment of current) {
282
- if (attachment.previewUrl) {
283
- URL.revokeObjectURL(attachment.previewUrl);
284
- }
285
- }
286
- return [];
287
- });
288
- }, []);
324
+ revokeAllPreviews();
325
+ setAttachments([]);
326
+ }, [revokeAllPreviews]);
289
327
 
290
328
  return {
291
329
  attachments,
@@ -4,6 +4,7 @@ import { useEmbeddedGoal, type EmbeddedGoalClientOverride } from "../session-con
4
4
  import {
5
5
  useDebouncedCallback,
6
6
  useMutationRunner,
7
+ usePageLiveActivity,
7
8
  useSessionEventTrigger,
8
9
  type SessionEventFeedOptions,
9
10
  } from "./internal";
@@ -75,6 +76,7 @@ export function useGoal(
75
76
  const enabled = (options.enabled ?? true) && Boolean(sessionId);
76
77
  const sharedEvents = options.events;
77
78
  const sharedFeed = sharedEvents !== undefined;
79
+ const pageLive = usePageLiveActivity();
78
80
  const [goal, setGoal] = useState<SessionGoal | null>(null);
79
81
  const [loading, setLoading] = useState(enabled);
80
82
  const [error, setError] = useState<Error | null>(null);
@@ -116,7 +118,7 @@ export function useGoal(
116
118
  setGoal(null);
117
119
  setError(null);
118
120
  }
119
- if (!enabled) {
121
+ if (!enabled || !pageLive) {
120
122
  setLoading(false);
121
123
  return;
122
124
  }
@@ -127,19 +129,29 @@ export function useGoal(
127
129
  };
128
130
  }
129
131
  setLoading(true);
130
- void load();
131
132
  const pollIntervalMs = options.pollIntervalMs;
132
133
  if (pollIntervalMs === undefined || pollIntervalMs <= 0) {
134
+ void load();
133
135
  return () => {
134
136
  generation.current += 1;
135
137
  };
136
138
  }
137
- const timer = setInterval(() => void load(), pollIntervalMs);
139
+ let cancelled = false;
140
+ let timer: ReturnType<typeof setTimeout> | null = null;
141
+ const schedule = () => {
142
+ if (cancelled) return;
143
+ timer = setTimeout(() => {
144
+ timer = null;
145
+ void load().finally(schedule);
146
+ }, pollIntervalMs);
147
+ };
148
+ void load().finally(schedule);
138
149
  return () => {
139
- clearInterval(timer);
150
+ cancelled = true;
151
+ if (timer !== null) clearTimeout(timer);
140
152
  generation.current += 1;
141
153
  };
142
- }, [load, enabled, workspaceId, sessionId, options.pollIntervalMs, sharedFeed]);
154
+ }, [load, enabled, pageLive, workspaceId, sessionId, options.pollIntervalMs, sharedFeed]);
143
155
 
144
156
  const scheduleRefresh = useDebouncedCallback(() => void load());
145
157
  useSessionEventTrigger(client, workspaceId, sessionId, isGoalRefreshEvent, scheduleRefresh, {
@@ -1,6 +1,7 @@
1
1
  import { useMemo } from "react";
2
2
  import type { MachineState } from "@opengeni/sdk";
3
3
  import type { SessionCapabilitiesState } from "./use-session-capabilities";
4
+ import { sandboxAcceptsLiveIo } from "../lib/sandbox-liveness";
4
5
 
5
6
  /** The one truthful machine indicator. Honest staleness beats
6
7
  * fake liveness: a cold/asleep box reads "offline — as of <time>", never "live". */
@@ -53,7 +54,7 @@ export function formatAsOf(capturedAt: string, now: number): string {
53
54
  * it; the whole point is a deterministic, testable projection).
54
55
  *
55
56
  * Precedence:
56
- * 1. warm/draining lease → **live** (a warm box always wins).
57
+ * 1. warm lease → **live** (a holder-confirmed box always wins).
57
58
  * 2. actively warming (negotiating, wake-on-edit, or a reconnecting/enrolling
58
59
  * machine) → **waking**.
59
60
  * 3. everything else (a cold/asleep box, a self-hosted machine that's offline,
@@ -64,8 +65,9 @@ export function deriveMachineChip(input: DeriveMachineChipInput): MachineChip {
64
65
  const asOf = input.capturedAt ?? null;
65
66
  const offlineLabel = asOf ? `Offline — as of ${formatAsOf(asOf, now)}` : "Offline";
66
67
 
67
- // 1. A warm (or draining) lease is live regardless of anything else.
68
- if (input.liveness === "warm" || input.liveness === "draining") {
68
+ // 1. Only holder-confirmed warm is live. Draining is teardown-owned and may
69
+ // already have lost its provider instance, so it uses the capture-backed label.
70
+ if (sandboxAcceptsLiveIo(input.liveness)) {
69
71
  return { state: "live", label: "Live", asOf: null };
70
72
  }
71
73
 
@@ -1,4 +1,9 @@
1
1
  import { useCallback, useRef, useState } from "react";
2
+ import type {
3
+ RemoveEnrollmentRequest,
4
+ RemoveEnrollmentResponse,
5
+ SwapActiveSandboxResponse,
6
+ } from "@opengeni/sdk";
2
7
  import { useOpenGeni, type ClientOverride } from "../provider";
3
8
  import { useMutationRunner, usePolledValue } from "./internal";
4
9
  import type { MachinesResponse, MachineView, MetricSample } from "../types/machines";
@@ -31,6 +36,12 @@ export type MachinesClientLike = {
31
36
  enrollmentId: string,
32
37
  options?: { window?: "15m" | "1h" | "6h" | "24h" },
33
38
  ) => Promise<MetricSample[]>;
39
+ /** POST .../enrollments/:enrollmentId/revoke — workspace-admin removal. */
40
+ removeEnrollment?: (
41
+ workspaceId: string,
42
+ enrollmentId: string,
43
+ request?: RemoveEnrollmentRequest,
44
+ ) => Promise<RemoveEnrollmentResponse>;
34
45
  /**
35
46
  * POST .../sessions/:sessionId/active-sandbox — swap the session's active
36
47
  * sandbox to a machine. The default swap path; the real SDK client provides it.
@@ -39,7 +50,7 @@ export type MachinesClientLike = {
39
50
  workspaceId: string,
40
51
  sessionId: string,
41
52
  request: { target: string },
42
- ) => Promise<unknown>;
53
+ ) => Promise<SwapActiveSandboxResponse>;
43
54
  /**
44
55
  * Host-supplied swap adapter (an escape hatch). When present it wins over the
45
56
  * default `swapActiveSandbox` path. Session-scoped, like the swap it backs.
@@ -69,6 +80,13 @@ export type UseMachinesResult = {
69
80
  refresh: () => Promise<void>;
70
81
  /** Attach/swap the session's active sandbox to a machine (returns the new pointer). */
71
82
  attach: (sandboxId: string) => Promise<boolean>;
83
+ /** Remove a self-hosted enrollment while retaining history. */
84
+ remove: (
85
+ enrollmentId: string,
86
+ request?: RemoveEnrollmentRequest,
87
+ ) => Promise<RemoveEnrollmentResponse | null>;
88
+ canRemove: boolean;
89
+ removingEnrollmentId: string | null;
72
90
  /** Whether the host wired an attach/swap path (drives the card affordance). */
73
91
  canAttach: boolean;
74
92
  /** Fetch a downsampled metric series for one enrolled machine. */
@@ -85,6 +103,24 @@ export type UseMachinesResult = {
85
103
 
86
104
  const EMPTY: MachinesResponse = { activeSandboxId: null, activeEpoch: 0, machines: [] };
87
105
 
106
+ function swapFailureMessage(result: SwapActiveSandboxResponse): string {
107
+ if (result.reason?.trim()) return result.reason;
108
+ switch (result.code) {
109
+ case "recovery_in_progress":
110
+ return "The managed sandbox is still recovering. Try again shortly.";
111
+ case "recovery_degraded":
112
+ return "The managed sandbox recovery is degraded and needs attention.";
113
+ case "recovery_unrecoverable":
114
+ return "The managed sandbox could not be recovered.";
115
+ case "offline_enrollment":
116
+ return "The selected machine is offline.";
117
+ case "concurrent_swap":
118
+ return "The session route changed concurrently. Refresh and try again.";
119
+ default:
120
+ return "The session stayed on its current sandbox.";
121
+ }
122
+ }
123
+
88
124
  /**
89
125
  * The workspace Machines fleet: the selfhosted enrollments + the session's Modal
90
126
  * box, each with latest metrics + state, plus the active-sandbox pointer. Polls
@@ -128,6 +164,12 @@ export function useMachines(options: UseMachinesOptions = {}): UseMachinesResult
128
164
  sandboxId: string | null;
129
165
  }>(() => ({ identity: identityKey, sandboxId: null }));
130
166
  const attachingSandboxId = attachState.identity === identityKey ? attachState.sandboxId : null;
167
+ const [removeState, setRemoveState] = useState<{
168
+ identity: string;
169
+ enrollmentId: string | null;
170
+ }>(() => ({ identity: identityKey, enrollmentId: null }));
171
+ const removingEnrollmentId =
172
+ removeState.identity === identityKey ? removeState.enrollmentId : null;
131
173
 
132
174
  const data = loadedData ?? EMPTY;
133
175
  // The swap is session-scoped: a host adapter (`attachMachine`) wins; otherwise
@@ -137,6 +179,7 @@ export function useMachines(options: UseMachinesOptions = {}): UseMachinesResult
137
179
  sessionId !== undefined &&
138
180
  (typeof machinesClient.attachMachine === "function" ||
139
181
  typeof machinesClient.swapActiveSandbox === "function");
182
+ const canRemove = typeof machinesClient.removeEnrollment === "function";
140
183
 
141
184
  const attach = useCallback(
142
185
  async (sandboxId: string): Promise<boolean> => {
@@ -150,7 +193,15 @@ export function useMachines(options: UseMachinesOptions = {}): UseMachinesResult
150
193
  const ownedIdentity = identityKey;
151
194
  setAttachState({ identity: ownedIdentity, sandboxId });
152
195
  const result = await run(async () => {
153
- await runSwap();
196
+ const response = await runSwap();
197
+ if (
198
+ response &&
199
+ typeof response === "object" &&
200
+ "swapped" in response &&
201
+ response.swapped === false
202
+ ) {
203
+ throw new Error(swapFailureMessage(response as SwapActiveSandboxResponse));
204
+ }
154
205
  return true;
155
206
  });
156
207
  if (identityRef.current === ownedIdentity) {
@@ -173,6 +224,28 @@ export function useMachines(options: UseMachinesOptions = {}): UseMachinesResult
173
224
  [machinesClient, workspaceId],
174
225
  );
175
226
 
227
+ const remove = useCallback(
228
+ async (
229
+ enrollmentId: string,
230
+ request: RemoveEnrollmentRequest = {},
231
+ ): Promise<RemoveEnrollmentResponse | null> => {
232
+ if (!machinesClient.removeEnrollment) return null;
233
+ const ownedIdentity = identityKey;
234
+ setRemoveState({ identity: ownedIdentity, enrollmentId });
235
+ const result = await run(() =>
236
+ machinesClient.removeEnrollment!(workspaceId, enrollmentId, request),
237
+ );
238
+ if (identityRef.current === ownedIdentity) {
239
+ setRemoveState({ identity: ownedIdentity, enrollmentId: null });
240
+ if (result?.outcome === "removed" || result?.outcome === "already_removed") {
241
+ await refresh();
242
+ }
243
+ }
244
+ return result;
245
+ },
246
+ [machinesClient, workspaceId, identityKey, run, refresh],
247
+ );
248
+
176
249
  return {
177
250
  machines: data.machines,
178
251
  activeSandboxId: data.activeSandboxId,
@@ -183,8 +256,11 @@ export function useMachines(options: UseMachinesOptions = {}): UseMachinesResult
183
256
  attach,
184
257
  canAttach,
185
258
  fetchSeries,
186
- attaching: mutating,
259
+ attaching: mutating && attachingSandboxId !== null,
187
260
  attachingSandboxId,
261
+ remove,
262
+ canRemove,
263
+ removingEnrollmentId,
188
264
  mutationError,
189
265
  clearMutationError,
190
266
  };
@@ -1,8 +1,14 @@
1
1
  import type {
2
2
  CapabilityPack,
3
3
  EnablePackRequest,
4
+ InstallPackRequest,
5
+ PackInstallationPreview,
4
6
  PackInstallation,
7
+ PackUninstallPreview,
8
+ PreviewPackInstallationRequest,
5
9
  RegisterCapabilityPackRequest,
10
+ UninstallPackRequest,
11
+ UninstallPackResult,
6
12
  WorkspaceRegisteredPack,
7
13
  } from "@opengeni/sdk";
8
14
  import { useCallback } from "react";
@@ -28,7 +34,15 @@ export type UsePacksResult = {
28
34
  refresh: () => Promise<void>;
29
35
  /** Register (or replace) a workspace-scoped pack manifest. */
30
36
  register: (manifest: RegisterCapabilityPackRequest) => Promise<WorkspaceRegisteredPack | null>;
37
+ /** @deprecated Use previewInstallation + install for component/Rig-aware Packs. */
31
38
  enable: (packId: string, request?: EnablePackRequest) => Promise<PackInstallation | null>;
39
+ previewInstallation: (
40
+ packId: string,
41
+ request?: PreviewPackInstallationRequest,
42
+ ) => Promise<PackInstallationPreview | null>;
43
+ install: (packId: string, request: InstallPackRequest) => Promise<PackInstallation | null>;
44
+ previewUninstall: (packId: string) => Promise<PackUninstallPreview | null>;
45
+ uninstall: (packId: string, request: UninstallPackRequest) => Promise<UninstallPackResult | null>;
32
46
  /** Unregister a workspace-scoped pack (built-ins cannot be removed). */
33
47
  remove: (packId: string) => Promise<boolean>;
34
48
  mutating: boolean;
@@ -68,6 +82,39 @@ export function usePacks(options: UsePacksOptions = {}): UsePacksResult {
68
82
  [client, workspaceId, run, refresh],
69
83
  );
70
84
 
85
+ const previewInstallation = useCallback(
86
+ async (
87
+ packId: string,
88
+ request: PreviewPackInstallationRequest = {},
89
+ ): Promise<PackInstallationPreview | null> =>
90
+ await run(() => client.previewPackInstallation(workspaceId, packId, request)),
91
+ [client, workspaceId, run],
92
+ );
93
+
94
+ const install = useCallback(
95
+ async (packId: string, request: InstallPackRequest): Promise<PackInstallation | null> => {
96
+ const result = await run(() => client.installPack(workspaceId, packId, request));
97
+ if (result) await refresh();
98
+ return result;
99
+ },
100
+ [client, workspaceId, run, refresh],
101
+ );
102
+
103
+ const previewUninstall = useCallback(
104
+ async (packId: string): Promise<PackUninstallPreview | null> =>
105
+ await run(() => client.previewPackUninstall(workspaceId, packId)),
106
+ [client, workspaceId, run],
107
+ );
108
+
109
+ const uninstall = useCallback(
110
+ async (packId: string, request: UninstallPackRequest): Promise<UninstallPackResult | null> => {
111
+ const result = await run(() => client.uninstallPack(workspaceId, packId, request));
112
+ if (result) await refresh();
113
+ return result;
114
+ },
115
+ [client, workspaceId, run, refresh],
116
+ );
117
+
71
118
  const remove = useCallback(
72
119
  async (packId: string): Promise<boolean> => {
73
120
  const result = await run(async () => {
@@ -98,6 +145,10 @@ export function usePacks(options: UsePacksOptions = {}): UsePacksResult {
98
145
  refresh,
99
146
  register,
100
147
  enable,
148
+ previewInstallation,
149
+ install,
150
+ previewUninstall,
151
+ uninstall,
101
152
  remove,
102
153
  mutating,
103
154
  mutationError,