@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,146 @@
1
+ /**
2
+ * Asset SELECTION state (W2) — the "single click selects" half of the selection-vs-open
3
+ * contract:
4
+ *
5
+ * - single click in the Project/Assets browser SELECTS the asset and shows
6
+ * compact preview/metadata in the Inspector (the registered
7
+ * `components/asset-selection-section.tsx` section reads this store);
8
+ * - double click / Enter OPENS the full viewer as a center document
9
+ * (`components/asset-documents.tsx`);
10
+ * - drag remains a placement gesture and never touches this store.
11
+ *
12
+ * A tiny module-scope store in the house `useSyncExternalStore` shape
13
+ * (mirrors `inspector-section-registry.ts`): version counter + subscribe +
14
+ * `__resetForTest`. It deliberately does NOT touch the EditorShellStore's entity
15
+ * selection — clicking an asset must never deselect/reselect scene entities
16
+ * (§6.1 "selection never unexpectedly..."); instead the Inspector gives the
17
+ * asset domain precedence while retaining that entity selection, and the asset is auto-cleared
18
+ * when the ENTITY selection changes (the user moved on — see
19
+ * `installAssetSelectionAutoClear`).
20
+ */
21
+
22
+ import type { AssetCapabilities } from '@volter/sdk/kit/asset-capabilities';
23
+
24
+ export type AssetKind = 'model' | 'image' | 'video' | 'audio' | 'json' | 'source';
25
+
26
+ export interface OnlineAssetInfo {
27
+ source: 'polyhaven' | 'ambientcg' | 'local';
28
+ id: string;
29
+ name: string;
30
+ thumbnailUrl: string;
31
+ type: string;
32
+ tags: string[];
33
+ license?: string;
34
+ author?: string;
35
+ sourceUrl?: string;
36
+ }
37
+
38
+ /** The §5.1 compact-selection payload — enough for the Inspector section to
39
+ * render preview + metadata without re-deriving browser state. */
40
+ export interface SelectedAsset {
41
+ /** Project serving path, or a stable `online:<source>:<id>` document key. */
42
+ readonly path: string;
43
+ /** Source-owned file name as authored (§8 — `crate.png`). */
44
+ readonly name: string;
45
+ readonly kind: AssetKind | 'component' | 'folder' | 'unknown';
46
+ /** Portable-CSF preview identity for a source-owned prefab/component. */
47
+ readonly componentPreview?: {
48
+ readonly surface: 'three' | 'canvas' | 'dom' | 'unknown';
49
+ readonly sourcePath: string;
50
+ };
51
+ /** File size in bytes when the browser knows it. */
52
+ readonly sizeBytes?: number;
53
+ readonly capabilities?: AssetCapabilities;
54
+ readonly health?: 'healthy' | 'source-only' | 'unsupported';
55
+ readonly sourcePath?: string;
56
+ readonly selectionCount?: number;
57
+ readonly selectionTotalBytes?: number;
58
+ readonly selectionFormats?: readonly string[];
59
+ readonly dependencies?: readonly string[];
60
+ readonly references?: readonly { ownerPath: string; jsonPath: string }[];
61
+ readonly healthCodes?: readonly string[];
62
+ /** Selection came from the external acquisition Library rather than the
63
+ * project's owned file tree. `online` carries the provider identity and is
64
+ * intentionally absent from project assets. */
65
+ readonly origin?: 'project' | 'library';
66
+ readonly online?: OnlineAssetInfo;
67
+ }
68
+
69
+ let _selected: SelectedAsset | null = null;
70
+ let _version = 0;
71
+ const _listeners = new Set<() => void>();
72
+
73
+ function notifyChanged(): void {
74
+ _version++;
75
+ for (const fn of _listeners) fn();
76
+ }
77
+
78
+ /** Subscribe to selection changes. Returns an unsubscribe function. */
79
+ export function subscribeAssetSelection(fn: () => void): () => void {
80
+ _listeners.add(fn);
81
+ return () => {
82
+ _listeners.delete(fn);
83
+ };
84
+ }
85
+
86
+ /** Monotonic change counter — the `getSnapshot` for `useSyncExternalStore`. */
87
+ export function assetSelectionVersion(): number {
88
+ return _version;
89
+ }
90
+
91
+ /** The currently selected asset, or `null`. */
92
+ export function getSelectedAsset(): SelectedAsset | null {
93
+ return _selected;
94
+ }
95
+
96
+ /** Select an asset (single-click). Idempotent on the same path. */
97
+ export function setSelectedAsset(asset: SelectedAsset): void {
98
+ if (_selected && JSON.stringify(_selected) === JSON.stringify(asset)) return;
99
+ _selected = asset;
100
+ notifyChanged();
101
+ }
102
+
103
+ /** Clear the asset selection (no-op when already clear). */
104
+ export function clearSelectedAsset(): void {
105
+ if (_selected === null) return;
106
+ _selected = null;
107
+ notifyChanged();
108
+ }
109
+
110
+ /** The narrow store surface the auto-clear needs (testable with a fake). */
111
+ export interface AssetSelectionAutoClearStore {
112
+ subscribe(listener: () => void): () => void;
113
+ readonly selectedEntityIds: ReadonlySet<string>;
114
+ }
115
+
116
+ function entitySelectionKey(store: AssetSelectionAutoClearStore): string {
117
+ return [...store.selectedEntityIds].sort().join('\n');
118
+ }
119
+
120
+ /**
121
+ * Auto-clear wiring (installed once per editor session by the layout): when
122
+ * the ENTITY selection changes while an asset is selected, the user has moved
123
+ * on — drop the asset selection so the Inspector goes back to being purely
124
+ * entity-contextual. The entity-selection snapshot is captured on every asset
125
+ * selection SET (not at install time), so only a change that happens AFTER
126
+ * the asset click clears it.
127
+ */
128
+ export function installAssetSelectionAutoClear(store: AssetSelectionAutoClearStore): () => void {
129
+ let snapshot = entitySelectionKey(store);
130
+ const unsubscribeSelf = subscribeAssetSelection(() => {
131
+ if (_selected) snapshot = entitySelectionKey(store);
132
+ });
133
+ const unsubscribeStore = store.subscribe(() => {
134
+ if (_selected && entitySelectionKey(store) !== snapshot) clearSelectedAsset();
135
+ });
136
+ return () => {
137
+ unsubscribeSelf();
138
+ unsubscribeStore();
139
+ };
140
+ }
141
+
142
+ /** Test-only reset (mirrors `__resetInspectorSectionRegistryForTest`). */
143
+ export function __resetAssetSelectionForTest(): void {
144
+ _selected = null;
145
+ notifyChanged();
146
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * ASSET THUMBNAILS BY THE MEDIUM THAT CAN DRAW THEM — a model file's picture is
3
+ * rendered offscreen by the integration that loads that format. The kit's asset
4
+ * browser asks here whether a file has a rendered thumbnail and queues the
5
+ * render; a file no renderer accepts keeps its icon.
6
+ */
7
+ export interface AssetThumbnailRenderer {
8
+ accepts(url: string): boolean;
9
+ /** A data URL of the file's picture. */
10
+ render(url: string): Promise<string>;
11
+ }
12
+
13
+ let renderers: readonly AssetThumbnailRenderer[] = [];
14
+
15
+ export function registerAssetThumbnailRenderer(renderer: AssetThumbnailRenderer): () => void {
16
+ renderers = [...renderers, renderer];
17
+ return () => {
18
+ renderers = renderers.filter((existing) => existing !== renderer);
19
+ };
20
+ }
21
+
22
+ /** The first registered renderer that draws `url`, or null. */
23
+ export function assetThumbnailRenderer(url: string): AssetThumbnailRenderer | null {
24
+ return renderers.find((renderer) => renderer.accepts(url)) ?? null;
25
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * ASSET VIEWERS BY ROUTE — the Asset Lab's native views for the formats a media
3
+ * integration renders (a model, an environment map, a LUT, a shader, a live
4
+ * modeling module, an entity's model). The kit's asset documents render the
5
+ * registered viewer for a route and their own fallback when none is: a
6
+ * composition with no three.js integration still opens the file, as text or as
7
+ * a file with no renderer. One registration per route; `useAssetViewer` re-renders
8
+ * when one arrives, so a document restored before its integration loaded
9
+ * upgrades in place.
10
+ */
11
+ import { type ComponentType, createElement, type ReactNode, useSyncExternalStore } from 'react';
12
+
13
+ export type AssetViewerRoute =
14
+ | 'model'
15
+ | 'environment'
16
+ | 'lut'
17
+ | 'shader'
18
+ | 'module'
19
+ | 'entity-model'
20
+ /** A compact live preview of a model file (an online asset's detail). */
21
+ | 'model-preview';
22
+
23
+ export interface AssetViewerProps {
24
+ readonly documentId: string;
25
+ /** The asset's project path; empty for an `entity-model`. */
26
+ readonly assetPath: string;
27
+ readonly displayName: string;
28
+ readonly active: boolean;
29
+ /** `entity-model`: the live entity whose model this is. */
30
+ readonly entityId?: string;
31
+ /** `module`: the project root the module is served from. */
32
+ readonly projectRoot?: string;
33
+ /** `model-preview`: a material file applied to the model. */
34
+ readonly materialPath?: string;
35
+ /** What to show when the viewer finds nothing it renders (a `module` that
36
+ * builds no Object3D). */
37
+ readonly fallback?: ReactNode;
38
+ }
39
+
40
+ const viewers = new Map<AssetViewerRoute, ComponentType<AssetViewerProps>>();
41
+ const listeners = new Set<() => void>();
42
+ let version = 0;
43
+
44
+ function changed(): void {
45
+ version += 1;
46
+ for (const listener of listeners) listener();
47
+ }
48
+
49
+ /** Register the viewer for one route. Returns the removal. */
50
+ export function registerAssetViewer(
51
+ route: AssetViewerRoute,
52
+ viewer: ComponentType<AssetViewerProps>,
53
+ ): () => void {
54
+ const existing = viewers.get(route);
55
+ if (existing && existing !== viewer) throw new Error(`An asset viewer for "${route}" is already registered.`);
56
+ viewers.set(route, viewer);
57
+ changed();
58
+ return () => {
59
+ if (viewers.get(route) !== viewer) return;
60
+ viewers.delete(route);
61
+ changed();
62
+ };
63
+ }
64
+
65
+ function subscribe(listener: () => void): () => void {
66
+ listeners.add(listener);
67
+ return () => listeners.delete(listener);
68
+ }
69
+
70
+ /** The registered viewer for `route`, or null; re-renders when one arrives. */
71
+ export function useAssetViewer(route: AssetViewerRoute): ComponentType<AssetViewerProps> | null {
72
+ useSyncExternalStore(subscribe, () => version, () => version);
73
+ return viewers.get(route) ?? null;
74
+ }
75
+
76
+ /** The registered viewer for `route` with `props`, or `whenUnregistered` when this
77
+ * composition registered none. `props.fallback` still reaches the viewer. */
78
+ export function AssetViewerSlot({
79
+ route,
80
+ whenUnregistered,
81
+ ...props
82
+ }: AssetViewerProps & { readonly route: AssetViewerRoute; readonly whenUnregistered: ReactNode }): ReactNode {
83
+ const Viewer = useAssetViewer(route);
84
+ return Viewer ? createElement(Viewer, props) : whenUnregistered;
85
+ }
86
+
87
+ /**
88
+ * A JSON FORMAT A MEDIUM RECOGNIZES BY ITS CONTENT — three.quarks writes plain
89
+ * Object3D JSON with no extension of its own, so only the file's structure can
90
+ * say it is a particle system. The kit's JSON document asks each registered
91
+ * recognizer in turn and shows the generic JSON viewer when none claims it.
92
+ */
93
+ export interface JsonContentViewer {
94
+ /** The parsed content this viewer renders, or null when it is not its format. */
95
+ recognize(assetPath: string, signal: AbortSignal): Promise<unknown | null>;
96
+ readonly Viewer: ComponentType<AssetViewerProps & { readonly content: unknown }>;
97
+ }
98
+
99
+ let jsonViewers: readonly JsonContentViewer[] = [];
100
+
101
+ export function registerJsonContentViewer(viewer: JsonContentViewer): () => void {
102
+ jsonViewers = [...jsonViewers, viewer];
103
+ changed();
104
+ return () => {
105
+ if (!jsonViewers.includes(viewer)) return;
106
+ jsonViewers = jsonViewers.filter((existing) => existing !== viewer);
107
+ changed();
108
+ };
109
+ }
110
+
111
+ /** The registered JSON recognizers, in registration order — a new array only
112
+ * when the set changes, so an effect keyed on it re-runs exactly then. */
113
+ export function useJsonContentViewers(): readonly JsonContentViewer[] {
114
+ return useSyncExternalStore(subscribe, () => jsonViewers, () => jsonViewers);
115
+ }
@@ -0,0 +1,106 @@
1
+ import { connectEvents } from '@volter/sdk/kit/editor-api';
2
+ import type { AssetImportStage } from './import-contract';
3
+
4
+ export interface AssetImportJob {
5
+ id: string;
6
+ label: string;
7
+ stage: AssetImportStage;
8
+ loaded: number;
9
+ total: number;
10
+ status: 'running' | 'imported' | 'skipped' | 'failed' | 'cancelled';
11
+ message?: string;
12
+ controller: AbortController;
13
+ retry?: () => void;
14
+ }
15
+
16
+ const jobs = new Map<string, AssetImportJob>();
17
+ const listeners = new Set<() => void>();
18
+ let version = 0;
19
+ function notify(): void {
20
+ version++;
21
+ for (const listener of listeners) listener();
22
+ }
23
+ export function assetImportJobsVersion(): number {
24
+ return version;
25
+ }
26
+ export function subscribeAssetImportJobs(listener: () => void): () => void {
27
+ listeners.add(listener);
28
+ return () => {
29
+ listeners.delete(listener);
30
+ };
31
+ }
32
+ export function assetImportJobs(): readonly AssetImportJob[] {
33
+ return [...jobs.values()];
34
+ }
35
+
36
+ export function beginAssetImportJob(id: string, label: string): AssetImportJob {
37
+ const existing = jobs.get(id);
38
+ if (existing?.status === 'running') return existing;
39
+ const job: AssetImportJob = {
40
+ id,
41
+ label,
42
+ stage: 'fetch',
43
+ loaded: 0,
44
+ total: 0,
45
+ status: 'running',
46
+ controller: new AbortController(),
47
+ };
48
+ jobs.set(id, job);
49
+ notify();
50
+ return job;
51
+ }
52
+ export function updateAssetImportJob(
53
+ id: string,
54
+ patch: Partial<Omit<AssetImportJob, 'id' | 'controller'>>,
55
+ ): void {
56
+ const job = jobs.get(id);
57
+ if (!job) return;
58
+ Object.assign(job, patch);
59
+ notify();
60
+ }
61
+ export function cancelAssetImportJob(id: string): void {
62
+ const job = jobs.get(id);
63
+ if (!job || job.status !== 'running') return;
64
+ job.controller.abort(new DOMException('Import cancelled', 'AbortError'));
65
+ job.status = 'cancelled';
66
+ job.message = 'Cancelled before project commit.';
67
+ notify();
68
+ }
69
+ export function clearFinishedAssetImportJobs(): void {
70
+ for (const [id, job] of jobs) if (job.status !== 'running') jobs.delete(id);
71
+ notify();
72
+ }
73
+ export function resetAssetImportJobs(): void {
74
+ jobs.clear();
75
+ notify();
76
+ }
77
+
78
+ /** Keep jobs progressing independently of whether the Library document is mounted. */
79
+ export function connectAssetImportProgressEvents(): () => void {
80
+ const source = connectEvents();
81
+ const listener = (event: MessageEvent) => {
82
+ try {
83
+ const update = JSON.parse(event.data as string) as {
84
+ jobId?: string;
85
+ stage?: AssetImportStage;
86
+ loaded?: number;
87
+ total?: number;
88
+ message?: string;
89
+ };
90
+ if (!update.jobId || !update.stage) return;
91
+ updateAssetImportJob(update.jobId, {
92
+ stage: update.stage,
93
+ loaded: Math.max(0, update.loaded ?? 0),
94
+ total: Math.max(0, update.total ?? 0),
95
+ ...(update.message ? { message: update.message } : {}),
96
+ });
97
+ } catch {
98
+ // Optional progress cannot break a running import.
99
+ }
100
+ };
101
+ source.addEventListener('asset-import-progress', listener);
102
+ return () => {
103
+ source.removeEventListener('asset-import-progress', listener);
104
+ source.close();
105
+ };
106
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * `StorageBackend` side of the asset provenance ledger (D-AP3) — the
3
+ * browser/isomorphic sibling of `packages/editor-core/server/asset-ledger-store.ts`,
4
+ * which reads/writes `.volter/assets.json` via `node:fs` for the local
5
+ * (HttpStorage-backed) Node editor. Every environment materializes through the
6
+ * SAME record shape (`../asset-workflow/asset-ledger.ts`'s pure schema) — only
7
+ * the I/O side differs, exactly like `storage/seed.ts`'s `readProjectManifest`
8
+ * reading `volter.project.json` through a `StorageBackend` instead of `node:fs`.
9
+ *
10
+ * Used by `hosted-asset-materialization.ts` (D-AP4 — a project's declared
11
+ * packs).
12
+ *
13
+ * Concurrency: the same two-half protection the Node side takes, over this
14
+ * side's I/O (see `./ledger-write-lock.ts`). The in-realm chain covers one tab
15
+ * — several declared entries materializing in one pass, the Library panel and a
16
+ * reopen retry overlapping — and the `.lock` file covers the case only another
17
+ * realm can see: two tabs open on the same project, both retrying their
18
+ * declared packs. `writeIfAbsent` is honest about not being O_EXCL on
19
+ * handle APIs (it "serializes same-origin writers and rechecks at handle
20
+ * acquisition"), which is exactly the guarantee that matters here — the racing
21
+ * writers ARE same-origin — so it is the strongest primitive available and not
22
+ * a claim of more.
23
+ */
24
+
25
+ import { withPathLock } from '../storage/path-lock';
26
+ import type { StorageBackend } from '@volter/sdk/kit/storage-types';
27
+ import {
28
+ ASSET_LEDGER_PATH,
29
+ type AssetLedger,
30
+ type AssetLedgerEntry,
31
+ normalizeLedgerPath,
32
+ parseAssetLedgerJson,
33
+ serializeAssetLedger,
34
+ sourceHashFromSha256,
35
+ upsertAssetLedgerEntry,
36
+ } from './asset-ledger';
37
+ import { createSerializer, withExclusiveLock } from './ledger-write-lock';
38
+
39
+ /** Read the ledger via `backend`. Absent → `{}`. Corrupt → throws (same
40
+ * contract as the Node `asset-ledger-store.ts` — a provenance record that
41
+ * silently drops entries is worse than no record). */
42
+ export async function readAssetLedgerFromBackend(backend: StorageBackend): Promise<AssetLedger> {
43
+ if (!(await backend.exists(ASSET_LEDGER_PATH))) return {};
44
+ return parseAssetLedgerJson(await backend.read(ASSET_LEDGER_PATH));
45
+ }
46
+
47
+ export async function writeAssetLedgerToBackend(
48
+ backend: StorageBackend,
49
+ ledger: AssetLedger,
50
+ ): Promise<void> {
51
+ await backend.write(ASSET_LEDGER_PATH, serializeAssetLedger(ledger));
52
+ }
53
+
54
+ export interface BackendMaterializationRecord {
55
+ /** Project-relative destination, e.g. `public/asset-library/local/x/y.glb`. */
56
+ readonly destPath: string;
57
+ /** `source:id` — the library's identity for this asset. */
58
+ readonly key: string;
59
+ /** License string as the library reported it, if it reported one. */
60
+ readonly license?: string | undefined;
61
+ /** The LIBRARY's sha256 of the source bytes. Omit when the library has
62
+ * none — never substitute a hash of the bytes just written (anti-shim). */
63
+ readonly sourceSha256?: string | undefined;
64
+ readonly materializedAt?: string;
65
+ }
66
+
67
+ const LEDGER_LOCK_PATH = `${ASSET_LEDGER_PATH}.lock`;
68
+ const serializeLedgerWrite = createSerializer();
69
+ /** Stable per-backend key for the in-realm chain (`backend.id` is shared by
70
+ * every instance of a backend TYPE, so it cannot key this on its own). */
71
+ const backendKeys = new WeakMap<StorageBackend, string>();
72
+ let nextBackendKey = 0;
73
+
74
+ function ledgerWriteKey(backend: StorageBackend): string {
75
+ const existing = backendKeys.get(backend);
76
+ if (existing !== undefined) return existing;
77
+ nextBackendKey += 1;
78
+ const key = `${backend.id}#${nextBackendKey}`;
79
+ backendKeys.set(backend, key);
80
+ return key;
81
+ }
82
+
83
+ /** Record one materialization in the project's ledger, via `backend`. */
84
+ export async function recordAssetMaterializationInBackend(
85
+ backend: StorageBackend,
86
+ record: BackendMaterializationRecord,
87
+ ): Promise<void> {
88
+ const entry: AssetLedgerEntry = {
89
+ key: record.key,
90
+ ...(record.license ? { license: record.license } : {}),
91
+ ...(record.sourceSha256 ? { sourceHash: sourceHashFromSha256(record.sourceSha256) } : {}),
92
+ materializedAt: record.materializedAt ?? new Date().toISOString(),
93
+ };
94
+ await serializeLedgerWrite(ledgerWriteKey(backend), () =>
95
+ withExclusiveLock(
96
+ {
97
+ createIfAbsent: (content) => backend.writeIfAbsent(LEDGER_LOCK_PATH, content),
98
+ read: async () =>
99
+ (await backend.exists(LEDGER_LOCK_PATH)) ? backend.read(LEDGER_LOCK_PATH) : null,
100
+ // Compare-and-delete (see `./ledger-write-lock.ts`'s `ExclusiveLockIO`),
101
+ // and its three steps must not interleave with another realm's — so
102
+ // they run under the SAME path lock `HandleStorage.writeIfAbsent` takes
103
+ // (`../storage/path-lock.ts`). That makes this side genuinely atomic
104
+ // against every same-origin tab, so it needs no `rename` takeover
105
+ // like the `node:fs` side.
106
+ // NOT covered: `HttpStorage`, whose peer writer is the Node server/CLI
107
+ // rather than another tab — Web Locks cannot reach a separate process,
108
+ // and neither can anything else available in the page.
109
+ removeIfHeldBy: (expected) =>
110
+ withPathLock(backend.id, LEDGER_LOCK_PATH, async () => {
111
+ if (!(await backend.exists(LEDGER_LOCK_PATH))) return;
112
+ if ((await backend.read(LEDGER_LOCK_PATH)) !== expected) return;
113
+ await backend.remove(LEDGER_LOCK_PATH);
114
+ }),
115
+ },
116
+ async () => {
117
+ const ledger = await readAssetLedgerFromBackend(backend);
118
+ await writeAssetLedgerToBackend(
119
+ backend,
120
+ upsertAssetLedgerEntry(ledger, normalizeLedgerPath(record.destPath), entry),
121
+ );
122
+ },
123
+ { owner: backend.id },
124
+ ),
125
+ );
126
+ }
@@ -0,0 +1,156 @@
1
+ /**
2
+ * The project-owned asset provenance ledger — `.volter/assets.json` (D-AP3).
3
+ *
4
+ * Assets follow the capability model: the asset library is the SOURCE, a
5
+ * project owns its COPIES. Every materialization — the editor's Library-panel
6
+ * download, the template/example `asset-packs:sync` script, the hosted seed —
7
+ * records the copy here, keyed by PROJECT-RELATIVE destination path.
8
+ *
9
+ * One ledger, not per-file sidecars: sidecars pollute asset directories and
10
+ * break tooling that globs them.
11
+ *
12
+ * The ledger is the license/attribution record and the drift input. Comparing a
13
+ * file's current hash to `sourceHash` distinguishes "the user edited their copy"
14
+ * (legitimate; git reports it) from "the library moved" (reported, never
15
+ * auto-applied — there is deliberately no `volter asset update`).
16
+ *
17
+ * ANTI-SHIM: `license` and `sourceHash` are OPTIONAL and are recorded only when
18
+ * the library actually supplied them. We never hash the bytes we just wrote and
19
+ * call the result a `sourceHash` — that would make every copy look pristine
20
+ * forever and destroy the drift signal the field exists for. A materialization
21
+ * path with no library-supplied hash records the key and the timestamp and
22
+ * nothing else. Today that is the polyhaven/ambientcg remote proxy, whose
23
+ * upstream APIs publish no per-file digest; the local/cloud catalog paths
24
+ * (34,412 assets) carry `sha256` and populate the field.
25
+ */
26
+
27
+ import { isContainedRelativePath } from '@volter/sdk/session/relative-path-guard';
28
+ import { z } from 'zod';
29
+
30
+ /** Project-relative location of the ledger. */
31
+ export const ASSET_LEDGER_PATH = '.volter/assets.json';
32
+
33
+ /** The library's asset identity: `source:id` (see `onlineAssetKey`). */
34
+ export function assetKey(source: string, id: string): string {
35
+ return `${source}:${id}`;
36
+ }
37
+
38
+ export const AssetLedgerEntrySchema = z
39
+ .object({
40
+ /** `source:id` — the library's own identity for the asset. */
41
+ key: z.string().min(1),
42
+ /** SPDX-ish license string as the library reported it, when it reported one. */
43
+ license: z.string().min(1).optional(),
44
+ /** The LIBRARY's digest of the source bytes — never a re-hash of our copy. */
45
+ sourceHash: z
46
+ .string()
47
+ .regex(/^sha256-[a-f0-9]{64}$/, 'sourceHash must be "sha256-<64 hex>"')
48
+ .optional(),
49
+ /** ISO-8601 instant the copy was written into this project. */
50
+ materializedAt: z.string().datetime(),
51
+ })
52
+ .strict();
53
+
54
+ export const AssetLedgerSchema = z.record(z.string().min(1), AssetLedgerEntrySchema);
55
+
56
+ export type AssetLedgerEntry = z.infer<typeof AssetLedgerEntrySchema>;
57
+ export type AssetLedger = Record<string, AssetLedgerEntry>;
58
+
59
+ /** Format a raw hex digest as the ledger's `sourceHash`. Rejects non-digests
60
+ * loudly rather than storing something that only looks like a hash. */
61
+ export function sourceHashFromSha256(sha256: string): string {
62
+ if (!/^[a-f0-9]{64}$/.test(sha256)) {
63
+ throw new Error(`Not a sha256 digest, refusing to record it as a sourceHash: ${sha256}`);
64
+ }
65
+ return `sha256-${sha256}`;
66
+ }
67
+
68
+ /** The raw hex digest inside a `sha256-…` sourceHash, or null for other forms. */
69
+ export function sha256FromSourceHash(sourceHash: string): string | null {
70
+ const match = /^sha256-([a-f0-9]{64})$/.exec(sourceHash);
71
+ return match?.[1] ?? null;
72
+ }
73
+
74
+ /** Normalize a ledger key: project-relative, forward slashes, no leading `./`. */
75
+ export function normalizeLedgerPath(path: string): string {
76
+ const normalized = path.replaceAll('\\', '/').replace(/^\.\//, '').replace(/^\/+/, '');
77
+ if (!normalized) throw new Error('An asset ledger path cannot be empty.');
78
+ if (!isContainedRelativePath(normalized)) {
79
+ throw new Error(`An asset ledger path cannot escape the project: ${path}`);
80
+ }
81
+ return normalized;
82
+ }
83
+
84
+ /** Parse a ledger document. Throws (loudly) on anything malformed — a
85
+ * provenance record that silently drops entries is worse than no record. */
86
+ export function parseAssetLedger(input: unknown): AssetLedger {
87
+ return AssetLedgerSchema.parse(input);
88
+ }
89
+
90
+ /** Parse ledger JSON text; an absent ledger is `{}`, a CORRUPT one throws. */
91
+ export function parseAssetLedgerJson(text: string | null | undefined): AssetLedger {
92
+ if (text == null || text.trim() === '') return {};
93
+ let parsed: unknown;
94
+ try {
95
+ parsed = JSON.parse(text);
96
+ } catch (cause) {
97
+ throw new Error(`${ASSET_LEDGER_PATH} is not valid JSON: ${String(cause)}`);
98
+ }
99
+ return parseAssetLedger(parsed);
100
+ }
101
+
102
+ /** Record one materialization. Pure: returns a new, key-sorted ledger. */
103
+ export function upsertAssetLedgerEntry(
104
+ ledger: AssetLedger,
105
+ destPath: string,
106
+ entry: AssetLedgerEntry,
107
+ ): AssetLedger {
108
+ const key = normalizeLedgerPath(destPath);
109
+ const validated = AssetLedgerEntrySchema.parse(entry);
110
+ const merged: AssetLedger = { ...ledger, [key]: validated };
111
+ const sorted: AssetLedger = {};
112
+ for (const path of Object.keys(merged).sort()) sorted[path] = merged[path]!;
113
+ return sorted;
114
+ }
115
+
116
+ /** Serialize for disk — stable key order, trailing newline. */
117
+ export function serializeAssetLedger(ledger: AssetLedger): string {
118
+ const sorted: AssetLedger = {};
119
+ for (const path of Object.keys(ledger).sort()) sorted[path] = ledger[path]!;
120
+ return `${JSON.stringify(sorted, null, 2)}\n`;
121
+ }
122
+
123
+ export type AssetLedgerDrift =
124
+ | { readonly status: 'untracked' }
125
+ | { readonly status: 'unknown-source-hash' }
126
+ | { readonly status: 'pristine' }
127
+ | {
128
+ readonly status: 'edited-locally';
129
+ readonly sourceHash: string;
130
+ readonly currentHash: string;
131
+ };
132
+
133
+ /**
134
+ * Classify one copy against its ledger entry. `currentHash` is the sha256 of
135
+ * the bytes on disk RIGHT NOW.
136
+ *
137
+ * This deliberately cannot tell "user edited" from "library moved" on its own —
138
+ * both show as a hash difference. The ledger supplies one half (what we copied);
139
+ * re-reading the library supplies the other. Callers that have not consulted the
140
+ * library must report `edited-locally` as "differs from what was materialized",
141
+ * never as "the library moved".
142
+ */
143
+ export function classifyAssetLedgerDrift(
144
+ ledger: AssetLedger,
145
+ destPath: string,
146
+ currentSha256: string,
147
+ ): AssetLedgerDrift {
148
+ const entry = ledger[normalizeLedgerPath(destPath)];
149
+ if (!entry) return { status: 'untracked' };
150
+ if (!entry.sourceHash) return { status: 'unknown-source-hash' };
151
+ const expected = sha256FromSourceHash(entry.sourceHash);
152
+ if (expected === null) return { status: 'unknown-source-hash' };
153
+ return expected === currentSha256
154
+ ? { status: 'pristine' }
155
+ : { status: 'edited-locally', sourceHash: expected, currentHash: currentSha256 };
156
+ }