@volter/editor-core 0.5.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BUNDLED_NOTICES +1527 -0
- package/LICENSE +686 -0
- package/LICENSE-APACHE +202 -0
- package/NOTICE +18 -0
- package/README.md +24 -0
- package/dist/build/chunk-JS4D4XZ3.js +175 -0
- package/dist/build/chunk-JS4D4XZ3.js.map +7 -0
- package/dist/build/vite-plugin-product-contributions.js +100 -0
- package/dist/build/vite-plugin-product-contributions.js.map +7 -0
- package/dist/build/vite-plugin-shared-react.js +25 -0
- package/dist/build/vite-plugin-shared-react.js.map +7 -0
- package/dist/build/vite-plugin-shared-three.js +86 -0
- package/dist/build/vite-plugin-shared-three.js.map +7 -0
- package/dist/server/chunk-KMJC7AGO.js +98 -0
- package/dist/server/chunk-KMJC7AGO.js.map +7 -0
- package/dist/server/chunk-PSILUMGS.js +46 -0
- package/dist/server/chunk-PSILUMGS.js.map +7 -0
- package/dist/server/frame-proxy.js +255 -0
- package/dist/server/frame-proxy.js.map +7 -0
- package/dist/server/open-browser.js +53 -0
- package/dist/server/open-browser.js.map +7 -0
- package/dist/server/process-shutdown.js +127 -0
- package/dist/server/process-shutdown.js.map +7 -0
- package/dist/server/session-registry.js +141 -0
- package/dist/server/session-registry.js.map +7 -0
- package/dist/server/spawn-opener.js +11 -0
- package/dist/server/spawn-opener.js.map +7 -0
- package/dist/server/worktree-identity.js +11 -0
- package/dist/server/worktree-identity.js.map +7 -0
- package/dist-server/packaged.mjs +88816 -0
- package/package.json +118 -0
- package/scripts/build-plugins.mjs +14 -0
- package/scripts/build-server.mjs +26 -0
- package/scripts/build-session.mjs +9 -0
- package/server/account-credentials.ts +60 -0
- package/server/account-service.ts +1434 -0
- package/server/adapter-region-includes.ts +47 -0
- package/server/asset-catalog-v2.ts +175 -0
- package/server/asset-history-snapshots.ts +196 -0
- package/server/asset-ledger-store.ts +195 -0
- package/server/asset-library-routes.ts +1595 -0
- package/server/blender-wasm-artifact.ts +430 -0
- package/server/boot-timings.ts +106 -0
- package/server/canonical-path.ts +50 -0
- package/server/checkout-workspace-preflight.ts +349 -0
- package/server/cloud-asset-catalog.ts +158 -0
- package/server/coding-inference-launch.ts +237 -0
- package/server/collaboration-account-client.ts +202 -0
- package/server/collaboration-attribution.ts +122 -0
- package/server/collaboration-session.ts +934 -0
- package/server/comfyui-bridge.ts +248 -0
- package/server/console-ledger.ts +499 -0
- package/server/creation-site-transform.ts +304 -0
- package/server/creation-site-write.ts +648 -0
- package/server/data-file-serialize.ts +158 -0
- package/server/editor-brand-html.ts +72 -0
- package/server/editor-control-socket.ts +366 -0
- package/server/editor-server-options.ts +190 -0
- package/server/editor-server.ts +1483 -0
- package/server/editor-sse.ts +352 -0
- package/server/engine-provenance.ts +169 -0
- package/server/engine-source-restart.ts +117 -0
- package/server/frame-bridge.ts +115 -0
- package/server/frame-proxy.ts +490 -0
- package/server/frame-workbench.ts +259 -0
- package/server/frontend-handoff.ts +229 -0
- package/server/game-globals-shadow.ts +113 -0
- package/server/gameplay-session-retention.ts +149 -0
- package/server/gameplay-sessions.ts +123 -0
- package/server/generation-jobs.ts +201 -0
- package/server/generation-reconciler.ts +137 -0
- package/server/generative-execution-context.ts +59 -0
- package/server/git-workflow.ts +612 -0
- package/server/harness-chat-caller.ts +36 -0
- package/server/harness-chat-service.ts +1681 -0
- package/server/idle-shutdown.ts +170 -0
- package/server/js-profiling-policy.ts +52 -0
- package/server/launcher-settings.ts +84 -0
- package/server/local-asset-catalog.ts +410 -0
- package/server/managed-account-defaults.ts +22 -0
- package/server/mock-control-plane.ts +540 -0
- package/server/model-import-conversion.ts +345 -0
- package/server/native-credential-store.ts +162 -0
- package/server/open-browser.ts +118 -0
- package/server/packaged.ts +1192 -0
- package/server/play-stall.ts +126 -0
- package/server/process-shutdown.ts +218 -0
- package/server/product-presets.ts +55 -0
- package/server/project-build-artifact.ts +95 -0
- package/server/project-components.ts +100 -0
- package/server/project-dependency-invalidation.ts +114 -0
- package/server/project-file-scan.ts +235 -0
- package/server/project-hmr-files.ts +215 -0
- package/server/project-install-roots.ts +210 -0
- package/server/project-kinds.ts +71 -0
- package/server/project-mcp-servers.ts +82 -0
- package/server/project-module-freshness.ts +109 -0
- package/server/project-module-instance.ts +375 -0
- package/server/project-optimize-deps-entries.ts +827 -0
- package/server/project-output-writer.ts +679 -0
- package/server/project-package-origin.ts +63 -0
- package/server/project-root-surface.ts +831 -0
- package/server/project-scratch-path.ts +47 -0
- package/server/project-script-hmr.ts +619 -0
- package/server/project-serving-plugins.ts +236 -0
- package/server/project-tools.ts +653 -0
- package/server/project-validation.ts +250 -0
- package/server/project-verbs.ts +127 -0
- package/server/project-view.ts +52 -0
- package/server/project-watch.ts +1134 -0
- package/server/project-work-coordinator.ts +288 -0
- package/server/provider-credentials.ts +331 -0
- package/server/recent-projects-store.ts +98 -0
- package/server/redact-secrets.ts +71 -0
- package/server/repository-presence.ts +267 -0
- package/server/routes/account.ts +357 -0
- package/server/routes/agents.ts +60 -0
- package/server/routes/assets.ts +154 -0
- package/server/routes/build.ts +13 -0
- package/server/routes/collaboration.ts +595 -0
- package/server/routes/configurations.ts +419 -0
- package/server/routes/context.ts +264 -0
- package/server/routes/control-plane.ts +1811 -0
- package/server/routes/logs.ts +272 -0
- package/server/routes/project-identity.ts +302 -0
- package/server/routes/project-open.ts +429 -0
- package/server/routes/project-source.ts +686 -0
- package/server/routes/project-state.ts +383 -0
- package/server/routes/relay.ts +1029 -0
- package/server/routes/route-helpers.ts +29 -0
- package/server/routes/served-modules.ts +138 -0
- package/server/routes/session-tabs.ts +196 -0
- package/server/routes/settings.ts +121 -0
- package/server/routes/share-control.ts +486 -0
- package/server/routes/themes.ts +116 -0
- package/server/routes/tools.ts +230 -0
- package/server/routes/worktrees.ts +595 -0
- package/server/scoped-game-css.ts +461 -0
- package/server/server-utils.ts +1194 -0
- package/server/session-product.ts +112 -0
- package/server/session-registry.ts +230 -0
- package/server/share-claims.ts +138 -0
- package/server/share-host.ts +526 -0
- package/server/share-session-gateway.ts +1362 -0
- package/server/share-tunnel.ts +123 -0
- package/server/spawn-opener.ts +74 -0
- package/server/support/play/log-format.ts +76 -0
- package/server/support/play/session-record.ts +199 -0
- package/server/support/project/build-discipline.ts +718 -0
- package/server/support/project/inspection-node.ts +119 -0
- package/server/support/project/log-naming.ts +54 -0
- package/server/support/project/provenance.ts +290 -0
- package/server/support/project/run-name.ts +18 -0
- package/server/support/project/session-journal.ts +830 -0
- package/server/support/project/shared.ts +327 -0
- package/server/tab-bootstrap.ts +62 -0
- package/server/tab-heartbeat.ts +477 -0
- package/server/tab-lifecycle.ts +550 -0
- package/server/tab-presence.ts +1508 -0
- package/server/team-agent-mirror.ts +95 -0
- package/server/twin-auth.ts +138 -0
- package/server/vendored-lock-recorder.ts +968 -0
- package/server/worktree-identity.ts +121 -0
- package/server/worktree-management.ts +398 -0
- package/server/worktree-retention.d.mts +13 -0
- package/server/worktree-retention.mjs +205 -0
- package/src/EditorContext.tsx +169 -0
- package/src/account.ts +333 -0
- package/src/action-registry.ts +532 -0
- package/src/active-product.ts +74 -0
- package/src/active-project.ts +155 -0
- package/src/adapter-editor-config.ts +25 -0
- package/src/adapter-observation.ts +49 -0
- package/src/animation/stage-transport.ts +379 -0
- package/src/animation/three-clips-subject.ts +172 -0
- package/src/api/asset-library-wire.ts +45 -0
- package/src/api/assets.ts +365 -0
- package/src/api/base.ts +10 -0
- package/src/api/build.ts +99 -0
- package/src/api/git-wire.ts +56 -0
- package/src/api/logs.ts +92 -0
- package/src/api/project-identity.ts +74 -0
- package/src/api/project-open.ts +355 -0
- package/src/api/project-source.ts +162 -0
- package/src/api/project-state.ts +107 -0
- package/src/api/relay.ts +268 -0
- package/src/api/settings.ts +36 -0
- package/src/api/themes.ts +45 -0
- package/src/api/worktrees.ts +257 -0
- package/src/asset-compare-core.ts +171 -0
- package/src/asset-compare.ts +294 -0
- package/src/asset-editor-context.tsx +100 -0
- package/src/asset-events.ts +97 -0
- package/src/asset-inspector-actions.ts +87 -0
- package/src/asset-preview-framing.ts +357 -0
- package/src/asset-preview.ts +2802 -0
- package/src/asset-selection-viewer-registry.ts +113 -0
- package/src/asset-selection.ts +133 -0
- package/src/asset-workflow/asset-capabilities.ts +344 -0
- package/src/asset-workflow/asset-import-jobs.ts +106 -0
- package/src/asset-workflow/asset-ledger-backend.ts +126 -0
- package/src/asset-workflow/asset-ledger.ts +156 -0
- package/src/asset-workflow/asset-materialization-report.ts +140 -0
- package/src/asset-workflow/asset-pack-manifest.ts +320 -0
- package/src/asset-workflow/asset-types.ts +142 -0
- package/src/asset-workflow/asset-workflow-quality.ts +61 -0
- package/src/asset-workflow/audio-preview-player.ts +193 -0
- package/src/asset-workflow/audio-waveform.ts +22 -0
- package/src/asset-workflow/cloud-asset-client.ts +263 -0
- package/src/asset-workflow/folder-preview.ts +345 -0
- package/src/asset-workflow/hosted-asset-materialization.ts +236 -0
- package/src/asset-workflow/image-view-scale.ts +32 -0
- package/src/asset-workflow/import-contract.ts +124 -0
- package/src/asset-workflow/ledger-write-lock.ts +244 -0
- package/src/asset-workflow/model-inspection.ts +818 -0
- package/src/asset-workflow/pixi-spritesheet.ts +197 -0
- package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
- package/src/asset-workflow/project-asset-commands.ts +23 -0
- package/src/asset-workflow/project-asset-health.ts +139 -0
- package/src/asset-workflow/project-asset-operations.ts +154 -0
- package/src/asset-workflow/project-asset-roots.ts +68 -0
- package/src/asset-workflow/project-content.ts +288 -0
- package/src/asset-workflow/project-source-index.ts +550 -0
- package/src/asset-workflow/thumbnail-system.ts +256 -0
- package/src/authoring/active-adapter.ts +199 -0
- package/src/authoring/active-systems.ts +422 -0
- package/src/authoring/adapter-key.ts +18 -0
- package/src/authoring/authoring-asset-url.ts +27 -0
- package/src/authoring/bootstrap-state.ts +49 -0
- package/src/authoring/boundary-authoring-adapter.ts +184 -0
- package/src/authoring/breakpoint-state.ts +43 -0
- package/src/authoring/canvas-scene-guides.ts +76 -0
- package/src/authoring/component-instance-root.ts +171 -0
- package/src/authoring/composite-authoring-adapter.ts +2110 -0
- package/src/authoring/consumer-actions.ts +520 -0
- package/src/authoring/css-numeric-style.ts +97 -0
- package/src/authoring/design-time-layers.ts +849 -0
- package/src/authoring/design-time-mount-registry.ts +235 -0
- package/src/authoring/design-time-settle.ts +343 -0
- package/src/authoring/edit-mode-authoring.ts +619 -0
- package/src/authoring/eyedropper-session.ts +60 -0
- package/src/authoring/instance-source-menu-register.ts +13 -0
- package/src/authoring/instance-source-menu.ts +135 -0
- package/src/authoring/layered-pick.ts +183 -0
- package/src/authoring/live-gesture-lock.ts +50 -0
- package/src/authoring/live-object-transform.ts +62 -0
- package/src/authoring/mount-failure-report.ts +154 -0
- package/src/authoring/mounted-root-subjects.ts +144 -0
- package/src/authoring/no-authoring-adapter.ts +55 -0
- package/src/authoring/null-inspection-subjects.tsx +75 -0
- package/src/authoring/object3d-document-persistence.ts +106 -0
- package/src/authoring/object3d-document-session-registry.ts +120 -0
- package/src/authoring/object3d-document-session.ts +1326 -0
- package/src/authoring/object3d-gesture-controller.ts +113 -0
- package/src/authoring/panel-authoring.ts +121 -0
- package/src/authoring/prefab-instance-inspector-section.tsx +237 -0
- package/src/authoring/prefab-instance-section-model.ts +55 -0
- package/src/authoring/project-authoring-session.ts +105 -0
- package/src/authoring/provenance.ts +99 -0
- package/src/authoring/quarks-particle-systems.ts +19 -0
- package/src/authoring/react-canvas-navigation.ts +255 -0
- package/src/authoring/react-design-canvas-style.ts +20 -0
- package/src/authoring/react-story-board.ts +937 -0
- package/src/authoring/selection-scope.ts +195 -0
- package/src/authoring/shell-document-ops.ts +169 -0
- package/src/authoring/shell-object3d-document-write-policy.ts +108 -0
- package/src/authoring/shell-viewport-policy.ts +48 -0
- package/src/authoring/source-object3d-authoring-adapter.ts +526 -0
- package/src/authoring/stories-scope.ts +35 -0
- package/src/authoring/story-board-chrome-fit.ts +107 -0
- package/src/authoring/story-board-presentation.ts +111 -0
- package/src/authoring/three-projection-core.ts +226 -0
- package/src/authoring/viewport-pick-context.ts +40 -0
- package/src/authoring/viewport-raycast.ts +240 -0
- package/src/authoring/viewport-tool-context.ts +73 -0
- package/src/authoring/world-canvas-viewport-state.ts +35 -0
- package/src/authoring/world-hidden-viewport.ts +152 -0
- package/src/authoring/world-pan-state.ts +198 -0
- package/src/authoring/world-session-state.ts +101 -0
- package/src/authoring/write-pipe.ts +173 -0
- package/src/availability-tick.ts +66 -0
- package/src/bitmap-label.ts +120 -0
- package/src/blender-tab-metrics.ts +161 -0
- package/src/board-open-actions.ts +20 -0
- package/src/boot-routing.ts +391 -0
- package/src/build-identity.ts +15 -0
- package/src/bytes-codec.ts +62 -0
- package/src/camera-authoring.ts +175 -0
- package/src/cancellation-reason.ts +58 -0
- package/src/canvas-preview-frames.ts +482 -0
- package/src/capture-camera-pose.ts +77 -0
- package/src/chrome-registry.ts +159 -0
- package/src/chrome-slot-registry.ts +91 -0
- package/src/collaboration-client.ts +264 -0
- package/src/collaboration-presence.ts +41 -0
- package/src/command-dispatch.ts +19 -0
- package/src/command-listener.ts +2743 -0
- package/src/command-registry.ts +70 -0
- package/src/component-board-registry.ts +205 -0
- package/src/component-states-registry.ts +200 -0
- package/src/components/AgentPresentationNotice.tsx +75 -0
- package/src/components/AlignToolbar.tsx +204 -0
- package/src/components/AppRoot.tsx +394 -0
- package/src/components/ApplicationMenus.tsx +415 -0
- package/src/components/AssetBrowser.tsx +2843 -0
- package/src/components/AssetEditorShell.tsx +216 -0
- package/src/components/AssetInspectorToolSection.tsx +124 -0
- package/src/components/BoardRulers.tsx +354 -0
- package/src/components/CameraInfo.tsx +81 -0
- package/src/components/CanvasSceneViewport.tsx +556 -0
- package/src/components/CapabilityCoverageSection.tsx +185 -0
- package/src/components/CenterDocuments.tsx +22 -0
- package/src/components/ChromeSlot.tsx +20 -0
- package/src/components/CodeView.tsx +470 -0
- package/src/components/CollaborationHeaderControl.css +74 -0
- package/src/components/CompactInspectorCard.tsx +190 -0
- package/src/components/CompactInspectorShell.tsx +39 -0
- package/src/components/ConsolePanel.css +55 -0
- package/src/components/ConsolePanel.tsx +270 -0
- package/src/components/DefaultEditorLayout.tsx +106 -0
- package/src/components/DocumentHeaderStrip.tsx +96 -0
- package/src/components/DocumentShelfRail.tsx +45 -0
- package/src/components/DocumentThumbnail.tsx +345 -0
- package/src/components/EditorLeaseGuard.tsx +372 -0
- package/src/components/ErrorBanner.tsx +123 -0
- package/src/components/FolderPreviewTile.tsx +159 -0
- package/src/components/GameHierarchy.tsx +3842 -0
- package/src/components/GameplaySessionTimeline.tsx +295 -0
- package/src/components/InspectionProjection.tsx +968 -0
- package/src/components/Inspector.tsx +233 -0
- package/src/components/InspectorCanvasPreview.tsx +35 -0
- package/src/components/InspectorFieldsSection.tsx +290 -0
- package/src/components/InspectorObjectPreview.tsx +57 -0
- package/src/components/InspectorStoriesSection.tsx +92 -0
- package/src/components/InspectorToolSection.tsx +96 -0
- package/src/components/InspectorTransformSection.tsx +245 -0
- package/src/components/LightExplorerPanel.tsx +433 -0
- package/src/components/MediaProperties.tsx +145 -0
- package/src/components/NonThreeAuthoringBootstrap.tsx +19 -0
- package/src/components/Object3DDocumentToolbar.css +100 -0
- package/src/components/Object3DDocumentToolbar.tsx +454 -0
- package/src/components/Object3DDocumentViewport.tsx +58 -0
- package/src/components/ProjectHeader.css +617 -0
- package/src/components/ProjectHeader.tsx +328 -0
- package/src/components/ProjectLayout.tsx +249 -0
- package/src/components/ReactCanvasControls.tsx +284 -0
- package/src/components/RootSelectionOverlay.tsx +3162 -0
- package/src/components/RootTextEditor.tsx +79 -0
- package/src/components/SaveStatus.tsx +70 -0
- package/src/components/StageHost.tsx +1954 -0
- package/src/components/StageOverlays.tsx +21 -0
- package/src/components/StartupErrorScreen.tsx +76 -0
- package/src/components/StartupLoadingScreen.tsx +65 -0
- package/src/components/StatsOverlay.tsx +78 -0
- package/src/components/SurfaceStateOverlay.tsx +24 -0
- package/src/components/ToolContributionSurfaces.tsx +65 -0
- package/src/components/ToolHost.tsx +370 -0
- package/src/components/ToolObject3DPreview.tsx +39 -0
- package/src/components/Toolbar.tsx +595 -0
- package/src/components/TransientHint.tsx +44 -0
- package/src/components/TransportStrip.tsx +174 -0
- package/src/components/VersionControlSection.tsx +470 -0
- package/src/components/VgaiLogo.css +83 -0
- package/src/components/VgaiLogo.tsx +35 -0
- package/src/components/ViewportControlsHint.tsx +60 -0
- package/src/components/ViewportFurniture.tsx +401 -0
- package/src/components/ViewportOverlay.tsx +145 -0
- package/src/components/ViewportOverlaysMenu.tsx +153 -0
- package/src/components/ViewportShadingMenu.tsx +300 -0
- package/src/components/ViewportViewMenu.tsx +101 -0
- package/src/components/WorkspaceDocumentSurface.tsx +204 -0
- package/src/components/WorkspaceUtilitySurface.tsx +22 -0
- package/src/components/WorktreeSwitcher.css +239 -0
- package/src/components/WorktreeSwitcher.tsx +890 -0
- package/src/components/account-documents.tsx +1162 -0
- package/src/components/asset-documents.tsx +812 -0
- package/src/components/asset-editor-persistence.ts +216 -0
- package/src/components/asset-selection-section.tsx +535 -0
- package/src/components/asset-thumbnails.tsx +312 -0
- package/src/components/asset-viewers/AudioViewer.tsx +201 -0
- package/src/components/asset-viewers/EntityModelDocument.tsx +122 -0
- package/src/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
- package/src/components/asset-viewers/GenericJsonViewer.tsx +102 -0
- package/src/components/asset-viewers/ImageViewer.tsx +300 -0
- package/src/components/asset-viewers/JsonAssetDocument.tsx +93 -0
- package/src/components/asset-viewers/LiveModuleDocument.tsx +417 -0
- package/src/components/asset-viewers/LutAssetDocument.tsx +444 -0
- package/src/components/asset-viewers/ModelAssetDocument.tsx +105 -0
- package/src/components/asset-viewers/Object3DPreview.tsx +359 -0
- package/src/components/asset-viewers/OnlineAssetDetail.tsx +421 -0
- package/src/components/asset-viewers/PasteboardModuleDocument.tsx +67 -0
- package/src/components/asset-viewers/QuarksAssetDocument.tsx +526 -0
- package/src/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
- package/src/components/asset-viewers/SourceAssetViewer.tsx +281 -0
- package/src/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
- package/src/components/asset-viewers/VideoViewer.tsx +101 -0
- package/src/components/asset-viewers/shader-source.ts +144 -0
- package/src/components/asset-workflow.css +731 -0
- package/src/components/board-guides.ts +150 -0
- package/src/components/compact-inspector.css +539 -0
- package/src/components/core-utilities.tsx +90 -0
- package/src/components/editor-notifications.css +40 -0
- package/src/components/engine-workspace.css +274 -0
- package/src/components/inspector-preview-section.tsx +238 -0
- package/src/components/inspector-property-grouping.ts +64 -0
- package/src/components/inspector-revert-label.ts +20 -0
- package/src/components/inspector-selection.ts +42 -0
- package/src/components/inspector-stories-gating.ts +171 -0
- package/src/components/inspector-transform-subject.ts +11 -0
- package/src/components/inspector-transform.ts +75 -0
- package/src/components/kind-documents.tsx +500 -0
- package/src/components/palette-action-publisher.tsx +140 -0
- package/src/components/primitives/DraftColorInput.tsx +74 -0
- package/src/components/product-shell.css +1829 -0
- package/src/components/project-tool-documents.tsx +410 -0
- package/src/components/scene-documents.tsx +223 -0
- package/src/components/stage-keyboard.tsx +37 -0
- package/src/components/stage-overlay-set.tsx +107 -0
- package/src/components/stage-presence-markers.ts +478 -0
- package/src/components/standard-viewport-dressing.ts +417 -0
- package/src/components/status-contributions.tsx +403 -0
- package/src/components/tool-documents.tsx +309 -0
- package/src/components/tool-schema-form.tsx +262 -0
- package/src/components/use-after-paint.ts +41 -0
- package/src/components/use-project-image-assets.ts +86 -0
- package/src/components/viewport-header-controls.css +90 -0
- package/src/components/viewport-surface-status.tsx +55 -0
- package/src/components/workspace-history.ts +32 -0
- package/src/components/workspace-static-panel-registry.tsx +152 -0
- package/src/components/workspace-surfaces.css +621 -0
- package/src/components/world-documents.tsx +586 -0
- package/src/components/world-overlay-gestures.ts +1694 -0
- package/src/composite-screenshot.ts +1641 -0
- package/src/console-sync.ts +131 -0
- package/src/constraint-helper.ts +338 -0
- package/src/content-entry-source-registry.ts +184 -0
- package/src/coverage/authoring-seam-evidence.ts +300 -0
- package/src/coverage/canvas-reveal.ts +192 -0
- package/src/coverage/design-time-surfaces.ts +101 -0
- package/src/coverage/live-seam-evidence.ts +11 -0
- package/src/coverage/ontology-invariants.ts +466 -0
- package/src/coverage/session-vitals.ts +501 -0
- package/src/coverage/system-seam-evidence.ts +72 -0
- package/src/crash-null-boundary.ts +36 -0
- package/src/creation-site-edit.ts +1479 -0
- package/src/creation-site-registry.ts +160 -0
- package/src/delegate-harness-registry.ts +143 -0
- package/src/document-context-registry.ts +177 -0
- package/src/document-open-registry.ts +200 -0
- package/src/document-preview-source.ts +20 -0
- package/src/document-renderer-session.ts +138 -0
- package/src/editor-api.ts +46 -0
- package/src/editor-chrome-capture.ts +139 -0
- package/src/editor-commands.ts +164 -0
- package/src/editor-console.ts +563 -0
- package/src/editor-current-view.ts +82 -0
- package/src/editor-document-probe.ts +881 -0
- package/src/editor-git-client.ts +115 -0
- package/src/editor-host-door.ts +462 -0
- package/src/editor-hotkeys.ts +842 -0
- package/src/editor-lease-view.ts +39 -0
- package/src/editor-lease.ts +415 -0
- package/src/editor-mode.ts +19 -0
- package/src/editor-notifications.ts +140 -0
- package/src/editor-presence.ts +563 -0
- package/src/editor-presentation-activity.ts +50 -0
- package/src/editor-presentation-notice.ts +42 -0
- package/src/editor-runtime.tsx +145 -0
- package/src/editor-server-response.ts +86 -0
- package/src/editor-session-attribution.ts +75 -0
- package/src/editor-session-mode.ts +54 -0
- package/src/editor-shell-store.ts +1304 -0
- package/src/editor-state-facets.ts +74 -0
- package/src/editor-styles.css +33 -0
- package/src/editor-view-presentation.ts +810 -0
- package/src/editor-viewport.ts +5302 -0
- package/src/entity-lod.ts +31 -0
- package/src/entity-object.ts +91 -0
- package/src/files/file-provider.ts +62 -0
- package/src/files/project-files.ts +264 -0
- package/src/finders/index.ts +136 -0
- package/src/finders/scenes-from-entrypoint-selection.ts +387 -0
- package/src/frame/bridge.tsx +1408 -0
- package/src/frame/product.ts +77 -0
- package/src/gameplay-dom-recording.ts +319 -0
- package/src/gameplay-export-state.ts +14 -0
- package/src/gameplay-replay.ts +417 -0
- package/src/gameplay-session-time.ts +9 -0
- package/src/gameplay-sessions.ts +204 -0
- package/src/harness-chat-types.ts +253 -0
- package/src/hierarchy-component-marks.ts +298 -0
- package/src/hierarchy-drop.ts +91 -0
- package/src/hierarchy-expansion-state.ts +80 -0
- package/src/hierarchy-header-slot.ts +52 -0
- package/src/hierarchy-internals.ts +197 -0
- package/src/hierarchy-kind-icon.ts +217 -0
- package/src/hierarchy-mark-reader.ts +73 -0
- package/src/hierarchy-menu-registry.ts +67 -0
- package/src/hierarchy-node-rows.ts +307 -0
- package/src/hierarchy-panel-view.ts +280 -0
- package/src/hierarchy-projection.ts +76 -0
- package/src/hierarchy-row-cache.ts +243 -0
- package/src/hierarchy-row-model.ts +308 -0
- package/src/hierarchy-rows.ts +11 -0
- package/src/hierarchy-walk.ts +86 -0
- package/src/history/editor-session.ts +25 -0
- package/src/history/history-commands.ts +147 -0
- package/src/history/history-delegate.ts +163 -0
- package/src/history/history-limit-notices.ts +43 -0
- package/src/history/history-service.ts +1173 -0
- package/src/history/persistence-coordinator.ts +35 -0
- package/src/history/project-file-history.ts +386 -0
- package/src/history/project-root-history-backends.ts +139 -0
- package/src/history/resource-registry.ts +209 -0
- package/src/history/snapshot-store.ts +103 -0
- package/src/history/source-history-backend.ts +546 -0
- package/src/history/types.ts +124 -0
- package/src/hmr-registration-group.ts +67 -0
- package/src/hmr-stable-react-context.ts +23 -0
- package/src/hotkeys.ts +188 -0
- package/src/inference-diagnostics.ts +69 -0
- package/src/initial-project.ts +80 -0
- package/src/inspection/active-subject.ts +578 -0
- package/src/inspection/active-surface.ts +142 -0
- package/src/inspection/compose.ts +1064 -0
- package/src/inspection/display.ts +170 -0
- package/src/inspection/document-subject.ts +109 -0
- package/src/inspection/game-subject.ts +85 -0
- package/src/inspection/model.ts +542 -0
- package/src/inspection/null-subject.ts +115 -0
- package/src/inspection/serialize.ts +357 -0
- package/src/inspection/use-active-inspection.ts +180 -0
- package/src/inspector-presentation.ts +201 -0
- package/src/inspector-section-registry.ts +221 -0
- package/src/instance-source-actions.ts +163 -0
- package/src/instanced-presentation.ts +164 -0
- package/src/js-heap.ts +71 -0
- package/src/key-actions.ts +91 -0
- package/src/keymap-presets.ts +401 -0
- package/src/layout-policy.ts +31 -0
- package/src/learn-links.ts +73 -0
- package/src/light-explorer-model.ts +134 -0
- package/src/live-canvas-frame.ts +55 -0
- package/src/live-document.ts +279 -0
- package/src/live-module-source.ts +230 -0
- package/src/live-session-registry.ts +220 -0
- package/src/live-transition.ts +633 -0
- package/src/manifest-project.ts +107 -0
- package/src/model-thumbnail.ts +523 -0
- package/src/native-selection-style.ts +202 -0
- package/src/object3d-document-write-policy.ts +137 -0
- package/src/packaged-runtime.ts +108 -0
- package/src/palettes/maya.palette.json +57 -0
- package/src/palettes/substance.palette.json +57 -0
- package/src/pasteboard-module.ts +81 -0
- package/src/performance-profiler.ts +367 -0
- package/src/performance-sources.ts +69 -0
- package/src/play-boot-phase.ts +145 -0
- package/src/presentation-surface.ts +248 -0
- package/src/project-adapter.ts +1143 -0
- package/src/project-asset-refresh.ts +26 -0
- package/src/project-declaration-refresh.ts +31 -0
- package/src/project-local-state.ts +118 -0
- package/src/project-manager.ts +243 -0
- package/src/project-module-changes.ts +163 -0
- package/src/project-module-split.ts +266 -0
- package/src/project-provenance.ts +115 -0
- package/src/project-ready.ts +42 -0
- package/src/project-session-reset.ts +67 -0
- package/src/project-shape.ts +68 -0
- package/src/project-tool-discovery.ts +66 -0
- package/src/project-tools.ts +107 -0
- package/src/project-work-types.ts +149 -0
- package/src/projection/three.ts +898 -0
- package/src/projection/types.ts +44 -0
- package/src/readiness.ts +113 -0
- package/src/reflection-probe-helper.ts +142 -0
- package/src/reported-play-state.ts +90 -0
- package/src/resolve-relative-specifier.ts +33 -0
- package/src/scene-document-plan.ts +315 -0
- package/src/scene-framing.ts +315 -0
- package/src/scene-live-open.ts +210 -0
- package/src/scene-view-fog.ts +89 -0
- package/src/scoped-game-css.ts +152 -0
- package/src/session-orphan-record.ts +193 -0
- package/src/session-tombstone.ts +126 -0
- package/src/settings/settings-provider.ts +82 -0
- package/src/settings-store.ts +345 -0
- package/src/shared-view-restore.ts +42 -0
- package/src/shell-store-door.ts +45 -0
- package/src/source-conflict.ts +122 -0
- package/src/spatial-handle-visuals.ts +332 -0
- package/src/stage-context.ts +341 -0
- package/src/stage-store-registry.ts +63 -0
- package/src/stale-chunk-recovery.ts +34 -0
- package/src/state-report-deferral.ts +73 -0
- package/src/storage/host-files-storage.ts +97 -0
- package/src/storage/http-storage.ts +174 -0
- package/src/storage/index.ts +75 -0
- package/src/storage/mem-storage.ts +149 -0
- package/src/storage/path-lock.ts +44 -0
- package/src/storage/paths.ts +26 -0
- package/src/storage/types.ts +116 -0
- package/src/stories/StoryComponentThumbnail.tsx +184 -0
- package/src/stories/StoryPreviewMount.tsx +306 -0
- package/src/stories/component-content-source.tsx +106 -0
- package/src/stories/component-states-source.ts +78 -0
- package/src/stories/compose-project-stories.ts +255 -0
- package/src/stories/pixi-story-model.ts +30 -0
- package/src/stories/prefabs-finder.ts +54 -0
- package/src/stories/prefabs-from-stories.ts +182 -0
- package/src/stories/project-story-discovery.ts +78 -0
- package/src/stories/project-story-regions.ts +24 -0
- package/src/stories/story-actions.ts +54 -0
- package/src/stories/story-capture-command.ts +124 -0
- package/src/stories/story-capture.ts +584 -0
- package/src/stories/story-declared-medium.ts +126 -0
- package/src/stories/story-discovery.ts +176 -0
- package/src/stories/story-document-openers.ts +36 -0
- package/src/stories/story-dom-runtime.ts +78 -0
- package/src/stories/story-grouping.ts +111 -0
- package/src/stories/story-lane.ts +88 -0
- package/src/stories/story-mount-turn.ts +27 -0
- package/src/stories/story-opener.ts +260 -0
- package/src/stories/story-pixi-preview.ts +408 -0
- package/src/stories/story-presentation.ts +215 -0
- package/src/stories/story-registry.ts +517 -0
- package/src/stories/story-three-preview.ts +807 -0
- package/src/stories/three-story-model.ts +96 -0
- package/src/story-three-preview-runtime.ts +56 -0
- package/src/surface-keyboard.ts +112 -0
- package/src/surface-state.ts +124 -0
- package/src/tab-bootstrap.js +628 -0
- package/src/tab-census.ts +198 -0
- package/src/tab-lifecycle-client.ts +196 -0
- package/src/theme-library.ts +844 -0
- package/src/theme-preference.ts +378 -0
- package/src/theme.css +3437 -0
- package/src/three-viewport/bone-selection-highlight.ts +119 -0
- package/src/three-viewport/camera-fit.ts +41 -0
- package/src/three-viewport/interactive-renderer.ts +132 -0
- package/src/three-viewport/selection-brackets.ts +310 -0
- package/src/three-viewport/selection-outline.ts +183 -0
- package/src/three-viewport/skeleton-helper.ts +61 -0
- package/src/three-viewport/source-color.ts +167 -0
- package/src/three-viewport/studio-environment.ts +96 -0
- package/src/three-viewport-presentation.ts +23 -0
- package/src/tool-contribution-play.ts +74 -0
- package/src/tool-loader.ts +1798 -0
- package/src/transform-mode-request.ts +57 -0
- package/src/transient-hint.ts +78 -0
- package/src/trigger-volume-helper.ts +116 -0
- package/src/ui-source/adapter-region-includes.ts +241 -0
- package/src/ui-source/ensure-import.ts +132 -0
- package/src/ui-source/file-region-resolver.ts +302 -0
- package/src/ui-source/inspect.ts +775 -0
- package/src/ui-source/oid-transform.ts +1845 -0
- package/src/ui-source/plan-csf-story.ts +196 -0
- package/src/ui-source/plan-extract-component.ts +421 -0
- package/src/ui-source/plan-fork-component.ts +621 -0
- package/src/ui-source/plan-named-style.ts +95 -0
- package/src/ui-source/plan-source-edit.ts +353 -0
- package/src/ui-source/r3f-contract-resolver.ts +327 -0
- package/src/ui-source/r3f-diagnostic-index.ts +165 -0
- package/src/ui-source/r3f-environment-binding.ts +133 -0
- package/src/ui-source/r3f-joint-binding.ts +251 -0
- package/src/ui-source/r3f-lod-binding.ts +91 -0
- package/src/ui-source/r3f-particle-binding.ts +235 -0
- package/src/ui-source/r3f-physics-binding.ts +483 -0
- package/src/ui-source/r3f-project-contracts.ts +444 -0
- package/src/ui-source/relative-import-specifier.ts +34 -0
- package/src/ui-source/reparent-guard.ts +544 -0
- package/src/ui-source/source-edit-request.ts +97 -0
- package/src/ui-source/source-write-backend.ts +618 -0
- package/src/ui-source/syntactic-prop-specs.ts +296 -0
- package/src/ui-source/tier-source-write-backend.ts +279 -0
- package/src/ui-source/ts-ast.ts +171 -0
- package/src/ui-source/utility-class-support.ts +169 -0
- package/src/ui-source/write-component-default.ts +133 -0
- package/src/ui-source/writer.ts +1989 -0
- package/src/viewport-activation-timings.ts +840 -0
- package/src/viewport-authoring-policy.ts +186 -0
- package/src/viewport-controls-hint.ts +57 -0
- package/src/viewport-door.ts +237 -0
- package/src/viewport-shading-boundary.ts +12 -0
- package/src/vite-error-surface.ts +141 -0
- package/src/wait-until.ts +37 -0
- package/src/workspace-areas.ts +156 -0
- package/src/workspace-aux-commands.ts +11 -0
- package/src/workspace-available-documents.ts +127 -0
- package/src/workspace-core-utilities.ts +31 -0
- package/src/workspace-document-ids.ts +59 -0
- package/src/workspace-document-registry.ts +612 -0
- package/src/workspace-document-restore.ts +145 -0
- package/src/workspace-host-commands.ts +141 -0
- package/src/workspace-persistence-gate.ts +40 -0
- package/src/workspace-play-utilities.ts +44 -0
- package/src/workspace-presets.ts +425 -0
- package/src/workspace-regions.ts +294 -0
- package/src/workspace-state-persistence.ts +536 -0
- package/src/workspace-static-panels.ts +73 -0
- package/src/workspace-status-registry.ts +121 -0
- package/src/workspace-style.ts +239 -0
- package/src/workspace-utility-commands.ts +74 -0
- package/src/workspace-utility-registry.ts +263 -0
- package/src/workspace-viewport-rect.ts +97 -0
- package/src/world-adoption.ts +115 -0
- package/src/world-document-routing.ts +104 -0
- package/vite-plugin-creation-site-write.ts +184 -0
- package/vite-plugin-creation-site.ts +80 -0
- package/vite-plugin-game-static.ts +303 -0
- package/vite-plugin-module-doorways.ts +336 -0
- package/vite-plugin-product-contributions.ts +197 -0
- package/vite-plugin-project-game-static.ts +125 -0
- package/vite-plugin-project-jsx-js.ts +65 -0
- package/vite-plugin-project-root-absolute-assets.ts +359 -0
- package/vite-plugin-shared-react.ts +420 -0
- package/vite-plugin-shared-three.ts +203 -0
- package/vite-plugin-ui-oid.ts +2106 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace UTILITY registry (W0 — the shell-contract slice of §9 W0).
|
|
3
|
+
* Utilities are the TRANSIENT output/debug surfaces of §1.4/§5: Console,
|
|
4
|
+
* Problems, Build Output, Dev, and story-scoped addon results. They live in
|
|
5
|
+
* the on-demand bottom utility region — never substantial editors, which are
|
|
6
|
+
* documents (`workspace-document-registry.ts`).
|
|
7
|
+
*
|
|
8
|
+
* On-demand is about the TAB: a registration with no materialized tab has no
|
|
9
|
+
* presence at all. Once a tab EXISTS — pre-registered here, contributed by
|
|
10
|
+
* the open project, or introduced by background activity through
|
|
11
|
+
* `ensureWorkspaceUtility` — the region stays on screen COLLAPSED to its own
|
|
12
|
+
* tab strip, so the tab and its badge are discoverable while the body stays
|
|
13
|
+
* closed until the tab is clicked (the layout host owns that presentation).
|
|
14
|
+
*
|
|
15
|
+
* The layout host pre-registers default-visible tabs in a
|
|
16
|
+
* zero-footprint hidden host. Semantic commands and actionable failures reveal
|
|
17
|
+
* that host directly. Other registrations
|
|
18
|
+
* are created on demand (built-ins register via
|
|
19
|
+
* `components/core-utilities.tsx`; migration map).
|
|
20
|
+
*
|
|
21
|
+
* Registrations declare a `section` (`core` | `project`, default `core`) —
|
|
22
|
+
* the editor's own instruments versus the open game's plane. It is the OUTER
|
|
23
|
+
* sort key, so the drawer's tab strip renders the two as visually separated
|
|
24
|
+
* clusters (`utilitySectionBoundaryId` names the divider's position). It is
|
|
25
|
+
* presentation within the one bottom group; it is not a second dock.
|
|
26
|
+
*
|
|
27
|
+
* Idioms mirror `inspector-section-registry.ts`: module-scope state,
|
|
28
|
+
* `useSyncExternalStore`-shaped subscribe + monotonic version,
|
|
29
|
+
* `__resetForTest`, pure-logic headless tests (`Content` is never rendered
|
|
30
|
+
* here). Unlike that registry, utility ids KEY tabs (test ids, persisted
|
|
31
|
+
* drawer state), so duplicate registration is a programming error and
|
|
32
|
+
* throws.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import type { ComponentType } from 'react';
|
|
36
|
+
|
|
37
|
+
/** Attention badge a utility surfaces when its host is open; persistent
|
|
38
|
+
* signals such as Console errors are also projected into the status bar. */
|
|
39
|
+
export interface WorkspaceUtilityBadge {
|
|
40
|
+
readonly count: number;
|
|
41
|
+
readonly severity: 'info' | 'warn' | 'error';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Which audience a utility belongs to, and therefore which cluster of the
|
|
46
|
+
* drawer's tab strip it sits in.
|
|
47
|
+
*
|
|
48
|
+
* - `core` — the EDITOR's own instruments (Console, Animation, Profiler,
|
|
49
|
+
* Network, Audio…). Present in every project.
|
|
50
|
+
* - `project` — the GAME's own plane: one tab per `workspace.utility` tool
|
|
51
|
+
* contribution the open project ships (`tool-loader.ts` registers them
|
|
52
|
+
* under `tool:<contributionId>`). Which tabs exist depends entirely on the
|
|
53
|
+
* open game, so this cluster is empty for a project that contributes none.
|
|
54
|
+
*/
|
|
55
|
+
export type WorkspaceUtilitySection = 'core' | 'project';
|
|
56
|
+
|
|
57
|
+
const SECTION_RANK: Record<WorkspaceUtilitySection, number> = { core: 0, project: 1 };
|
|
58
|
+
|
|
59
|
+
/** The §7 utility contribution contract. */
|
|
60
|
+
export interface WorkspaceUtilityRegistration {
|
|
61
|
+
/** Stable id — keys the drawer tab (`data-testid`, persisted layout). */
|
|
62
|
+
readonly id: string;
|
|
63
|
+
/** Tab label (§8 naming: `Build Output`, not `Build`). */
|
|
64
|
+
readonly title: string;
|
|
65
|
+
/** Tab-strip cluster. Default `'core'` — a contribution that says nothing
|
|
66
|
+
* is one of the editor's own instruments. */
|
|
67
|
+
readonly section?: WorkspaceUtilitySection;
|
|
68
|
+
/** React content host. Never rendered by the registry itself. */
|
|
69
|
+
readonly Content: ComponentType;
|
|
70
|
+
/** Tab order among registered utilities (ascending; ties keep
|
|
71
|
+
* registration order). Default `0`. */
|
|
72
|
+
readonly order?: number;
|
|
73
|
+
/** Session-scoped availability — e.g. Network exists only while a live
|
|
74
|
+
* session exposes the owning adapter (§5 "play-only bottom utility").
|
|
75
|
+
* Default: always available. */
|
|
76
|
+
readonly available?: () => boolean;
|
|
77
|
+
/** Optional attention badge for the tab (may return `null` for none). */
|
|
78
|
+
readonly badge?: () => WorkspaceUtilityBadge | null;
|
|
79
|
+
/** Subscribe to the source read by `badge()`. Dynamic badges must provide
|
|
80
|
+
* this together with `badgeSnapshot` so a dock tab updates while its panel
|
|
81
|
+
* is collapsed. */
|
|
82
|
+
readonly subscribeBadge?: (listener: () => void) => () => void;
|
|
83
|
+
/** Stable `useSyncExternalStore` snapshot for `subscribeBadge`. */
|
|
84
|
+
readonly badgeSnapshot?: () => number;
|
|
85
|
+
/** Whether the tab is pre-registered in the clean layout's hidden utility
|
|
86
|
+
* host. Defaults to `true`; this does not make the host itself visible.
|
|
87
|
+
* Event/output surfaces can remain discoverable while creating their tab
|
|
88
|
+
* only after an explicit command or relevant activity. */
|
|
89
|
+
readonly visibleByDefault?: boolean;
|
|
90
|
+
/** Whether a revealed utility tab may be closed. Defaults to `false`. */
|
|
91
|
+
readonly closeable?: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// --- Module-scope state (mirrors inspector-section-registry.ts) -----------
|
|
95
|
+
|
|
96
|
+
interface StoredUtility {
|
|
97
|
+
readonly registration: WorkspaceUtilityRegistration;
|
|
98
|
+
readonly seq: number;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let _utilities: StoredUtility[] = [];
|
|
102
|
+
let _seq = 0;
|
|
103
|
+
let _version = 0;
|
|
104
|
+
const _listeners = new Set<() => void>();
|
|
105
|
+
|
|
106
|
+
function notifyChanged(): void {
|
|
107
|
+
_version++;
|
|
108
|
+
for (const fn of _listeners) fn();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Subscribe to (un)registrations. Returns an unsubscribe function. */
|
|
112
|
+
export function subscribeWorkspaceUtilities(fn: () => void): () => void {
|
|
113
|
+
_listeners.add(fn);
|
|
114
|
+
return () => {
|
|
115
|
+
_listeners.delete(fn);
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Monotonic change counter — the `getSnapshot` for `useSyncExternalStore`. */
|
|
120
|
+
export function workspaceUtilityRegistryVersion(): number {
|
|
121
|
+
return _version;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Register a utility contribution. Returns an unregister function.
|
|
126
|
+
* Throws on a duplicate id — utility ids key tabs and persisted layout, so
|
|
127
|
+
* two live registrations sharing one id is always a bug (re-registration
|
|
128
|
+
* flows, e.g. project-tool HMR, unregister first — tool-loader's own
|
|
129
|
+
* discipline).
|
|
130
|
+
*/
|
|
131
|
+
export function registerWorkspaceUtility(registration: WorkspaceUtilityRegistration): () => void {
|
|
132
|
+
if (_utilities.some((u) => u.registration.id === registration.id)) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`registerWorkspaceUtility: id "${registration.id}" is already registered — ` +
|
|
135
|
+
'utility ids key drawer tabs and persisted layout, so they must be unique; ' +
|
|
136
|
+
'unregister the previous contribution first.',
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const stored: StoredUtility = { registration, seq: _seq++ };
|
|
140
|
+
_utilities = [..._utilities, stored];
|
|
141
|
+
notifyChanged();
|
|
142
|
+
return () => {
|
|
143
|
+
if (!_utilities.includes(stored)) return;
|
|
144
|
+
_utilities = _utilities.filter((u) => u !== stored);
|
|
145
|
+
notifyChanged();
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** A registration's cluster, defaulting to the editor's own instruments. */
|
|
150
|
+
export function workspaceUtilitySection(
|
|
151
|
+
registration: WorkspaceUtilityRegistration,
|
|
152
|
+
): WorkspaceUtilitySection {
|
|
153
|
+
return registration.section ?? 'core';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function sorted(): WorkspaceUtilityRegistration[] {
|
|
157
|
+
return [..._utilities]
|
|
158
|
+
.sort(
|
|
159
|
+
(a, b) =>
|
|
160
|
+
// Section is the OUTER key: the two clusters never interleave, so the
|
|
161
|
+
// tab strip's divider is a single boundary rather than a repeated one.
|
|
162
|
+
SECTION_RANK[workspaceUtilitySection(a.registration)] -
|
|
163
|
+
SECTION_RANK[workspaceUtilitySection(b.registration)] ||
|
|
164
|
+
(a.registration.order ?? 0) - (b.registration.order ?? 0) ||
|
|
165
|
+
a.seq - b.seq,
|
|
166
|
+
)
|
|
167
|
+
.map((u) => u.registration);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The id of the tab the `project` cluster STARTS at, for a given rendered tab
|
|
172
|
+
* order — i.e. the first project-section utility that some core-section
|
|
173
|
+
* utility precedes. `null` when the order has no such boundary (one cluster
|
|
174
|
+
* only, or the project cluster leads). Pure: the caller passes the list it is
|
|
175
|
+
* actually rendering, which after a user tab-drag need not be registry order.
|
|
176
|
+
*/
|
|
177
|
+
export function utilitySectionBoundaryId(
|
|
178
|
+
utilities: readonly WorkspaceUtilityRegistration[],
|
|
179
|
+
): string | null {
|
|
180
|
+
let sawCore = false;
|
|
181
|
+
for (const utility of utilities) {
|
|
182
|
+
if (workspaceUtilitySection(utility) === 'core') {
|
|
183
|
+
sawCore = true;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (sawCore) return utility.id;
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Where a NEWLY ADDED utility tab belongs among the tabs already in the
|
|
193
|
+
* drawer, per registry order — the count of existing tabs that sort at or
|
|
194
|
+
* before it. Registrations arrive at different times (core utilities at
|
|
195
|
+
* module init, project-tool contributions after the async tool load), so
|
|
196
|
+
* appending would interleave the clusters by arrival order; inserting at
|
|
197
|
+
* this index makes any arrival order converge to registry order. Ids the
|
|
198
|
+
* registry no longer knows (a stale persisted tab) sort AFTER every known
|
|
199
|
+
* one, and an unknown `id` appends. Pure: the caller passes the tab ids it
|
|
200
|
+
* is actually hosting, which after a user drag need not be registry order —
|
|
201
|
+
* rank-counting still yields a stable, in-bounds index there.
|
|
202
|
+
*/
|
|
203
|
+
export function utilityInsertionIndex(
|
|
204
|
+
existingIds: readonly string[],
|
|
205
|
+
id: string,
|
|
206
|
+
): number | undefined {
|
|
207
|
+
const rank = new Map(availableWorkspaceUtilities().map((utility, index) => [utility.id, index]));
|
|
208
|
+
const target = rank.get(id);
|
|
209
|
+
if (target === undefined) return undefined;
|
|
210
|
+
let index = 0;
|
|
211
|
+
for (const existing of existingIds) {
|
|
212
|
+
const existingRank = rank.get(existing);
|
|
213
|
+
if (existingRank !== undefined && existingRank <= target) index += 1;
|
|
214
|
+
}
|
|
215
|
+
return index;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Every registered utility, in (order, registration-sequence) order. */
|
|
219
|
+
export function registeredWorkspaceUtilities(): WorkspaceUtilityRegistration[] {
|
|
220
|
+
return sorted();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** The registered utilities whose `available()` currently returns true
|
|
224
|
+
* (guarded: a THROWING `available` counts as unavailable — a broken
|
|
225
|
+
* contribution must not take the drawer down; same failure physics as
|
|
226
|
+
* tool-loader's match guard). */
|
|
227
|
+
export function availableWorkspaceUtilities(): WorkspaceUtilityRegistration[] {
|
|
228
|
+
return sorted().filter((u) => {
|
|
229
|
+
if (!u.available) return true;
|
|
230
|
+
try {
|
|
231
|
+
return u.available();
|
|
232
|
+
} catch {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Order-preserving fingerprint of the available utility ids — a stable
|
|
239
|
+
* STRING, so `useAvailabilitySelector` consumers (the dock's reconciler)
|
|
240
|
+
* re-render only when the available SET changes, not on every 250ms tick. */
|
|
241
|
+
export function availableUtilityFingerprint(): string {
|
|
242
|
+
return availableWorkspaceUtilities()
|
|
243
|
+
.map((u) => u.id)
|
|
244
|
+
.join('\n');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** A utility's current badge (guarded: a throwing `badge` yields `null`). */
|
|
248
|
+
export function workspaceUtilityBadge(id: string): WorkspaceUtilityBadge | null {
|
|
249
|
+
const found = _utilities.find((u) => u.registration.id === id);
|
|
250
|
+
if (!found?.registration.badge) return null;
|
|
251
|
+
try {
|
|
252
|
+
return found.registration.badge();
|
|
253
|
+
} catch {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** Test-only reset (mirrors `__resetInspectorSectionRegistryForTest`). */
|
|
259
|
+
export function __resetWorkspaceUtilityRegistryForTest(): void {
|
|
260
|
+
_utilities = [];
|
|
261
|
+
_seq = 0;
|
|
262
|
+
notifyChanged();
|
|
263
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CENTER (viewport) group's live rect in dock-root-local coordinates.
|
|
3
|
+
* The workspace host is the sole writer because the frame owns this geometry —
|
|
4
|
+
* Consumers are
|
|
5
|
+
* overlays that belong to the VIEWPORT rather than the whole workspace
|
|
6
|
+
* (the compact inspector card clamps itself inside this rect), without
|
|
7
|
+
* measuring the layout themselves.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export interface WorkspaceViewportRect {
|
|
11
|
+
readonly x: number;
|
|
12
|
+
readonly y: number;
|
|
13
|
+
readonly width: number;
|
|
14
|
+
readonly height: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let rect: WorkspaceViewportRect | null = null;
|
|
18
|
+
let version = 0;
|
|
19
|
+
const listeners = new Set<() => void>();
|
|
20
|
+
|
|
21
|
+
export function workspaceViewportRect(): WorkspaceViewportRect | null {
|
|
22
|
+
return rect;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function workspaceViewportRectVersion(): number {
|
|
26
|
+
return version;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function subscribeWorkspaceViewportRect(listener: () => void): () => void {
|
|
30
|
+
listeners.add(listener);
|
|
31
|
+
return () => listeners.delete(listener);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function setWorkspaceViewportRect(next: WorkspaceViewportRect | null): void {
|
|
35
|
+
const same =
|
|
36
|
+
rect === next ||
|
|
37
|
+
(rect !== null &&
|
|
38
|
+
next !== null &&
|
|
39
|
+
rect.x === next.x &&
|
|
40
|
+
rect.y === next.y &&
|
|
41
|
+
rect.width === next.width &&
|
|
42
|
+
rect.height === next.height);
|
|
43
|
+
if (same) return;
|
|
44
|
+
rect = next;
|
|
45
|
+
version += 1;
|
|
46
|
+
for (const listener of listeners) listener();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ---- Viewport-owned overlay placement (pure — headlessly testable) --------
|
|
50
|
+
|
|
51
|
+
/** Offsets of an overlay's bottom-right corner from the VIEWPORT's
|
|
52
|
+
* bottom-right corner. Bottom-right anchoring keeps a corner-hugging
|
|
53
|
+
* overlay hugging its corner under viewport resizes, wherever it was
|
|
54
|
+
* dragged. */
|
|
55
|
+
export interface ViewportOverlayAnchor {
|
|
56
|
+
readonly right: number;
|
|
57
|
+
readonly bottom: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ViewportOverlaySizing {
|
|
61
|
+
readonly maxWidth: number;
|
|
62
|
+
readonly maxHeight: number;
|
|
63
|
+
/** Floor when the viewport is too small for the full size. */
|
|
64
|
+
readonly minSize: number;
|
|
65
|
+
/** Breathing room kept between the overlay and every viewport edge. */
|
|
66
|
+
readonly margin: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** The overlay's size and top-left for a given anchor, clamped fully inside
|
|
70
|
+
* the viewport (pinned toward the top-left edge when the viewport is
|
|
71
|
+
* smaller than the overlay + margins). */
|
|
72
|
+
export function resolveViewportOverlayPlacement(
|
|
73
|
+
viewport: WorkspaceViewportRect,
|
|
74
|
+
sizing: ViewportOverlaySizing,
|
|
75
|
+
anchor: ViewportOverlayAnchor,
|
|
76
|
+
): { left: number; top: number; width: number; height: number } {
|
|
77
|
+
const width = Math.min(
|
|
78
|
+
sizing.maxWidth,
|
|
79
|
+
Math.max(sizing.minSize, viewport.width - sizing.margin * 2),
|
|
80
|
+
);
|
|
81
|
+
const height = Math.min(
|
|
82
|
+
sizing.maxHeight,
|
|
83
|
+
Math.max(sizing.minSize, viewport.height - sizing.margin * 2),
|
|
84
|
+
);
|
|
85
|
+
const minLeft = viewport.x + sizing.margin;
|
|
86
|
+
const maxLeft = viewport.x + viewport.width - width - sizing.margin;
|
|
87
|
+
const minTop = viewport.y + sizing.margin;
|
|
88
|
+
const maxTop = viewport.y + viewport.height - height - sizing.margin;
|
|
89
|
+
const left = viewport.x + viewport.width - anchor.right - width;
|
|
90
|
+
const top = viewport.y + viewport.height - anchor.bottom - height;
|
|
91
|
+
return {
|
|
92
|
+
width,
|
|
93
|
+
height,
|
|
94
|
+
left: Math.min(Math.max(left, minLeft), Math.max(maxLeft, minLeft)),
|
|
95
|
+
top: Math.min(Math.max(top, minTop), Math.max(maxTop, minTop)),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WORLD-ADOPTION AMBIGUITY — the reader for what the capture trap decided, and
|
|
3
|
+
* for every world it saw afterwards and did not adopt.
|
|
4
|
+
*
|
|
5
|
+
* `@volter/editor-threejs/adapter/ingest/scene-capture` adopts a self-booting game's world on
|
|
6
|
+
* the first non-host render. That is a sound MEASURED default and a permanent,
|
|
7
|
+
* silent commitment: a splash scene, a shadow pre-pass or a render-to-texture
|
|
8
|
+
* warm-up that happens to draw first is adopted as the game forever, and the
|
|
9
|
+
* real world drawing one frame later reached nobody.
|
|
10
|
+
*
|
|
11
|
+
* This module does not change the decision (ARCHITECTURE-CORE §The editor
|
|
12
|
+
* protocol: a diagnostic diagnoses; it does not silently re-pick). It records
|
|
13
|
+
* the adoption's PROVENANCE — `declared` when the game's contract named the
|
|
14
|
+
* scene, `measured` when first-render-wins ran — and every distinct
|
|
15
|
+
* (scene, camera) pair seen after it, and publishes both as the `worldAdoption`
|
|
16
|
+
* facet of `/__editor/state`.
|
|
17
|
+
*
|
|
18
|
+
* Alternates are INFORMATION, not an error: a post-processing chain renders
|
|
19
|
+
* several pairs per frame by design. The facet says how many and which, and the
|
|
20
|
+
* `ambiguity` sentence exists so a reader chasing "the editor is showing the
|
|
21
|
+
* wrong scene" has one place that already knows there was a choice.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import type { WorldAdoptionEvent } from '@volter/editor-threejs/adapter/ingest/scene-capture';
|
|
25
|
+
|
|
26
|
+
export interface WorldAdoptionAlternate {
|
|
27
|
+
readonly sceneId: string;
|
|
28
|
+
readonly cameraId: string;
|
|
29
|
+
/** `false` ⇒ a SECOND renderer is drawing — the stronger signal that the
|
|
30
|
+
* adopted world may not be the one on screen. */
|
|
31
|
+
readonly sameRenderer: boolean;
|
|
32
|
+
readonly drawCount: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface WorldAdoption {
|
|
36
|
+
readonly rootId: string;
|
|
37
|
+
/** `declared` = the game's contract named this scene; `measured` = the trap's
|
|
38
|
+
* first-non-host-render default decided. */
|
|
39
|
+
readonly source: 'declared' | 'measured';
|
|
40
|
+
readonly sceneId: string;
|
|
41
|
+
readonly cameraId: string;
|
|
42
|
+
/** Distinct worlds seen AFTER the adopted one, capped by the trap's own
|
|
43
|
+
* `MAX_RECORDED_ALTERNATES`. */
|
|
44
|
+
readonly alternates: readonly WorldAdoptionAlternate[];
|
|
45
|
+
/** Present iff `alternates` is non-empty — the one sentence, spelled once. */
|
|
46
|
+
readonly ambiguity?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** RESOURCE OWNERSHIP: one entry per self-booting root, written through
|
|
50
|
+
* {@link worldAdoptionRecorder} by the mount that installed the capture trap,
|
|
51
|
+
* and dropped by that mount's teardown ({@link clearWorldAdoption}). */
|
|
52
|
+
const _adoptions = new Map<
|
|
53
|
+
string,
|
|
54
|
+
{
|
|
55
|
+
source: 'declared' | 'measured';
|
|
56
|
+
sceneId: string;
|
|
57
|
+
cameraId: string;
|
|
58
|
+
alternates: WorldAdoptionAlternate[];
|
|
59
|
+
}
|
|
60
|
+
>();
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The `onWorldAdoption` handler a mount hands to `installSceneCapture`, bound
|
|
64
|
+
* to one root id. One door: the mount passes this straight through, so nothing
|
|
65
|
+
* in the editor transcribes the engine's event shape a second time.
|
|
66
|
+
*/
|
|
67
|
+
export function worldAdoptionRecorder(rootId: string): (event: WorldAdoptionEvent) => void {
|
|
68
|
+
return (event) => {
|
|
69
|
+
if (event.phase === 'adopted') {
|
|
70
|
+
_adoptions.set(rootId, {
|
|
71
|
+
source: event.source,
|
|
72
|
+
sceneId: event.sceneId,
|
|
73
|
+
cameraId: event.cameraId,
|
|
74
|
+
alternates: [],
|
|
75
|
+
});
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
// An alternate before an adoption cannot happen (the trap only reports one
|
|
79
|
+
// after it has committed), so a missing entry here means this root's
|
|
80
|
+
// adoption was already torn down — drop it rather than resurrect the root.
|
|
81
|
+
const entry = _adoptions.get(rootId);
|
|
82
|
+
if (!entry) return;
|
|
83
|
+
entry.alternates.push({
|
|
84
|
+
sceneId: event.sceneId,
|
|
85
|
+
cameraId: event.cameraId,
|
|
86
|
+
sameRenderer: event.sameRenderer,
|
|
87
|
+
drawCount: event.drawCount,
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function clearWorldAdoption(rootId: string): void {
|
|
93
|
+
_adoptions.delete(rootId);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function worldAdoptionFacet(): readonly WorldAdoption[] {
|
|
97
|
+
return [..._adoptions].map(([rootId, entry]) => ({
|
|
98
|
+
rootId,
|
|
99
|
+
source: entry.source,
|
|
100
|
+
sceneId: entry.sceneId,
|
|
101
|
+
cameraId: entry.cameraId,
|
|
102
|
+
alternates: [...entry.alternates],
|
|
103
|
+
...(entry.alternates.length > 0
|
|
104
|
+
? {
|
|
105
|
+
ambiguity:
|
|
106
|
+
`"${rootId}" rendered ${entry.alternates.length} other world(s) after the one the ` +
|
|
107
|
+
`editor adopted (${entry.source}: ${entry.sceneId}). The adopted world is unchanged; ` +
|
|
108
|
+
'if the editor is showing the wrong scene, one of these is it: ' +
|
|
109
|
+
entry.alternates
|
|
110
|
+
.map((alt) => `${alt.sceneId}${alt.sameRenderer ? '' : ' (a SECOND renderer)'}`)
|
|
111
|
+
.join(', '),
|
|
112
|
+
}
|
|
113
|
+
: {}),
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import {
|
|
2
|
+
availableWorkspaceDocuments,
|
|
3
|
+
openAvailableWorkspaceDocument,
|
|
4
|
+
} from './workspace-available-documents';
|
|
5
|
+
import { activateWorkspaceDocument } from './workspace-document-registry';
|
|
6
|
+
|
|
7
|
+
const _documentIdByRoot = new Map<string, string>();
|
|
8
|
+
|
|
9
|
+
export function registerRootDocumentRoute(worldId: string, documentId: string): () => void {
|
|
10
|
+
_documentIdByRoot.set(worldId, documentId);
|
|
11
|
+
return () => {
|
|
12
|
+
if (_documentIdByRoot.get(worldId) === documentId) _documentIdByRoot.delete(worldId);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** The edit-time document that owns a manifest world, or `null` when the
|
|
17
|
+
* session installed none. Read by the Edit tab row, whose `root-mount` scene
|
|
18
|
+
* entries NAME a standing document rather than adding one
|
|
19
|
+
* (`components/scene-documents.tsx`). */
|
|
20
|
+
export function rootDocumentId(worldId: string): string | null {
|
|
21
|
+
return (
|
|
22
|
+
_documentIdByRoot.get(worldId) ??
|
|
23
|
+
availableWorkspaceDocuments().find((document) => document.rootId === worldId)?.descriptor.id ??
|
|
24
|
+
null
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Activate the edit-time document that owns a manifest world. */
|
|
29
|
+
export function activateRootDocument(worldId: string): boolean {
|
|
30
|
+
const documentId = rootDocumentId(worldId);
|
|
31
|
+
return documentId
|
|
32
|
+
? openAvailableWorkspaceDocument(documentId) || activateWorkspaceDocument(documentId)
|
|
33
|
+
: false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const _gapByRoot = new Map<string, () => string | null>();
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Register the reason a root has NO document to activate — the DECIDED half of
|
|
40
|
+
* {@link activateRootDocument}'s `false`.
|
|
41
|
+
*
|
|
42
|
+
* A root's document is installed asynchronously, so `false` from
|
|
43
|
+
* `activateRootDocument` means one of two opposite things: "not yet" (boot in
|
|
44
|
+
* flight) or "never" (this session has settled that this root has no design
|
|
45
|
+
* surface of its own). Callers cannot tell them apart, so every caller waits
|
|
46
|
+
* out the full registration window even for an answer that was decided in the
|
|
47
|
+
* first second — long enough that the asking side has usually given up before
|
|
48
|
+
* the refusal is spoken.
|
|
49
|
+
*
|
|
50
|
+
* The `reason` is a THUNK, evaluated live at each ask, precisely so it can keep
|
|
51
|
+
* answering `null` while the document may still arrive and only speak once the
|
|
52
|
+
* question is settled. It is registered by whoever OWNS the decision — the
|
|
53
|
+
* presenter must never infer why a document is absent.
|
|
54
|
+
*/
|
|
55
|
+
export function registerRootDocumentGap(worldId: string, reason: () => string | null): () => void {
|
|
56
|
+
_gapByRoot.set(worldId, reason);
|
|
57
|
+
return () => {
|
|
58
|
+
if (_gapByRoot.get(worldId) === reason) _gapByRoot.delete(worldId);
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Why this root has no document to activate, when that is decided; `null`
|
|
63
|
+
* while one may still arrive. */
|
|
64
|
+
export function rootDocumentGap(worldId: string): string | null {
|
|
65
|
+
return _gapByRoot.get(worldId)?.() ?? null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const _workspaceGaps = new Set<(documentId: string) => string | null>();
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The same DECIDED half, for a workspace document asked for by id.
|
|
72
|
+
*
|
|
73
|
+
* `activateWorkspaceDocument` returns `false` with the identical ambiguity
|
|
74
|
+
* {@link registerRootDocumentGap} describes — "not yet" and "never" are one
|
|
75
|
+
* answer — and a workspace document has the further case a root cannot have:
|
|
76
|
+
* the id may name nothing at all. Both are the same question ("why is this
|
|
77
|
+
* document not here?"), so they share this mechanism rather than growing a
|
|
78
|
+
* second one; the arms differ only in their KEY, because a root is asked for
|
|
79
|
+
* by manifest id and a workspace document by document id.
|
|
80
|
+
*
|
|
81
|
+
* The resolver takes the requested id rather than being registered per id,
|
|
82
|
+
* because the ids that will never exist cannot be enumerated in advance — the
|
|
83
|
+
* owner answers for the whole namespace it installs into. Same thunk contract:
|
|
84
|
+
* `null` means "no verdict" (boot in flight, or not this owner's question),
|
|
85
|
+
* and the first owner to speak wins.
|
|
86
|
+
*/
|
|
87
|
+
export function registerWorkspaceDocumentGap(
|
|
88
|
+
reason: (documentId: string) => string | null,
|
|
89
|
+
): () => void {
|
|
90
|
+
_workspaceGaps.add(reason);
|
|
91
|
+
return () => {
|
|
92
|
+
_workspaceGaps.delete(reason);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Why this workspace document is not here, when that is decided; `null` while
|
|
97
|
+
* one may still arrive. */
|
|
98
|
+
export function workspaceDocumentGap(documentId: string): string | null {
|
|
99
|
+
for (const reason of _workspaceGaps) {
|
|
100
|
+
const answer = reason(documentId);
|
|
101
|
+
if (answer !== null) return answer;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|