@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,115 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import type { ProductIdentity } from '@volter/editor-sdk/session/product-locator';
4
+
5
+ /**
6
+ * WHERE THE EDITOR'S FRAME ENTRY POINT IS — and it is the PRODUCT's, not the
7
+ * kit's.
8
+ *
9
+ * The module the Code-OSS contribution imports (`/__editor/served-modules`,
10
+ * routes/served-modules.ts) is `@vgai/game-editor`'s or `@vgai/model-editor`'s
11
+ * ONE source entry, which composes the product and re-exports `mountVgai`
12
+ * (`packages/editor/src/frame/product.ts`). The kit's own mount is
13
+ * `frame/bridge.tsx`'s `mountEditor`, which names no product and is not served
14
+ * to anybody.
15
+ *
16
+ * There is no constant here to spell it, and that is the point: which file it
17
+ * is depends on WHICH PRODUCT the project resolved, so the one source is the
18
+ * product's own `package.json#vgai.product.entry`
19
+ * (`@volter/editor-sdk/session/product-locator`). Three readers agree through it:
20
+ * the dev host builds a Vite URL from it, the packaged host finds it in the
21
+ * product's production build manifest by it, and
22
+ * `packages/editor/vite-product-build.ts` makes it that build's rollup input.
23
+ */
24
+
25
+ /** The entry as a path relative to `fromDir`, POSIX — which is what a Vite
26
+ * manifest key is, and what a dev-server URL is built from. */
27
+ export { productEntryPath } from '@volter/editor-sdk/session/product-locator';
28
+
29
+ /**
30
+ * The URL the packaged host serves the built product entry's CSS-loading
31
+ * wrapper at.
32
+ *
33
+ * A production build emits the entry's stylesheet as its own asset and nothing
34
+ * injects the `<link>`: under the frame there is no HTML of ours for Vite's
35
+ * HTML plugin to write into — the page is the workbench's. So the packaged host
36
+ * serves a three-line ES module that adds the entry's own stylesheets and
37
+ * re-exports the built chunk, and the door hands back THIS url. The
38
+ * contribution still imports one module and still reads `mountVgai` off it.
39
+ */
40
+ export const FRAME_BRIDGE_PACKAGED_PATH = '/__editor/frame-bridge.js';
41
+
42
+ /** What a production build emitted for the product entry, read off its manifest. */
43
+ export interface BuiltProductEntry {
44
+ /** The entry chunk's url under the served `dist/`, e.g. `/assets/product-a1b2.js`. */
45
+ readonly js: string;
46
+ /** Its own stylesheets, in the manifest's order. */
47
+ readonly css: readonly string[];
48
+ }
49
+
50
+ /**
51
+ * The product entry inside a product's `dist/`, or a throw naming the build.
52
+ *
53
+ * `build.manifest` is on for exactly this read (repo-root `vite.config.ts`) —
54
+ * the entry's file name is content-hashed, so the only honest way to find it is
55
+ * the manifest the build writes. A `dist/` cut before this product existed
56
+ * answers the door with this sentence rather than a 404 two layers down.
57
+ *
58
+ * THE KEY IS MATCHED BY SUFFIX, not spelled. A Vite manifest key is the entry
59
+ * module's path relative to the build's ROOT, and the root is the repo the
60
+ * build ran in — a fact this process, reading an INSTALLED product out of
61
+ * `node_modules`, has no way to reconstruct. What it does know is the
62
+ * product's own declaration (`./src/index.ts`), and that is the tail of the
63
+ * key whatever the build's root was. `isEntry` is what keeps the match honest:
64
+ * only a rollup entry may answer this door.
65
+ */
66
+ export function readBuiltProductEntry(
67
+ distPath: string,
68
+ product: ProductIdentity,
69
+ ): BuiltProductEntry {
70
+ const manifestPath = join(distPath, '.vite', 'manifest.json');
71
+ const rebuild = `npm run build -w ${product.name}`;
72
+ let manifest: Record<string, { file?: string; css?: string[]; isEntry?: boolean }>;
73
+ try {
74
+ manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as typeof manifest;
75
+ } catch (error) {
76
+ throw new Error(
77
+ `${manifestPath} is not readable (${error instanceof Error ? error.message : String(error)}), so this ` +
78
+ `session cannot find ${product.name}'s entry in its own production build. Rebuild it:\n ${rebuild}`,
79
+ );
80
+ }
81
+ const tail = product.entry.replace(/^\.\//, '');
82
+ const found = Object.entries(manifest).find(
83
+ ([key, value]) => value.isEntry === true && (key === tail || key.endsWith(`/${tail}`)),
84
+ );
85
+ const entry = found?.[1];
86
+ if (!entry || typeof entry.file !== 'string') {
87
+ throw new Error(
88
+ `${manifestPath} names no entry ending in ${tail}, so this ${product.name} build predates ` +
89
+ `its frame entry and cannot be framed. Rebuild it:\n ${rebuild}`,
90
+ );
91
+ }
92
+ return { js: `/${entry.file}`, css: (entry.css ?? []).map((file) => `/${file}`) };
93
+ }
94
+
95
+ /**
96
+ * The wrapper module the packaged host serves at
97
+ * {@link FRAME_BRIDGE_PACKAGED_PATH}: the built entry's stylesheets, then the
98
+ * built entry itself, re-exported whole so `mountVgai` is read off this module
99
+ * exactly as it is read off the dev one.
100
+ */
101
+ export function builtFrameBridgeModule(built: BuiltProductEntry): string {
102
+ const sheets = JSON.stringify(built.css);
103
+ return (
104
+ '// Generated per request by packages/editor/server/frame-bridge.ts — the\n' +
105
+ "// product's production build entry, with the stylesheets no HTML of ours injects.\n" +
106
+ `for (const href of ${sheets}) {\n` +
107
+ ' if (document.head.querySelector(`link[href="${href}"]`)) continue;\n' +
108
+ " const link = document.createElement('link');\n" +
109
+ " link.rel = 'stylesheet';\n" +
110
+ ' link.href = href;\n' +
111
+ ' document.head.appendChild(link);\n' +
112
+ '}\n' +
113
+ `export * from ${JSON.stringify(built.js)};\n`
114
+ );
115
+ }
@@ -0,0 +1,490 @@
1
+ /**
2
+ * THE ONE ORIGIN in front of two servers: the Code-OSS workbench and this
3
+ * session. It listens IN THE SESSION PROCESS — no spawn, no second program —
4
+ * exactly as the loopback Colyseus server does.
5
+ *
6
+ * /$product-segment/*, /static, /vscode-remote, … the workbench (the REH)
7
+ * everything else this session
8
+ *
9
+ * WHY A PROXY AND NOT TWO ORIGINS (measured 2026-09-19 against the REH). The
10
+ * REH stamps its own CSP on the workbench page
11
+ * (`createWorkbenchContentSecurityPolicy`, src/vs/server/node/webClientServer.ts):
12
+ *
13
+ * script-src 'self' 'unsafe-eval' blob: 'nonce-…' <sha> http://<the REH's own authority>
14
+ * connect-src 'self' ws: wss: https:
15
+ *
16
+ * The ONLY http origin on either list is the server's own. The editor's own
17
+ * entry module and every project module are imported as module scripts from
18
+ * this session, and every `/__editor/*` call is a fetch to it — so a session on
19
+ * a second port is refused by `script-src` before CORS is ever consulted, and
20
+ * its fetches by `connect-src` (which carries no `http:` at all). Relaxing that
21
+ * means editing a core service; the proxy costs none.
22
+ *
23
+ * CROSS-ORIGIN ISOLATION. Every response carries COOP `same-origin` and COEP
24
+ * `credentialless`, because the Blender build is `-sPROXY_TO_PTHREAD` and needs
25
+ * `SharedArrayBuffer`. The REH has no cross-origin-isolation flag or header
26
+ * hook of its own — `--enable-coi` is an ELECTRON-MAIN argument — so these
27
+ * headers are this proxy's. `credentialless` rather than `require-corp` so the
28
+ * workbench's own cross-origin loads keep working, the same choice `dev.ts`
29
+ * makes.
30
+ *
31
+ * THE WEBVIEW'S SECOND ORIGIN. VS Code loads every webview from
32
+ * `webviewExternalEndpoint`, which defaults to `https://{{uuid}}.vscode-cdn.net/…`
33
+ * — a host that does not exist for this fork and that a cross-origin-isolated
34
+ * page could not embed anyway. `IWorkbenchConstructionOptions.webviewEndpoint`
35
+ * is the supported door and the REH leaves it unset, so this rewrites the page
36
+ * config to `http://{{uuid}}.localhost:<port>`. It has to be a SUBDOMAIN and
37
+ * not this origin itself: `pre/index.html` refuses to start unless
38
+ * `location.hostname` IS the hash of `{parentOrigin, salt}` or begins with it,
39
+ * and `*.localhost` is the one wildcard host a browser resolves to loopback
40
+ * with no DNS. Two consequences handled here: the webview is genuinely
41
+ * cross-origin, so its responses need CORP `cross-origin` (without it the frame
42
+ * dies as `corp-not-same-origin-after-defaulted-to-same-origin-by-coep`, which
43
+ * Chrome renders as "refused to connect" and which cost an hour); and the REH's
44
+ * own `frame-src 'self' https://*.vscode-cdn.net` is widened on the way through.
45
+ *
46
+ * COMPRESSION IS THIS PROXY'S JOB, and it is the reason the frame's page weight
47
+ * is not the workbench's disk size. U3 measured `transferSize ===
48
+ * decodedBodySize` on every entry of a 41.75 MB page: the REH writes no
49
+ * `content-encoding` at all, and neither did this proxy. It negotiates
50
+ * `accept-encoding` now — brotli, then gzip — over text, JavaScript, CSS, JSON
51
+ * and wasm only; everything else is byte-for-byte.
52
+ */
53
+
54
+ import {
55
+ createServer,
56
+ request as httpRequest,
57
+ type IncomingMessage,
58
+ type Server,
59
+ type ServerResponse,
60
+ } from 'node:http';
61
+ import { connect as netConnect, type Socket } from 'node:net';
62
+ import { basename } from 'node:path';
63
+ import type { Transform } from 'node:stream';
64
+ import { pipeline } from 'node:stream/promises';
65
+ import { createBrotliCompress, createGzip, constants as zlibConstants } from 'node:zlib';
66
+
67
+ export interface FrameProxyOptions {
68
+ /** The one port a person opens: this proxy's. */
69
+ readonly port: number;
70
+ /** The Code-OSS workbench (REH) behind it. */
71
+ readonly upstreamPort: number;
72
+ /** This session's own port. */
73
+ readonly sessionPort: number;
74
+ /** The project the workbench opens; its folder name is the `?project=` id. */
75
+ readonly projectRoot: string;
76
+ /**
77
+ * Which way round the PRODUCT paints, from its own declaration
78
+ * (`package.json#vgai.product.colorTheme`, `@volter/editor-sdk/session/
79
+ * product-locator`), or `null` when this session could not resolve a product
80
+ * — in which case the page keeps the workbench's own web default and the
81
+ * `served-modules` door is what says why there is no product.
82
+ */
83
+ readonly colorTheme: 'dark' | 'light' | null;
84
+ readonly log: (line: string) => void;
85
+ }
86
+
87
+ export interface FrameProxy {
88
+ /** The url to open: this origin, on this project. */
89
+ readonly url: string;
90
+ close(): Promise<void>;
91
+ }
92
+
93
+ /**
94
+ * The workbench's own paths. `<product segment>` (`/oss-dev` out of a source
95
+ * checkout, the quality segment out of a build — `getServerProductSegment`) is
96
+ * DISCOVERED at boot rather than spelled here, because the page states it.
97
+ */
98
+ const VSCODE_PATH_BASE =
99
+ '^\\/$|^\\/(static|favicon|manifest\\.json|code-192|code-512|callback|oauth|out|extensions|builtin|remote|vscode-remote|_static|web-extension|version|delay-shutdown)';
100
+
101
+ /** What is worth compressing. Everything else goes through byte for byte. */
102
+ const COMPRESSIBLE =
103
+ /^(?:text\/|application\/(?:javascript|json|wasm|manifest\+json)|image\/svg\+xml)/;
104
+
105
+ /** `&quot;`-encoded HTML attribute value ↔ JSON, the way webClientServer writes it. */
106
+ const decodeAttr = (value: string): string =>
107
+ value
108
+ .replaceAll('&quot;', '"')
109
+ .replaceAll('&#39;', "'")
110
+ .replaceAll('&lt;', '<')
111
+ .replaceAll('&gt;', '>')
112
+ .replaceAll('&amp;', '&');
113
+ const encodeAttr = (value: string): string =>
114
+ value
115
+ .replaceAll('&', '&amp;')
116
+ .replaceAll('"', '&quot;')
117
+ .replaceAll("'", '&#39;')
118
+ .replaceAll('<', '&lt;')
119
+ .replaceAll('>', '&gt;');
120
+
121
+ /**
122
+ * Which encoding the browser asked for, in this proxy's order of preference.
123
+ * `null` means "send it as it is" — no `accept-encoding`, or none we write.
124
+ */
125
+ function negotiateEncoding(header: string | string[] | undefined): 'br' | 'gzip' | null {
126
+ const accepted = (Array.isArray(header) ? header.join(',') : (header ?? '')).toLowerCase();
127
+ if (accepted.includes('br')) return 'br';
128
+ if (accepted.includes('gzip')) return 'gzip';
129
+ return null;
130
+ }
131
+
132
+ /**
133
+ * Quality 5 rather than brotli's default 11. The default spends seconds on a
134
+ * multi-megabyte workbench chunk and this proxy compresses on the request path,
135
+ * with the person waiting; 5 is the knee where the ratio is nearly the same and
136
+ * the CPU is not.
137
+ */
138
+ function compressor(encoding: 'br' | 'gzip'): Transform {
139
+ return encoding === 'br'
140
+ ? createBrotliCompress({ params: { [zlibConstants.BROTLI_PARAM_QUALITY]: 5 } })
141
+ : createGzip({ level: 6 });
142
+ }
143
+
144
+ export async function startFrameProxy(options: FrameProxyOptions): Promise<FrameProxy> {
145
+ const { port, upstreamPort, sessionPort, projectRoot, colorTheme, log } = options;
146
+ const upstream = { host: '127.0.0.1', port: upstreamPort };
147
+ const session = { host: '127.0.0.1', port: sessionPort };
148
+ const upstreamOrigin = `http://${upstream.host}:${upstream.port}`;
149
+ const selfOrigin = `http://127.0.0.1:${port}`;
150
+ const webviewOriginTemplate = `http://{{uuid}}.localhost:${port}`;
151
+ const webviewOriginPattern = `http://*.localhost:${port}`;
152
+ const projectId = basename(projectRoot);
153
+
154
+ const isolation: Record<string, string> = {
155
+ 'Cross-Origin-Opener-Policy': 'same-origin',
156
+ 'Cross-Origin-Embedder-Policy': 'credentialless',
157
+ 'Cross-Origin-Resource-Policy': 'cross-origin',
158
+ };
159
+
160
+ let vscodePath = new RegExp(VSCODE_PATH_BASE);
161
+
162
+ /**
163
+ * THE DOCUMENT'S OWN COLOUR, before it has any styles at all.
164
+ *
165
+ * `initialColorTheme` below fixes the WORKBENCH's first paint, and that is not the page's
166
+ * first paint: measured 2026-09-21 on the live release, `html` and `body` compute
167
+ * `rgba(0, 0, 0, 0)` — upstream's `workbench.css` styles `.monaco-workbench` and nothing
168
+ * above it — so from the document's first frame until `Workbench.renderWorkbench` builds that
169
+ * element, the canvas is the BROWSER's default, which is white. One frame of it survived F1's
170
+ * first reading (frame 0 at 0.0 s white, frame 1 at 0.5 s already the product's splash).
171
+ *
172
+ * `color-scheme` is the platform's own answer to exactly that question, and it is why this is
173
+ * a meta tag and not a background rule: it hands the browser the product's `dark`/`light`
174
+ * declaration UNCHANGED and lets it paint its own dark canvas, so nothing here becomes a
175
+ * second author of a palette value. The workbench sets `color-scheme` itself once its theme
176
+ * loads; this only fills the window before that.
177
+ */
178
+ const colorSchemeMeta = (html: string): string =>
179
+ colorTheme === null
180
+ ? html
181
+ : html.replace('<head>', `<head>\n\t\t<meta name="color-scheme" content="${colorTheme}">`);
182
+
183
+ /** Rewrite the workbench page's own configuration for THIS origin.
184
+ *
185
+ * - `remoteAuthority` needs NOTHING here, and that is worth stating: the REH
186
+ * derives it from the request's HOST header (measured — a direct fetch to
187
+ * the REH reports its own authority, the same fetch through this proxy
188
+ * reports this one), so forwarding the original Host is already what makes
189
+ * the management websocket, the `vscode-remote://` file system, every
190
+ * `vscode-remote-resource` url AND the page's own CSP address this origin.
191
+ * - `webviewEndpoint` is set (see the header).
192
+ * - `initialColorTheme` is set (see below). */
193
+ const patchWorkbenchConfig = (html: string): string => {
194
+ const webBaseUrl =
195
+ html.match(/id="vscode-workbench-web-base-url" data-settings="([^"]*)"/)?.[1] ?? '/static';
196
+ return html.replace(
197
+ /(id="vscode-workbench-web-configuration" data-settings=")([^"]*)(")/,
198
+ (_all, head: string, value: string, tail: string) => {
199
+ const config = JSON.parse(decodeAttr(value)) as Record<string, unknown>;
200
+ config['webviewEndpoint'] =
201
+ `${webviewOriginTemplate}${decodeAttr(webBaseUrl)}/out/vs/workbench/contrib/webview/browser/pre/`;
202
+ // THE FIRST PAINT IS THE PRODUCT'S, NOT THE WEB DEFAULT'S. Measured
203
+ // 2026-09-21 against both releases: with nothing here the page's first
204
+ // frame is LIGHT — `workbenchThemeService` falls back to
205
+ // `isWeb ? ColorScheme.LIGHT : ColorScheme.DARK` when it has no stored
206
+ // theme — so the product's opening cover, every colour of which is a
207
+ // `--vscode-*` variable by design, was WHITE from the first frame until
208
+ // the real theme loaded seconds later, and then flipped.
209
+ //
210
+ // `IWorkbenchConstructionOptions.initialColorTheme` is the supported
211
+ // door and the REH leaves it unset, the same shape as `webviewEndpoint`
212
+ // above. It has to be HERE and not in a setting or an extension: the
213
+ // theme service reads it in its constructor, before any extension is
214
+ // registered, which is exactly the window the cover lives in. The
215
+ // themeType strings ARE `ColorScheme`'s values (`dark`, `light`).
216
+ //
217
+ // The colour comes from the PRODUCT's own declaration and nothing else
218
+ // (`package.json#vgai.product.colorTheme`), and it is a FALLBACK in the
219
+ // workbench's own order: a person who has already picked a theme has it
220
+ // in storage, and `ColorThemeData.fromStorageData` is preferred over
221
+ // this on every open after the first.
222
+ if (colorTheme !== null) config['initialColorTheme'] = { themeType: colorTheme };
223
+ return head + encodeAttr(JSON.stringify(config)) + tail;
224
+ },
225
+ );
226
+ };
227
+
228
+ const sendText = (res: ServerResponse, status: number, body: string, type: string): void => {
229
+ res.writeHead(status, { ...isolation, 'content-type': type, 'cache-control': 'no-store' });
230
+ res.end(body);
231
+ };
232
+
233
+ /** An unknown `?project=` says so by name rather than opening an empty workbench. */
234
+ const refuseProject = (res: ServerResponse, id: string): void => {
235
+ sendText(
236
+ res,
237
+ 404,
238
+ `<!doctype html><meta charset="utf-8"><title>no such project</title>` +
239
+ `<body style="font:14px system-ui;padding:2rem"><h1>No project "${encodeAttr(id)}" is open here.</h1>` +
240
+ `<p>This workbench is the session for <code>${encodeAttr(projectRoot)}</code>, whose id is ` +
241
+ `<code>${encodeAttr(projectId)}</code>.</p>`,
242
+ 'text/html; charset=utf-8',
243
+ );
244
+ };
245
+
246
+ const handleRequest = (req: IncomingMessage, res: ServerResponse): void => {
247
+ const url = new URL(req.url ?? '/', selfOrigin);
248
+ const pathname = url.pathname;
249
+ // THE ONE HOSTED BOOT PARAM, ONTO THE WORKBENCH'S OWN. `?project=<id>` is
250
+ // what a link to the vgai editor carries; the workbench's own boot contract
251
+ // is `?folder=<path>` (`WorkspaceProvider.create`, which reads a bare path
252
+ // against `remoteAuthority`). This is a REDIRECT and not an injected
253
+ // `folderUri`, and the reason was measured (2026-09-19): under this shape
254
+ // the workbench page is ALSO the vgai editor's page, and the editor's boot
255
+ // refuses `?project=` on a session-backed surface by name — "project
256
+ // identity does NOT live in the URL on a local editor"
257
+ // (`assertNoRemovedBootParams`, packages/editor/src/boot-routing.ts). The
258
+ // redirect hands the page a url both halves accept.
259
+ if (pathname === '/') {
260
+ const id = url.searchParams.get('project');
261
+ if (id && !url.searchParams.has('folder') && !url.searchParams.has('workspace')) {
262
+ if (id !== projectId) {
263
+ refuseProject(res, id);
264
+ return;
265
+ }
266
+ const next = new URL(url);
267
+ next.searchParams.delete('project');
268
+ next.searchParams.set('folder', projectRoot);
269
+ res.writeHead(302, {
270
+ ...isolation,
271
+ location: `${next.pathname}${next.search}`,
272
+ 'cache-control': 'no-store',
273
+ });
274
+ res.end();
275
+ return;
276
+ }
277
+ }
278
+
279
+ const target = vscodePath.test(pathname) ? upstream : session;
280
+ const encoding = negotiateEncoding(req.headers['accept-encoding']);
281
+ const forward = httpRequest(
282
+ { ...target, method: req.method, path: req.url, headers: req.headers },
283
+ (answer) => {
284
+ const headers: Record<string, string | string[]> = {};
285
+ for (const [key, value] of Object.entries(answer.headers)) {
286
+ if (value !== undefined) headers[key] = value;
287
+ }
288
+ delete headers['cross-origin-opener-policy'];
289
+ delete headers['cross-origin-embedder-policy'];
290
+ delete headers['cross-origin-resource-policy'];
291
+ // The webview's second origin, onto the REH's own `frame-src`.
292
+ const csp = headers['content-security-policy'];
293
+ if (typeof csp === 'string' && csp.includes('frame-src')) {
294
+ // GLTFLoader fetches local blob textures; img-src alone cannot
295
+ // authorize that fetch. Media previews use local blobs as well.
296
+ headers['content-security-policy'] = csp
297
+ .replace(/frame-src([^;]*)/, `frame-src$1 ${webviewOriginPattern}`)
298
+ .replace(/connect-src([^;]*)/, 'connect-src$1 blob:')
299
+ .replace(/media-src([^;]*)/, 'media-src$1 blob:');
300
+ }
301
+ const type = String(headers['content-type'] ?? '');
302
+ const alreadyEncoded = headers['content-encoding'] !== undefined;
303
+ // The workbench HTML and its config spell the upstream's OWN origin
304
+ // into absolute script and endpoint URLs; through this origin those are
305
+ // cross-origin and CORS refuses them. Text bodies are re-spelled here,
306
+ // which needs the whole body — so this branch buffers and the streaming
307
+ // one below does not.
308
+ if (/text\/html|javascript|json/.test(type) && !alreadyEncoded) {
309
+ const chunks: Buffer[] = [];
310
+ answer.on('data', (chunk: Buffer) => chunks.push(chunk));
311
+ answer.on('end', () => {
312
+ let body = Buffer.concat(chunks)
313
+ .toString('utf8')
314
+ .replaceAll(upstreamOrigin, selfOrigin);
315
+ if (pathname === '/' && target === upstream && /text\/html/.test(type)) {
316
+ body = colorSchemeMeta(patchWorkbenchConfig(body));
317
+ }
318
+ delete headers['content-length'];
319
+ const raw = Buffer.from(body, 'utf8');
320
+ if (encoding === null) {
321
+ res.writeHead(answer.statusCode ?? 502, {
322
+ ...headers,
323
+ ...isolation,
324
+ 'content-length': raw.byteLength,
325
+ });
326
+ res.end(raw);
327
+ return;
328
+ }
329
+ res.writeHead(answer.statusCode ?? 502, {
330
+ ...headers,
331
+ ...isolation,
332
+ 'content-encoding': encoding,
333
+ vary: 'accept-encoding',
334
+ });
335
+ const stream = compressor(encoding);
336
+ stream.pipe(res);
337
+ stream.end(raw);
338
+ });
339
+ return;
340
+ }
341
+ if (encoding !== null && !alreadyEncoded && COMPRESSIBLE.test(type)) {
342
+ delete headers['content-length'];
343
+ res.writeHead(answer.statusCode ?? 502, {
344
+ ...headers,
345
+ ...isolation,
346
+ 'content-encoding': encoding,
347
+ vary: 'accept-encoding',
348
+ });
349
+ void pipeline(answer, compressor(encoding), res).catch(() => res.destroy());
350
+ return;
351
+ }
352
+ res.writeHead(answer.statusCode ?? 502, { ...headers, ...isolation });
353
+ answer.pipe(res);
354
+ },
355
+ );
356
+ forward.on('error', (error) => {
357
+ if (!res.headersSent) {
358
+ sendText(
359
+ res,
360
+ 502,
361
+ `upstream ${target.port}: ${error.message}`,
362
+ 'text/plain; charset=utf-8',
363
+ );
364
+ } else res.destroy();
365
+ });
366
+ // A browser that goes away takes its upstream request with it — otherwise a
367
+ // dead tab's event stream stays open, this session keeps that tab blessed,
368
+ // and EVERY later tab lands on `/__editor/tab-yielded` (measured
369
+ // 2026-09-19 in the session journal).
370
+ res.on('close', () => forward.destroy());
371
+ req.pipe(forward);
372
+ };
373
+
374
+ const handleUpgrade = (req: IncomingMessage, socket: Socket, head: Buffer): void => {
375
+ const target = vscodePath.test(new URL(req.url ?? '/', selfOrigin).pathname)
376
+ ? upstream
377
+ : session;
378
+ const proxied = netConnect(target.port, target.host, () => {
379
+ proxied.write(
380
+ `${req.method} ${req.url} HTTP/${req.httpVersion}\r\n` +
381
+ Object.entries(req.headers)
382
+ .map(([key, value]) => `${key}: ${Array.isArray(value) ? value.join(', ') : value}`)
383
+ .join('\r\n') +
384
+ '\r\n\r\n',
385
+ );
386
+ if (head.length) proxied.write(head);
387
+ socket.pipe(proxied).pipe(socket);
388
+ });
389
+ proxied.on('error', () => socket.destroy());
390
+ socket.on('error', () => proxied.destroy());
391
+ };
392
+
393
+ /**
394
+ * Wait for the upstream to report its shape before accepting requests. The REH serves its static
395
+ * assets under a PRODUCT SEGMENT (`/oss-dev/static` out of a source checkout,
396
+ * `/<quality>/static` out of a build), and this cannot route without knowing
397
+ * it. The page itself states it in `vscode-workbench-web-base-url`, so it is
398
+ * read rather than spelled.
399
+ */
400
+ const discoverUpstream = (): Promise<string | null> =>
401
+ new Promise((done) => {
402
+ const probe = httpRequest({ ...upstream, path: '/' }, (answer) => {
403
+ const chunks: Buffer[] = [];
404
+ answer.on('data', (chunk: Buffer) => chunks.push(chunk));
405
+ answer.on('end', () => {
406
+ const html = Buffer.concat(chunks).toString('utf8');
407
+ const base = html.match(
408
+ /id="vscode-workbench-web-base-url" data-settings="([^"]*)"/,
409
+ )?.[1];
410
+ done(answer.statusCode === 200 && base ? decodeAttr(base).replace(/\/static\/?$/, '') : null);
411
+ });
412
+ });
413
+ probe.on('error', () => done(null));
414
+ probe.setTimeout(3_000, () => {
415
+ probe.destroy();
416
+ done(null);
417
+ });
418
+ probe.end();
419
+ });
420
+
421
+ // A listening socket is not proof that Code-OSS can serve its HTML yet.
422
+ // Never expose a half-configured proxy: unknown prefixes route native JS to
423
+ // the session server and produce a blank workbench with script 404s.
424
+ const discoveryDeadline = Date.now() + 30_000;
425
+ let segment: string | null = null;
426
+ do {
427
+ segment = await discoverUpstream();
428
+ if (segment !== null) break;
429
+ await new Promise(resolve => setTimeout(resolve, 100));
430
+ } while (Date.now() < discoveryDeadline);
431
+ if (segment === null) throw new Error(
432
+ `Code-OSS on port ${upstream.port} did not report its workbench asset base within 30s; refusing to start an incorrectly routed proxy.`,
433
+ );
434
+ if (segment) {
435
+ vscodePath = new RegExp(
436
+ `${VSCODE_PATH_BASE}|^${segment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(\\/|$)`,
437
+ );
438
+ log(`frame: workbench product segment ${segment}`);
439
+ }
440
+
441
+ // ONE handler, TWO loopback listeners — 127.0.0.1 and ::1. The webview's
442
+ // origin is a `*.localhost` subdomain (see the header), and macOS answers
443
+ // `<anything>.localhost` with the IPv6 `::1` as well as 127.0.0.1
444
+ // (`dscacheutil -q host -a name x.localhost`); a browser that picks the IPv6
445
+ // address finds nothing listening and the webview iframe fails as
446
+ // `chrome-error://chromewebdata` with no message at all — measured
447
+ // 2026-09-19 against a proxy bound to 127.0.0.1 alone.
448
+ const servers: Server[] = [];
449
+ await new Promise<void>((ready, failed) => {
450
+ let settled = false;
451
+ for (const host of ['127.0.0.1', '::1']) {
452
+ const one = createServer(handleRequest);
453
+ one.on('upgrade', handleUpgrade);
454
+ one.on('error', (error) => {
455
+ if (host === '::1') {
456
+ log(
457
+ `frame: no IPv6 loopback listener (${error.message}); webviews need one if the browser resolves *.localhost to ::1`,
458
+ );
459
+ return;
460
+ }
461
+ if (!settled) {
462
+ settled = true;
463
+ failed(error);
464
+ }
465
+ });
466
+ servers.push(one);
467
+ one.listen(port, host, () => {
468
+ if (!settled) {
469
+ settled = true;
470
+ ready();
471
+ }
472
+ });
473
+ }
474
+ });
475
+
476
+ return {
477
+ url: `${selfOrigin}/?project=${encodeURIComponent(projectId)}`,
478
+ close: async () => {
479
+ await Promise.all(
480
+ servers.map(
481
+ (one) =>
482
+ new Promise<void>((done) => {
483
+ one.close(() => done());
484
+ one.closeAllConnections?.();
485
+ }),
486
+ ),
487
+ );
488
+ },
489
+ };
490
+ }