@volter/sdk 0.0.0-stage → 0.5.204

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 (523) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +20 -0
  3. package/README.md +38 -3
  4. package/package.json +510 -4
  5. package/src/account.ts +210 -0
  6. package/src/chrome.ts +88 -0
  7. package/src/client.ts +1646 -0
  8. package/src/commands.ts +66 -0
  9. package/src/contributions.ts +619 -0
  10. package/src/css-numeric-style.ts +97 -0
  11. package/src/document-probe.ts +282 -0
  12. package/src/editor-view.ts +225 -0
  13. package/src/extension.ts +40 -0
  14. package/src/generations.ts +178 -0
  15. package/src/host.ts +1157 -0
  16. package/src/http-transport.browser.ts +14 -0
  17. package/src/http-transport.node.ts +19 -0
  18. package/src/index.ts +131 -0
  19. package/src/kit/CapabilityCoverageSection.tsx +185 -0
  20. package/src/kit/account-client.ts +333 -0
  21. package/src/kit/action-registry.ts +317 -0
  22. package/src/kit/active-product.ts +76 -0
  23. package/src/kit/active-project.ts +155 -0
  24. package/src/kit/adapter-editor-config.ts +25 -0
  25. package/src/kit/adapter-module.ts +7 -0
  26. package/src/kit/adapter-observation.ts +49 -0
  27. package/src/kit/animation/animation-clock.ts +479 -0
  28. package/src/kit/animation/stage-transport.ts +385 -0
  29. package/src/kit/api/assets.ts +365 -0
  30. package/src/kit/api/project-open.ts +355 -0
  31. package/src/kit/api/project-source.ts +180 -0
  32. package/src/kit/api/project-state.ts +110 -0
  33. package/src/kit/api/relay.ts +270 -0
  34. package/src/kit/api/themes.ts +45 -0
  35. package/src/kit/api-asset-library-wire.ts +45 -0
  36. package/src/kit/api-base.ts +10 -0
  37. package/src/kit/api-build.ts +99 -0
  38. package/src/kit/api-git-wire.ts +56 -0
  39. package/src/kit/api-logs.ts +92 -0
  40. package/src/kit/api-project-identity.ts +74 -0
  41. package/src/kit/api-settings.ts +36 -0
  42. package/src/kit/api-worktrees.ts +205 -0
  43. package/src/kit/asset-capabilities.ts +344 -0
  44. package/src/kit/asset-compare-core.ts +171 -0
  45. package/src/kit/asset-editor-context.tsx +101 -0
  46. package/src/kit/asset-events.ts +96 -0
  47. package/src/kit/asset-inspector-actions.ts +87 -0
  48. package/src/kit/asset-selection-viewer-registry.ts +113 -0
  49. package/src/kit/asset-selection.ts +146 -0
  50. package/src/kit/asset-thumbnails.ts +25 -0
  51. package/src/kit/asset-viewers.ts +115 -0
  52. package/src/kit/asset-workflow/asset-import-jobs.ts +106 -0
  53. package/src/kit/asset-workflow/asset-ledger-backend.ts +126 -0
  54. package/src/kit/asset-workflow/asset-ledger.ts +156 -0
  55. package/src/kit/asset-workflow/asset-materialization-report.ts +140 -0
  56. package/src/kit/asset-workflow/asset-pack-manifest.ts +320 -0
  57. package/src/kit/asset-workflow/asset-types.ts +142 -0
  58. package/src/kit/asset-workflow/audio-preview-player.ts +193 -0
  59. package/src/kit/asset-workflow/audio-waveform.ts +22 -0
  60. package/src/kit/asset-workflow/cloud-asset-client.ts +263 -0
  61. package/src/kit/asset-workflow/hosted-asset-materialization.ts +236 -0
  62. package/src/kit/asset-workflow/image-view-scale.ts +31 -0
  63. package/src/kit/asset-workflow/import-contract.ts +124 -0
  64. package/src/kit/asset-workflow/ledger-write-lock.ts +244 -0
  65. package/src/kit/asset-workflow/pixi-spritesheet.ts +197 -0
  66. package/src/kit/asset-workflow/preview-resource-lifetime.ts +44 -0
  67. package/src/kit/asset-workflow/project-asset-commands.ts +20 -0
  68. package/src/kit/asset-workflow/project-content.ts +288 -0
  69. package/src/kit/asset-workflow/project-source-index.ts +545 -0
  70. package/src/kit/asset-workflow/thumbnail-system.ts +256 -0
  71. package/src/kit/authoring/active-adapter.ts +200 -0
  72. package/src/kit/authoring/active-systems.ts +422 -0
  73. package/src/kit/authoring/adapter-key.ts +18 -0
  74. package/src/kit/authoring/authoring-asset-url.ts +27 -0
  75. package/src/kit/authoring/bootstrap-state.ts +49 -0
  76. package/src/kit/authoring/boundary-authoring-adapter.ts +189 -0
  77. package/src/kit/authoring/canvas-scene-guides.ts +84 -0
  78. package/src/kit/authoring/composite-authoring-adapter.ts +2109 -0
  79. package/src/kit/authoring/consumer-actions.ts +531 -0
  80. package/src/kit/authoring/design-time-layers.ts +852 -0
  81. package/src/kit/authoring/design-time-mount-registry.ts +244 -0
  82. package/src/kit/authoring/edit-mode-authoring.ts +637 -0
  83. package/src/kit/authoring/empty-project-authoring.ts +22 -0
  84. package/src/kit/authoring/instance-source-menu.ts +135 -0
  85. package/src/kit/authoring/layered-pick.ts +185 -0
  86. package/src/kit/authoring/mounted-root-subjects.ts +146 -0
  87. package/src/kit/authoring/no-authoring-adapter.ts +59 -0
  88. package/src/kit/authoring/object3d-document-persistence.ts +122 -0
  89. package/src/kit/authoring/panel-authoring.ts +121 -0
  90. package/src/kit/authoring/project-authoring-session.ts +105 -0
  91. package/src/kit/authoring/provenance.ts +99 -0
  92. package/src/kit/authoring/react-canvas-navigation.ts +259 -0
  93. package/src/kit/authoring/react-design-canvas-style.ts +20 -0
  94. package/src/kit/authoring/react-story-board.ts +917 -0
  95. package/src/kit/authoring/selection-scope.ts +195 -0
  96. package/src/kit/authoring/shell-document-ops.ts +169 -0
  97. package/src/kit/authoring/story-board-chrome-fit.ts +107 -0
  98. package/src/kit/authoring/story-board-presentation.ts +111 -0
  99. package/src/kit/authoring/three-root.ts +67 -0
  100. package/src/kit/authoring/viewport-tool-context.ts +73 -0
  101. package/src/kit/authoring/viewport-tool-owner.ts +38 -0
  102. package/src/kit/authoring/world-session-state.ts +101 -0
  103. package/src/kit/authoring-seam-evidence.ts +300 -0
  104. package/src/kit/availability-tick.ts +66 -0
  105. package/src/kit/bitmap-label.ts +120 -0
  106. package/src/kit/boot-routing.ts +392 -0
  107. package/src/kit/breakpoint-state.ts +43 -0
  108. package/src/kit/build-identity.ts +16 -0
  109. package/src/kit/bytes-codec.ts +62 -0
  110. package/src/kit/cancellation-reason.ts +58 -0
  111. package/src/kit/canvas-frames.ts +88 -0
  112. package/src/kit/capture-camera-pose.ts +77 -0
  113. package/src/kit/capture-size.ts +88 -0
  114. package/src/kit/chrome-registry.ts +159 -0
  115. package/src/kit/chrome-slot-registry.ts +91 -0
  116. package/src/kit/collaboration-client.ts +264 -0
  117. package/src/kit/collaboration-presence.ts +41 -0
  118. package/src/kit/command-dispatch.ts +19 -0
  119. package/src/kit/command-listener.ts +2182 -0
  120. package/src/kit/command-registry.ts +71 -0
  121. package/src/kit/component-board-registry.ts +205 -0
  122. package/src/kit/component-states-registry.ts +199 -0
  123. package/src/kit/components/AlignToolbar.tsx +204 -0
  124. package/src/kit/components/ApplicationMenus.tsx +372 -0
  125. package/src/kit/components/AssetEditorShell.tsx +216 -0
  126. package/src/kit/components/AssetInspectorToolSection.tsx +124 -0
  127. package/src/kit/components/BoardRulers.tsx +354 -0
  128. package/src/kit/components/CanvasAddNodeDialogs.tsx +529 -0
  129. package/src/kit/components/CanvasSceneViewport.tsx +1195 -0
  130. package/src/kit/components/ChromeSlot.tsx +20 -0
  131. package/src/kit/components/CodeView.tsx +470 -0
  132. package/src/kit/components/CompactInspectorShell.tsx +39 -0
  133. package/src/kit/components/ConsolePanel.tsx +273 -0
  134. package/src/kit/components/GameplaySessionTimeline.tsx +295 -0
  135. package/src/kit/components/InspectionProjection.tsx +932 -0
  136. package/src/kit/components/Inspector.tsx +270 -0
  137. package/src/kit/components/InspectorCanvasPreview.tsx +35 -0
  138. package/src/kit/components/InspectorFieldsSection.tsx +290 -0
  139. package/src/kit/components/InspectorStoriesSection.tsx +92 -0
  140. package/src/kit/components/InspectorToolSection.tsx +96 -0
  141. package/src/kit/components/InspectorTransformSection.tsx +245 -0
  142. package/src/kit/components/LightExplorerPanel.tsx +433 -0
  143. package/src/kit/components/MediaProperties.tsx +145 -0
  144. package/src/kit/components/ProjectHeader.tsx +328 -0
  145. package/src/kit/components/ReactCanvasControls.tsx +358 -0
  146. package/src/kit/components/RootSelectionOverlay.tsx +3688 -0
  147. package/src/kit/components/RootTextEditor.tsx +79 -0
  148. package/src/kit/components/SaveStatus.tsx +70 -0
  149. package/src/kit/components/SurfaceCrashBoundary.tsx +105 -0
  150. package/src/kit/components/SurfaceStateOverlay.tsx +24 -0
  151. package/src/kit/components/ToolContributionSurfaces.tsx +49 -0
  152. package/src/kit/components/ToolHost.tsx +380 -0
  153. package/src/kit/components/Toolbar.tsx +811 -0
  154. package/src/kit/components/TransientHint.tsx +44 -0
  155. package/src/kit/components/VersionControlSection.tsx +470 -0
  156. package/src/kit/components/ViewportOverlaysMenu.tsx +177 -0
  157. package/src/kit/components/VolterLogo.tsx +18 -0
  158. package/src/kit/components/WorktreeSwitcher.tsx +712 -0
  159. package/src/kit/components/account-documents.tsx +1162 -0
  160. package/src/kit/components/asset-documents.tsx +794 -0
  161. package/src/kit/components/asset-editor-persistence.ts +216 -0
  162. package/src/kit/components/asset-selection-section.tsx +545 -0
  163. package/src/kit/components/asset-thumbnails.tsx +307 -0
  164. package/src/kit/components/asset-viewers/AudioViewer.tsx +201 -0
  165. package/src/kit/components/asset-viewers/GenericJsonViewer.tsx +102 -0
  166. package/src/kit/components/asset-viewers/ImageViewer.tsx +300 -0
  167. package/src/kit/components/asset-viewers/JsonAssetDocument.tsx +98 -0
  168. package/src/kit/components/asset-viewers/OnlineAssetDetail.tsx +426 -0
  169. package/src/kit/components/asset-viewers/SourceAssetViewer.tsx +356 -0
  170. package/src/kit/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
  171. package/src/kit/components/asset-viewers/VideoViewer.tsx +101 -0
  172. package/src/kit/components/asset-viewers/shader-source.ts +144 -0
  173. package/src/kit/components/board-guides.ts +150 -0
  174. package/src/kit/components/canvas-scene-hotkeys.ts +37 -0
  175. package/src/kit/components/canvas-temporary-pivot.ts +34 -0
  176. package/src/kit/components/core-utilities.tsx +94 -0
  177. package/src/kit/components/inspector-preview-section.tsx +223 -0
  178. package/src/kit/components/inspector-revert-label.ts +20 -0
  179. package/src/kit/components/inspector-selection.ts +42 -0
  180. package/src/kit/components/inspector-stories-gating.ts +171 -0
  181. package/src/kit/components/inspector-transform-subject.ts +11 -0
  182. package/src/kit/components/inspector-transform.ts +88 -0
  183. package/src/kit/components/kind-documents.tsx +544 -0
  184. package/src/kit/components/primitives/DraftColorInput.tsx +74 -0
  185. package/src/kit/components/project-tool-documents.tsx +402 -0
  186. package/src/kit/components/scene-documents.tsx +221 -0
  187. package/src/kit/components/status-contributions.tsx +407 -0
  188. package/src/kit/components/tool-documents.tsx +302 -0
  189. package/src/kit/components/tool-schema-form.tsx +262 -0
  190. package/src/kit/components/use-after-paint.ts +41 -0
  191. package/src/kit/components/use-project-image-assets.ts +86 -0
  192. package/src/kit/components/workspace-history.ts +32 -0
  193. package/src/kit/components/world-documents.tsx +570 -0
  194. package/src/kit/components/world-overlay-gestures.ts +1939 -0
  195. package/src/kit/composite-screenshot.ts +2238 -0
  196. package/src/kit/content-entry-source-registry.ts +184 -0
  197. package/src/kit/contribution-surfaces.ts +48 -0
  198. package/src/kit/coverage/canvas-reveal.ts +192 -0
  199. package/src/kit/coverage/design-time-surfaces.ts +101 -0
  200. package/src/kit/coverage/ontology-invariants.ts +466 -0
  201. package/src/kit/coverage/session-vitals.ts +503 -0
  202. package/src/kit/crash-null-boundary.ts +36 -0
  203. package/src/kit/creation-site-edit.ts +1491 -0
  204. package/src/kit/creation-site-registry.ts +160 -0
  205. package/src/kit/delegate-harness-registry.ts +134 -0
  206. package/src/kit/document-areas.ts +70 -0
  207. package/src/kit/document-context-registry.ts +193 -0
  208. package/src/kit/document-open-registry.ts +200 -0
  209. package/src/kit/document-play-extension.ts +221 -0
  210. package/src/kit/document-preview-source.ts +20 -0
  211. package/src/kit/document-renderer-session.ts +138 -0
  212. package/src/kit/document-stage-sessions.ts +26 -0
  213. package/src/kit/document-viewports.ts +120 -0
  214. package/src/kit/editor-api.ts +46 -0
  215. package/src/kit/editor-chrome-capture.ts +136 -0
  216. package/src/kit/editor-commands.ts +176 -0
  217. package/src/kit/editor-console.ts +580 -0
  218. package/src/kit/editor-current-view.ts +56 -0
  219. package/src/kit/editor-document-probe.ts +1168 -0
  220. package/src/kit/editor-git-client.ts +115 -0
  221. package/src/kit/editor-hotkeys.ts +728 -0
  222. package/src/kit/editor-lease-view.ts +39 -0
  223. package/src/kit/editor-lease.ts +415 -0
  224. package/src/kit/editor-mode.ts +19 -0
  225. package/src/kit/editor-notifications.ts +140 -0
  226. package/src/kit/editor-presence.ts +563 -0
  227. package/src/kit/editor-presentation-activity.ts +58 -0
  228. package/src/kit/editor-presentation-notice.ts +42 -0
  229. package/src/kit/editor-runtime.tsx +147 -0
  230. package/src/kit/editor-server-response.ts +86 -0
  231. package/src/kit/editor-session-attribution.ts +85 -0
  232. package/src/kit/editor-session-mode.ts +54 -0
  233. package/src/kit/editor-state-facets.ts +74 -0
  234. package/src/kit/editor-view-presentation.ts +777 -0
  235. package/src/kit/environment-images.ts +58 -0
  236. package/src/kit/eyedropper-session.ts +60 -0
  237. package/src/kit/files/file-provider.ts +62 -0
  238. package/src/kit/files/project-files.ts +270 -0
  239. package/src/kit/finders/index.ts +137 -0
  240. package/src/kit/finders/scenes-from-entrypoint-selection.ts +387 -0
  241. package/src/kit/frame/frame-parts.ts +30 -0
  242. package/src/kit/framed-document-capture.ts +34 -0
  243. package/src/kit/game-globals-prelude.ts +143 -0
  244. package/src/kit/game-surface-defaults.ts +33 -0
  245. package/src/kit/gameplay-dom-recording.ts +318 -0
  246. package/src/kit/gameplay-export-state.ts +14 -0
  247. package/src/kit/gameplay-replay.ts +417 -0
  248. package/src/kit/gameplay-session-time.ts +9 -0
  249. package/src/kit/gameplay-sessions.ts +204 -0
  250. package/src/kit/hierarchy-component-marks.ts +298 -0
  251. package/src/kit/hierarchy-internals.ts +197 -0
  252. package/src/kit/hierarchy-kind-icon.ts +217 -0
  253. package/src/kit/hierarchy-menu-registry.ts +67 -0
  254. package/src/kit/hierarchy-node-rows.ts +307 -0
  255. package/src/kit/hierarchy-panel-view.ts +280 -0
  256. package/src/kit/hierarchy-projection.ts +76 -0
  257. package/src/kit/hierarchy-row-media.ts +45 -0
  258. package/src/kit/hierarchy-row-model.ts +308 -0
  259. package/src/kit/hierarchy-rows.ts +11 -0
  260. package/src/kit/hierarchy-walk.ts +86 -0
  261. package/src/kit/history/editor-session.ts +25 -0
  262. package/src/kit/history/history-commands.ts +147 -0
  263. package/src/kit/history/history-delegate.ts +187 -0
  264. package/src/kit/history/history-limit-notices.ts +43 -0
  265. package/src/kit/history/history-service.ts +1189 -0
  266. package/src/kit/history/persistence-coordinator.ts +35 -0
  267. package/src/kit/history/project-file-history.ts +386 -0
  268. package/src/kit/history/project-root-history-backends.ts +139 -0
  269. package/src/kit/history/resource-registry.ts +209 -0
  270. package/src/kit/history/snapshot-store.ts +103 -0
  271. package/src/kit/history/source-history-backend.ts +546 -0
  272. package/src/kit/history-types.ts +124 -0
  273. package/src/kit/hmr-registration-group.ts +67 -0
  274. package/src/kit/hmr-stable-react-context.ts +23 -0
  275. package/src/kit/hotkeys.ts +190 -0
  276. package/src/kit/inference-diagnostics.ts +69 -0
  277. package/src/kit/initial-project.ts +80 -0
  278. package/src/kit/inspection/active-subject.ts +571 -0
  279. package/src/kit/inspection/active-surface.ts +142 -0
  280. package/src/kit/inspection/compose-subject.ts +1055 -0
  281. package/src/kit/inspection/compose.ts +7 -0
  282. package/src/kit/inspection/display.ts +171 -0
  283. package/src/kit/inspection/document-subject.ts +109 -0
  284. package/src/kit/inspection/game-subject.ts +85 -0
  285. package/src/kit/inspection/null-subject.ts +119 -0
  286. package/src/kit/inspection/serialize.ts +357 -0
  287. package/src/kit/inspection/use-active-inspection.ts +180 -0
  288. package/src/kit/inspection-model.ts +542 -0
  289. package/src/kit/inspection-node-media.ts +58 -0
  290. package/src/kit/inspector-presentation.ts +203 -0
  291. package/src/kit/inspector-property-grouping.ts +64 -0
  292. package/src/kit/inspector-section-registry.ts +221 -0
  293. package/src/kit/instance-source-actions.ts +163 -0
  294. package/src/kit/js-heap.ts +71 -0
  295. package/src/kit/key-actions.ts +91 -0
  296. package/src/kit/keymap-presets.ts +428 -0
  297. package/src/kit/layout-policy.ts +31 -0
  298. package/src/kit/light-explorer-model.ts +134 -0
  299. package/src/kit/live-canvas-frame.ts +55 -0
  300. package/src/kit/live-document.ts +296 -0
  301. package/src/kit/live-gesture-lock.ts +50 -0
  302. package/src/kit/live-seam-evidence.ts +11 -0
  303. package/src/kit/live-session-registry.ts +220 -0
  304. package/src/kit/live-transition.ts +391 -0
  305. package/src/kit/manifest-project.ts +107 -0
  306. package/src/kit/module-fetch-diagnosis.ts +192 -0
  307. package/src/kit/mount-failure-report.ts +154 -0
  308. package/src/kit/native-selection-style.ts +497 -0
  309. package/src/kit/object3d-document-write-policy.ts +137 -0
  310. package/src/kit/packaged-runtime.ts +108 -0
  311. package/src/kit/palettes/maya.palette.json +57 -0
  312. package/src/kit/palettes/substance.palette.json +57 -0
  313. package/src/kit/performance-profiler.ts +367 -0
  314. package/src/kit/performance-sources.ts +69 -0
  315. package/src/kit/photograph-notice.ts +141 -0
  316. package/src/kit/play-boot-phase.ts +166 -0
  317. package/src/kit/play-camera-flight.ts +35 -0
  318. package/src/kit/png-encode.worker.ts +26 -0
  319. package/src/kit/presentation-surface.ts +248 -0
  320. package/src/kit/product-command.ts +90 -0
  321. package/src/kit/project-adapter.ts +1140 -0
  322. package/src/kit/project-asset-refresh.ts +23 -0
  323. package/src/kit/project-asset-roots.ts +68 -0
  324. package/src/kit/project-local-state.ts +151 -0
  325. package/src/kit/project-manager.ts +243 -0
  326. package/src/kit/project-module-changes.ts +201 -0
  327. package/src/kit/project-module-split.ts +270 -0
  328. package/src/kit/project-play-layers.ts +25 -0
  329. package/src/kit/project-provenance.ts +115 -0
  330. package/src/kit/project-ready.ts +42 -0
  331. package/src/kit/project-shape.ts +68 -0
  332. package/src/kit/project-tools.ts +107 -0
  333. package/src/kit/projection-types.ts +44 -0
  334. package/src/kit/readiness.ts +113 -0
  335. package/src/kit/renderer-resource-counts.ts +27 -0
  336. package/src/kit/reported-play-state.ts +90 -0
  337. package/src/kit/resolve-contributed-command.ts +14 -0
  338. package/src/kit/resolve-relative-specifier.ts +33 -0
  339. package/src/kit/retained-document-states.ts +91 -0
  340. package/src/kit/scene-document-plan.ts +320 -0
  341. package/src/kit/scene-live-open.ts +210 -0
  342. package/src/kit/scoped-game-css.ts +152 -0
  343. package/src/kit/served-url.ts +5 -0
  344. package/src/kit/session-close.ts +17 -0
  345. package/src/kit/session-tombstone.ts +127 -0
  346. package/src/kit/settings/settings-provider.ts +82 -0
  347. package/src/kit/settings-store.ts +348 -0
  348. package/src/kit/shell-document-state.ts +27 -0
  349. package/src/kit/shell-store-door.ts +45 -0
  350. package/src/kit/shell-store.ts +722 -0
  351. package/src/kit/source-conflict.ts +122 -0
  352. package/src/kit/stage-context.ts +377 -0
  353. package/src/kit/stage-invalidation.ts +25 -0
  354. package/src/kit/stage-store-registry.ts +69 -0
  355. package/src/kit/startup-failure.ts +80 -0
  356. package/src/kit/state-report-deferral.ts +73 -0
  357. package/src/kit/storage/host-files-storage.ts +97 -0
  358. package/src/kit/storage/http-storage.ts +174 -0
  359. package/src/kit/storage/index.ts +75 -0
  360. package/src/kit/storage/mem-storage.ts +158 -0
  361. package/src/kit/storage/path-lock.ts +44 -0
  362. package/src/kit/storage/paths.ts +26 -0
  363. package/src/kit/storage-types.ts +127 -0
  364. package/src/kit/stories/StoryPreviewMount.tsx +306 -0
  365. package/src/kit/stories/compose-project-stories.ts +255 -0
  366. package/src/kit/stories/prefabs-finder.ts +54 -0
  367. package/src/kit/stories/prefabs-from-stories.ts +182 -0
  368. package/src/kit/stories/project-story-regions.ts +24 -0
  369. package/src/kit/stories/story-capture.ts +579 -0
  370. package/src/kit/stories/story-declared-medium.ts +126 -0
  371. package/src/kit/stories/story-discovery.ts +176 -0
  372. package/src/kit/stories/story-dom-runtime.ts +78 -0
  373. package/src/kit/stories/story-grouping.ts +111 -0
  374. package/src/kit/stories/story-mount-turn.ts +27 -0
  375. package/src/kit/stories/story-presentation.ts +215 -0
  376. package/src/kit/stories/story-preview-component.ts +7 -0
  377. package/src/kit/stories/story-registry.ts +530 -0
  378. package/src/kit/stories-scope.ts +35 -0
  379. package/src/kit/story-document-openers.ts +36 -0
  380. package/src/kit/story-thumbnails.ts +47 -0
  381. package/src/kit/surface-keyboard.ts +101 -0
  382. package/src/kit/surface-state.ts +135 -0
  383. package/src/kit/system-seam-evidence.ts +72 -0
  384. package/src/kit/tab-census.ts +202 -0
  385. package/src/kit/tab-lifecycle-client.ts +227 -0
  386. package/src/kit/theme-library.ts +897 -0
  387. package/src/kit/theme-preference.ts +429 -0
  388. package/src/kit/three-viewport-presentation.ts +23 -0
  389. package/src/kit/tool-contribution-play.ts +74 -0
  390. package/src/kit/tool-loader.ts +1918 -0
  391. package/src/kit/transform-mode-request.ts +66 -0
  392. package/src/kit/transient-hint.ts +78 -0
  393. package/src/kit/transport-strip.tsx +174 -0
  394. package/src/kit/ui-source/adapter-region-includes.ts +238 -0
  395. package/src/kit/ui-source/file-region-resolver.ts +302 -0
  396. package/src/kit/ui-source/inspect.ts +775 -0
  397. package/src/kit/ui-source/source-write-backend.ts +605 -0
  398. package/src/kit/ui-source/tier-source-write-backend.ts +279 -0
  399. package/src/kit/user-local-state.ts +105 -0
  400. package/src/kit/viewport-activation-timings.ts +840 -0
  401. package/src/kit/viewport-editor-controls.ts +22 -0
  402. package/src/kit/viewport-presentation.ts +668 -0
  403. package/src/kit/viewport-surface-status.tsx +55 -0
  404. package/src/kit/wait-until.ts +37 -0
  405. package/src/kit/worker-call-metrics.ts +166 -0
  406. package/src/kit/workspace-areas.ts +191 -0
  407. package/src/kit/workspace-aux-commands.ts +11 -0
  408. package/src/kit/workspace-available-documents.ts +142 -0
  409. package/src/kit/workspace-core-utilities.ts +31 -0
  410. package/src/kit/workspace-document-ids.ts +59 -0
  411. package/src/kit/workspace-document-registry.ts +624 -0
  412. package/src/kit/workspace-document-restore.ts +146 -0
  413. package/src/kit/workspace-host-commands.ts +141 -0
  414. package/src/kit/workspace-persistence-gate.ts +40 -0
  415. package/src/kit/workspace-play-utilities.ts +44 -0
  416. package/src/kit/workspace-presets.ts +446 -0
  417. package/src/kit/workspace-regions.ts +276 -0
  418. package/src/kit/workspace-static-panels.ts +73 -0
  419. package/src/kit/workspace-status-registry.ts +121 -0
  420. package/src/kit/workspace-storage.ts +35 -0
  421. package/src/kit/workspace-style.ts +226 -0
  422. package/src/kit/workspace-utility-commands.ts +74 -0
  423. package/src/kit/workspace-utility-registry.ts +263 -0
  424. package/src/kit/world-adoption-event.ts +23 -0
  425. package/src/kit/world-adoption.ts +115 -0
  426. package/src/kit/world-canvas-viewport-state.ts +35 -0
  427. package/src/kit/world-document-routing.ts +104 -0
  428. package/src/kit/world-pan-state.ts +198 -0
  429. package/src/kit/write-pipe.ts +173 -0
  430. package/src/layout-arrangements.ts +5 -0
  431. package/src/layouts.tsx +108 -0
  432. package/src/looks.ts +16 -0
  433. package/src/project/output-roots.ts +73 -0
  434. package/src/project/tab-census.ts +155 -0
  435. package/src/project-tool-catalog.ts +104 -0
  436. package/src/selection.tsx +107 -0
  437. package/src/services.ts +18 -0
  438. package/src/session/build-report.ts +22 -0
  439. package/src/session/collaboration-types.ts +262 -0
  440. package/src/session/command-table.ts +327 -0
  441. package/src/session/discovery.ts +100 -0
  442. package/src/session/editor-brand.ts +48 -0
  443. package/src/session/editor-compatibility.ts +329 -0
  444. package/src/session/editor-control-lifecycle.ts +68 -0
  445. package/src/session/editor-control-protocol.ts +5 -0
  446. package/src/session/entrypoint-selection-readers.ts +66 -0
  447. package/src/session/entrypoint-selection-source.ts +120 -0
  448. package/src/session/game-css-scope.ts +30 -0
  449. package/src/session/hosted-attachment.ts +225 -0
  450. package/src/session/limited-view.ts +82 -0
  451. package/src/session/product-create.ts +24 -0
  452. package/src/session/product-locator.ts +478 -0
  453. package/src/session/project-module-url.ts +242 -0
  454. package/src/session/project-serving.ts +164 -0
  455. package/src/session/project-upgrade.ts +669 -0
  456. package/src/session/registry-format.ts +210 -0
  457. package/src/session/relative-path-guard.ts +56 -0
  458. package/src/session/scoped-game-css.ts +461 -0
  459. package/src/session/source-glob.ts +15 -0
  460. package/src/session/tool-contribution-convention.ts +123 -0
  461. package/src/session/workbench-locator.ts +712 -0
  462. package/src/session.ts +41 -0
  463. package/src/share.ts +160 -0
  464. package/src/source-analysis.ts +28 -0
  465. package/src/source-authoring.ts +439 -0
  466. package/src/tools/errors.ts +91 -0
  467. package/src/tools/provider-execution.ts +70 -0
  468. package/src/tools/registry.ts +341 -0
  469. package/src/tools/types.ts +159 -0
  470. package/src/transport.ts +100 -0
  471. package/src/types.ts +1693 -0
  472. package/src/views.ts +164 -0
  473. package/src/widgets/design-system.ts +93 -0
  474. package/src/widgets/editor-appearance.ts +151 -0
  475. package/src/widgets/editor-material.ts +83 -0
  476. package/src/widgets/icon-set-registry.ts +105 -0
  477. package/src/widgets/index.ts +71 -0
  478. package/src/widgets/inspector-widgets/AlignmentGrid.tsx +182 -0
  479. package/src/widgets/inspector-widgets/AssetSlotPicker.tsx +123 -0
  480. package/src/widgets/inspector-widgets/BorderEditor.tsx +309 -0
  481. package/src/widgets/inspector-widgets/ColorPicker.tsx +549 -0
  482. package/src/widgets/inspector-widgets/CurveEditor.tsx +359 -0
  483. package/src/widgets/inspector-widgets/FilterEditor.tsx +108 -0
  484. package/src/widgets/inspector-widgets/FontPicker.tsx +191 -0
  485. package/src/widgets/inspector-widgets/GradientEditor.tsx +623 -0
  486. package/src/widgets/inspector-widgets/ScrubbableInput.tsx +180 -0
  487. package/src/widgets/inspector-widgets/ShadowEditor.tsx +319 -0
  488. package/src/widgets/inspector-widgets/color-utils.ts +201 -0
  489. package/src/widgets/inspector-widgets/curve-utils.ts +212 -0
  490. package/src/widgets/inspector-widgets/index.ts +25 -0
  491. package/src/widgets/inspector-widgets/shared.tsx +140 -0
  492. package/src/widgets/interactive-edit-scope.ts +33 -0
  493. package/src/widgets/patterns/Dialog.tsx +140 -0
  494. package/src/widgets/patterns/Fields.tsx +44 -0
  495. package/src/widgets/patterns/List.tsx +25 -0
  496. package/src/widgets/patterns/StateSurface.tsx +40 -0
  497. package/src/widgets/patterns/Surfaces.tsx +122 -0
  498. package/src/widgets/patterns/Tabs.tsx +80 -0
  499. package/src/widgets/patterns/Toolbar.tsx +72 -0
  500. package/src/widgets/patterns/Tree.tsx +72 -0
  501. package/src/widgets/primitives/AnchoredMenu.tsx +260 -0
  502. package/src/widgets/primitives/Button.tsx +62 -0
  503. package/src/widgets/primitives/ColorInput.tsx +78 -0
  504. package/src/widgets/primitives/DraftTextInput.tsx +63 -0
  505. package/src/widgets/primitives/EditorIcon.tsx +157 -0
  506. package/src/widgets/primitives/FormControls.tsx +88 -0
  507. package/src/widgets/primitives/HoverPreview.tsx +96 -0
  508. package/src/widgets/primitives/JsonInput.tsx +113 -0
  509. package/src/widgets/primitives/Layout.tsx +100 -0
  510. package/src/widgets/primitives/Menu.tsx +161 -0
  511. package/src/widgets/primitives/NumberInput.tsx +169 -0
  512. package/src/widgets/primitives/Panel.tsx +80 -0
  513. package/src/widgets/primitives/SectionHeader.tsx +77 -0
  514. package/src/widgets/primitives/Text.tsx +54 -0
  515. package/src/widgets/primitives/ThemeRootPortal.tsx +52 -0
  516. package/src/widgets/primitives/Tooltip.tsx +204 -0
  517. package/src/widgets/primitives/Vec3Input.tsx +70 -0
  518. package/src/widgets/primitives/banner-tones.ts +32 -0
  519. package/src/widgets/primitives/clamp-to-viewport.ts +44 -0
  520. package/src/widgets/primitives/editor-icons.ts +254 -0
  521. package/src/widgets/primitives/panel-header-styles.ts +42 -0
  522. package/src/widgets/theme.ts +2841 -0
  523. package/src/widgets/z-index.ts +25 -0
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Keeping the editor's status snapshot off the interaction critical path.
3
+ *
4
+ * `collectState` (command-listener.ts) is not a read — it RE-DERIVES the whole
5
+ * status surface. Two families dominate, and both scale with the size of the
6
+ * project rather than with the size of the change:
7
+ *
8
+ * - the hierarchy walk behind `entities`/`entityCount`, and
9
+ * - the capability GRADING facets (`rootCoverage`, `systemCoverage`,
10
+ * `projectCoverage`, `authoringCoverage`, `ontologyInvariants`), each
11
+ * documented as re-derived on read; `rootCoverage`'s conformance probe
12
+ * walks the hierarchy AGAIN, once per mounted root, allocating a receipt
13
+ * object and a formatted sentence per node.
14
+ *
15
+ * Measured 2026-08-19 through the session journal on `examples/first-person`
16
+ * in play mode, 251 hierarchy nodes:
17
+ *
18
+ * collectState total 76ms = rootCoverage 30ms
19
+ * + 2 x hierarchy walk 23ms
20
+ * JSON.stringify of the 41KB result: 0.0ms. Sending it: 0.1ms.
21
+ *
22
+ * So none of the cost is serialization or transport; all of it is derivation,
23
+ * and it is superlinear in node count (56 nodes: 1.5ms per walk; 251 nodes:
24
+ * 23ms). On a game-heavy project the same function measured 1.2-1.3s of
25
+ * main-thread block.
26
+ *
27
+ * That would be survivable if it ran rarely. It does not: `reportLatestState`
28
+ * is wired to the store's own change notification, to restart-required, to the
29
+ * ingest capture wait, to the adapter load, to every command completion, and
30
+ * to focus/blur/visibilitychange. So the whole derivation ran on every
31
+ * selection click and several times over during a mount — which is why the
32
+ * defect reads as "the editor is slow to touch" while an idle tab is fine.
33
+ *
34
+ * The fix is not to derive less truth, it is to derive it OFF the critical
35
+ * path: an interaction reports immediately with the cheap fields fresh and the
36
+ * derived families reused from the last full snapshot, and schedules ONE
37
+ * deferred full collect that makes them current again. the editor's `status` command readers
38
+ * are never handed a snapshot older than that deferral, and the snapshot
39
+ * already carries its own age.
40
+ */
41
+
42
+ /**
43
+ * How long the deferred full collect may wait for an idle moment before the
44
+ * browser runs it anyway. Short enough that "current shortly after the change"
45
+ * stays true for a the editor's `status` command reader; long enough that the interaction that
46
+ * triggered it paints first, which is the entire point.
47
+ */
48
+ export const DEFERRED_FULL_REPORT_TIMEOUT_MS = 500;
49
+
50
+ interface IdleCallbackHost {
51
+ requestIdleCallback?: (callback: () => void, options?: { timeout?: number }) => number;
52
+ cancelIdleCallback?: (handle: number) => void;
53
+ }
54
+
55
+ /**
56
+ * Run `report` off the critical path — at the next idle moment, or when
57
+ * {@link DEFERRED_FULL_REPORT_TIMEOUT_MS} expires, whichever comes first.
58
+ * Returns the canceller the caller's teardown must run.
59
+ *
60
+ * Falls back to a task (`setTimeout`) where `requestIdleCallback` is missing
61
+ * (Safari before 17, and jsdom): still off the triggering handler's own frame,
62
+ * which is what makes the interaction cheap.
63
+ */
64
+ export function scheduleDeferredFullReport(report: () => void): () => void {
65
+ const host = globalThis as IdleCallbackHost;
66
+ const idle = host.requestIdleCallback;
67
+ if (typeof idle === 'function') {
68
+ const handle = idle.call(globalThis, report, { timeout: DEFERRED_FULL_REPORT_TIMEOUT_MS });
69
+ return () => host.cancelIdleCallback?.call(globalThis, handle);
70
+ }
71
+ const handle = setTimeout(report, 0);
72
+ return () => clearTimeout(handle);
73
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * `StorageBackend`, answered by the WORKBENCH'S OWN FILE SERVICE (U5).
3
+ *
4
+ * ARCHITECTURE-CORE §The core is Code-OSS: *"the storage backends → file
5
+ * system providers, the dev server as one provider"*. What that turned out to
6
+ * mean, measured: both product shapes already have a real file service over
7
+ * the project folder (desktop's disk provider, the REH's `vscode-remote://`),
8
+ * so there is nothing to PROVIDE — the door CALLS what exists
9
+ * (`files/project-files.ts` states the decision and the reason).
10
+ *
11
+ * This class is how the existing `StorageBackend` callers — forty-odd of
12
+ * them, from the asset browser to the provenance ledger — reach that file
13
+ * service without one of them changing. It is a DECORATOR, not a fourth
14
+ * backend: it overrides exactly the three operations where "is this the
15
+ * workbench's own write?" is a question that has an answer (`read`,
16
+ * `readBytes`, `write`) and delegates everything else to the tier's real
17
+ * backend. `remove`, `mkdir`, `stat`, `list` and `watch` are the session's
18
+ * still, because the file door deliberately carries no remove/mkdir — a
19
+ * member nobody reads is cut, and nothing in the frame needs them yet.
20
+ *
21
+ * THE ROOT DIFFERENCE IS THE WHOLE JOB. `StorageBackend`'s paths on the server
22
+ * tier are rooted at `<project>/public/` (`http-storage.ts`'s header) while
23
+ * the file door's are PROJECT-RELATIVE, because that is the spelling the frame
24
+ * can resolve against its workspace folder. This class is the `public/` view:
25
+ * one prefix, in one place, instead of forty callers learning a second
26
+ * spelling.
27
+ */
28
+
29
+ import { projectFiles } from '../files/project-files';
30
+ import type { DirEntry, Stat, StorageBackend, WatchCallback } from '@volter/sdk/kit/storage-types';
31
+
32
+ export class HostFilesStorage implements StorageBackend {
33
+ readonly id: string;
34
+
35
+ /**
36
+ * @param inner the tier's own backend, which still owns every operation the
37
+ * file door does not carry — and which is also the FALLBACK while the
38
+ * frame has taken ownership but not yet installed its provider (the mount
39
+ * window `files/file-provider.ts` describes).
40
+ * @param root the project-relative prefix these paths live under. Always
41
+ * `public` today; named rather than hardcoded so the prefix is visible at
42
+ * the call site that chose it.
43
+ */
44
+ constructor(
45
+ private readonly inner: StorageBackend,
46
+ private readonly root = 'public',
47
+ ) {
48
+ this.id = `frame:${inner.id}`;
49
+ }
50
+
51
+ private resolve(path: string): string {
52
+ const key = path.replace(/\\/g, '/').replace(/^\/+/, '');
53
+ return key ? `${this.root}/${key}` : this.root;
54
+ }
55
+
56
+ read(path: string): Promise<string> {
57
+ return projectFiles.read(this.resolve(path));
58
+ }
59
+
60
+ readBytes(path: string): Promise<Uint8Array> {
61
+ return projectFiles.readBytes(this.resolve(path));
62
+ }
63
+
64
+ write(path: string, data: string | Uint8Array): Promise<void> {
65
+ return projectFiles.write(this.resolve(path), data);
66
+ }
67
+
68
+ async writeIfAbsent(path: string, data: string | Uint8Array): Promise<boolean> {
69
+ if (await this.exists(path)) return false;
70
+ await this.write(path, data);
71
+ return true;
72
+ }
73
+
74
+ list(dir: string): Promise<DirEntry[]> {
75
+ return this.inner.list(dir);
76
+ }
77
+
78
+ stat(path: string): Promise<Stat | null> {
79
+ return this.inner.stat(path);
80
+ }
81
+
82
+ exists(path: string): Promise<boolean> {
83
+ return projectFiles.exists(this.resolve(path));
84
+ }
85
+
86
+ mkdir(path: string): Promise<void> {
87
+ return this.inner.mkdir(path);
88
+ }
89
+
90
+ remove(path: string): Promise<void> {
91
+ return this.inner.remove(path);
92
+ }
93
+
94
+ watch(callback: WatchCallback): () => void {
95
+ return this.inner.watch(callback);
96
+ }
97
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Server-backed `StorageBackend` for the local (Node) editor.
3
+ *
4
+ * A thin adapter over the editor server's existing routes — it changes nothing
5
+ * about how the local editor talks to disk, it just presents that surface behind
6
+ * the shared interface. The backend is rooted at the project's `public/` folder,
7
+ * matching the server's `/__editor/assets` (list) and `/__editor/save-file`
8
+ * (write) routes; reads come from Vite's `/@fs/` static serving.
9
+ *
10
+ * Route mapping (paths are relative to `public/`):
11
+ * list → GET /__editor/assets?dir → { entries: [{name,type,size,mtime}] }
12
+ * write → POST /__editor/save-file ({path, content, encoding?})
13
+ * read → GET /@fs/{projectRoot}/public/{path}
14
+ * watch → EventSource /__editor/events (chokidar-backed)
15
+ *
16
+ * The CLI control channel, native dialogs, `export`, online asset library, and
17
+ * project/editor-state persistence are NOT file operations and live outside this
18
+ * interface (see types.ts and editor-api.ts).
19
+ */
20
+
21
+ import { bytesToBase64 } from '@volter/sdk/kit/bytes-codec';
22
+ import { assertEditorServerAnswered, editorServerJson } from '@volter/sdk/kit/editor-server-response';
23
+ import { sourceMutationAttribution } from '@volter/sdk/kit/editor-session-attribution';
24
+ import { handleProjectMutationFailure } from '@volter/sdk/kit/source-conflict';
25
+ import { dirAndBase, normalize } from './paths';
26
+ import type { DirEntry, Stat, StorageBackend, WatchCallback, WatchEvent } from '@volter/sdk/kit/storage-types';
27
+
28
+ const BASE = '/__editor';
29
+
30
+ interface ServerAssetEntry {
31
+ name: string;
32
+ type: 'file' | 'directory';
33
+ size: number;
34
+ mtime: number;
35
+ }
36
+
37
+ export class HttpStorage implements StorageBackend {
38
+ readonly id = 'http';
39
+
40
+ /** Absolute project root on the server (used for /@fs reads). */
41
+ constructor(private readonly projectRoot: string) {}
42
+
43
+ async read(path: string): Promise<string> {
44
+ const res = await fetch(`/@fs/${this.projectRoot}/public/${normalize(path)}`);
45
+ if (!res.ok) throw new Error(`HttpStorage.read '${normalize(path)}': HTTP ${res.status}`);
46
+ return res.text();
47
+ }
48
+
49
+ async readBytes(path: string): Promise<Uint8Array> {
50
+ const res = await fetch(`/@fs/${this.projectRoot}/public/${normalize(path)}`);
51
+ if (!res.ok) throw new Error(`HttpStorage.readBytes '${normalize(path)}': HTTP ${res.status}`);
52
+ return new Uint8Array(await res.arrayBuffer());
53
+ }
54
+
55
+ async write(path: string, data: string | Uint8Array): Promise<void> {
56
+ const body =
57
+ typeof data === 'string'
58
+ ? { path: normalize(path), content: data, ...sourceMutationAttribution() }
59
+ : {
60
+ path: normalize(path),
61
+ content: bytesToBase64(data),
62
+ encoding: 'base64' as const,
63
+ ...sourceMutationAttribution(),
64
+ };
65
+ const res = await fetch(`${BASE}/save-file`, {
66
+ method: 'POST',
67
+ headers: { 'Content-Type': 'application/json' },
68
+ body: JSON.stringify(body),
69
+ });
70
+ // This is the AUTOSAVE path. `!res.ok` alone let a page fallback report
71
+ // every save as written, so the editor kept showing saved work that no
72
+ // server had ever received.
73
+ assertEditorServerAnswered(res, `Write ${normalize(path)} failed`);
74
+ if (!res.ok) {
75
+ await handleProjectMutationFailure(res, {
76
+ label: `Write ${normalize(path)}`,
77
+ attempted: {
78
+ [`public/${normalize(path)}`]:
79
+ typeof data === 'string' ? data : `[${data.byteLength} binary bytes]`,
80
+ },
81
+ reapply: () => this.write(path, data),
82
+ });
83
+ }
84
+ }
85
+
86
+ async writeIfAbsent(path: string, data: string | Uint8Array): Promise<boolean> {
87
+ // Browser adaptation never uses HttpStorage: the Node endpoint owns its
88
+ // true `wx` write. Keep the interface honest for generic callers.
89
+ if (await this.exists(path)) return false;
90
+ await this.write(path, data);
91
+ return true;
92
+ }
93
+
94
+ async list(dir: string): Promise<DirEntry[]> {
95
+ const res = await fetch(`${BASE}/assets?${new URLSearchParams({ dir: normalize(dir) })}`);
96
+ const { entries } = await editorServerJson<{ entries: ServerAssetEntry[] }>(
97
+ res,
98
+ `HttpStorage.list '${normalize(dir)}' failed`,
99
+ );
100
+ return entries.map((e) => {
101
+ const out: DirEntry = {
102
+ name: e.name,
103
+ path: normalize(dir ? `${dir}/${e.name}` : e.name),
104
+ type: e.type === 'directory' ? 'dir' : 'file',
105
+ mtime: e.mtime,
106
+ };
107
+ if (e.type === 'file') out.size = e.size;
108
+ out.mtime = e.mtime;
109
+ return out;
110
+ });
111
+ }
112
+
113
+ async stat(path: string): Promise<Stat | null> {
114
+ // The server exposes listings, not a per-path stat. Derive from the parent
115
+ // listing — sufficient for the editor's needs (existence + type + size).
116
+ const [dir, base] = dirAndBase(path);
117
+ if (!base) return { path: '', type: 'dir', size: 0, mtime: 0 };
118
+ let entries: DirEntry[];
119
+ try {
120
+ entries = await this.list(dir);
121
+ } catch {
122
+ return null;
123
+ }
124
+ const hit = entries.find((e) => e.name === base);
125
+ return hit
126
+ ? { path: hit.path, type: hit.type, size: hit.size ?? 0, mtime: hit.mtime ?? 0 }
127
+ : null;
128
+ }
129
+
130
+ async exists(path: string): Promise<boolean> {
131
+ return (await this.stat(path)) !== null;
132
+ }
133
+
134
+ async mkdir(path: string): Promise<void> {
135
+ // The server has no empty-dir route; directories materialize when their
136
+ // first file is written (save-file creates parents). No-op here.
137
+ void path;
138
+ }
139
+
140
+ async remove(path: string): Promise<void> {
141
+ const res = await fetch(`${BASE}/save-file`, {
142
+ method: 'POST',
143
+ headers: { 'Content-Type': 'application/json' },
144
+ body: JSON.stringify({ path: normalize(path), delete: true, ...sourceMutationAttribution() }),
145
+ });
146
+ assertEditorServerAnswered(res, `Delete ${normalize(path)} failed`);
147
+ if (!res.ok) {
148
+ await handleProjectMutationFailure(res, {
149
+ label: `Delete ${normalize(path)}`,
150
+ attempted: { [`public/${normalize(path)}`]: null },
151
+ reapply: () => this.remove(path),
152
+ });
153
+ }
154
+ }
155
+
156
+ watch(callback: WatchCallback): () => void {
157
+ const source = new EventSource(`${BASE}/events`);
158
+ const handler = (ev: MessageEvent) => {
159
+ try {
160
+ const data = JSON.parse(ev.data) as { type?: string; file?: string; path?: string };
161
+ const path = data.path ?? data.file;
162
+ if (!path) return;
163
+ callback({ type: (data.type as WatchEvent['type']) ?? 'update', path: normalize(path) });
164
+ } catch {
165
+ // Ignore non-JSON keepalive frames.
166
+ }
167
+ };
168
+ source.addEventListener('message', handler);
169
+ return () => {
170
+ source.removeEventListener('message', handler);
171
+ source.close();
172
+ };
173
+ }
174
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Storage backend selection — the `public/`-rooted file interface the editor's
3
+ * asset surfaces read and write through.
4
+ *
5
+ * ONE TIER, two implementations, and the second is a decorator:
6
+ * - `HttpStorage` — the session's own `/__editor/*` routes.
7
+ * - `HostFilesStorage` — the same view, written through `EditorHost.files`
8
+ * so a write is the WORKBENCH's own (U5).
9
+ * `MemStorage` is the design system's fixture backend and nothing else.
10
+ *
11
+ * Upstream code depends only on `StorageBackend` from `./types` and obtains
12
+ * an instance via `getStorageBackend()`.
13
+ */
14
+
15
+ import { getProjectDefinePath } from '../editor-mode';
16
+ import { filesProviderInstalled } from '../files/file-provider';
17
+ import { HostFilesStorage } from './host-files-storage';
18
+ import { HttpStorage } from './http-storage';
19
+ import type { StorageBackend } from '@volter/sdk/kit/storage-types';
20
+
21
+ export { HttpStorage } from './http-storage';
22
+ export { MemStorage } from './mem-storage';
23
+ export type { DirEntry, HostCapabilities, Stat, StorageBackend, WatchEvent } from '@volter/sdk/kit/storage-types';
24
+
25
+ let _backend: StorageBackend | null = null;
26
+ /** The tier's own backend, kept beside the active one so the frame decorator
27
+ * never becomes its own delegate — see {@link tierStorageBackend}. */
28
+ let _tier: StorageBackend | null = null;
29
+
30
+ /**
31
+ * THE TIER'S OWN backend — never the frame decorator, and the only thing the
32
+ * file door's host fill is allowed to stand on.
33
+ *
34
+ * Without this the fill would recurse: `projectFiles.read` falls back to
35
+ * `getStorageBackend()`, which under the frame is `HostFilesStorage`, whose
36
+ * `read` is `projectFiles.read`. One function, so the cycle cannot be written
37
+ * by accident.
38
+ */
39
+ export function tierStorageBackend(): StorageBackend {
40
+ if (_backend && !(_backend instanceof HostFilesStorage)) return _backend;
41
+ if (!_tier) _tier = new HttpStorage(getProjectDefinePath());
42
+ return _tier;
43
+ }
44
+
45
+ /**
46
+ * The active storage backend: the session's own, wrapped by the frame's file
47
+ * door once its provider has landed.
48
+ *
49
+ * UNDER THE CODE-OSS FRAME the file system is the WORKBENCH'S, not the
50
+ * session's (U5; ARCHITECTURE-CORE §The core is Code-OSS, "the storage
51
+ * backends → file system providers"). `HostFilesStorage` is the `public/`
52
+ * view onto `EditorHost.files`, so an asset write is the workbench's own write
53
+ * on the URI it already holds — the same property that closed U4's redo open
54
+ * for source files. Everything the file door does not carry (remove, mkdir,
55
+ * stat, list, watch) stays this tier's, which is why the decorator keeps it
56
+ * rather than replacing it.
57
+ *
58
+ * Read at FIRST USE rather than at module load: the bridge takes ownership
59
+ * before the editor mounts, but the provider arrives with the contribution's
60
+ * own services, after — see `files/file-provider.ts`.
61
+ */
62
+ export function getStorageBackend(): StorageBackend {
63
+ if (_backend) return _backend;
64
+ const tier = tierStorageBackend();
65
+ _backend = filesProviderInstalled() ? new HostFilesStorage(tier) : tier;
66
+ return _backend;
67
+ }
68
+
69
+ /** Override the active backend (the design system's fixture). */
70
+ export function setStorageBackend(backend: StorageBackend): void {
71
+ _backend = backend;
72
+ // An explicitly installed backend REPLACES the tier, so the file door's host
73
+ // fill stands on it too rather than on a stale one it would otherwise hold.
74
+ if (!(backend instanceof HostFilesStorage)) _tier = backend;
75
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Pure in-memory `StorageBackend` — a virtual filesystem backed by a `Map`.
3
+ *
4
+ * Nothing touches disk; files live as bytes in JS and vanish on reload. The
5
+ * most "virtual" of the backends, and the simplest — the design system's
6
+ * fixture (`design-system-stories/fixtures/editor-runtime.tsx`) is what uses
7
+ * it: a story needs a project-shaped backend and must write nothing.
8
+ *
9
+ * Implements the same interface as every other backend, so it is a drop-in via
10
+ * `setStorageBackend(new MemStorage())`.
11
+ */
12
+
13
+ import { dirAndBase, normalize } from './paths';
14
+ import type { DirEntry, Stat, StorageBackend, WatchCallback, WatchEvent } from '@volter/sdk/kit/storage-types';
15
+
16
+ type Node = { type: 'file'; data: Uint8Array; mtime: number } | { type: 'dir'; mtime: number };
17
+
18
+ export class MemStorage implements StorageBackend {
19
+ readonly id = 'mem';
20
+
21
+ /** Normalized path → node. The root (`''`) is implicit. */
22
+ private readonly nodes = new Map<string, Node>();
23
+ private readonly watchers = new Set<WatchCallback>();
24
+
25
+ /** Optionally seed the VFS from a `{ path: contents }` map. */
26
+ constructor(seed?: Record<string, string | Uint8Array>) {
27
+ if (seed) for (const [path, data] of Object.entries(seed)) this.writeSync(path, data);
28
+ }
29
+
30
+ private emit(event: WatchEvent): void {
31
+ for (const cb of this.watchers) cb(event);
32
+ }
33
+
34
+ /** Ensure every ancestor directory of `path` exists. */
35
+ private ensureParents(path: string): void {
36
+ const parts = normalize(path).split('/');
37
+ parts.pop();
38
+ let cur = '';
39
+ for (const part of parts) {
40
+ cur = cur ? `${cur}/${part}` : part;
41
+ if (this.nodes.get(cur)?.type !== 'dir') this.nodes.set(cur, { type: 'dir', mtime: now() });
42
+ }
43
+ }
44
+
45
+ private writeSync(path: string, data: string | Uint8Array): boolean {
46
+ const norm = normalize(path);
47
+ this.ensureParents(norm);
48
+ const existed = this.nodes.get(norm)?.type === 'file';
49
+ const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data);
50
+ this.nodes.set(norm, { type: 'file', data: bytes, mtime: now() });
51
+ return existed;
52
+ }
53
+
54
+ /**
55
+ * Put bytes in place WITHOUT announcing a change: a backend that fills itself lazily from
56
+ * somewhere else (the limited view's seed, `editor-core/view/page/project-store.ts`) is not
57
+ * editing the file when its first read arrives, so no watcher may hear it as one.
58
+ */
59
+ seed(path: string, data: string | Uint8Array): void {
60
+ this.writeSync(path, data);
61
+ }
62
+
63
+ async read(path: string): Promise<string> {
64
+ return new TextDecoder().decode(await this.readBytes(path));
65
+ }
66
+
67
+ async readBytes(path: string): Promise<Uint8Array> {
68
+ const node = this.nodes.get(normalize(path));
69
+ if (node?.type !== 'file')
70
+ throw new Error(`MemStorage.read: no such file '${normalize(path)}'`);
71
+ // Reads own their bytes, just like File/HTTP backends. Asset serving
72
+ // transfers this buffer to a worker; sharing the stored buffer would
73
+ // detach the file itself and break every subsequent read.
74
+ return node.data.slice();
75
+ }
76
+
77
+ async write(path: string, data: string | Uint8Array): Promise<void> {
78
+ const existed = this.writeSync(path, data);
79
+ this.emit({ type: existed ? 'update' : 'create', path: normalize(path) });
80
+ }
81
+
82
+ async writeIfAbsent(path: string, data: string | Uint8Array): Promise<boolean> {
83
+ if (await this.exists(path)) return false;
84
+ this.writeSync(path, data);
85
+ this.emit({ type: 'create', path: normalize(path) });
86
+ return true;
87
+ }
88
+
89
+ async list(dir: string): Promise<DirEntry[]> {
90
+ const dn = normalize(dir);
91
+ if (dn !== '' && this.nodes.get(dn)?.type !== 'dir') {
92
+ throw new Error(`MemStorage.list: no such directory '${dn}'`);
93
+ }
94
+ const entries: DirEntry[] = [];
95
+ for (const [path, node] of this.nodes) {
96
+ const [parent, base] = dirAndBase(path);
97
+ if (parent !== dn || !base) continue;
98
+ const entry: DirEntry = {
99
+ name: base,
100
+ path,
101
+ type: node.type === 'dir' ? 'dir' : 'file',
102
+ mtime: node.mtime,
103
+ };
104
+ if (node.type === 'file') entry.size = node.data.length;
105
+ entry.mtime = node.mtime;
106
+ entries.push(entry);
107
+ }
108
+ entries.sort((a, b) => {
109
+ if (a.type !== b.type) return a.type === 'dir' ? -1 : 1;
110
+ return a.name.localeCompare(b.name);
111
+ });
112
+ return entries;
113
+ }
114
+
115
+ async stat(path: string): Promise<Stat | null> {
116
+ const norm = normalize(path);
117
+ if (norm === '') return { path: '', type: 'dir', size: 0, mtime: 0 };
118
+ const node = this.nodes.get(norm);
119
+ if (!node) return null;
120
+ return node.type === 'file'
121
+ ? { path: norm, type: 'file', size: node.data.length, mtime: node.mtime }
122
+ : { path: norm, type: 'dir', size: 0, mtime: node.mtime };
123
+ }
124
+
125
+ async exists(path: string): Promise<boolean> {
126
+ return (await this.stat(path)) !== null;
127
+ }
128
+
129
+ async mkdir(path: string): Promise<void> {
130
+ const norm = normalize(path);
131
+ if (!norm || this.nodes.get(norm)?.type === 'dir') return;
132
+ this.ensureParents(norm);
133
+ this.nodes.set(norm, { type: 'dir', mtime: now() });
134
+ this.emit({ type: 'create', path: norm });
135
+ }
136
+
137
+ async remove(path: string): Promise<void> {
138
+ const norm = normalize(path);
139
+ if (!norm) return;
140
+ let removed = false;
141
+ for (const key of [...this.nodes.keys()]) {
142
+ if (key === norm || key.startsWith(`${norm}/`)) {
143
+ this.nodes.delete(key);
144
+ removed = true;
145
+ }
146
+ }
147
+ if (removed) this.emit({ type: 'remove', path: norm });
148
+ }
149
+
150
+ watch(callback: WatchCallback): () => void {
151
+ this.watchers.add(callback);
152
+ return () => this.watchers.delete(callback);
153
+ }
154
+ }
155
+
156
+ function now(): number {
157
+ return Date.now();
158
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The one cross-realm mutual exclusion a browser storage backend has:
3
+ * `navigator.locks`, keyed by backend id + path.
4
+ *
5
+ * Two callers matter and they MUST agree on the name, which is why this is a
6
+ * shared function rather than a string built at each site — and why the name is
7
+ * derived from the NORMALIZED path here rather than from whatever each caller
8
+ * happens to hold. Sharing the function is not enough on its own: one caller
9
+ * passes an already-normalized path and the other passes a module constant, so
10
+ * agreement used to rest on that constant being spelled in normalized form.
11
+ * Respell it as `/.volter/assets.json` and the two names diverge, both locks are
12
+ * "held", and mutual exclusion is silently gone with nothing failing. Deriving
13
+ * the name from `normalize()` makes the agreement structural.
14
+ *
15
+ * Callers:
16
+ * - the asset ledger's `.lock` compare-and-delete
17
+ * (`../asset-workflow/asset-ledger-backend.ts`) — several steps that must
18
+ * not interleave with each other OR with the create above.
19
+ *
20
+ * Scope, stated exactly: Web Locks span every same-origin realm — the two
21
+ * tabs on one project that motivate the ledger lock in the first place — and
22
+ * nothing else. A writer that is not same-origin JS (a Node process
23
+ * reaching the same files, i.e. `HttpStorage` racing the CLI) is not serialized
24
+ * by this, and cannot be from the browser side.
25
+ *
26
+ * Absent in a non-secure context and in Node (tests): callers then get the bare
27
+ * operation, which is the same exclusivity the platform itself offers.
28
+ */
29
+ import { normalize } from '@volter/sdk/kit/storage/paths';
30
+
31
+ export function withPathLock<T>(
32
+ backendId: string,
33
+ path: string,
34
+ operation: () => Promise<T>,
35
+ ): Promise<T> {
36
+ const locks = globalThis.navigator?.locks;
37
+ if (!locks) return operation();
38
+ // `LockManager.request`'s DOM typing infers its result from the callback's
39
+ // literal return type (`(lock) => T`), so an async callback types as
40
+ // `Promise<Promise<T>>`. The platform awaits the returned promise before
41
+ // releasing the lock — that flattening is the documented behavior, not an
42
+ // assumption — so the settled value really is `T`.
43
+ return locks.request(`volter:${backendId}:${normalize(path)}`, operation) as Promise<T>;
44
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Path helpers for storage backends. Paths are POSIX-style, root-relative,
3
+ * '/'-separated, with no leading/trailing slashes.
4
+ */
5
+
6
+ /** Split a path into non-empty segments, collapsing `.` and redundant slashes. */
7
+ export function segments(path: string): string[] {
8
+ return path.split('/').filter((s) => s.length > 0 && s !== '.');
9
+ }
10
+
11
+ /** Normalize to a canonical root-relative path (`''` for the root). */
12
+ export function normalize(path: string): string {
13
+ return segments(path).join('/');
14
+ }
15
+
16
+ /** Split into `[parentDir, baseName]`. Root entries have `parent === ''`. */
17
+ export function dirAndBase(path: string): [string, string] {
18
+ const segs = segments(path);
19
+ const base = segs.pop() ?? '';
20
+ return [segs.join('/'), base];
21
+ }
22
+
23
+ /** Join path parts into a normalized path. */
24
+ export function join(...parts: string[]): string {
25
+ return normalize(parts.join('/'));
26
+ }