@volter/editor-core 0.5.57

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 (719) hide show
  1. package/BUNDLED_NOTICES +1527 -0
  2. package/LICENSE +686 -0
  3. package/LICENSE-APACHE +202 -0
  4. package/NOTICE +18 -0
  5. package/README.md +24 -0
  6. package/dist/build/chunk-JS4D4XZ3.js +175 -0
  7. package/dist/build/chunk-JS4D4XZ3.js.map +7 -0
  8. package/dist/build/vite-plugin-product-contributions.js +100 -0
  9. package/dist/build/vite-plugin-product-contributions.js.map +7 -0
  10. package/dist/build/vite-plugin-shared-react.js +25 -0
  11. package/dist/build/vite-plugin-shared-react.js.map +7 -0
  12. package/dist/build/vite-plugin-shared-three.js +86 -0
  13. package/dist/build/vite-plugin-shared-three.js.map +7 -0
  14. package/dist/server/chunk-KMJC7AGO.js +98 -0
  15. package/dist/server/chunk-KMJC7AGO.js.map +7 -0
  16. package/dist/server/chunk-PSILUMGS.js +46 -0
  17. package/dist/server/chunk-PSILUMGS.js.map +7 -0
  18. package/dist/server/frame-proxy.js +255 -0
  19. package/dist/server/frame-proxy.js.map +7 -0
  20. package/dist/server/open-browser.js +53 -0
  21. package/dist/server/open-browser.js.map +7 -0
  22. package/dist/server/process-shutdown.js +127 -0
  23. package/dist/server/process-shutdown.js.map +7 -0
  24. package/dist/server/session-registry.js +141 -0
  25. package/dist/server/session-registry.js.map +7 -0
  26. package/dist/server/spawn-opener.js +11 -0
  27. package/dist/server/spawn-opener.js.map +7 -0
  28. package/dist/server/worktree-identity.js +11 -0
  29. package/dist/server/worktree-identity.js.map +7 -0
  30. package/dist-server/packaged.mjs +88816 -0
  31. package/package.json +118 -0
  32. package/scripts/build-plugins.mjs +14 -0
  33. package/scripts/build-server.mjs +26 -0
  34. package/scripts/build-session.mjs +9 -0
  35. package/server/account-credentials.ts +60 -0
  36. package/server/account-service.ts +1434 -0
  37. package/server/adapter-region-includes.ts +47 -0
  38. package/server/asset-catalog-v2.ts +175 -0
  39. package/server/asset-history-snapshots.ts +196 -0
  40. package/server/asset-ledger-store.ts +195 -0
  41. package/server/asset-library-routes.ts +1595 -0
  42. package/server/blender-wasm-artifact.ts +430 -0
  43. package/server/boot-timings.ts +106 -0
  44. package/server/canonical-path.ts +50 -0
  45. package/server/checkout-workspace-preflight.ts +349 -0
  46. package/server/cloud-asset-catalog.ts +158 -0
  47. package/server/coding-inference-launch.ts +237 -0
  48. package/server/collaboration-account-client.ts +202 -0
  49. package/server/collaboration-attribution.ts +122 -0
  50. package/server/collaboration-session.ts +934 -0
  51. package/server/comfyui-bridge.ts +248 -0
  52. package/server/console-ledger.ts +499 -0
  53. package/server/creation-site-transform.ts +304 -0
  54. package/server/creation-site-write.ts +648 -0
  55. package/server/data-file-serialize.ts +158 -0
  56. package/server/editor-brand-html.ts +72 -0
  57. package/server/editor-control-socket.ts +366 -0
  58. package/server/editor-server-options.ts +190 -0
  59. package/server/editor-server.ts +1483 -0
  60. package/server/editor-sse.ts +352 -0
  61. package/server/engine-provenance.ts +169 -0
  62. package/server/engine-source-restart.ts +117 -0
  63. package/server/frame-bridge.ts +115 -0
  64. package/server/frame-proxy.ts +490 -0
  65. package/server/frame-workbench.ts +259 -0
  66. package/server/frontend-handoff.ts +229 -0
  67. package/server/game-globals-shadow.ts +113 -0
  68. package/server/gameplay-session-retention.ts +149 -0
  69. package/server/gameplay-sessions.ts +123 -0
  70. package/server/generation-jobs.ts +201 -0
  71. package/server/generation-reconciler.ts +137 -0
  72. package/server/generative-execution-context.ts +59 -0
  73. package/server/git-workflow.ts +612 -0
  74. package/server/harness-chat-caller.ts +36 -0
  75. package/server/harness-chat-service.ts +1681 -0
  76. package/server/idle-shutdown.ts +170 -0
  77. package/server/js-profiling-policy.ts +52 -0
  78. package/server/launcher-settings.ts +84 -0
  79. package/server/local-asset-catalog.ts +410 -0
  80. package/server/managed-account-defaults.ts +22 -0
  81. package/server/mock-control-plane.ts +540 -0
  82. package/server/model-import-conversion.ts +345 -0
  83. package/server/native-credential-store.ts +162 -0
  84. package/server/open-browser.ts +118 -0
  85. package/server/packaged.ts +1192 -0
  86. package/server/play-stall.ts +126 -0
  87. package/server/process-shutdown.ts +218 -0
  88. package/server/product-presets.ts +55 -0
  89. package/server/project-build-artifact.ts +95 -0
  90. package/server/project-components.ts +100 -0
  91. package/server/project-dependency-invalidation.ts +114 -0
  92. package/server/project-file-scan.ts +235 -0
  93. package/server/project-hmr-files.ts +215 -0
  94. package/server/project-install-roots.ts +210 -0
  95. package/server/project-kinds.ts +71 -0
  96. package/server/project-mcp-servers.ts +82 -0
  97. package/server/project-module-freshness.ts +109 -0
  98. package/server/project-module-instance.ts +375 -0
  99. package/server/project-optimize-deps-entries.ts +827 -0
  100. package/server/project-output-writer.ts +679 -0
  101. package/server/project-package-origin.ts +63 -0
  102. package/server/project-root-surface.ts +831 -0
  103. package/server/project-scratch-path.ts +47 -0
  104. package/server/project-script-hmr.ts +619 -0
  105. package/server/project-serving-plugins.ts +236 -0
  106. package/server/project-tools.ts +653 -0
  107. package/server/project-validation.ts +250 -0
  108. package/server/project-verbs.ts +127 -0
  109. package/server/project-view.ts +52 -0
  110. package/server/project-watch.ts +1134 -0
  111. package/server/project-work-coordinator.ts +288 -0
  112. package/server/provider-credentials.ts +331 -0
  113. package/server/recent-projects-store.ts +98 -0
  114. package/server/redact-secrets.ts +71 -0
  115. package/server/repository-presence.ts +267 -0
  116. package/server/routes/account.ts +357 -0
  117. package/server/routes/agents.ts +60 -0
  118. package/server/routes/assets.ts +154 -0
  119. package/server/routes/build.ts +13 -0
  120. package/server/routes/collaboration.ts +595 -0
  121. package/server/routes/configurations.ts +419 -0
  122. package/server/routes/context.ts +264 -0
  123. package/server/routes/control-plane.ts +1811 -0
  124. package/server/routes/logs.ts +272 -0
  125. package/server/routes/project-identity.ts +302 -0
  126. package/server/routes/project-open.ts +429 -0
  127. package/server/routes/project-source.ts +686 -0
  128. package/server/routes/project-state.ts +383 -0
  129. package/server/routes/relay.ts +1029 -0
  130. package/server/routes/route-helpers.ts +29 -0
  131. package/server/routes/served-modules.ts +138 -0
  132. package/server/routes/session-tabs.ts +196 -0
  133. package/server/routes/settings.ts +121 -0
  134. package/server/routes/share-control.ts +486 -0
  135. package/server/routes/themes.ts +116 -0
  136. package/server/routes/tools.ts +230 -0
  137. package/server/routes/worktrees.ts +595 -0
  138. package/server/scoped-game-css.ts +461 -0
  139. package/server/server-utils.ts +1194 -0
  140. package/server/session-product.ts +112 -0
  141. package/server/session-registry.ts +230 -0
  142. package/server/share-claims.ts +138 -0
  143. package/server/share-host.ts +526 -0
  144. package/server/share-session-gateway.ts +1362 -0
  145. package/server/share-tunnel.ts +123 -0
  146. package/server/spawn-opener.ts +74 -0
  147. package/server/support/play/log-format.ts +76 -0
  148. package/server/support/play/session-record.ts +199 -0
  149. package/server/support/project/build-discipline.ts +718 -0
  150. package/server/support/project/inspection-node.ts +119 -0
  151. package/server/support/project/log-naming.ts +54 -0
  152. package/server/support/project/provenance.ts +290 -0
  153. package/server/support/project/run-name.ts +18 -0
  154. package/server/support/project/session-journal.ts +830 -0
  155. package/server/support/project/shared.ts +327 -0
  156. package/server/tab-bootstrap.ts +62 -0
  157. package/server/tab-heartbeat.ts +477 -0
  158. package/server/tab-lifecycle.ts +550 -0
  159. package/server/tab-presence.ts +1508 -0
  160. package/server/team-agent-mirror.ts +95 -0
  161. package/server/twin-auth.ts +138 -0
  162. package/server/vendored-lock-recorder.ts +968 -0
  163. package/server/worktree-identity.ts +121 -0
  164. package/server/worktree-management.ts +398 -0
  165. package/server/worktree-retention.d.mts +13 -0
  166. package/server/worktree-retention.mjs +205 -0
  167. package/src/EditorContext.tsx +169 -0
  168. package/src/account.ts +333 -0
  169. package/src/action-registry.ts +532 -0
  170. package/src/active-product.ts +74 -0
  171. package/src/active-project.ts +155 -0
  172. package/src/adapter-editor-config.ts +25 -0
  173. package/src/adapter-observation.ts +49 -0
  174. package/src/animation/stage-transport.ts +379 -0
  175. package/src/animation/three-clips-subject.ts +172 -0
  176. package/src/api/asset-library-wire.ts +45 -0
  177. package/src/api/assets.ts +365 -0
  178. package/src/api/base.ts +10 -0
  179. package/src/api/build.ts +99 -0
  180. package/src/api/git-wire.ts +56 -0
  181. package/src/api/logs.ts +92 -0
  182. package/src/api/project-identity.ts +74 -0
  183. package/src/api/project-open.ts +355 -0
  184. package/src/api/project-source.ts +162 -0
  185. package/src/api/project-state.ts +107 -0
  186. package/src/api/relay.ts +268 -0
  187. package/src/api/settings.ts +36 -0
  188. package/src/api/themes.ts +45 -0
  189. package/src/api/worktrees.ts +257 -0
  190. package/src/asset-compare-core.ts +171 -0
  191. package/src/asset-compare.ts +294 -0
  192. package/src/asset-editor-context.tsx +100 -0
  193. package/src/asset-events.ts +97 -0
  194. package/src/asset-inspector-actions.ts +87 -0
  195. package/src/asset-preview-framing.ts +357 -0
  196. package/src/asset-preview.ts +2802 -0
  197. package/src/asset-selection-viewer-registry.ts +113 -0
  198. package/src/asset-selection.ts +133 -0
  199. package/src/asset-workflow/asset-capabilities.ts +344 -0
  200. package/src/asset-workflow/asset-import-jobs.ts +106 -0
  201. package/src/asset-workflow/asset-ledger-backend.ts +126 -0
  202. package/src/asset-workflow/asset-ledger.ts +156 -0
  203. package/src/asset-workflow/asset-materialization-report.ts +140 -0
  204. package/src/asset-workflow/asset-pack-manifest.ts +320 -0
  205. package/src/asset-workflow/asset-types.ts +142 -0
  206. package/src/asset-workflow/asset-workflow-quality.ts +61 -0
  207. package/src/asset-workflow/audio-preview-player.ts +193 -0
  208. package/src/asset-workflow/audio-waveform.ts +22 -0
  209. package/src/asset-workflow/cloud-asset-client.ts +263 -0
  210. package/src/asset-workflow/folder-preview.ts +345 -0
  211. package/src/asset-workflow/hosted-asset-materialization.ts +236 -0
  212. package/src/asset-workflow/image-view-scale.ts +32 -0
  213. package/src/asset-workflow/import-contract.ts +124 -0
  214. package/src/asset-workflow/ledger-write-lock.ts +244 -0
  215. package/src/asset-workflow/model-inspection.ts +818 -0
  216. package/src/asset-workflow/pixi-spritesheet.ts +197 -0
  217. package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
  218. package/src/asset-workflow/project-asset-commands.ts +23 -0
  219. package/src/asset-workflow/project-asset-health.ts +139 -0
  220. package/src/asset-workflow/project-asset-operations.ts +154 -0
  221. package/src/asset-workflow/project-asset-roots.ts +68 -0
  222. package/src/asset-workflow/project-content.ts +288 -0
  223. package/src/asset-workflow/project-source-index.ts +550 -0
  224. package/src/asset-workflow/thumbnail-system.ts +256 -0
  225. package/src/authoring/active-adapter.ts +199 -0
  226. package/src/authoring/active-systems.ts +422 -0
  227. package/src/authoring/adapter-key.ts +18 -0
  228. package/src/authoring/authoring-asset-url.ts +27 -0
  229. package/src/authoring/bootstrap-state.ts +49 -0
  230. package/src/authoring/boundary-authoring-adapter.ts +184 -0
  231. package/src/authoring/breakpoint-state.ts +43 -0
  232. package/src/authoring/canvas-scene-guides.ts +76 -0
  233. package/src/authoring/component-instance-root.ts +171 -0
  234. package/src/authoring/composite-authoring-adapter.ts +2110 -0
  235. package/src/authoring/consumer-actions.ts +520 -0
  236. package/src/authoring/css-numeric-style.ts +97 -0
  237. package/src/authoring/design-time-layers.ts +849 -0
  238. package/src/authoring/design-time-mount-registry.ts +235 -0
  239. package/src/authoring/design-time-settle.ts +343 -0
  240. package/src/authoring/edit-mode-authoring.ts +619 -0
  241. package/src/authoring/eyedropper-session.ts +60 -0
  242. package/src/authoring/instance-source-menu-register.ts +13 -0
  243. package/src/authoring/instance-source-menu.ts +135 -0
  244. package/src/authoring/layered-pick.ts +183 -0
  245. package/src/authoring/live-gesture-lock.ts +50 -0
  246. package/src/authoring/live-object-transform.ts +62 -0
  247. package/src/authoring/mount-failure-report.ts +154 -0
  248. package/src/authoring/mounted-root-subjects.ts +144 -0
  249. package/src/authoring/no-authoring-adapter.ts +55 -0
  250. package/src/authoring/null-inspection-subjects.tsx +75 -0
  251. package/src/authoring/object3d-document-persistence.ts +106 -0
  252. package/src/authoring/object3d-document-session-registry.ts +120 -0
  253. package/src/authoring/object3d-document-session.ts +1326 -0
  254. package/src/authoring/object3d-gesture-controller.ts +113 -0
  255. package/src/authoring/panel-authoring.ts +121 -0
  256. package/src/authoring/prefab-instance-inspector-section.tsx +237 -0
  257. package/src/authoring/prefab-instance-section-model.ts +55 -0
  258. package/src/authoring/project-authoring-session.ts +105 -0
  259. package/src/authoring/provenance.ts +99 -0
  260. package/src/authoring/quarks-particle-systems.ts +19 -0
  261. package/src/authoring/react-canvas-navigation.ts +255 -0
  262. package/src/authoring/react-design-canvas-style.ts +20 -0
  263. package/src/authoring/react-story-board.ts +937 -0
  264. package/src/authoring/selection-scope.ts +195 -0
  265. package/src/authoring/shell-document-ops.ts +169 -0
  266. package/src/authoring/shell-object3d-document-write-policy.ts +108 -0
  267. package/src/authoring/shell-viewport-policy.ts +48 -0
  268. package/src/authoring/source-object3d-authoring-adapter.ts +526 -0
  269. package/src/authoring/stories-scope.ts +35 -0
  270. package/src/authoring/story-board-chrome-fit.ts +107 -0
  271. package/src/authoring/story-board-presentation.ts +111 -0
  272. package/src/authoring/three-projection-core.ts +226 -0
  273. package/src/authoring/viewport-pick-context.ts +40 -0
  274. package/src/authoring/viewport-raycast.ts +240 -0
  275. package/src/authoring/viewport-tool-context.ts +73 -0
  276. package/src/authoring/world-canvas-viewport-state.ts +35 -0
  277. package/src/authoring/world-hidden-viewport.ts +152 -0
  278. package/src/authoring/world-pan-state.ts +198 -0
  279. package/src/authoring/world-session-state.ts +101 -0
  280. package/src/authoring/write-pipe.ts +173 -0
  281. package/src/availability-tick.ts +66 -0
  282. package/src/bitmap-label.ts +120 -0
  283. package/src/blender-tab-metrics.ts +161 -0
  284. package/src/board-open-actions.ts +20 -0
  285. package/src/boot-routing.ts +391 -0
  286. package/src/build-identity.ts +15 -0
  287. package/src/bytes-codec.ts +62 -0
  288. package/src/camera-authoring.ts +175 -0
  289. package/src/cancellation-reason.ts +58 -0
  290. package/src/canvas-preview-frames.ts +482 -0
  291. package/src/capture-camera-pose.ts +77 -0
  292. package/src/chrome-registry.ts +159 -0
  293. package/src/chrome-slot-registry.ts +91 -0
  294. package/src/collaboration-client.ts +264 -0
  295. package/src/collaboration-presence.ts +41 -0
  296. package/src/command-dispatch.ts +19 -0
  297. package/src/command-listener.ts +2743 -0
  298. package/src/command-registry.ts +70 -0
  299. package/src/component-board-registry.ts +205 -0
  300. package/src/component-states-registry.ts +200 -0
  301. package/src/components/AgentPresentationNotice.tsx +75 -0
  302. package/src/components/AlignToolbar.tsx +204 -0
  303. package/src/components/AppRoot.tsx +394 -0
  304. package/src/components/ApplicationMenus.tsx +415 -0
  305. package/src/components/AssetBrowser.tsx +2843 -0
  306. package/src/components/AssetEditorShell.tsx +216 -0
  307. package/src/components/AssetInspectorToolSection.tsx +124 -0
  308. package/src/components/BoardRulers.tsx +354 -0
  309. package/src/components/CameraInfo.tsx +81 -0
  310. package/src/components/CanvasSceneViewport.tsx +556 -0
  311. package/src/components/CapabilityCoverageSection.tsx +185 -0
  312. package/src/components/CenterDocuments.tsx +22 -0
  313. package/src/components/ChromeSlot.tsx +20 -0
  314. package/src/components/CodeView.tsx +470 -0
  315. package/src/components/CollaborationHeaderControl.css +74 -0
  316. package/src/components/CompactInspectorCard.tsx +190 -0
  317. package/src/components/CompactInspectorShell.tsx +39 -0
  318. package/src/components/ConsolePanel.css +55 -0
  319. package/src/components/ConsolePanel.tsx +270 -0
  320. package/src/components/DefaultEditorLayout.tsx +106 -0
  321. package/src/components/DocumentHeaderStrip.tsx +96 -0
  322. package/src/components/DocumentShelfRail.tsx +45 -0
  323. package/src/components/DocumentThumbnail.tsx +345 -0
  324. package/src/components/EditorLeaseGuard.tsx +372 -0
  325. package/src/components/ErrorBanner.tsx +123 -0
  326. package/src/components/FolderPreviewTile.tsx +159 -0
  327. package/src/components/GameHierarchy.tsx +3842 -0
  328. package/src/components/GameplaySessionTimeline.tsx +295 -0
  329. package/src/components/InspectionProjection.tsx +968 -0
  330. package/src/components/Inspector.tsx +233 -0
  331. package/src/components/InspectorCanvasPreview.tsx +35 -0
  332. package/src/components/InspectorFieldsSection.tsx +290 -0
  333. package/src/components/InspectorObjectPreview.tsx +57 -0
  334. package/src/components/InspectorStoriesSection.tsx +92 -0
  335. package/src/components/InspectorToolSection.tsx +96 -0
  336. package/src/components/InspectorTransformSection.tsx +245 -0
  337. package/src/components/LightExplorerPanel.tsx +433 -0
  338. package/src/components/MediaProperties.tsx +145 -0
  339. package/src/components/NonThreeAuthoringBootstrap.tsx +19 -0
  340. package/src/components/Object3DDocumentToolbar.css +100 -0
  341. package/src/components/Object3DDocumentToolbar.tsx +454 -0
  342. package/src/components/Object3DDocumentViewport.tsx +58 -0
  343. package/src/components/ProjectHeader.css +617 -0
  344. package/src/components/ProjectHeader.tsx +328 -0
  345. package/src/components/ProjectLayout.tsx +249 -0
  346. package/src/components/ReactCanvasControls.tsx +284 -0
  347. package/src/components/RootSelectionOverlay.tsx +3162 -0
  348. package/src/components/RootTextEditor.tsx +79 -0
  349. package/src/components/SaveStatus.tsx +70 -0
  350. package/src/components/StageHost.tsx +1954 -0
  351. package/src/components/StageOverlays.tsx +21 -0
  352. package/src/components/StartupErrorScreen.tsx +76 -0
  353. package/src/components/StartupLoadingScreen.tsx +65 -0
  354. package/src/components/StatsOverlay.tsx +78 -0
  355. package/src/components/SurfaceStateOverlay.tsx +24 -0
  356. package/src/components/ToolContributionSurfaces.tsx +65 -0
  357. package/src/components/ToolHost.tsx +370 -0
  358. package/src/components/ToolObject3DPreview.tsx +39 -0
  359. package/src/components/Toolbar.tsx +595 -0
  360. package/src/components/TransientHint.tsx +44 -0
  361. package/src/components/TransportStrip.tsx +174 -0
  362. package/src/components/VersionControlSection.tsx +470 -0
  363. package/src/components/VgaiLogo.css +83 -0
  364. package/src/components/VgaiLogo.tsx +35 -0
  365. package/src/components/ViewportControlsHint.tsx +60 -0
  366. package/src/components/ViewportFurniture.tsx +401 -0
  367. package/src/components/ViewportOverlay.tsx +145 -0
  368. package/src/components/ViewportOverlaysMenu.tsx +153 -0
  369. package/src/components/ViewportShadingMenu.tsx +300 -0
  370. package/src/components/ViewportViewMenu.tsx +101 -0
  371. package/src/components/WorkspaceDocumentSurface.tsx +204 -0
  372. package/src/components/WorkspaceUtilitySurface.tsx +22 -0
  373. package/src/components/WorktreeSwitcher.css +239 -0
  374. package/src/components/WorktreeSwitcher.tsx +890 -0
  375. package/src/components/account-documents.tsx +1162 -0
  376. package/src/components/asset-documents.tsx +812 -0
  377. package/src/components/asset-editor-persistence.ts +216 -0
  378. package/src/components/asset-selection-section.tsx +535 -0
  379. package/src/components/asset-thumbnails.tsx +312 -0
  380. package/src/components/asset-viewers/AudioViewer.tsx +201 -0
  381. package/src/components/asset-viewers/EntityModelDocument.tsx +122 -0
  382. package/src/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
  383. package/src/components/asset-viewers/GenericJsonViewer.tsx +102 -0
  384. package/src/components/asset-viewers/ImageViewer.tsx +300 -0
  385. package/src/components/asset-viewers/JsonAssetDocument.tsx +93 -0
  386. package/src/components/asset-viewers/LiveModuleDocument.tsx +417 -0
  387. package/src/components/asset-viewers/LutAssetDocument.tsx +444 -0
  388. package/src/components/asset-viewers/ModelAssetDocument.tsx +105 -0
  389. package/src/components/asset-viewers/Object3DPreview.tsx +359 -0
  390. package/src/components/asset-viewers/OnlineAssetDetail.tsx +421 -0
  391. package/src/components/asset-viewers/PasteboardModuleDocument.tsx +67 -0
  392. package/src/components/asset-viewers/QuarksAssetDocument.tsx +526 -0
  393. package/src/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
  394. package/src/components/asset-viewers/SourceAssetViewer.tsx +281 -0
  395. package/src/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
  396. package/src/components/asset-viewers/VideoViewer.tsx +101 -0
  397. package/src/components/asset-viewers/shader-source.ts +144 -0
  398. package/src/components/asset-workflow.css +731 -0
  399. package/src/components/board-guides.ts +150 -0
  400. package/src/components/compact-inspector.css +539 -0
  401. package/src/components/core-utilities.tsx +90 -0
  402. package/src/components/editor-notifications.css +40 -0
  403. package/src/components/engine-workspace.css +274 -0
  404. package/src/components/inspector-preview-section.tsx +238 -0
  405. package/src/components/inspector-property-grouping.ts +64 -0
  406. package/src/components/inspector-revert-label.ts +20 -0
  407. package/src/components/inspector-selection.ts +42 -0
  408. package/src/components/inspector-stories-gating.ts +171 -0
  409. package/src/components/inspector-transform-subject.ts +11 -0
  410. package/src/components/inspector-transform.ts +75 -0
  411. package/src/components/kind-documents.tsx +500 -0
  412. package/src/components/palette-action-publisher.tsx +140 -0
  413. package/src/components/primitives/DraftColorInput.tsx +74 -0
  414. package/src/components/product-shell.css +1829 -0
  415. package/src/components/project-tool-documents.tsx +410 -0
  416. package/src/components/scene-documents.tsx +223 -0
  417. package/src/components/stage-keyboard.tsx +37 -0
  418. package/src/components/stage-overlay-set.tsx +107 -0
  419. package/src/components/stage-presence-markers.ts +478 -0
  420. package/src/components/standard-viewport-dressing.ts +417 -0
  421. package/src/components/status-contributions.tsx +403 -0
  422. package/src/components/tool-documents.tsx +309 -0
  423. package/src/components/tool-schema-form.tsx +262 -0
  424. package/src/components/use-after-paint.ts +41 -0
  425. package/src/components/use-project-image-assets.ts +86 -0
  426. package/src/components/viewport-header-controls.css +90 -0
  427. package/src/components/viewport-surface-status.tsx +55 -0
  428. package/src/components/workspace-history.ts +32 -0
  429. package/src/components/workspace-static-panel-registry.tsx +152 -0
  430. package/src/components/workspace-surfaces.css +621 -0
  431. package/src/components/world-documents.tsx +586 -0
  432. package/src/components/world-overlay-gestures.ts +1694 -0
  433. package/src/composite-screenshot.ts +1641 -0
  434. package/src/console-sync.ts +131 -0
  435. package/src/constraint-helper.ts +338 -0
  436. package/src/content-entry-source-registry.ts +184 -0
  437. package/src/coverage/authoring-seam-evidence.ts +300 -0
  438. package/src/coverage/canvas-reveal.ts +192 -0
  439. package/src/coverage/design-time-surfaces.ts +101 -0
  440. package/src/coverage/live-seam-evidence.ts +11 -0
  441. package/src/coverage/ontology-invariants.ts +466 -0
  442. package/src/coverage/session-vitals.ts +501 -0
  443. package/src/coverage/system-seam-evidence.ts +72 -0
  444. package/src/crash-null-boundary.ts +36 -0
  445. package/src/creation-site-edit.ts +1479 -0
  446. package/src/creation-site-registry.ts +160 -0
  447. package/src/delegate-harness-registry.ts +143 -0
  448. package/src/document-context-registry.ts +177 -0
  449. package/src/document-open-registry.ts +200 -0
  450. package/src/document-preview-source.ts +20 -0
  451. package/src/document-renderer-session.ts +138 -0
  452. package/src/editor-api.ts +46 -0
  453. package/src/editor-chrome-capture.ts +139 -0
  454. package/src/editor-commands.ts +164 -0
  455. package/src/editor-console.ts +563 -0
  456. package/src/editor-current-view.ts +82 -0
  457. package/src/editor-document-probe.ts +881 -0
  458. package/src/editor-git-client.ts +115 -0
  459. package/src/editor-host-door.ts +462 -0
  460. package/src/editor-hotkeys.ts +842 -0
  461. package/src/editor-lease-view.ts +39 -0
  462. package/src/editor-lease.ts +415 -0
  463. package/src/editor-mode.ts +19 -0
  464. package/src/editor-notifications.ts +140 -0
  465. package/src/editor-presence.ts +563 -0
  466. package/src/editor-presentation-activity.ts +50 -0
  467. package/src/editor-presentation-notice.ts +42 -0
  468. package/src/editor-runtime.tsx +145 -0
  469. package/src/editor-server-response.ts +86 -0
  470. package/src/editor-session-attribution.ts +75 -0
  471. package/src/editor-session-mode.ts +54 -0
  472. package/src/editor-shell-store.ts +1304 -0
  473. package/src/editor-state-facets.ts +74 -0
  474. package/src/editor-styles.css +33 -0
  475. package/src/editor-view-presentation.ts +810 -0
  476. package/src/editor-viewport.ts +5302 -0
  477. package/src/entity-lod.ts +31 -0
  478. package/src/entity-object.ts +91 -0
  479. package/src/files/file-provider.ts +62 -0
  480. package/src/files/project-files.ts +264 -0
  481. package/src/finders/index.ts +136 -0
  482. package/src/finders/scenes-from-entrypoint-selection.ts +387 -0
  483. package/src/frame/bridge.tsx +1408 -0
  484. package/src/frame/product.ts +77 -0
  485. package/src/gameplay-dom-recording.ts +319 -0
  486. package/src/gameplay-export-state.ts +14 -0
  487. package/src/gameplay-replay.ts +417 -0
  488. package/src/gameplay-session-time.ts +9 -0
  489. package/src/gameplay-sessions.ts +204 -0
  490. package/src/harness-chat-types.ts +253 -0
  491. package/src/hierarchy-component-marks.ts +298 -0
  492. package/src/hierarchy-drop.ts +91 -0
  493. package/src/hierarchy-expansion-state.ts +80 -0
  494. package/src/hierarchy-header-slot.ts +52 -0
  495. package/src/hierarchy-internals.ts +197 -0
  496. package/src/hierarchy-kind-icon.ts +217 -0
  497. package/src/hierarchy-mark-reader.ts +73 -0
  498. package/src/hierarchy-menu-registry.ts +67 -0
  499. package/src/hierarchy-node-rows.ts +307 -0
  500. package/src/hierarchy-panel-view.ts +280 -0
  501. package/src/hierarchy-projection.ts +76 -0
  502. package/src/hierarchy-row-cache.ts +243 -0
  503. package/src/hierarchy-row-model.ts +308 -0
  504. package/src/hierarchy-rows.ts +11 -0
  505. package/src/hierarchy-walk.ts +86 -0
  506. package/src/history/editor-session.ts +25 -0
  507. package/src/history/history-commands.ts +147 -0
  508. package/src/history/history-delegate.ts +163 -0
  509. package/src/history/history-limit-notices.ts +43 -0
  510. package/src/history/history-service.ts +1173 -0
  511. package/src/history/persistence-coordinator.ts +35 -0
  512. package/src/history/project-file-history.ts +386 -0
  513. package/src/history/project-root-history-backends.ts +139 -0
  514. package/src/history/resource-registry.ts +209 -0
  515. package/src/history/snapshot-store.ts +103 -0
  516. package/src/history/source-history-backend.ts +546 -0
  517. package/src/history/types.ts +124 -0
  518. package/src/hmr-registration-group.ts +67 -0
  519. package/src/hmr-stable-react-context.ts +23 -0
  520. package/src/hotkeys.ts +188 -0
  521. package/src/inference-diagnostics.ts +69 -0
  522. package/src/initial-project.ts +80 -0
  523. package/src/inspection/active-subject.ts +578 -0
  524. package/src/inspection/active-surface.ts +142 -0
  525. package/src/inspection/compose.ts +1064 -0
  526. package/src/inspection/display.ts +170 -0
  527. package/src/inspection/document-subject.ts +109 -0
  528. package/src/inspection/game-subject.ts +85 -0
  529. package/src/inspection/model.ts +542 -0
  530. package/src/inspection/null-subject.ts +115 -0
  531. package/src/inspection/serialize.ts +357 -0
  532. package/src/inspection/use-active-inspection.ts +180 -0
  533. package/src/inspector-presentation.ts +201 -0
  534. package/src/inspector-section-registry.ts +221 -0
  535. package/src/instance-source-actions.ts +163 -0
  536. package/src/instanced-presentation.ts +164 -0
  537. package/src/js-heap.ts +71 -0
  538. package/src/key-actions.ts +91 -0
  539. package/src/keymap-presets.ts +401 -0
  540. package/src/layout-policy.ts +31 -0
  541. package/src/learn-links.ts +73 -0
  542. package/src/light-explorer-model.ts +134 -0
  543. package/src/live-canvas-frame.ts +55 -0
  544. package/src/live-document.ts +279 -0
  545. package/src/live-module-source.ts +230 -0
  546. package/src/live-session-registry.ts +220 -0
  547. package/src/live-transition.ts +633 -0
  548. package/src/manifest-project.ts +107 -0
  549. package/src/model-thumbnail.ts +523 -0
  550. package/src/native-selection-style.ts +202 -0
  551. package/src/object3d-document-write-policy.ts +137 -0
  552. package/src/packaged-runtime.ts +108 -0
  553. package/src/palettes/maya.palette.json +57 -0
  554. package/src/palettes/substance.palette.json +57 -0
  555. package/src/pasteboard-module.ts +81 -0
  556. package/src/performance-profiler.ts +367 -0
  557. package/src/performance-sources.ts +69 -0
  558. package/src/play-boot-phase.ts +145 -0
  559. package/src/presentation-surface.ts +248 -0
  560. package/src/project-adapter.ts +1143 -0
  561. package/src/project-asset-refresh.ts +26 -0
  562. package/src/project-declaration-refresh.ts +31 -0
  563. package/src/project-local-state.ts +118 -0
  564. package/src/project-manager.ts +243 -0
  565. package/src/project-module-changes.ts +163 -0
  566. package/src/project-module-split.ts +266 -0
  567. package/src/project-provenance.ts +115 -0
  568. package/src/project-ready.ts +42 -0
  569. package/src/project-session-reset.ts +67 -0
  570. package/src/project-shape.ts +68 -0
  571. package/src/project-tool-discovery.ts +66 -0
  572. package/src/project-tools.ts +107 -0
  573. package/src/project-work-types.ts +149 -0
  574. package/src/projection/three.ts +898 -0
  575. package/src/projection/types.ts +44 -0
  576. package/src/readiness.ts +113 -0
  577. package/src/reflection-probe-helper.ts +142 -0
  578. package/src/reported-play-state.ts +90 -0
  579. package/src/resolve-relative-specifier.ts +33 -0
  580. package/src/scene-document-plan.ts +315 -0
  581. package/src/scene-framing.ts +315 -0
  582. package/src/scene-live-open.ts +210 -0
  583. package/src/scene-view-fog.ts +89 -0
  584. package/src/scoped-game-css.ts +152 -0
  585. package/src/session-orphan-record.ts +193 -0
  586. package/src/session-tombstone.ts +126 -0
  587. package/src/settings/settings-provider.ts +82 -0
  588. package/src/settings-store.ts +345 -0
  589. package/src/shared-view-restore.ts +42 -0
  590. package/src/shell-store-door.ts +45 -0
  591. package/src/source-conflict.ts +122 -0
  592. package/src/spatial-handle-visuals.ts +332 -0
  593. package/src/stage-context.ts +341 -0
  594. package/src/stage-store-registry.ts +63 -0
  595. package/src/stale-chunk-recovery.ts +34 -0
  596. package/src/state-report-deferral.ts +73 -0
  597. package/src/storage/host-files-storage.ts +97 -0
  598. package/src/storage/http-storage.ts +174 -0
  599. package/src/storage/index.ts +75 -0
  600. package/src/storage/mem-storage.ts +149 -0
  601. package/src/storage/path-lock.ts +44 -0
  602. package/src/storage/paths.ts +26 -0
  603. package/src/storage/types.ts +116 -0
  604. package/src/stories/StoryComponentThumbnail.tsx +184 -0
  605. package/src/stories/StoryPreviewMount.tsx +306 -0
  606. package/src/stories/component-content-source.tsx +106 -0
  607. package/src/stories/component-states-source.ts +78 -0
  608. package/src/stories/compose-project-stories.ts +255 -0
  609. package/src/stories/pixi-story-model.ts +30 -0
  610. package/src/stories/prefabs-finder.ts +54 -0
  611. package/src/stories/prefabs-from-stories.ts +182 -0
  612. package/src/stories/project-story-discovery.ts +78 -0
  613. package/src/stories/project-story-regions.ts +24 -0
  614. package/src/stories/story-actions.ts +54 -0
  615. package/src/stories/story-capture-command.ts +124 -0
  616. package/src/stories/story-capture.ts +584 -0
  617. package/src/stories/story-declared-medium.ts +126 -0
  618. package/src/stories/story-discovery.ts +176 -0
  619. package/src/stories/story-document-openers.ts +36 -0
  620. package/src/stories/story-dom-runtime.ts +78 -0
  621. package/src/stories/story-grouping.ts +111 -0
  622. package/src/stories/story-lane.ts +88 -0
  623. package/src/stories/story-mount-turn.ts +27 -0
  624. package/src/stories/story-opener.ts +260 -0
  625. package/src/stories/story-pixi-preview.ts +408 -0
  626. package/src/stories/story-presentation.ts +215 -0
  627. package/src/stories/story-registry.ts +517 -0
  628. package/src/stories/story-three-preview.ts +807 -0
  629. package/src/stories/three-story-model.ts +96 -0
  630. package/src/story-three-preview-runtime.ts +56 -0
  631. package/src/surface-keyboard.ts +112 -0
  632. package/src/surface-state.ts +124 -0
  633. package/src/tab-bootstrap.js +628 -0
  634. package/src/tab-census.ts +198 -0
  635. package/src/tab-lifecycle-client.ts +196 -0
  636. package/src/theme-library.ts +844 -0
  637. package/src/theme-preference.ts +378 -0
  638. package/src/theme.css +3437 -0
  639. package/src/three-viewport/bone-selection-highlight.ts +119 -0
  640. package/src/three-viewport/camera-fit.ts +41 -0
  641. package/src/three-viewport/interactive-renderer.ts +132 -0
  642. package/src/three-viewport/selection-brackets.ts +310 -0
  643. package/src/three-viewport/selection-outline.ts +183 -0
  644. package/src/three-viewport/skeleton-helper.ts +61 -0
  645. package/src/three-viewport/source-color.ts +167 -0
  646. package/src/three-viewport/studio-environment.ts +96 -0
  647. package/src/three-viewport-presentation.ts +23 -0
  648. package/src/tool-contribution-play.ts +74 -0
  649. package/src/tool-loader.ts +1798 -0
  650. package/src/transform-mode-request.ts +57 -0
  651. package/src/transient-hint.ts +78 -0
  652. package/src/trigger-volume-helper.ts +116 -0
  653. package/src/ui-source/adapter-region-includes.ts +241 -0
  654. package/src/ui-source/ensure-import.ts +132 -0
  655. package/src/ui-source/file-region-resolver.ts +302 -0
  656. package/src/ui-source/inspect.ts +775 -0
  657. package/src/ui-source/oid-transform.ts +1845 -0
  658. package/src/ui-source/plan-csf-story.ts +196 -0
  659. package/src/ui-source/plan-extract-component.ts +421 -0
  660. package/src/ui-source/plan-fork-component.ts +621 -0
  661. package/src/ui-source/plan-named-style.ts +95 -0
  662. package/src/ui-source/plan-source-edit.ts +353 -0
  663. package/src/ui-source/r3f-contract-resolver.ts +327 -0
  664. package/src/ui-source/r3f-diagnostic-index.ts +165 -0
  665. package/src/ui-source/r3f-environment-binding.ts +133 -0
  666. package/src/ui-source/r3f-joint-binding.ts +251 -0
  667. package/src/ui-source/r3f-lod-binding.ts +91 -0
  668. package/src/ui-source/r3f-particle-binding.ts +235 -0
  669. package/src/ui-source/r3f-physics-binding.ts +483 -0
  670. package/src/ui-source/r3f-project-contracts.ts +444 -0
  671. package/src/ui-source/relative-import-specifier.ts +34 -0
  672. package/src/ui-source/reparent-guard.ts +544 -0
  673. package/src/ui-source/source-edit-request.ts +97 -0
  674. package/src/ui-source/source-write-backend.ts +618 -0
  675. package/src/ui-source/syntactic-prop-specs.ts +296 -0
  676. package/src/ui-source/tier-source-write-backend.ts +279 -0
  677. package/src/ui-source/ts-ast.ts +171 -0
  678. package/src/ui-source/utility-class-support.ts +169 -0
  679. package/src/ui-source/write-component-default.ts +133 -0
  680. package/src/ui-source/writer.ts +1989 -0
  681. package/src/viewport-activation-timings.ts +840 -0
  682. package/src/viewport-authoring-policy.ts +186 -0
  683. package/src/viewport-controls-hint.ts +57 -0
  684. package/src/viewport-door.ts +237 -0
  685. package/src/viewport-shading-boundary.ts +12 -0
  686. package/src/vite-error-surface.ts +141 -0
  687. package/src/wait-until.ts +37 -0
  688. package/src/workspace-areas.ts +156 -0
  689. package/src/workspace-aux-commands.ts +11 -0
  690. package/src/workspace-available-documents.ts +127 -0
  691. package/src/workspace-core-utilities.ts +31 -0
  692. package/src/workspace-document-ids.ts +59 -0
  693. package/src/workspace-document-registry.ts +612 -0
  694. package/src/workspace-document-restore.ts +145 -0
  695. package/src/workspace-host-commands.ts +141 -0
  696. package/src/workspace-persistence-gate.ts +40 -0
  697. package/src/workspace-play-utilities.ts +44 -0
  698. package/src/workspace-presets.ts +425 -0
  699. package/src/workspace-regions.ts +294 -0
  700. package/src/workspace-state-persistence.ts +536 -0
  701. package/src/workspace-static-panels.ts +73 -0
  702. package/src/workspace-status-registry.ts +121 -0
  703. package/src/workspace-style.ts +239 -0
  704. package/src/workspace-utility-commands.ts +74 -0
  705. package/src/workspace-utility-registry.ts +263 -0
  706. package/src/workspace-viewport-rect.ts +97 -0
  707. package/src/world-adoption.ts +115 -0
  708. package/src/world-document-routing.ts +104 -0
  709. package/vite-plugin-creation-site-write.ts +184 -0
  710. package/vite-plugin-creation-site.ts +80 -0
  711. package/vite-plugin-game-static.ts +303 -0
  712. package/vite-plugin-module-doorways.ts +336 -0
  713. package/vite-plugin-product-contributions.ts +197 -0
  714. package/vite-plugin-project-game-static.ts +125 -0
  715. package/vite-plugin-project-jsx-js.ts +65 -0
  716. package/vite-plugin-project-root-absolute-assets.ts +359 -0
  717. package/vite-plugin-shared-react.ts +420 -0
  718. package/vite-plugin-shared-three.ts +203 -0
  719. package/vite-plugin-ui-oid.ts +2106 -0
