@volter/sdk 0.0.0-stage → 0.5.203

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 +1166 -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 +317 -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 +403 -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,355 @@
1
+ /**
2
+ * Choosing, creating and OPENING a project — the New Project screen's client
3
+ * half, plus the runtime project switch.
4
+ *
5
+ * The user-triggered actions with no browser equivalent throw a clear, honest
6
+ * `Error` rather than doing a doomed fetch (`createProject`, `browseFolder`,
7
+ * `openProjectOnServer`, `revealInFinder`); the browser-mode UI either hides
8
+ * the affordance or catches the throw into an existing error banner.
9
+ */
10
+
11
+ import {
12
+ assertProjectCompatibility,
13
+ editorServerUnavailableError,
14
+ isStartupRecovery,
15
+ ProjectCompatibilityError,
16
+ } from '@volter/sdk/session/editor-compatibility';
17
+ import type { ProjectInspection } from '@volter/project/inspection';
18
+ import {
19
+ assertEditorServerAnswered,
20
+ assertEditorServerResponse,
21
+ editorServerJson,
22
+ } from '@volter/sdk/kit/editor-server-response';
23
+ import { BASE } from '@volter/sdk/kit/api-base';
24
+ import { requireEditorCompatibility } from '@volter/sdk/kit/api-project-identity';
25
+
26
+ /** One row of the launcher's recent-projects list. */
27
+ export interface RecentProject {
28
+ name: string;
29
+ path: string;
30
+ lastOpened: string;
31
+ thumbnail?: string;
32
+ }
33
+ /** List recently opened projects — the folders this machine's sessions have
34
+ * opened, tracked by the editor server. */
35
+ export async function listRecentProjects(): Promise<RecentProject[]> {
36
+ try {
37
+ const res = await fetch(`${BASE}/recent-projects`);
38
+ const data = await editorServerJson<{ projects: RecentProject[] }>(
39
+ res,
40
+ 'Could not list recent projects',
41
+ );
42
+ return data.projects;
43
+ } catch {
44
+ return [];
45
+ }
46
+ }
47
+
48
+ /** Forget one launcher entry without touching the project folder. */
49
+ export async function removeRecentProject(path: string): Promise<void> {
50
+ const response = await fetch(`${BASE}/recent-projects`, {
51
+ method: 'DELETE',
52
+ headers: { 'Content-Type': 'application/json' },
53
+ body: JSON.stringify({ path }),
54
+ });
55
+ assertEditorServerResponse(response, 'Could not remove recent project');
56
+ }
57
+
58
+ /** User-global launcher preferences (G5). */
59
+ export interface LauncherSettings {
60
+ reopenLastProject: boolean;
61
+ }
62
+
63
+ const DEFAULT_LAUNCHER_SETTINGS: LauncherSettings = { reopenLastProject: false };
64
+
65
+ /** Read the launcher preferences. Any failure degrades to the documented
66
+ * defaults — a preferences read must never be able to block boot. */
67
+ export async function getLauncherSettings(): Promise<LauncherSettings> {
68
+ try {
69
+ const res = await fetch(`${BASE}/launcher-settings`);
70
+ const data = await editorServerJson<Partial<LauncherSettings>>(
71
+ res,
72
+ 'Could not read launcher settings',
73
+ );
74
+ return {
75
+ reopenLastProject:
76
+ typeof data.reopenLastProject === 'boolean'
77
+ ? data.reopenLastProject
78
+ : DEFAULT_LAUNCHER_SETTINGS.reopenLastProject,
79
+ };
80
+ } catch {
81
+ return { ...DEFAULT_LAUNCHER_SETTINGS };
82
+ }
83
+ }
84
+
85
+ /** Persist a launcher preference. Unlike the read above this throws on
86
+ * failure: a toggle that silently does nothing would leave the checkbox
87
+ * lying about what happens at the next launch. */
88
+ export async function updateLauncherSettings(
89
+ update: Partial<LauncherSettings>,
90
+ ): Promise<LauncherSettings> {
91
+ const res = await fetch(`${BASE}/launcher-settings`, {
92
+ method: 'PUT',
93
+ headers: { 'Content-Type': 'application/json' },
94
+ body: JSON.stringify(update),
95
+ });
96
+ return await editorServerJson<LauncherSettings>(res, 'Could not save launcher settings');
97
+ }
98
+
99
+ /** Create a project from a registry source. The server validates the plain
100
+ * string against the scaffolder's live capability tuple. */
101
+ export async function createProject(
102
+ name: string,
103
+ location: string,
104
+ template: string,
105
+ exampleId?: string,
106
+ presentation?: string,
107
+ additions: readonly string[] = [],
108
+ ): Promise<{ ok: boolean; path?: string; config?: { name: string }; error?: string }> {
109
+ const res = await fetch(`${BASE}/create-project`, {
110
+ method: 'POST',
111
+ headers: { 'Content-Type': 'application/json' },
112
+ body: JSON.stringify({
113
+ name,
114
+ location,
115
+ template,
116
+ ...(exampleId ? { exampleId } : {}),
117
+ ...(presentation ? { presentation } : {}),
118
+ ...(additions.length > 0 ? { additions } : {}),
119
+ }),
120
+ });
121
+ // The route reports its own refusals in `{ ok: false, error }` with a non-2xx
122
+ // status, and the New Project form renders that string — so only the "did the
123
+ // editor server answer at all" half applies here.
124
+ assertEditorServerAnswered(res, 'Could not create the project');
125
+ return (await res.json()) as {
126
+ ok: boolean;
127
+ path?: string;
128
+ config?: { name: string };
129
+ error?: string;
130
+ };
131
+ }
132
+
133
+ /** Open a native folder picker dialog. Returns the selected path, or null if cancelled. */
134
+ export async function browseFolder(title?: string): Promise<string | null> {
135
+ try {
136
+ const res = await fetch(`${BASE}/browse-folder`, {
137
+ method: 'POST',
138
+ headers: { 'Content-Type': 'application/json' },
139
+ body: JSON.stringify({ title }),
140
+ });
141
+ const data = await editorServerJson<{ path: string | null }>(
142
+ res,
143
+ 'Could not open the folder picker',
144
+ );
145
+ return data.path;
146
+ } catch {
147
+ return null;
148
+ }
149
+ }
150
+
151
+ /** Inspect an arbitrary local folder without opening it or writing Volter files. */
152
+ export async function inspectProjectFolder(
153
+ path: string,
154
+ ): Promise<{ path: string; report: ProjectInspection }> {
155
+ const res = await fetch(`${BASE}/inspect-project`, {
156
+ method: 'POST',
157
+ headers: { 'Content-Type': 'application/json' },
158
+ body: JSON.stringify({ path }),
159
+ });
160
+ assertEditorServerAnswered(res, `Could not inspect ${path}`);
161
+ const payload = (await res.json()) as {
162
+ ok?: boolean;
163
+ path?: string;
164
+ report?: ProjectInspection;
165
+ error?: string;
166
+ };
167
+ if (!res.ok || !payload.path || !payload.report) {
168
+ throw new Error(payload.error ?? `Could not inspect ${path}.`);
169
+ }
170
+ return { path: payload.path, report: payload.report };
171
+ }
172
+
173
+ /** Add the one-file Volter metadata bridge after the user approves an inspection. */
174
+ export async function adaptProjectFolder(
175
+ path: string,
176
+ selection?: { surface?: ProjectInspection['suggestedSurface']; entry?: string },
177
+ ): Promise<{ path: string; writes: string[] }> {
178
+ const res = await fetch(`${BASE}/adapt-project`, {
179
+ method: 'POST',
180
+ headers: { 'Content-Type': 'application/json' },
181
+ body: JSON.stringify({ path, ...selection }),
182
+ });
183
+ assertEditorServerAnswered(res, `Could not add Volter Editor metadata to ${path}`);
184
+ const payload = (await res.json()) as { path?: string; writes?: string[]; error?: string };
185
+ if (!res.ok || !payload.path || !payload.writes) {
186
+ throw new Error(payload.error ?? `Could not add Volter Editor metadata to ${path}.`);
187
+ }
188
+ return { path: payload.path, writes: payload.writes };
189
+ }
190
+
191
+ /** Reveal a file or folder in the OS file manager. */
192
+ export async function revealInFinder(targetPath: string): Promise<void> {
193
+ const res = await fetch(`${BASE}/reveal`, {
194
+ method: 'POST',
195
+ headers: { 'Content-Type': 'application/json' },
196
+ body: JSON.stringify({ path: targetPath }),
197
+ });
198
+ // Every caller is a fire-and-forget menu action, so this rejection reaches
199
+ // the editor console through the page's `unhandledrejection` capture
200
+ // (`editor-console.ts`) — which is still a report, where the unread response
201
+ // was a file manager that never opened and nothing said so.
202
+ assertEditorServerResponse(res, `Could not reveal ${targetPath}`);
203
+ }
204
+
205
+ /** Save a viewport thumbnail for the current project — background bookkeeping
206
+ * for the recent-projects list, not a user-facing promise. */
207
+ export async function saveThumbnail(dataUrl: string): Promise<boolean> {
208
+ try {
209
+ const res = await fetch(`${BASE}/save-thumbnail`, {
210
+ method: 'POST',
211
+ headers: { 'Content-Type': 'application/json' },
212
+ body: JSON.stringify({ dataUrl }),
213
+ });
214
+ assertEditorServerResponse(res, 'Could not save the project thumbnail');
215
+ return true;
216
+ } catch {
217
+ return false;
218
+ }
219
+ }
220
+
221
+ export interface ServerProject {
222
+ path: string;
223
+ config: {
224
+ manifestVersion: 2;
225
+ name: string;
226
+ version: string;
227
+ engine: { version: string };
228
+ [key: string]: unknown;
229
+ };
230
+ /** Whether the project ships src/ui/registry.ts (scene-UI project mode, D9). */
231
+ hasUiRegistry?: boolean;
232
+ /** Whether this server is the no-monorepo-checkout packaged runtime
233
+ * (`packages/editor-core/server/packaged.ts`) — see `binding-resolver.ts`'s
234
+ * `isPackagedRuntime` for why a react world's mount needs this. */
235
+ packaged?: boolean;
236
+ /** The engine package resolved from this project's own node_modules graph. */
237
+ enginePackage?: {
238
+ name: '@volter/game-runtime';
239
+ version: string | null;
240
+ path: string;
241
+ installPath: string;
242
+ linked: boolean;
243
+ } | null;
244
+ }
245
+
246
+ /**
247
+ * What the server says it is serving — with the failures kept apart from the
248
+ * answer "nothing".
249
+ *
250
+ * `getCurrentServerProject` (below) flattens all three negatives to `null`,
251
+ * which is fine for a background read that only wants the happy path. It is
252
+ * NOT fine at boot: `null` there routes to the launcher, so a lost request or
253
+ * an unreadable manifest silently claimed the server had no project while it
254
+ * was serving one. See `boot-routing.ts`'s `decideServerProjectBoot`.
255
+ */
256
+ export type ServerProjectProbe =
257
+ | { status: 'project'; project: ServerProject }
258
+ | { status: 'none' }
259
+ /** Serving `path`, but the server could not describe it (broken manifest). */
260
+ | { status: 'unreadable'; path: string; error: string }
261
+ /** The ask itself failed — server down, mid-restart, malformed answer. */
262
+ | { status: 'unknown'; error: string };
263
+
264
+ interface ServerProjectResponse {
265
+ project: ServerProject | null;
266
+ serving?: { path?: unknown; error?: unknown } | null;
267
+ }
268
+
269
+ /** Ask the server what it serves, keeping the reason when it cannot say. */
270
+ export async function probeCurrentServerProject(): Promise<ServerProjectProbe> {
271
+ // Browser mode has no Node dev server to ask — same honest no-fetch
272
+ // degrade as the other background reads in this file.
273
+ let data: ServerProjectResponse;
274
+ try {
275
+ const res = await fetch(`${BASE}/project`);
276
+ data = await editorServerJson<ServerProjectResponse>(res, `No answer from ${BASE}/project`);
277
+ } catch (error) {
278
+ return {
279
+ status: 'unknown',
280
+ error: error instanceof Error ? error.message : String(error),
281
+ };
282
+ }
283
+ if (data.project) return { status: 'project', project: data.project };
284
+ const serving = data.serving;
285
+ if (serving && typeof serving.path === 'string') {
286
+ return {
287
+ status: 'unreadable',
288
+ path: serving.path,
289
+ error: typeof serving.error === 'string' ? serving.error : 'unknown error',
290
+ };
291
+ }
292
+ if (data.project === null) return { status: 'none' };
293
+ return { status: 'unknown', error: `Unrecognized ${BASE}/project response` };
294
+ }
295
+
296
+ /** Query the server for the currently active project (if any). Every failure
297
+ * reads as "no project" — see `probeCurrentServerProject` for the callers
298
+ * (boot) that must not make that trade. */
299
+ export async function getCurrentServerProject(): Promise<ServerProject | null> {
300
+ const probe = await probeCurrentServerProject();
301
+ return probe.status === 'project' ? probe.project : null;
302
+ }
303
+
304
+ /** Open/switch to a project by its filesystem path. */
305
+ export async function openProjectOnServer(projectPath: string): Promise<{
306
+ ok: boolean;
307
+ config?: {
308
+ manifestVersion: 2;
309
+ name: string;
310
+ version: string;
311
+ engine: { version: string };
312
+ [key: string]: unknown;
313
+ };
314
+ }> {
315
+ const compatibility = await requireEditorCompatibility();
316
+ const res = await fetch(`${BASE}/open-project`, {
317
+ method: 'POST',
318
+ headers: { 'Content-Type': 'application/json' },
319
+ body: JSON.stringify({ path: projectPath }),
320
+ });
321
+ let payload: unknown;
322
+ try {
323
+ // The fallback check goes INSIDE this try so a page-fallback answer reaches
324
+ // the same startup-recovery error class the parse failure already used —
325
+ // now naming the cause instead of "invalid response".
326
+ assertEditorServerAnswered(res, `Could not open project at ${projectPath}`);
327
+ payload = await res.json();
328
+ } catch (cause) {
329
+ throw editorServerUnavailableError(
330
+ cause instanceof Error ? cause.message : `HTTP ${res.status} returned an invalid response`,
331
+ );
332
+ }
333
+ if (!res.ok) {
334
+ if (payload && typeof payload === 'object') {
335
+ const failure = payload as Record<string, unknown>;
336
+ if (typeof failure['error'] === 'string' && isStartupRecovery(failure['recovery'])) {
337
+ throw new ProjectCompatibilityError(failure['error'], failure['recovery']);
338
+ }
339
+ if (typeof failure['error'] === 'string') throw new Error(failure['error']);
340
+ }
341
+ throw new Error(`Could not open project at ${projectPath}: HTTP ${res.status}`);
342
+ }
343
+ const result = payload as {
344
+ ok: boolean;
345
+ config?: {
346
+ manifestVersion: 2;
347
+ name: string;
348
+ version: string;
349
+ engine: { version: string };
350
+ [key: string]: unknown;
351
+ };
352
+ };
353
+ if (result.config) assertProjectCompatibility(result.config, compatibility);
354
+ return result;
355
+ }
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Reading and writing the project's own files.
3
+ *
4
+ * `public/` operations route through the backend-agnostic `StorageBackend`
5
+ * (`../storage`): `HttpStorage` over the same `/__editor/*` routes, wrapped by
6
+ * the frame's file door once its provider lands.
7
+ *
8
+ * The SPA-fallback check here is load-bearing: a dev server answers 200 with
9
+ * the editor's own `index.html` for a missing file, so "did I get the file"
10
+ * cannot be asked of the status code alone.
11
+ */
12
+
13
+ import { base64ToBytes } from '@volter/sdk/kit/bytes-codec';
14
+ import { servedUrl } from '../served-url';
15
+ import { getStorageBackend } from '../storage/index';
16
+
17
+ /**
18
+ * Read a project text file from the session that owns the project namespace.
19
+ *
20
+ * The storage backend is NOT the door here: `HttpStorage` is rooted at
21
+ * `public/`, not at the project root, so asking it for `src/...` produces a
22
+ * known-false asset-list 404 before the real Vite read. This goes directly to
23
+ * HTTP. Returns null when the file is not served.
24
+ */
25
+ export async function readProjectTextFile(path: string): Promise<string | null> {
26
+ try {
27
+ const res = await fetch(servedUrl(path));
28
+ if (res.ok) return await res.text();
29
+ } catch {
30
+ /* ignore */
31
+ }
32
+ return null;
33
+ }
34
+
35
+ /**
36
+ * A project source file as written, or null when it is absent or unreadable.
37
+ * The dev server serves `src/...` TRANSFORMED (imports rewritten to served
38
+ * paths), so a reader of the author's source asks `/__editor/source-file`.
39
+ */
40
+ export async function readProjectSourceText(path: string): Promise<string | null> {
41
+ try {
42
+ const res = await fetch(`/__editor/source-file?path=${encodeURIComponent(path.replace(/^\.?\//, ''))}`, {
43
+ cache: 'no-store',
44
+ });
45
+ if (res.ok) return await res.text();
46
+ } catch {
47
+ /* ignore */
48
+ }
49
+ return null;
50
+ }
51
+
52
+ /**
53
+ * What a probe can honestly conclude about a project file. THREE answers,
54
+ * because "no" and "I could not tell" are different facts and a boolean has
55
+ * to spend one of them.
56
+ */
57
+ export type ProjectFilePresence = 'present' | 'absent' | 'unreachable';
58
+
59
+ /**
60
+ * A 200 that is really the SPA FALLBACK, not the file.
61
+ *
62
+ * MEASURED, dev server, project root `public/ingest/cuberun/` (which owns no
63
+ * `editor/volter.adapter.ts`):
64
+ *
65
+ * curl -sI /editor/volter.adapter.ts -> 200, Content-Type: text/html (index.html)
66
+ * curl -sI /volter.project.json -> 200, Content-Type: application/json; charset=utf-8
67
+ *
68
+ * The fallback serves the editor's own `index.html`, so it is identifiable by
69
+ * the one thing it cannot hide: it is an HTML DOCUMENT. Nothing this probe is
70
+ * ever pointed at — a module, a manifest, an asset — is served as `text/html`,
71
+ * and the storage backend answers first for anything that could be.
72
+ *
73
+ * This shape is not dev-only: `docs/DEPLOY.md` §Surface 3 specifies serving
74
+ * `dist/` with an index.html fallback, i.e. "a missing asset returns
75
+ * `index.html`". Both shipped surfaces answer the same way.
76
+ */
77
+ function isSpaFallbackDocument(response: Response): boolean {
78
+ return (response.headers.get('content-type') ?? '').toLowerCase().includes('text/html');
79
+ }
80
+
81
+ /**
82
+ * Does this project file exist? — CONTENT-DISCRIMINATED, because on both
83
+ * surfaces this product ships an existence probe that trusts `res.ok` is a
84
+ * constant `true`.
85
+ *
86
+ * `HttpStorage` is deliberately rooted at
87
+ * `public/`, while this probe accepts project-root paths such as
88
+ * `src/prefabs/Player.tsx`; asking that backend first turns an ordinary source
89
+ * probe into a noisy `/__editor/assets?dir=src` 404. This therefore
90
+ * asks Vite directly with HEAD. Both routes remain existence-only — neither
91
+ * downloads the file body.
92
+ *
93
+ * The HTTP probe classifies rather than trusting `res.ok`:
94
+ *
95
+ * - not ok -> `absent` (a real 404 from a real route);
96
+ * - ok + `text/html` -> `absent` — {@link isSpaFallbackDocument}, the
97
+ * measured false positive;
98
+ * - ok, anything else -> `present` (a real file answering with its own
99
+ * content type);
100
+ * - the fetch throws -> `unreachable`. NOT `absent`: an unanswered probe is
101
+ * a fact about the transport, and a caller that must not act on a guess
102
+ * (see `project-adapter.ts`, which chooses a BINDING TABLE off this) is
103
+ * entitled to know the difference.
104
+ *
105
+ * This function's earlier docblock already recorded the false positive —
106
+ * "the dev server's SPA fallback also answers a HEAD/GET for a MISSING path
107
+ * with 200 (it serves `index.html` rather than 404), so `res.ok` alone cannot
108
+ * fully distinguish 'exists' from 'missing'" — and dismissed it as harmless
109
+ * because "a false positive here just means a subsequent real open attempt
110
+ * fails through its own error path". That held for the then-only caller
111
+ * (`workspace-state-persistence`, probing `public/`-rooted asset paths the
112
+ * storage backend answers authoritatively). It stopped holding the moment a
113
+ * project-ROOT path was probed AHEAD of a branch that would otherwise have
114
+ * succeeded: the "own error path" then reports a load failure for a file the
115
+ * project never had, and the real binding is never reached. The discrimination
116
+ * lives HERE, inside the probe, so the next caller cannot re-inherit the blind
117
+ * question.
118
+ */
119
+ export async function probeProjectFile(path: string): Promise<ProjectFilePresence> {
120
+ // Ask the origin; the fallback detector below keeps a SPA 200 from counting
121
+ // as the file.
122
+ try {
123
+ const res = await fetch(servedUrl(path), { method: 'HEAD' });
124
+ if (!res.ok) return 'absent';
125
+ return isSpaFallbackDocument(res) ? 'absent' : 'present';
126
+ } catch {
127
+ return 'unreachable';
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Check whether a project file exists WITHOUT reading its content — the
133
+ * boolean face of {@link probeProjectFile}, for callers with nothing to do
134
+ * about the difference between "no" and "could not tell". Prefer this over
135
+ * `readProjectTextFile(...) !== null` when only existence is needed, since
136
+ * that reads and discards the whole body.
137
+ */
138
+ export async function projectFileExists(path: string): Promise<boolean> {
139
+ return (await probeProjectFile(path)) === 'present';
140
+ }
141
+
142
+ /** Save a file to public/. Returns true on success. */
143
+ export async function saveFile(
144
+ path: string,
145
+ content: string,
146
+ encoding?: 'base64',
147
+ ): Promise<boolean> {
148
+ try {
149
+ // base64 content → raw bytes; the backend re-encodes per its transport.
150
+ // `base64ToBytes` is a LOOP; `Uint8Array.from(atob(…), (c) => …)` calls the
151
+ // mapping callback once per CHARACTER (measured 27.7x slower at 3MB).
152
+ const data: string | Uint8Array = encoding === 'base64' ? base64ToBytes(content) : content;
153
+ await getStorageBackend().write(path, data);
154
+ return true;
155
+ } catch {
156
+ return false;
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Project-relative source files matching `globs` (`src/models/**\/*.ts`; `*`
162
+ * within a segment, `**` across segments) — what a finder's `include`
163
+ * reads through (`FinderInput.sources`), answered by the session's
164
+ * `/__editor/source-files` route.
165
+ */
166
+ export async function listProjectSourceFiles(
167
+ globs: readonly string[],
168
+ options: { readonly order?: 'name' | 'mtime' } = {},
169
+ ): Promise<string[]> {
170
+ if (globs.length === 0) return [];
171
+ const res = await fetch(
172
+ `/__editor/source-files?${new URLSearchParams([
173
+ ...globs.map((g): [string, string] => ['include', g]),
174
+ ...(options.order === 'mtime' ? [['order', 'mtime'] as [string, string]] : []),
175
+ ])}`,
176
+ );
177
+ if (!res.ok) return [];
178
+ const body = (await res.json()) as { files?: string[] };
179
+ return body.files ?? [];
180
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * What the session currently IS, as the editor's own UI reads it: the server
3
+ * validation log, the editor lease identity, and the durable
4
+ * `.volter/editor-state.json` view/tool state.
5
+ *
6
+ */
7
+
8
+ import type { LeasePollResult } from '../editor-lease';
9
+ import { assertEditorServerResponse, editorServerJson } from '@volter/sdk/kit/editor-server-response';
10
+ import { postJson } from '@volter/sdk/kit/user-local-state';
11
+ import { BASE } from '@volter/sdk/kit/api-base';
12
+ /**
13
+ * PD-13: the validation failures and authoring warnings the dev server knows
14
+ * about RIGHT NOW, pre-formatted as `server-log` payloads. `editor-console.ts`
15
+ * pulls this once per connection to render what the live broadcast could not
16
+ * deliver — see `connectServerLogs` for why a pull rather than a push. THROWS
17
+ * on any failure, including a server that predates the endpoint and an origin
18
+ * whose page fallback answered instead; the one caller treats a failed replay
19
+ * as "nothing to replay" and says why.
20
+ */
21
+ export async function getServerValidationLog(): Promise<{ level: string; message: string }[]> {
22
+ const res = await fetch(`${BASE}/validation-log`);
23
+ const data = await editorServerJson<{ entries?: { level: string; message: string }[] }>(
24
+ res,
25
+ 'Could not read the server validation log',
26
+ );
27
+ return data.entries ?? [];
28
+ }
29
+
30
+ /**
31
+ * One liveness poll for the editor-lease watchdog (editor-lease.ts): ask the
32
+ * server on THIS tab's origin who it is. Reuses the same `/__editor/project`
33
+ * identity endpoint the CLI probes (`session.pid` + the served project path) —
34
+ * a replaced server on the same port answers with a new pid, which is how the
35
+ * watchdog detects a takeover.
36
+ *
37
+ * `ok: false` is any reason the reading is unusable — connection refused (the
38
+ * server is gone), a non-OK status, a timeout, or a malformed body — folded
39
+ * into one "failed poll" the reducer counts toward `server-gone`. The timeout
40
+ * is short: this runs every few seconds and a hung request should read as a
41
+ * failure, not stall the poll.
42
+ */
43
+ export async function pollEditorLeaseIdentity(timeoutMs = 3000): Promise<LeasePollResult> {
44
+ // Static transports report a page-owned lease; process-backed sessions keep
45
+ // reporting their server identity, including older servers without a lease field.
46
+ if (typeof fetch === 'undefined') return { ok: false };
47
+ try {
48
+ const res = await fetch(`${BASE}/project`, { signal: AbortSignal.timeout(timeoutMs) });
49
+ const body = await editorServerJson<{
50
+ project?: { path?: unknown } | null;
51
+ session?: { pid?: unknown; lease?: unknown } | null;
52
+ }>(res, 'Editor lease poll failed');
53
+ return {
54
+ ok: true,
55
+ ...(body.session?.lease === 'page' ? { lease: 'page' as const } : {}),
56
+ identity: {
57
+ project: typeof body.project?.path === 'string' ? body.project.path : null,
58
+ pid: typeof body.session?.pid === 'number' ? body.session.pid : null,
59
+ },
60
+ };
61
+ } catch {
62
+ return { ok: false };
63
+ }
64
+ }
65
+
66
+ // ---------------------------------------------------------------------------
67
+ // Persistent editor state (.volter/editor-state.json)
68
+ // ---------------------------------------------------------------------------
69
+
70
+ /** Load persisted editor state (remembered transform mode/snap/last
71
+ * scene/camera). Returns {} if none exists. */
72
+ export async function loadEditorState(): Promise<Record<string, unknown>> {
73
+ try {
74
+ const res = await fetch(`${BASE}/editor-state`);
75
+ return await editorServerJson<Record<string, unknown>>(res, 'Could not read editor state');
76
+ } catch {
77
+ return {};
78
+ }
79
+ }
80
+
81
+ /** Set once the write below has reported a failure, so an autosave that fires
82
+ * on every viewport change reports a permanently broken origin ONCE. */
83
+ let reportedEditorStateWriteFailure = false;
84
+
85
+ /** Save editor state (persisted in .volter/editor-state.json — see
86
+ * `loadEditorState`'s doc comment for the browser-mode routing).
87
+ *
88
+ * The boolean is this function's only channel and its one caller
89
+ * (`editor-shell-store.savePersistentState`) discards it, so the failure is
90
+ * ALSO logged: `res.ok` used to read a page fallback as a completed write,
91
+ * and a silent false would be the same lie one indirection later. */
92
+ export async function saveEditorState(
93
+ state: Record<string, unknown>,
94
+ options: { readonly leaving?: boolean } = {},
95
+ ): Promise<boolean> {
96
+ try {
97
+ // A page going away cancels its requests unless they are kept alive (`postJson` says within
98
+ // what bound).
99
+ const res = await postJson(`${BASE}/editor-state`, JSON.stringify(state), options.leaving === true);
100
+ assertEditorServerResponse(res, 'Could not save editor state');
101
+ return true;
102
+ } catch (cause) {
103
+ if (!reportedEditorStateWriteFailure) {
104
+ reportedEditorStateWriteFailure = true;
105
+ // biome-ignore lint/suspicious/noConsole: the editor console captures console.error session-wide — this IS the report channel for a caller that discards the boolean.
106
+ console.error(cause instanceof Error ? cause.message : String(cause));
107
+ }
108
+ return false;
109
+ }
110
+ }