@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.
- package/BUNDLED_NOTICES +1527 -0
- package/LICENSE +686 -0
- package/LICENSE-APACHE +202 -0
- package/NOTICE +18 -0
- package/README.md +24 -0
- package/dist/build/chunk-JS4D4XZ3.js +175 -0
- package/dist/build/chunk-JS4D4XZ3.js.map +7 -0
- package/dist/build/vite-plugin-product-contributions.js +100 -0
- package/dist/build/vite-plugin-product-contributions.js.map +7 -0
- package/dist/build/vite-plugin-shared-react.js +25 -0
- package/dist/build/vite-plugin-shared-react.js.map +7 -0
- package/dist/build/vite-plugin-shared-three.js +86 -0
- package/dist/build/vite-plugin-shared-three.js.map +7 -0
- package/dist/server/chunk-KMJC7AGO.js +98 -0
- package/dist/server/chunk-KMJC7AGO.js.map +7 -0
- package/dist/server/chunk-PSILUMGS.js +46 -0
- package/dist/server/chunk-PSILUMGS.js.map +7 -0
- package/dist/server/frame-proxy.js +255 -0
- package/dist/server/frame-proxy.js.map +7 -0
- package/dist/server/open-browser.js +53 -0
- package/dist/server/open-browser.js.map +7 -0
- package/dist/server/process-shutdown.js +127 -0
- package/dist/server/process-shutdown.js.map +7 -0
- package/dist/server/session-registry.js +141 -0
- package/dist/server/session-registry.js.map +7 -0
- package/dist/server/spawn-opener.js +11 -0
- package/dist/server/spawn-opener.js.map +7 -0
- package/dist/server/worktree-identity.js +11 -0
- package/dist/server/worktree-identity.js.map +7 -0
- package/dist-server/packaged.mjs +88816 -0
- package/package.json +118 -0
- package/scripts/build-plugins.mjs +14 -0
- package/scripts/build-server.mjs +26 -0
- package/scripts/build-session.mjs +9 -0
- package/server/account-credentials.ts +60 -0
- package/server/account-service.ts +1434 -0
- package/server/adapter-region-includes.ts +47 -0
- package/server/asset-catalog-v2.ts +175 -0
- package/server/asset-history-snapshots.ts +196 -0
- package/server/asset-ledger-store.ts +195 -0
- package/server/asset-library-routes.ts +1595 -0
- package/server/blender-wasm-artifact.ts +430 -0
- package/server/boot-timings.ts +106 -0
- package/server/canonical-path.ts +50 -0
- package/server/checkout-workspace-preflight.ts +349 -0
- package/server/cloud-asset-catalog.ts +158 -0
- package/server/coding-inference-launch.ts +237 -0
- package/server/collaboration-account-client.ts +202 -0
- package/server/collaboration-attribution.ts +122 -0
- package/server/collaboration-session.ts +934 -0
- package/server/comfyui-bridge.ts +248 -0
- package/server/console-ledger.ts +499 -0
- package/server/creation-site-transform.ts +304 -0
- package/server/creation-site-write.ts +648 -0
- package/server/data-file-serialize.ts +158 -0
- package/server/editor-brand-html.ts +72 -0
- package/server/editor-control-socket.ts +366 -0
- package/server/editor-server-options.ts +190 -0
- package/server/editor-server.ts +1483 -0
- package/server/editor-sse.ts +352 -0
- package/server/engine-provenance.ts +169 -0
- package/server/engine-source-restart.ts +117 -0
- package/server/frame-bridge.ts +115 -0
- package/server/frame-proxy.ts +490 -0
- package/server/frame-workbench.ts +259 -0
- package/server/frontend-handoff.ts +229 -0
- package/server/game-globals-shadow.ts +113 -0
- package/server/gameplay-session-retention.ts +149 -0
- package/server/gameplay-sessions.ts +123 -0
- package/server/generation-jobs.ts +201 -0
- package/server/generation-reconciler.ts +137 -0
- package/server/generative-execution-context.ts +59 -0
- package/server/git-workflow.ts +612 -0
- package/server/harness-chat-caller.ts +36 -0
- package/server/harness-chat-service.ts +1681 -0
- package/server/idle-shutdown.ts +170 -0
- package/server/js-profiling-policy.ts +52 -0
- package/server/launcher-settings.ts +84 -0
- package/server/local-asset-catalog.ts +410 -0
- package/server/managed-account-defaults.ts +22 -0
- package/server/mock-control-plane.ts +540 -0
- package/server/model-import-conversion.ts +345 -0
- package/server/native-credential-store.ts +162 -0
- package/server/open-browser.ts +118 -0
- package/server/packaged.ts +1192 -0
- package/server/play-stall.ts +126 -0
- package/server/process-shutdown.ts +218 -0
- package/server/product-presets.ts +55 -0
- package/server/project-build-artifact.ts +95 -0
- package/server/project-components.ts +100 -0
- package/server/project-dependency-invalidation.ts +114 -0
- package/server/project-file-scan.ts +235 -0
- package/server/project-hmr-files.ts +215 -0
- package/server/project-install-roots.ts +210 -0
- package/server/project-kinds.ts +71 -0
- package/server/project-mcp-servers.ts +82 -0
- package/server/project-module-freshness.ts +109 -0
- package/server/project-module-instance.ts +375 -0
- package/server/project-optimize-deps-entries.ts +827 -0
- package/server/project-output-writer.ts +679 -0
- package/server/project-package-origin.ts +63 -0
- package/server/project-root-surface.ts +831 -0
- package/server/project-scratch-path.ts +47 -0
- package/server/project-script-hmr.ts +619 -0
- package/server/project-serving-plugins.ts +236 -0
- package/server/project-tools.ts +653 -0
- package/server/project-validation.ts +250 -0
- package/server/project-verbs.ts +127 -0
- package/server/project-view.ts +52 -0
- package/server/project-watch.ts +1134 -0
- package/server/project-work-coordinator.ts +288 -0
- package/server/provider-credentials.ts +331 -0
- package/server/recent-projects-store.ts +98 -0
- package/server/redact-secrets.ts +71 -0
- package/server/repository-presence.ts +267 -0
- package/server/routes/account.ts +357 -0
- package/server/routes/agents.ts +60 -0
- package/server/routes/assets.ts +154 -0
- package/server/routes/build.ts +13 -0
- package/server/routes/collaboration.ts +595 -0
- package/server/routes/configurations.ts +419 -0
- package/server/routes/context.ts +264 -0
- package/server/routes/control-plane.ts +1811 -0
- package/server/routes/logs.ts +272 -0
- package/server/routes/project-identity.ts +302 -0
- package/server/routes/project-open.ts +429 -0
- package/server/routes/project-source.ts +686 -0
- package/server/routes/project-state.ts +383 -0
- package/server/routes/relay.ts +1029 -0
- package/server/routes/route-helpers.ts +29 -0
- package/server/routes/served-modules.ts +138 -0
- package/server/routes/session-tabs.ts +196 -0
- package/server/routes/settings.ts +121 -0
- package/server/routes/share-control.ts +486 -0
- package/server/routes/themes.ts +116 -0
- package/server/routes/tools.ts +230 -0
- package/server/routes/worktrees.ts +595 -0
- package/server/scoped-game-css.ts +461 -0
- package/server/server-utils.ts +1194 -0
- package/server/session-product.ts +112 -0
- package/server/session-registry.ts +230 -0
- package/server/share-claims.ts +138 -0
- package/server/share-host.ts +526 -0
- package/server/share-session-gateway.ts +1362 -0
- package/server/share-tunnel.ts +123 -0
- package/server/spawn-opener.ts +74 -0
- package/server/support/play/log-format.ts +76 -0
- package/server/support/play/session-record.ts +199 -0
- package/server/support/project/build-discipline.ts +718 -0
- package/server/support/project/inspection-node.ts +119 -0
- package/server/support/project/log-naming.ts +54 -0
- package/server/support/project/provenance.ts +290 -0
- package/server/support/project/run-name.ts +18 -0
- package/server/support/project/session-journal.ts +830 -0
- package/server/support/project/shared.ts +327 -0
- package/server/tab-bootstrap.ts +62 -0
- package/server/tab-heartbeat.ts +477 -0
- package/server/tab-lifecycle.ts +550 -0
- package/server/tab-presence.ts +1508 -0
- package/server/team-agent-mirror.ts +95 -0
- package/server/twin-auth.ts +138 -0
- package/server/vendored-lock-recorder.ts +968 -0
- package/server/worktree-identity.ts +121 -0
- package/server/worktree-management.ts +398 -0
- package/server/worktree-retention.d.mts +13 -0
- package/server/worktree-retention.mjs +205 -0
- package/src/EditorContext.tsx +169 -0
- package/src/account.ts +333 -0
- package/src/action-registry.ts +532 -0
- package/src/active-product.ts +74 -0
- package/src/active-project.ts +155 -0
- package/src/adapter-editor-config.ts +25 -0
- package/src/adapter-observation.ts +49 -0
- package/src/animation/stage-transport.ts +379 -0
- package/src/animation/three-clips-subject.ts +172 -0
- package/src/api/asset-library-wire.ts +45 -0
- package/src/api/assets.ts +365 -0
- package/src/api/base.ts +10 -0
- package/src/api/build.ts +99 -0
- package/src/api/git-wire.ts +56 -0
- package/src/api/logs.ts +92 -0
- package/src/api/project-identity.ts +74 -0
- package/src/api/project-open.ts +355 -0
- package/src/api/project-source.ts +162 -0
- package/src/api/project-state.ts +107 -0
- package/src/api/relay.ts +268 -0
- package/src/api/settings.ts +36 -0
- package/src/api/themes.ts +45 -0
- package/src/api/worktrees.ts +257 -0
- package/src/asset-compare-core.ts +171 -0
- package/src/asset-compare.ts +294 -0
- package/src/asset-editor-context.tsx +100 -0
- package/src/asset-events.ts +97 -0
- package/src/asset-inspector-actions.ts +87 -0
- package/src/asset-preview-framing.ts +357 -0
- package/src/asset-preview.ts +2802 -0
- package/src/asset-selection-viewer-registry.ts +113 -0
- package/src/asset-selection.ts +133 -0
- package/src/asset-workflow/asset-capabilities.ts +344 -0
- package/src/asset-workflow/asset-import-jobs.ts +106 -0
- package/src/asset-workflow/asset-ledger-backend.ts +126 -0
- package/src/asset-workflow/asset-ledger.ts +156 -0
- package/src/asset-workflow/asset-materialization-report.ts +140 -0
- package/src/asset-workflow/asset-pack-manifest.ts +320 -0
- package/src/asset-workflow/asset-types.ts +142 -0
- package/src/asset-workflow/asset-workflow-quality.ts +61 -0
- package/src/asset-workflow/audio-preview-player.ts +193 -0
- package/src/asset-workflow/audio-waveform.ts +22 -0
- package/src/asset-workflow/cloud-asset-client.ts +263 -0
- package/src/asset-workflow/folder-preview.ts +345 -0
- package/src/asset-workflow/hosted-asset-materialization.ts +236 -0
- package/src/asset-workflow/image-view-scale.ts +32 -0
- package/src/asset-workflow/import-contract.ts +124 -0
- package/src/asset-workflow/ledger-write-lock.ts +244 -0
- package/src/asset-workflow/model-inspection.ts +818 -0
- package/src/asset-workflow/pixi-spritesheet.ts +197 -0
- package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
- package/src/asset-workflow/project-asset-commands.ts +23 -0
- package/src/asset-workflow/project-asset-health.ts +139 -0
- package/src/asset-workflow/project-asset-operations.ts +154 -0
- package/src/asset-workflow/project-asset-roots.ts +68 -0
- package/src/asset-workflow/project-content.ts +288 -0
- package/src/asset-workflow/project-source-index.ts +550 -0
- package/src/asset-workflow/thumbnail-system.ts +256 -0
- package/src/authoring/active-adapter.ts +199 -0
- package/src/authoring/active-systems.ts +422 -0
- package/src/authoring/adapter-key.ts +18 -0
- package/src/authoring/authoring-asset-url.ts +27 -0
- package/src/authoring/bootstrap-state.ts +49 -0
- package/src/authoring/boundary-authoring-adapter.ts +184 -0
- package/src/authoring/breakpoint-state.ts +43 -0
- package/src/authoring/canvas-scene-guides.ts +76 -0
- package/src/authoring/component-instance-root.ts +171 -0
- package/src/authoring/composite-authoring-adapter.ts +2110 -0
- package/src/authoring/consumer-actions.ts +520 -0
- package/src/authoring/css-numeric-style.ts +97 -0
- package/src/authoring/design-time-layers.ts +849 -0
- package/src/authoring/design-time-mount-registry.ts +235 -0
- package/src/authoring/design-time-settle.ts +343 -0
- package/src/authoring/edit-mode-authoring.ts +619 -0
- package/src/authoring/eyedropper-session.ts +60 -0
- package/src/authoring/instance-source-menu-register.ts +13 -0
- package/src/authoring/instance-source-menu.ts +135 -0
- package/src/authoring/layered-pick.ts +183 -0
- package/src/authoring/live-gesture-lock.ts +50 -0
- package/src/authoring/live-object-transform.ts +62 -0
- package/src/authoring/mount-failure-report.ts +154 -0
- package/src/authoring/mounted-root-subjects.ts +144 -0
- package/src/authoring/no-authoring-adapter.ts +55 -0
- package/src/authoring/null-inspection-subjects.tsx +75 -0
- package/src/authoring/object3d-document-persistence.ts +106 -0
- package/src/authoring/object3d-document-session-registry.ts +120 -0
- package/src/authoring/object3d-document-session.ts +1326 -0
- package/src/authoring/object3d-gesture-controller.ts +113 -0
- package/src/authoring/panel-authoring.ts +121 -0
- package/src/authoring/prefab-instance-inspector-section.tsx +237 -0
- package/src/authoring/prefab-instance-section-model.ts +55 -0
- package/src/authoring/project-authoring-session.ts +105 -0
- package/src/authoring/provenance.ts +99 -0
- package/src/authoring/quarks-particle-systems.ts +19 -0
- package/src/authoring/react-canvas-navigation.ts +255 -0
- package/src/authoring/react-design-canvas-style.ts +20 -0
- package/src/authoring/react-story-board.ts +937 -0
- package/src/authoring/selection-scope.ts +195 -0
- package/src/authoring/shell-document-ops.ts +169 -0
- package/src/authoring/shell-object3d-document-write-policy.ts +108 -0
- package/src/authoring/shell-viewport-policy.ts +48 -0
- package/src/authoring/source-object3d-authoring-adapter.ts +526 -0
- package/src/authoring/stories-scope.ts +35 -0
- package/src/authoring/story-board-chrome-fit.ts +107 -0
- package/src/authoring/story-board-presentation.ts +111 -0
- package/src/authoring/three-projection-core.ts +226 -0
- package/src/authoring/viewport-pick-context.ts +40 -0
- package/src/authoring/viewport-raycast.ts +240 -0
- package/src/authoring/viewport-tool-context.ts +73 -0
- package/src/authoring/world-canvas-viewport-state.ts +35 -0
- package/src/authoring/world-hidden-viewport.ts +152 -0
- package/src/authoring/world-pan-state.ts +198 -0
- package/src/authoring/world-session-state.ts +101 -0
- package/src/authoring/write-pipe.ts +173 -0
- package/src/availability-tick.ts +66 -0
- package/src/bitmap-label.ts +120 -0
- package/src/blender-tab-metrics.ts +161 -0
- package/src/board-open-actions.ts +20 -0
- package/src/boot-routing.ts +391 -0
- package/src/build-identity.ts +15 -0
- package/src/bytes-codec.ts +62 -0
- package/src/camera-authoring.ts +175 -0
- package/src/cancellation-reason.ts +58 -0
- package/src/canvas-preview-frames.ts +482 -0
- package/src/capture-camera-pose.ts +77 -0
- package/src/chrome-registry.ts +159 -0
- package/src/chrome-slot-registry.ts +91 -0
- package/src/collaboration-client.ts +264 -0
- package/src/collaboration-presence.ts +41 -0
- package/src/command-dispatch.ts +19 -0
- package/src/command-listener.ts +2743 -0
- package/src/command-registry.ts +70 -0
- package/src/component-board-registry.ts +205 -0
- package/src/component-states-registry.ts +200 -0
- package/src/components/AgentPresentationNotice.tsx +75 -0
- package/src/components/AlignToolbar.tsx +204 -0
- package/src/components/AppRoot.tsx +394 -0
- package/src/components/ApplicationMenus.tsx +415 -0
- package/src/components/AssetBrowser.tsx +2843 -0
- package/src/components/AssetEditorShell.tsx +216 -0
- package/src/components/AssetInspectorToolSection.tsx +124 -0
- package/src/components/BoardRulers.tsx +354 -0
- package/src/components/CameraInfo.tsx +81 -0
- package/src/components/CanvasSceneViewport.tsx +556 -0
- package/src/components/CapabilityCoverageSection.tsx +185 -0
- package/src/components/CenterDocuments.tsx +22 -0
- package/src/components/ChromeSlot.tsx +20 -0
- package/src/components/CodeView.tsx +470 -0
- package/src/components/CollaborationHeaderControl.css +74 -0
- package/src/components/CompactInspectorCard.tsx +190 -0
- package/src/components/CompactInspectorShell.tsx +39 -0
- package/src/components/ConsolePanel.css +55 -0
- package/src/components/ConsolePanel.tsx +270 -0
- package/src/components/DefaultEditorLayout.tsx +106 -0
- package/src/components/DocumentHeaderStrip.tsx +96 -0
- package/src/components/DocumentShelfRail.tsx +45 -0
- package/src/components/DocumentThumbnail.tsx +345 -0
- package/src/components/EditorLeaseGuard.tsx +372 -0
- package/src/components/ErrorBanner.tsx +123 -0
- package/src/components/FolderPreviewTile.tsx +159 -0
- package/src/components/GameHierarchy.tsx +3842 -0
- package/src/components/GameplaySessionTimeline.tsx +295 -0
- package/src/components/InspectionProjection.tsx +968 -0
- package/src/components/Inspector.tsx +233 -0
- package/src/components/InspectorCanvasPreview.tsx +35 -0
- package/src/components/InspectorFieldsSection.tsx +290 -0
- package/src/components/InspectorObjectPreview.tsx +57 -0
- package/src/components/InspectorStoriesSection.tsx +92 -0
- package/src/components/InspectorToolSection.tsx +96 -0
- package/src/components/InspectorTransformSection.tsx +245 -0
- package/src/components/LightExplorerPanel.tsx +433 -0
- package/src/components/MediaProperties.tsx +145 -0
- package/src/components/NonThreeAuthoringBootstrap.tsx +19 -0
- package/src/components/Object3DDocumentToolbar.css +100 -0
- package/src/components/Object3DDocumentToolbar.tsx +454 -0
- package/src/components/Object3DDocumentViewport.tsx +58 -0
- package/src/components/ProjectHeader.css +617 -0
- package/src/components/ProjectHeader.tsx +328 -0
- package/src/components/ProjectLayout.tsx +249 -0
- package/src/components/ReactCanvasControls.tsx +284 -0
- package/src/components/RootSelectionOverlay.tsx +3162 -0
- package/src/components/RootTextEditor.tsx +79 -0
- package/src/components/SaveStatus.tsx +70 -0
- package/src/components/StageHost.tsx +1954 -0
- package/src/components/StageOverlays.tsx +21 -0
- package/src/components/StartupErrorScreen.tsx +76 -0
- package/src/components/StartupLoadingScreen.tsx +65 -0
- package/src/components/StatsOverlay.tsx +78 -0
- package/src/components/SurfaceStateOverlay.tsx +24 -0
- package/src/components/ToolContributionSurfaces.tsx +65 -0
- package/src/components/ToolHost.tsx +370 -0
- package/src/components/ToolObject3DPreview.tsx +39 -0
- package/src/components/Toolbar.tsx +595 -0
- package/src/components/TransientHint.tsx +44 -0
- package/src/components/TransportStrip.tsx +174 -0
- package/src/components/VersionControlSection.tsx +470 -0
- package/src/components/VgaiLogo.css +83 -0
- package/src/components/VgaiLogo.tsx +35 -0
- package/src/components/ViewportControlsHint.tsx +60 -0
- package/src/components/ViewportFurniture.tsx +401 -0
- package/src/components/ViewportOverlay.tsx +145 -0
- package/src/components/ViewportOverlaysMenu.tsx +153 -0
- package/src/components/ViewportShadingMenu.tsx +300 -0
- package/src/components/ViewportViewMenu.tsx +101 -0
- package/src/components/WorkspaceDocumentSurface.tsx +204 -0
- package/src/components/WorkspaceUtilitySurface.tsx +22 -0
- package/src/components/WorktreeSwitcher.css +239 -0
- package/src/components/WorktreeSwitcher.tsx +890 -0
- package/src/components/account-documents.tsx +1162 -0
- package/src/components/asset-documents.tsx +812 -0
- package/src/components/asset-editor-persistence.ts +216 -0
- package/src/components/asset-selection-section.tsx +535 -0
- package/src/components/asset-thumbnails.tsx +312 -0
- package/src/components/asset-viewers/AudioViewer.tsx +201 -0
- package/src/components/asset-viewers/EntityModelDocument.tsx +122 -0
- package/src/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
- package/src/components/asset-viewers/GenericJsonViewer.tsx +102 -0
- package/src/components/asset-viewers/ImageViewer.tsx +300 -0
- package/src/components/asset-viewers/JsonAssetDocument.tsx +93 -0
- package/src/components/asset-viewers/LiveModuleDocument.tsx +417 -0
- package/src/components/asset-viewers/LutAssetDocument.tsx +444 -0
- package/src/components/asset-viewers/ModelAssetDocument.tsx +105 -0
- package/src/components/asset-viewers/Object3DPreview.tsx +359 -0
- package/src/components/asset-viewers/OnlineAssetDetail.tsx +421 -0
- package/src/components/asset-viewers/PasteboardModuleDocument.tsx +67 -0
- package/src/components/asset-viewers/QuarksAssetDocument.tsx +526 -0
- package/src/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
- package/src/components/asset-viewers/SourceAssetViewer.tsx +281 -0
- package/src/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
- package/src/components/asset-viewers/VideoViewer.tsx +101 -0
- package/src/components/asset-viewers/shader-source.ts +144 -0
- package/src/components/asset-workflow.css +731 -0
- package/src/components/board-guides.ts +150 -0
- package/src/components/compact-inspector.css +539 -0
- package/src/components/core-utilities.tsx +90 -0
- package/src/components/editor-notifications.css +40 -0
- package/src/components/engine-workspace.css +274 -0
- package/src/components/inspector-preview-section.tsx +238 -0
- package/src/components/inspector-property-grouping.ts +64 -0
- package/src/components/inspector-revert-label.ts +20 -0
- package/src/components/inspector-selection.ts +42 -0
- package/src/components/inspector-stories-gating.ts +171 -0
- package/src/components/inspector-transform-subject.ts +11 -0
- package/src/components/inspector-transform.ts +75 -0
- package/src/components/kind-documents.tsx +500 -0
- package/src/components/palette-action-publisher.tsx +140 -0
- package/src/components/primitives/DraftColorInput.tsx +74 -0
- package/src/components/product-shell.css +1829 -0
- package/src/components/project-tool-documents.tsx +410 -0
- package/src/components/scene-documents.tsx +223 -0
- package/src/components/stage-keyboard.tsx +37 -0
- package/src/components/stage-overlay-set.tsx +107 -0
- package/src/components/stage-presence-markers.ts +478 -0
- package/src/components/standard-viewport-dressing.ts +417 -0
- package/src/components/status-contributions.tsx +403 -0
- package/src/components/tool-documents.tsx +309 -0
- package/src/components/tool-schema-form.tsx +262 -0
- package/src/components/use-after-paint.ts +41 -0
- package/src/components/use-project-image-assets.ts +86 -0
- package/src/components/viewport-header-controls.css +90 -0
- package/src/components/viewport-surface-status.tsx +55 -0
- package/src/components/workspace-history.ts +32 -0
- package/src/components/workspace-static-panel-registry.tsx +152 -0
- package/src/components/workspace-surfaces.css +621 -0
- package/src/components/world-documents.tsx +586 -0
- package/src/components/world-overlay-gestures.ts +1694 -0
- package/src/composite-screenshot.ts +1641 -0
- package/src/console-sync.ts +131 -0
- package/src/constraint-helper.ts +338 -0
- package/src/content-entry-source-registry.ts +184 -0
- package/src/coverage/authoring-seam-evidence.ts +300 -0
- package/src/coverage/canvas-reveal.ts +192 -0
- package/src/coverage/design-time-surfaces.ts +101 -0
- package/src/coverage/live-seam-evidence.ts +11 -0
- package/src/coverage/ontology-invariants.ts +466 -0
- package/src/coverage/session-vitals.ts +501 -0
- package/src/coverage/system-seam-evidence.ts +72 -0
- package/src/crash-null-boundary.ts +36 -0
- package/src/creation-site-edit.ts +1479 -0
- package/src/creation-site-registry.ts +160 -0
- package/src/delegate-harness-registry.ts +143 -0
- package/src/document-context-registry.ts +177 -0
- package/src/document-open-registry.ts +200 -0
- package/src/document-preview-source.ts +20 -0
- package/src/document-renderer-session.ts +138 -0
- package/src/editor-api.ts +46 -0
- package/src/editor-chrome-capture.ts +139 -0
- package/src/editor-commands.ts +164 -0
- package/src/editor-console.ts +563 -0
- package/src/editor-current-view.ts +82 -0
- package/src/editor-document-probe.ts +881 -0
- package/src/editor-git-client.ts +115 -0
- package/src/editor-host-door.ts +462 -0
- package/src/editor-hotkeys.ts +842 -0
- package/src/editor-lease-view.ts +39 -0
- package/src/editor-lease.ts +415 -0
- package/src/editor-mode.ts +19 -0
- package/src/editor-notifications.ts +140 -0
- package/src/editor-presence.ts +563 -0
- package/src/editor-presentation-activity.ts +50 -0
- package/src/editor-presentation-notice.ts +42 -0
- package/src/editor-runtime.tsx +145 -0
- package/src/editor-server-response.ts +86 -0
- package/src/editor-session-attribution.ts +75 -0
- package/src/editor-session-mode.ts +54 -0
- package/src/editor-shell-store.ts +1304 -0
- package/src/editor-state-facets.ts +74 -0
- package/src/editor-styles.css +33 -0
- package/src/editor-view-presentation.ts +810 -0
- package/src/editor-viewport.ts +5302 -0
- package/src/entity-lod.ts +31 -0
- package/src/entity-object.ts +91 -0
- package/src/files/file-provider.ts +62 -0
- package/src/files/project-files.ts +264 -0
- package/src/finders/index.ts +136 -0
- package/src/finders/scenes-from-entrypoint-selection.ts +387 -0
- package/src/frame/bridge.tsx +1408 -0
- package/src/frame/product.ts +77 -0
- package/src/gameplay-dom-recording.ts +319 -0
- package/src/gameplay-export-state.ts +14 -0
- package/src/gameplay-replay.ts +417 -0
- package/src/gameplay-session-time.ts +9 -0
- package/src/gameplay-sessions.ts +204 -0
- package/src/harness-chat-types.ts +253 -0
- package/src/hierarchy-component-marks.ts +298 -0
- package/src/hierarchy-drop.ts +91 -0
- package/src/hierarchy-expansion-state.ts +80 -0
- package/src/hierarchy-header-slot.ts +52 -0
- package/src/hierarchy-internals.ts +197 -0
- package/src/hierarchy-kind-icon.ts +217 -0
- package/src/hierarchy-mark-reader.ts +73 -0
- package/src/hierarchy-menu-registry.ts +67 -0
- package/src/hierarchy-node-rows.ts +307 -0
- package/src/hierarchy-panel-view.ts +280 -0
- package/src/hierarchy-projection.ts +76 -0
- package/src/hierarchy-row-cache.ts +243 -0
- package/src/hierarchy-row-model.ts +308 -0
- package/src/hierarchy-rows.ts +11 -0
- package/src/hierarchy-walk.ts +86 -0
- package/src/history/editor-session.ts +25 -0
- package/src/history/history-commands.ts +147 -0
- package/src/history/history-delegate.ts +163 -0
- package/src/history/history-limit-notices.ts +43 -0
- package/src/history/history-service.ts +1173 -0
- package/src/history/persistence-coordinator.ts +35 -0
- package/src/history/project-file-history.ts +386 -0
- package/src/history/project-root-history-backends.ts +139 -0
- package/src/history/resource-registry.ts +209 -0
- package/src/history/snapshot-store.ts +103 -0
- package/src/history/source-history-backend.ts +546 -0
- package/src/history/types.ts +124 -0
- package/src/hmr-registration-group.ts +67 -0
- package/src/hmr-stable-react-context.ts +23 -0
- package/src/hotkeys.ts +188 -0
- package/src/inference-diagnostics.ts +69 -0
- package/src/initial-project.ts +80 -0
- package/src/inspection/active-subject.ts +578 -0
- package/src/inspection/active-surface.ts +142 -0
- package/src/inspection/compose.ts +1064 -0
- package/src/inspection/display.ts +170 -0
- package/src/inspection/document-subject.ts +109 -0
- package/src/inspection/game-subject.ts +85 -0
- package/src/inspection/model.ts +542 -0
- package/src/inspection/null-subject.ts +115 -0
- package/src/inspection/serialize.ts +357 -0
- package/src/inspection/use-active-inspection.ts +180 -0
- package/src/inspector-presentation.ts +201 -0
- package/src/inspector-section-registry.ts +221 -0
- package/src/instance-source-actions.ts +163 -0
- package/src/instanced-presentation.ts +164 -0
- package/src/js-heap.ts +71 -0
- package/src/key-actions.ts +91 -0
- package/src/keymap-presets.ts +401 -0
- package/src/layout-policy.ts +31 -0
- package/src/learn-links.ts +73 -0
- package/src/light-explorer-model.ts +134 -0
- package/src/live-canvas-frame.ts +55 -0
- package/src/live-document.ts +279 -0
- package/src/live-module-source.ts +230 -0
- package/src/live-session-registry.ts +220 -0
- package/src/live-transition.ts +633 -0
- package/src/manifest-project.ts +107 -0
- package/src/model-thumbnail.ts +523 -0
- package/src/native-selection-style.ts +202 -0
- package/src/object3d-document-write-policy.ts +137 -0
- package/src/packaged-runtime.ts +108 -0
- package/src/palettes/maya.palette.json +57 -0
- package/src/palettes/substance.palette.json +57 -0
- package/src/pasteboard-module.ts +81 -0
- package/src/performance-profiler.ts +367 -0
- package/src/performance-sources.ts +69 -0
- package/src/play-boot-phase.ts +145 -0
- package/src/presentation-surface.ts +248 -0
- package/src/project-adapter.ts +1143 -0
- package/src/project-asset-refresh.ts +26 -0
- package/src/project-declaration-refresh.ts +31 -0
- package/src/project-local-state.ts +118 -0
- package/src/project-manager.ts +243 -0
- package/src/project-module-changes.ts +163 -0
- package/src/project-module-split.ts +266 -0
- package/src/project-provenance.ts +115 -0
- package/src/project-ready.ts +42 -0
- package/src/project-session-reset.ts +67 -0
- package/src/project-shape.ts +68 -0
- package/src/project-tool-discovery.ts +66 -0
- package/src/project-tools.ts +107 -0
- package/src/project-work-types.ts +149 -0
- package/src/projection/three.ts +898 -0
- package/src/projection/types.ts +44 -0
- package/src/readiness.ts +113 -0
- package/src/reflection-probe-helper.ts +142 -0
- package/src/reported-play-state.ts +90 -0
- package/src/resolve-relative-specifier.ts +33 -0
- package/src/scene-document-plan.ts +315 -0
- package/src/scene-framing.ts +315 -0
- package/src/scene-live-open.ts +210 -0
- package/src/scene-view-fog.ts +89 -0
- package/src/scoped-game-css.ts +152 -0
- package/src/session-orphan-record.ts +193 -0
- package/src/session-tombstone.ts +126 -0
- package/src/settings/settings-provider.ts +82 -0
- package/src/settings-store.ts +345 -0
- package/src/shared-view-restore.ts +42 -0
- package/src/shell-store-door.ts +45 -0
- package/src/source-conflict.ts +122 -0
- package/src/spatial-handle-visuals.ts +332 -0
- package/src/stage-context.ts +341 -0
- package/src/stage-store-registry.ts +63 -0
- package/src/stale-chunk-recovery.ts +34 -0
- package/src/state-report-deferral.ts +73 -0
- package/src/storage/host-files-storage.ts +97 -0
- package/src/storage/http-storage.ts +174 -0
- package/src/storage/index.ts +75 -0
- package/src/storage/mem-storage.ts +149 -0
- package/src/storage/path-lock.ts +44 -0
- package/src/storage/paths.ts +26 -0
- package/src/storage/types.ts +116 -0
- package/src/stories/StoryComponentThumbnail.tsx +184 -0
- package/src/stories/StoryPreviewMount.tsx +306 -0
- package/src/stories/component-content-source.tsx +106 -0
- package/src/stories/component-states-source.ts +78 -0
- package/src/stories/compose-project-stories.ts +255 -0
- package/src/stories/pixi-story-model.ts +30 -0
- package/src/stories/prefabs-finder.ts +54 -0
- package/src/stories/prefabs-from-stories.ts +182 -0
- package/src/stories/project-story-discovery.ts +78 -0
- package/src/stories/project-story-regions.ts +24 -0
- package/src/stories/story-actions.ts +54 -0
- package/src/stories/story-capture-command.ts +124 -0
- package/src/stories/story-capture.ts +584 -0
- package/src/stories/story-declared-medium.ts +126 -0
- package/src/stories/story-discovery.ts +176 -0
- package/src/stories/story-document-openers.ts +36 -0
- package/src/stories/story-dom-runtime.ts +78 -0
- package/src/stories/story-grouping.ts +111 -0
- package/src/stories/story-lane.ts +88 -0
- package/src/stories/story-mount-turn.ts +27 -0
- package/src/stories/story-opener.ts +260 -0
- package/src/stories/story-pixi-preview.ts +408 -0
- package/src/stories/story-presentation.ts +215 -0
- package/src/stories/story-registry.ts +517 -0
- package/src/stories/story-three-preview.ts +807 -0
- package/src/stories/three-story-model.ts +96 -0
- package/src/story-three-preview-runtime.ts +56 -0
- package/src/surface-keyboard.ts +112 -0
- package/src/surface-state.ts +124 -0
- package/src/tab-bootstrap.js +628 -0
- package/src/tab-census.ts +198 -0
- package/src/tab-lifecycle-client.ts +196 -0
- package/src/theme-library.ts +844 -0
- package/src/theme-preference.ts +378 -0
- package/src/theme.css +3437 -0
- package/src/three-viewport/bone-selection-highlight.ts +119 -0
- package/src/three-viewport/camera-fit.ts +41 -0
- package/src/three-viewport/interactive-renderer.ts +132 -0
- package/src/three-viewport/selection-brackets.ts +310 -0
- package/src/three-viewport/selection-outline.ts +183 -0
- package/src/three-viewport/skeleton-helper.ts +61 -0
- package/src/three-viewport/source-color.ts +167 -0
- package/src/three-viewport/studio-environment.ts +96 -0
- package/src/three-viewport-presentation.ts +23 -0
- package/src/tool-contribution-play.ts +74 -0
- package/src/tool-loader.ts +1798 -0
- package/src/transform-mode-request.ts +57 -0
- package/src/transient-hint.ts +78 -0
- package/src/trigger-volume-helper.ts +116 -0
- package/src/ui-source/adapter-region-includes.ts +241 -0
- package/src/ui-source/ensure-import.ts +132 -0
- package/src/ui-source/file-region-resolver.ts +302 -0
- package/src/ui-source/inspect.ts +775 -0
- package/src/ui-source/oid-transform.ts +1845 -0
- package/src/ui-source/plan-csf-story.ts +196 -0
- package/src/ui-source/plan-extract-component.ts +421 -0
- package/src/ui-source/plan-fork-component.ts +621 -0
- package/src/ui-source/plan-named-style.ts +95 -0
- package/src/ui-source/plan-source-edit.ts +353 -0
- package/src/ui-source/r3f-contract-resolver.ts +327 -0
- package/src/ui-source/r3f-diagnostic-index.ts +165 -0
- package/src/ui-source/r3f-environment-binding.ts +133 -0
- package/src/ui-source/r3f-joint-binding.ts +251 -0
- package/src/ui-source/r3f-lod-binding.ts +91 -0
- package/src/ui-source/r3f-particle-binding.ts +235 -0
- package/src/ui-source/r3f-physics-binding.ts +483 -0
- package/src/ui-source/r3f-project-contracts.ts +444 -0
- package/src/ui-source/relative-import-specifier.ts +34 -0
- package/src/ui-source/reparent-guard.ts +544 -0
- package/src/ui-source/source-edit-request.ts +97 -0
- package/src/ui-source/source-write-backend.ts +618 -0
- package/src/ui-source/syntactic-prop-specs.ts +296 -0
- package/src/ui-source/tier-source-write-backend.ts +279 -0
- package/src/ui-source/ts-ast.ts +171 -0
- package/src/ui-source/utility-class-support.ts +169 -0
- package/src/ui-source/write-component-default.ts +133 -0
- package/src/ui-source/writer.ts +1989 -0
- package/src/viewport-activation-timings.ts +840 -0
- package/src/viewport-authoring-policy.ts +186 -0
- package/src/viewport-controls-hint.ts +57 -0
- package/src/viewport-door.ts +237 -0
- package/src/viewport-shading-boundary.ts +12 -0
- package/src/vite-error-surface.ts +141 -0
- package/src/wait-until.ts +37 -0
- package/src/workspace-areas.ts +156 -0
- package/src/workspace-aux-commands.ts +11 -0
- package/src/workspace-available-documents.ts +127 -0
- package/src/workspace-core-utilities.ts +31 -0
- package/src/workspace-document-ids.ts +59 -0
- package/src/workspace-document-registry.ts +612 -0
- package/src/workspace-document-restore.ts +145 -0
- package/src/workspace-host-commands.ts +141 -0
- package/src/workspace-persistence-gate.ts +40 -0
- package/src/workspace-play-utilities.ts +44 -0
- package/src/workspace-presets.ts +425 -0
- package/src/workspace-regions.ts +294 -0
- package/src/workspace-state-persistence.ts +536 -0
- package/src/workspace-static-panels.ts +73 -0
- package/src/workspace-status-registry.ts +121 -0
- package/src/workspace-style.ts +239 -0
- package/src/workspace-utility-commands.ts +74 -0
- package/src/workspace-utility-registry.ts +263 -0
- package/src/workspace-viewport-rect.ts +97 -0
- package/src/world-adoption.ts +115 -0
- package/src/world-document-routing.ts +104 -0
- package/vite-plugin-creation-site-write.ts +184 -0
- package/vite-plugin-creation-site.ts +80 -0
- package/vite-plugin-game-static.ts +303 -0
- package/vite-plugin-module-doorways.ts +336 -0
- package/vite-plugin-product-contributions.ts +197 -0
- package/vite-plugin-project-game-static.ts +125 -0
- package/vite-plugin-project-jsx-js.ts +65 -0
- package/vite-plugin-project-root-absolute-assets.ts +359 -0
- package/vite-plugin-shared-react.ts +420 -0
- package/vite-plugin-shared-three.ts +203 -0
- package/vite-plugin-ui-oid.ts +2106 -0
|
@@ -0,0 +1,1192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packaged editor server — the entry a `@vgai/editor` npm package resolves from a
|
|
3
|
+
* PROJECT's own `node_modules`, with NO monorepo checkout on disk (Phase B; see
|
|
4
|
+
* the phase plan's D-FORK decision + §0/§3 "the real work" for `@vgai/editor`).
|
|
5
|
+
*
|
|
6
|
+
* Run with:
|
|
7
|
+
* VGAI_PROJECT=<projectDir> node dist-server/packaged.mjs
|
|
8
|
+
*
|
|
9
|
+
* ## Why this file exists (and isn't just `dev.ts`)
|
|
10
|
+
*
|
|
11
|
+
* `dev.ts` boots ONE Vite instance rooted at the monorepo checkout, which
|
|
12
|
+
* does double duty: it builds the editor's OWN React app AND resolves the
|
|
13
|
+
* OPENED PROJECT's module graph (bare imports like `three`/`zod`/`react`
|
|
14
|
+
* resolve only because that Vite's `root` is the repo root, whose hoisted
|
|
15
|
+
* `node_modules` has everything). That is exactly what a registry install
|
|
16
|
+
* does NOT have: there is no checkout, so there is no repo root to serve
|
|
17
|
+
* either graph from.
|
|
18
|
+
*
|
|
19
|
+
* This file is the second code path: it serves the editor's OWN
|
|
20
|
+
* app as a PREBUILT static SPA (`../dist/`, produced by the workspace-local
|
|
21
|
+
* `npm run build -w @vgai/editor`) — no dev-mode transform of the editor's
|
|
22
|
+
* own source is needed, since a project author isn't hot-reloading the
|
|
23
|
+
* editor's own UI — and boots a SEPARATE, PROJECT-ROOTED Vite instance
|
|
24
|
+
* (`root: <project>`, `configFile: false`, middleware mode, HMR + watch
|
|
25
|
+
* ENABLED) whose job is ONLY to resolve/transform the opened PROJECT's own
|
|
26
|
+
* source. Because that Vite instance's `root` is the project directory,
|
|
27
|
+
* Vite's own resolver naturally walks the PROJECT's OWN `node_modules` for
|
|
28
|
+
* every bare specifier (`three`, `zod`, `react`, ...) —
|
|
29
|
+
* for free, with zero hand-written import rewriting. This is the same
|
|
30
|
+
* pattern `packages/editor/scripts/run-conformance.ts` uses to run the
|
|
31
|
+
* adapter conformance kit against an arbitrary external folder, adapted for
|
|
32
|
+
* live editing (HMR/watch on) instead of a one-shot SSR run.
|
|
33
|
+
*
|
|
34
|
+
* The project's runtime packages — `@vgai/project`, `@vgai/threejs-runtime`
|
|
35
|
+
* and `@vgai/game-runtime` — resolve to the PROJECT's own installed copies,
|
|
36
|
+
* not copies baked into this package's tarball. A project pinning
|
|
37
|
+
* `@vgai/game-runtime@0.3.0` must be served ITS 0.3.0 source, so each is
|
|
38
|
+
* resolved via `createRequire`, rooted at the project directory — Node's own
|
|
39
|
+
* resolution algorithm, not a hardcoded path (see
|
|
40
|
+
* `resolveInstalledPackageSrcDir` in `server-utils.ts`).
|
|
41
|
+
*
|
|
42
|
+
* ## React-world OID authoring parity (DEBT-4 follow-on)
|
|
43
|
+
*
|
|
44
|
+
* `dev.ts` reaches THREE extra plugins via its `configFile:` (repo-root
|
|
45
|
+
* `vite.config.ts`): `uiOidPlugin()` (stamps `data-oid` on every JSX element
|
|
46
|
+
* in project-scoped `.tsx` files + serves the `/__ui-source/*` read/write
|
|
47
|
+
* endpoints the hierarchy/inspector's source-write path needs),
|
|
48
|
+
* `creationSiteWritePlugin()` (the `/__ingest-source/*` ownership +
|
|
49
|
+
* read/plan/apply routes an INGEST root's edits are written through — absent
|
|
50
|
+
* here until 2026-08-20, which made ingest-lane source writes unreachable
|
|
51
|
+
* under a registry install no matter what the client asked) and
|
|
52
|
+
* `reactRootProviderPlugin()` (resolves the synthetic
|
|
53
|
+
* `/__vgai-game-provider` module `binding-resolver.ts`'s
|
|
54
|
+
* `loadProjectWorldProvider` imports — WITHOUT it, every `kind: 'dom'`
|
|
55
|
+
* world 404s on mount, not just "authors without OID"). All are carried
|
|
56
|
+
* over here, imported straight from this package's own `vite-plugin-ui-oid`
|
|
57
|
+
* / `vite-plugin-creation-site-write` / `vite-plugin-react-world-provider`
|
|
58
|
+
* (same files, no copy) and registered
|
|
59
|
+
* with NO extra scoping beyond their own built-in `defaultProjectScopeInclude`
|
|
60
|
+
* (already project-scoped — see that file's doc comment: excludes
|
|
61
|
+
* `node_modules`, vendored trees, and the vgai tooling/engine source, which
|
|
62
|
+
* this Vite instance never serves anyway since its `root` IS the project).
|
|
63
|
+
*
|
|
64
|
+
* `@vitejs/plugin-react` (`react()`) is DELIBERATELY NOT added here — this
|
|
65
|
+
* is the one piece of `dev.ts` parity that is a genuine, structural
|
|
66
|
+
* incompatibility, not a missing plugin call:
|
|
67
|
+
*
|
|
68
|
+
* 1. **Fast Refresh's preamble has nowhere to run.** `@vitejs/plugin-react`
|
|
69
|
+
* only skips its fast-refresh code-injection when `config.isProduction ||
|
|
70
|
+
* config.command === 'build' || config.server.hmr === false` — none of
|
|
71
|
+
* which hold here (this instance is `middlewareMode` `serve` with `hmr`
|
|
72
|
+
* ON, by design, for live editing). With fast-refresh injection ON, every
|
|
73
|
+
* transformed `.tsx` module gets a trailer that THROWS
|
|
74
|
+
* (`"@vitejs/plugin-react can't detect preamble. Something is wrong."`)
|
|
75
|
+
* unless `window.$RefreshReg$`/`$RefreshSig$` were set by the preamble
|
|
76
|
+
* script `transformIndexHtml` injects into an HTML page THAT INSTANCE
|
|
77
|
+
* SERVES. This instance is `appType: 'custom'` (no HTML serving at all —
|
|
78
|
+
* the editor's own shell is a PREBUILT static `dist/`, sent by `express.
|
|
79
|
+
* static` below with zero Vite involvement, so no `transformIndexHtml`
|
|
80
|
+
* hook ever runs for it either). Registering `react()` as-is would not
|
|
81
|
+
* degrade gracefully to "no Fast Refresh" — it would make every react-
|
|
82
|
+
* world/component module throw on first load, a regression versus
|
|
83
|
+
* today's baseline (plain esbuild JSX, which works fine for basic JSX —
|
|
84
|
+
* proven by the default template). The only way to silence just the
|
|
85
|
+
* fast-refresh half (short of a bespoke preamble-bootstrap module the
|
|
86
|
+
* browser would need to import before any project entry, itself a new
|
|
87
|
+
* client-side subsystem) is `server.hmr: false` on the WHOLE instance,
|
|
88
|
+
* which would also kill the `vgai-script-hmr` plugin below's WebSocket
|
|
89
|
+
* delivery — not an acceptable trade for this slice.
|
|
90
|
+
* 2. **JSX compilation itself doesn't need it.** Vite's default esbuild JSX
|
|
91
|
+
* transform (`automatic` runtime, no config here) already compiles
|
|
92
|
+
* `.tsx`/`.jsx` correctly without `@vitejs/plugin-react` — proven by the
|
|
93
|
+
* default (threejs-only) template authoring fine today, and unaffected
|
|
94
|
+
* by this file's plugin list either way.
|
|
95
|
+
*
|
|
96
|
+
* So: OID stamping (source-write authoring) and the `WorldProvider` identity
|
|
97
|
+
* fix are real, working parity gained by this change. React Fast Refresh
|
|
98
|
+
* for a project's own components remains NOT at `dev.ts` parity under the
|
|
99
|
+
* packaged runtime — a documented, structural gap, not a hidden one.
|
|
100
|
+
*
|
|
101
|
+
* ## ONE React for the editor's tree — the shell's (`vite-plugin-shared-react.ts`)
|
|
102
|
+
*
|
|
103
|
+
* The deeper structural gap this file's two-graph design opens: the editor's
|
|
104
|
+
* own `react`/`react-dom` are STATICALLY bundled into its prebuilt SPA
|
|
105
|
+
* (`dist/`, built at `npm run build -w @vgai/editor` time), while this
|
|
106
|
+
* project-rooted Vite instance resolves bare `react` from the PROJECT's own
|
|
107
|
+
* `node_modules` — two React module instances on one page, reading different
|
|
108
|
+
* internal singletons. `dev.ts` has no such split (ONE Vite + repo-root
|
|
109
|
+
* `vite.config.ts`'s `resolve.dedupe: ['react', 'react-dom', …]`), which is
|
|
110
|
+
* why nothing in a checkout ever reproduced any of it.
|
|
111
|
+
*
|
|
112
|
+
* It surfaced twice, both confirmed live against a tarball-installed,
|
|
113
|
+
* checkout-absent packaged editor:
|
|
114
|
+
*
|
|
115
|
+
* 1. a `dom` root's `useWorldState` threw `TypeError: Cannot read properties
|
|
116
|
+
* of null (reading 'useContext')` at mount, because the editor's bundled
|
|
117
|
+
* `createRoot` reconciled a component whose hooks came from the project's
|
|
118
|
+
* react; and
|
|
119
|
+
* 2. every project TOOL CONTRIBUTION — the four dev-tools inspector facets
|
|
120
|
+
* (`src/contributions/game-*.inspector.tsx`), the builder inspectors, the World
|
|
121
|
+
* Labs asset inspector, the data-tables document — REGISTERED and then
|
|
122
|
+
* rendered as a crash box: `Invalid hook call … more than one copy of
|
|
123
|
+
* React in the same app`. Those render INSIDE the editor's own tree, so
|
|
124
|
+
* there was no isolated subtree to hide in.
|
|
125
|
+
*
|
|
126
|
+
* The fix, for (2): the editor build publishes its OWN React (plus `react-dom`,
|
|
127
|
+
* `react-dom/client`, `react/jsx-runtime`, `react/jsx-dev-runtime`, and the one
|
|
128
|
+
* third-party package that calls React hooks in the editor's tree) as entry
|
|
129
|
+
* chunks, and `sharedReactPlugin` below resolves those specifiers — for
|
|
130
|
+
* the EDITOR TREE only — to those chunks' URLs, the same URLs the shell's
|
|
131
|
+
* bundle already imports, so the browser's module map hands both graphs one
|
|
132
|
+
* instance. `@volter/editor-sdk/widgets` moves out of `optimizeDeps.include` and into
|
|
133
|
+
* `exclude` for the same reason: a prebundled chunk's React is decided at
|
|
134
|
+
* prebundle time, where a source-level redirect cannot reach it.
|
|
135
|
+
*
|
|
136
|
+
* The seam stops at the GAME, and that boundary is measured, not assumed: a
|
|
137
|
+
* first attempt redirected the whole graph and broke Play mode
|
|
138
|
+
* (`@react-three/fiber`'s prebundled DEVELOPMENT `react-reconciler` against the
|
|
139
|
+
* shell's PRODUCTION React → `Cannot read properties of undefined (reading
|
|
140
|
+
* 'push')` in `updateContainer`, then `onCreated did not fire within 10s`). So
|
|
141
|
+
* the game keeps its own development React — which is exactly (1)'s fix, and
|
|
142
|
+
* why the react-world and story MODULE DOORWAYS below still route the
|
|
143
|
+
* editor's own mount/story imports through THIS graph. Read
|
|
144
|
+
* `../vite-plugin-shared-react.ts` for the full rule and for why the entry
|
|
145
|
+
* bodies are generated rather than written.
|
|
146
|
+
*
|
|
147
|
+
* ## Scoped dependency discovery, not disabled discovery (C3 follow-on)
|
|
148
|
+
*
|
|
149
|
+
* `optimizeDeps` below used to carry `noDiscovery: true` (see git history for
|
|
150
|
+
* the exact prior comment): with the boot-time crawl DEFAULT-targeting the
|
|
151
|
+
* project's own `index.html`, and a scaffolded project's `src/main.ts`
|
|
152
|
+
* bootstrap containing a `?net=p2p-host`-gated `await import('../server/
|
|
153
|
+
* rooms')` that esbuild's scanner statically follows regardless of the
|
|
154
|
+
* runtime guard around it, that crawl reached real Colyseus SERVER code
|
|
155
|
+
* (`colyseus` -> `@colyseus/core` -> `@pm2/io`, a package with no browser-
|
|
156
|
+
* resolvable entry) and crashed the esbuild prebundle step outright. Turning
|
|
157
|
+
* discovery off entirely sidestepped that crash — at the cost of any CJS-
|
|
158
|
+
* only dependency NOT in the hardcoded `include` list below being served raw
|
|
159
|
+
* to the browser and failing (this is exactly what broke `examples/
|
|
160
|
+
* r3f-first-party`: `@react-three/fiber`'s CJS transitive deps, e.g.
|
|
161
|
+
* `use-sync-external-store/shim/with-selector.js`, have no place to be
|
|
162
|
+
* hardcoded — this server serves ARBITRARY projects, most without R3F
|
|
163
|
+
* installed at all, and Vite errors on `include`-ing a not-installed dep).
|
|
164
|
+
*
|
|
165
|
+
* The fix (C3, `phase-b/c3-r3f-packaged`) is not "add R3F to the allowlist"
|
|
166
|
+
* — that just moves the whack-a-mole to the next ecosystem a project
|
|
167
|
+
* happens to pull in. It SCOPES the crawl instead of disabling it:
|
|
168
|
+
* `optimizeDeps.entries` is set (see `projectOptimizeDepsEntries` /
|
|
169
|
+
* `computeProjectOptimizeDepsEntries` in `project-optimize-deps-entries.ts`)
|
|
170
|
+
* to the OPENED PROJECT's own `vgai.project.json`-declared world `entry` files
|
|
171
|
+
* — the exact per-world mount code the editor's binding-resolver dynamically
|
|
172
|
+
* imports for Play mode, never the project's `src/main.ts` bootstrap (a
|
|
173
|
+
* standalone-build concern this Vite instance never serves — the editor's
|
|
174
|
+
* own prebuilt SPA answers `/`). A world entry's own import graph reaches
|
|
175
|
+
* real client packages (react, R3F, a legitimate client `@colyseus/sdk`
|
|
176
|
+
* import for real multiplayer — `examples/third-person-arena/src/
|
|
177
|
+
* network.ts`) but never `server/`, so the `@pm2/io` crash class cannot
|
|
178
|
+
* occur no matter what a project's room code imports, while ANY CJS-needing-
|
|
179
|
+
* prebundle client dependency a world reaches gets auto-discovered and
|
|
180
|
+
* prebundled — no per-package allowlist, adapts to whatever the opened
|
|
181
|
+
* project actually has installed. `project-optimize-deps-entries.ts`'s doc
|
|
182
|
+
* comment has the empirical proof (direct `vite.optimizeDeps` runs, not just
|
|
183
|
+
* theory): scoped to the template's world entry, prebundling succeeds
|
|
184
|
+
* clean; scoped to `index.html` (the old default), it reproduces the exact
|
|
185
|
+
* `@pm2/io` crash; scoped to `examples/r3f-first-party`'s world entries, `@react-
|
|
186
|
+
* three/fiber`/`@react-three/drei` are discovered and prebundled with no
|
|
187
|
+
* hardcoding; scoped to `examples/third-person-arena`'s world entry (a real
|
|
188
|
+
* colyseus multiplayer project), `@colyseus/sdk` prebundles clean too — the
|
|
189
|
+
* client SDK's own published build is self-contained and never reaches
|
|
190
|
+
* `@colyseus/core`'s server-only `Stats.mjs`. See the C3 build report for
|
|
191
|
+
* the real-browser proof (checkout absent, tarball-installed): R3F's
|
|
192
|
+
* `examples/r3f-first-party` "net" world mounts with no console error, AND the
|
|
193
|
+
* pre-existing react-world (C1) / colyseus-bearing-project (this section)
|
|
194
|
+
* cases still work — no regression.
|
|
195
|
+
*
|
|
196
|
+
* ## Known scope trims (v1 — flagged, not silently dropped)
|
|
197
|
+
*
|
|
198
|
+
* - Project creation resolves the shared scaffold from this package's npm
|
|
199
|
+
* installation root, so the in-editor and terminal journeys use the same
|
|
200
|
+
* packaged template, examples, and registry dependency mode.
|
|
201
|
+
*/
|
|
202
|
+
|
|
203
|
+
import { createRequire } from 'node:module';
|
|
204
|
+
import path from 'node:path';
|
|
205
|
+
import { fileURLToPath } from 'node:url';
|
|
206
|
+
import type { ProductIdentity } from '@volter/editor-sdk/session/product-locator';
|
|
207
|
+
import express from 'express';
|
|
208
|
+
import {
|
|
209
|
+
createServer as createViteServer,
|
|
210
|
+
type InlineConfig,
|
|
211
|
+
optimizeDeps,
|
|
212
|
+
resolveConfig,
|
|
213
|
+
} from 'vite';
|
|
214
|
+
import {
|
|
215
|
+
DEFAULT_EDITOR_PORT,
|
|
216
|
+
editorHmrPort,
|
|
217
|
+
editorOrigin,
|
|
218
|
+
} from '@volter/editor-project/manifest/editor-port';
|
|
219
|
+
import { servesIngestSourceRoutes } from '../vite-plugin-creation-site-write';
|
|
220
|
+
import { PACKAGED_MODULE_DOORWAYS } from '../vite-plugin-module-doorways';
|
|
221
|
+
import { readSharedReactManifest, sharedReactUrls } from '../vite-plugin-shared-react';
|
|
222
|
+
import { readSharedThreeManifest, sharedThreeUrl } from '../vite-plugin-shared-three';
|
|
223
|
+
import { servesUiSourceRoutes } from '../vite-plugin-ui-oid';
|
|
224
|
+
import { canonicalProjectRoot } from './canonical-path';
|
|
225
|
+
import { createEditorServer } from './editor-server';
|
|
226
|
+
import { clientCount } from './editor-sse';
|
|
227
|
+
import {
|
|
228
|
+
builtFrameBridgeModule,
|
|
229
|
+
FRAME_BRIDGE_PACKAGED_PATH,
|
|
230
|
+
readBuiltProductEntry,
|
|
231
|
+
} from './frame-bridge';
|
|
232
|
+
import {
|
|
233
|
+
type FrameWorkbench,
|
|
234
|
+
frameLaunchFromEnv,
|
|
235
|
+
frameWorkbenchUrl,
|
|
236
|
+
startFrameWorkbench,
|
|
237
|
+
} from './frame-workbench';
|
|
238
|
+
import {
|
|
239
|
+
createIdleShutdown,
|
|
240
|
+
formatIdleWindow,
|
|
241
|
+
IDLE_SHUTDOWN_MINUTES_ENV,
|
|
242
|
+
resolveIdleShutdownMs,
|
|
243
|
+
} from './idle-shutdown';
|
|
244
|
+
import { jsProfilingPolicy } from './js-profiling-policy';
|
|
245
|
+
import { configureManagedAccountDefaults } from './managed-account-defaults';
|
|
246
|
+
import { closeHttpServer, createProcessShutdown } from './process-shutdown';
|
|
247
|
+
import { projectServingRoots } from './project-install-roots';
|
|
248
|
+
import { freshProjectModuleLoader } from './project-module-freshness';
|
|
249
|
+
import {
|
|
250
|
+
computeEditorRuntimeIncludes,
|
|
251
|
+
computeRuntimeSourceCrawlEntries,
|
|
252
|
+
computePackageContributionCrawlEntries,
|
|
253
|
+
computeProjectOptimizeDepsEntries,
|
|
254
|
+
computeUnresolvableRuntimeImports,
|
|
255
|
+
RUNTIME_PACKAGE_NAMES,
|
|
256
|
+
SERVER_ONLY_PREBUNDLE_EXCLUDE,
|
|
257
|
+
viteOptimizeDepsEntries,
|
|
258
|
+
} from './project-optimize-deps-entries';
|
|
259
|
+
import { isProjectScratchPath } from './project-scratch-path';
|
|
260
|
+
import { createProjectServingPlugins } from './project-serving-plugins';
|
|
261
|
+
import {
|
|
262
|
+
friendlyListenError,
|
|
263
|
+
resolveBindHost,
|
|
264
|
+
resolveInstalledPackageSrcDir,
|
|
265
|
+
} from './server-utils';
|
|
266
|
+
import { resolveProductForProject, sessionProduct } from './session-product';
|
|
267
|
+
import { registerSession, unregisterSession } from './session-registry';
|
|
268
|
+
|
|
269
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
270
|
+
// This file lives directly under the `@vgai/editor` package root either as
|
|
271
|
+
// `packages/editor/server/packaged.ts` (source, run via tsx) or as the
|
|
272
|
+
// esbuild-bundled `packages/editor/dist-server/packaged.mjs` (`server/` and
|
|
273
|
+
// `dist-server/` are BOTH direct children of the package root) — so
|
|
274
|
+
// `resolve(__dirname, '..')` lands on the package root in either shape.
|
|
275
|
+
const editorPackageRoot = path.resolve(__dirname, '..');
|
|
276
|
+
const checkoutRoot = path.resolve(editorPackageRoot, '..', '..');
|
|
277
|
+
const PORT =
|
|
278
|
+
Number(process.env['PORT']) || Number(process.env['VGAI_EDITOR_PORT']) || DEFAULT_EDITOR_PORT;
|
|
279
|
+
const HMR_PORT = Number(process.env['VGAI_HMR_PORT']) || editorHmrPort(PORT);
|
|
280
|
+
const HMR_CLIENT_PORT = Number(process.env['VGAI_HMR_CLIENT_PORT']) || HMR_PORT;
|
|
281
|
+
// S3: bind to loopback by default; opt-in to a wider interface via env.
|
|
282
|
+
const HOST = resolveBindHost();
|
|
283
|
+
// Same rule as dev.ts: every URL this process prints or opens names the host it
|
|
284
|
+
// actually bound, never `localhost` (see `editorOrigin`).
|
|
285
|
+
const EDITOR_ORIGIN = editorOrigin(PORT, HOST);
|
|
286
|
+
|
|
287
|
+
if (!process.env['VGAI_PROJECT']) {
|
|
288
|
+
console.error(
|
|
289
|
+
'\n \x1b[31mVGAI_PROJECT is required — the packaged editor has no monorepo checkout to fall ' +
|
|
290
|
+
'back to. Set VGAI_PROJECT=<absolute path to your vgai project>.\x1b[0m\n',
|
|
291
|
+
);
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
// Canonicalized (symlink-resolved) — see canonical-path.ts's doc comment
|
|
295
|
+
// (dev.ts's identical fix: a react world's `WorldProvider` colocation breaks
|
|
296
|
+
// if this path and Vite's own resolver disagree on a symlinked segment).
|
|
297
|
+
const projectPath = canonicalProjectRoot(process.env['VGAI_PROJECT']);
|
|
298
|
+
|
|
299
|
+
// THE PRODUCT'S BUILD is what this host serves — `npm run build -w
|
|
300
|
+
// @vgai/game-editor` / `-w @vgai/model-editor`, each into its own package's
|
|
301
|
+
// `dist/` (`packages/editor/vite-product-build.ts`). The kit has no browser
|
|
302
|
+
// build of its own any more: `frame/bridge.tsx` is a module the product's entry
|
|
303
|
+
// imports, and the ENTRY is what a build has (ARCHITECTURE-CORE §The target
|
|
304
|
+
// shape, rule 4: "each product's build is its own entry").
|
|
305
|
+
//
|
|
306
|
+
// `null` when this session serves no product — the served-modules door says so
|
|
307
|
+
// by name rather than answering with an empty directory.
|
|
308
|
+
const resolvedProduct = sessionProduct(projectPath);
|
|
309
|
+
if (resolvedProduct === null) {
|
|
310
|
+
// The same refusal the CLI prints before it ever spawns this process. Said
|
|
311
|
+
// again here because this host can also be started by hand, and a packaged
|
|
312
|
+
// session with no product has no bundle to serve at all — there is nothing to
|
|
313
|
+
// degrade to.
|
|
314
|
+
try {
|
|
315
|
+
resolveProductForProject(projectPath);
|
|
316
|
+
} catch (error) {
|
|
317
|
+
console.error(`\n \x1b[31m${error instanceof Error ? error.message : String(error)}\x1b[0m\n`);
|
|
318
|
+
}
|
|
319
|
+
process.exit(1);
|
|
320
|
+
}
|
|
321
|
+
// Re-bound with the non-null type rather than leaning on the narrowing above:
|
|
322
|
+
// every reader below is inside a closure, and a narrowing is not a type.
|
|
323
|
+
const sessionProductIdentity: ProductIdentity = resolvedProduct;
|
|
324
|
+
const distPath = path.join(sessionProductIdentity.dir, 'dist');
|
|
325
|
+
|
|
326
|
+
// WHAT THIS SESSION WAS TOLD TO FRAME — the workbench directory `vgai edit`
|
|
327
|
+
// resolved and the two reserved ports. `null` when the launch named none.
|
|
328
|
+
const frameLaunch = frameLaunchFromEnv();
|
|
329
|
+
/** What the frame is running, once it is. Read by `/__editor/state`. */
|
|
330
|
+
let frameWorkbench: FrameWorkbench | null = null;
|
|
331
|
+
|
|
332
|
+
// Where this project's modules REALLY live — the project plus the install
|
|
333
|
+
// roots Node itself would resolve its dependencies from
|
|
334
|
+
// (`project-install-roots.ts`). This replaces a boot-time
|
|
335
|
+
// `realpath(<project>/node_modules)` guess that was correct only for a
|
|
336
|
+
// standalone flat install: a workspace-member project (every `examples/<id>`,
|
|
337
|
+
// any user monorepo game) has no `node_modules` of its own — npm hoists it
|
|
338
|
+
// ABOVE the project — and its sibling packages resolve through symlinks that
|
|
339
|
+
// land outside the project entirely, so Vite 403'd the world's own engine
|
|
340
|
+
// imports and served `?inline` CSS raw instead of transforming it. See that
|
|
341
|
+
// module's header for the measured failures.
|
|
342
|
+
const projectFsRoots = projectServingRoots(projectPath);
|
|
343
|
+
|
|
344
|
+
// D-X2: the project-static route must follow the CURRENTLY open project, not
|
|
345
|
+
// a boot-time snapshot — mirrors dev.ts's `currentProjectRoot` box, updated
|
|
346
|
+
// in the SAME `onProjectOpened` callback that extends Vite's fs.allow/
|
|
347
|
+
// watcher/game-globals shadow for a newly opened project.
|
|
348
|
+
let currentProjectRoot: string = projectPath;
|
|
349
|
+
const projectRoots = new Set<string>([projectPath]);
|
|
350
|
+
|
|
351
|
+
// C3: the OPENED project's own manifest-declared world entry files — scopes
|
|
352
|
+
// `optimizeDeps.entries` below to exactly the client code a world can mount,
|
|
353
|
+
// never `index.html`/the project's own bootstrap `main.ts` (which is how the
|
|
354
|
+
// crawl used to reach `server/` room code and crash on `@pm2/io`). Boot-time
|
|
355
|
+
// snapshot only, same trim as `runtimeSources`/`resolve.alias` below — see
|
|
356
|
+
// `project-optimize-deps-entries.ts`'s doc comment for the full rationale
|
|
357
|
+
// and the empirical proof this avoids the colyseus-scanner crash.
|
|
358
|
+
const projectOptimizeDepsEntries = computeProjectOptimizeDepsEntries(projectPath);
|
|
359
|
+
|
|
360
|
+
/** Whether `packageName` resolves from the PROJECT's own node_modules —
|
|
361
|
+
* Node's resolution rooted at the project, same discipline as
|
|
362
|
+
* `resolveInstalledPackageSrcDir` (server-utils.ts), for deps that are only
|
|
363
|
+
* safe to `optimizeDeps.include` when actually installed. */
|
|
364
|
+
function projectHasPackage(fromDir: string, packageName: string): boolean {
|
|
365
|
+
try {
|
|
366
|
+
createRequire(path.join(fromDir, 'package.json')).resolve(packageName);
|
|
367
|
+
return true;
|
|
368
|
+
} catch {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
async function main(): Promise<void> {
|
|
374
|
+
configureManagedAccountDefaults();
|
|
375
|
+
const app = express();
|
|
376
|
+
// Cross-origin isolation, and the Blender WORKER is why it stays. Removing
|
|
377
|
+
// these in the belief that nothing wanted a SharedArrayBuffer broke every
|
|
378
|
+
// module worker on the page (measured 2026-09-14): a cross-origin-isolated
|
|
379
|
+
// document may only create a dedicated worker whose SCRIPT is itself
|
|
380
|
+
// delivered with a COEP header, and without it Chrome refuses with an
|
|
381
|
+
// ErrorEvent carrying no message, no file and no error — a three-line worker
|
|
382
|
+
// failed exactly like Blender's. Blender runs in a module worker, so this
|
|
383
|
+
// middleware is load-bearing. `same-origin` costs the editor nothing — every
|
|
384
|
+
// window it opens is `noopener` already — and `credentialless` embedding
|
|
385
|
+
// keeps cross-origin assets loading (without credentials) where
|
|
386
|
+
// `require-corp` would demand a resource policy on each. Set first, ahead of
|
|
387
|
+
// every route and of Vite's own responses.
|
|
388
|
+
app.use((_req, res, next) => {
|
|
389
|
+
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
|
|
390
|
+
res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless');
|
|
391
|
+
next();
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
// Idle self-shutdown — same contract, same wiring, same reasons as dev.ts
|
|
395
|
+
// (read idle-shutdown.ts's header for the ownership story). Armed ahead of
|
|
396
|
+
// every route so `noteActivity` sees each request; the forward reference is
|
|
397
|
+
// resolved to this host's own shutdown function below.
|
|
398
|
+
let onIdleShutdown: (why: string) => void = () => {};
|
|
399
|
+
const idleShutdown = createIdleShutdown({
|
|
400
|
+
idleMs: resolveIdleShutdownMs(),
|
|
401
|
+
hasConnectedClients: () => clientCount() > 0,
|
|
402
|
+
onIdle: (why) => onIdleShutdown(why),
|
|
403
|
+
});
|
|
404
|
+
app.use((_req, _res, next) => {
|
|
405
|
+
idleShutdown.noteActivity();
|
|
406
|
+
next();
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// Same contract as dev.ts: grant the editor page the JS Self-Profiling API
|
|
410
|
+
// its own `visible-tab-fps-floor` invariant tells the reader to use, ahead of
|
|
411
|
+
// every route so it lands on whichever of this host's three paths
|
|
412
|
+
// (`express.static`, the SPA fallback, Vite) writes the document response.
|
|
413
|
+
// See `js-profiling-policy.ts`.
|
|
414
|
+
app.use(jsProfilingPolicy());
|
|
415
|
+
|
|
416
|
+
// The project's own installed runtime packages — resolved from the PROJECT's
|
|
417
|
+
// node_modules (Node's own resolution algorithm), never copies baked into
|
|
418
|
+
// this package's own tarball (see this file's header doc comment). A package
|
|
419
|
+
// that does not resolve simply contributes no alias — e.g. a project that
|
|
420
|
+
// hasn't run `npm install` yet — so a bad install reports a resolution
|
|
421
|
+
// failure without silently using the editor package's own copy.
|
|
422
|
+
const runtimeSources = new Map<string, string>();
|
|
423
|
+
for (const name of RUNTIME_PACKAGE_NAMES) {
|
|
424
|
+
const dir = resolveInstalledPackageSrcDir(projectPath, name);
|
|
425
|
+
if (dir) runtimeSources.set(name, dir);
|
|
426
|
+
}
|
|
427
|
+
const unresolvedRuntimePackages = RUNTIME_PACKAGE_NAMES.filter(
|
|
428
|
+
(name) => !runtimeSources.has(name),
|
|
429
|
+
);
|
|
430
|
+
if (unresolvedRuntimePackages.length > 0) {
|
|
431
|
+
console.warn(
|
|
432
|
+
`\n \x1b[33mWarning:\x1b[0m ${unresolvedRuntimePackages.join(', ')} not resolvable from ` +
|
|
433
|
+
`${projectPath} — run npm install in the project first. ` +
|
|
434
|
+
'Their imports will fail to resolve until then.\n',
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// The editor's OWN browser-side modules, folded into the boot pass. The
|
|
439
|
+
// four `/__vgai-*-runtime` plugins registered above synthesize modules that
|
|
440
|
+
// exist only in memory, so NO crawl entry can reach them, yet they are what
|
|
441
|
+
// the editor imports at the first Play mount / story preview — every
|
|
442
|
+
// specifier they carry was otherwise discovered mid-session, re-optimized,
|
|
443
|
+
// and hard-reloaded the controlling tab. See
|
|
444
|
+
// `project-optimize-deps-entries.ts`'s "EDITOR's own browser-side modules"
|
|
445
|
+
// section for the measurement and for why the three parts differ:
|
|
446
|
+
// `include` for the packages (gated on the project actually having them),
|
|
447
|
+
// crawl `entries` for the engine subpaths (which `exclude` below deliberately
|
|
448
|
+
// keeps source-served, and which the scanner therefore refuses to follow by
|
|
449
|
+
// specifier), and `exclude` for engine imports this project cannot resolve
|
|
450
|
+
// (without which the added crawl would throw and kill the boot).
|
|
451
|
+
const editorRuntimeIncludes = computeEditorRuntimeIncludes(projectPath);
|
|
452
|
+
const runtimeSourceCrawlEntries = computeRuntimeSourceCrawlEntries(runtimeSources);
|
|
453
|
+
const unresolvableRuntimeImports = computeUnresolvableRuntimeImports(runtimeSources, projectPath);
|
|
454
|
+
// The skew packages the project declares (`@volter/editor-blender`, `@vgai/game`): their
|
|
455
|
+
// contributions are walked at boot the way the engine's source is, so the
|
|
456
|
+
// dependencies they reach are prebundled instead of served raw — see
|
|
457
|
+
// `computePackageContributionCrawlEntries`.
|
|
458
|
+
const packageContributionCrawl = computePackageContributionCrawlEntries(projectPath);
|
|
459
|
+
|
|
460
|
+
// ONE React for everything that renders inside the EDITOR's own tree — the
|
|
461
|
+
// shell's. The shell is a prebuilt bundle with React inlined; this Vite
|
|
462
|
+
// instance serves the project's source and would otherwise resolve `react`
|
|
463
|
+
// to the PROJECT's node_modules, so a tool contribution called hooks from a
|
|
464
|
+
// different React than the one reconciling it ("Invalid hook call"). The
|
|
465
|
+
// build publishes the shell's own React as entry chunks; `sharedReactPlugin`
|
|
466
|
+
// below points the editor tree's React specifiers at those chunks' URLs. The
|
|
467
|
+
// GAME keeps the project's own React — see that plugin's doc comment for the
|
|
468
|
+
// measured reason that boundary exists.
|
|
469
|
+
const sharedReact = readSharedReactManifest(distPath);
|
|
470
|
+
if (!sharedReact) {
|
|
471
|
+
console.warn(
|
|
472
|
+
`\n \x1b[33mWarning:\x1b[0m ${distPath} carries no usable vgai-shared-react.json — this ` +
|
|
473
|
+
'editor build predates the shared-React entry chunks, or predates one of ' +
|
|
474
|
+
'them (the manifest must name every published specifier). Project tool contributions, ' +
|
|
475
|
+
'Asset Lab documents and asset inspectors will crash with "Invalid hook call" ' +
|
|
476
|
+
'because the page has two React copies. Rebuild the editor ' +
|
|
477
|
+
`(npm run build -w ${sessionProductIdentity.name}).\n`,
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
const sharedReactSpecifierUrls = sharedReact ? sharedReactUrls(sharedReact) : null;
|
|
481
|
+
|
|
482
|
+
// ONE three for the whole page — the shell's. The shell inlines three (the
|
|
483
|
+
// viewport renderer, gizmos, ~100 modules) and evaluates it at boot; this
|
|
484
|
+
// project-rooted Vite would otherwise prebundle the PROJECT's own three into
|
|
485
|
+
// `.vite/deps`, a SECOND instance whose module body trips three's
|
|
486
|
+
// `window.__THREE__` "Multiple instances" guard and keeps `vgai console` off
|
|
487
|
+
// exit-0. The build publishes the shell's three as a chunk;
|
|
488
|
+
// `sharedThreePlugin` (below, via project-serving-plugins) redirects the
|
|
489
|
+
// project graph's `three` onto its URL, and `optimizeDeps.exclude` below
|
|
490
|
+
// keeps three from being prebundled so Fiber's own `import 'three'` is
|
|
491
|
+
// externalized and follows the same redirect. See
|
|
492
|
+
// `../vite-plugin-shared-three.ts`.
|
|
493
|
+
const sharedThree = readSharedThreeManifest(distPath);
|
|
494
|
+
if (!sharedThree) {
|
|
495
|
+
console.warn(
|
|
496
|
+
`\n \x1b[33mWarning:\x1b[0m ${distPath} carries no usable vgai-shared-three.json — this ` +
|
|
497
|
+
'editor build predates the shared-three entry chunk. The page will load three.js twice ' +
|
|
498
|
+
"(the shell's inlined copy and the project's prebundled copy), and three's own " +
|
|
499
|
+
'duplicate-instance guard will warn, blocking a clean console. Rebuild the editor ' +
|
|
500
|
+
`(npm run build -w ${sessionProductIdentity.name}).\n`,
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
const sharedThreeSpecifierUrl = sharedThree ? sharedThreeUrl(sharedThree) : null;
|
|
504
|
+
|
|
505
|
+
// 1. Boot a Vite instance rooted at the PROJECT, not this editor package
|
|
506
|
+
// or a monorepo checkout — its own node_modules resolves every bare
|
|
507
|
+
// specifier for free (the run-conformance.ts pattern, live-editing not
|
|
508
|
+
// one-shot: HMR + watch stay ON, unlike that script's headless SSR run).
|
|
509
|
+
// Annotated rather than inferred: an unannotated object literal widens
|
|
510
|
+
// `configFile: false` to `boolean` and `appType: 'custom'` to `string`,
|
|
511
|
+
// neither of which `resolveConfig` accepts — so the literal typechecks on
|
|
512
|
+
// its own and only fails at the call site far below.
|
|
513
|
+
const viteInlineConfig: InlineConfig = {
|
|
514
|
+
configFile: false,
|
|
515
|
+
root: projectPath,
|
|
516
|
+
appType: 'custom', // no HTML serving/SPA-fallback — this instance only serves project modules
|
|
517
|
+
// Same reasoning as `dev.ts`: a transform failure in the project's own
|
|
518
|
+
// source must not erase this terminal's scrollback (Vite's error
|
|
519
|
+
// middleware logs with `{ clear: true }`), because the `✖ Invalid project
|
|
520
|
+
// file` verdict printed for the same edit is the record that outlives it.
|
|
521
|
+
clearScreen: false,
|
|
522
|
+
// Registry-standalone SDK loadability (WORK.md, measured by the donut
|
|
523
|
+
// build 2026-08-28): a NON-checkout-linked project installs @vgai/* from
|
|
524
|
+
// the registry as PUBLISHED TS SOURCE under node_modules. The project-
|
|
525
|
+
// module loader is `vite.ssrLoadModule`, and Vite externalizes
|
|
526
|
+
// node_modules in SSR — handing the .ts files to Node, whose type
|
|
527
|
+
// stripping refuses anything under node_modules. So a standalone project
|
|
528
|
+
// could not run its own tool contributions (`project.bake.*`,
|
|
529
|
+
// `vgai screenshot <module>`) until a checkout link existed. noExternal
|
|
530
|
+
// keeps every @vgai package inside Vite's own SSR transform, where TS
|
|
531
|
+
// source is ordinary input; a checkout link resolves outside
|
|
532
|
+
// node_modules and never hit the wall, which is why only registry
|
|
533
|
+
// installs were broken.
|
|
534
|
+
ssr: { noExternal: [/^@volter\//] },
|
|
535
|
+
// This Vite instance transforms not only project TSX (which uiOidPlugin
|
|
536
|
+
// already sends through automatic JSX) but also the installed engine's
|
|
537
|
+
// React bridge. Vite/esbuild otherwise compiles that dependency source to
|
|
538
|
+
// `React.createElement` even though the canonical bridge uses named React
|
|
539
|
+
// imports and intentionally has no global `React` binding. Keep Fast
|
|
540
|
+
// Refresh out (the custom app has no preamble host), but make the JSX
|
|
541
|
+
// runtime explicit for every TSX module served through this graph.
|
|
542
|
+
esbuild: { jsx: 'automatic' },
|
|
543
|
+
// ONE ordered list with `dev.ts` (`project-serving-plugins.ts`) — the two
|
|
544
|
+
// hand-maintained lists drifted apart three times, each time as a silent
|
|
545
|
+
// capability hole under a registry install only. `packagedOnly` is what
|
|
546
|
+
// this host genuinely adds: the shared-React redirect, the two source-write
|
|
547
|
+
// route plugins `dev.ts` instead reaches through its repo-root
|
|
548
|
+
// `configFile:`, and the synthetic module doorways that bridge the shell's
|
|
549
|
+
// prebuilt bundle to this separate, project-rooted graph.
|
|
550
|
+
plugins: createProjectServingPlugins({
|
|
551
|
+
projectRoots: () => projectRoots,
|
|
552
|
+
// A THUNK, like every other project-scoped plugin: `onProjectOpened`
|
|
553
|
+
// below moves `currentProjectRoot` when a session switches project, and a
|
|
554
|
+
// boot-time snapshot would keep resolving an INGEST root's
|
|
555
|
+
// out-of-manifest sources, the reported `resourcePath` of a write, and
|
|
556
|
+
// the shared-session path gate against the project this process started
|
|
557
|
+
// on.
|
|
558
|
+
currentProjectRoot: () => currentProjectRoot,
|
|
559
|
+
packagedOnly: {
|
|
560
|
+
// Omitted (`null`) only when this dist predates the shared-React
|
|
561
|
+
// chunks, which the boot warning above names.
|
|
562
|
+
sharedReactUrls: sharedReactSpecifierUrls,
|
|
563
|
+
// Omitted (`null`) only when this dist predates the shared-three chunk
|
|
564
|
+
// (the boot warning above names it).
|
|
565
|
+
sharedThreeUrl: sharedThreeSpecifierUrl,
|
|
566
|
+
editorPackageRoot,
|
|
567
|
+
checkoutRoot,
|
|
568
|
+
doorways: PACKAGED_MODULE_DOORWAYS,
|
|
569
|
+
},
|
|
570
|
+
// Always registered here — a project is ALWAYS open in packaged mode,
|
|
571
|
+
// unlike dev.ts's conditional-on-boot-time-projectPath gate. No
|
|
572
|
+
// `watchDir`: this instance's Vite root IS the project.
|
|
573
|
+
scriptHmr: { projectRoot: () => currentProjectRoot },
|
|
574
|
+
}),
|
|
575
|
+
optimizeDeps: {
|
|
576
|
+
// C3 (phase-b/c3-r3f-packaged) — SCOPED auto-discovery, not disabled
|
|
577
|
+
// discovery. This used to be `noDiscovery: true` (see git history for
|
|
578
|
+
// the pre-C3 version of this comment): that flag disabled Vite's
|
|
579
|
+
// AUTO-prebundling entirely — both the boot-time crawl AND the lazy,
|
|
580
|
+
// on-request discovery of new bare specifiers — because the DEFAULT
|
|
581
|
+
// crawl target (the project's own `index.html`) follows everything
|
|
582
|
+
// dynamically reachable from it, including the project's `server/`
|
|
583
|
+
// room code (a scaffolded project's `src/main.ts` dynamically imports
|
|
584
|
+
// `../server/rooms` behind a `?net=p2p-host` URL-param branch — a
|
|
585
|
+
// branch esbuild's scanner still statically follows), whose colyseus
|
|
586
|
+
// server transitive deps (`@colyseus/core` -> `@pm2/io`) have no
|
|
587
|
+
// browser-resolvable entry and crash the esbuild prebundle step
|
|
588
|
+
// (`Failed to resolve entry for package "@pm2/io"`).
|
|
589
|
+
//
|
|
590
|
+
// That worked for the react-only CJS fix (C1) because the fix could be
|
|
591
|
+
// fully hardcoded: react/react-dom are ALWAYS present (the editor
|
|
592
|
+
// itself depends on them). It does NOT work for R3F (or any other
|
|
593
|
+
// ecosystem a project's own `package.json` happens to pull in): this
|
|
594
|
+
// server can't hardcode `@react-three/fiber` into `include` for every
|
|
595
|
+
// possible project — most projects don't have it installed, and Vite
|
|
596
|
+
// errors on `include`-ing a dep that isn't there.
|
|
597
|
+
//
|
|
598
|
+
// The actual fix: scope the CRAWL, don't disable it. `entries` below
|
|
599
|
+
// points the crawl at the OPENED PROJECT's own manifest-declared world
|
|
600
|
+
// entry files (`computeProjectOptimizeDepsEntries` /
|
|
601
|
+
// `project-optimize-deps-entries.ts`) instead of `index.html` — the
|
|
602
|
+
// exact per-world mount code the editor's binding-resolver dynamically
|
|
603
|
+
// imports for Play mode (NEVER the project's own `src/main.ts`
|
|
604
|
+
// bootstrap, which is a standalone-build concern this Vite instance
|
|
605
|
+
// never serves anyway — the editor's own prebuilt SPA answers `/`).
|
|
606
|
+
// A world entry's import graph can reach real client packages
|
|
607
|
+
// (`react`, `@react-three/fiber`, `@react-three/drei`, a legitimate
|
|
608
|
+
// client `@colyseus/sdk` import for real multiplayer) but never
|
|
609
|
+
// `server/` — see `project-optimize-deps-entries.ts`'s doc comment for
|
|
610
|
+
// the empirical proof (a direct `vite.optimizeDeps` run) that this
|
|
611
|
+
// scoping avoids the `@pm2/io` crash for a colyseus-bearing project
|
|
612
|
+
// while a `@react-three/fiber`-bearing world's CJS transitive deps
|
|
613
|
+
// (`use-sync-external-store` and friends) get discovered and
|
|
614
|
+
// prebundled automatically — no allowlist, adapts to whatever the
|
|
615
|
+
// opened project actually has installed.
|
|
616
|
+
//
|
|
617
|
+
// `include` below is now a MINIMUM baseline, not the only mechanism:
|
|
618
|
+
// React's JSX-runtime specifiers are INJECTED by the JSX transform
|
|
619
|
+
// (not written as literal source imports), so even an entries-scoped
|
|
620
|
+
// crawl does not reliably discover them on its own — the repo-root
|
|
621
|
+
// `vite.config.ts` / template `vite.config.ts` `optimizeDeps.include`
|
|
622
|
+
// carry the identical comment/list for the same reason. Kept
|
|
623
|
+
// unconditional (not project-conditional) since react/react-dom are
|
|
624
|
+
// always present (the editor's own react-world mount runtime depends
|
|
625
|
+
// on them regardless of what a given project uses).
|
|
626
|
+
//
|
|
627
|
+
// `react-dom` (bare, NOT just `/client`) was added for C1
|
|
628
|
+
// (`phase-b/c1-react-mount`): `vite-plugin-module-doorways.ts`'s
|
|
629
|
+
// synthetic `/__vgai-react-world-runtime` module re-exports `flushSync`
|
|
630
|
+
// from bare `react-dom` (the same peer `react-dom/client`'s `createRoot`
|
|
631
|
+
// comes from — `design-time-layers.ts`'s react-world layer mount needs
|
|
632
|
+
// it from that SAME installed package). Confirmed live at the time:
|
|
633
|
+
// a real-browser Playwright run against a tarball-installed,
|
|
634
|
+
// checkout-absent packaged editor threw exactly `SyntaxError: The
|
|
635
|
+
// requested module '/node_modules/react-dom/index.js' does not
|
|
636
|
+
// provide an export named 'flushSync'` at Play-mode mount before this
|
|
637
|
+
// entry was added.
|
|
638
|
+
include: [
|
|
639
|
+
'react',
|
|
640
|
+
'react-dom',
|
|
641
|
+
'react-dom/client',
|
|
642
|
+
'react/jsx-runtime',
|
|
643
|
+
'react/jsx-dev-runtime',
|
|
644
|
+
// ^ the GAME's React, and it stays prebundled: the game mounts into
|
|
645
|
+
// its own isolated tree with its own development React and reconciler
|
|
646
|
+
// (see the `sharedReactPlugin` registration above for why the editor
|
|
647
|
+
// shell's production React must not reach it).
|
|
648
|
+
//
|
|
649
|
+
// A scaffold's project-authored client modules are loaded lazily by
|
|
650
|
+
// the prebuilt editor. They are outside the manifest-world entry
|
|
651
|
+
// crawl above, so a cold install otherwise discovers what they import
|
|
652
|
+
// in waves and Vite hard-reloads the controlling tab each time.
|
|
653
|
+
// The editor's own widget kit is NOT here — it renders in the editor's
|
|
654
|
+
// own React tree, so it is `exclude`d below and source-served, which is
|
|
655
|
+
// the only way `sharedReactPlugin`'s scope reaches its React imports.
|
|
656
|
+
// Its dependency closure is deliberately shallow (react plus the widget
|
|
657
|
+
// files — see `src/widgets/index.ts`'s header), so source-serving it
|
|
658
|
+
// costs a round of module requests, not a discovery wave. The ENGINE
|
|
659
|
+
// subpaths these modules import are handled a third way — as crawl
|
|
660
|
+
// `entries` (see `LAZY_ENGINE_CRAWL_SUBPATHS`), because `include`-ing an
|
|
661
|
+
// engine module prebundles a second copy of everything it reaches,
|
|
662
|
+
// which is exactly the split WorldProvider identity the `exclude`
|
|
663
|
+
// below exists to prevent.
|
|
664
|
+
//
|
|
665
|
+
// Project tool contributions load this after the shell is visible;
|
|
666
|
+
// discovering it then would invalidate the already-loaded React graph.
|
|
667
|
+
'zod',
|
|
668
|
+
// The story runtime (`/__vgai-story-runtime`) re-exports
|
|
669
|
+
// `@storybook/react`, which a project's CSF files import ONLY as
|
|
670
|
+
// types (erased) — so the entries crawl never discovers it, and the
|
|
671
|
+
// first story preview/capture of a session would otherwise trigger a
|
|
672
|
+
// second optimization wave and hard-reload the controlling tab
|
|
673
|
+
// mid-command. Conditional because Vite errors on `include`-ing a
|
|
674
|
+
// package that isn't installed, and `@storybook/react` is a
|
|
675
|
+
// devDependency a project may legitimately not have (it then has no
|
|
676
|
+
// usable stories, and the story lane reports the missing package by
|
|
677
|
+
// name — story-dom-runtime.ts).
|
|
678
|
+
...(projectHasPackage(projectPath, '@storybook/react') ? ['@storybook/react'] : []),
|
|
679
|
+
// The editor's own synthesized runtime modules' packages (`three`,
|
|
680
|
+
// `@react-three/fiber`, … — whatever those module bodies actually
|
|
681
|
+
// import, read from the bodies themselves). Same installed-only gate
|
|
682
|
+
// as the two conditionals above, for the same reason.
|
|
683
|
+
//
|
|
684
|
+
// `three` is dropped from this list when the shared-three redirect is
|
|
685
|
+
// active (`sharedThreeSpecifierUrl`): it moves to `exclude` below so
|
|
686
|
+
// Fiber's own `import 'three'` is externalized onto the shell's one
|
|
687
|
+
// copy, and a specifier cannot be both `include` and `exclude`. The
|
|
688
|
+
// three ADDONS stay included — they prebundle fine, and their internal
|
|
689
|
+
// `import 'three'` is the externalized one. When no shared-three chunk
|
|
690
|
+
// exists (old dist), three stays included/prebundled as before.
|
|
691
|
+
...(sharedThreeSpecifierUrl
|
|
692
|
+
? editorRuntimeIncludes.filter((specifier) => specifier !== 'three')
|
|
693
|
+
: editorRuntimeIncludes),
|
|
694
|
+
],
|
|
695
|
+
// Installed engine entry points include TSX. Dependency optimization
|
|
696
|
+
// is a separate esbuild pipeline from Vite's top-level `esbuild`
|
|
697
|
+
// option, so it needs the same automatic runtime explicitly.
|
|
698
|
+
// `loader['.js'] = 'jsx'` is the SCANNER half of the JSX-in-`.js`
|
|
699
|
+
// acceptance (`projectJsxInJsPlugin` in the plugin list above is the
|
|
700
|
+
// transform half, and `project-validation.ts`'s `sourceLoader` the
|
|
701
|
+
// validate half — the plugin's header names all three and why fixing
|
|
702
|
+
// one alone leaves the others red). `dev.ts` has carried it since the
|
|
703
|
+
// transform landed; this host had neither, so a CRA-era ingested game
|
|
704
|
+
// under a registry install died at its first `.js` file.
|
|
705
|
+
esbuildOptions: { jsx: 'automatic', loader: { '.js': 'jsx' } },
|
|
706
|
+
// Spelled root-relative wherever the file is under the project, because
|
|
707
|
+
// Vite reads the whole list as ONE decision: one entry that parses as a
|
|
708
|
+
// glob pattern (a project at `~/my (game)`) sends every entry through
|
|
709
|
+
// `glob()`, whose `**/node_modules/**` ignore silently drops the
|
|
710
|
+
// engine-source crawl entries below. See `viteOptimizeDepsEntries`.
|
|
711
|
+
entries: viteOptimizeDepsEntries(projectPath, [
|
|
712
|
+
...projectOptimizeDepsEntries,
|
|
713
|
+
...runtimeSourceCrawlEntries,
|
|
714
|
+
...packageContributionCrawl.entries,
|
|
715
|
+
]),
|
|
716
|
+
// C3 hardening: belt to the entries-scoping suspenders. Entries-scoping
|
|
717
|
+
// ALREADY keeps the crawl out of `server/` for a well-formed project
|
|
718
|
+
// (so the colyseus server stack is never reached), but a project that
|
|
719
|
+
// VIOLATES D2 by value-importing `server/` room code FROM a world entry
|
|
720
|
+
// would drag `@colyseus/core` -> `@pm2/io` into the crawl and crash the
|
|
721
|
+
// esbuild prebundle step — which, unhandled in the async optimizer,
|
|
722
|
+
// hard-kills the whole packaged process (the only authoring surface).
|
|
723
|
+
// Excluding these SERVER-ONLY names stops esbuild crawling into them, so
|
|
724
|
+
// that pathological world degrades to a benign in-browser import failure
|
|
725
|
+
// instead of process death. Does NOT include `@colyseus/sdk` — the
|
|
726
|
+
// legitimate CLIENT SDK a real multiplayer project imports (D2, dynamic-
|
|
727
|
+
// imported) must still prebundle; it is a separate package and its path
|
|
728
|
+
// is untouched. See `project-optimize-deps-entries.ts`'s
|
|
729
|
+
// `SERVER_ONLY_PREBUNDLE_EXCLUDE` doc comment for the live proof.
|
|
730
|
+
exclude: [
|
|
731
|
+
...SERVER_ONLY_PREBUNDLE_EXCLUDE,
|
|
732
|
+
// ONE three for the whole page. Excluding `three` externalizes it out
|
|
733
|
+
// of every prebundled chunk (notably `@react-three/fiber`'s), so those
|
|
734
|
+
// chunks' `import 'three'` is resolved at serve time by
|
|
735
|
+
// `sharedThreePlugin` and lands on the shell's single published copy
|
|
736
|
+
// instead of a second `.vite/deps/three.js`. Only when the shell
|
|
737
|
+
// actually published that chunk — otherwise three must stay prebundled
|
|
738
|
+
// (there is nothing to redirect to). See `../vite-plugin-shared-three.ts`.
|
|
739
|
+
...(sharedThreeSpecifierUrl ? ['three'] : []),
|
|
740
|
+
// The editor's own widget kit, the API's fourth face. A PREBUNDLED
|
|
741
|
+
// package bakes its React import at prebundle time, where
|
|
742
|
+
// `sharedReactPlugin`'s source-level scope can never reach it — and
|
|
743
|
+
// this kit renders inside the EDITOR's React tree, so a prebundled
|
|
744
|
+
// copy is a second React and the crash box that plugin exists to
|
|
745
|
+
// remove. Source-served, its `react` import resolves through the
|
|
746
|
+
// plugin like any other editor-tree module. (It is listed with the
|
|
747
|
+
// SDK's other doors below for the same reason; the name is here
|
|
748
|
+
// because the kit is the one a PROJECT's own contributions import.)
|
|
749
|
+
'@volter/editor-sdk/widgets',
|
|
750
|
+
// The Blender engine spawns its worker as
|
|
751
|
+
// `new Worker(new URL('./worker.ts', import.meta.url))`. Prebundled,
|
|
752
|
+
// that URL is rewritten against a `.vite/deps` chunk that has no
|
|
753
|
+
// worker beside it, and the request 404s — measured 2026-09-20 from a
|
|
754
|
+
// REGISTRY install (invisible from a checkout, where the package is a
|
|
755
|
+
// symlink Vite serves as source): every Model document died with
|
|
756
|
+
// "Blender worker failed: the worker script did not load". Served as
|
|
757
|
+
// source, the URL resolves to the package's own file.
|
|
758
|
+
//
|
|
759
|
+
// THIS LIST IS THE KIT'S, AND A PRODUCT ADDS NOTHING TO IT (measured
|
|
760
|
+
// 2026-09-21, WORK.md step 3 P1). This instance is rooted at the
|
|
761
|
+
// PROJECT and prebundles what the PROJECT's graph reaches: a package
|
|
762
|
+
// the project DECLARES, whose contributions are served `/@fs/` from its
|
|
763
|
+
// own install — which is how `@volter/editor-blender` gets here, and why the
|
|
764
|
+
// name below is a fact about a project's dependency rather than about
|
|
765
|
+
// any composition. A package the PRODUCT composes is in the product's
|
|
766
|
+
// built bundle, which this instance never transforms, so no
|
|
767
|
+
// product-declared dependency needs an exclusion and there is no
|
|
768
|
+
// `vgai.product.optimizeDepsExclude` to declare one with.
|
|
769
|
+
'@volter/blender-engine',
|
|
770
|
+
'@volter/blender-engine/browser',
|
|
771
|
+
'@volter/editor-sdk/layouts',
|
|
772
|
+
'@volter/editor-sdk/layout-arrangements',
|
|
773
|
+
// The SDK's OTHER doors, same rule: each holds module state or calls
|
|
774
|
+
// React hooks, and a prebundled copy would carry the PROJECT's React
|
|
775
|
+
// into the editor's tree — measured 2026-09-17 as "Cannot read
|
|
776
|
+
// properties of null (reading 'useSyncExternalStore')" from a package
|
|
777
|
+
// contribution's status item, whose `@volter/editor-sdk/host` had been
|
|
778
|
+
// prebundled with `.vite/deps/react.js` inside it.
|
|
779
|
+
'@volter/editor-sdk/host',
|
|
780
|
+
'@volter/editor-sdk/contributions',
|
|
781
|
+
'@volter/editor-sdk/commands',
|
|
782
|
+
'@volter/editor-sdk/looks',
|
|
783
|
+
// Engine imports this project cannot resolve — the guard that lets the
|
|
784
|
+
// engine-source crawl entries above be safe. An unresolvable bare
|
|
785
|
+
// import makes Vite's discovery THROW ("imported but could not be
|
|
786
|
+
// resolved"), which rejects the boot-time `optimizeDeps()` barrier
|
|
787
|
+
// below and kills the process; excluding the name externalizes it in
|
|
788
|
+
// the scanner instead, degrading one optional engine feature in the
|
|
789
|
+
// browser rather than the whole editor. See
|
|
790
|
+
// `computeUnresolvableRuntimeImports`.
|
|
791
|
+
...unresolvableRuntimeImports,
|
|
792
|
+
...packageContributionCrawl.unresolvable,
|
|
793
|
+
// The project's runtime-package source is the document-side module
|
|
794
|
+
// graph. Keep every subpath source-served so an arbitrary project
|
|
795
|
+
// import cannot create a second prebundled WorldProvider identity.
|
|
796
|
+
// React/Fiber themselves remain prebundled and deduped above.
|
|
797
|
+
//
|
|
798
|
+
// The scanner matches the RAW specifier before any alias runs, so a
|
|
799
|
+
// package left out here is prebundlable — which is how eight runtime
|
|
800
|
+
// modules (`world3d-react`, `runtime/mount-game`, …) once sat in
|
|
801
|
+
// `.vite/deps` beside their source-served twins, each chunk carrying
|
|
802
|
+
// its own bundled `react/world-state` `GameContext`.
|
|
803
|
+
...RUNTIME_PACKAGE_NAMES,
|
|
804
|
+
],
|
|
805
|
+
},
|
|
806
|
+
resolve: {
|
|
807
|
+
// `configFile: false` deliberately ignores the project's Vite config,
|
|
808
|
+
// so reconstruct the template's renderer identity contract here. Fiber,
|
|
809
|
+
// Drei, the installed engine and the world must share these instances.
|
|
810
|
+
// The runtime packages are in the list for the same
|
|
811
|
+
// WorldProvider/`useGame` singleton the checkout-rooted `dev.ts` path
|
|
812
|
+
// gets from repo-root `vite.config.ts` (see that file's dedupe comment).
|
|
813
|
+
// The alias below already points each specifier at the project's own
|
|
814
|
+
// installed source when it resolves; dedupe is the remaining collapse
|
|
815
|
+
// for a nested copy that alias resolution still walks into.
|
|
816
|
+
dedupe: [
|
|
817
|
+
'@volter/editor-sdk',
|
|
818
|
+
...RUNTIME_PACKAGE_NAMES,
|
|
819
|
+
'react',
|
|
820
|
+
'react-dom',
|
|
821
|
+
'three',
|
|
822
|
+
'@react-three/fiber',
|
|
823
|
+
'pixi.js',
|
|
824
|
+
'@pixi/react',
|
|
825
|
+
],
|
|
826
|
+
alias: [
|
|
827
|
+
// The editor's own deep specifiers a project contribution still
|
|
828
|
+
// names — `@editor/game-module-access`, and the R3F analyzer a
|
|
829
|
+
// project's `check-idioms` loads (the scaffolder writes the matching
|
|
830
|
+
// tsconfig path). The widget kit is NOT among them any more: it is
|
|
831
|
+
// `@volter/editor-sdk/widgets`, an ordinary package export. In checkout
|
|
832
|
+
// mode the root Vite config supplies this alias; this project-rooted
|
|
833
|
+
// packaged Vite instance has no configFile, so it must reconstruct
|
|
834
|
+
// the runtime half from its own package root.
|
|
835
|
+
{ find: /^@editor\//, replacement: `${path.join(editorPackageRoot, 'src')}/` },
|
|
836
|
+
// Each runtime package resolves to THIS project's installed copy.
|
|
837
|
+
// Keeping one source root per package is what preserves React/Fiber
|
|
838
|
+
// singleton identity in Play mode.
|
|
839
|
+
...[...runtimeSources].map(([name, src]) => ({
|
|
840
|
+
find: new RegExp(`^${name.replace('/', '\\/')}(?=\\/|$)`),
|
|
841
|
+
replacement: src,
|
|
842
|
+
})),
|
|
843
|
+
],
|
|
844
|
+
},
|
|
845
|
+
server: {
|
|
846
|
+
middlewareMode: true,
|
|
847
|
+
// `overlay: false` for the same product reason as `dev.ts`'s instance:
|
|
848
|
+
// this server's project modules load into the SAME page as the packaged
|
|
849
|
+
// editor shell, so Vite's full-screen error overlay would cover the
|
|
850
|
+
// editor whenever the game fails to compile. `overlay` is the CLIENT
|
|
851
|
+
// overlay only — HMR itself (and therefore `vgai-script-hmr`'s WebSocket
|
|
852
|
+
// delivery, which the header note above says `hmr: false` would kill)
|
|
853
|
+
// stays fully on.
|
|
854
|
+
hmr: { port: HMR_PORT, clientPort: HMR_CLIENT_PORT, overlay: false },
|
|
855
|
+
// OFF because the shared-React doorway makes it structurally broken in
|
|
856
|
+
// THIS instance — see `vite-plugin-shared-react.ts`. Every editor-tree
|
|
857
|
+
// module's `react`/`react/jsx-runtime` import is resolved to the prebuilt
|
|
858
|
+
// shell's own chunk URL (`/assets/vgai-shared-*.js`), which the BROWSER
|
|
859
|
+
// fetches from `express.static(dist)` below and this project-rooted Vite
|
|
860
|
+
// deliberately cannot resolve. Import analysis then hands each of those
|
|
861
|
+
// URLs to `warmupRequest`, which resolves them against the project root,
|
|
862
|
+
// fails, and logs a formatted `Pre-transform error` — measured on a fresh
|
|
863
|
+
// scaffold: 64 of them from ONE `src/contributions/*.inspector.tsx` request,
|
|
864
|
+
// because nothing caches a failed warmup and each import site retries it.
|
|
865
|
+
//
|
|
866
|
+
// The plugin already opts out of Vite's dependency SCAN for exactly this
|
|
867
|
+
// reason (`options.scan` — the scanner recorded the URL as a file to
|
|
868
|
+
// prebundle and died on ENOENT). Pre-transform is the same class of
|
|
869
|
+
// server-side pass following a browser-only redirect, but Vite exposes no
|
|
870
|
+
// per-request opt-out, and the alternative — teaching this Vite to LOAD
|
|
871
|
+
// those URLs from `dist/` — is worse than the noise: each doorway chunk
|
|
872
|
+
// imports the shell's own `./index-*.js`, so satisfying one warmup drags
|
|
873
|
+
// the entire prebuilt SPA into the project's dev module graph, which is
|
|
874
|
+
// the exact separation this file's two-graph design exists to keep.
|
|
875
|
+
//
|
|
876
|
+
// What is given up is latency-only: known static imports are transformed
|
|
877
|
+
// when the browser asks instead of just before. The editor reaches the
|
|
878
|
+
// project through DYNAMIC imports (tool contributions, world entries,
|
|
879
|
+
// stories), which pre-transform skips anyway, and this instance declares
|
|
880
|
+
// no `server.warmup` list (which the same flag would have disabled).
|
|
881
|
+
preTransformRequests: false,
|
|
882
|
+
// Watch source; never watch output — the same list as `dev.ts`'s
|
|
883
|
+
// instance, for the same product reason: a build (`npm run build`,
|
|
884
|
+
// `vercel build`) rewriting output HTML inside the project root reads
|
|
885
|
+
// as a source change and full-page-reloads the editor tab out from
|
|
886
|
+
// under whatever it was doing.
|
|
887
|
+
watch: {
|
|
888
|
+
ignored: [
|
|
889
|
+
// Scratch HTML/tsconfig writes must not reload the active editor.
|
|
890
|
+
(filename: string) => isProjectScratchPath(filename, projectRoots),
|
|
891
|
+
'**/.claude/worktrees/**',
|
|
892
|
+
'**/.vercel/**',
|
|
893
|
+
'**/dist/**',
|
|
894
|
+
'**/dist-ssr/**',
|
|
895
|
+
'**/dist-wip/**',
|
|
896
|
+
'**/logs/**',
|
|
897
|
+
],
|
|
898
|
+
},
|
|
899
|
+
fs: {
|
|
900
|
+
allow: [
|
|
901
|
+
...projectFsRoots,
|
|
902
|
+
// The `@editor/*` deep specifiers above are source-served, so this
|
|
903
|
+
// package's own `src/` must be readable even when it does not sit
|
|
904
|
+
// under the project's own resolved `node_modules`.
|
|
905
|
+
editorPackageRoot,
|
|
906
|
+
],
|
|
907
|
+
},
|
|
908
|
+
},
|
|
909
|
+
};
|
|
910
|
+
|
|
911
|
+
// This is a custom, prebuilt SPA host: unlike Vite's normal HTML-serving
|
|
912
|
+
// path, nothing asks the project-rooted middleware server for an HTML entry
|
|
913
|
+
// before the editor begins importing its virtual runtime modules. Finish the
|
|
914
|
+
// entries-scoped optimizer pass first so every project module sees one
|
|
915
|
+
// browser hash from the first request. Without this barrier, the synthetic
|
|
916
|
+
// React/R3F runtime can load against the provisional hash while the world
|
|
917
|
+
// entry loads against the scan's committed hash, producing two React/Fiber
|
|
918
|
+
// graphs and an invalid-hook-call failure on a clean packaged install.
|
|
919
|
+
const resolvedViteConfig = await resolveConfig(viteInlineConfig, 'serve');
|
|
920
|
+
await optimizeDeps(resolvedViteConfig);
|
|
921
|
+
const vite = await createViteServer(resolvedViteConfig);
|
|
922
|
+
|
|
923
|
+
// 2. Mount editor API routes (/__editor/*). `engineRoot` identifies the
|
|
924
|
+
// running packaged editor for runtime capability checks.
|
|
925
|
+
const editorRouter = createEditorServer({
|
|
926
|
+
engineRoot: editorPackageRoot,
|
|
927
|
+
projectPath,
|
|
928
|
+
collaborationPort: PORT,
|
|
929
|
+
// This host DOES serve the `/__ui-source/*` recorder (`uiOidPlugin()` is
|
|
930
|
+
// registered above), and saying so is what makes design-time edits write
|
|
931
|
+
// the game's own TSX under a registry install. Read off the resolved
|
|
932
|
+
// plugin list rather than hardcoded `true`, so removing the plugin can
|
|
933
|
+
// never leave a flag claiming a route that is gone.
|
|
934
|
+
sourceWriteRoutes: servesUiSourceRoutes(vite.config.plugins),
|
|
935
|
+
// And the ingest lane's route, off the same resolved list — this host
|
|
936
|
+
// registers `creationSiteWritePlugin()` above, and saying so is what lets an
|
|
937
|
+
// ingest edit be written into the game's own source under a registry
|
|
938
|
+
// install instead of reporting the live-only floor forever.
|
|
939
|
+
ingestSourceWriteRoutes: servesIngestSourceRoutes(vite.config.plugins),
|
|
940
|
+
// Tab bijection — same session contract as dev.ts: one blessed browser
|
|
941
|
+
// tab, self-healed and closed with the session; VGAI_NO_OPEN (the CLI's
|
|
942
|
+
// --no-open) disables the whole loop for headless sessions.
|
|
943
|
+
tabBijection: {
|
|
944
|
+
enabled: !process.env['VGAI_NO_OPEN'],
|
|
945
|
+
// Same contract as dev.ts: under the frame this session's ONE tab is the
|
|
946
|
+
// workbench page, and the url is arithmetic over the reserved proxy port.
|
|
947
|
+
editorUrl: frameLaunch ? frameWorkbenchUrl(frameLaunch, projectPath) : `${EDITOR_ORIGIN}/`,
|
|
948
|
+
},
|
|
949
|
+
// The session's children are the session's to report (`vgai status`).
|
|
950
|
+
workbench: () => frameWorkbench?.identity ?? null,
|
|
951
|
+
// The serving door (routes/served-modules.ts), same contract as dev.ts:
|
|
952
|
+
// where the Code-OSS frame finds the editor. Registered on BOTH bundler
|
|
953
|
+
// hosts deliberately — a capability that exists on one and not the other is
|
|
954
|
+
// the drift `project-serving-plugins.ts`'s header was written about. Here
|
|
955
|
+
// the answer is the PRODUCTION BUILD's frame entry (WORK.md §U3), reached
|
|
956
|
+
// through the wrapper below rather than directly, because the built entry's
|
|
957
|
+
// stylesheet has no HTML of ours to be injected into.
|
|
958
|
+
frameBridgeUrl: () => {
|
|
959
|
+
readBuiltProductEntry(distPath, sessionProductIdentity);
|
|
960
|
+
return FRAME_BRIDGE_PACKAGED_PATH;
|
|
961
|
+
},
|
|
962
|
+
// The session's children are its to report: which product it is serving,
|
|
963
|
+
// beside which workbench it is running.
|
|
964
|
+
product: () => ({
|
|
965
|
+
id: sessionProductIdentity.name,
|
|
966
|
+
dir: sessionProductIdentity.dir,
|
|
967
|
+
version: sessionProductIdentity.version,
|
|
968
|
+
}),
|
|
969
|
+
loadProjectModule: freshProjectModuleLoader(vite, () => projectPath),
|
|
970
|
+
// Same contract as dev.ts: a dependency installed under a live session
|
|
971
|
+
// (`vgai add <capability>`) is invisible until the SSR module graph, which
|
|
972
|
+
// caches even a REJECTED module load, is dropped.
|
|
973
|
+
invalidateProjectModules() {
|
|
974
|
+
vite.environments.ssr.moduleGraph.invalidateAll();
|
|
975
|
+
console.log('[vgai-editor] project dependencies changed; reloaded project modules.');
|
|
976
|
+
},
|
|
977
|
+
onProjectOpened(newProjectPath: string) {
|
|
978
|
+
const allowed = vite.config.server.fs.allow;
|
|
979
|
+
// The newly opened project's OWN install roots, not just its folder —
|
|
980
|
+
// a project switched into at runtime has exactly the hoisting/symlink
|
|
981
|
+
// shapes the boot-time set above exists for.
|
|
982
|
+
for (const root of projectServingRoots(newProjectPath)) {
|
|
983
|
+
if (!allowed.includes(root)) allowed.push(root);
|
|
984
|
+
}
|
|
985
|
+
projectRoots.add(newProjectPath);
|
|
986
|
+
vite.watcher.add(newProjectPath);
|
|
987
|
+
currentProjectRoot = newProjectPath;
|
|
988
|
+
// Session parity with dev.ts (D12): keep the registry pointing
|
|
989
|
+
// at the CURRENT project so `vgai edit`/`sessions`/cwd-resolution see
|
|
990
|
+
// switches, not boot state — same call, same shape.
|
|
991
|
+
registerSession({
|
|
992
|
+
project: newProjectPath,
|
|
993
|
+
port: PORT,
|
|
994
|
+
pid: process.pid,
|
|
995
|
+
startedAt: sessionStartedAt,
|
|
996
|
+
});
|
|
997
|
+
},
|
|
998
|
+
});
|
|
999
|
+
app.use(editorRouter);
|
|
1000
|
+
|
|
1001
|
+
// 3. The project-rooted Vite instance — handles `/@fs/`, `/@id/`, and any
|
|
1002
|
+
// request matching a real file under the project root (module
|
|
1003
|
+
// transform + bare-specifier resolution through the PROJECT's own
|
|
1004
|
+
// node_modules). `appType: 'custom'` means it calls `next()` instead of
|
|
1005
|
+
// synthesizing an HTML/404 response for anything else, so requests for
|
|
1006
|
+
// the editor's OWN app (`/`, `/assets/*`) fall through to step 4.
|
|
1007
|
+
app.use(vite.middlewares);
|
|
1008
|
+
|
|
1009
|
+
// 3b. The Code-OSS frame's entry into this build (routes/served-modules.ts
|
|
1010
|
+
// answers this url). Generated per request rather than emitted at build
|
|
1011
|
+
// time, because both halves it needs — the hashed chunk and its
|
|
1012
|
+
// stylesheets — are facts about the `dist/` this process is serving.
|
|
1013
|
+
app.get(FRAME_BRIDGE_PACKAGED_PATH, (_req, res) => {
|
|
1014
|
+
let body: string;
|
|
1015
|
+
try {
|
|
1016
|
+
body = builtFrameBridgeModule(readBuiltProductEntry(distPath, sessionProductIdentity));
|
|
1017
|
+
} catch (error) {
|
|
1018
|
+
// The door already reports this sentence as a refusal; a direct fetch of
|
|
1019
|
+
// this url gets it too rather than an empty 200 that imports nothing.
|
|
1020
|
+
res
|
|
1021
|
+
.status(503)
|
|
1022
|
+
.type('text/plain')
|
|
1023
|
+
.send(error instanceof Error ? error.message : String(error));
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
1026
|
+
res.type('text/javascript').set('Cache-Control', 'no-store').send(body);
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
// 4. Serve the PRODUCT's prebuilt chunks (static — no dev-mode transform of
|
|
1030
|
+
// editor or product source; see this file's header doc comment). The
|
|
1031
|
+
// module served at step 3b re-exports one of these by its hashed name.
|
|
1032
|
+
app.use(express.static(distPath));
|
|
1033
|
+
|
|
1034
|
+
// 5. Start Express
|
|
1035
|
+
const sessionStartedAt = new Date().toISOString();
|
|
1036
|
+
const server = app.listen(PORT, HOST, () => {
|
|
1037
|
+
void (async () => {
|
|
1038
|
+
console.log(
|
|
1039
|
+
`\n \x1b[32mEditor server\x1b[0m (packaged) running at \x1b[36m${EDITOR_ORIGIN}\x1b[0m`,
|
|
1040
|
+
);
|
|
1041
|
+
console.log(` \x1b[33mProject\x1b[0m: ${projectPath}`);
|
|
1042
|
+
console.log(` \x1b[33mEditor\x1b[0m: \x1b[36m${EDITOR_ORIGIN}/\x1b[0m\n`);
|
|
1043
|
+
if (idleShutdown.armed) {
|
|
1044
|
+
console.log(
|
|
1045
|
+
` Idle shutdown after ${formatIdleWindow(resolveIdleShutdownMs())} with no connected ` +
|
|
1046
|
+
`editor tab and no request (${IDLE_SHUTDOWN_MINUTES_ENV}=0 disables)\n`,
|
|
1047
|
+
);
|
|
1048
|
+
}
|
|
1049
|
+
// D12: announce this session so `vgai edit`/`sessions`/`play`
|
|
1050
|
+
// (cwd-resolution) see the packaged runtime exactly like dev.ts's.
|
|
1051
|
+
registerSession({
|
|
1052
|
+
project: projectPath,
|
|
1053
|
+
port: PORT,
|
|
1054
|
+
pid: process.pid,
|
|
1055
|
+
startedAt: sessionStartedAt,
|
|
1056
|
+
});
|
|
1057
|
+
// The workbench, last and for the same reason dev.ts starts it last: it
|
|
1058
|
+
// is the slowest thing this boot does, and a frame that cannot start is a
|
|
1059
|
+
// `vgai edit` that has failed (frame-workbench.ts states the ownership).
|
|
1060
|
+
if (frameLaunch) {
|
|
1061
|
+
// THE AGENT'S RUNTIME COMES FIRST — same reason as dev.ts: an extension
|
|
1062
|
+
// host inherits its server's environment and that environment is fixed
|
|
1063
|
+
// at spawn (frame-workbench.ts's `env`, frontend-handoff.ts's header).
|
|
1064
|
+
const handoff = await editorRouter.frontendHandoff();
|
|
1065
|
+
if (handoff.refusal) console.log(` \x1b[33mAgent\x1b[0m: ${handoff.refusal}`);
|
|
1066
|
+
try {
|
|
1067
|
+
frameWorkbench = await startFrameWorkbench({
|
|
1068
|
+
launch: frameLaunch,
|
|
1069
|
+
projectRoot: projectPath,
|
|
1070
|
+
sessionPort: PORT,
|
|
1071
|
+
env: handoff.env,
|
|
1072
|
+
log: (line) => console.log(` ${line}`),
|
|
1073
|
+
});
|
|
1074
|
+
console.log(` \x1b[33mWorkbench\x1b[0m: \x1b[36m${frameWorkbench.url}\x1b[0m\n`);
|
|
1075
|
+
} catch (error) {
|
|
1076
|
+
// biome-ignore lint/suspicious/noConsole: the frame's refusal IS the product here — this terminal is the only surface that exists yet.
|
|
1077
|
+
console.error(
|
|
1078
|
+
`\n \x1b[31m${error instanceof Error ? error.message : String(error)}\x1b[0m\n`,
|
|
1079
|
+
);
|
|
1080
|
+
process.exit(1);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
})();
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
// The tab's duplex control socket rides this same HTTP server — an
|
|
1087
|
+
// `upgrade` for `/__editor/events`, routed by pathname so every other
|
|
1088
|
+
// upgrade (Vite's HMR socket) passes through untouched.
|
|
1089
|
+
editorRouter.attachControlSocket(server);
|
|
1090
|
+
|
|
1091
|
+
server.on('error', (err: NodeJS.ErrnoException) => {
|
|
1092
|
+
console.error(`\n \x1b[31m${friendlyListenError(err, PORT, HOST, 'PORT')}\x1b[0m\n`);
|
|
1093
|
+
process.exit(1);
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
// Self-healing registration — same rationale and cadence as dev.ts: the
|
|
1097
|
+
// registry's unlocked read-modify-write can lose this entry to a concurrent
|
|
1098
|
+
// writer's interleaved write, leaving a healthy server invisible to
|
|
1099
|
+
// `vgai edit`/`sessions`/`close`; re-asserting once a minute heals it.
|
|
1100
|
+
const reregisterTimer = setInterval(() => {
|
|
1101
|
+
registerSession({
|
|
1102
|
+
project: currentProjectRoot,
|
|
1103
|
+
port: PORT,
|
|
1104
|
+
pid: process.pid,
|
|
1105
|
+
startedAt: sessionStartedAt,
|
|
1106
|
+
});
|
|
1107
|
+
}, 60_000);
|
|
1108
|
+
reregisterTimer.unref();
|
|
1109
|
+
|
|
1110
|
+
// Best-effort, and nothing but the HTTP server waits on it — see dev.ts's
|
|
1111
|
+
// note at its own `tabNotice` for the measurement (a `vgai close` under load
|
|
1112
|
+
// died inside this notify, the shutdown list never ran, and the Code-OSS
|
|
1113
|
+
// server outlived the session on its reserved port).
|
|
1114
|
+
let tabNotice: Promise<void> | null = null;
|
|
1115
|
+
const shutdown = createProcessShutdown({
|
|
1116
|
+
journal: (record) => editorRouter.journalShutdownTask(record),
|
|
1117
|
+
tasks: [
|
|
1118
|
+
{ name: 'tab-close notice', run: () => tabNotice ?? undefined },
|
|
1119
|
+
{
|
|
1120
|
+
name: 'http server',
|
|
1121
|
+
run: async () => {
|
|
1122
|
+
// The `tab-close` write needs a live SSE socket, and closing the
|
|
1123
|
+
// server takes those sockets down: this ORDER is the only dependency
|
|
1124
|
+
// on the notice anywhere in the list.
|
|
1125
|
+
await tabNotice;
|
|
1126
|
+
await closeHttpServer(server);
|
|
1127
|
+
},
|
|
1128
|
+
},
|
|
1129
|
+
// THE ONE TEARDOWN for the REH and the proxy (frame-workbench.ts's
|
|
1130
|
+
// ownership note) — the path `vgai close`, SIGTERM and the idle timer
|
|
1131
|
+
// all take. The detached CHILD waits on nothing; the proxy is the tab's
|
|
1132
|
+
// route and waits with the HTTP server.
|
|
1133
|
+
{ name: 'Code-OSS server', run: () => frameWorkbench?.stopServer() },
|
|
1134
|
+
{
|
|
1135
|
+
name: 'one-origin proxy',
|
|
1136
|
+
run: async () => {
|
|
1137
|
+
await tabNotice;
|
|
1138
|
+
await frameWorkbench?.closeProxy();
|
|
1139
|
+
},
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
name: 'editor router',
|
|
1143
|
+
run: async () => {
|
|
1144
|
+
// The other half of the notice's dependency: `close()` takes the
|
|
1145
|
+
// control plane down and the `tab-close` push rides it. See dev.ts's
|
|
1146
|
+
// `tabNotice` for the measurement (acked ~26ms ordered, unacked at
|
|
1147
|
+
// the full 2s budget when it races).
|
|
1148
|
+
await tabNotice;
|
|
1149
|
+
await editorRouter.close();
|
|
1150
|
+
},
|
|
1151
|
+
},
|
|
1152
|
+
{ name: 'vite', run: () => vite.close() },
|
|
1153
|
+
],
|
|
1154
|
+
});
|
|
1155
|
+
let shutdownStarted = false;
|
|
1156
|
+
const unregisterAndShutdown = (signal: string) => {
|
|
1157
|
+
// A repeat signal is not a new instruction — see dev.ts's note at its own
|
|
1158
|
+
// handler registration for the measurement behind this latch.
|
|
1159
|
+
if (shutdownStarted) return;
|
|
1160
|
+
shutdownStarted = true;
|
|
1161
|
+
idleShutdown.stop();
|
|
1162
|
+
clearInterval(reregisterTimer);
|
|
1163
|
+
unregisterSession(process.pid);
|
|
1164
|
+
// Tab bijection: session-end notice to the blessed tab.
|
|
1165
|
+
// No-op after /__editor/tab/expect-restart.
|
|
1166
|
+
tabNotice = editorRouter.notifyTabSessionEnded().catch((error) => {
|
|
1167
|
+
console.error(
|
|
1168
|
+
`[vgai-editor] tab-close notice failed: ${error instanceof Error ? error.message : error}`,
|
|
1169
|
+
);
|
|
1170
|
+
});
|
|
1171
|
+
void shutdown(signal);
|
|
1172
|
+
};
|
|
1173
|
+
// The idle timer's ONE exit: the same function a signal takes, plus the
|
|
1174
|
+
// honest line naming why the session ended (dev.ts prints this from its
|
|
1175
|
+
// shared `lastGasp`; this host has no such line, so the idle path says it).
|
|
1176
|
+
onIdleShutdown = (why) => {
|
|
1177
|
+
console.error(`[vgai-editor] shutting down (${why}) — pid ${process.pid}, port ${PORT}`);
|
|
1178
|
+
unregisterAndShutdown(why);
|
|
1179
|
+
};
|
|
1180
|
+
process.on('SIGINT', () => unregisterAndShutdown('SIGINT'));
|
|
1181
|
+
process.on('SIGTERM', () => unregisterAndShutdown('SIGTERM'));
|
|
1182
|
+
process.once('exit', () => {
|
|
1183
|
+
idleShutdown.stop();
|
|
1184
|
+
clearInterval(reregisterTimer);
|
|
1185
|
+
unregisterSession(process.pid);
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
main().catch((err) => {
|
|
1190
|
+
console.error('Failed to start packaged editor server:', err);
|
|
1191
|
+
process.exit(1);
|
|
1192
|
+
});
|