@@ -0,0 +1,648 @@
1
+ /**
2
+ * The server half of creation-site write-back — ownership, path
3
+ * containment, and the read/plan/apply handlers behind `/__ingest-source/*`.
4
+ *
5
+ * The client never decides any of this. It sends an anchor
6
+ * (`{file, line, col}`, project-root-RELATIVE — the string the creation-site
7
+ * registry hands out) plus the value in force and the value the user produced; this
8
+ * module resolves that to a real path inside the project, reads it, runs the
9
+ * pure planner, and hands back exact bytes or a named refusal. Three properties
10
+ * are deliberately server-side and unreachable from the browser:
11
+ *
12
+ * - OWNERSHIP. Whether the base may be written at all, and WHO RECORDS the
13
+ * resulting diff, are facts about the filesystem and about which folder this
14
+ * editor was pointed at. A client cannot be trusted to answer either and is
15
+ * never asked to; it renders whatever {@link ingestSourceOwnership} says,
16
+ * including the reason and the recorder.
17
+ * - CONTAINMENT. {@link resolveIngestSourceFile} refuses any path that escapes
18
+ * the roots an anchor may name, including through `..`, an absolute path, or
19
+ * a symlink (the resolution is `realpath`-based, so a link planted inside a
20
+ * root cannot be used to write outside it). There are TWO such roots and
21
+ * that is not a widening: the opened project, and — only for a file some
22
+ * `vendor/games/<id>.UPSTREAM.lock` actually claims — the repo-vendored
23
+ * home, which is the set this route can write WITH its lock in one gesture.
24
+ * This is the only door, so it is the only place the check has to be right.
25
+ * - THE CHECKSUM GUARD. `apply` refuses a write whose `ifMatchSha` no longer
26
+ * matches the file on disk, which is what makes undo/redo safe against a
27
+ * file the user edited in their own editor meanwhile.
28
+ *
29
+ * WHY A SEPARATE ROUTE FAMILY FROM `/__ui-source/*`. That family's scope guard
30
+ * (`resolveEditableSourceFile`) admits `.tsx` under the project's `src/` and
31
+ * project TypeScript — it is the JSX/R3F authoring door, and its shape encodes
32
+ * that. An ingested game is somebody else's JavaScript, laid out however they
33
+ * laid it out (`src/scripts/sim/city.js`), and it is reachable ONLY through an
34
+ * anchor this editor itself stamped. Widening the JSX door to admit arbitrary
35
+ * `.js` would hand every existing oid-driven endpoint a scope it was never
36
+ * designed for; a second door with its own, narrower key does not.
37
+ */
38
+
39
+ import { createHash } from 'node:crypto';
40
+ import {
41
+ accessSync,
42
+ constants,
43
+ readFileSync,
44
+ realpathSync,
45
+ statSync,
46
+ writeFileSync,
47
+ } from 'node:fs';
48
+ import { isAbsolute, join, relative, resolve, sep } from 'node:path';
49
+ import {
50
+ type CreationSiteEditRequest,
51
+ type CreationSiteLiteralReport,
52
+ type CreationSiteLiteralRequest,
53
+ type CreationSiteSurface,
54
+ type CreationSiteWriteScope,
55
+ planCreationSiteEdit,
56
+ planCreationSiteRemoval,
57
+ readCreationSiteLiteral,
58
+ } from '../src/creation-site-edit';
59
+ import {
60
+ type HmrInvalidationGraph,
61
+ staleModuleWarning,
62
+ stampHmrInvalidation,
63
+ } from './project-script-hmr';
64
+ import { isPathInside } from './server-utils';
65
+ import {
66
+ findVendoredTarget,
67
+ settleVendoredWrite,
68
+ LOCKS_DIR as VENDORED_HOME,
69
+ writeRecordedVendoredFile,
70
+ } from './vendored-lock-recorder';
71
+
72
+ /** The JSON response a handler produces (status defaults to 200). */
73
+ export interface HandlerResult {
74
+ readonly status?: number;
75
+ readonly body: unknown;
76
+ }
77
+
78
+ export interface IngestSourceOwnership {
79
+ /** May this session write the game's own source at all? */
80
+ readonly writable: boolean;
81
+ /** Always present when `writable` is false — never a blank (honest-floor). */
82
+ readonly reason?: string;
83
+ /** Echoed back so the surface can name the folder it is talking about. */
84
+ readonly projectRoot: string | null;
85
+ /**
86
+ * WHO RECORDS the diff this session's edits produce, in one phrase a surface
87
+ * can show. Present whenever `writable` — the two answers are the user's own
88
+ * version control, and (for a repo-vendored copy) that game's UPSTREAM lock,
89
+ * updated in the same gesture as the write.
90
+ */
91
+ readonly recorder?: string;
92
+ }
93
+
94
+ /** Hashes BYTES. Every digest this route quotes — `ifMatchSha`, the one it
95
+ * returns — has to mean the same thing as the vendored lock's and the
96
+ * verifier's, and those hash the file's bytes. */
97
+ function sha256(bytes: Buffer): string {
98
+ return createHash('sha256').update(bytes).digest('hex');
99
+ }
100
+
101
+ /**
102
+ * The wire form of a file's content.
103
+ *
104
+ * Source is text and stays text. But a vendored game's authorable truth is not
105
+ * always source: a level-based game's placed objects live in a binary level
106
+ * file, so the same route has to carry megabytes of binary data, and a JSON
107
+ * string cannot hold it — UTF-8 round-tripping those bytes silently produces a
108
+ * different, longer file. `encoding` is explicit on the wire rather than sniffed, so a
109
+ * client that forgets it gets a wrong SHA and a refusal, not a corrupted game.
110
+ */
111
+ function decodeSource(source: string, encoding: unknown): Buffer | null {
112
+ if (encoding === 'base64') return Buffer.from(source, 'base64');
113
+ if (encoding === undefined || encoding === 'utf8') return Buffer.from(source, 'utf8');
114
+ return null;
115
+ }
116
+
117
+ /** Git's own rule: a NUL byte near the front means this is not text. */
118
+ function looksBinary(bytes: Buffer): boolean {
119
+ return bytes.subarray(0, 8000).includes(0);
120
+ }
121
+
122
+ function realOrSelf(path: string): string {
123
+ try {
124
+ return realpathSync(path);
125
+ } catch {
126
+ return path;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Whether an ingest session may write the game's own source, WHO RECORDS the
132
+ * diff, and — when it may not — the sentence the UI shows verbatim.
133
+ *
134
+ * OWNERSHIP DECIDES THE RECORDER, NOT WHETHER TO WRITE. Persistence works the
135
+ * same way it does in the native lane: an authored edit edits the game's own
136
+ * code, and the only thing that varies is where the resulting divergence is
137
+ * accounted for. A folder the user owns records in their version control. A
138
+ * repo-vendored copy records in its own `vendor/games/<id>.UPSTREAM.lock`, in
139
+ * the same server gesture as the write, so the estate's bar — zero UNRECORDED
140
+ * diff, never zero diff — holds at every instant (`vendored-lock-recorder.ts`).
141
+ *
142
+ * What is left here is the filesystem's own answer: a folder has to exist and
143
+ * be writable. Everything else this function used to decide was a policy about
144
+ * whose files these are, and that policy now lives one layer down, in which
145
+ * recorder runs.
146
+ */
147
+ export function ingestSourceOwnership(
148
+ projectRoot: string | undefined | null,
149
+ engineRoot: string,
150
+ ): IngestSourceOwnership {
151
+ if (!projectRoot) {
152
+ return {
153
+ writable: false,
154
+ reason: 'no project folder is open — this session has no source to write',
155
+ projectRoot: null,
156
+ };
157
+ }
158
+ const root = realOrSelf(resolve(projectRoot));
159
+ try {
160
+ if (!statSync(root).isDirectory()) {
161
+ return { writable: false, reason: 'the project path is not a folder', projectRoot: root };
162
+ }
163
+ accessSync(root, constants.W_OK);
164
+ } catch {
165
+ return { writable: false, reason: 'the project folder is not writable', projectRoot: root };
166
+ }
167
+ return { writable: true, projectRoot: root, recorder: recorderFor(root, engineRoot) };
168
+ }
169
+
170
+ /** The one phrase naming who accounts for this session's edits. */
171
+ function recorderFor(projectRoot: string, engineRoot: string): string {
172
+ const vendored = findVendoredTarget(projectRoot, engineRoot);
173
+ return vendored
174
+ ? `the vendored game’s own lock (vendor/games/${vendored.id}.UPSTREAM.lock), updated in the same gesture as the write`
175
+ : 'your own version control — these are your project’s files';
176
+ }
177
+
178
+ /** Resolve `clean` under `root`, contained on both sides of symlink resolution. */
179
+ function resolveInsideRoot(clean: string, rootDir: string): string | null {
180
+ const root = realOrSelf(resolve(rootDir));
181
+ const candidate = resolve(root, clean);
182
+ if (!isPathInside(root, candidate)) return null;
183
+ let real: string;
184
+ try {
185
+ real = realpathSync(candidate);
186
+ if (!statSync(real).isFile()) return null;
187
+ } catch {
188
+ return null;
189
+ }
190
+ // Re-checked AFTER symlink resolution: a link inside the root pointing out of
191
+ // it passes the first check and fails this one.
192
+ return isPathInside(root, real) ? real : null;
193
+ }
194
+
195
+ /**
196
+ * The absolute path an anchor's root-relative `file` names, or `null` when it
197
+ * escapes every root an anchor may be written against (or does not exist).
198
+ *
199
+ * TWO ROOTS, because an anchor is relative to whichever root OWNS the module,
200
+ * and `vite-plugin-creation-site`'s `creationSiteScopeFor` picks that root from
201
+ * the same set the game-globals shadow uses (`ingestGameShadowRoots`): an
202
+ * opened project, AND the repo-vendored home. So a repo-vendored game's
203
+ * creation site arrives as `<id>/src/...`, relative to `vendor/games` — a path
204
+ * that cannot resolve inside the opened project and, until this, was refused as
205
+ * "not a file inside this project". MEASURED on the bubbo-bubbo ingest: every
206
+ * edit to that game stayed live-only with that reason, which was TRUE and
207
+ * beside the point — the file is not the project's, it is the vendored game's,
208
+ * and `vendored-lock-recorder.ts` exists precisely to write it.
209
+ *
210
+ * The vendored leg's containment is not a path prefix but the RECORDER's own
211
+ * answer: `findVendoredTarget` must claim the resolved file, i.e. some
212
+ * `vendor/games/<id>.UPSTREAM.lock` covers it. That is strictly stronger than
213
+ * "under vendor/games", because it is exactly the set of files this route can
214
+ * write WITH their lock in the same gesture (`handleIngestApply`) — a file the
215
+ * recorder does not claim can never be written here, so it is never resolved
216
+ * here either.
217
+ *
218
+ * Every rejection is the same `null` on purpose: a client that can distinguish
219
+ * "outside the project" from "does not exist" can probe the host's filesystem
220
+ * one guess at a time.
221
+ */
222
+ export function resolveIngestSourceFile(
223
+ file: unknown,
224
+ projectRoot: string,
225
+ engineRoot?: string,
226
+ ): string | null {
227
+ if (typeof file !== 'string' || file.length === 0) return null;
228
+ const clean = file.split('?')[0] ?? file;
229
+ // An ANCHOR is always root-relative — an absolute path did not come from the
230
+ // registry, so it is refused rather than resolved.
231
+ if (isAbsolute(clean)) return null;
232
+ const inProject = resolveInsideRoot(clean, projectRoot);
233
+ if (inProject) return inProject;
234
+ if (engineRoot === undefined) return null;
235
+ const inVendored = resolveInsideRoot(clean, join(engineRoot, ...VENDORED_HOME));
236
+ return inVendored && findVendoredTarget(inVendored, engineRoot) ? inVendored : null;
237
+ }
238
+
239
+ /**
240
+ * Complete any vendored write that died between its own artifacts, BEFORE this
241
+ * request reads the file. A journalled write is finished by the next request
242
+ * that touches the game, which is why every route calls this and not just the
243
+ * writing one — planning an edit against half-written bytes would produce a
244
+ * plan that is wrong in a way no later check could catch.
245
+ *
246
+ * When it does roll bytes forward it stamps the same invalidation a write of
247
+ * our own stamps: settling REPLACES the file's content, so a dev server that
248
+ * kept serving the pre-settle module would hand the next mount source that no
249
+ * longer exists on disk — the defect `invalidateWrittenSource` above was added
250
+ * for, reaching the graph through the settle instead of through the write.
251
+ */
252
+ function settlePendingRecord(resolvedFile: string, engineRoot: string): void {
253
+ const vendored = findVendoredTarget(resolvedFile, engineRoot);
254
+ if (vendored && settleVendoredWrite(vendored)) invalidateWrittenSource(resolvedFile);
255
+ }
256
+
257
+ /**
258
+ * Stable identity for the history registry (mirrors the `/__ui-source` family's
259
+ * `sourceResourcePath`).
260
+ *
261
+ * A vendored game's file is not under the project root, so a plain `relative()`
262
+ * would key it by a ladder of `..` segments that describes the host's directory
263
+ * layout rather than the file. It is keyed by its position in the vendored home
264
+ * instead — the same `<id>/…` string the creation-site anchor already uses, so
265
+ * one file has one identity whichever route reached it.
266
+ */
267
+ function resourcePathOf(file: string, projectRoot: string, engineRoot: string): string {
268
+ const vendorHome = realOrSelf(resolve(join(engineRoot, ...VENDORED_HOME)));
269
+ const root = isPathInside(vendorHome, file) ? vendorHome : realOrSelf(resolve(projectRoot));
270
+ return relative(root, file).split(sep).join('/');
271
+ }
272
+
273
+ /** The wire shape of a prepare request — the anchor plus the two values.
274
+ * `remove: true` plans a REMOVAL instead (`planCreationSiteRemoval`): `next`
275
+ * is absent because absence is not a value, and the same route carries it so
276
+ * ownership, path containment and the checksum-guarded apply are literally
277
+ * the same code for either direction. */
278
+ interface PrepareBody {
279
+ readonly site?: { file?: unknown; line?: unknown; col?: unknown };
280
+ readonly instances?: unknown;
281
+ readonly writeScope?: unknown;
282
+ readonly property?: unknown;
283
+ readonly surface?: unknown;
284
+ readonly baseline?: unknown;
285
+ readonly next?: unknown;
286
+ readonly remove?: unknown;
287
+ }
288
+
289
+ function writeScopeOf(value: unknown): CreationSiteWriteScope | 'invalid' {
290
+ if (value === undefined || value === 'instance') return 'instance';
291
+ if (value === 'creation-site') return 'creation-site';
292
+ return 'invalid';
293
+ }
294
+
295
+ /**
296
+ * Which surface vocabulary the client's `property` is in — validated here rather
297
+ * than cast, because it selects the CHANNEL TABLE and an unrecognized value must
298
+ * not silently fall through to the other surface's meaning of the same word
299
+ * (`position` is a 3-vector on three and a 2-vector on canvas).
300
+ */
301
+ function surfaceOf(value: unknown): CreationSiteSurface | 'invalid' {
302
+ if (value === undefined || value === 'three') return 'three';
303
+ if (value === 'pixi' || value === 'babylon') return value;
304
+ return 'invalid';
305
+ }
306
+
307
+ export interface PreparedCreationSiteEdit {
308
+ readonly changed: boolean;
309
+ readonly file?: string;
310
+ readonly resourcePath?: string;
311
+ readonly prevSource?: string;
312
+ readonly newSource?: string;
313
+ readonly prevSha?: string;
314
+ readonly newSha?: string;
315
+ /** Present iff `!changed` — the named refusal. */
316
+ readonly reason?: string;
317
+ }
318
+
319
+ /**
320
+ * POST `/__ingest-source/prepare` — plan one property edit against the game's
321
+ * own source. Reads, never writes.
322
+ *
323
+ * The planning itself is `planCreationSiteEdit`, which is pure and shared with
324
+ * the unit tests, so what a test proves is what the server does.
325
+ */
326
+ export function handleIngestPrepare(
327
+ body: PrepareBody,
328
+ projectRoot: string | undefined | null,
329
+ engineRoot: string,
330
+ ): HandlerResult {
331
+ const ownership = ingestSourceOwnership(projectRoot, engineRoot);
332
+ if (!ownership.writable || !ownership.projectRoot) {
333
+ return { status: 403, body: { changed: false, reason: ownership.reason } };
334
+ }
335
+ const site = body.site ?? {};
336
+ const surface = surfaceOf(body.surface);
337
+ const writeScope = writeScopeOf(body.writeScope);
338
+ if (
339
+ typeof site.file !== 'string' ||
340
+ typeof site.line !== 'number' ||
341
+ typeof site.col !== 'number' ||
342
+ typeof body.property !== 'string' ||
343
+ typeof body.instances !== 'number' ||
344
+ surface === 'invalid' ||
345
+ writeScope === 'invalid'
346
+ ) {
347
+ return {
348
+ status: 400,
349
+ body: { changed: false, reason: 'malformed creation-site edit request' },
350
+ };
351
+ }
352
+ const resolved = resolveIngestSourceFile(site.file, ownership.projectRoot, engineRoot);
353
+ if (!resolved) {
354
+ return {
355
+ status: 403,
356
+ body: { changed: false, reason: 'the creation site is not a file inside this project' },
357
+ };
358
+ }
359
+ settlePendingRecord(resolved, engineRoot);
360
+ const source = readFileSync(resolved, 'utf8');
361
+ const plan =
362
+ body.remove === true
363
+ ? planCreationSiteRemoval(source, {
364
+ site: { file: site.file, line: site.line, col: site.col },
365
+ instances: body.instances,
366
+ writeScope,
367
+ property: body.property,
368
+ surface,
369
+ })
370
+ : planCreationSiteEdit(source, {
371
+ site: { file: site.file, line: site.line, col: site.col },
372
+ instances: body.instances,
373
+ writeScope,
374
+ property: body.property,
375
+ surface,
376
+ baseline: body.baseline as CreationSiteEditRequest['baseline'],
377
+ next: body.next as CreationSiteEditRequest['next'],
378
+ });
379
+ if (!plan.changed) {
380
+ return { body: { changed: false, reason: plan.reason ?? 'the edit was refused' } };
381
+ }
382
+ return {
383
+ body: {
384
+ changed: true,
385
+ file: site.file,
386
+ resourcePath: resourcePathOf(resolved, ownership.projectRoot, engineRoot),
387
+ prevSource: plan.prevSource,
388
+ newSource: plan.newSource,
389
+ prevSha: sha256(Buffer.from(plan.prevSource, 'utf8')),
390
+ newSha: sha256(Buffer.from(plan.newSource, 'utf8')),
391
+ } satisfies PreparedCreationSiteEdit,
392
+ };
393
+ }
394
+
395
+ /** The wire shape of an inspect request — one anchor, many properties, each
396
+ * with the value in force on the live object. */
397
+ interface InspectBody {
398
+ readonly site?: { file?: unknown; line?: unknown; col?: unknown };
399
+ readonly instances?: unknown;
400
+ readonly writeScope?: unknown;
401
+ readonly surface?: unknown;
402
+ readonly properties?: unknown;
403
+ }
404
+
405
+ /**
406
+ * POST `/__ingest-source/inspect` — what the construction statement SAYS each of
407
+ * these properties is, so the inspector can show the live object's value as an
408
+ * override of the site's own literal. Reads, never writes, never plans.
409
+ *
410
+ * ONE ROUND TRIP FOR THE WHOLE SUBJECT, not one per property: the file is read
411
+ * and parsed once per request, and a per-property route would re-parse the
412
+ * game's source for every row the inspector draws.
413
+ *
414
+ * It is the same `readCreationSiteLiteral` the unit tests drive, for the same
415
+ * reason `prepare` is `planCreationSiteEdit`: what a test proves is what the
416
+ * server does. The route is deliberately NOT gated on the session's "persist to
417
+ * game source" consent — reading what a line of the game says is a read, and the
418
+ * write consent is checked where a byte would actually move.
419
+ */
420
+ export function handleIngestInspect(
421
+ body: InspectBody,
422
+ projectRoot: string | undefined | null,
423
+ engineRoot: string,
424
+ ): HandlerResult {
425
+ const ownership = ingestSourceOwnership(projectRoot, engineRoot);
426
+ if (!ownership.writable || !ownership.projectRoot) {
427
+ return { status: 403, body: { error: ownership.reason } };
428
+ }
429
+ const site = body.site ?? {};
430
+ const surface = surfaceOf(body.surface);
431
+ const writeScope = writeScopeOf(body.writeScope);
432
+ if (
433
+ typeof site.file !== 'string' ||
434
+ typeof site.line !== 'number' ||
435
+ typeof site.col !== 'number' ||
436
+ typeof body.instances !== 'number' ||
437
+ !Array.isArray(body.properties) ||
438
+ surface === 'invalid' ||
439
+ writeScope === 'invalid'
440
+ ) {
441
+ return { status: 400, body: { error: 'malformed creation-site inspect request' } };
442
+ }
443
+ const resolved = resolveIngestSourceFile(site.file, ownership.projectRoot, engineRoot);
444
+ if (!resolved) {
445
+ return { status: 403, body: { error: 'the creation site is not a file inside this project' } };
446
+ }
447
+ settlePendingRecord(resolved, engineRoot);
448
+ const source = readFileSync(resolved, 'utf8');
449
+ const properties: Record<string, CreationSiteLiteralReport> = {};
450
+ for (const entry of body.properties as ReadonlyArray<{ property?: unknown; live?: unknown }>) {
451
+ if (typeof entry?.property !== 'string') continue;
452
+ properties[entry.property] = readCreationSiteLiteral(source, {
453
+ site: { file: site.file, line: site.line, col: site.col },
454
+ instances: body.instances,
455
+ writeScope,
456
+ property: entry.property,
457
+ surface,
458
+ live: entry.live as CreationSiteLiteralRequest['live'],
459
+ });
460
+ }
461
+ return { body: { file: site.file, properties } };
462
+ }
463
+
464
+ /** POST `/__ingest-source/read` — one scope-checked file, for history capture
465
+ * and the undo/redo preflight. */
466
+ export function handleIngestRead(
467
+ body: { file?: unknown },
468
+ projectRoot: string | undefined | null,
469
+ engineRoot: string,
470
+ ): HandlerResult {
471
+ const ownership = ingestSourceOwnership(projectRoot, engineRoot);
472
+ if (!ownership.writable || !ownership.projectRoot) {
473
+ return { status: 403, body: { error: ownership.reason } };
474
+ }
475
+ const resolved = resolveIngestSourceFile(body.file, ownership.projectRoot, engineRoot);
476
+ if (!resolved) return { status: 403, body: { error: 'file out of project scope' } };
477
+ settlePendingRecord(resolved, engineRoot);
478
+ const bytes = readFileSync(resolved);
479
+ // Binary comes back base64-tagged so the caller can hand the SAME bytes back
480
+ // through `apply` for undo — which is the only thing that makes undo of a
481
+ // level-data edit byte-exact.
482
+ const binary = looksBinary(bytes);
483
+ return {
484
+ body: {
485
+ source: binary ? bytes.toString('base64') : bytes.toString('utf8'),
486
+ encoding: binary ? 'base64' : 'utf8',
487
+ sha: sha256(bytes),
488
+ resourcePath: resourcePathOf(resolved, ownership.projectRoot, engineRoot),
489
+ },
490
+ };
491
+ }
492
+
493
+ /**
494
+ * THE MODULE GRAPH `handleIngestApply` MUST INVALIDATE — and why the editor
495
+ * cannot leave that to the file watcher.
496
+ *
497
+ * The editor writes the ingested game's own bytes itself, so making that write
498
+ * visible to the next mount is its own job. Vite serves a source module from
499
+ * `ModuleGraph.transformResult` until something invalidates it, and the only
500
+ * thing that ever did here was the filesystem watcher's change event. Where the
501
+ * watcher is not watching, the write lands on disk, the ack is honest, the diff
502
+ * is real — and the next mount re-derives the game from the PRE-EDIT bytes.
503
+ *
504
+ * That is not a hypothetical environment: the root config's
505
+ * `server.watch.ignored` carries a `.claude` glob (it stops one agent
506
+ * worktree's churn reloading every OTHER live session's tab), so every project
507
+ * opened from inside a worktree gets no watcher event for its own source at
508
+ * all. Measured on the `/__ui-source/*` family first — an authored
509
+ * `position={[0,1.5,0]}` read back as `[0,0,0]` after a reload — and closed
510
+ * there by `vite-plugin-ui-oid.ts`'s `invalidateWrittenSource`. This is the
511
+ * same defect on the ingest lane's own write door, closed the same way. A write
512
+ * path may not depend on an ignore list it does not own.
513
+ *
514
+ * Graph-only, deliberately: this stamps invalidation exactly the way
515
+ * `handleProjectScriptHotUpdate` does when it swallows Vite's HMR, and sends no
516
+ * client event, so hot-update behaviour on a watched project is untouched (its
517
+ * watcher event still arrives and still drives the custom events) and stamping
518
+ * twice is idempotent.
519
+ */
520
+ let writtenSourceInvalidationGraph: HmrInvalidationGraph | undefined;
521
+ let writtenSourceStampBoundary: ((moduleFile: string) => boolean) | undefined;
522
+
523
+ /** Called once by `creationSiteWritePlugin`'s `configureServer` — these routes
524
+ * are mounted on exactly one dev server. `stampBoundary` bounds the stamp's
525
+ * importer propagation at editor-chrome modules (see
526
+ * `project-script-hmr.ts`'s `stampHmrInvalidation` doc for the
527
+ * split-singleton failure an unbounded walk shipped): a written GAME module
528
+ * must re-evaluate on the next mount, and the editor modules that imported
529
+ * it must not be re-instanced mid-session. */
530
+ export function bindIngestWriteInvalidation(
531
+ graph: HmrInvalidationGraph,
532
+ stampBoundary?: (moduleFile: string) => boolean,
533
+ ): void {
534
+ writtenSourceInvalidationGraph = graph;
535
+ writtenSourceStampBoundary = stampBoundary;
536
+ }
537
+
538
+ function invalidateWrittenSource(file: string): void {
539
+ if (!writtenSourceInvalidationGraph) return;
540
+ const outcome = stampHmrInvalidation(
541
+ writtenSourceInvalidationGraph,
542
+ file,
543
+ undefined,
544
+ writtenSourceStampBoundary,
545
+ );
546
+ const warning = staleModuleWarning(file, outcome);
547
+ if (warning) console.warn(warning);
548
+ }
549
+
550
+ /**
551
+ * POST `/__ingest-source/apply` — the guarded whole-file write used by commit,
552
+ * undo and redo.
553
+ *
554
+ * `ifMatchSha` is not optional and there is no force: a stale digest means the
555
+ * file changed under us, and the only honest response is to refuse and say so.
556
+ *
557
+ * THE RECORDER RUNS INSIDE THIS ROUTE, not beside it. When the target is a
558
+ * repo-vendored game, the bytes and that game's lock move in ONE operation
559
+ * (`writeRecordedVendoredFile`), so there is no instant at which the file has
560
+ * changed and its lock has not. Undo needs no counterpart: it comes back
561
+ * through this same route with the previous bytes, and the recorder reconciles
562
+ * to whatever those bytes are — including all the way back to upstream's own,
563
+ * which removes the record entirely.
564
+ *
565
+ * `note` is an optional hint from the client naming the edit (the property and
566
+ * the creation site) for the generated record. It is a HINT: the record's
567
+ * truth — the diff and both shas — is derived from the bytes on either side, so
568
+ * an absent or stale note can make the prose less specific and can never make
569
+ * it wrong.
570
+ */
571
+ export function handleIngestApply(
572
+ body: {
573
+ file?: unknown;
574
+ source?: unknown;
575
+ encoding?: unknown;
576
+ ifMatchSha?: unknown;
577
+ note?: unknown;
578
+ },
579
+ projectRoot: string | undefined | null,
580
+ engineRoot: string,
581
+ ): HandlerResult {
582
+ const ownership = ingestSourceOwnership(projectRoot, engineRoot);
583
+ if (!ownership.writable || !ownership.projectRoot) {
584
+ return { status: 403, body: { applied: false, error: ownership.reason } };
585
+ }
586
+ const resolved = resolveIngestSourceFile(body.file, ownership.projectRoot, engineRoot);
587
+ if (!resolved)
588
+ return { status: 403, body: { applied: false, error: 'file out of project scope' } };
589
+ if (typeof body.source !== 'string' || typeof body.ifMatchSha !== 'string') {
590
+ return { status: 400, body: { applied: false, error: 'malformed apply request' } };
591
+ }
592
+ const next = decodeSource(body.source, body.encoding);
593
+ if (next === null) {
594
+ return {
595
+ status: 400,
596
+ body: {
597
+ applied: false,
598
+ error: `unknown source encoding ${String(body.encoding)} — expected "utf8" or "base64"`,
599
+ },
600
+ };
601
+ }
602
+ settlePendingRecord(resolved, engineRoot);
603
+ const vendored = findVendoredTarget(resolved, engineRoot);
604
+ const current = readFileSync(resolved);
605
+ // Every path below this line reads `current`, which is now settled.
606
+ const currentSha = sha256(current);
607
+ if (currentSha !== body.ifMatchSha) {
608
+ return {
609
+ status: 409,
610
+ body: {
611
+ applied: false,
612
+ error: 'the file changed on disk since this edit was planned',
613
+ sha: currentSha,
614
+ },
615
+ };
616
+ }
617
+ if (vendored) {
618
+ const outcome = writeRecordedVendoredFile(
619
+ vendored,
620
+ next,
621
+ typeof body.note === 'string' ? body.note : undefined,
622
+ );
623
+ if (!outcome.ok) {
624
+ // The lock could not be brought along, so the bytes do not move either:
625
+ // an unrecordable edit to a vendored game is refused, never written.
626
+ return {
627
+ status: 409,
628
+ body: {
629
+ applied: false,
630
+ error: `the edit was not written — its divergence could not be recorded in ${vendored.id}'s lock: ${outcome.error}`,
631
+ },
632
+ };
633
+ }
634
+ invalidateWrittenSource(resolved);
635
+ return { body: { applied: true, sha: sha256(next), recorded: outcome.recorded } };
636
+ }
637
+ writeFileSync(resolved, next);
638
+ invalidateWrittenSource(resolved);
639
+ return { body: { applied: true, sha: sha256(next) } };
640
+ }
641
+
642
+ /** GET `/__ingest-source/ownership`. */
643
+ export function handleIngestOwnership(
644
+ projectRoot: string | undefined | null,
645
+ engineRoot: string,
646
+ ): HandlerResult {
647
+ return { body: ingestSourceOwnership(projectRoot, engineRoot) };
648
+ }