@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,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PD-3's runtime backstop: DETECT a cross-root module split and report it
|
|
3
|
+
* LOUDLY, so the next one can never be silent the way the measured one was
|
|
4
|
+
* ("HUD rendered defaults forever while `game.state()` moved; no error, no
|
|
5
|
+
* warning").
|
|
6
|
+
*
|
|
7
|
+
* `project-module-url.ts` removes the deterministic CAUSE (one mount epoch
|
|
8
|
+
* shared by every root's entry url). This module is the tripwire for whatever
|
|
9
|
+
* that guarantee does not cover — a future root resolver that hand-builds a
|
|
10
|
+
* url, a `/@fs//doubled-slash` form reappearing, a symlink-uncanonical root,
|
|
11
|
+
* or a source edit landing between two roots' transforms inside one mount.
|
|
12
|
+
*
|
|
13
|
+
* HOW IT MEASURES, and why this observable and not another
|
|
14
|
+
* --------------------------------------------------------
|
|
15
|
+
* Browser ES-module identity is per-URL and a module is EVALUATED exactly
|
|
16
|
+
* once per url, so "two live instances of one file" is exactly "two distinct
|
|
17
|
+
* urls for one file were fetched as modules". Resource Timing already records
|
|
18
|
+
* every one of those fetches with a timestamp, which makes the whole check a
|
|
19
|
+
* pure function over `performance.getEntriesByType('resource')` — no
|
|
20
|
+
* instrumentation injected into project code, no per-module cost, and
|
|
21
|
+
* trivially unit-testable against a synthetic entry list.
|
|
22
|
+
*
|
|
23
|
+
* The window matters, and is what keeps this SOUND rather than noisy:
|
|
24
|
+
*
|
|
25
|
+
* - Counting over the whole session would fire on every healthy remount —
|
|
26
|
+
* an edited module legitimately gets a new `?t=` url each mount, and the
|
|
27
|
+
* superseded instance's fetch stays in the timeline forever.
|
|
28
|
+
* - Counting only fetches made DURING one mount cannot false-positive: a
|
|
29
|
+
* single mount has no legitimate reason to evaluate one file twice. A file
|
|
30
|
+
* reused from the browser's module registry is not re-fetched, so it never
|
|
31
|
+
* inflates the count.
|
|
32
|
+
*
|
|
33
|
+
* The cost of that soundness is the honest gap recorded here: the ONE case
|
|
34
|
+
* this cannot see is a root that reuses a cached module while a sibling
|
|
35
|
+
* evaluates a fresh one (the original PD-3 shape) — the cached side performs
|
|
36
|
+
* no fetch at all. That case is closed by construction upstream, in
|
|
37
|
+
* `project-module-url.ts`; this module is deliberately the second line, not
|
|
38
|
+
* the first.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/** The Resource Timing fields this module reads — declared structurally so a
|
|
42
|
+
* test can hand over a plain array and so nothing here depends on the DOM
|
|
43
|
+
* lib's `PerformanceResourceTiming`. */
|
|
44
|
+
export interface ResourceTimingLike {
|
|
45
|
+
readonly name: string;
|
|
46
|
+
readonly startTime: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** One file that was evaluated more than once inside a single mount. */
|
|
50
|
+
export interface ProjectModuleSplit {
|
|
51
|
+
/** The file's path (query stripped) — the `/@fs/…` pathname as fetched, so
|
|
52
|
+
* it names the module the way every other editor/dev-server message does. */
|
|
53
|
+
readonly path: string;
|
|
54
|
+
/** Every distinct url the file was fetched under during the window, in
|
|
55
|
+
* fetch order. Always length >= 2. */
|
|
56
|
+
readonly urls: readonly string[];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Module-graph extensions vite serves for a NON-module purpose — the same
|
|
60
|
+
* file legitimately produces a different module for each of these, so two
|
|
61
|
+
* urls differing only by one of them is not a split. */
|
|
62
|
+
const NON_MODULE_QUERY_KEYS = new Set(['raw', 'url', 'worker', 'sharedworker', 'inline', 'init']);
|
|
63
|
+
|
|
64
|
+
import { PROJECT_MOUNT_QUERY } from '@volter/editor-sdk/session/project-module-url';
|
|
65
|
+
|
|
66
|
+
const MODULE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
|
|
67
|
+
const STORY_MODULE_PATTERN = /\.stories\.[cm]?[jt]sx?$/i;
|
|
68
|
+
|
|
69
|
+
function pathAndQuery(name: string): { path: string; query: string } | null {
|
|
70
|
+
// Resource Timing `name` is an absolute url. Parsing against a fixed base
|
|
71
|
+
// keeps this pure (no `window.location` read) and works for both forms.
|
|
72
|
+
let parsed: URL;
|
|
73
|
+
try {
|
|
74
|
+
parsed = new URL(name, 'http://vgai.invalid');
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return { path: parsed.pathname, query: parsed.search };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isNonModuleQuery(query: string): boolean {
|
|
82
|
+
const params = new URLSearchParams(query);
|
|
83
|
+
for (const key of params.keys()) {
|
|
84
|
+
if (NON_MODULE_QUERY_KEYS.has(key)) return true;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The pure half: given the Resource Timing entries of one mount window and
|
|
91
|
+
* the project's absolute root, return every project file fetched under more
|
|
92
|
+
* than one url.
|
|
93
|
+
*
|
|
94
|
+
* `projectRoot` is matched against the `/@fs/`-mounted pathname, which is how
|
|
95
|
+
* every project module the editor imports is served in dev. A project served
|
|
96
|
+
* some other way simply yields no candidates — an empty result, never a
|
|
97
|
+
* fabricated one.
|
|
98
|
+
*/
|
|
99
|
+
/** The one candidate test: is this fetch a MODULE of the project under test?
|
|
100
|
+
* Split out so the grouping loop stays one thing. */
|
|
101
|
+
function projectModuleFetch(
|
|
102
|
+
entry: ResourceTimingLike,
|
|
103
|
+
root: string,
|
|
104
|
+
since: number,
|
|
105
|
+
): { group: string; path: string; url: string } | null {
|
|
106
|
+
if (entry.startTime < since) return null;
|
|
107
|
+
const parts = pathAndQuery(entry.name);
|
|
108
|
+
if (!parts) return null;
|
|
109
|
+
const { path, query } = parts;
|
|
110
|
+
if (!path.includes(root)) return null;
|
|
111
|
+
if (!MODULE_EXTENSIONS.some((ext) => path.endsWith(ext))) return null;
|
|
112
|
+
// Portable CSF is a design-time document, not part of a mounted root's
|
|
113
|
+
// runtime module graph. Story discovery deliberately gives every refresh a
|
|
114
|
+
// fresh `?t=` URL (`stories/story-discovery.ts`), and a board refresh may
|
|
115
|
+
// overlap this Play mount window. Counting that intentional reload as a
|
|
116
|
+
// cross-root split makes a healthy multi-root game report an error even
|
|
117
|
+
// though every root entry still shares the one `vgai-mount` epoch.
|
|
118
|
+
if (STORY_MODULE_PATTERN.test(path)) return null;
|
|
119
|
+
if (isNonModuleQuery(query)) return null;
|
|
120
|
+
// The mount id is not a variant of a module — it names WHICH INSTANCE's copy
|
|
121
|
+
// this is, and per-instance module graphs are the isolation working (see
|
|
122
|
+
// ARCHITECTURE-CORE §Multiplayer authoring). Two instances fetch every
|
|
123
|
+
// project module under different urls BY DESIGN, so comparing across them
|
|
124
|
+
// would report the entire project as split the moment a second one mounts —
|
|
125
|
+
// every module, every time, on the loudest diagnostic in the play path.
|
|
126
|
+
// Group per instance instead: the question this watch asks ("did the roots
|
|
127
|
+
// of one mount fail to share a module?") is a per-instance question. With
|
|
128
|
+
// one instance — every mount today — there is one group and nothing changes.
|
|
129
|
+
const params = new URLSearchParams(query);
|
|
130
|
+
const mount = params.get(PROJECT_MOUNT_QUERY) ?? '';
|
|
131
|
+
params.delete(PROJECT_MOUNT_QUERY);
|
|
132
|
+
const rest = params.toString();
|
|
133
|
+
return {
|
|
134
|
+
group: `${mount}\u0000${path}`,
|
|
135
|
+
path,
|
|
136
|
+
url: `${path}${rest ? `?${rest}` : ''}`,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function findProjectModuleSplits(
|
|
141
|
+
resources: readonly ResourceTimingLike[],
|
|
142
|
+
opts: { readonly projectRoot: string; readonly since: number },
|
|
143
|
+
): ProjectModuleSplit[] {
|
|
144
|
+
const root = opts.projectRoot.endsWith('/') ? opts.projectRoot.slice(0, -1) : opts.projectRoot;
|
|
145
|
+
if (root.length === 0) return [];
|
|
146
|
+
const byGroup = new Map<string, { path: string; urls: string[] }>();
|
|
147
|
+
|
|
148
|
+
for (const entry of resources) {
|
|
149
|
+
const fetched = projectModuleFetch(entry, root, opts.since);
|
|
150
|
+
if (!fetched) continue;
|
|
151
|
+
const seen = byGroup.get(fetched.group);
|
|
152
|
+
if (seen === undefined) byGroup.set(fetched.group, { path: fetched.path, urls: [fetched.url] });
|
|
153
|
+
else if (!seen.urls.includes(fetched.url)) seen.urls.push(fetched.url);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const splits: ProjectModuleSplit[] = [];
|
|
157
|
+
for (const { path, urls } of byGroup.values()) {
|
|
158
|
+
if (urls.length > 1) splits.push({ path, urls });
|
|
159
|
+
}
|
|
160
|
+
return splits;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* The message a split is reported with. Pure (and exported) so the wording is
|
|
165
|
+
* a testable contract rather than an inline string: a silent split is the
|
|
166
|
+
* entire defect, so the report has to NAME the module and show the two urls
|
|
167
|
+
* that prove it.
|
|
168
|
+
*/
|
|
169
|
+
export function formatProjectModuleSplitMessage(split: ProjectModuleSplit): string {
|
|
170
|
+
return (
|
|
171
|
+
`Cross-root module split: ${split.path} was loaded ${split.urls.length} times in one mount, ` +
|
|
172
|
+
'so each root holds its OWN copy of its module-level state (a `let` written by one root is ' +
|
|
173
|
+
'invisible to the other). Urls: ' +
|
|
174
|
+
split.urls.join(' | ')
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// The stateful half — one mount window, and the reports it produced
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
interface PerformanceLike {
|
|
183
|
+
now(): number;
|
|
184
|
+
getEntriesByType(type: string): ResourceTimingLike[];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function performanceHost(): PerformanceLike | null {
|
|
188
|
+
const candidate = (globalThis as { performance?: unknown }).performance;
|
|
189
|
+
if (!candidate || typeof candidate !== 'object') return null;
|
|
190
|
+
const perf = candidate as Partial<PerformanceLike>;
|
|
191
|
+
if (typeof perf.now !== 'function' || typeof perf.getEntriesByType !== 'function') return null;
|
|
192
|
+
return perf as PerformanceLike;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Capture this diagnostic window independently of the browser's bounded
|
|
196
|
+
// Resource Timing history. Module lookup is owned by the game realm.
|
|
197
|
+
let resourceObserver: PerformanceObserver | null = null;
|
|
198
|
+
let windowResources: ResourceTimingLike[] = [];
|
|
199
|
+
|
|
200
|
+
let windowStart: number | null = null;
|
|
201
|
+
let reports: ProjectModuleSplit[] = [];
|
|
202
|
+
|
|
203
|
+
/** Open the mount window. Called immediately before a composition's roots are
|
|
204
|
+
* resolved/imported; clears the previous mount's reports so the diagnostic
|
|
205
|
+
* can always go back to healthy (the PD-1 lesson — a report that cannot
|
|
206
|
+
* clear itself is worse than none). */
|
|
207
|
+
export function beginProjectModuleSplitWatch(): void {
|
|
208
|
+
reports = [];
|
|
209
|
+
resourceObserver?.disconnect();
|
|
210
|
+
resourceObserver = null;
|
|
211
|
+
windowResources = [];
|
|
212
|
+
const perf = performanceHost();
|
|
213
|
+
if (!perf) {
|
|
214
|
+
windowStart = null;
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
windowStart = perf.now();
|
|
218
|
+
if (typeof PerformanceObserver !== 'undefined') {
|
|
219
|
+
resourceObserver = new PerformanceObserver((list) => {
|
|
220
|
+
windowResources.push(...list.getEntries());
|
|
221
|
+
});
|
|
222
|
+
resourceObserver.observe({ type: 'resource' });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Close the mount window and record what it found. Called after every root
|
|
228
|
+
* has mounted (not merely resolved) so a root that imports its entry lazily
|
|
229
|
+
* inside `mount()` is inside the window too. Returns the reports so the
|
|
230
|
+
* caller can log them; a no-op window (no `performance`, or no `begin`) is an
|
|
231
|
+
* empty result, never a guess.
|
|
232
|
+
*/
|
|
233
|
+
export function endProjectModuleSplitWatch(projectRoot: string): readonly ProjectModuleSplit[] {
|
|
234
|
+
const perf = performanceHost();
|
|
235
|
+
if (!perf || windowStart === null) {
|
|
236
|
+
windowStart = null;
|
|
237
|
+
return reports;
|
|
238
|
+
}
|
|
239
|
+
const entries = resourceObserver
|
|
240
|
+
? [...windowResources, ...resourceObserver.takeRecords()]
|
|
241
|
+
: perf.getEntriesByType('resource');
|
|
242
|
+
resourceObserver?.disconnect();
|
|
243
|
+
resourceObserver = null;
|
|
244
|
+
windowResources = [];
|
|
245
|
+
reports = findProjectModuleSplits(entries, {
|
|
246
|
+
projectRoot,
|
|
247
|
+
since: windowStart,
|
|
248
|
+
});
|
|
249
|
+
windowStart = null;
|
|
250
|
+
return reports;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** What the last closed mount window found — `[]` on a healthy mount. Read by
|
|
254
|
+
* `command-listener.ts`'s `collectState` so `vgai status` carries it. */
|
|
255
|
+
export function getProjectModuleSplitReports(): readonly ProjectModuleSplit[] {
|
|
256
|
+
return reports;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** Drop every recorded split — what a torn-down play session calls. */
|
|
260
|
+
export function clearProjectModuleSplitReports(): void {
|
|
261
|
+
resourceObserver?.disconnect();
|
|
262
|
+
resourceObserver = null;
|
|
263
|
+
windowResources = [];
|
|
264
|
+
reports = [];
|
|
265
|
+
windowStart = null;
|
|
266
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const PROVENANCE_PATH = '.vgai/provenance.json';
|
|
2
|
+
|
|
3
|
+
export interface ProjectOutputProvenance {
|
|
4
|
+
readonly operationId: string;
|
|
5
|
+
readonly createdAt: string;
|
|
6
|
+
readonly operationName: string;
|
|
7
|
+
readonly operationSource?: string;
|
|
8
|
+
readonly input?: unknown;
|
|
9
|
+
readonly output: {
|
|
10
|
+
readonly path: string;
|
|
11
|
+
readonly bytes: number;
|
|
12
|
+
readonly sha256: string;
|
|
13
|
+
readonly mediaType?: string;
|
|
14
|
+
readonly role?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** The project-root-relative FILE behind a served asset path — the served path
|
|
19
|
+
* with `public/` put back, which is where a writer's bytes have to land. */
|
|
20
|
+
export function projectOutputPath(assetPath: string): string {
|
|
21
|
+
const clean = assetPath.split(/[?#]/, 1)[0]!.replace(/^\/+/, '');
|
|
22
|
+
return clean.startsWith('public/') ? clean : `public/${clean}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function readProjectProvenance(): Promise<unknown> {
|
|
26
|
+
// NOT read through `editor-server-response.ts`: this route's GET half serves
|
|
27
|
+
// raw file bytes as `text/plain` (routes/project-source.ts), and that reader
|
|
28
|
+
// asserts `application/json` — it would reject the success case.
|
|
29
|
+
const response = await fetch(
|
|
30
|
+
`/__editor/vgai-file?${new URLSearchParams({ path: PROVENANCE_PATH })}`,
|
|
31
|
+
);
|
|
32
|
+
if (!response.ok) return null;
|
|
33
|
+
return JSON.parse(await response.text());
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function record(value: unknown): Record<string, unknown> | null {
|
|
37
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
38
|
+
? (value as Record<string, unknown>)
|
|
39
|
+
: null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parsedOutput(
|
|
43
|
+
value: unknown,
|
|
44
|
+
expectedPath: string,
|
|
45
|
+
): ProjectOutputProvenance['output'] | null {
|
|
46
|
+
const output = record(value);
|
|
47
|
+
if (
|
|
48
|
+
output?.['path'] !== expectedPath ||
|
|
49
|
+
typeof output['bytes'] !== 'number' ||
|
|
50
|
+
typeof output['sha256'] !== 'string'
|
|
51
|
+
)
|
|
52
|
+
return null;
|
|
53
|
+
const mediaType = output['mediaType'];
|
|
54
|
+
const role = output['role'];
|
|
55
|
+
return {
|
|
56
|
+
path: expectedPath,
|
|
57
|
+
bytes: output['bytes'],
|
|
58
|
+
sha256: output['sha256'],
|
|
59
|
+
...(typeof mediaType === 'string' ? { mediaType } : {}),
|
|
60
|
+
...(typeof role === 'string' ? { role } : {}),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function operationMatches(
|
|
65
|
+
operationId: string,
|
|
66
|
+
value: unknown,
|
|
67
|
+
expectedPath: string,
|
|
68
|
+
): ProjectOutputProvenance[] {
|
|
69
|
+
const operation = record(value);
|
|
70
|
+
const identity = record(operation?.['operation']);
|
|
71
|
+
const outputs = operation?.['outputs'];
|
|
72
|
+
const createdAt = operation?.['createdAt'];
|
|
73
|
+
const operationName = identity?.['name'];
|
|
74
|
+
if (
|
|
75
|
+
!operation ||
|
|
76
|
+
!identity ||
|
|
77
|
+
typeof createdAt !== 'string' ||
|
|
78
|
+
typeof operationName !== 'string' ||
|
|
79
|
+
!Array.isArray(outputs)
|
|
80
|
+
)
|
|
81
|
+
return [];
|
|
82
|
+
const operationSource = identity['source'];
|
|
83
|
+
return outputs.flatMap((value) => {
|
|
84
|
+
const output = parsedOutput(value, expectedPath);
|
|
85
|
+
if (!output) return [];
|
|
86
|
+
return [
|
|
87
|
+
{
|
|
88
|
+
operationId,
|
|
89
|
+
createdAt,
|
|
90
|
+
operationName,
|
|
91
|
+
...(typeof operationSource === 'string' ? { operationSource } : {}),
|
|
92
|
+
...(operation['input'] !== undefined ? { input: operation['input'] } : {}),
|
|
93
|
+
output,
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Resolve the newest central provenance operation that produced this asset path. */
|
|
100
|
+
export async function provenanceForProjectAsset(
|
|
101
|
+
assetPath: string,
|
|
102
|
+
): Promise<ProjectOutputProvenance | null> {
|
|
103
|
+
const document = record(await readProjectProvenance());
|
|
104
|
+
const operations = record(document?.['operations']);
|
|
105
|
+
if (!operations) return null;
|
|
106
|
+
const expectedPath = projectOutputPath(assetPath);
|
|
107
|
+
const matches = Object.entries(operations).flatMap(([operationId, operation]) =>
|
|
108
|
+
operationMatches(operationId, operation, expectedPath),
|
|
109
|
+
);
|
|
110
|
+
return matches.sort((left, right) => right.createdAt.localeCompare(left.createdAt))[0] ?? null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function __projectOutputPathForTest(assetPath: string): string {
|
|
114
|
+
return projectOutputPath(assetPath);
|
|
115
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE PROJECT-READY HOOK — the host's side of `host.project.onReady`: the
|
|
3
|
+
* moment both bootstraps (`the world root's stage`'s boot chain, after the scene
|
|
4
|
+
* loads and the composite installs; `NonThreeAuthoringBootstrap`'s, after
|
|
5
|
+
* its composite installs) reach when a lane may auto-launch what the
|
|
6
|
+
* manifest declares. Listeners run in registration order, each awaited, so
|
|
7
|
+
* a later one may read what an earlier one mounted.
|
|
8
|
+
*
|
|
9
|
+
* LATCHED, per project, for the same reason `hosted-example.ts`'s auto-play
|
|
10
|
+
* decision is: this hook's registrants are PACKAGE SERVICES, and a
|
|
11
|
+
* contribution pass is asynchronous — it can finish on either side of the
|
|
12
|
+
* boot chain. Unlatched, a service that registered one tick late simply
|
|
13
|
+
* never ran, and the lane it starts (the ingest auto-launch) silently
|
|
14
|
+
* did nothing for the whole session; measured 2026-09-17 on a staged
|
|
15
|
+
* vendored game, which mounted nothing at all. The latch is keyed to the
|
|
16
|
+
* project that reached ready, so opening a second project does not fire its
|
|
17
|
+
* services against the first project's boot.
|
|
18
|
+
*/
|
|
19
|
+
import { getCurrentProject } from './project-manager';
|
|
20
|
+
|
|
21
|
+
const listeners = new Set<() => void | Promise<void>>();
|
|
22
|
+
|
|
23
|
+
/** The `rootPath` of the project whose boot chain last reached ready. */
|
|
24
|
+
let readyFor: string | null = null;
|
|
25
|
+
|
|
26
|
+
function currentProjectKey(): string | null {
|
|
27
|
+
return getCurrentProject()?.rootPath ?? null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function onProjectReady(fn: () => void | Promise<void>): () => void {
|
|
31
|
+
listeners.add(fn);
|
|
32
|
+
const key = currentProjectKey();
|
|
33
|
+
if (key !== null && readyFor === key) void fn();
|
|
34
|
+
return () => {
|
|
35
|
+
listeners.delete(fn);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function runProjectReady(): Promise<void> {
|
|
40
|
+
readyFor = currentProjectKey();
|
|
41
|
+
for (const fn of [...listeners]) await fn();
|
|
42
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { resetAvailableWorkspaceDocuments } from './workspace-available-documents';
|
|
2
|
+
/**
|
|
3
|
+
* What must NOT survive a project switch.
|
|
4
|
+
*
|
|
5
|
+
* Switching projects without a page reload is a real path — the project
|
|
6
|
+
* screen's own open sites call `setActiveProject`, and `AppRoot` remounts the
|
|
7
|
+
* editor layout under a fresh provider. React state goes with that remount;
|
|
8
|
+
* MODULE-LEVEL state does not. Every singleton below was written against "one
|
|
9
|
+
* project per page load", and each one carries the previous project's answers
|
|
10
|
+
* into the next: a running play session (RAF loop, WebGL context, Rapier
|
|
11
|
+
* world), a live ingest session nothing unmounted, an authoring override
|
|
12
|
+
* pointing at a game that is gone, System adapters still answering the gizmo
|
|
13
|
+
* and the CLI wire, and two measurement ledgers whose keys (document ids,
|
|
14
|
+
* surface ids) repeat across projects.
|
|
15
|
+
*
|
|
16
|
+
* ONE subscriber, listed in one place, because that is the only way this stays
|
|
17
|
+
* honest: a singleton with a session lifetime that is not named here is a
|
|
18
|
+
* singleton nobody will remember to reset. Add new ones HERE.
|
|
19
|
+
*
|
|
20
|
+
* WHICH SWITCHES ACTUALLY LAND HERE, measured rather than assumed: the
|
|
21
|
+
* browser/FSA project paths (`rootPath: 'browser' | 'fsa'`) never touch the
|
|
22
|
+
* editor server, so nothing reloads and this is the ONLY teardown they get.
|
|
23
|
+
* A local, server-backed open additionally POSTs `/__editor/open-project`,
|
|
24
|
+
* whose broadcast makes `command-listener.ts` reload the page — so there this
|
|
25
|
+
* runs during the window before that reload lands, not instead of it. A page
|
|
26
|
+
* reload reclaims everything by definition; the window before it does not, and
|
|
27
|
+
* it is long enough to hold a live WebGL context and RAF loop across a network
|
|
28
|
+
* round trip.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { clearSelectedAsset } from './asset-selection';
|
|
32
|
+
import { setActiveAuthoring } from './authoring/active-adapter';
|
|
33
|
+
import { resetActiveSystemsForNewProject } from './authoring/active-systems';
|
|
34
|
+
import { resetSessionVitalsForNewProject } from './coverage/session-vitals';
|
|
35
|
+
import { stopAllLiveSessions } from './live-session-registry';
|
|
36
|
+
import { onProjectSessionEnd } from './project-manager';
|
|
37
|
+
import { resetViewportActivationTimingsForNewProject } from './viewport-activation-timings';
|
|
38
|
+
import { closeAllWorkspaceDocuments } from './workspace-document-registry';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Register the project-session resets. Called once at editor init
|
|
42
|
+
* (`EditorContext.tsx`), the same lifecycle shape `startProjectAdapterLoad`
|
|
43
|
+
* uses; returns its own teardown.
|
|
44
|
+
*/
|
|
45
|
+
export function startProjectSessionReset(): () => void {
|
|
46
|
+
return onProjectSessionEnd(() => {
|
|
47
|
+
// TEARDOWN FIRST, and in the order a normal stop would run it: these two
|
|
48
|
+
// own mounted games (loop, renderer, realm, adapters, subscriptions) and
|
|
49
|
+
// each is idempotent + a no-op when nothing is running. Dropping a
|
|
50
|
+
// reference to either would leak the whole session, not just the handle.
|
|
51
|
+
stopAllLiveSessions();
|
|
52
|
+
// Both teardowns above clear the override themselves WHEN they had one;
|
|
53
|
+
// this covers the surfaces that install an override without owning a
|
|
54
|
+
// session (an open design/boundary adapter), which nothing else ends.
|
|
55
|
+
setActiveAuthoring(null);
|
|
56
|
+
resetActiveSystemsForNewProject();
|
|
57
|
+
resetSessionVitalsForNewProject();
|
|
58
|
+
resetViewportActivationTimingsForNewProject();
|
|
59
|
+
// The center's open documents and the Content selection are module
|
|
60
|
+
// state too: a project SWITCH is not a reload, so the previous project's
|
|
61
|
+
// model stayed open in the next project's center, and its restore saw
|
|
62
|
+
// "something is open" and never opened the new project's own default.
|
|
63
|
+
closeAllWorkspaceDocuments();
|
|
64
|
+
resetAvailableWorkspaceDocuments();
|
|
65
|
+
clearSelectedAsset();
|
|
66
|
+
});
|
|
67
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the active project DECLARES, as the chrome reads it (ARCHITECTURE-CORE
|
|
3
|
+
* §Roots: "a project's shape is derived from what it declares, never
|
|
4
|
+
* assumed"). Nothing here names a kind of project; the questions are the
|
|
5
|
+
* ones chrome actually has — does anything mount? — answered from the
|
|
6
|
+
* manifest's own `roots`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useSyncExternalStore } from 'react';
|
|
10
|
+
import { getCurrentProject, onProjectChange } from './active-project';
|
|
11
|
+
|
|
12
|
+
/** True when the active project declares at least one root — something the
|
|
13
|
+
* host mounts, plays and instances. A project config from before
|
|
14
|
+
* `rootCount` existed answers true, which is what every project was. */
|
|
15
|
+
export function projectMounts(): boolean {
|
|
16
|
+
const count = getCurrentProject()?.config.rootCount;
|
|
17
|
+
return count === undefined ? true : count > 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** {@link projectMounts} as a React subscription. */
|
|
21
|
+
export function useProjectMounts(): boolean {
|
|
22
|
+
return useSyncExternalStore(onProjectChange, projectMounts, projectMounts);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const shapeListeners = new Set<() => void>();
|
|
26
|
+
|
|
27
|
+
/** The adapter host resolved (or re-resolved) the document table: what the
|
|
28
|
+
* project declares may have changed without the project itself changing. */
|
|
29
|
+
export function notifyProjectShapeChanged(): void {
|
|
30
|
+
for (const fn of shapeListeners) fn();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Fires on {@link notifyProjectShapeChanged} and on a project change. */
|
|
34
|
+
export function subscribeProjectShape(fn: () => void): () => void {
|
|
35
|
+
shapeListeners.add(fn);
|
|
36
|
+
const stopProject = onProjectChange(fn);
|
|
37
|
+
return () => {
|
|
38
|
+
shapeListeners.delete(fn);
|
|
39
|
+
stopProject();
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The document kinds the active project's resolved table holds, supplied by
|
|
44
|
+
* the adapter host (`project-adapter.ts` registers it) so this module —
|
|
45
|
+
* which a bounded host's closure carries — imports no adapter machinery. `null`
|
|
46
|
+
* until an adapter has resolved. */
|
|
47
|
+
let documentKindsSupplier: (() => readonly string[] | null) | null = null;
|
|
48
|
+
export function registerDocumentKindsSupplier(supplier: () => readonly string[] | null): void {
|
|
49
|
+
documentKindsSupplier = supplier;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** True when the active project's resolved document table holds an entry
|
|
53
|
+
* of `kind` — what a workspace built around one kind of document requires
|
|
54
|
+
* (Model, Sculpt and Texture require a `model`). Before the adapter has
|
|
55
|
+
* resolved, the answer is true, so a workspace never vanishes mid-boot. */
|
|
56
|
+
export function projectDeclaresDocumentKind(kind: string): boolean {
|
|
57
|
+
const kinds = documentKindsSupplier?.() ?? null;
|
|
58
|
+
if (kinds === null) return true;
|
|
59
|
+
return kinds.includes(kind);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** The same answer as a LIST, for a message that has to name the vocabulary
|
|
63
|
+
* rather than test one value against it (`present-view`'s refusal on an
|
|
64
|
+
* unknown document kind). `null` before the adapter has resolved — a refusal
|
|
65
|
+
* that cannot read the table says less, never something invented. */
|
|
66
|
+
export function projectDocumentKinds(): readonly string[] | null {
|
|
67
|
+
return documentKindsSupplier?.() ?? null;
|
|
68
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-tool discovery LIFECYCLE (W0 — "project tool discovery must move
|
|
3
|
+
* out of `BottomPanel` and into project/editor initialization").
|
|
4
|
+
*
|
|
5
|
+
* Until W0, `BottomPanel.tsx` anchored discovery in its own mount effects:
|
|
6
|
+
* the dock was both the DISCOVERER and one consumer of project tools, so
|
|
7
|
+
* inspector-placement tools only loaded because the bottom dock happened to
|
|
8
|
+
* be mounted. This module owns that lifecycle instead; the editor shell
|
|
9
|
+
* starts it once at editor initialization (`EditorContext.tsx`'s
|
|
10
|
+
* `EditorProvider`), and the placement hosts (center tool documents,
|
|
11
|
+
* workspace-utility registrations — `components/tool-documents.tsx`,
|
|
12
|
+
* tool-loader.ts's `getGlobalTools`/`subscribeGlobalTools`) are plain
|
|
13
|
+
* consumers of the already-discovered store — proven by
|
|
14
|
+
* `test/project-tool-discovery.test.ts`, which runs discovery with no
|
|
15
|
+
* component module imported at all.
|
|
16
|
+
*
|
|
17
|
+
* The pass itself still has editor-init ownership (`refreshProjectTools`,
|
|
18
|
+
* tool-loader.ts), but its generic startup inventory waits until the opening
|
|
19
|
+
* viewport has painted: discover after first presentation, re-discover when
|
|
20
|
+
* the open project changes, and
|
|
21
|
+
* re-discover on server-watched editor-lane add/unlink events (W6a).
|
|
22
|
+
* Edit-HMR stays where it was — tool-loader's own module-level
|
|
23
|
+
* `vgai:script-update` listener.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { connectToolFileEvents } from './asset-events';
|
|
27
|
+
import { onProjectChange } from './project-manager';
|
|
28
|
+
import { refreshProjectToolContributions } from './tool-loader';
|
|
29
|
+
import { waitForFirstViewportFrame } from './viewport-activation-timings';
|
|
30
|
+
|
|
31
|
+
async function refreshAfterOpeningViewport(): Promise<void> {
|
|
32
|
+
// Contribution modules are executable UI, not an index. A plain startup
|
|
33
|
+
// used to import every unopened tool here, putting the template's full Data
|
|
34
|
+
// Tables/react-data-grid graph into the same Vite queue as the Scene. Saved
|
|
35
|
+
// tool documents still take workspace-state-persistence's explicit awaited
|
|
36
|
+
// refresh path; this generic inventory can land after the authored frame.
|
|
37
|
+
// Non-navigation DOMs (unit hosts and embedded documents) have no opening
|
|
38
|
+
// page critical path to protect. In a real editor page the Navigation entry
|
|
39
|
+
// is always present, including reloads and history restoration.
|
|
40
|
+
const hasOpeningNavigation =
|
|
41
|
+
typeof performance !== 'undefined' && performance.getEntriesByType('navigation').length > 0;
|
|
42
|
+
if (hasOpeningNavigation) {
|
|
43
|
+
await Promise.race([
|
|
44
|
+
waitForFirstViewportFrame(),
|
|
45
|
+
new Promise<void>((resolve) => setTimeout(resolve, 5_000)),
|
|
46
|
+
]);
|
|
47
|
+
}
|
|
48
|
+
await refreshProjectToolContributions();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Start the project-tool discovery lifecycle: one presentation-deferred
|
|
53
|
+
* inventory pass, plus immediate re-discovery on project change and on
|
|
54
|
+
* tool-file add/unlink events.
|
|
55
|
+
* Returns a stop function that disconnects both subscriptions (the pass in
|
|
56
|
+
* flight is left to finish — `refreshProjectTools` never throws).
|
|
57
|
+
*/
|
|
58
|
+
export function startProjectToolContributionDiscovery(): () => void {
|
|
59
|
+
void refreshAfterOpeningViewport();
|
|
60
|
+
const stopProjectWatch = onProjectChange(() => void refreshProjectToolContributions());
|
|
61
|
+
const stopToolFileWatch = connectToolFileEvents(() => void refreshProjectToolContributions());
|
|
62
|
+
return () => {
|
|
63
|
+
stopProjectWatch();
|
|
64
|
+
stopToolFileWatch();
|
|
65
|
+
};
|
|
66
|
+
}
|