@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,262 @@
|
|
|
1
|
+
import type { ShareRole } from '../share';
|
|
2
|
+
|
|
3
|
+
export type CollaborationCapability =
|
|
4
|
+
| 'view'
|
|
5
|
+
| 'comment'
|
|
6
|
+
| 'test'
|
|
7
|
+
| 'edit'
|
|
8
|
+
| 'terminal'
|
|
9
|
+
| 'maintain';
|
|
10
|
+
/**
|
|
11
|
+
* A collaboration role is a {@link ShareRole} PLUS the local-only `maintainer`,
|
|
12
|
+
* and it is spelled that way so the relationship is CHECKED. Written as its own
|
|
13
|
+
* six-member union — which is what it was — the two lists drift with no
|
|
14
|
+
* compiler signal: a role added to the share wire is simply a role this session
|
|
15
|
+
* cannot hold, and the only symptom is a participant the UI refuses to promote.
|
|
16
|
+
*/
|
|
17
|
+
export type CollaborationRole = ShareRole | 'maintainer';
|
|
18
|
+
/**
|
|
19
|
+
* Least authority first; `maintainer` is local-only and has no share role.
|
|
20
|
+
*
|
|
21
|
+
* Declared as a `satisfies Record<CollaborationRole, …>` rather than an array
|
|
22
|
+
* annotated `readonly CollaborationRole[]`, because the array form accepts an
|
|
23
|
+
* INCOMPLETE list: adding a role to `CollaborationRole` and forgetting it here
|
|
24
|
+
* compiles, and the only symptom is that `assignableCollaborationRoles` quietly
|
|
25
|
+
* offers a participant one fewer role than they can hold. A missing key here is
|
|
26
|
+
* a compile error.
|
|
27
|
+
*/
|
|
28
|
+
const COLLABORATION_ROLE_RANK = {
|
|
29
|
+
viewer: 0,
|
|
30
|
+
commenter: 1,
|
|
31
|
+
tester: 2,
|
|
32
|
+
editor: 3,
|
|
33
|
+
terminal: 4,
|
|
34
|
+
maintainer: 5,
|
|
35
|
+
} as const satisfies Record<CollaborationRole, number>;
|
|
36
|
+
|
|
37
|
+
export const COLLABORATION_ROLE_ORDER: readonly CollaborationRole[] = (
|
|
38
|
+
Object.keys(COLLABORATION_ROLE_RANK) as CollaborationRole[]
|
|
39
|
+
).sort((a, b) => COLLABORATION_ROLE_RANK[a] - COLLABORATION_ROLE_RANK[b]);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Which roles a UI may OFFER for one participant. Enforcement is the server's,
|
|
43
|
+
* always; this only keeps the editor from presenting an option the session
|
|
44
|
+
* would refuse. A participant that entered through the share gateway carries a
|
|
45
|
+
* verified `account` and can never reach `maintainer`, nor exceed the ceiling
|
|
46
|
+
* its invitation set.
|
|
47
|
+
*/
|
|
48
|
+
export function assignableCollaborationRoles(
|
|
49
|
+
participant: { account: { id: string } | null },
|
|
50
|
+
ceiling?: CollaborationRole,
|
|
51
|
+
): CollaborationRole[] {
|
|
52
|
+
if (!participant.account) return [...COLLABORATION_ROLE_ORDER];
|
|
53
|
+
const remoteLimit = COLLABORATION_ROLE_ORDER.indexOf('terminal');
|
|
54
|
+
const ceilingIndex = ceiling ? COLLABORATION_ROLE_ORDER.indexOf(ceiling) : remoteLimit;
|
|
55
|
+
const limit = Math.min(remoteLimit, ceilingIndex < 0 ? remoteLimit : ceilingIndex);
|
|
56
|
+
return COLLABORATION_ROLE_ORDER.slice(0, limit + 1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type ParticipantKind = 'human' | 'agent';
|
|
60
|
+
export type ParticipantStatus = 'active' | 'idle' | 'needs-input' | 'done';
|
|
61
|
+
|
|
62
|
+
export interface CollaborationParticipantLocation {
|
|
63
|
+
repositoryId: string;
|
|
64
|
+
worktreeId: string;
|
|
65
|
+
sessionId: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface CollaborationAgentIdentity {
|
|
69
|
+
harness: string;
|
|
70
|
+
conversationId: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface CollaborationCameraPose {
|
|
74
|
+
x: number;
|
|
75
|
+
y: number;
|
|
76
|
+
z: number;
|
|
77
|
+
targetX: number;
|
|
78
|
+
targetY: number;
|
|
79
|
+
targetZ: number;
|
|
80
|
+
fov: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function isCollaborationCameraPose(value: unknown): value is CollaborationCameraPose {
|
|
84
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
85
|
+
const camera = value as Record<string, unknown>;
|
|
86
|
+
const keys = ['x', 'y', 'z', 'targetX', 'targetY', 'targetZ', 'fov'] as const;
|
|
87
|
+
return (
|
|
88
|
+
Object.keys(camera).length === keys.length &&
|
|
89
|
+
keys.every((key) => typeof camera[key] === 'number' && Number.isFinite(camera[key])) &&
|
|
90
|
+
(camera['fov'] as number) > 0 &&
|
|
91
|
+
(camera['fov'] as number) < 180
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* THE owner of team-message size limits, read by the HTTP route guard and by
|
|
97
|
+
* `CollaborationSession`'s own methods alike.
|
|
98
|
+
*
|
|
99
|
+
* The two used to carry separate numbers and disagree in both directions — the
|
|
100
|
+
* route accepted 20k of text the session then refused, and refused 50
|
|
101
|
+
* references the session would have taken — so which error a caller saw
|
|
102
|
+
* depended on which layer happened to see the message first. Each value here is
|
|
103
|
+
* the tighter of the pair that split produced.
|
|
104
|
+
*/
|
|
105
|
+
export const TEAM_MESSAGE_LIMITS = {
|
|
106
|
+
text: 10_000,
|
|
107
|
+
mentions: 16,
|
|
108
|
+
mentionLength: 80,
|
|
109
|
+
references: 32,
|
|
110
|
+
} as const;
|
|
111
|
+
|
|
112
|
+
export const COLLABORATION_AGENT_MENTIONS = ['agent', 'claude', 'codex'] as const;
|
|
113
|
+
|
|
114
|
+
export function isCollaborationAgentMention(value: string): boolean {
|
|
115
|
+
return (COLLABORATION_AGENT_MENTIONS as readonly string[]).includes(value.toLowerCase());
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface CollaborationPresence {
|
|
119
|
+
document: string | null;
|
|
120
|
+
file: string | null;
|
|
121
|
+
oid: string | null;
|
|
122
|
+
selection: readonly string[];
|
|
123
|
+
camera: Readonly<CollaborationCameraPose> | null;
|
|
124
|
+
gesture: Readonly<Record<string, unknown>> | null;
|
|
125
|
+
playtest?: {
|
|
126
|
+
id: string;
|
|
127
|
+
play: 'starting' | 'ready' | 'error';
|
|
128
|
+
networking: 'not-declared' | 'connecting' | 'ready' | 'error';
|
|
129
|
+
roomName: string | null;
|
|
130
|
+
problem: string | null;
|
|
131
|
+
} | null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface CollaborationParticipant {
|
|
135
|
+
participantId: string;
|
|
136
|
+
/** Verified Volter account authority. Null only for local-only host/agent
|
|
137
|
+
* participants that did not enter through a public share gateway. */
|
|
138
|
+
account: { id: string; email: string; name?: string } | null;
|
|
139
|
+
displayName: string;
|
|
140
|
+
kind: ParticipantKind;
|
|
141
|
+
color: string;
|
|
142
|
+
status: ParticipantStatus;
|
|
143
|
+
location: CollaborationParticipantLocation | null;
|
|
144
|
+
agent: CollaborationAgentIdentity | null;
|
|
145
|
+
role: CollaborationRole;
|
|
146
|
+
capabilities: readonly CollaborationCapability[];
|
|
147
|
+
connectedAt: string;
|
|
148
|
+
lastSeenAt: string;
|
|
149
|
+
presence: CollaborationPresence;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface CollaborationAuthorProjection {
|
|
153
|
+
participantId: string;
|
|
154
|
+
account: { id: string; email: string; name?: string } | null;
|
|
155
|
+
displayName: string;
|
|
156
|
+
kind: ParticipantKind;
|
|
157
|
+
color: string;
|
|
158
|
+
location: CollaborationParticipantLocation | null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const PARTICIPANT_COLORS = [
|
|
162
|
+
'#4f8cff',
|
|
163
|
+
'#e45c9d',
|
|
164
|
+
'#20a87a',
|
|
165
|
+
'#a46de8',
|
|
166
|
+
'#d9782d',
|
|
167
|
+
'#2f9eb8',
|
|
168
|
+
'#ca4f55',
|
|
169
|
+
'#6f9f32',
|
|
170
|
+
] as const;
|
|
171
|
+
|
|
172
|
+
export function collaborationParticipantColor(identity: string): string {
|
|
173
|
+
let hash = 2_166_136_261;
|
|
174
|
+
for (const codePoint of identity) {
|
|
175
|
+
hash ^= codePoint.codePointAt(0) ?? 0;
|
|
176
|
+
hash = Math.imul(hash, 16_777_619);
|
|
177
|
+
}
|
|
178
|
+
return PARTICIPANT_COLORS[(hash >>> 0) % PARTICIPANT_COLORS.length]!;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export type TeamMessageReference =
|
|
182
|
+
| { type: 'worktree'; worktreeId: string }
|
|
183
|
+
| { type: 'revision'; revision: number }
|
|
184
|
+
| { type: 'file'; path: string; revision: number }
|
|
185
|
+
| { type: 'oid'; oid: string; revision: number }
|
|
186
|
+
| { type: 'asset'; path: string; revision: number }
|
|
187
|
+
| { type: 'screenshot'; id: string; revision: number }
|
|
188
|
+
| { type: 'playtest'; id: string; revision: number }
|
|
189
|
+
| { type: 'diff'; fromRevision: number; toRevision: number };
|
|
190
|
+
|
|
191
|
+
export interface TeamMessage {
|
|
192
|
+
id: string;
|
|
193
|
+
authorId: string;
|
|
194
|
+
author: CollaborationAuthorProjection;
|
|
195
|
+
text: string;
|
|
196
|
+
mentions: readonly string[];
|
|
197
|
+
references: readonly TeamMessageReference[];
|
|
198
|
+
threadId: string | null;
|
|
199
|
+
editedAt: string | null;
|
|
200
|
+
deletedAt: string | null;
|
|
201
|
+
reactions: Readonly<Record<string, readonly string[]>>;
|
|
202
|
+
revision: number;
|
|
203
|
+
createdAt: string;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface SourceRevision {
|
|
207
|
+
revision: number;
|
|
208
|
+
authorId: string;
|
|
209
|
+
author: CollaborationAuthorProjection;
|
|
210
|
+
source: 'editor' | 'filesystem';
|
|
211
|
+
resources: readonly { path: string; sha: string | null }[];
|
|
212
|
+
createdAt: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export interface CollaborationAuditEvent {
|
|
216
|
+
id: string;
|
|
217
|
+
type: 'join' | 'leave' | 'role' | 'revision' | 'message' | 'agent' | 'playtest' | 'git';
|
|
218
|
+
participantId: string;
|
|
219
|
+
createdAt: string;
|
|
220
|
+
detail: Readonly<Record<string, unknown>>;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export interface TeamPlaytest {
|
|
224
|
+
id: string;
|
|
225
|
+
revision: number;
|
|
226
|
+
seed: number;
|
|
227
|
+
roomKey: string;
|
|
228
|
+
startedBy: string;
|
|
229
|
+
startedAt: string;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export interface CollaborationSnapshot {
|
|
233
|
+
sequence: number;
|
|
234
|
+
revision: number;
|
|
235
|
+
activePlaytest: TeamPlaytest | null;
|
|
236
|
+
participants: readonly CollaborationParticipant[];
|
|
237
|
+
messages: readonly TeamMessage[];
|
|
238
|
+
revisions: readonly SourceRevision[];
|
|
239
|
+
audit: readonly CollaborationAuditEvent[];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export type CollaborationEventChannel =
|
|
243
|
+
| 'participants'
|
|
244
|
+
| 'presence'
|
|
245
|
+
| 'messages'
|
|
246
|
+
| 'revisions'
|
|
247
|
+
| 'audit'
|
|
248
|
+
| 'team-test';
|
|
249
|
+
|
|
250
|
+
export interface CollaborationEvent {
|
|
251
|
+
sequence: number;
|
|
252
|
+
channel: CollaborationEventChannel;
|
|
253
|
+
createdAt: string;
|
|
254
|
+
payload: unknown;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export interface CollaborationResume {
|
|
258
|
+
cursor: number;
|
|
259
|
+
reset: boolean;
|
|
260
|
+
events: readonly CollaborationEvent[];
|
|
261
|
+
snapshot?: CollaborationSnapshot;
|
|
262
|
+
}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { MAX_DOCUMENT_KEY_HOLD_MS } from '../document-probe';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* THE RELAY COMMAND VOCABULARY, in one typed table.
|
|
5
|
+
*
|
|
6
|
+
* A relay command's type string used to be answered by two independent
|
|
7
|
+
* switches that had to agree and were never checked against each other:
|
|
8
|
+
* `command-listener.ts`'s dispatch (what the command DOES) and
|
|
9
|
+
* `server/server-utils.ts`'s `relayCommandTimeoutMs` (how long the server
|
|
10
|
+
* waits for it). A command missing from the second one did not fail — it
|
|
11
|
+
* silently took the generic 5s default, which undercut a client's 60s hold, so
|
|
12
|
+
* the uninformative timer won every race and sent a real investigation looking
|
|
13
|
+
* for a dead editor.
|
|
14
|
+
*
|
|
15
|
+
* This table is the single source. Adding a command means adding a ROW here:
|
|
16
|
+
* the dispatch switch keys off `RelayCommandType`, so a case with no row does
|
|
17
|
+
* not compile, and a row with no case fails the exhaustiveness check in that
|
|
18
|
+
* switch's `default`. The server imports the timeout column rather than
|
|
19
|
+
* restating it.
|
|
20
|
+
*
|
|
21
|
+
* `timeoutMs` is the budget for the WORK. Delivery has its own, much shorter
|
|
22
|
+
* budget (`RELAY_DELIVERY_ACK_MS`, clamped by `RELAY_DELIVERY_MAX_WAIT_MS`) —
|
|
23
|
+
* see `server/server-utils.ts`, which explains why the two are separate.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The generic budget. Most commands are a synchronous edit against the live
|
|
28
|
+
* editor and answer in milliseconds; the rows that override this are the ones
|
|
29
|
+
* that boot a game, rasterize something, or hand control to a game's own code.
|
|
30
|
+
*/
|
|
31
|
+
export const DEFAULT_RELAY_COMMAND_TIMEOUT_MS = 5_000;
|
|
32
|
+
|
|
33
|
+
interface RelayCommandSpec {
|
|
34
|
+
/** How long the relay waits for this command to FINISH. */
|
|
35
|
+
readonly timeoutMs: number;
|
|
36
|
+
/** Whether command completion owes a tree-scale status derivation. */
|
|
37
|
+
readonly derivedRefresh: RelayCommandDerivedRefresh;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type RelayCommandDerivedRefresh = 'none' | 'if-content-changed' | 'always';
|
|
41
|
+
|
|
42
|
+
const noDerivedRefresh = (timeoutMs = DEFAULT_RELAY_COMMAND_TIMEOUT_MS): RelayCommandSpec => ({
|
|
43
|
+
timeoutMs,
|
|
44
|
+
derivedRefresh: 'none',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const refreshIfContentChanged = (
|
|
48
|
+
timeoutMs = DEFAULT_RELAY_COMMAND_TIMEOUT_MS,
|
|
49
|
+
): RelayCommandSpec => ({ timeoutMs, derivedRefresh: 'if-content-changed' });
|
|
50
|
+
|
|
51
|
+
const alwaysRefresh = (timeoutMs = DEFAULT_RELAY_COMMAND_TIMEOUT_MS): RelayCommandSpec => ({
|
|
52
|
+
timeoutMs,
|
|
53
|
+
derivedRefresh: 'always',
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Every command the editor's relay accepts, and how long it waits for each one
|
|
58
|
+
* to answer. Pure and exported so the table is testable without booting a
|
|
59
|
+
* server and standing through a real 5-second expiry.
|
|
60
|
+
*
|
|
61
|
+
* The rule the table encodes: the budget belongs to whoever the ack is
|
|
62
|
+
* actually gated on. An ordinary editor interaction ("select this entity") is
|
|
63
|
+
* gated on the editor and must fail fast — 5s. Everything with its own entry
|
|
64
|
+
* is gated on something slower and outside the editor's control:
|
|
65
|
+
*
|
|
66
|
+
* - `capture-asset-preview` loads a model, renders four views and encodes
|
|
67
|
+
* five PNGs before acknowledging.
|
|
68
|
+
* - `capture-active-document` can wait for an ingested canvas's next render,
|
|
69
|
+
* composite its canvas and DOM layers, sample flatness, and encode the PNG.
|
|
70
|
+
* It is not an ordinary editor read. Measured in Doctor on racing-game under
|
|
71
|
+
* SwiftShader: the 5s default expired while the page kept rasterizing; the
|
|
72
|
+
* walk retried, parked more captures behind it, and `stop` then 504ed behind
|
|
73
|
+
* work the relay had already told its caller was over.
|
|
74
|
+
* - `active-tab` may synchronously mount a component board before its result can
|
|
75
|
+
* be serialized. The Unity FPS import has 178 stories: the page RECEIVED the
|
|
76
|
+
* command in 0.9s but its first board activation answered after the generic
|
|
77
|
+
* 5s budget, while heartbeats continued throughout. This is editor work, but
|
|
78
|
+
* it is not a millisecond chrome toggle when the destination mounts a board.
|
|
79
|
+
* - `select` and `inspect` may synchronously publish the selected subject and
|
|
80
|
+
* compose its inspector after a cold remount. The translated Unity FPS scene
|
|
81
|
+
* has 4,458 authored objects: Doctor measured both commands received by a
|
|
82
|
+
* beating tab yet still working past 5s, which filed seven false `play-stall`
|
|
83
|
+
* errors and made a source value that had survived the remount look unreadable.
|
|
84
|
+
* - `set-inspection-field`, `remove-inspection-field`, and
|
|
85
|
+
* `run-inspection-action` are authored WRITES —
|
|
86
|
+
* the same dialect writer, the same pipe, the same budget; removing an
|
|
87
|
+
* attribute re-parses and rewrites the module exactly as setting one does.
|
|
88
|
+
* For a source-backed root
|
|
89
|
+
* that write is server work the tab waits on: the planner re-parses the
|
|
90
|
+
* game's own module, the writer rewrites the literal, and a vendored game's
|
|
91
|
+
* lock is re-hashed and recorded in the same gesture. Measured on the
|
|
92
|
+
* racing-game ingest, where the tab is also servicing a game that logs every
|
|
93
|
+
* frame: EVERY transform write came back 504 at the 5s default while the
|
|
94
|
+
* same tab answered `select`/`inspect`/`hierarchy` in the same second — so
|
|
95
|
+
* the caller was told "no editor answered" about a write that was merely
|
|
96
|
+
* slow, which is the failure mode this whole table exists to stop.
|
|
97
|
+
* The PLAY verbs and the whole page-bridge family carry their budgets in
|
|
98
|
+
* `@volter/editor-game`'s own contributed rows now, for the same reasons and with the
|
|
99
|
+
* same numbers: `play` waits on the project's entire async `setup()`; `stop`
|
|
100
|
+
* waits on a teardown chain; `bridge-recording-export` steps a paused game
|
|
101
|
+
* frame by frame and encodes a video; `bridge-call` runs GAME code;
|
|
102
|
+
* `page-script` and `game-eval` run a step the CALLER wrote; and
|
|
103
|
+
* `bridge-screenshot` rasterizes the whole game stack.
|
|
104
|
+
*
|
|
105
|
+
* That family is the reason this table exists as a named thing. Their
|
|
106
|
+
* client (`@volter/game-live`'s `RelayTransport`) already applies its own per-leg
|
|
107
|
+
* `AbortSignal.timeout` — 60s for invoke/page-script, 15s for screenshot —
|
|
108
|
+
* and the server's generic 5s was UNDERCUTTING it, so the server's timer won
|
|
109
|
+
* every race. That mattered for the message, not just the duration: the
|
|
110
|
+
* client's own expiry produces `RELAY_UNREACHABLE` plus a "split the hold into
|
|
111
|
+
* shorter calls" hint, while the server's produces "Command timed out —
|
|
112
|
+
* editor connected but did not respond", which names nothing and sent a real
|
|
113
|
+
* investigation looking for a dead editor. Keep each entry >= its client-side
|
|
114
|
+
* counterpart so the informative timer is always the one that fires.
|
|
115
|
+
*
|
|
116
|
+
* Rows without an explicit budget take {@link DEFAULT_RELAY_COMMAND_TIMEOUT_MS}.
|
|
117
|
+
*/
|
|
118
|
+
export const RELAY_COMMANDS = {
|
|
119
|
+
'session-prepare-close': noDerivedRefresh(120_000),
|
|
120
|
+
// ---- Selection ---------------------------------------------------------
|
|
121
|
+
select: noDerivedRefresh(30_000),
|
|
122
|
+
'select-multiple': noDerivedRefresh(),
|
|
123
|
+
'select-all': noDerivedRefresh(),
|
|
124
|
+
|
|
125
|
+
// ---- Editor chrome ------------------------------------------------------
|
|
126
|
+
'viewport-tab': noDerivedRefresh(),
|
|
127
|
+
// Focusing a panel is dock work, but its ack WAITS for the dock to report
|
|
128
|
+
// the panel focused (`revealStaticPanel`), so keep the relay past that wait.
|
|
129
|
+
'show-panel': noDerivedRefresh(15_000),
|
|
130
|
+
'active-tab': alwaysRefresh(30_000),
|
|
131
|
+
// Opening and presenting can await the inspector and a fresh source build.
|
|
132
|
+
// Keep their relay budget aligned with capture-active-document below.
|
|
133
|
+
'open-asset-tab': alwaysRefresh(30_000),
|
|
134
|
+
// The selection half: it changes what the Inspector shows, so the derived
|
|
135
|
+
// state a caller reads next must be refreshed like the open half's.
|
|
136
|
+
'select-asset': alwaysRefresh(),
|
|
137
|
+
'close-asset-tab': alwaysRefresh(),
|
|
138
|
+
'toggle-command-palette': noDerivedRefresh(),
|
|
139
|
+
'toggle-console': noDerivedRefresh(),
|
|
140
|
+
// RELOAD THE EDITOR PAGE — `@volter/game-live`'s `page.reload()`, the one page verb
|
|
141
|
+
// no step can express. It is the HOST's, not a package's: reloading the tab
|
|
142
|
+
// is what the tab is, and until walk 5 it was a `@volter/editor-game` command
|
|
143
|
+
// contribution, so a project without that package — every model project —
|
|
144
|
+
// answered `unknown command type "page-reload"` for a door `@volter/game-live`
|
|
145
|
+
// documents as general (measured on a `cyclotron create` scaffold,
|
|
146
|
+
// 2026-09-21). The handler schedules the navigation for the next task so
|
|
147
|
+
// this ack can travel before the channel is torn down; the client waits for
|
|
148
|
+
// the new page load on the server's own tab table.
|
|
149
|
+
'page-reload': alwaysRefresh(),
|
|
150
|
+
// Acks the ARRANGEMENT, not the intent: the dock clears and rebuilds on the
|
|
151
|
+
// next paint, so the handler waits for that rebuild (see
|
|
152
|
+
// `workspace-presets.ts`'s applied signal). Still ordinary editor work.
|
|
153
|
+
'set-workspace': noDerivedRefresh(),
|
|
154
|
+
// A style bundle is chrome appearance; the document is untouched.
|
|
155
|
+
'set-style': noDerivedRefresh(),
|
|
156
|
+
'set-appearance': noDerivedRefresh(),
|
|
157
|
+
// A view's viewport presentation (lighting, backdrop, overlays); the document is untouched.
|
|
158
|
+
'viewport-presentation': noDerivedRefresh(),
|
|
159
|
+
'present-view': alwaysRefresh(30_000),
|
|
160
|
+
'current-view': refreshIfContentChanged(),
|
|
161
|
+
// A read of the resolved document table; changes nothing.
|
|
162
|
+
'document-table': noDerivedRefresh(),
|
|
163
|
+
|
|
164
|
+
// ---- Inspection and authoring ------------------------------------------
|
|
165
|
+
// The inspection writes go through the project mutation path, which touches
|
|
166
|
+
// the filesystem and may wait on a collaboration revision.
|
|
167
|
+
inspect: refreshIfContentChanged(30_000),
|
|
168
|
+
hierarchy: refreshIfContentChanged(),
|
|
169
|
+
'expand-hierarchy-all': refreshIfContentChanged(),
|
|
170
|
+
'collapse-hierarchy-all': refreshIfContentChanged(),
|
|
171
|
+
'document-probe': refreshIfContentChanged(),
|
|
172
|
+
// A step against the open document's session can edit it (`ctx.ops.mesh.*`).
|
|
173
|
+
// Project-owned document code can rebuild an entire Model, just as a
|
|
174
|
+
// page-script can rebuild a game. Give both the same execution budget.
|
|
175
|
+
'document-script': refreshIfContentChanged(60_000),
|
|
176
|
+
'set-inspection-field': alwaysRefresh(30_000),
|
|
177
|
+
'remove-inspection-field': alwaysRefresh(30_000),
|
|
178
|
+
// `extract-component` and `fork-component` left this table with their menus
|
|
179
|
+
// (`@volter/editor-game/contributions/component-verbs.command.ts`), which carries
|
|
180
|
+
// both budgets forward row for row.
|
|
181
|
+
// The hierarchy context menu's structure verbs, over the control door. Every
|
|
182
|
+
// one of them rewrites the game's own source, so they refresh like a write.
|
|
183
|
+
'structure-op': alwaysRefresh(30_000),
|
|
184
|
+
'run-inspection-action': alwaysRefresh(30_000),
|
|
185
|
+
// `editor.command(id, args)` — ONE workbench/view command by id. What it
|
|
186
|
+
// does is the command's, so nothing here can know whether the document
|
|
187
|
+
// changed: `alwaysRefresh` is the honest budget, the same one every other
|
|
188
|
+
// "run something the editor does not model" verb takes.
|
|
189
|
+
'run-command': alwaysRefresh(30_000),
|
|
190
|
+
undo: alwaysRefresh(),
|
|
191
|
+
redo: alwaysRefresh(),
|
|
192
|
+
// `open` WAITS FOR THE PROJECT ADAPTER, for the same reason `play` waits on
|
|
193
|
+
// the project's async `setup()`: on a cold session the adapter's scene table
|
|
194
|
+
// is not there yet, and the door's whole job is to put a document on screen
|
|
195
|
+
// once it is. MEASURED on three cold the editor's `edit` command sessions over a
|
|
196
|
+
// `--template models` probe — 6025 / 6831 / 6474 ms from tab-connected to
|
|
197
|
+
// the entry being listed, every one of them first refusing with
|
|
198
|
+
// `SCENE_TABLE_UNAVAILABLE`. At the 5 s default the relay's timer won that
|
|
199
|
+
// race and the caller was told "the tab did not respond" about a door that
|
|
200
|
+
// was merely waiting, which is the exact failure this table exists to stop.
|
|
201
|
+
// 30 s sits above `openSceneTableEntryWhenListed`'s own 15 s bound so the
|
|
202
|
+
// INFORMATIVE refusal (the scene table's, naming the known ids) is always
|
|
203
|
+
// the one that fires.
|
|
204
|
+
open: alwaysRefresh(30_000),
|
|
205
|
+
|
|
206
|
+
// ---- Rasterizing --------------------------------------------------------
|
|
207
|
+
// Everything here renders something and reads pixels back.
|
|
208
|
+
'capture-active-document': refreshIfContentChanged(30_000),
|
|
209
|
+
// The whole editor page through the same compositor; the foreignObject leg
|
|
210
|
+
// over a full dock takes seconds, not milliseconds.
|
|
211
|
+
'capture-editor-chrome': refreshIfContentChanged(30_000),
|
|
212
|
+
|
|
213
|
+
// The ONE door onto a view's verbs (`@volter/sdk/views`, U8 ruling 1).
|
|
214
|
+
// A verb either READS the view or moves its own transform; neither touches
|
|
215
|
+
// a document, so nothing derived refreshes.
|
|
216
|
+
|
|
217
|
+
// The THREE VIEWPORT'S verbs — framing, the camera, view presets, the open
|
|
218
|
+
// Object3D document's orbit/turntable/frame, the viewport photograph and the
|
|
219
|
+
// display and transform toggles — are its own command contribution
|
|
220
|
+
// (`viewport-commands.ts`), each budget on its contributed row.
|
|
221
|
+
|
|
222
|
+
// The BLENDER lane's ten verbs are `@volter/editor-blender`'s
|
|
223
|
+
// `contributions/blender.command.ts` (WORK.md §The workbench, item D) —
|
|
224
|
+
// each row's budget travelled with it, onto the contributed spec the page
|
|
225
|
+
// reports to the server. `capture-story-variants` made the same move, to the
|
|
226
|
+
// kit's own `stories/story-capture-command.ts`: it
|
|
227
|
+
// mounts each CSF export, waits for the DOM to settle, rasterizes it through
|
|
228
|
+
// the `foreignObject` leg and tiles the sheet, so its budget scales with the
|
|
229
|
+
// file's export count rather than with any single render — 120 s, measured
|
|
230
|
+
// on a real 10-story HUD file that expired the default outright, and stated
|
|
231
|
+
// now on the contributed row instead of here.
|
|
232
|
+
} as const satisfies Record<string, RelayCommandSpec>;
|
|
233
|
+
|
|
234
|
+
/** Every command type the relay accepts. The dispatch switch keys off this. */
|
|
235
|
+
export type RelayCommandType = keyof typeof RELAY_COMMANDS;
|
|
236
|
+
|
|
237
|
+
/** The vocabulary as data — what a guard or a tool enumerates. */
|
|
238
|
+
export const RELAY_COMMAND_TYPES = Object.keys(RELAY_COMMANDS) as readonly RelayCommandType[];
|
|
239
|
+
|
|
240
|
+
export function isRelayCommandType(value: unknown): value is RelayCommandType {
|
|
241
|
+
return typeof value === 'string' && Object.hasOwn(RELAY_COMMANDS, value);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* How long the relay waits for a command to finish. An unrecognized type gets
|
|
246
|
+
* the generic budget rather than an error: the relay's job is to hand the
|
|
247
|
+
* string to the tab and let the TAB say it does not know it.
|
|
248
|
+
*/
|
|
249
|
+
export function relayCommandTimeoutMs(type: unknown, command?: Record<string, unknown>): number {
|
|
250
|
+
const base = isRelayCommandType(type)
|
|
251
|
+
? RELAY_COMMANDS[type].timeoutMs
|
|
252
|
+
: DEFAULT_RELAY_COMMAND_TIMEOUT_MS;
|
|
253
|
+
// A held key answers after release. Its requested duration is work, not a
|
|
254
|
+
// stalled tab; ordinary probes retain their short completion budget.
|
|
255
|
+
if (type === 'document-probe' && command?.['step'] && typeof command['step'] === 'object') {
|
|
256
|
+
const step = command['step'] as Record<string, unknown>;
|
|
257
|
+
const hold = step['holdMs'];
|
|
258
|
+
if (step['action'] === 'key' && typeof hold === 'number' && Number.isFinite(hold) &&
|
|
259
|
+
hold >= 0 && hold <= MAX_DOCUMENT_KEY_HOLD_MS) return base + Math.ceil(hold);
|
|
260
|
+
}
|
|
261
|
+
return base;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** The status-derivation policy owned by the same command row as its timeout. */
|
|
265
|
+
export function relayCommandDerivedRefresh(type: unknown): RelayCommandDerivedRefresh {
|
|
266
|
+
return isRelayCommandType(type) ? RELAY_COMMANDS[type].derivedRefresh : 'always';
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* The subset an INGEST session answers itself (`ingest/ingest-play-commands.ts`).
|
|
271
|
+
* A captured ingest is not a host-mounted root, so first-party play would tear
|
|
272
|
+
* its mount down; these five are dispatched against the ingest surface instead.
|
|
273
|
+
*
|
|
274
|
+
* Plain strings, not `RelayCommandType`: the five verbs left this table for
|
|
275
|
+
* `@volter/editor-game`'s `play.command.ts` when Play left the host (WORK.md §The
|
|
276
|
+
* workbench, P3b), and the ingest latch runs in `handleCommand`'s PROLOGUE —
|
|
277
|
+
* before any contributed handler is looked up — so a captured ingest still
|
|
278
|
+
* answers them first. The latch moves with ingest in P4.
|
|
279
|
+
*/
|
|
280
|
+
export const INGEST_PLAY_COMMAND_TYPES = [
|
|
281
|
+
'play',
|
|
282
|
+
'stop',
|
|
283
|
+
'pause',
|
|
284
|
+
'resume',
|
|
285
|
+
'step',
|
|
286
|
+
] as const satisfies readonly string[];
|
|
287
|
+
|
|
288
|
+
export type IngestPlayCommandType = (typeof INGEST_PLAY_COMMAND_TYPES)[number];
|
|
289
|
+
|
|
290
|
+
export function isIngestPlayCommandType(value: unknown): value is IngestPlayCommandType {
|
|
291
|
+
return (INGEST_PLAY_COMMAND_TYPES as readonly string[]).includes(value as string);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* THE ANSWER SHAPE, the other column of the same vocabulary — what a tab posts
|
|
296
|
+
* back to `/__editor/command-result` for a command it just ran.
|
|
297
|
+
*
|
|
298
|
+
* Same rule as the timeout column above, for the same reason: the relay has two
|
|
299
|
+
* ends in two compilation units — the browser that PRODUCES this
|
|
300
|
+
* (`command-listener.ts`) and the server that settles and re-serves it
|
|
301
|
+
* (`server/server-utils.ts`, `server/routes/control-plane.ts`) — and each used
|
|
302
|
+
* to declare its own copy. They had already drifted on the field that matters
|
|
303
|
+
* most: the browser's said `ok: boolean` and the server's said `ok?: boolean`,
|
|
304
|
+
* so server code could read a result that never says whether it worked. Both
|
|
305
|
+
* files already import this module (so does `ingest/ingest-play-commands.ts`,
|
|
306
|
+
* which restated the shape a third time), so there is no new dependency here.
|
|
307
|
+
*
|
|
308
|
+
* `ok` is REQUIRED because the producer always writes it: every browser exit
|
|
309
|
+
* (`structuredErrorResult`, `commandThrewResult`, every handler's return) and
|
|
310
|
+
* every server-side settle (`settlePendingCommand`'s callers, all of which pair
|
|
311
|
+
* `timedOut: true` with `ok: false`) sets it. A payload arriving from off the
|
|
312
|
+
* wire is narrowed where it enters — `handleCommandResult` — not by weakening
|
|
313
|
+
* this type.
|
|
314
|
+
*
|
|
315
|
+
* `timedOut` is deliberately NOT here: no tab produces it. It is the SERVER's
|
|
316
|
+
* own verdict for a command no tab answered, so it lives on the server's
|
|
317
|
+
* `RelayedCommandResult` extension beside the code that sets it.
|
|
318
|
+
*/
|
|
319
|
+
export interface CommandResult {
|
|
320
|
+
ok: boolean;
|
|
321
|
+
error?: string;
|
|
322
|
+
/** Payload for commands that answer with data (`capture-viewport`'s base64
|
|
323
|
+
* PNG, the debug-seam reads). On the failure path it carries structured
|
|
324
|
+
* markers (`{ code: 'UNKNOWN_COMMAND_TYPE' }`, registered-name lists) the
|
|
325
|
+
* SDK matches on — never message prose. */
|
|
326
|
+
data?: Record<string, unknown>;
|
|
327
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/** Registered-session discovery; never selects another project's session. */
|
|
2
|
+
import { readLiveRegisteredSessions, servedProjectAnswer } from './registry-format.js';
|
|
3
|
+
export { servedProjectAnswer } from './registry-format.js';
|
|
4
|
+
|
|
5
|
+
export const EDITOR_SESSION_DISCOVERY_TIMEOUT_MS = 2000;
|
|
6
|
+
|
|
7
|
+
export const EDITOR_PROBE_TIMEOUT_MS = 1500;
|
|
8
|
+
|
|
9
|
+
export class EditorTimeoutError extends Error {
|
|
10
|
+
constructor(label: string, ms: number) {
|
|
11
|
+
super(`${label} timed out after ${ms}ms`);
|
|
12
|
+
this.name = 'EditorTimeoutError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {
|
|
17
|
+
return new Promise<T>((resolvePromise, reject) => {
|
|
18
|
+
const timer = setTimeout(() => reject(new EditorTimeoutError(label, ms)), ms);
|
|
19
|
+
promise.then(
|
|
20
|
+
(v) => {
|
|
21
|
+
clearTimeout(timer);
|
|
22
|
+
resolvePromise(v);
|
|
23
|
+
},
|
|
24
|
+
(err) => {
|
|
25
|
+
clearTimeout(timer);
|
|
26
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface EditorSessionInfo {
|
|
33
|
+
/** The port this session's dev server is bound to. */
|
|
34
|
+
port: number;
|
|
35
|
+
/** Canonical project root path currently open, or null when none. */
|
|
36
|
+
project: string | null;
|
|
37
|
+
/** Dev-server process id, when known from the local session registry (null for an unregistered/legacy server the caller only probed by port). */
|
|
38
|
+
pid: number | null;
|
|
39
|
+
/** Exact explicitly targeted editor origin/base URL, including protocol and host. */
|
|
40
|
+
url?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Why this server cannot DESCRIBE the `project` it is serving — its
|
|
43
|
+
* manifest's own parse/validation failure, naming the failing key. `null`
|
|
44
|
+
* when the project reads fine, and `undefined` from a probe that did not ask
|
|
45
|
+
* (or a server too old to say). See {@link servedProjectAnswer}: a session in
|
|
46
|
+
* this state is still THIS project's session, and callers must report the
|
|
47
|
+
* reason rather than treat it as no session at all.
|
|
48
|
+
*/
|
|
49
|
+
manifestError?: string | null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function fetchJson(url: string, timeoutMs: number): Promise<unknown> {
|
|
53
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
54
|
+
if (!res.ok) throw new Error(`GET /__editor/project returned HTTP ${res.status}`);
|
|
55
|
+
return await res.json();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function baseUrl(session: EditorSessionInfo): string {
|
|
59
|
+
return session.url ?? `http://127.0.0.1:${session.port}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface SessionListingTransport { listSessions(timeoutMs: number): Promise<EditorSessionInfo[]>; }
|
|
63
|
+
export class HttpSessionDiscovery implements SessionListingTransport {
|
|
64
|
+
async listSessions(timeoutMs: number): Promise<EditorSessionInfo[]> {
|
|
65
|
+
const registered = readLiveRegisteredSessions();
|
|
66
|
+
const perProbeTimeout = Math.min(EDITOR_PROBE_TIMEOUT_MS, Math.max(200, timeoutMs));
|
|
67
|
+
const failures: string[] = [];
|
|
68
|
+
const probes = await Promise.all(
|
|
69
|
+
registered.map(async (s) => {
|
|
70
|
+
try {
|
|
71
|
+
const body = await fetchJson(
|
|
72
|
+
`${baseUrl({ port: s.port, project: null, pid: s.pid })}/__editor/project`,
|
|
73
|
+
perProbeTimeout,
|
|
74
|
+
);
|
|
75
|
+
const served = servedProjectAnswer(body);
|
|
76
|
+
const info: EditorSessionInfo = {
|
|
77
|
+
port: s.port,
|
|
78
|
+
project: served.path,
|
|
79
|
+
pid: s.pid,
|
|
80
|
+
manifestError: served.manifestError,
|
|
81
|
+
};
|
|
82
|
+
return info;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
const detail = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
85
|
+
failures.push(`port ${s.port}: ${detail}`);
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
const sessions = probes.filter((p): p is EditorSessionInfo => p !== undefined);
|
|
91
|
+
// A readable registry with registered live processes is not an empty
|
|
92
|
+
// registry just because every HTTP discovery request failed. Keep any
|
|
93
|
+
// verified sessions usable, but refuse an entirely unanswered inventory
|
|
94
|
+
// rather than telling the caller to launch a second editor.
|
|
95
|
+
if (registered.length > 0 && sessions.length === 0) {
|
|
96
|
+
throw new Error(`Registered editor sessions could not be inspected: ${failures.join('; ')}`);
|
|
97
|
+
}
|
|
98
|
+
return sessions;
|
|
99
|
+
}
|
|
100
|
+
}
|