@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,47 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
/** Scratch belongs to its project, not to the project a study may be opened in. */
|
|
4
|
+
export function isProjectScratchPath(filename: string, roots: Iterable<string>): boolean {
|
|
5
|
+
const file = path.resolve(filename);
|
|
6
|
+
let owner = '';
|
|
7
|
+
for (const candidate of roots) {
|
|
8
|
+
const root = path.resolve(candidate);
|
|
9
|
+
if (root.length > owner.length && (file === root || file.startsWith(root + path.sep))) {
|
|
10
|
+
owner = root;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
if (!owner) return false;
|
|
14
|
+
const [directory, child] = path.relative(owner, file).split(path.sep);
|
|
15
|
+
return directory === '.vgai' && child === 'tmp';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* An agent-workspace path that is NOT this server's own source.
|
|
20
|
+
*
|
|
21
|
+
* Agent/IDE worktrees and scratch live under `<checkout>/.claude/`, and Vite
|
|
22
|
+
* full-reloads every connected tab when a file under its root changes — so one
|
|
23
|
+
* agent's worktree churn was reloading every OTHER editor served from the
|
|
24
|
+
* checkout (a tab kicked mid-boot). Hence the ignore. But a server can also BE
|
|
25
|
+
* served FROM one of those worktrees, and the path-shaped ignore (`.claude/**`)
|
|
26
|
+
* could not tell the two apart: it swallowed the worktree's own source, so that
|
|
27
|
+
* editor silently stopped watching the very files it serves. MEASURED
|
|
28
|
+
* 2026-09-18: an edit to `editor-chrome-capture.ts` in an agent worktree never
|
|
29
|
+
* reached the page — the dev server transformed the new module on request while
|
|
30
|
+
* the tab kept running the old one, with nothing reporting a problem, and the
|
|
31
|
+
* only way to see a source edit was to restart the session.
|
|
32
|
+
*
|
|
33
|
+
* The discriminator is OWNERSHIP, not the path's shape: a file inside
|
|
34
|
+
* `serverRoot` whose path below that root holds no `.claude` segment is the
|
|
35
|
+
* server's own source and is watched. Everything else under a `.claude`
|
|
36
|
+
* directory — a sibling worktree, the checkout's own agent scratch, this
|
|
37
|
+
* worktree's `.claude/` — is ignored exactly as before, so a server rooted at
|
|
38
|
+
* the checkout itself keeps today's behaviour for every path.
|
|
39
|
+
*/
|
|
40
|
+
export function isForeignAgentPath(filename: string, serverRoot: string): boolean {
|
|
41
|
+
const file = path.resolve(filename);
|
|
42
|
+
const segments = file.split(path.sep);
|
|
43
|
+
if (!segments.includes('.claude')) return false;
|
|
44
|
+
const root = path.resolve(serverRoot);
|
|
45
|
+
if (file !== root && !file.startsWith(root + path.sep)) return true;
|
|
46
|
+
return path.relative(root, file).split(path.sep).includes('.claude');
|
|
47
|
+
}
|
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor's project-script HMR hook — ONE copy, shared by `dev.ts` and
|
|
3
|
+
* `packaged.ts` (both used to carry a hand-maintained "byte-identical" copy).
|
|
4
|
+
*
|
|
5
|
+
* IT RUNS ON VITE'S `hotUpdate`, NOT `handleHotUpdate`, AND THAT IS THE POINT
|
|
6
|
+
* -------------------------------------------------------------------------
|
|
7
|
+
* Vite calls the legacy `handleHotUpdate` hook for `type === 'update'` ONLY
|
|
8
|
+
* (`handleHMRUpdate`, vite 6.4.3). The watcher's `add`/`unlink` path emits
|
|
9
|
+
* `'create'`/`'delete'` instead, so for two years every delete and every
|
|
10
|
+
* create of a project file went past this seam entirely: the running game kept
|
|
11
|
+
* the vanished module, nothing set `restartRequired`, nothing was printed, and
|
|
12
|
+
* vite fanned a useless HMR update across every accumulated `?vgai-mount=N`
|
|
13
|
+
* variant of the project's modules (measured at 7 and 14 variants; the only
|
|
14
|
+
* trace was `[vite] Failed to reload` in the page console, and often not even
|
|
15
|
+
* that). The modern `hotUpdate` hook receives all three types, so the editor
|
|
16
|
+
* now owns the whole file-event vocabulary — see
|
|
17
|
+
* {@link handleProjectScriptHotUpdate}'s create/delete branch.
|
|
18
|
+
*
|
|
19
|
+
* WHY THIS MODULE EXISTS AT ALL: `vgai restart` served STALE CODE
|
|
20
|
+
* ---------------------------------------------------------------
|
|
21
|
+
* Measured 2026-08-02, live: editing `src/components/Dragon.tsx` (a component
|
|
22
|
+
* the R3F entry imports) and then running `vgai restart` + play left the edit
|
|
23
|
+
* UNAPPLIED, while an edit to `src/world.tsx` (the entry ITSELF) applied after
|
|
24
|
+
* the same restart. Only closing the session and re-running `npm run dev`
|
|
25
|
+
* picked the component edit up — i.e. the documented restart contract ("so
|
|
26
|
+
* setup and disposal rerun") was silently running the pre-edit module.
|
|
27
|
+
*
|
|
28
|
+
* The mechanism, end to end:
|
|
29
|
+
*
|
|
30
|
+
* 1. This hook classifies a project source change and, for the kinds the
|
|
31
|
+
* editor drives itself (`r3f-entry`/`component`/`restart`), sends its OWN
|
|
32
|
+
* custom websocket event and returns `[]` — deliberately swallowing
|
|
33
|
+
* Vite's stock HMR propagation, because stock HMR on an R3F-dialect
|
|
34
|
+
* module bubbles to a full page reload (W4).
|
|
35
|
+
* 2. Returning `[]` means Vite never calls `updateModules`. The only
|
|
36
|
+
* invalidation that ran is the watcher's `moduleGraph.onFileChange`,
|
|
37
|
+
* which calls `invalidateModule(mod, seen)` with `isHmr === false` — that
|
|
38
|
+
* branch sets `lastInvalidationTimestamp` and leaves `lastHMRTimestamp`
|
|
39
|
+
* at 0 (vite 6.4.1, `ModuleGraph.invalidateModule`).
|
|
40
|
+
* 3. Vite's import-analysis appends the `?t=<ts>` cache-busting query to a
|
|
41
|
+
* static import ONLY when `depModule.lastHMRTimestamp > 0` (both the full
|
|
42
|
+
* transform path and `handleModuleSoftInvalidation`'s rewrite path check
|
|
43
|
+
* exactly that field).
|
|
44
|
+
* 4. So when play remounts and the realm's entry loader
|
|
45
|
+
* (`src/realm-services.ts`) re-imports the ENTRY with
|
|
46
|
+
* its own `?vgai-play=<n>` buster, the freshly transformed entry still
|
|
47
|
+
* points at the BYTE-IDENTICAL `/@fs/.../Dragon.tsx` URL the browser
|
|
48
|
+
* already has in its ES module registry. Browser module identity is
|
|
49
|
+
* per-URL, so the browser reuses the pre-edit module. The entry is fresh;
|
|
50
|
+
* everything it imports is stale.
|
|
51
|
+
*
|
|
52
|
+
* THE FIX is one line of intent: when this hook swallows Vite's HMR, it must
|
|
53
|
+
* still do the half of `updateModules` that the module graph needs — stamp
|
|
54
|
+
* the changed file's modules as HMR-invalidated (`isHmr: true`), which
|
|
55
|
+
* propagates to their importers and gives every ancestor a fresh `?t=` for
|
|
56
|
+
* the changed module on its next transform. Cache-busting the entry then
|
|
57
|
+
* genuinely re-evaluates the whole edited subgraph, which is what "restart"
|
|
58
|
+
* always claimed to do.
|
|
59
|
+
*
|
|
60
|
+
* `stampHmrInvalidation` is deliberately defensive about the graph's shape:
|
|
61
|
+
* if a module graph ever stops offering the invalidation API, this hook says
|
|
62
|
+
* so LOUDLY and names the file, rather than swallowing HMR into silence and
|
|
63
|
+
* letting a restart remount old code again.
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
import { createHash } from 'node:crypto';
|
|
67
|
+
import { relative } from 'node:path';
|
|
68
|
+
import {
|
|
69
|
+
classifyProjectHotUpdate,
|
|
70
|
+
type ProjectHotUpdateKind,
|
|
71
|
+
reactRefreshBoundaryExports,
|
|
72
|
+
} from './project-hmr-files';
|
|
73
|
+
import {
|
|
74
|
+
importersFromModuleGraph,
|
|
75
|
+
type ModuleGraphLike,
|
|
76
|
+
resolveOidSurface,
|
|
77
|
+
} from './project-root-surface';
|
|
78
|
+
|
|
79
|
+
/** Structural stand-in for a Vite `ModuleNode` (never imported from `vite` —
|
|
80
|
+
* this file holds the same dependency-light bar as `project-root-surface`). */
|
|
81
|
+
export interface HmrModuleNodeLike {
|
|
82
|
+
readonly url?: string | undefined;
|
|
83
|
+
readonly id?: string | null | undefined;
|
|
84
|
+
readonly file?: string | null | undefined;
|
|
85
|
+
readonly isSelfAccepting?: boolean | undefined;
|
|
86
|
+
/** Vite's `ModuleNode.importers` — read by {@link stampHmrInvalidation}'s
|
|
87
|
+
* boundary pre-walk; optional so a bare graph stays acceptable. */
|
|
88
|
+
readonly importers?: Iterable<HmrModuleNodeLike> | undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The slice of Vite's `ModuleGraph` this module needs, both members optional
|
|
92
|
+
* so a caller can hand over any graph-shaped object and get an honest
|
|
93
|
+
* `supported: false` rather than a crash.
|
|
94
|
+
*
|
|
95
|
+
* METHOD syntax, deliberately: TypeScript checks method parameters
|
|
96
|
+
* bivariantly and property-typed function parameters contravariantly, and
|
|
97
|
+
* the whole point of this interface is that Vite's REAL `ModuleGraph`
|
|
98
|
+
* (whose `ModuleNode` is far richer than `HmrModuleNodeLike`) satisfies it. */
|
|
99
|
+
export interface HmrInvalidationGraph {
|
|
100
|
+
getModulesByFile?(file: string): Iterable<HmrModuleNodeLike> | undefined;
|
|
101
|
+
invalidateModule?(
|
|
102
|
+
mod: HmrModuleNodeLike,
|
|
103
|
+
seen?: Set<HmrModuleNodeLike>,
|
|
104
|
+
timestamp?: number,
|
|
105
|
+
isHmr?: boolean,
|
|
106
|
+
softInvalidate?: boolean,
|
|
107
|
+
): void;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type ScriptHmrModuleGraph = ModuleGraphLike & HmrInvalidationGraph;
|
|
111
|
+
|
|
112
|
+
/** Project documents can import helpers without being React boundaries.
|
|
113
|
+
* Report actual dependent files so a Model reloads for its own dependencies,
|
|
114
|
+
* never for every unrelated save in the project. Include every loaded variant. */
|
|
115
|
+
export function affectedProjectFiles(
|
|
116
|
+
graph: HmrInvalidationGraph,
|
|
117
|
+
file: string,
|
|
118
|
+
projectRoot: string,
|
|
119
|
+
): string[] {
|
|
120
|
+
const files = new Set([file.replaceAll('\\', '/')]);
|
|
121
|
+
const seen = new Set<HmrModuleNodeLike>();
|
|
122
|
+
const visit = (node: HmrModuleNodeLike): void => {
|
|
123
|
+
if (seen.has(node)) return;
|
|
124
|
+
seen.add(node);
|
|
125
|
+
if (node.file) {
|
|
126
|
+
const path = relative(projectRoot, node.file);
|
|
127
|
+
if (path === '..' || path.startsWith('../')) return;
|
|
128
|
+
files.add(node.file.replaceAll('\\', '/'));
|
|
129
|
+
}
|
|
130
|
+
for (const importer of node.importers ?? []) visit(importer);
|
|
131
|
+
};
|
|
132
|
+
for (const node of graph.getModulesByFile?.(file) ?? []) visit(node);
|
|
133
|
+
return [...files].sort();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The minimal dev-server shape this hook drives. */
|
|
137
|
+
export interface ScriptHmrServerLike {
|
|
138
|
+
ws: { send: (msg: unknown) => void };
|
|
139
|
+
moduleGraph: ScriptHmrModuleGraph;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** The slice of vite's `HotUpdateOptions` the editor's plugin reads —
|
|
143
|
+
* structural, so neither host has to import `vite` to declare its hook. */
|
|
144
|
+
export interface ScriptHmrHostOptions {
|
|
145
|
+
readonly file: string;
|
|
146
|
+
readonly type: ProjectFileEventType;
|
|
147
|
+
readonly timestamp?: number;
|
|
148
|
+
readonly server: ScriptHmrServerLike;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** The `this` vite binds on `hotUpdate` — the environment whose pass this is. */
|
|
152
|
+
export interface ScriptHmrHookContext {
|
|
153
|
+
readonly environment?: { readonly name?: string } | undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Does this update kind SWALLOW Vite's own HMR propagation (return `[]`)?
|
|
158
|
+
*
|
|
159
|
+
* Stated as the complement on purpose: the three kinds below return EARLY, so
|
|
160
|
+
* stock Vite HMR runs `updateModules` and stamps the graph for us. Everything
|
|
161
|
+
* else — including `ignore` — reaches `return []`, and therefore has to be
|
|
162
|
+
* stamped by hand or an edit to it can survive a remount. Writing this as a
|
|
163
|
+
* positive list of "the kinds I remembered" is how `ignore` would quietly
|
|
164
|
+
* become a second hole.
|
|
165
|
+
*/
|
|
166
|
+
export function swallowsViteHmr(kind: ProjectHotUpdateKind): boolean {
|
|
167
|
+
return kind !== 'outside' && kind !== 'stock-data' && kind !== 'react' && kind !== 'r3f-refresh';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** What {@link stampHmrInvalidation} did, so the caller can report honestly. */
|
|
171
|
+
export interface HmrStampOutcome {
|
|
172
|
+
/** False when the graph does not expose the invalidation API at all — the
|
|
173
|
+
* ONE case where an edited module provably cannot be re-evaluated by a
|
|
174
|
+
* remount, and therefore the one case that must be shouted about. */
|
|
175
|
+
readonly supported: boolean;
|
|
176
|
+
/** Module urls/ids that were stamped. Empty with `supported: true` simply
|
|
177
|
+
* means the file has no module-graph node yet — it was never loaded, so
|
|
178
|
+
* it cannot be stale. */
|
|
179
|
+
readonly stamped: readonly string[];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Mark every module of `file` as HMR-invalidated, the way Vite's own
|
|
184
|
+
* `updateModules` would have, so import-analysis re-stamps `?t=` on it for
|
|
185
|
+
* every importer. Propagation to importers is `invalidateModule`'s own job
|
|
186
|
+
* (it walks `mod.importers` with the same `isHmr` flag).
|
|
187
|
+
*
|
|
188
|
+
* `stopAt` BOUNDS that propagation at the editor's own modules, and its
|
|
189
|
+
* absence was a live defect (measured on bubbo-bubbo, 2026-08-21): a
|
|
190
|
+
* creation-site write to the game's source stamped the changed module, and
|
|
191
|
+
* the importer walk climbed THROUGH the isolation-document's import edge into
|
|
192
|
+
* editor chrome — `play-mode.ts` among the ancestors. Editor chrome is full
|
|
193
|
+
* of lazy `await import('./x')` seams, and the next one to fire after the
|
|
194
|
+
* stamp fetched a SECOND `play-mode.ts?t=…` instance: `GamePanel` then
|
|
195
|
+
* reported its container to the new instance while the mount path read the
|
|
196
|
+
* old one, and every subsequent ▶ refused with "Game container not mounted"
|
|
197
|
+
* until a full page reload. A game edit re-evaluates the GAME's subgraph
|
|
198
|
+
* (the entry re-import's own cache-buster sees the fresh `?t=`); it must
|
|
199
|
+
* never re-instance editor-chrome singletons mid-session. The boundary works
|
|
200
|
+
* by pre-seeding `invalidateModule`'s `seen` set: a module already in `seen`
|
|
201
|
+
* is skipped AND its importers are not walked, which is exactly "stop here".
|
|
202
|
+
*/
|
|
203
|
+
export function stampHmrInvalidation(
|
|
204
|
+
graph: HmrInvalidationGraph | undefined,
|
|
205
|
+
file: string,
|
|
206
|
+
timestamp: number = Date.now(),
|
|
207
|
+
stopAt?: (moduleFile: string) => boolean,
|
|
208
|
+
): HmrStampOutcome {
|
|
209
|
+
if (!graph || typeof graph.getModulesByFile !== 'function')
|
|
210
|
+
return { supported: false, stamped: [] };
|
|
211
|
+
if (typeof graph.invalidateModule !== 'function') return { supported: false, stamped: [] };
|
|
212
|
+
const mods = graph.getModulesByFile(file);
|
|
213
|
+
if (!mods) return { supported: true, stamped: [] };
|
|
214
|
+
const stamped: string[] = [];
|
|
215
|
+
if (stopAt) {
|
|
216
|
+
// BOUNDED. Vite's `seen` is a CYCLE guard, not a fence: `invalidateModule`
|
|
217
|
+
// assigns `invalidationState` BEFORE its early-return check, and only
|
|
218
|
+
// returns for a seen module WHEN THAT ASSIGNMENT CHANGED NOTHING
|
|
219
|
+
// (`if (seen.has(mod) && prevInvalidationState === mod.invalidationState)
|
|
220
|
+
// return`, vite 6.4.3). A fresh module in `seen` therefore still gets
|
|
221
|
+
// stamped and walked through — measured on bubbo-bubbo: every seeding
|
|
222
|
+
// strategy shipped 33 editor-module stamps per write, identically. The
|
|
223
|
+
// fence that actually holds is PRE-ARMING each boundary module's
|
|
224
|
+
// `invalidationState` to the exact value both walk arms would assign:
|
|
225
|
+
// the hard arm re-assigns `'HARD_INVALIDATED'` (no change) and the soft
|
|
226
|
+
// arm's `??=` keeps it (no change), so the early return finally fires.
|
|
227
|
+
// Pre-arming is behaviorally free for the boundary module itself — its
|
|
228
|
+
// `transformResult` cache is untouched, and the soft-invalidation
|
|
229
|
+
// replay path only consumes `invalidationState` after an invalidation
|
|
230
|
+
// nulled that cache.
|
|
231
|
+
const boundary = new Set<HmrModuleNodeLike>();
|
|
232
|
+
const visited = new Set<HmrModuleNodeLike>([...mods]);
|
|
233
|
+
const queue = [...visited];
|
|
234
|
+
while (queue.length > 0) {
|
|
235
|
+
const mod = queue.pop() as HmrModuleNodeLike;
|
|
236
|
+
for (const importer of mod.importers ?? []) {
|
|
237
|
+
if (visited.has(importer)) continue;
|
|
238
|
+
visited.add(importer);
|
|
239
|
+
if (typeof importer.file === 'string' && stopAt(importer.file)) {
|
|
240
|
+
boundary.add(importer);
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
queue.push(importer);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
for (const node of boundary) {
|
|
247
|
+
// The mixed backward-compat graph hands out WRAPPERS whose state lives
|
|
248
|
+
// on the per-environment halves; a plain environment graph's node holds
|
|
249
|
+
// the field itself. Write whichever exists.
|
|
250
|
+
const halves = node as {
|
|
251
|
+
_clientModule?: { invalidationState?: unknown };
|
|
252
|
+
_ssrModule?: { invalidationState?: unknown };
|
|
253
|
+
invalidationState?: unknown;
|
|
254
|
+
};
|
|
255
|
+
if (halves._clientModule) halves._clientModule.invalidationState = 'HARD_INVALIDATED';
|
|
256
|
+
if (halves._ssrModule) halves._ssrModule.invalidationState = 'HARD_INVALIDATED';
|
|
257
|
+
if (!halves._clientModule && !halves._ssrModule) {
|
|
258
|
+
halves.invalidationState = 'HARD_INVALIDATED';
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const seen = new Set<HmrModuleNodeLike>(boundary);
|
|
262
|
+
for (const mod of mods) {
|
|
263
|
+
graph.invalidateModule(mod, seen, timestamp, true);
|
|
264
|
+
stamped.push(mod.url ?? mod.id ?? file);
|
|
265
|
+
}
|
|
266
|
+
return { supported: true, stamped };
|
|
267
|
+
}
|
|
268
|
+
const seen = new Set<HmrModuleNodeLike>();
|
|
269
|
+
for (const mod of mods) {
|
|
270
|
+
graph.invalidateModule(mod, seen, timestamp, true);
|
|
271
|
+
stamped.push(mod.url ?? mod.id ?? file);
|
|
272
|
+
}
|
|
273
|
+
return { supported: true, stamped };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* The loud warning for the one genuinely-uninvalidatable case. Pure so the
|
|
278
|
+
* exact wording is a unit-testable contract rather than an inline string: a
|
|
279
|
+
* silent stale remount is the defect this whole module exists to prevent, so
|
|
280
|
+
* the failure to prevent it must NAME the module.
|
|
281
|
+
*/
|
|
282
|
+
export function staleModuleWarning(file: string, outcome: HmrStampOutcome): string | null {
|
|
283
|
+
if (outcome.supported) return null;
|
|
284
|
+
return (
|
|
285
|
+
`vgai: ${file} changed, but this dev server's module graph does not support HMR ` +
|
|
286
|
+
'invalidation — a play restart will re-run setup against the STALE copy of that ' +
|
|
287
|
+
'module. Reload the editor page to pick the edit up.'
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** Vite's `HotUpdateOptions['type']`, restated so this module keeps its
|
|
292
|
+
* never-import-`vite` bar. */
|
|
293
|
+
export type ProjectFileEventType = 'create' | 'update' | 'delete';
|
|
294
|
+
|
|
295
|
+
/** Everything `handleProjectScriptHotUpdate` needs from its plugin host. */
|
|
296
|
+
export interface ProjectScriptHotUpdateArgs {
|
|
297
|
+
readonly file: string;
|
|
298
|
+
readonly projectRoot: string;
|
|
299
|
+
/** Which watcher event this is. Defaults to `'update'` so a caller that only
|
|
300
|
+
* ever had edits keeps its old meaning. */
|
|
301
|
+
readonly type?: ProjectFileEventType | undefined;
|
|
302
|
+
/** The changed file's source, or `''` when there is none to read — a
|
|
303
|
+
* non-script file, or a file that has just been DELETED (the caller reads
|
|
304
|
+
* it; this module does no I/O). */
|
|
305
|
+
readonly source: string;
|
|
306
|
+
readonly server: ScriptHmrServerLike;
|
|
307
|
+
/**
|
|
308
|
+
* Which of vite's environments this invocation is for. `hotUpdate` runs once
|
|
309
|
+
* per environment (client, then ssr), and the editor's side effects — the
|
|
310
|
+
* module-graph stamp and the custom websocket event — belong to the CLIENT
|
|
311
|
+
* pass alone: the ssr pass would double-send both. Non-client passes still
|
|
312
|
+
* return the same swallow/pass-through decision so vite's own propagation
|
|
313
|
+
* stays consistent across environments.
|
|
314
|
+
*/
|
|
315
|
+
readonly environment?: string | undefined;
|
|
316
|
+
readonly timestamp?: number | undefined;
|
|
317
|
+
/** Defaults to `console.warn`; injected in tests. */
|
|
318
|
+
readonly warn?: ((message: string) => void) | undefined;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Fast Refresh boundary status of the LAST source this hook saw for a file.
|
|
323
|
+
*
|
|
324
|
+
* React Refresh validates a boundary by COMPARING the loaded module's exports
|
|
325
|
+
* with the incoming ones, so the hazard is a TRANSITION, not a state: the
|
|
326
|
+
* update that REMOVES a non-component export invalidates exactly as hard as
|
|
327
|
+
* the one that adds it (measured live — removing the `export` keyword again
|
|
328
|
+
* full-reloaded the editor even though the new source is a perfectly good
|
|
329
|
+
* boundary). Judging the incoming source alone therefore closes only half the
|
|
330
|
+
* hole; the previous source has to be remembered.
|
|
331
|
+
*
|
|
332
|
+
* The serving plugin records initial client transforms as well as updates,
|
|
333
|
+
* so the first edit after loading mixed exports cannot skip the transition.
|
|
334
|
+
*/
|
|
335
|
+
const lastSeenBoundary = new Map<string, readonly string[] | null>();
|
|
336
|
+
|
|
337
|
+
/** Clears the memo above so a test can start from a known first-sight state. */
|
|
338
|
+
export function resetReactBoundaryMemoForTest(): void {
|
|
339
|
+
lastSeenBoundary.clear();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** Record the source actually served, including the initial mixed-export case. */
|
|
343
|
+
export function recordReactBoundary(file: string, source: string): void {
|
|
344
|
+
if (/\.[jt]sx$/.test(file)) lastSeenBoundary.set(file, reactRefreshBoundaryExports(source));
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Record this source's boundary status and downgrade a `react` classification
|
|
349
|
+
* to `restart` unless BOTH the previous and the incoming source are Fast
|
|
350
|
+
* Refresh boundaries. Runs for every `.tsx`/`.jsx` update, whatever its kind,
|
|
351
|
+
* so the memo also records the versions that never rode stock HMR.
|
|
352
|
+
*/
|
|
353
|
+
function trackReactBoundary(
|
|
354
|
+
kind: ProjectHotUpdateKind,
|
|
355
|
+
file: string,
|
|
356
|
+
source: string,
|
|
357
|
+
): ProjectHotUpdateKind {
|
|
358
|
+
if (!/\.(tsx|jsx)$/.test(file)) return kind;
|
|
359
|
+
const isBoundary = reactRefreshBoundaryExports(source);
|
|
360
|
+
const wasBoundary = lastSeenBoundary.has(file) ? lastSeenBoundary.get(file)! : isBoundary;
|
|
361
|
+
lastSeenBoundary.set(file, isBoundary);
|
|
362
|
+
if (kind !== 'react' && kind !== 'r3f-refresh') return kind;
|
|
363
|
+
return isBoundary && wasBoundary && isBoundary.join('\0') === wasBoundary.join('\0')
|
|
364
|
+
? kind
|
|
365
|
+
: kind === 'r3f-refresh'
|
|
366
|
+
? 'r3f-entry'
|
|
367
|
+
: 'restart';
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/** A plain model/helper module may use Vite's dependency propagation only
|
|
371
|
+
* when EVERY loaded importer path ends at a proven R3F refresh boundary.
|
|
372
|
+
* Dead ends, cycles, mixed exports and paths into editor code retain the
|
|
373
|
+
* controlled fallback. The URLs are Vite's own, including mount variants.
|
|
374
|
+
*/
|
|
375
|
+
export function r3fDependencyBoundaries(
|
|
376
|
+
graph: ScriptHmrModuleGraph,
|
|
377
|
+
file: string,
|
|
378
|
+
projectRoot: string,
|
|
379
|
+
): readonly string[] | null {
|
|
380
|
+
const nodes = [...(graph.getModulesByFile?.(file) ?? [])];
|
|
381
|
+
if (!nodes.length) return null;
|
|
382
|
+
const boundaries = new Set<string>();
|
|
383
|
+
const root = `${projectRoot.replaceAll('\\', '/').replace(/\/$/, '')}/`;
|
|
384
|
+
const importersOf = importersFromModuleGraph(graph);
|
|
385
|
+
const proven = new Set<HmrModuleNodeLike>();
|
|
386
|
+
const visit = (node: HmrModuleNodeLike, ancestors: Set<HmrModuleNodeLike>): boolean => {
|
|
387
|
+
if (proven.has(node)) return true;
|
|
388
|
+
if (ancestors.has(node) || !node.file?.replaceAll('\\', '/').startsWith(root)) return false;
|
|
389
|
+
if (node.isSelfAccepting) {
|
|
390
|
+
if (
|
|
391
|
+
!node.url ||
|
|
392
|
+
!lastSeenBoundary.get(node.file) ||
|
|
393
|
+
resolveOidSurface(node.file, '', importersOf).attribute !== 'userData-oid'
|
|
394
|
+
)
|
|
395
|
+
return false;
|
|
396
|
+
boundaries.add(node.url);
|
|
397
|
+
proven.add(node);
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
const importers = [...(node.importers ?? [])];
|
|
401
|
+
if (!importers.length) return false;
|
|
402
|
+
const next = new Set(ancestors).add(node);
|
|
403
|
+
if (!importers.every((importer) => visit(importer, next))) return false;
|
|
404
|
+
proven.add(node);
|
|
405
|
+
return true;
|
|
406
|
+
};
|
|
407
|
+
return nodes.every((node) => visit(node, new Set())) && boundaries.size ? [...boundaries] : null;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Is a file APPEARING or VANISHING under this kind the editor's event to own?
|
|
412
|
+
*
|
|
413
|
+
* `outside` is not the project's, so vite keeps it. Everything else is —
|
|
414
|
+
* including `ignore`, whose files are swallowed silently exactly as an edit to
|
|
415
|
+
* them is. The kinds in between all name a module the running game may hold,
|
|
416
|
+
* and a module that no longer exists (or has just started existing beside the
|
|
417
|
+
* ones it does) cannot be reconciled by any hot update: only a remount can.
|
|
418
|
+
*/
|
|
419
|
+
function appearanceIsOurs(kind: ProjectHotUpdateKind): boolean {
|
|
420
|
+
return kind !== 'outside';
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* A project file was CREATED or DELETED.
|
|
425
|
+
*
|
|
426
|
+
* There is exactly one honest answer for a runtime module: restart. Vite's own
|
|
427
|
+
* propagation is swallowed (`[]`) rather than allowed to run, because for a
|
|
428
|
+
* delete it has nothing to send that any client can apply — its only effect
|
|
429
|
+
* was pushing an unusable update at every `?vgai-mount=N` variant the session
|
|
430
|
+
* had accumulated, which is how this failure stayed invisible: the page logged
|
|
431
|
+
* `[vite] Failed to reload` and nothing else did anything at all.
|
|
432
|
+
*/
|
|
433
|
+
/**
|
|
434
|
+
* The stamp's propagation boundary for a PROJECT file: the project's own
|
|
435
|
+
* modules re-evaluate on the next remount; any importer OUTSIDE the project
|
|
436
|
+
* tree is editor chrome (or an engine module the chrome shares) and must
|
|
437
|
+
* never be re-instanced by a game edit — see {@link stampHmrInvalidation}'s
|
|
438
|
+
* doc for the split-singleton failure this prevents.
|
|
439
|
+
*/
|
|
440
|
+
function projectStampBoundary(projectRoot: string): (moduleFile: string) => boolean {
|
|
441
|
+
const root = `${projectRoot.replaceAll('\\', '/').replace(/\/+$/, '')}/`;
|
|
442
|
+
return (moduleFile) => !moduleFile.replaceAll('\\', '/').startsWith(root);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Pick the stamp boundary for ONE changed file. A file inside the project
|
|
447
|
+
* tree bounds at the project; a repo-VENDORED game file (classified
|
|
448
|
+
* `restart` by `classifyProjectHotUpdate` even though it sits outside the
|
|
449
|
+
* project folder) must keep propagating through the vendored subtree AND the
|
|
450
|
+
* project's own modules — only editor chrome stops it — so its boundary is
|
|
451
|
+
* the engine-root form, with the engine root read off the file's own
|
|
452
|
+
* `/vendor/games/` position.
|
|
453
|
+
*/
|
|
454
|
+
function stampBoundaryFor(file: string, projectRoot: string): (moduleFile: string) => boolean {
|
|
455
|
+
const normalized = file.replaceAll('\\', '/');
|
|
456
|
+
const vendorIdx = normalized.indexOf('/vendor/games/');
|
|
457
|
+
if (vendorIdx !== -1) {
|
|
458
|
+
return editorChromeStampBoundary(normalized.slice(0, vendorIdx), () => projectRoot);
|
|
459
|
+
}
|
|
460
|
+
return projectStampBoundary(projectRoot);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* The same boundary for a WRITE-ROUTE stamp, where the changed file can live
|
|
465
|
+
* OUTSIDE the project root (a repo-vendored game's source under
|
|
466
|
+
* `vendor/games/`): editor chrome is what must not re-instance, and here it
|
|
467
|
+
* is nameable directly — modules under the engine checkout's `packages/`
|
|
468
|
+
* that are not the open project's own tree. The project-root carve-out is
|
|
469
|
+
* load-bearing for in-tree fixture projects, which live inside
|
|
470
|
+
* `packages/editor/src/ingest/games/`. Vendored sources sit under `vendor/`
|
|
471
|
+
* (not `packages/`), so they propagate; engine modules the chrome shares sit
|
|
472
|
+
* under `packages/engine/`, so they stop. ONE spelling, exported so every
|
|
473
|
+
* write route stamps with the same boundary — a second inline copy is how
|
|
474
|
+
* one route shipped unbounded (see {@link stampHmrInvalidation}'s doc).
|
|
475
|
+
*/
|
|
476
|
+
export function editorChromeStampBoundary(
|
|
477
|
+
engineRoot: string,
|
|
478
|
+
getProjectRoot: () => string | undefined,
|
|
479
|
+
): (moduleFile: string) => boolean {
|
|
480
|
+
const packagesRoot = `${engineRoot.replaceAll('\\', '/').replace(/\/+$/, '')}/packages/`;
|
|
481
|
+
return (moduleFile) => {
|
|
482
|
+
const normalized = moduleFile.replaceAll('\\', '/');
|
|
483
|
+
if (!normalized.startsWith(packagesRoot)) return false;
|
|
484
|
+
const projectRoot = getProjectRoot();
|
|
485
|
+
if (!projectRoot) return true;
|
|
486
|
+
const projectPrefix = `${projectRoot.replaceAll('\\', '/').replace(/\/+$/, '')}/`;
|
|
487
|
+
return !normalized.startsWith(projectPrefix);
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function handleProjectFileAppearance(
|
|
492
|
+
args: ProjectScriptHotUpdateArgs,
|
|
493
|
+
kind: ProjectHotUpdateKind,
|
|
494
|
+
isClient: boolean,
|
|
495
|
+
): never[] | undefined {
|
|
496
|
+
if (!appearanceIsOurs(kind)) return undefined;
|
|
497
|
+
if (!isClient || kind === 'ignore') return [];
|
|
498
|
+
const { file, server } = args;
|
|
499
|
+
// A delete leaves the graph holding nodes for a file that is gone; stamping
|
|
500
|
+
// them HMR-invalid is what makes every importer re-transform (and therefore
|
|
501
|
+
// re-resolve, and therefore FAIL LOUDLY) instead of silently serving the
|
|
502
|
+
// cached transform that still points at the vanished module.
|
|
503
|
+
const outcome = stampHmrInvalidation(
|
|
504
|
+
server.moduleGraph,
|
|
505
|
+
file,
|
|
506
|
+
args.timestamp,
|
|
507
|
+
stampBoundaryFor(file, args.projectRoot),
|
|
508
|
+
);
|
|
509
|
+
const warning = staleModuleWarning(file, outcome);
|
|
510
|
+
if (warning) (args.warn ?? console.warn)(warning);
|
|
511
|
+
server.ws.send({
|
|
512
|
+
type: 'custom',
|
|
513
|
+
event: kind === 'tool' ? 'vgai:script-update' : 'vgai:restart-required',
|
|
514
|
+
data: { file: file.replaceAll('\\', '/') },
|
|
515
|
+
});
|
|
516
|
+
return [];
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* The shared `hotUpdate` body. Returns `[]` to swallow Vite's HMR
|
|
521
|
+
* propagation, or `undefined` to let it run — the same two-valued contract
|
|
522
|
+
* `dev.ts`/`packaged.ts` returned when each carried its own copy.
|
|
523
|
+
*/
|
|
524
|
+
export function handleProjectScriptHotUpdate(
|
|
525
|
+
args: ProjectScriptHotUpdateArgs,
|
|
526
|
+
): never[] | undefined {
|
|
527
|
+
const { file, projectRoot, source, server } = args;
|
|
528
|
+
const isClient = (args.environment ?? 'client') === 'client';
|
|
529
|
+
const classified = classifyProjectHotUpdate(
|
|
530
|
+
file,
|
|
531
|
+
projectRoot,
|
|
532
|
+
source,
|
|
533
|
+
// T43: reach a non-entry R3F component through the live import graph,
|
|
534
|
+
// same as `vite-plugin-ui-oid.ts`'s transform hook — see
|
|
535
|
+
// `project-hmr-files.ts`'s doc comment on why this is shared, not
|
|
536
|
+
// re-derived.
|
|
537
|
+
importersFromModuleGraph(server.moduleGraph),
|
|
538
|
+
);
|
|
539
|
+
if ((args.type ?? 'update') !== 'update') {
|
|
540
|
+
return handleProjectFileAppearance(args, classified, isClient);
|
|
541
|
+
}
|
|
542
|
+
const boundaries =
|
|
543
|
+
classified === 'restart' && /\.[cm]?[jt]s$/.test(file)
|
|
544
|
+
? r3fDependencyBoundaries(server.moduleGraph, file, projectRoot)
|
|
545
|
+
: null;
|
|
546
|
+
const kind = boundaries
|
|
547
|
+
? 'r3f-refresh'
|
|
548
|
+
: isClient
|
|
549
|
+
? trackReactBoundary(classified, file, source)
|
|
550
|
+
: classified;
|
|
551
|
+
// `outside` / `stock-data` / `react` ride stock Vite HMR (a data handle's
|
|
552
|
+
// owning module live-tunes it through its own `import.meta.hot.accept`;
|
|
553
|
+
// a react module takes Fast Refresh) — and stock HMR does the module-graph
|
|
554
|
+
// stamping itself, which is why they leave here untouched.
|
|
555
|
+
if (!swallowsViteHmr(kind)) {
|
|
556
|
+
if (kind === 'r3f-refresh' && isClient) {
|
|
557
|
+
server.ws.send({
|
|
558
|
+
type: 'custom',
|
|
559
|
+
event: 'vgai:r3f-refresh-source',
|
|
560
|
+
data: {
|
|
561
|
+
file: file.replaceAll('\\', '/'),
|
|
562
|
+
path: relative(projectRoot, file).replaceAll('\\', '/'),
|
|
563
|
+
sha: createHash('sha256').update(source).digest('hex').slice(0, 16),
|
|
564
|
+
timestamp: args.timestamp,
|
|
565
|
+
affected: affectedProjectFiles(server.moduleGraph, file, projectRoot),
|
|
566
|
+
...(boundaries ? { boundaries } : {}),
|
|
567
|
+
},
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
return undefined;
|
|
571
|
+
}
|
|
572
|
+
// The ssr pass owns no side effects — see `ProjectScriptHotUpdateArgs.environment`.
|
|
573
|
+
if (!isClient) return [];
|
|
574
|
+
|
|
575
|
+
// Swallowing Vite's HMR means taking on the module-graph bookkeeping it
|
|
576
|
+
// would have done. See this module's header for the full mechanism and the
|
|
577
|
+
// stale-restart incident that produced it.
|
|
578
|
+
const outcome = stampHmrInvalidation(
|
|
579
|
+
server.moduleGraph,
|
|
580
|
+
file,
|
|
581
|
+
args.timestamp,
|
|
582
|
+
stampBoundaryFor(file, args.projectRoot),
|
|
583
|
+
);
|
|
584
|
+
const warning = staleModuleWarning(file, outcome);
|
|
585
|
+
if (warning) (args.warn ?? console.warn)(warning);
|
|
586
|
+
|
|
587
|
+
// R3F-dialect modules are swallowed from stock HMR (their non-component)
|
|
588
|
+
// exports would force a full page reload) — the editor's R3F design
|
|
589
|
+
// session listens for this custom event and remounts the design world in
|
|
590
|
+
// place, re-resolving selection by oid.
|
|
591
|
+
if (kind === 'r3f-entry') {
|
|
592
|
+
server.ws.send({
|
|
593
|
+
type: 'custom',
|
|
594
|
+
event: 'vgai:r3f-entry-update',
|
|
595
|
+
data: { file, affected: affectedProjectFiles(server.moduleGraph, file, projectRoot) },
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
if (kind === 'tool') {
|
|
599
|
+
server.ws.send({
|
|
600
|
+
type: 'custom',
|
|
601
|
+
event: 'vgai:script-update',
|
|
602
|
+
data: {
|
|
603
|
+
file: file.replaceAll('\\', '/'),
|
|
604
|
+
affected: affectedProjectFiles(server.moduleGraph, file, projectRoot),
|
|
605
|
+
},
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
if (kind === 'restart') {
|
|
609
|
+
server.ws.send({
|
|
610
|
+
type: 'custom',
|
|
611
|
+
event: 'vgai:restart-required',
|
|
612
|
+
data: { file, affected: affectedProjectFiles(server.moduleGraph, file, projectRoot) },
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
// Other project changes (including scripts/, tests/, dist/) are not runtime
|
|
616
|
+
// modules. Swallow them; scene/asset changes are delivered through the
|
|
617
|
+
// editor's own SSE channel.
|
|
618
|
+
return [];
|
|
619
|
+
}
|