@volter/sdk 0.0.0-stage → 0.5.203
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/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +38 -3
- package/package.json +510 -4
- package/src/account.ts +210 -0
- package/src/chrome.ts +88 -0
- package/src/client.ts +1646 -0
- package/src/commands.ts +66 -0
- package/src/contributions.ts +619 -0
- package/src/css-numeric-style.ts +97 -0
- package/src/document-probe.ts +282 -0
- package/src/editor-view.ts +225 -0
- package/src/extension.ts +40 -0
- package/src/generations.ts +178 -0
- package/src/host.ts +1157 -0
- package/src/http-transport.browser.ts +14 -0
- package/src/http-transport.node.ts +19 -0
- package/src/index.ts +131 -0
- package/src/kit/CapabilityCoverageSection.tsx +185 -0
- package/src/kit/account-client.ts +333 -0
- package/src/kit/action-registry.ts +317 -0
- package/src/kit/active-product.ts +76 -0
- package/src/kit/active-project.ts +155 -0
- package/src/kit/adapter-editor-config.ts +25 -0
- package/src/kit/adapter-module.ts +7 -0
- package/src/kit/adapter-observation.ts +49 -0
- package/src/kit/animation/animation-clock.ts +479 -0
- package/src/kit/animation/stage-transport.ts +385 -0
- package/src/kit/api/assets.ts +365 -0
- package/src/kit/api/project-open.ts +355 -0
- package/src/kit/api/project-source.ts +180 -0
- package/src/kit/api/project-state.ts +110 -0
- package/src/kit/api/relay.ts +270 -0
- package/src/kit/api/themes.ts +45 -0
- package/src/kit/api-asset-library-wire.ts +45 -0
- package/src/kit/api-base.ts +10 -0
- package/src/kit/api-build.ts +99 -0
- package/src/kit/api-git-wire.ts +56 -0
- package/src/kit/api-logs.ts +92 -0
- package/src/kit/api-project-identity.ts +74 -0
- package/src/kit/api-settings.ts +36 -0
- package/src/kit/api-worktrees.ts +205 -0
- package/src/kit/asset-capabilities.ts +344 -0
- package/src/kit/asset-compare-core.ts +171 -0
- package/src/kit/asset-editor-context.tsx +101 -0
- package/src/kit/asset-events.ts +96 -0
- package/src/kit/asset-inspector-actions.ts +87 -0
- package/src/kit/asset-selection-viewer-registry.ts +113 -0
- package/src/kit/asset-selection.ts +146 -0
- package/src/kit/asset-thumbnails.ts +25 -0
- package/src/kit/asset-viewers.ts +115 -0
- package/src/kit/asset-workflow/asset-import-jobs.ts +106 -0
- package/src/kit/asset-workflow/asset-ledger-backend.ts +126 -0
- package/src/kit/asset-workflow/asset-ledger.ts +156 -0
- package/src/kit/asset-workflow/asset-materialization-report.ts +140 -0
- package/src/kit/asset-workflow/asset-pack-manifest.ts +320 -0
- package/src/kit/asset-workflow/asset-types.ts +142 -0
- package/src/kit/asset-workflow/audio-preview-player.ts +193 -0
- package/src/kit/asset-workflow/audio-waveform.ts +22 -0
- package/src/kit/asset-workflow/cloud-asset-client.ts +263 -0
- package/src/kit/asset-workflow/hosted-asset-materialization.ts +236 -0
- package/src/kit/asset-workflow/image-view-scale.ts +31 -0
- package/src/kit/asset-workflow/import-contract.ts +124 -0
- package/src/kit/asset-workflow/ledger-write-lock.ts +244 -0
- package/src/kit/asset-workflow/pixi-spritesheet.ts +197 -0
- package/src/kit/asset-workflow/preview-resource-lifetime.ts +44 -0
- package/src/kit/asset-workflow/project-asset-commands.ts +20 -0
- package/src/kit/asset-workflow/project-content.ts +288 -0
- package/src/kit/asset-workflow/project-source-index.ts +545 -0
- package/src/kit/asset-workflow/thumbnail-system.ts +256 -0
- package/src/kit/authoring/active-adapter.ts +200 -0
- package/src/kit/authoring/active-systems.ts +422 -0
- package/src/kit/authoring/adapter-key.ts +18 -0
- package/src/kit/authoring/authoring-asset-url.ts +27 -0
- package/src/kit/authoring/bootstrap-state.ts +49 -0
- package/src/kit/authoring/boundary-authoring-adapter.ts +189 -0
- package/src/kit/authoring/canvas-scene-guides.ts +84 -0
- package/src/kit/authoring/composite-authoring-adapter.ts +2109 -0
- package/src/kit/authoring/consumer-actions.ts +531 -0
- package/src/kit/authoring/design-time-layers.ts +852 -0
- package/src/kit/authoring/design-time-mount-registry.ts +244 -0
- package/src/kit/authoring/edit-mode-authoring.ts +637 -0
- package/src/kit/authoring/empty-project-authoring.ts +22 -0
- package/src/kit/authoring/instance-source-menu.ts +135 -0
- package/src/kit/authoring/layered-pick.ts +185 -0
- package/src/kit/authoring/mounted-root-subjects.ts +146 -0
- package/src/kit/authoring/no-authoring-adapter.ts +59 -0
- package/src/kit/authoring/object3d-document-persistence.ts +122 -0
- package/src/kit/authoring/panel-authoring.ts +121 -0
- package/src/kit/authoring/project-authoring-session.ts +105 -0
- package/src/kit/authoring/provenance.ts +99 -0
- package/src/kit/authoring/react-canvas-navigation.ts +259 -0
- package/src/kit/authoring/react-design-canvas-style.ts +20 -0
- package/src/kit/authoring/react-story-board.ts +917 -0
- package/src/kit/authoring/selection-scope.ts +195 -0
- package/src/kit/authoring/shell-document-ops.ts +169 -0
- package/src/kit/authoring/story-board-chrome-fit.ts +107 -0
- package/src/kit/authoring/story-board-presentation.ts +111 -0
- package/src/kit/authoring/three-root.ts +67 -0
- package/src/kit/authoring/viewport-tool-context.ts +73 -0
- package/src/kit/authoring/viewport-tool-owner.ts +38 -0
- package/src/kit/authoring/world-session-state.ts +101 -0
- package/src/kit/authoring-seam-evidence.ts +300 -0
- package/src/kit/availability-tick.ts +66 -0
- package/src/kit/bitmap-label.ts +120 -0
- package/src/kit/boot-routing.ts +392 -0
- package/src/kit/breakpoint-state.ts +43 -0
- package/src/kit/build-identity.ts +16 -0
- package/src/kit/bytes-codec.ts +62 -0
- package/src/kit/cancellation-reason.ts +58 -0
- package/src/kit/canvas-frames.ts +88 -0
- package/src/kit/capture-camera-pose.ts +77 -0
- package/src/kit/capture-size.ts +88 -0
- package/src/kit/chrome-registry.ts +159 -0
- package/src/kit/chrome-slot-registry.ts +91 -0
- package/src/kit/collaboration-client.ts +264 -0
- package/src/kit/collaboration-presence.ts +41 -0
- package/src/kit/command-dispatch.ts +19 -0
- package/src/kit/command-listener.ts +2182 -0
- package/src/kit/command-registry.ts +71 -0
- package/src/kit/component-board-registry.ts +205 -0
- package/src/kit/component-states-registry.ts +199 -0
- package/src/kit/components/AlignToolbar.tsx +204 -0
- package/src/kit/components/ApplicationMenus.tsx +372 -0
- package/src/kit/components/AssetEditorShell.tsx +216 -0
- package/src/kit/components/AssetInspectorToolSection.tsx +124 -0
- package/src/kit/components/BoardRulers.tsx +354 -0
- package/src/kit/components/CanvasAddNodeDialogs.tsx +529 -0
- package/src/kit/components/CanvasSceneViewport.tsx +1195 -0
- package/src/kit/components/ChromeSlot.tsx +20 -0
- package/src/kit/components/CodeView.tsx +470 -0
- package/src/kit/components/CompactInspectorShell.tsx +39 -0
- package/src/kit/components/ConsolePanel.tsx +273 -0
- package/src/kit/components/GameplaySessionTimeline.tsx +295 -0
- package/src/kit/components/InspectionProjection.tsx +932 -0
- package/src/kit/components/Inspector.tsx +270 -0
- package/src/kit/components/InspectorCanvasPreview.tsx +35 -0
- package/src/kit/components/InspectorFieldsSection.tsx +290 -0
- package/src/kit/components/InspectorStoriesSection.tsx +92 -0
- package/src/kit/components/InspectorToolSection.tsx +96 -0
- package/src/kit/components/InspectorTransformSection.tsx +245 -0
- package/src/kit/components/LightExplorerPanel.tsx +433 -0
- package/src/kit/components/MediaProperties.tsx +145 -0
- package/src/kit/components/ProjectHeader.tsx +328 -0
- package/src/kit/components/ReactCanvasControls.tsx +358 -0
- package/src/kit/components/RootSelectionOverlay.tsx +3688 -0
- package/src/kit/components/RootTextEditor.tsx +79 -0
- package/src/kit/components/SaveStatus.tsx +70 -0
- package/src/kit/components/SurfaceCrashBoundary.tsx +105 -0
- package/src/kit/components/SurfaceStateOverlay.tsx +24 -0
- package/src/kit/components/ToolContributionSurfaces.tsx +49 -0
- package/src/kit/components/ToolHost.tsx +380 -0
- package/src/kit/components/Toolbar.tsx +811 -0
- package/src/kit/components/TransientHint.tsx +44 -0
- package/src/kit/components/VersionControlSection.tsx +470 -0
- package/src/kit/components/ViewportOverlaysMenu.tsx +177 -0
- package/src/kit/components/VolterLogo.tsx +18 -0
- package/src/kit/components/WorktreeSwitcher.tsx +712 -0
- package/src/kit/components/account-documents.tsx +1162 -0
- package/src/kit/components/asset-documents.tsx +794 -0
- package/src/kit/components/asset-editor-persistence.ts +216 -0
- package/src/kit/components/asset-selection-section.tsx +545 -0
- package/src/kit/components/asset-thumbnails.tsx +307 -0
- package/src/kit/components/asset-viewers/AudioViewer.tsx +201 -0
- package/src/kit/components/asset-viewers/GenericJsonViewer.tsx +102 -0
- package/src/kit/components/asset-viewers/ImageViewer.tsx +300 -0
- package/src/kit/components/asset-viewers/JsonAssetDocument.tsx +98 -0
- package/src/kit/components/asset-viewers/OnlineAssetDetail.tsx +426 -0
- package/src/kit/components/asset-viewers/SourceAssetViewer.tsx +356 -0
- package/src/kit/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
- package/src/kit/components/asset-viewers/VideoViewer.tsx +101 -0
- package/src/kit/components/asset-viewers/shader-source.ts +144 -0
- package/src/kit/components/board-guides.ts +150 -0
- package/src/kit/components/canvas-scene-hotkeys.ts +37 -0
- package/src/kit/components/canvas-temporary-pivot.ts +34 -0
- package/src/kit/components/core-utilities.tsx +94 -0
- package/src/kit/components/inspector-preview-section.tsx +223 -0
- package/src/kit/components/inspector-revert-label.ts +20 -0
- package/src/kit/components/inspector-selection.ts +42 -0
- package/src/kit/components/inspector-stories-gating.ts +171 -0
- package/src/kit/components/inspector-transform-subject.ts +11 -0
- package/src/kit/components/inspector-transform.ts +88 -0
- package/src/kit/components/kind-documents.tsx +544 -0
- package/src/kit/components/primitives/DraftColorInput.tsx +74 -0
- package/src/kit/components/project-tool-documents.tsx +402 -0
- package/src/kit/components/scene-documents.tsx +221 -0
- package/src/kit/components/status-contributions.tsx +407 -0
- package/src/kit/components/tool-documents.tsx +302 -0
- package/src/kit/components/tool-schema-form.tsx +262 -0
- package/src/kit/components/use-after-paint.ts +41 -0
- package/src/kit/components/use-project-image-assets.ts +86 -0
- package/src/kit/components/workspace-history.ts +32 -0
- package/src/kit/components/world-documents.tsx +570 -0
- package/src/kit/components/world-overlay-gestures.ts +1939 -0
- package/src/kit/composite-screenshot.ts +2238 -0
- package/src/kit/content-entry-source-registry.ts +184 -0
- package/src/kit/contribution-surfaces.ts +48 -0
- package/src/kit/coverage/canvas-reveal.ts +192 -0
- package/src/kit/coverage/design-time-surfaces.ts +101 -0
- package/src/kit/coverage/ontology-invariants.ts +466 -0
- package/src/kit/coverage/session-vitals.ts +503 -0
- package/src/kit/crash-null-boundary.ts +36 -0
- package/src/kit/creation-site-edit.ts +1491 -0
- package/src/kit/creation-site-registry.ts +160 -0
- package/src/kit/delegate-harness-registry.ts +134 -0
- package/src/kit/document-areas.ts +70 -0
- package/src/kit/document-context-registry.ts +193 -0
- package/src/kit/document-open-registry.ts +200 -0
- package/src/kit/document-play-extension.ts +221 -0
- package/src/kit/document-preview-source.ts +20 -0
- package/src/kit/document-renderer-session.ts +138 -0
- package/src/kit/document-stage-sessions.ts +26 -0
- package/src/kit/document-viewports.ts +120 -0
- package/src/kit/editor-api.ts +46 -0
- package/src/kit/editor-chrome-capture.ts +136 -0
- package/src/kit/editor-commands.ts +176 -0
- package/src/kit/editor-console.ts +580 -0
- package/src/kit/editor-current-view.ts +56 -0
- package/src/kit/editor-document-probe.ts +1166 -0
- package/src/kit/editor-git-client.ts +115 -0
- package/src/kit/editor-hotkeys.ts +728 -0
- package/src/kit/editor-lease-view.ts +39 -0
- package/src/kit/editor-lease.ts +415 -0
- package/src/kit/editor-mode.ts +19 -0
- package/src/kit/editor-notifications.ts +140 -0
- package/src/kit/editor-presence.ts +563 -0
- package/src/kit/editor-presentation-activity.ts +58 -0
- package/src/kit/editor-presentation-notice.ts +42 -0
- package/src/kit/editor-runtime.tsx +147 -0
- package/src/kit/editor-server-response.ts +86 -0
- package/src/kit/editor-session-attribution.ts +85 -0
- package/src/kit/editor-session-mode.ts +54 -0
- package/src/kit/editor-state-facets.ts +74 -0
- package/src/kit/editor-view-presentation.ts +777 -0
- package/src/kit/environment-images.ts +58 -0
- package/src/kit/eyedropper-session.ts +60 -0
- package/src/kit/files/file-provider.ts +62 -0
- package/src/kit/files/project-files.ts +270 -0
- package/src/kit/finders/index.ts +137 -0
- package/src/kit/finders/scenes-from-entrypoint-selection.ts +387 -0
- package/src/kit/frame/frame-parts.ts +30 -0
- package/src/kit/framed-document-capture.ts +34 -0
- package/src/kit/game-globals-prelude.ts +143 -0
- package/src/kit/game-surface-defaults.ts +33 -0
- package/src/kit/gameplay-dom-recording.ts +318 -0
- package/src/kit/gameplay-export-state.ts +14 -0
- package/src/kit/gameplay-replay.ts +417 -0
- package/src/kit/gameplay-session-time.ts +9 -0
- package/src/kit/gameplay-sessions.ts +204 -0
- package/src/kit/hierarchy-component-marks.ts +298 -0
- package/src/kit/hierarchy-internals.ts +197 -0
- package/src/kit/hierarchy-kind-icon.ts +217 -0
- package/src/kit/hierarchy-menu-registry.ts +67 -0
- package/src/kit/hierarchy-node-rows.ts +307 -0
- package/src/kit/hierarchy-panel-view.ts +280 -0
- package/src/kit/hierarchy-projection.ts +76 -0
- package/src/kit/hierarchy-row-media.ts +45 -0
- package/src/kit/hierarchy-row-model.ts +308 -0
- package/src/kit/hierarchy-rows.ts +11 -0
- package/src/kit/hierarchy-walk.ts +86 -0
- package/src/kit/history/editor-session.ts +25 -0
- package/src/kit/history/history-commands.ts +147 -0
- package/src/kit/history/history-delegate.ts +187 -0
- package/src/kit/history/history-limit-notices.ts +43 -0
- package/src/kit/history/history-service.ts +1189 -0
- package/src/kit/history/persistence-coordinator.ts +35 -0
- package/src/kit/history/project-file-history.ts +386 -0
- package/src/kit/history/project-root-history-backends.ts +139 -0
- package/src/kit/history/resource-registry.ts +209 -0
- package/src/kit/history/snapshot-store.ts +103 -0
- package/src/kit/history/source-history-backend.ts +546 -0
- package/src/kit/history-types.ts +124 -0
- package/src/kit/hmr-registration-group.ts +67 -0
- package/src/kit/hmr-stable-react-context.ts +23 -0
- package/src/kit/hotkeys.ts +190 -0
- package/src/kit/inference-diagnostics.ts +69 -0
- package/src/kit/initial-project.ts +80 -0
- package/src/kit/inspection/active-subject.ts +571 -0
- package/src/kit/inspection/active-surface.ts +142 -0
- package/src/kit/inspection/compose-subject.ts +1055 -0
- package/src/kit/inspection/compose.ts +7 -0
- package/src/kit/inspection/display.ts +171 -0
- package/src/kit/inspection/document-subject.ts +109 -0
- package/src/kit/inspection/game-subject.ts +85 -0
- package/src/kit/inspection/null-subject.ts +119 -0
- package/src/kit/inspection/serialize.ts +357 -0
- package/src/kit/inspection/use-active-inspection.ts +180 -0
- package/src/kit/inspection-model.ts +542 -0
- package/src/kit/inspection-node-media.ts +58 -0
- package/src/kit/inspector-presentation.ts +203 -0
- package/src/kit/inspector-property-grouping.ts +64 -0
- package/src/kit/inspector-section-registry.ts +221 -0
- package/src/kit/instance-source-actions.ts +163 -0
- package/src/kit/js-heap.ts +71 -0
- package/src/kit/key-actions.ts +91 -0
- package/src/kit/keymap-presets.ts +428 -0
- package/src/kit/layout-policy.ts +31 -0
- package/src/kit/light-explorer-model.ts +134 -0
- package/src/kit/live-canvas-frame.ts +55 -0
- package/src/kit/live-document.ts +296 -0
- package/src/kit/live-gesture-lock.ts +50 -0
- package/src/kit/live-seam-evidence.ts +11 -0
- package/src/kit/live-session-registry.ts +220 -0
- package/src/kit/live-transition.ts +391 -0
- package/src/kit/manifest-project.ts +107 -0
- package/src/kit/module-fetch-diagnosis.ts +192 -0
- package/src/kit/mount-failure-report.ts +154 -0
- package/src/kit/native-selection-style.ts +497 -0
- package/src/kit/object3d-document-write-policy.ts +137 -0
- package/src/kit/packaged-runtime.ts +108 -0
- package/src/kit/palettes/maya.palette.json +57 -0
- package/src/kit/palettes/substance.palette.json +57 -0
- package/src/kit/performance-profiler.ts +367 -0
- package/src/kit/performance-sources.ts +69 -0
- package/src/kit/photograph-notice.ts +141 -0
- package/src/kit/play-boot-phase.ts +166 -0
- package/src/kit/play-camera-flight.ts +35 -0
- package/src/kit/png-encode.worker.ts +26 -0
- package/src/kit/presentation-surface.ts +248 -0
- package/src/kit/product-command.ts +90 -0
- package/src/kit/project-adapter.ts +1140 -0
- package/src/kit/project-asset-refresh.ts +23 -0
- package/src/kit/project-asset-roots.ts +68 -0
- package/src/kit/project-local-state.ts +151 -0
- package/src/kit/project-manager.ts +243 -0
- package/src/kit/project-module-changes.ts +201 -0
- package/src/kit/project-module-split.ts +270 -0
- package/src/kit/project-play-layers.ts +25 -0
- package/src/kit/project-provenance.ts +115 -0
- package/src/kit/project-ready.ts +42 -0
- package/src/kit/project-shape.ts +68 -0
- package/src/kit/project-tools.ts +107 -0
- package/src/kit/projection-types.ts +44 -0
- package/src/kit/readiness.ts +113 -0
- package/src/kit/renderer-resource-counts.ts +27 -0
- package/src/kit/reported-play-state.ts +90 -0
- package/src/kit/resolve-contributed-command.ts +14 -0
- package/src/kit/resolve-relative-specifier.ts +33 -0
- package/src/kit/retained-document-states.ts +91 -0
- package/src/kit/scene-document-plan.ts +320 -0
- package/src/kit/scene-live-open.ts +210 -0
- package/src/kit/scoped-game-css.ts +152 -0
- package/src/kit/served-url.ts +5 -0
- package/src/kit/session-close.ts +17 -0
- package/src/kit/session-tombstone.ts +127 -0
- package/src/kit/settings/settings-provider.ts +82 -0
- package/src/kit/settings-store.ts +348 -0
- package/src/kit/shell-document-state.ts +27 -0
- package/src/kit/shell-store-door.ts +45 -0
- package/src/kit/shell-store.ts +722 -0
- package/src/kit/source-conflict.ts +122 -0
- package/src/kit/stage-context.ts +377 -0
- package/src/kit/stage-invalidation.ts +25 -0
- package/src/kit/stage-store-registry.ts +69 -0
- package/src/kit/startup-failure.ts +80 -0
- package/src/kit/state-report-deferral.ts +73 -0
- package/src/kit/storage/host-files-storage.ts +97 -0
- package/src/kit/storage/http-storage.ts +174 -0
- package/src/kit/storage/index.ts +75 -0
- package/src/kit/storage/mem-storage.ts +158 -0
- package/src/kit/storage/path-lock.ts +44 -0
- package/src/kit/storage/paths.ts +26 -0
- package/src/kit/storage-types.ts +127 -0
- package/src/kit/stories/StoryPreviewMount.tsx +306 -0
- package/src/kit/stories/compose-project-stories.ts +255 -0
- package/src/kit/stories/prefabs-finder.ts +54 -0
- package/src/kit/stories/prefabs-from-stories.ts +182 -0
- package/src/kit/stories/project-story-regions.ts +24 -0
- package/src/kit/stories/story-capture.ts +579 -0
- package/src/kit/stories/story-declared-medium.ts +126 -0
- package/src/kit/stories/story-discovery.ts +176 -0
- package/src/kit/stories/story-dom-runtime.ts +78 -0
- package/src/kit/stories/story-grouping.ts +111 -0
- package/src/kit/stories/story-mount-turn.ts +27 -0
- package/src/kit/stories/story-presentation.ts +215 -0
- package/src/kit/stories/story-preview-component.ts +7 -0
- package/src/kit/stories/story-registry.ts +530 -0
- package/src/kit/stories-scope.ts +35 -0
- package/src/kit/story-document-openers.ts +36 -0
- package/src/kit/story-thumbnails.ts +47 -0
- package/src/kit/surface-keyboard.ts +101 -0
- package/src/kit/surface-state.ts +135 -0
- package/src/kit/system-seam-evidence.ts +72 -0
- package/src/kit/tab-census.ts +202 -0
- package/src/kit/tab-lifecycle-client.ts +227 -0
- package/src/kit/theme-library.ts +897 -0
- package/src/kit/theme-preference.ts +429 -0
- package/src/kit/three-viewport-presentation.ts +23 -0
- package/src/kit/tool-contribution-play.ts +74 -0
- package/src/kit/tool-loader.ts +1918 -0
- package/src/kit/transform-mode-request.ts +66 -0
- package/src/kit/transient-hint.ts +78 -0
- package/src/kit/transport-strip.tsx +174 -0
- package/src/kit/ui-source/adapter-region-includes.ts +238 -0
- package/src/kit/ui-source/file-region-resolver.ts +302 -0
- package/src/kit/ui-source/inspect.ts +775 -0
- package/src/kit/ui-source/source-write-backend.ts +605 -0
- package/src/kit/ui-source/tier-source-write-backend.ts +279 -0
- package/src/kit/user-local-state.ts +105 -0
- package/src/kit/viewport-activation-timings.ts +840 -0
- package/src/kit/viewport-editor-controls.ts +22 -0
- package/src/kit/viewport-presentation.ts +668 -0
- package/src/kit/viewport-surface-status.tsx +55 -0
- package/src/kit/wait-until.ts +37 -0
- package/src/kit/worker-call-metrics.ts +166 -0
- package/src/kit/workspace-areas.ts +191 -0
- package/src/kit/workspace-aux-commands.ts +11 -0
- package/src/kit/workspace-available-documents.ts +142 -0
- package/src/kit/workspace-core-utilities.ts +31 -0
- package/src/kit/workspace-document-ids.ts +59 -0
- package/src/kit/workspace-document-registry.ts +624 -0
- package/src/kit/workspace-document-restore.ts +146 -0
- package/src/kit/workspace-host-commands.ts +141 -0
- package/src/kit/workspace-persistence-gate.ts +40 -0
- package/src/kit/workspace-play-utilities.ts +44 -0
- package/src/kit/workspace-presets.ts +446 -0
- package/src/kit/workspace-regions.ts +276 -0
- package/src/kit/workspace-static-panels.ts +73 -0
- package/src/kit/workspace-status-registry.ts +121 -0
- package/src/kit/workspace-storage.ts +35 -0
- package/src/kit/workspace-style.ts +226 -0
- package/src/kit/workspace-utility-commands.ts +74 -0
- package/src/kit/workspace-utility-registry.ts +263 -0
- package/src/kit/world-adoption-event.ts +23 -0
- package/src/kit/world-adoption.ts +115 -0
- package/src/kit/world-canvas-viewport-state.ts +35 -0
- package/src/kit/world-document-routing.ts +104 -0
- package/src/kit/world-pan-state.ts +198 -0
- package/src/kit/write-pipe.ts +173 -0
- package/src/layout-arrangements.ts +5 -0
- package/src/layouts.tsx +108 -0
- package/src/looks.ts +16 -0
- package/src/project/output-roots.ts +73 -0
- package/src/project/tab-census.ts +155 -0
- package/src/project-tool-catalog.ts +104 -0
- package/src/selection.tsx +107 -0
- package/src/services.ts +18 -0
- package/src/session/build-report.ts +22 -0
- package/src/session/collaboration-types.ts +262 -0
- package/src/session/command-table.ts +327 -0
- package/src/session/discovery.ts +100 -0
- package/src/session/editor-brand.ts +48 -0
- package/src/session/editor-compatibility.ts +317 -0
- package/src/session/editor-control-lifecycle.ts +68 -0
- package/src/session/editor-control-protocol.ts +5 -0
- package/src/session/entrypoint-selection-readers.ts +66 -0
- package/src/session/entrypoint-selection-source.ts +120 -0
- package/src/session/game-css-scope.ts +30 -0
- package/src/session/hosted-attachment.ts +225 -0
- package/src/session/limited-view.ts +82 -0
- package/src/session/product-create.ts +24 -0
- package/src/session/product-locator.ts +478 -0
- package/src/session/project-module-url.ts +242 -0
- package/src/session/project-serving.ts +164 -0
- package/src/session/project-upgrade.ts +403 -0
- package/src/session/registry-format.ts +210 -0
- package/src/session/relative-path-guard.ts +56 -0
- package/src/session/scoped-game-css.ts +461 -0
- package/src/session/source-glob.ts +15 -0
- package/src/session/tool-contribution-convention.ts +123 -0
- package/src/session/workbench-locator.ts +712 -0
- package/src/session.ts +41 -0
- package/src/share.ts +160 -0
- package/src/source-analysis.ts +28 -0
- package/src/source-authoring.ts +439 -0
- package/src/tools/errors.ts +91 -0
- package/src/tools/provider-execution.ts +70 -0
- package/src/tools/registry.ts +341 -0
- package/src/tools/types.ts +159 -0
- package/src/transport.ts +100 -0
- package/src/types.ts +1693 -0
- package/src/views.ts +164 -0
- package/src/widgets/design-system.ts +93 -0
- package/src/widgets/editor-appearance.ts +151 -0
- package/src/widgets/editor-material.ts +83 -0
- package/src/widgets/icon-set-registry.ts +105 -0
- package/src/widgets/index.ts +71 -0
- package/src/widgets/inspector-widgets/AlignmentGrid.tsx +182 -0
- package/src/widgets/inspector-widgets/AssetSlotPicker.tsx +123 -0
- package/src/widgets/inspector-widgets/BorderEditor.tsx +309 -0
- package/src/widgets/inspector-widgets/ColorPicker.tsx +549 -0
- package/src/widgets/inspector-widgets/CurveEditor.tsx +359 -0
- package/src/widgets/inspector-widgets/FilterEditor.tsx +108 -0
- package/src/widgets/inspector-widgets/FontPicker.tsx +191 -0
- package/src/widgets/inspector-widgets/GradientEditor.tsx +623 -0
- package/src/widgets/inspector-widgets/ScrubbableInput.tsx +180 -0
- package/src/widgets/inspector-widgets/ShadowEditor.tsx +319 -0
- package/src/widgets/inspector-widgets/color-utils.ts +201 -0
- package/src/widgets/inspector-widgets/curve-utils.ts +212 -0
- package/src/widgets/inspector-widgets/index.ts +25 -0
- package/src/widgets/inspector-widgets/shared.tsx +140 -0
- package/src/widgets/interactive-edit-scope.ts +33 -0
- package/src/widgets/patterns/Dialog.tsx +140 -0
- package/src/widgets/patterns/Fields.tsx +44 -0
- package/src/widgets/patterns/List.tsx +25 -0
- package/src/widgets/patterns/StateSurface.tsx +40 -0
- package/src/widgets/patterns/Surfaces.tsx +122 -0
- package/src/widgets/patterns/Tabs.tsx +80 -0
- package/src/widgets/patterns/Toolbar.tsx +72 -0
- package/src/widgets/patterns/Tree.tsx +72 -0
- package/src/widgets/primitives/AnchoredMenu.tsx +260 -0
- package/src/widgets/primitives/Button.tsx +62 -0
- package/src/widgets/primitives/ColorInput.tsx +78 -0
- package/src/widgets/primitives/DraftTextInput.tsx +63 -0
- package/src/widgets/primitives/EditorIcon.tsx +157 -0
- package/src/widgets/primitives/FormControls.tsx +88 -0
- package/src/widgets/primitives/HoverPreview.tsx +96 -0
- package/src/widgets/primitives/JsonInput.tsx +113 -0
- package/src/widgets/primitives/Layout.tsx +100 -0
- package/src/widgets/primitives/Menu.tsx +161 -0
- package/src/widgets/primitives/NumberInput.tsx +169 -0
- package/src/widgets/primitives/Panel.tsx +80 -0
- package/src/widgets/primitives/SectionHeader.tsx +77 -0
- package/src/widgets/primitives/Text.tsx +54 -0
- package/src/widgets/primitives/ThemeRootPortal.tsx +52 -0
- package/src/widgets/primitives/Tooltip.tsx +204 -0
- package/src/widgets/primitives/Vec3Input.tsx +70 -0
- package/src/widgets/primitives/banner-tones.ts +32 -0
- package/src/widgets/primitives/clamp-to-viewport.ts +44 -0
- package/src/widgets/primitives/editor-icons.ts +254 -0
- package/src/widgets/primitives/panel-header-styles.ts +42 -0
- package/src/widgets/theme.ts +2841 -0
- package/src/widgets/z-index.ts +25 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Project asset BYTES changed on disk. A lane whose loaders cache parsed assets
|
|
2
|
+
* across mounts listens here, invalidates those paths, then reloads — so
|
|
3
|
+
* replacing a GLB updates every placement without editing source.
|
|
4
|
+
*/
|
|
5
|
+
const ASSET_RELOAD_EVENT = 'editor:asset-loaders-changed';
|
|
6
|
+
|
|
7
|
+
export function announceAssetReload(paths: readonly string[]): void {
|
|
8
|
+
if (
|
|
9
|
+
typeof window === 'undefined' ||
|
|
10
|
+
!paths.some((path) => /\.(glb|gltf|png|jpe?g|webp|avif)$/i.test(path))
|
|
11
|
+
)
|
|
12
|
+
return;
|
|
13
|
+
window.dispatchEvent(new CustomEvent(ASSET_RELOAD_EVENT, { detail: { paths } }));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function onAssetReload(listener: (paths: readonly string[]) => void): () => void {
|
|
17
|
+
if (typeof window === 'undefined') return () => {};
|
|
18
|
+
const handler = (event: Event): void => {
|
|
19
|
+
listener((event as CustomEvent<{ paths: readonly string[] }>).detail?.paths ?? []);
|
|
20
|
+
};
|
|
21
|
+
window.addEventListener(ASSET_RELOAD_EVENT, handler);
|
|
22
|
+
return () => window.removeEventListener(ASSET_RELOAD_EVENT, handler);
|
|
23
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The asset ROOTS Content lists, and the one place a row's root plus its
|
|
3
|
+
* root-relative path becomes a project path or a URL.
|
|
4
|
+
*
|
|
5
|
+
* `public/` is the shipped game's assets; `references/` is reference material
|
|
6
|
+
* that lives in the project and is deliberately NOT shipped (see
|
|
7
|
+
* `@volter/sdk/project/output-roots` for the writer's half of the same rule). Both are
|
|
8
|
+
* ordinary directories of ordinary files — there is no reference database, no
|
|
9
|
+
* import step, and no copy into `public/` to make something appear.
|
|
10
|
+
*
|
|
11
|
+
* Why a reference is addressed through `/project-game-static/`: that middleware
|
|
12
|
+
* (`vite-plugin-project-game-static.ts`) already serves the CURRENTLY OPEN
|
|
13
|
+
* project's own folder verbatim, which is exactly what a reference needs and
|
|
14
|
+
* exactly what `public/`'s root-relative URLs are not — a public asset's URL is
|
|
15
|
+
* `/<publicRelativePath>` because a shipped game addresses it that way, and
|
|
16
|
+
* giving references the same spelling would collide with the game's own paths.
|
|
17
|
+
* Nothing new is served; a reference simply uses the project-file route that
|
|
18
|
+
* already exists.
|
|
19
|
+
*
|
|
20
|
+
* `projectPathForAssetUrl` is the inverse: a bytes reader takes the URL a
|
|
21
|
+
* document or a tile already holds and asks THIS module which project file it
|
|
22
|
+
* names.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export const REFERENCE_ROOT = 'references';
|
|
26
|
+
|
|
27
|
+
/** A listable asset root. `public` is the default and the shipped one. */
|
|
28
|
+
export type AssetRootId = 'public' | typeof REFERENCE_ROOT;
|
|
29
|
+
|
|
30
|
+
export const ASSET_ROOTS: readonly AssetRootId[] = ['public', REFERENCE_ROOT];
|
|
31
|
+
|
|
32
|
+
/** The URL prefix a reference is served under on the local editor server. */
|
|
33
|
+
export const REFERENCE_URL_PREFIX = `/project-game-static/${REFERENCE_ROOT}/`;
|
|
34
|
+
|
|
35
|
+
/** Project-root-relative path for a root + root-relative path. */
|
|
36
|
+
export function projectAssetPath(root: AssetRootId, rootRelativePath: string): string {
|
|
37
|
+
return `${root}/${rootRelativePath}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The URL editor chrome, asset documents and the Inspector address this asset
|
|
42
|
+
* by. Public keeps its exact existing spelling (`/textures/crate.png`).
|
|
43
|
+
*/
|
|
44
|
+
export function assetRootServingUrl(root: AssetRootId, rootRelativePath: string): string {
|
|
45
|
+
return root === REFERENCE_ROOT
|
|
46
|
+
? `${REFERENCE_URL_PREFIX}${rootRelativePath}`
|
|
47
|
+
: `/${rootRelativePath}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Is this URL/document path a reference rather than a public asset? */
|
|
51
|
+
export function isReferenceAssetUrl(url: string): boolean {
|
|
52
|
+
return url.startsWith(REFERENCE_URL_PREFIX);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Which project file a serving URL names — the inverse of
|
|
57
|
+
* {@link assetRootServingUrl}, and the one mapping every bytes reader uses.
|
|
58
|
+
* A plain `/x.png` is a public asset, so it answers `public/x.png`, which is
|
|
59
|
+
* the rule those readers used to hardcode.
|
|
60
|
+
*/
|
|
61
|
+
export function projectPathForAssetUrl(url: string): string {
|
|
62
|
+
const servingUrl = url.startsWith('/') ? url : `/${url}`;
|
|
63
|
+
if (isReferenceAssetUrl(servingUrl)) {
|
|
64
|
+
return projectAssetPath(REFERENCE_ROOT, servingUrl.slice(REFERENCE_URL_PREFIX.length));
|
|
65
|
+
}
|
|
66
|
+
const withoutSlash = url.startsWith('/') ? url.slice(1) : url;
|
|
67
|
+
return withoutSlash.startsWith('public/') ? withoutSlash : `public/${withoutSlash}`;
|
|
68
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE PROJECT-LOCAL SETTINGS LAYER — one in-memory document mirroring
|
|
3
|
+
* `.volter/editor-state.json`, the git-ignored file the scaffold already
|
|
4
|
+
* reserves for "editor autosaved UI state" (ARCHITECTURE-CORE §Editor chrome,
|
|
5
|
+
* "Settings have four layers with named homes").
|
|
6
|
+
*
|
|
7
|
+
* Every piece of per-user, per-checkout state — the workspace layouts, the
|
|
8
|
+
* active workspace, the open documents, the view state the shell store
|
|
9
|
+
* autosaves — is a SECTION of this one document, loaded ONCE when a project
|
|
10
|
+
* becomes active and written back debounced through `saveEditorState`, the
|
|
11
|
+
* editor server's own route. One document, one writer, so two sections can
|
|
12
|
+
* never clobber each other through the whole-file route.
|
|
13
|
+
*
|
|
14
|
+
* Keyed by the folder itself: a rename, another browser or another checkout
|
|
15
|
+
* of the same folder finds the same file. Browser storage keyed by an
|
|
16
|
+
* absolute path was the previous home, and it lost a layout to exactly those
|
|
17
|
+
* three moves (measured 2026-09-04).
|
|
18
|
+
*
|
|
19
|
+
* UNDER THE CODE-OSS FRAME THE DOCUMENT IS ONE KEY OF THE WORKBENCH'S WORKSPACE
|
|
20
|
+
* STORAGE (`kit/workspace-storage`): the frame hands that scope over at mount,
|
|
21
|
+
* and the web workbench keeps it in the same folder
|
|
22
|
+
* (`.volter/workbench-storage.json`), beside the workbench's own layout. A host
|
|
23
|
+
* without the frame keeps the file above.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { activeProjectKey, getCurrentProject, onProjectChange } from '@volter/sdk/kit/active-project';
|
|
27
|
+
import { loadEditorState, saveEditorState } from '@volter/sdk/kit/editor-api';
|
|
28
|
+
import { onWorkspaceStorageProvider, workspaceStorageProvider } from '@volter/sdk/kit/workspace-storage';
|
|
29
|
+
import { preloadSettings } from '@volter/sdk/kit/settings-store';
|
|
30
|
+
|
|
31
|
+
type Sections = Record<string, unknown>;
|
|
32
|
+
|
|
33
|
+
const WRITE_DEBOUNCE_MS = 400;
|
|
34
|
+
|
|
35
|
+
/** The workspace storage key the whole document lives under when the frame provides the scope. */
|
|
36
|
+
const STORAGE_KEY = 'volter.projectLocalState';
|
|
37
|
+
|
|
38
|
+
let loadedFor: string | null = null;
|
|
39
|
+
let loading: Promise<void> | null = null;
|
|
40
|
+
let doc: Sections = {};
|
|
41
|
+
let dirty = false;
|
|
42
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
43
|
+
|
|
44
|
+
function projectKey(): string {
|
|
45
|
+
return activeProjectKey();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Load the active project's local document, once per project. Idempotent and
|
|
50
|
+
* memoized: the second caller for the same project joins the first load, and
|
|
51
|
+
* a different project starts over. Callers that read synchronously through
|
|
52
|
+
* {@link projectLocalSection} await this first.
|
|
53
|
+
*/
|
|
54
|
+
export function preloadProjectLocalState(): Promise<void> {
|
|
55
|
+
const key = projectKey();
|
|
56
|
+
if (loadedFor === key) return Promise.resolve();
|
|
57
|
+
// A load in flight for ANOTHER project (the boot's unscoped one, or a
|
|
58
|
+
// project switched away from mid-load) settles for that project; this
|
|
59
|
+
// caller's project loads after it, never joins it.
|
|
60
|
+
if (loading) return loading.then(() => preloadProjectLocalState());
|
|
61
|
+
const storage = workspaceStorageProvider();
|
|
62
|
+
const load = storage ? Promise.resolve(parseStored(storage.get(STORAGE_KEY))) : loadEditorState();
|
|
63
|
+
loading = Promise.all([load, preloadSettings()])
|
|
64
|
+
.then(([state]) => {
|
|
65
|
+
doc = state && typeof state === 'object' ? { ...state } : {};
|
|
66
|
+
loadedFor = key;
|
|
67
|
+
})
|
|
68
|
+
.catch(() => {
|
|
69
|
+
doc = {};
|
|
70
|
+
loadedFor = key;
|
|
71
|
+
})
|
|
72
|
+
.finally(() => {
|
|
73
|
+
loading = null;
|
|
74
|
+
});
|
|
75
|
+
return loading;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** True once the active project's document has loaded. */
|
|
79
|
+
export function projectLocalStateReady(): boolean {
|
|
80
|
+
return loadedFor === projectKey();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** One section of the loaded document, or `undefined` before load or when
|
|
84
|
+
* the project has never written it. Synchronous by design: the boot awaits
|
|
85
|
+
* {@link preloadProjectLocalState} before anything reads. */
|
|
86
|
+
export function projectLocalSection<T>(name: string): T | undefined {
|
|
87
|
+
if (!projectLocalStateReady()) return undefined;
|
|
88
|
+
return doc[name] as T | undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function flush(leaving = false): void {
|
|
92
|
+
if (timer !== null) {
|
|
93
|
+
clearTimeout(timer);
|
|
94
|
+
timer = null;
|
|
95
|
+
}
|
|
96
|
+
if (!dirty) return;
|
|
97
|
+
dirty = false;
|
|
98
|
+
const storage = workspaceStorageProvider();
|
|
99
|
+
if (storage) storage.store(STORAGE_KEY, JSON.stringify(doc));
|
|
100
|
+
else void saveEditorState(doc, { leaving });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function parseStored(raw: string | undefined): Sections {
|
|
104
|
+
if (!raw) return {};
|
|
105
|
+
try {
|
|
106
|
+
const parsed: unknown = JSON.parse(raw);
|
|
107
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? (parsed as Sections) : {};
|
|
108
|
+
} catch {
|
|
109
|
+
return {};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Replace one section and schedule the write. A write before the load has
|
|
114
|
+
* settled is applied on top of what loads, so a fast first edit is kept. */
|
|
115
|
+
export function writeProjectLocalSection(name: string, value: unknown): void {
|
|
116
|
+
const apply = () => {
|
|
117
|
+
doc = { ...doc, [name]: value };
|
|
118
|
+
dirty = true;
|
|
119
|
+
if (timer !== null) clearTimeout(timer);
|
|
120
|
+
timer = setTimeout(flush, WRITE_DEBOUNCE_MS);
|
|
121
|
+
};
|
|
122
|
+
if (projectLocalStateReady()) apply();
|
|
123
|
+
else void preloadProjectLocalState().then(apply);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Write what is pending NOW — the page is leaving. */
|
|
127
|
+
export function flushProjectLocalState(): void {
|
|
128
|
+
flush(true);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// The layer loads the moment a project becomes active, so the dock that
|
|
132
|
+
// mounts next reads its layout from the folder, not defaults. This module is
|
|
133
|
+
// imported by the shell's boot (`EditorContext`), which is what makes the
|
|
134
|
+
// subscription exist before the first project activates; `active-project.ts`
|
|
135
|
+
// imports nothing of it, so a bounded host's closure stays as it was.
|
|
136
|
+
onProjectChange(() => {
|
|
137
|
+
if (getCurrentProject()) void preloadProjectLocalState();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// The frame's scope arriving (or leaving) changes where the document lives: what was loaded from
|
|
141
|
+
// the other home is read again from this one, so one session never writes two homes.
|
|
142
|
+
onWorkspaceStorageProvider(() => {
|
|
143
|
+
if (loadedFor === null) return;
|
|
144
|
+
flush();
|
|
145
|
+
loadedFor = null;
|
|
146
|
+
if (getCurrentProject()) void preloadProjectLocalState();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (typeof window !== 'undefined') {
|
|
150
|
+
window.addEventListener('pagehide', flushProjectLocalState);
|
|
151
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project manager — manages the active game project.
|
|
3
|
+
*
|
|
4
|
+
* How the editor learns which project is open depends on the surface, and the
|
|
5
|
+
* split is the whole point:
|
|
6
|
+
*
|
|
7
|
+
* - LOCAL (server-backed) — it ASKS the server. The editor server holds
|
|
8
|
+
* "which project is open" as session state, re-rooted live by
|
|
9
|
+
* `POST /__editor/open-project` (the project browser, the editor's `edit <path>` command).
|
|
10
|
+
* The URL carries no project identity at all, so a
|
|
11
|
+
* refresh or a tab-heal navigation back to the bare origin lands in the
|
|
12
|
+
* same project — a VS Code window, not a deep link. A `?project=` on a
|
|
13
|
+
* local URL is a loud boot error (`assertNoRemovedBootParams`).
|
|
14
|
+
*
|
|
15
|
+
* Sibling deep-link param (the §6 contract):
|
|
16
|
+
* `?create-from=<templateOrExampleId>` — handled at AppRoot's routing layer,
|
|
17
|
+
* NOT here. When no explicit project target wins, it opens the
|
|
18
|
+
* hub's New Project wizard with that template/example preselected and the name
|
|
19
|
+
* field focused (invalid ids degrade to the default selection plus a
|
|
20
|
+
* non-blocking notice). An explicit project target always takes precedence.
|
|
21
|
+
*
|
|
22
|
+
* Boot precedence (§5/FT-7, unit G5) is decided by `boot-routing.ts`'s pure
|
|
23
|
+
* `resolveBootTarget` and merely EXECUTED here: explicit target → opted-in
|
|
24
|
+
* reopen-last → hub. `?hub=1` forces the hub, and a reopen-last project that
|
|
25
|
+
* fails to open falls back to the hub rather than trapping the user.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { assertProjectCompatibility } from '@volter/sdk/session/editor-compatibility';
|
|
29
|
+
import { hasRootOnSurface } from '@volter/project/adapter/manifest-interpreter';
|
|
30
|
+
import { loadGameManifest } from '@volter/project/manifest/load';
|
|
31
|
+
import { type ActiveProject, assignActiveProject, type ProjectConfig } from '@volter/sdk/kit/active-project';
|
|
32
|
+
import {
|
|
33
|
+
assertNoRemovedBootParams,
|
|
34
|
+
decideServerProjectBoot,
|
|
35
|
+
describeServerProjectFailure,
|
|
36
|
+
hubRequestedFromSearch,
|
|
37
|
+
resolveBootTarget,
|
|
38
|
+
ServerProjectDetectionError,
|
|
39
|
+
} from './boot-routing';
|
|
40
|
+
import {
|
|
41
|
+
getLauncherSettings,
|
|
42
|
+
listRecentProjects,
|
|
43
|
+
probeCurrentServerProject,
|
|
44
|
+
requireEditorCompatibility,
|
|
45
|
+
} from '@volter/sdk/kit/editor-api';
|
|
46
|
+
import { parseHierarchyProjection } from '@volter/sdk/kit/hierarchy-projection';
|
|
47
|
+
|
|
48
|
+
function describeManifestError(error: unknown): string {
|
|
49
|
+
const issues =
|
|
50
|
+
error && typeof error === 'object' && Array.isArray((error as { issues?: unknown }).issues)
|
|
51
|
+
? (error as { issues: unknown[] }).issues
|
|
52
|
+
: null;
|
|
53
|
+
if (!issues) return error instanceof Error ? error.message : String(error);
|
|
54
|
+
|
|
55
|
+
return issues
|
|
56
|
+
.map((issue) => {
|
|
57
|
+
if (!issue || typeof issue !== 'object') return String(issue);
|
|
58
|
+
const candidate = issue as { path?: unknown; message?: unknown };
|
|
59
|
+
const path = Array.isArray(candidate.path)
|
|
60
|
+
? candidate.path.map(String).join('.') || '(root)'
|
|
61
|
+
: '(root)';
|
|
62
|
+
const message =
|
|
63
|
+
typeof candidate.message === 'string' ? candidate.message : 'Invalid manifest value';
|
|
64
|
+
return `${path}: ${message}`;
|
|
65
|
+
})
|
|
66
|
+
.join('\n');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Open a project by its root path. Fetches the sole v2 project manifest. */
|
|
70
|
+
export async function openProject(rootPath: string): Promise<ActiveProject> {
|
|
71
|
+
const compatibility = await requireEditorCompatibility();
|
|
72
|
+
const res = await fetch('/volter.project.json');
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Could not open project at ${rootPath}.\n` +
|
|
76
|
+
`Failed to load volter.project.json: ${res.status} ${res.statusText}`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
let rawManifest: unknown;
|
|
80
|
+
try {
|
|
81
|
+
rawManifest = await res.json();
|
|
82
|
+
} catch (error) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Could not open project at ${rootPath}.\n` +
|
|
85
|
+
`volter.project.json is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
assertProjectCompatibility(
|
|
89
|
+
rawManifest && typeof rawManifest === 'object'
|
|
90
|
+
? (rawManifest as {
|
|
91
|
+
manifestVersion?: unknown;
|
|
92
|
+
engine?: { version?: unknown };
|
|
93
|
+
roots?: unknown;
|
|
94
|
+
})
|
|
95
|
+
: {},
|
|
96
|
+
compatibility,
|
|
97
|
+
);
|
|
98
|
+
let manifest: ReturnType<typeof loadGameManifest>;
|
|
99
|
+
try {
|
|
100
|
+
manifest = loadGameManifest(rawManifest, { configurationKinds: 'defer' });
|
|
101
|
+
} catch (error) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`Could not open project at ${rootPath}.\n` +
|
|
104
|
+
`volter.project.json does not match the current project format:\n${describeManifestError(error)}`,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
const config: ProjectConfig = {
|
|
108
|
+
manifestVersion: manifest.manifestVersion,
|
|
109
|
+
name: manifest.name,
|
|
110
|
+
version: manifest.version,
|
|
111
|
+
engine: manifest.engine,
|
|
112
|
+
appId: manifest.appId,
|
|
113
|
+
resolution: manifest.resolution,
|
|
114
|
+
authoring: manifest.authoring
|
|
115
|
+
? { hierarchy: parseHierarchyProjection(manifest.authoring.hierarchy) }
|
|
116
|
+
: undefined,
|
|
117
|
+
hasThreeRoot: hasRootOnSurface(manifest, 'three'),
|
|
118
|
+
rootCount: manifest.roots.length,
|
|
119
|
+
configurations: manifest.configurations,
|
|
120
|
+
};
|
|
121
|
+
return assignActiveProject({ rootPath, config });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** How many times boot may re-ask a server that failed to answer at all, and
|
|
125
|
+
* how long it waits between tries. Both small: `detectProject` runs inside
|
|
126
|
+
* AppRoot's detection timeout, and a failing fetch fails fast. */
|
|
127
|
+
export const SERVER_PROJECT_PROBE_ATTEMPTS = 3;
|
|
128
|
+
export const SERVER_PROJECT_PROBE_RETRY_MS = 300;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Detect and open whatever project the server currently has active.
|
|
132
|
+
* Used in production where __VOLTER_PROJECT_PATH__ isn't available at build time.
|
|
133
|
+
*
|
|
134
|
+
* Returns null ONLY when the server said it has no project open — that is the
|
|
135
|
+
* one answer the launcher is a truthful response to. A server that is serving
|
|
136
|
+
* a project it cannot describe, or that could not be asked at all, THROWS
|
|
137
|
+
* (after bounded retries for the transient shape), because rendering the
|
|
138
|
+
* launcher there tells the user their project does not exist when it does.
|
|
139
|
+
* The ladder itself is `boot-routing.ts`'s `decideServerProjectBoot`.
|
|
140
|
+
*/
|
|
141
|
+
export async function detectServerProject(): Promise<ActiveProject | null> {
|
|
142
|
+
const compatibility = await requireEditorCompatibility();
|
|
143
|
+
for (let attempt = 1; ; attempt++) {
|
|
144
|
+
const probe = await probeCurrentServerProject();
|
|
145
|
+
const action = decideServerProjectBoot({
|
|
146
|
+
status: probe.status,
|
|
147
|
+
attempt,
|
|
148
|
+
maxAttempts: SERVER_PROJECT_PROBE_ATTEMPTS,
|
|
149
|
+
});
|
|
150
|
+
if (action === 'continue-ladder') return null;
|
|
151
|
+
if (action === 'open' && probe.status === 'project') {
|
|
152
|
+
const info = probe.project;
|
|
153
|
+
assertProjectCompatibility(info.config, compatibility);
|
|
154
|
+
return assignActiveProject({ rootPath: info.path, config: info.config as ProjectConfig });
|
|
155
|
+
}
|
|
156
|
+
if (action === 'retry') {
|
|
157
|
+
await new Promise((resolve) => setTimeout(resolve, SERVER_PROJECT_PROBE_RETRY_MS));
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
// 'fail' is only reachable from the two failure shapes, and the surface
|
|
161
|
+
// that renders this must name the served path and the server's own error
|
|
162
|
+
// separately — a launcher with a banner is what this fix exists to stop.
|
|
163
|
+
throw new ServerProjectDetectionError(
|
|
164
|
+
describeServerProjectFailure(
|
|
165
|
+
probe.status === 'unreadable'
|
|
166
|
+
? { status: 'unreadable', path: probe.path, error: probe.error }
|
|
167
|
+
: {
|
|
168
|
+
status: 'unknown',
|
|
169
|
+
error: probe.status === 'unknown' ? probe.error : 'no answer from the server',
|
|
170
|
+
},
|
|
171
|
+
),
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Detect which project is open, by ASKING the session. Returns the project if
|
|
178
|
+
* found, null if the project screen should be shown.
|
|
179
|
+
*/
|
|
180
|
+
export async function detectProject(): Promise<ActiveProject | null> {
|
|
181
|
+
// One gate before anything is resolved: a removed boot
|
|
182
|
+
// param errors loudly naming its replacement rather than falling through
|
|
183
|
+
// (boot-routing.ts) — including `?project=` itself: project identity is
|
|
184
|
+
// session-held.
|
|
185
|
+
assertNoRemovedBootParams(window.location.search);
|
|
186
|
+
|
|
187
|
+
// 1. ASK THE SESSION. This is the one explicit target —
|
|
188
|
+
// the editor's `edit <path>` command, `VOLTER_PROJECT`, and the project browser all reach
|
|
189
|
+
// the client the same way, because they all move the SERVER's project
|
|
190
|
+
// and the client reads it from there. There is no URL param and no
|
|
191
|
+
// boot-time Vite define snapshot in this path: the define is a
|
|
192
|
+
// build-time value, and `POST /__editor/open-project` moves the session
|
|
193
|
+
// live, so a snapshot could disagree with the server that serves the
|
|
194
|
+
// files.
|
|
195
|
+
const serverProject = await detectServerProject();
|
|
196
|
+
if (serverProject) return serverProject;
|
|
197
|
+
|
|
198
|
+
// 2. Reopen-last (G5). Only reached when the server said it has no project
|
|
199
|
+
// open: a live session project outranks the preference.
|
|
200
|
+
return reopenLastProjectIfEnabled();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* The opted-in "Reopen last project on launch" rung of the §5 ladder.
|
|
205
|
+
*
|
|
206
|
+
* Returns the reopened project, or null to fall through to the hub — which is
|
|
207
|
+
* also what a FAILED reopen returns. That fallback is deliberate and is half
|
|
208
|
+
* the reason the escape hatch exists: a project that was deleted, moved, or
|
|
209
|
+
* broken since it was last opened must not be able to wedge the launcher in a
|
|
210
|
+
* boot loop the user cannot click their way out of. Unreal behaves the same
|
|
211
|
+
* way. The failure is reported to the console rather than thrown, because a
|
|
212
|
+
* thrown error here would render the startup-failure screen instead of the hub
|
|
213
|
+
* and hide the recents list the user needs in order to pick something else.
|
|
214
|
+
*/
|
|
215
|
+
async function reopenLastProjectIfEnabled(): Promise<ActiveProject | null> {
|
|
216
|
+
const [settings, recents] = await Promise.all([getLauncherSettings(), listRecentProjects()]);
|
|
217
|
+
const target = resolveBootTarget({
|
|
218
|
+
explicitTarget: null,
|
|
219
|
+
hubRequested: hubRequestedFromSearch(window.location.search),
|
|
220
|
+
reopenLastEnabled: settings.reopenLastProject,
|
|
221
|
+
recents,
|
|
222
|
+
});
|
|
223
|
+
if (target.kind !== 'reopen-last') return null;
|
|
224
|
+
try {
|
|
225
|
+
return await openProject(target.path);
|
|
226
|
+
} catch (err) {
|
|
227
|
+
// biome-ignore lint/suspicious/noConsole: a failed auto-reopen must be visible; the editor console isn't mounted yet at boot.
|
|
228
|
+
console.warn(
|
|
229
|
+
`[volter] "Reopen last project on launch" could not open ${target.path}; showing the project browser instead.`,
|
|
230
|
+
err,
|
|
231
|
+
);
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export {
|
|
237
|
+
type ActiveProject,
|
|
238
|
+
getCurrentProject,
|
|
239
|
+
onProjectChange,
|
|
240
|
+
onProjectSessionEnd,
|
|
241
|
+
type ProjectConfig,
|
|
242
|
+
setActiveProject,
|
|
243
|
+
} from '@volter/sdk/kit/active-project';
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "This project module was saved" — the ONE subscription for editor surfaces
|
|
3
|
+
* that hold a live, re-executable copy of a project source module.
|
|
4
|
+
*
|
|
5
|
+
* WHICH SIGNAL, AND WHY IT IS THE HMR CHANNEL AND NOT SSE
|
|
6
|
+
* -------------------------------------------------------
|
|
7
|
+
* The editor has two file-change channels and they answer different
|
|
8
|
+
* questions. `asset-events.ts` (SSE) reports FILE-SET changes — a tool or
|
|
9
|
+
* story file appeared/vanished, a `public/` asset changed — and it carries no
|
|
10
|
+
* event for "an arbitrary `src/**` module's bytes changed". Vite's HMR
|
|
11
|
+
* channel does, and it carries something the SSE channel cannot: the dev
|
|
12
|
+
* server has already stamped the changed file HMR-invalid across the
|
|
13
|
+
* project's own subgraph before it sends (`server/project-script-hmr.ts`'s
|
|
14
|
+
* `stampHmrInvalidation`, bounded at editor chrome). That stamp is what makes
|
|
15
|
+
* a cache-busted re-import re-evaluate the module's DEPENDENCIES too; without
|
|
16
|
+
* it a fresh leaf url re-runs against the browser's cached copies of
|
|
17
|
+
* everything it imports, which is the exact stale-restart defect that module's
|
|
18
|
+
* header documents. So the freshness guarantee is the server's, and this
|
|
19
|
+
* subscription is how a document learns the stamp has landed.
|
|
20
|
+
*
|
|
21
|
+
* THE THREE EVENTS are the complete set the server sends for a project source
|
|
22
|
+
* file (`handleProjectScriptHotUpdate`); a live module document takes all
|
|
23
|
+
* three because its subject can be any of those classifications:
|
|
24
|
+
* - `volter:restart-required` — a plain `.ts`, or a `.tsx` that is not a Fast
|
|
25
|
+
* Refresh boundary. THE COMMON CASE for a model module, whose export is a
|
|
26
|
+
* lowercase builder function.
|
|
27
|
+
* - `volter:script-update` — the file is in the editor's lane (`editor/contributions/`, `editor/tools/`).
|
|
28
|
+
* - `volter:r3f-entry-update` — the file is R3F-dialect.
|
|
29
|
+
* A `.tsx` that IS a Fast Refresh boundary rides stock Vite HMR instead and
|
|
30
|
+
* sends none of these, so `vite:afterUpdate` is taken as well: Vite stamped
|
|
31
|
+
* the graph itself on that path, and the accepted path names the file.
|
|
32
|
+
*
|
|
33
|
+
* Nothing here re-imports anything. The subscriber owns what "changed" means
|
|
34
|
+
* for its own surface.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/** Project-relative path of the module that changed, e.g. `src/prefabs/probe.ts`. */
|
|
38
|
+
export type ProjectModuleChangeListener = (
|
|
39
|
+
relativePath: string,
|
|
40
|
+
affected?: readonly string[],
|
|
41
|
+
type?: 'create' | 'update' | 'delete',
|
|
42
|
+
) => void;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* WHY THE TRANSFORM ERROR IS RECORDED SEPARATELY: a dynamic `import()` of a
|
|
46
|
+
* module the server could not transform rejects with the browser's own opaque
|
|
47
|
+
* `TypeError: Failed to fetch dynamically imported module: <url>` — the
|
|
48
|
+
* ACTUAL reason (`Unexpected ";"`, at line:col, with a source frame) never
|
|
49
|
+
* reaches the importer. Vite sends it on the HMR channel instead, as
|
|
50
|
+
* `vite:error`, and `editor-console.ts` already prints it. A document showing
|
|
51
|
+
* a build failure needs the same text: "failed to fetch" is not a modeling
|
|
52
|
+
* error message.
|
|
53
|
+
*
|
|
54
|
+
* Kept as a LAST-ERROR-PER-FILE map rather than a subscription because the
|
|
55
|
+
* consumer reads it at the moment its import rejects, which is after the
|
|
56
|
+
* event: the server sends `vite:error` while answering the very request that
|
|
57
|
+
* is about to reject.
|
|
58
|
+
*/
|
|
59
|
+
interface ViteErrorPayload {
|
|
60
|
+
readonly err?: {
|
|
61
|
+
readonly message?: unknown;
|
|
62
|
+
readonly id?: unknown;
|
|
63
|
+
readonly frame?: unknown;
|
|
64
|
+
readonly loc?: { readonly file?: unknown; readonly line?: unknown; readonly column?: unknown };
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Keyed by the normalized absolute file path Vite reports. */
|
|
69
|
+
const busKey = Symbol.for('volter.project-module-changes');
|
|
70
|
+
interface ModuleChangesBus {
|
|
71
|
+
readonly listeners: Set<ProjectModuleChangeListener>;
|
|
72
|
+
readonly errors: Map<string, string>;
|
|
73
|
+
transformErrorsWired: boolean;
|
|
74
|
+
changesWired: boolean;
|
|
75
|
+
}
|
|
76
|
+
const page = globalThis as typeof globalThis & { [busKey]?: ModuleChangesBus };
|
|
77
|
+
const bus = page[busKey] ??= {
|
|
78
|
+
listeners: new Set(), errors: new Map(), transformErrorsWired: false, changesWired: false,
|
|
79
|
+
};
|
|
80
|
+
const lastTransformError = bus.errors;
|
|
81
|
+
|
|
82
|
+
/** Vite's HMR context when a dev server serves this module, typed here so the SDK carries no
|
|
83
|
+
* bundler types. */
|
|
84
|
+
const viteHot = (
|
|
85
|
+
import.meta as ImportMeta & {
|
|
86
|
+
hot?: {
|
|
87
|
+
on(event: string, listener: (payload: never) => void): void;
|
|
88
|
+
off(event: string, listener: (payload: never) => void): void;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
).hot;
|
|
92
|
+
|
|
93
|
+
function wireTransformErrors(): void {
|
|
94
|
+
if (bus.transformErrorsWired) return;
|
|
95
|
+
const hot = viteHot;
|
|
96
|
+
if (!hot) return;
|
|
97
|
+
bus.transformErrorsWired = true;
|
|
98
|
+
hot.on('vite:error', (payload: ViteErrorPayload) => {
|
|
99
|
+
const err = payload?.err;
|
|
100
|
+
if (!err || typeof err.message !== 'string') return;
|
|
101
|
+
const file =
|
|
102
|
+
typeof err.loc?.file === 'string' ? err.loc.file : typeof err.id === 'string' ? err.id : null;
|
|
103
|
+
if (file === null) return;
|
|
104
|
+
const frame = typeof err.frame === 'string' && err.frame !== '' ? `\n${err.frame}` : '';
|
|
105
|
+
// Vite ids carry the transform query; the record is keyed by the file.
|
|
106
|
+
lastTransformError.set(normalize(file.split('?')[0] ?? file), `${err.message}${frame}`);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The server's own reason the module at `relativePath` did not transform, if
|
|
112
|
+
* it reported one — see {@link ViteErrorPayload}. `null` when the failure was
|
|
113
|
+
* something else (a throwing top level, a missing dependency at runtime),
|
|
114
|
+
* which is the caller's cue to report what its own `import()` said.
|
|
115
|
+
*/
|
|
116
|
+
export function projectModuleTransformError(relativePath: string): string | null {
|
|
117
|
+
for (const [file, message] of lastTransformError) {
|
|
118
|
+
if (projectModuleChangeMatches(file, relativePath)) return message;
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Drop the recorded transform error for a module that has now built. */
|
|
124
|
+
export function clearProjectModuleTransformError(relativePath: string): void {
|
|
125
|
+
for (const file of [...lastTransformError.keys()]) {
|
|
126
|
+
if (projectModuleChangeMatches(file, relativePath)) lastTransformError.delete(file);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Server-sent event payloads all carry `{ file }` as an ABSOLUTE path. */
|
|
131
|
+
interface HotFilePayload {
|
|
132
|
+
readonly file?: unknown;
|
|
133
|
+
readonly affected?: unknown;
|
|
134
|
+
readonly type?: unknown;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Vite's own `vite:afterUpdate` payload, narrowed to what is read here. */
|
|
138
|
+
interface ViteUpdatePayload {
|
|
139
|
+
readonly updates?: ReadonlyArray<{ readonly acceptedPath?: unknown; readonly path?: unknown }>;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function normalize(path: string): string {
|
|
143
|
+
return path.replaceAll('\\', '/');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Does `changedPath` (absolute, or already project-relative) name
|
|
148
|
+
* `relativePath` of the open project? Compared by SUFFIX because the two
|
|
149
|
+
* halves spell the same file differently: the dev server reports the absolute
|
|
150
|
+
* path it watched, and a document knows only its project-relative one. The
|
|
151
|
+
* leading separator makes the suffix a whole path segment, so
|
|
152
|
+
* `src/prefabs/probe.ts` never matches `.../not-src/prefabs/probe.ts`.
|
|
153
|
+
*/
|
|
154
|
+
export function projectModuleChangeMatches(changedPath: string, relativePath: string): boolean {
|
|
155
|
+
const changed = normalize(changedPath);
|
|
156
|
+
const relative = normalize(relativePath).replace(/^\.?\//, '');
|
|
157
|
+
return changed === relative || changed.endsWith(`/${relative}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Call `listener` whenever the dev server reports that a project source module
|
|
162
|
+
* was saved. A dev-served copy connects Vite to the page-wide bus, so bundled
|
|
163
|
+
* consumers hear the same channel. Outside a dev client no events arrive.
|
|
164
|
+
*/
|
|
165
|
+
export function subscribeProjectModuleChange(listener: ProjectModuleChangeListener): () => void {
|
|
166
|
+
bus.listeners.add(listener);
|
|
167
|
+
wireChanges();
|
|
168
|
+
return () => { bus.listeners.delete(listener); };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function wireChanges(): void {
|
|
172
|
+
const hot = viteHot;
|
|
173
|
+
if (!hot || bus.changesWired) return;
|
|
174
|
+
bus.changesWired = true;
|
|
175
|
+
wireTransformErrors();
|
|
176
|
+
const publish: ProjectModuleChangeListener = (path, affected, type) => {
|
|
177
|
+
for (const listener of [...bus.listeners]) listener(path, affected, type);
|
|
178
|
+
};
|
|
179
|
+
const onFileEvent = (payload: HotFilePayload): void => {
|
|
180
|
+
if (typeof payload?.file !== 'string') return;
|
|
181
|
+
const affected = Array.isArray(payload.affected)
|
|
182
|
+
? payload.affected.filter((path): path is string => typeof path === 'string').map(normalize)
|
|
183
|
+
: undefined;
|
|
184
|
+
const type = payload.type === 'create' || payload.type === 'update' || payload.type === 'delete'
|
|
185
|
+
? payload.type : undefined;
|
|
186
|
+
publish(normalize(payload.file), affected, type);
|
|
187
|
+
};
|
|
188
|
+
const onViteUpdate = (payload: ViteUpdatePayload): void => {
|
|
189
|
+
for (const update of payload?.updates ?? []) {
|
|
190
|
+
const path = update.acceptedPath ?? update.path;
|
|
191
|
+
// Vite's urls carry the transform query (`?t=…`); the path half is the file.
|
|
192
|
+
if (typeof path === 'string') publish(normalize(path.split('?')[0] ?? path));
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
hot.on('volter:restart-required', onFileEvent);
|
|
196
|
+
hot.on('volter:script-update', onFileEvent);
|
|
197
|
+
hot.on('volter:r3f-entry-update', onFileEvent);
|
|
198
|
+
hot.on('vite:afterUpdate', onViteUpdate);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
wireChanges();
|