@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,270 @@
|
|
|
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/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://volter.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 `volter-mount` epoch.
|
|
118
|
+
if (STORY_MODULE_PATTERN.test(path)) return null;
|
|
119
|
+
// The project's adapter is the same shape: a binding table the editor reads
|
|
120
|
+
// WITHOUT booting the game (`project-adapter.ts`'s `importAdapterModule`), fresh
|
|
121
|
+
// `?t=` on every read, and imported by no root.
|
|
122
|
+
if (path.endsWith('/volter.adapter.ts')) return null;
|
|
123
|
+
if (isNonModuleQuery(query)) return null;
|
|
124
|
+
// The mount id is not a variant of a module — it names WHICH INSTANCE's copy
|
|
125
|
+
// this is, and per-instance module graphs are the isolation working (see
|
|
126
|
+
// ARCHITECTURE-CORE §Multiplayer authoring). Two instances fetch every
|
|
127
|
+
// project module under different urls BY DESIGN, so comparing across them
|
|
128
|
+
// would report the entire project as split the moment a second one mounts —
|
|
129
|
+
// every module, every time, on the loudest diagnostic in the play path.
|
|
130
|
+
// Group per instance instead: the question this watch asks ("did the roots
|
|
131
|
+
// of one mount fail to share a module?") is a per-instance question. With
|
|
132
|
+
// one instance — every mount today — there is one group and nothing changes.
|
|
133
|
+
const params = new URLSearchParams(query);
|
|
134
|
+
const mount = params.get(PROJECT_MOUNT_QUERY) ?? '';
|
|
135
|
+
params.delete(PROJECT_MOUNT_QUERY);
|
|
136
|
+
const rest = params.toString();
|
|
137
|
+
return {
|
|
138
|
+
group: `${mount}\u0000${path}`,
|
|
139
|
+
path,
|
|
140
|
+
url: `${path}${rest ? `?${rest}` : ''}`,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function findProjectModuleSplits(
|
|
145
|
+
resources: readonly ResourceTimingLike[],
|
|
146
|
+
opts: { readonly projectRoot: string; readonly since: number },
|
|
147
|
+
): ProjectModuleSplit[] {
|
|
148
|
+
const root = opts.projectRoot.endsWith('/') ? opts.projectRoot.slice(0, -1) : opts.projectRoot;
|
|
149
|
+
if (root.length === 0) return [];
|
|
150
|
+
const byGroup = new Map<string, { path: string; urls: string[] }>();
|
|
151
|
+
|
|
152
|
+
for (const entry of resources) {
|
|
153
|
+
const fetched = projectModuleFetch(entry, root, opts.since);
|
|
154
|
+
if (!fetched) continue;
|
|
155
|
+
const seen = byGroup.get(fetched.group);
|
|
156
|
+
if (seen === undefined) byGroup.set(fetched.group, { path: fetched.path, urls: [fetched.url] });
|
|
157
|
+
else if (!seen.urls.includes(fetched.url)) seen.urls.push(fetched.url);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const splits: ProjectModuleSplit[] = [];
|
|
161
|
+
for (const { path, urls } of byGroup.values()) {
|
|
162
|
+
if (urls.length > 1) splits.push({ path, urls });
|
|
163
|
+
}
|
|
164
|
+
return splits;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The message a split is reported with. Pure (and exported) so the wording is
|
|
169
|
+
* a testable contract rather than an inline string: a silent split is the
|
|
170
|
+
* entire defect, so the report has to NAME the module and show the two urls
|
|
171
|
+
* that prove it.
|
|
172
|
+
*/
|
|
173
|
+
export function formatProjectModuleSplitMessage(split: ProjectModuleSplit): string {
|
|
174
|
+
return (
|
|
175
|
+
`Cross-root module split: ${split.path} was loaded ${split.urls.length} times in one mount, ` +
|
|
176
|
+
'so each root holds its OWN copy of its module-level state (a `let` written by one root is ' +
|
|
177
|
+
'invisible to the other). Urls: ' +
|
|
178
|
+
split.urls.join(' | ')
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
// The stateful half — one mount window, and the reports it produced
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
|
|
186
|
+
interface PerformanceLike {
|
|
187
|
+
now(): number;
|
|
188
|
+
getEntriesByType(type: string): ResourceTimingLike[];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function performanceHost(): PerformanceLike | null {
|
|
192
|
+
const candidate = (globalThis as { performance?: unknown }).performance;
|
|
193
|
+
if (!candidate || typeof candidate !== 'object') return null;
|
|
194
|
+
const perf = candidate as Partial<PerformanceLike>;
|
|
195
|
+
if (typeof perf.now !== 'function' || typeof perf.getEntriesByType !== 'function') return null;
|
|
196
|
+
return perf as PerformanceLike;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Capture this diagnostic window independently of the browser's bounded
|
|
200
|
+
// Resource Timing history. Module lookup is owned by the game realm.
|
|
201
|
+
let resourceObserver: PerformanceObserver | null = null;
|
|
202
|
+
let windowResources: ResourceTimingLike[] = [];
|
|
203
|
+
|
|
204
|
+
let windowStart: number | null = null;
|
|
205
|
+
let reports: ProjectModuleSplit[] = [];
|
|
206
|
+
|
|
207
|
+
/** Open the mount window. Called immediately before a composition's roots are
|
|
208
|
+
* resolved/imported; clears the previous mount's reports so the diagnostic
|
|
209
|
+
* can always go back to healthy (the PD-1 lesson — a report that cannot
|
|
210
|
+
* clear itself is worse than none). */
|
|
211
|
+
export function beginProjectModuleSplitWatch(): void {
|
|
212
|
+
reports = [];
|
|
213
|
+
resourceObserver?.disconnect();
|
|
214
|
+
resourceObserver = null;
|
|
215
|
+
windowResources = [];
|
|
216
|
+
const perf = performanceHost();
|
|
217
|
+
if (!perf) {
|
|
218
|
+
windowStart = null;
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
windowStart = perf.now();
|
|
222
|
+
if (typeof PerformanceObserver !== 'undefined') {
|
|
223
|
+
resourceObserver = new PerformanceObserver((list) => {
|
|
224
|
+
windowResources.push(...list.getEntries());
|
|
225
|
+
});
|
|
226
|
+
resourceObserver.observe({ type: 'resource' });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Close the mount window and record what it found. Called after every root
|
|
232
|
+
* has mounted (not merely resolved) so a root that imports its entry lazily
|
|
233
|
+
* inside `mount()` is inside the window too. Returns the reports so the
|
|
234
|
+
* caller can log them; a no-op window (no `performance`, or no `begin`) is an
|
|
235
|
+
* empty result, never a guess.
|
|
236
|
+
*/
|
|
237
|
+
export function endProjectModuleSplitWatch(projectRoot: string): readonly ProjectModuleSplit[] {
|
|
238
|
+
const perf = performanceHost();
|
|
239
|
+
if (!perf || windowStart === null) {
|
|
240
|
+
windowStart = null;
|
|
241
|
+
return reports;
|
|
242
|
+
}
|
|
243
|
+
const entries = resourceObserver
|
|
244
|
+
? [...windowResources, ...resourceObserver.takeRecords()]
|
|
245
|
+
: perf.getEntriesByType('resource');
|
|
246
|
+
resourceObserver?.disconnect();
|
|
247
|
+
resourceObserver = null;
|
|
248
|
+
windowResources = [];
|
|
249
|
+
reports = findProjectModuleSplits(entries, {
|
|
250
|
+
projectRoot,
|
|
251
|
+
since: windowStart,
|
|
252
|
+
});
|
|
253
|
+
windowStart = null;
|
|
254
|
+
return reports;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** What the last closed mount window found — `[]` on a healthy mount. Read by
|
|
258
|
+
* `command-listener.ts`'s `collectState` so the editor's `status` command carries it. */
|
|
259
|
+
export function getProjectModuleSplitReports(): readonly ProjectModuleSplit[] {
|
|
260
|
+
return reports;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Drop every recorded split — what a torn-down play session calls. */
|
|
264
|
+
export function clearProjectModuleSplitReports(): void {
|
|
265
|
+
resourceObserver?.disconnect();
|
|
266
|
+
resourceObserver = null;
|
|
267
|
+
windowResources = [];
|
|
268
|
+
reports = [];
|
|
269
|
+
windowStart = null;
|
|
270
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** A UI tool offers project roots to any playing stage. The caller lends a
|
|
2
|
+
* container and one mount epoch shared with its world/script; Stop disposes it.
|
|
3
|
+
* Neither the game context nor a product needs an overlay field. */
|
|
4
|
+
import type { ProjectMountEpoch } from '../session/project-module-url';
|
|
5
|
+
export interface MountedProjectPlayLayers {
|
|
6
|
+
/** Entries whose dependency graph belongs to these layers. */
|
|
7
|
+
readonly entries: readonly string[];
|
|
8
|
+
dispose(): void;
|
|
9
|
+
}
|
|
10
|
+
export type ProjectPlayLayers = (options: {
|
|
11
|
+
readonly projectRoot: string;
|
|
12
|
+
readonly epoch: ProjectMountEpoch;
|
|
13
|
+
readonly container: HTMLElement;
|
|
14
|
+
/** Report all declared entries before importing or mounting them, so a failed
|
|
15
|
+
* first mount can be retried when an entry or its dependency is saved. */
|
|
16
|
+
readonly onEntries: (entries: readonly string[]) => void;
|
|
17
|
+
}) => Promise<MountedProjectPlayLayers>;
|
|
18
|
+
const key = Symbol.for('volter.project-play-layers');
|
|
19
|
+
const page = globalThis as typeof globalThis & { [key]?: ProjectPlayLayers };
|
|
20
|
+
export function projectPlayLayers(): ProjectPlayLayers | null { return page[key] ?? null; }
|
|
21
|
+
export function registerProjectPlayLayers(provider: ProjectPlayLayers): () => void {
|
|
22
|
+
if (page[key]) throw new Error('A UI tool already offers project Play layers.');
|
|
23
|
+
page[key] = provider;
|
|
24
|
+
return () => { if (page[key] === provider) delete page[key]; };
|
|
25
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const PROVENANCE_PATH = '.volter/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/volter-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 '@volter/sdk/kit/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,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 '@volter/sdk/kit/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,107 @@
|
|
|
1
|
+
import type { ProjectToolCatalog } from '@volter/sdk/project-tool-catalog';
|
|
2
|
+
import { connectToolFileEvents } from './asset-events';
|
|
3
|
+
import { editorServerJson } from '@volter/sdk/kit/editor-server-response';
|
|
4
|
+
import { onProjectChange } from './project-manager';
|
|
5
|
+
|
|
6
|
+
export type {
|
|
7
|
+
ProjectToolCatalog,
|
|
8
|
+
ProjectToolCatalogEntry,
|
|
9
|
+
ProjectToolContribution,
|
|
10
|
+
ToolContributionPoint,
|
|
11
|
+
} from '@volter/sdk/project-tool-catalog';
|
|
12
|
+
|
|
13
|
+
export type ProjectToolOutcome =
|
|
14
|
+
| {
|
|
15
|
+
ok: true;
|
|
16
|
+
data: unknown;
|
|
17
|
+
generation?: import('@volter/sdk/generations').GenerationJob;
|
|
18
|
+
generationWarning?: string;
|
|
19
|
+
}
|
|
20
|
+
| { ok: false; error: { code: string; message: string; data?: unknown; issues?: unknown[] } };
|
|
21
|
+
|
|
22
|
+
const EMPTY_CATALOG: ProjectToolCatalog = { tools: [], contributions: [], loadErrors: [] };
|
|
23
|
+
let catalog = EMPTY_CATALOG;
|
|
24
|
+
let version = 0;
|
|
25
|
+
const listeners = new Set<() => void>();
|
|
26
|
+
|
|
27
|
+
function publish(next: ProjectToolCatalog): void {
|
|
28
|
+
catalog = next;
|
|
29
|
+
version++;
|
|
30
|
+
for (const listener of listeners) listener();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getProjectTools(): ProjectToolCatalog {
|
|
34
|
+
return catalog;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function projectToolsVersion(): number {
|
|
38
|
+
return version;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function subscribeProjectTools(listener: () => void): () => void {
|
|
42
|
+
listeners.add(listener);
|
|
43
|
+
return () => listeners.delete(listener);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function refreshProjectTools(): Promise<ProjectToolCatalog> {
|
|
47
|
+
try {
|
|
48
|
+
const response = await fetch('/__editor/project-tools');
|
|
49
|
+
const next = await editorServerJson<ProjectToolCatalog>(response, 'Catalog request failed');
|
|
50
|
+
publish(next);
|
|
51
|
+
return next;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
const next = {
|
|
54
|
+
tools: [],
|
|
55
|
+
contributions: [],
|
|
56
|
+
loadErrors: [
|
|
57
|
+
{
|
|
58
|
+
sourcePath: 'package.json#volter.tools',
|
|
59
|
+
message: error instanceof Error ? error.message : String(error),
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
publish(next);
|
|
64
|
+
return next;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function runProjectTool(
|
|
69
|
+
name: string,
|
|
70
|
+
input: unknown,
|
|
71
|
+
options: { confirm?: boolean } = {},
|
|
72
|
+
): Promise<ProjectToolOutcome> {
|
|
73
|
+
const response = await fetch('/__editor/project-tools/run', {
|
|
74
|
+
method: 'POST',
|
|
75
|
+
headers: { 'Content-Type': 'application/json' },
|
|
76
|
+
body: JSON.stringify({ name, input, confirm: options.confirm === true }),
|
|
77
|
+
});
|
|
78
|
+
// Named BEFORE parsing. A host with no editor server answers this POST with
|
|
79
|
+
// its page fallback, and `res.json()` on HTML throws `Unexpected token '<'` —
|
|
80
|
+
// an error that names neither the tool nor the reason, surfacing to the user
|
|
81
|
+
// as a broken tool rather than a host that never ran one.
|
|
82
|
+
const outcome = await editorServerJson<ProjectToolOutcome>(
|
|
83
|
+
response,
|
|
84
|
+
`Running the project tool ${JSON.stringify(name)} failed`,
|
|
85
|
+
);
|
|
86
|
+
if (!outcome || typeof outcome !== 'object' || typeof outcome.ok !== 'boolean') {
|
|
87
|
+
throw new Error(`Tool request returned an invalid response (${response.status}).`);
|
|
88
|
+
}
|
|
89
|
+
return outcome;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Editor-init lifecycle for the Node-side registered tool catalog. */
|
|
93
|
+
export function startProjectToolCatalog(): () => void {
|
|
94
|
+
void refreshProjectTools();
|
|
95
|
+
const stopProjectWatch = onProjectChange(() => void refreshProjectTools());
|
|
96
|
+
const stopFileWatch = connectToolFileEvents(() => void refreshProjectTools());
|
|
97
|
+
return () => {
|
|
98
|
+
stopProjectWatch();
|
|
99
|
+
stopFileWatch();
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function __resetProjectToolsForTest(): void {
|
|
104
|
+
catalog = EMPTY_CATALOG;
|
|
105
|
+
version = 0;
|
|
106
|
+
listeners.clear();
|
|
107
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PROJECTION family's surface-neutral shapes (ARCHITECTURE-CORE §The editor
|
|
3
|
+
* protocol).
|
|
4
|
+
*
|
|
5
|
+
* A projection answers "what nodes are in this world, what are their stable
|
|
6
|
+
* ids, and how do they nest" over the RUNTIME objects a mounted world is made
|
|
7
|
+
* of — the live `Object3D`/`Container`/DOM element, never an AST node. A walk
|
|
8
|
+
* always answers: an empty projection over a mounted world is a defect, never a
|
|
9
|
+
* fact.
|
|
10
|
+
*
|
|
11
|
+
* Only the shapes live here. The projectors themselves are per surface
|
|
12
|
+
* (`./three.ts`, `./pixi.ts`, `./dom.ts`), because what an
|
|
13
|
+
* object IS, how identity is minted and what an editor-owned object looks like
|
|
14
|
+
* are all surface facts.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* One projected authoring node.
|
|
19
|
+
*
|
|
20
|
+
* `parentId` is the nearest ADMITTED ancestor — not the runtime parent — so a
|
|
21
|
+
* projection that folds a library's internals into their owner reports the
|
|
22
|
+
* owner. `null` means this node is a root of the projection.
|
|
23
|
+
*/
|
|
24
|
+
export interface ProjectedNode<TObject> {
|
|
25
|
+
readonly object: TObject;
|
|
26
|
+
readonly id: string;
|
|
27
|
+
readonly parentId: string | null;
|
|
28
|
+
readonly childIds: string[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* One walk's product: every node by id, the roots in walk order, and whatever
|
|
33
|
+
* the surface counts about itself.
|
|
34
|
+
*
|
|
35
|
+
* `nodes` is keyed by the id the rest of the editor addresses the node by, so
|
|
36
|
+
* the id the gizmo binds to, the id the hierarchy row shows and the id
|
|
37
|
+
* `EditorShellStore.objectMap` indexes can never disagree — they are all this
|
|
38
|
+
* one map.
|
|
39
|
+
*/
|
|
40
|
+
export interface Projection<TObject, TStats> {
|
|
41
|
+
readonly nodes: Map<string, ProjectedNode<TObject>>;
|
|
42
|
+
readonly rootIds: string[];
|
|
43
|
+
readonly stats: TStats;
|
|
44
|
+
}
|