@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,563 @@
|
|
|
1
|
+
import type { EditorControlLifecycle } from '@volter/editor-sdk/session/editor-control-lifecycle';
|
|
2
|
+
import { COMMAND_RESULT_RECEIPT_EVENT } from '@volter/editor-sdk/session/editor-control-protocol';
|
|
3
|
+
import { isCancellationReason } from './cancellation-reason';
|
|
4
|
+
// Type-only: erased at compile, so the pre-React bootstrap module stays
|
|
5
|
+
// dependency-light while the channel vocabulary keeps ONE owner.
|
|
6
|
+
import type { LeaseChannelState } from './editor-lease';
|
|
7
|
+
import {
|
|
8
|
+
COLLABORATION_PARTICIPANT_ID,
|
|
9
|
+
COLLABORATION_PARTICIPANT_NAME,
|
|
10
|
+
} from './editor-session-attribution';
|
|
11
|
+
import { onSessionEndedChange } from './session-tombstone';
|
|
12
|
+
import type { TabCensus } from './tab-census';
|
|
13
|
+
import { type EditorTabRoute, installTabLifecycleListeners } from './tab-lifecycle-client';
|
|
14
|
+
|
|
15
|
+
const BASE = '/__editor';
|
|
16
|
+
|
|
17
|
+
interface EditorPresenceBootstrap {
|
|
18
|
+
clientId: string;
|
|
19
|
+
participantId: string;
|
|
20
|
+
displayName: string;
|
|
21
|
+
/**
|
|
22
|
+
* This TAB's identity (sessionStorage, survives reloads) and this
|
|
23
|
+
* page-load's `epoch`. Minted by the inline bootstrap, which also starts
|
|
24
|
+
* the heartbeat worker that proves the tab to the server — see
|
|
25
|
+
* `server/tab-presence.ts`. Absent only where there is no inline bootstrap
|
|
26
|
+
* at all (browser-mode builds, jsdom tests).
|
|
27
|
+
*/
|
|
28
|
+
tabId?: string;
|
|
29
|
+
epoch?: string;
|
|
30
|
+
/** The generation record most recently accepted by the server. */
|
|
31
|
+
controlLifecycle?: EditorControlLifecycle | null;
|
|
32
|
+
/**
|
|
33
|
+
* Hand this tab's resource census to the heartbeat worker, which carries it
|
|
34
|
+
* out on the next beat and then drops it (`server/tab-presence.ts`'s
|
|
35
|
+
* `TabCensus`) — one call, one sample the server files. Absent wherever the
|
|
36
|
+
* inline bootstrap is — browser-mode builds, jsdom tests, a tunnelled tab
|
|
37
|
+
* that was refused the worker script.
|
|
38
|
+
*/
|
|
39
|
+
reportCensus?: (census: TabCensus) => void;
|
|
40
|
+
/** Hand the heartbeat worker what the page's main thread is about to do
|
|
41
|
+
* (`building src/models/x.ts`) or that it is done (`null`): the beat
|
|
42
|
+
* carries it while the page itself cannot speak. */
|
|
43
|
+
reportPhase?: (phase: string | null) => void;
|
|
44
|
+
/**
|
|
45
|
+
* Stop the heartbeat worker, withdrawing this tab from the server's tab
|
|
46
|
+
* table. The one caller is a TERMINAL session tombstone
|
|
47
|
+
* (`session-tombstone.ts`) — see the bootstrap's own comment in index.html
|
|
48
|
+
* for why a beating corpse is what this closes. Absent wherever the inline
|
|
49
|
+
* bootstrap is.
|
|
50
|
+
*/
|
|
51
|
+
stopHeartbeat?: () => void;
|
|
52
|
+
source: PresenceEventSource | null;
|
|
53
|
+
pageOwned: boolean;
|
|
54
|
+
pending: Array<{ type: string; data: string }>;
|
|
55
|
+
queueListeners: Array<{ type: string; listener: EventListener }>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
type PresenceEventSource = Pick<
|
|
59
|
+
EventSource,
|
|
60
|
+
'addEventListener' | 'removeEventListener' | 'dispatchEvent' | 'close'
|
|
61
|
+
> & {
|
|
62
|
+
/**
|
|
63
|
+
* Upstream control frame, present only on the duplex control socket the
|
|
64
|
+
* inline bootstrap builds (index.html). Returns false when this transport
|
|
65
|
+
* cannot carry it — an `EventSource`, or a socket the server has not
|
|
66
|
+
* granted duplex to (the share tunnel bridges the SSE stream one way).
|
|
67
|
+
*
|
|
68
|
+
* Type and payload are separate ARGUMENTS, never one merged object: the
|
|
69
|
+
* payload is open-ended (a state snapshot is whatever the editor reports),
|
|
70
|
+
* so sharing a namespace with the discriminator would both leak `type`
|
|
71
|
+
* into the state the server stores and let a payload key named `type`
|
|
72
|
+
* silently redirect the frame.
|
|
73
|
+
*/
|
|
74
|
+
send?(type: string, payload: Record<string, unknown>): boolean;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Whether this transport's connection to the server is UP right now.
|
|
78
|
+
* Present only on the duplex control socket the inline bootstrap builds
|
|
79
|
+
* (index.html). A real `EventSource` exposes the equivalent as its numeric
|
|
80
|
+
* `readyState`, which `readControlChannelState` reads instead.
|
|
81
|
+
*/
|
|
82
|
+
readonly connected?: boolean;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const bootstrapGlobal = globalThis as typeof globalThis & {
|
|
86
|
+
__VGAI_EDITOR_PRESENCE_BOOTSTRAP__?: EditorPresenceBootstrap;
|
|
87
|
+
};
|
|
88
|
+
const bootstrap = bootstrapGlobal.__VGAI_EDITOR_PRESENCE_BOOTSTRAP__;
|
|
89
|
+
|
|
90
|
+
export const EDITOR_CLIENT_ID =
|
|
91
|
+
bootstrap?.clientId ?? globalThis.crypto?.randomUUID?.() ?? `editor-${Date.now()}`;
|
|
92
|
+
export const EDITOR_PARTICIPANT_ID = COLLABORATION_PARTICIPANT_ID;
|
|
93
|
+
export const EDITOR_PARTICIPANT_NAME = COLLABORATION_PARTICIPANT_NAME;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Push this tab's resource census onto the heartbeat.
|
|
97
|
+
*
|
|
98
|
+
* A no-op wherever there is no inline bootstrap (browser-mode builds, jsdom):
|
|
99
|
+
* the census is diagnostics, and diagnostics that break their host are worse
|
|
100
|
+
* than none.
|
|
101
|
+
*/
|
|
102
|
+
export function reportTabPhase(phase: string | null): void {
|
|
103
|
+
bootstrap?.reportPhase?.(phase);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function reportTabCensus(census: TabCensus): void {
|
|
107
|
+
bootstrap?.reportCensus?.(census);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* WITHDRAW THIS TAB from the server's tab table. Terminal tombstones only
|
|
112
|
+
* (`session-tombstone.ts`).
|
|
113
|
+
*
|
|
114
|
+
* Presence is a UNION (`server/tab-presence.ts`): a fresh BEAT **or** a live
|
|
115
|
+
* control channel. Both halves therefore have to go, and measured live on
|
|
116
|
+
* 2026-08-15, stopping only the beat was not enough — the inert page's control
|
|
117
|
+
* socket reconnected to the successor server on the same port, which kept the
|
|
118
|
+
* corpse present, blessed, and reported as `commandListener not attached`
|
|
119
|
+
* while `vgai edit` answered "focused" instead of opening a real tab.
|
|
120
|
+
*
|
|
121
|
+
* The channel is closed unconditionally, not by releasing a reference: this
|
|
122
|
+
* page is over, so there is no consumer whose refcount could legitimately hold
|
|
123
|
+
* it open. Both calls are no-ops where the inline bootstrap never ran (browser
|
|
124
|
+
* mode, jsdom), which is also where the tab was never in the table.
|
|
125
|
+
*/
|
|
126
|
+
export function withdrawTabFromSession(): void {
|
|
127
|
+
bootstrap?.stopHeartbeat?.();
|
|
128
|
+
const real = sharedSource;
|
|
129
|
+
if (real === null) return;
|
|
130
|
+
sharedSource = null;
|
|
131
|
+
sharedRefCount = 0;
|
|
132
|
+
if (bootstrap?.source === real) bootstrap.source = null;
|
|
133
|
+
if (lifecycleSource === real) lifecycleSource = null;
|
|
134
|
+
try {
|
|
135
|
+
real.close();
|
|
136
|
+
} catch {
|
|
137
|
+
/* the socket is going away with the page regardless */
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function eventsUrl(): string {
|
|
142
|
+
const query = new URLSearchParams({
|
|
143
|
+
clientId: EDITOR_CLIENT_ID,
|
|
144
|
+
participantId: EDITOR_PARTICIPANT_ID,
|
|
145
|
+
displayName: EDITOR_PARTICIPANT_NAME,
|
|
146
|
+
});
|
|
147
|
+
if (bootstrap?.tabId) query.set('tabId', bootstrap.tabId);
|
|
148
|
+
return `${BASE}/events?${query}`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* The subset of `EventSource` used by editor event consumers. `close()` only
|
|
153
|
+
* releases the calling consumer; one real socket is shared by the whole page.
|
|
154
|
+
*/
|
|
155
|
+
export interface EditorEventSource {
|
|
156
|
+
addEventListener(type: string, listener: (event: MessageEvent) => void): void;
|
|
157
|
+
removeEventListener(type: string, listener: (event: MessageEvent) => void): void;
|
|
158
|
+
close(): void;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let sharedSource: PresenceEventSource | null = bootstrap?.source ?? null;
|
|
162
|
+
let sharedRefCount = bootstrap?.source && bootstrap.pageOwned ? 1 : 0;
|
|
163
|
+
let lifecycleSource: PresenceEventSource | null = null;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Buffered types whose replay must wait for their own consumer.
|
|
167
|
+
*
|
|
168
|
+
* The tab-* events are replayed by `installLifecycle` because
|
|
169
|
+
* `installTabLifecycleListeners` has just attached their listeners — the
|
|
170
|
+
* consumer is in place before the drain. `editor-command` is different: its
|
|
171
|
+
* listener is attached by `connectCommandListener`, once the whole React
|
|
172
|
+
* graph has loaded, long after boot. Replaying it at boot would dispatch it
|
|
173
|
+
* to zero listeners and lose it exactly as not buffering it did.
|
|
174
|
+
*/
|
|
175
|
+
const DEFERRED_REPLAY_TYPES = new Set(['editor-command']);
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Hand back the buffered events whose type `accept`s, and stop buffering
|
|
179
|
+
* that type — its consumer is now attached, so later events reach it
|
|
180
|
+
* directly. Everything else stays queued for its own consumer.
|
|
181
|
+
*/
|
|
182
|
+
function drainBootstrap(source: PresenceEventSource, accept: (type: string) => boolean): void {
|
|
183
|
+
if (!bootstrap || bootstrap.source !== source) return;
|
|
184
|
+
bootstrap.queueListeners = bootstrap.queueListeners.filter(({ type, listener }) => {
|
|
185
|
+
if (!accept(type)) return true;
|
|
186
|
+
source.removeEventListener(type, listener);
|
|
187
|
+
return false;
|
|
188
|
+
});
|
|
189
|
+
const replay = bootstrap.pending.filter((event) => accept(event.type));
|
|
190
|
+
bootstrap.pending = bootstrap.pending.filter((event) => !accept(event.type));
|
|
191
|
+
for (const { type, data } of replay) {
|
|
192
|
+
source.dispatchEvent(new MessageEvent(type, { data }));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function installLifecycle(source: PresenceEventSource): void {
|
|
197
|
+
if (lifecycleSource === source) return;
|
|
198
|
+
lifecycleSource = source;
|
|
199
|
+
// This tab's identity rides along so `tab-close` can be ACKNOWLEDGED: the
|
|
200
|
+
// bootstrap global is read here and nowhere else.
|
|
201
|
+
installTabLifecycleListeners(source, BASE, { tabId: bootstrap?.tabId, epoch: bootstrap?.epoch });
|
|
202
|
+
drainBootstrap(source, (type) => !DEFERRED_REPLAY_TYPES.has(type));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Connect to the editor's shared SSE stream.
|
|
207
|
+
*
|
|
208
|
+
* Keeping this implementation in a dependency-light module is intentional:
|
|
209
|
+
* index.html imports it before the React entry so the server sees the tab even
|
|
210
|
+
* while Vite is still loading or optimizing the much larger editor graph.
|
|
211
|
+
*/
|
|
212
|
+
export function connectEvents(): EditorEventSource {
|
|
213
|
+
if (!sharedSource) {
|
|
214
|
+
if (bootstrap?.source) {
|
|
215
|
+
sharedSource = bootstrap.source;
|
|
216
|
+
if (bootstrap.pageOwned) sharedRefCount++;
|
|
217
|
+
} else {
|
|
218
|
+
sharedSource = new EventSource(eventsUrl());
|
|
219
|
+
if (bootstrap) bootstrap.source = sharedSource;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const real = sharedSource;
|
|
223
|
+
installLifecycle(real);
|
|
224
|
+
sharedRefCount++;
|
|
225
|
+
|
|
226
|
+
const ownListeners: Array<{ type: string; listener: EventListener }> = [];
|
|
227
|
+
let released = false;
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
addEventListener(type, listener) {
|
|
231
|
+
const wrapped = listener as EventListener;
|
|
232
|
+
real.addEventListener(type, wrapped);
|
|
233
|
+
ownListeners.push({ type, listener: wrapped });
|
|
234
|
+
// The consumer this type was buffered FOR has just arrived. Replaying
|
|
235
|
+
// here — rather than at boot — is the whole point of the deferral.
|
|
236
|
+
if (DEFERRED_REPLAY_TYPES.has(type)) drainBootstrap(real, (queued) => queued === type);
|
|
237
|
+
},
|
|
238
|
+
removeEventListener(type, listener) {
|
|
239
|
+
const wrapped = listener as EventListener;
|
|
240
|
+
real.removeEventListener(type, wrapped);
|
|
241
|
+
const idx = ownListeners.findIndex((item) => item.type === type && item.listener === wrapped);
|
|
242
|
+
if (idx >= 0) ownListeners.splice(idx, 1);
|
|
243
|
+
},
|
|
244
|
+
close() {
|
|
245
|
+
if (released) return;
|
|
246
|
+
released = true;
|
|
247
|
+
for (const { type, listener } of ownListeners) real.removeEventListener(type, listener);
|
|
248
|
+
ownListeners.length = 0;
|
|
249
|
+
sharedRefCount--;
|
|
250
|
+
if (sharedRefCount <= 0) {
|
|
251
|
+
real.close();
|
|
252
|
+
if (sharedSource === real) sharedSource = null;
|
|
253
|
+
// The bootstrap holds its own reference, and `connectEvents` adopts
|
|
254
|
+
// it before minting a socket. Leaving it pointing at the one we just
|
|
255
|
+
// closed would hand the next caller a dead EventSource that never
|
|
256
|
+
// reconnects and never errors — it would simply go quiet.
|
|
257
|
+
if (bootstrap?.source === real) bootstrap.source = null;
|
|
258
|
+
if (lifecycleSource === real) lifecycleSource = null;
|
|
259
|
+
sharedRefCount = 0;
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Is this page's control connection to its editor server up?
|
|
267
|
+
*
|
|
268
|
+
* The supervised lease (editor-lease.ts) reads this as its SECOND liveness
|
|
269
|
+
* signal, independent of the HTTP poll: a fetch can fail because the browser's
|
|
270
|
+
* per-origin pool is saturated by a cold module flood or because the server's
|
|
271
|
+
* event loop is blocked, neither of which means the session is gone — but a
|
|
272
|
+
* dead PROCESS cannot hold this socket open. Both readings together are what
|
|
273
|
+
* separates "gone" from "busy".
|
|
274
|
+
*
|
|
275
|
+
* `unknown` is deliberate rather than an optimistic `open`: a transport that
|
|
276
|
+
* exposes no connection state (the share tunnel's one-way SSE bridge) gives no
|
|
277
|
+
* evidence, and absent evidence must not make the watchdog keener to keep a
|
|
278
|
+
* dead tab alive. The lease treats it exactly like `closed`.
|
|
279
|
+
*/
|
|
280
|
+
export function readControlChannelState(): LeaseChannelState {
|
|
281
|
+
const source = sharedSource ?? bootstrap?.source ?? null;
|
|
282
|
+
if (!source) return 'unknown';
|
|
283
|
+
if (typeof source.connected === 'boolean') return source.connected ? 'open' : 'closed';
|
|
284
|
+
// A real `EventSource`: 0 CONNECTING, 1 OPEN, 2 CLOSED. Only OPEN is
|
|
285
|
+
// evidence — a socket mid-reconnect proves nothing about the server.
|
|
286
|
+
const readyState = (source as { readyState?: unknown }).readyState;
|
|
287
|
+
if (typeof readyState === 'number') return readyState === 1 ? 'open' : 'closed';
|
|
288
|
+
return 'unknown';
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** Hold this page's editor-session connection until its caller releases it. */
|
|
292
|
+
export function connectTabPresence(): () => void {
|
|
293
|
+
if (typeof EventSource === 'undefined') return () => {};
|
|
294
|
+
const events = connectEvents();
|
|
295
|
+
// A TERMINAL tombstone withdraws this tab from the server's table — both
|
|
296
|
+
// halves of the presence union. Subscribed HERE rather than inside
|
|
297
|
+
// `session-tombstone.ts` so that module keeps no dependencies at all (and so
|
|
298
|
+
// this file, which owns both doors, stays the only thing that touches them).
|
|
299
|
+
// `server-gone` deliberately stays present: that page may still resume onto
|
|
300
|
+
// the same process, and a tab that withdrew could not.
|
|
301
|
+
const unsubscribeTombstone = onSessionEndedChange((state) => {
|
|
302
|
+
if (state !== null && state.reason !== 'server-gone') withdrawTabFromSession();
|
|
303
|
+
});
|
|
304
|
+
const stopBootErrors = reportBootErrors();
|
|
305
|
+
return () => {
|
|
306
|
+
stopBootErrors();
|
|
307
|
+
unsubscribeTombstone();
|
|
308
|
+
events.close();
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** How many boot failures one page-load reports. A module that throws inside a
|
|
313
|
+
* retry loop must not become a firehose; the first few say what broke. */
|
|
314
|
+
const BOOT_ERROR_CAP = 5;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* THE APP'S FIRST ERROR, reported by the layer that is already up.
|
|
318
|
+
*
|
|
319
|
+
* `installEditorConsoleCapture` hooks `error`/`unhandledrejection`, but it is
|
|
320
|
+
* part of the editor app -- so when the app dies during init, that hook never
|
|
321
|
+
* exists and the page reports NOTHING. The reporter sat downstream of the
|
|
322
|
+
* failure it needed to describe.
|
|
323
|
+
*
|
|
324
|
+
* MEASURED 2026-09-15: a tab beat for the better part of an hour, answered
|
|
325
|
+
* liveness echoes, and reported `commandListener not attached` with no page
|
|
326
|
+
* error and an empty `vgai console` -- so `vgai status` could say only that
|
|
327
|
+
* the app "never finished loading", which is the symptom, never the cause.
|
|
328
|
+
* Every door the CLI offers was blind to a crash before the app came up.
|
|
329
|
+
*
|
|
330
|
+
* Presence is connected by this point, so this reports through the SAME
|
|
331
|
+
* `console-entries` door the app uses later and lands in the same ledger
|
|
332
|
+
* `vgai console` reads. A duplicate once the app's own capture starts is
|
|
333
|
+
* deduplicated there by fingerprint.
|
|
334
|
+
*/
|
|
335
|
+
function reportBootErrors(): () => void {
|
|
336
|
+
if (typeof window === 'undefined') return () => {};
|
|
337
|
+
let sent = 0;
|
|
338
|
+
const report = (message: string): void => {
|
|
339
|
+
if (message === '' || sent >= BOOT_ERROR_CAP) return;
|
|
340
|
+
sent += 1;
|
|
341
|
+
void postControl('console-entries', {
|
|
342
|
+
entries: [
|
|
343
|
+
{
|
|
344
|
+
id: `boot-error:${sent}`,
|
|
345
|
+
severity: 'error',
|
|
346
|
+
// Named as a BOOT failure, so a reader knows the app never came up
|
|
347
|
+
// rather than hunting for a console that was never going to fill.
|
|
348
|
+
message: `editor app failed to start: ${message}`,
|
|
349
|
+
source: 'runtime',
|
|
350
|
+
occurrences: 1,
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
_clientId: bootstrap?.clientId ?? 'boot',
|
|
354
|
+
});
|
|
355
|
+
};
|
|
356
|
+
const onError = (event: ErrorEvent): void => {
|
|
357
|
+
const error = event.error as Error | undefined;
|
|
358
|
+
report(error?.stack ?? `${event.message} (${event.filename ?? '?'}:${event.lineno ?? 0})`);
|
|
359
|
+
};
|
|
360
|
+
const onRejection = (event: PromiseRejectionEvent): void => {
|
|
361
|
+
const reason: unknown = event.reason;
|
|
362
|
+
// A CANCELLATION IS NOT A FAILURE TO START. See `isCancellationReason`'s
|
|
363
|
+
// own note in `editor-console.ts`: this listener is the page's, the page
|
|
364
|
+
// under the Code-OSS frame is a WORKBENCH, and a workbench throws
|
|
365
|
+
// `CancellationError` (`name === 'Canceled'`) whenever a quick input is
|
|
366
|
+
// dismissed or a search is superseded. MEASURED 2026-09-19, the frame
|
|
367
|
+
// walk's beat 9: `[runtime] editor app failed to start: Canceled: Canceled`
|
|
368
|
+
// on a game scaffold whose editor had started perfectly. The claim in that
|
|
369
|
+
// sentence was false in BOTH halves — nothing failed, and nothing was
|
|
370
|
+
// starting.
|
|
371
|
+
if (isCancellationReason(reason)) return;
|
|
372
|
+
report(
|
|
373
|
+
reason instanceof Error
|
|
374
|
+
? (reason.stack ?? reason.message)
|
|
375
|
+
: `unhandled rejection: ${String(reason)}`,
|
|
376
|
+
);
|
|
377
|
+
};
|
|
378
|
+
window.addEventListener('error', onError);
|
|
379
|
+
window.addEventListener('unhandledrejection', onRejection);
|
|
380
|
+
return () => {
|
|
381
|
+
window.removeEventListener('error', onError);
|
|
382
|
+
window.removeEventListener('unhandledrejection', onRejection);
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* The five things this tab reports UPSTREAM, and the one door they go
|
|
388
|
+
* through.
|
|
389
|
+
*
|
|
390
|
+
* Each has an equivalent POST route, and the POST is still the fallback —
|
|
391
|
+
* the share tunnel's gateway bridges the SSE stream one way, so a tunnelled
|
|
392
|
+
* tab has no upstream socket. But when the page holds a duplex control
|
|
393
|
+
* socket (every local tab), these ride it instead. That is the entire point
|
|
394
|
+
* of the socket: a blocked main thread cannot issue a `fetch`, and even an
|
|
395
|
+
* unblocked one queues control POSTs behind a cold module flood in the
|
|
396
|
+
* browser's per-origin HTTP connection pool.
|
|
397
|
+
*
|
|
398
|
+
* `play-phase` is the second of those standing facts, and it exists for the
|
|
399
|
+
* same reason: it says which of play's eight boot steps the page is INSIDE,
|
|
400
|
+
* published before the step runs, so a step that never returns is still named.
|
|
401
|
+
* It rides its own message rather than the state snapshot on purpose — the
|
|
402
|
+
* snapshot is the expensive derivation, and a page wedged inside a boot step is
|
|
403
|
+
* exactly the page that cannot produce one. Measured at N=20000: `play`,
|
|
404
|
+
* `screenshot` and `stop` all timed out and every reader called the session
|
|
405
|
+
* healthy (`server/play-stall.ts`).
|
|
406
|
+
*
|
|
407
|
+
* `command-listener` is the odd one out: it reports nothing
|
|
408
|
+
* about a command, only whether this page is in a position to run one. THIS
|
|
409
|
+
* module opens the control channel before any other module loads, so a page
|
|
410
|
+
* that dies during boot still connects, still beats, and still counts as
|
|
411
|
+
* present — and every one of those facts is about the TAB, not the document.
|
|
412
|
+
* The listener says so about the document, which is the only thing that
|
|
413
|
+
* separates a healthy session from an eight-minute lie.
|
|
414
|
+
*/
|
|
415
|
+
export type EditorControlMessage =
|
|
416
|
+
| 'command-received'
|
|
417
|
+
| 'command-result'
|
|
418
|
+
| 'command-listener'
|
|
419
|
+
| 'console-entries'
|
|
420
|
+
| 'console-resolved'
|
|
421
|
+
| 'play-phase'
|
|
422
|
+
| 'state'
|
|
423
|
+
| 'tab-route';
|
|
424
|
+
|
|
425
|
+
/** A missing receipt must never strand deferred editor presentation forever. */
|
|
426
|
+
const CONTROL_RECEIPT_TIMEOUT_MS = 2_000;
|
|
427
|
+
|
|
428
|
+
const CONTROL_POST_PATHS: Record<EditorControlMessage, string> = {
|
|
429
|
+
'command-received': `${BASE}/command-received`,
|
|
430
|
+
'command-result': `${BASE}/command-result`,
|
|
431
|
+
'command-listener': `${BASE}/command-listener`,
|
|
432
|
+
'console-entries': `${BASE}/console-entries`,
|
|
433
|
+
'console-resolved': `${BASE}/console-resolved`,
|
|
434
|
+
'play-phase': `${BASE}/play-phase`,
|
|
435
|
+
state: `${BASE}/state`,
|
|
436
|
+
'tab-route': `${BASE}/tab/route`,
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
/** Send one control message on the socket, else POST it. Never throws — a
|
|
440
|
+
* failed report costs a named refusal, never a broken page.
|
|
441
|
+
*
|
|
442
|
+
* Deliberately NOT read through `editor-server-response.ts`: never-throwing is
|
|
443
|
+
* this function's contract and there is no caller to report to, so asserting
|
|
444
|
+
* could only turn a dropped report into a swallowed one. The absence is
|
|
445
|
+
* detected at the READING end instead — `/__editor/state` goes stale and the
|
|
446
|
+
* CLI says so — which is where a missing report is actually visible. */
|
|
447
|
+
async function postControl(
|
|
448
|
+
type: EditorControlMessage,
|
|
449
|
+
payload: Record<string, unknown>,
|
|
450
|
+
): Promise<void> {
|
|
451
|
+
if (typeof fetch === 'undefined') return;
|
|
452
|
+
try {
|
|
453
|
+
await fetch(CONTROL_POST_PATHS[type], {
|
|
454
|
+
method: 'POST',
|
|
455
|
+
headers: { 'Content-Type': 'application/json' },
|
|
456
|
+
body: JSON.stringify({
|
|
457
|
+
...payload,
|
|
458
|
+
...(bootstrap?.controlLifecycle ? { _controlLifecycle: bootstrap.controlLifecycle } : {}),
|
|
459
|
+
}),
|
|
460
|
+
});
|
|
461
|
+
} catch {
|
|
462
|
+
// Relative URLs outside a real document (jsdom/tests) can throw
|
|
463
|
+
// synchronously, and a dropped report must never take down the page.
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export async function sendControl(
|
|
468
|
+
type: EditorControlMessage,
|
|
469
|
+
payload: Record<string, unknown>,
|
|
470
|
+
): Promise<void> {
|
|
471
|
+
const source = sharedSource ?? bootstrap?.source ?? null;
|
|
472
|
+
if (source?.send?.(type, payload)) return;
|
|
473
|
+
await postControl(type, payload);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Report one command result and wait until its original caller is answered.
|
|
478
|
+
*
|
|
479
|
+
* `WebSocket.send()` only queues bytes; its return says nothing about whether
|
|
480
|
+
* the relay accepted the result. Selection presentation depends on that
|
|
481
|
+
* distinction: the server must release the waiting control caller before a
|
|
482
|
+
* large hierarchy/inspector render can monopolize the editor page again.
|
|
483
|
+
*
|
|
484
|
+
* The server answers with {@link COMMAND_RESULT_RECEIPT_EVENT} only after the
|
|
485
|
+
* original command caller's response has finished. That works for both a
|
|
486
|
+
* native duplex result and a tunnelled/SSE result posted upstream. The timeout
|
|
487
|
+
* preserves the standing control-channel rule that a vanished server may drop
|
|
488
|
+
* a report but must never leave the editor page wedged.
|
|
489
|
+
*/
|
|
490
|
+
export async function sendCommandResultControl(
|
|
491
|
+
requestId: string,
|
|
492
|
+
payload: Record<string, unknown>,
|
|
493
|
+
): Promise<void> {
|
|
494
|
+
const source = sharedSource ?? bootstrap?.source ?? null;
|
|
495
|
+
if (!source) {
|
|
496
|
+
await postControl('command-result', payload);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
let settle!: () => void;
|
|
501
|
+
const receipt = new Promise<void>((resolve) => {
|
|
502
|
+
settle = resolve;
|
|
503
|
+
});
|
|
504
|
+
const onReceipt: EventListener = (event) => {
|
|
505
|
+
const wireData = (event as MessageEvent).data;
|
|
506
|
+
let received = wireData;
|
|
507
|
+
if (typeof wireData === 'string') {
|
|
508
|
+
try {
|
|
509
|
+
received = JSON.parse(wireData);
|
|
510
|
+
} catch {
|
|
511
|
+
// Direct/fake event sources may already carry the unencoded id.
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (received === requestId) settle();
|
|
515
|
+
};
|
|
516
|
+
source.addEventListener(COMMAND_RESULT_RECEIPT_EVENT, onReceipt);
|
|
517
|
+
|
|
518
|
+
const resultPayload = { ...payload, _awaitCallerReceipt: true };
|
|
519
|
+
if (!source.send?.('command-result', resultPayload)) {
|
|
520
|
+
await postControl('command-result', resultPayload);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
524
|
+
let acknowledged = false;
|
|
525
|
+
await Promise.race([
|
|
526
|
+
receipt.then(() => {
|
|
527
|
+
acknowledged = true;
|
|
528
|
+
}),
|
|
529
|
+
new Promise<void>((resolve) => {
|
|
530
|
+
timer = setTimeout(resolve, CONTROL_RECEIPT_TIMEOUT_MS);
|
|
531
|
+
}),
|
|
532
|
+
]);
|
|
533
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
534
|
+
|
|
535
|
+
// NO RECEIPT MEANS THE RESULT DID NOT LAND — SO SEND IT AGAIN, OVER HTTP.
|
|
536
|
+
//
|
|
537
|
+
// This is the whole reason the receipt exists (see the docblock: `send()`
|
|
538
|
+
// only queues bytes), and until now nothing acted on its absence: the race
|
|
539
|
+
// simply expired and the page dropped an answer it was still holding. The
|
|
540
|
+
// caller then burned its entire command budget waiting for a result that had
|
|
541
|
+
// already been computed.
|
|
542
|
+
//
|
|
543
|
+
// MEASURED 2026-09-15 on `02-hinged-vise`: a `blender-read-file` was relayed
|
|
544
|
+
// 2.1 s before the socket closed 1006, the page reconnected, and the command
|
|
545
|
+
// failed at exactly 60.0 s — its budget — with the tab's last heartbeat
|
|
546
|
+
// 0.9 s old. The bytes went into a socket that died before the server read
|
|
547
|
+
// them, and `send()` had already returned true.
|
|
548
|
+
//
|
|
549
|
+
// Re-posting is safe to do blind: `settlePendingCommand` returns early when
|
|
550
|
+
// the request is no longer pending, so a duplicate result is a no-op, and
|
|
551
|
+
// the HTTP path does not depend on the socket that just died.
|
|
552
|
+
if (!acknowledged) await postControl('command-result', payload);
|
|
553
|
+
source.removeEventListener(COMMAND_RESULT_RECEIPT_EVENT, onReceipt);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/** Tell the local editor session which surface this tab is showing. */
|
|
557
|
+
export function reportTabRoute(route: EditorTabRoute): void {
|
|
558
|
+
void sendControl('tab-route', {
|
|
559
|
+
clientId: EDITOR_CLIENT_ID,
|
|
560
|
+
participantId: EDITOR_PARTICIPANT_ID,
|
|
561
|
+
route,
|
|
562
|
+
});
|
|
563
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Host visibility controls presentation work, never document ownership. */
|
|
2
|
+
interface PresentationActivity {
|
|
3
|
+
hostActive: boolean;
|
|
4
|
+
readonly listeners: Set<() => void>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// Existing renderer sessions can survive a replacement of this module. Keep
|
|
8
|
+
// their subscriptions and the host's last answer on the same shared object.
|
|
9
|
+
const hotData = import.meta.hot?.data;
|
|
10
|
+
const activity: PresentationActivity = hotData?.presentationActivity ?? {
|
|
11
|
+
hostActive: true,
|
|
12
|
+
listeners: new Set<() => void>(),
|
|
13
|
+
};
|
|
14
|
+
if (hotData) hotData.presentationActivity = activity;
|
|
15
|
+
|
|
16
|
+
export function isEditorPresentationActive(): boolean {
|
|
17
|
+
return activity.hostActive && (typeof document === 'undefined' || !document.hidden);
|
|
18
|
+
}
|
|
19
|
+
function changed(): void {
|
|
20
|
+
for (const listener of activity.listeners) listener();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const parentOrigin =
|
|
24
|
+
typeof document !== 'undefined' && document.referrer ? new URL(document.referrer).origin : null;
|
|
25
|
+
|
|
26
|
+
function receive(event: MessageEvent): void {
|
|
27
|
+
if (window.parent === window || event.source !== window.parent) return;
|
|
28
|
+
if (!parentOrigin || event.origin !== parentOrigin) return;
|
|
29
|
+
if (event.data?.type !== 'vgai:embed-activity' || typeof event.data.active !== 'boolean') return;
|
|
30
|
+
if (activity.hostActive === event.data.active) return;
|
|
31
|
+
activity.hostActive = event.data.active;
|
|
32
|
+
changed();
|
|
33
|
+
}
|
|
34
|
+
export function subscribeEditorPresentationActivity(listener: () => void): () => void {
|
|
35
|
+
activity.listeners.add(listener);
|
|
36
|
+
return () => {
|
|
37
|
+
activity.listeners.delete(listener);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (typeof window !== 'undefined') {
|
|
41
|
+
window.addEventListener('message', receive);
|
|
42
|
+
document.addEventListener('visibilitychange', changed);
|
|
43
|
+
if (window.parent !== window && parentOrigin) {
|
|
44
|
+
window.parent.postMessage({ type: 'vgai:request-embed-activity' }, parentOrigin);
|
|
45
|
+
}
|
|
46
|
+
import.meta.hot?.dispose(() => {
|
|
47
|
+
window.removeEventListener('message', receive);
|
|
48
|
+
document.removeEventListener('visibilitychange', changed);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { EditorView, PresentedEditorView } from '@volter/editor-sdk';
|
|
2
|
+
|
|
3
|
+
export interface EditorPresentationNotice {
|
|
4
|
+
readonly presented: PresentedEditorView;
|
|
5
|
+
readonly previousView: EditorView;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let notice: EditorPresentationNotice | null = null;
|
|
9
|
+
let version = 0;
|
|
10
|
+
const listeners = new Set<() => void>();
|
|
11
|
+
|
|
12
|
+
function publish(next: EditorPresentationNotice | null): void {
|
|
13
|
+
if (notice === next) return;
|
|
14
|
+
notice = next;
|
|
15
|
+
version++;
|
|
16
|
+
for (const listener of listeners) listener();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function editorPresentationNotice(): EditorPresentationNotice | null {
|
|
20
|
+
return notice;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function showEditorPresentationNotice(next: EditorPresentationNotice): void {
|
|
24
|
+
publish(next);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function clearEditorPresentationNotice(): void {
|
|
28
|
+
publish(null);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function subscribeEditorPresentationNotice(listener: () => void): () => void {
|
|
32
|
+
listeners.add(listener);
|
|
33
|
+
return () => listeners.delete(listener);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function editorPresentationNoticeVersion(): number {
|
|
37
|
+
return version;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function __resetEditorPresentationNoticeForTest(): void {
|
|
41
|
+
publish(null);
|
|
42
|
+
}
|