@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,477 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE HEARTBEAT TRANSPORT — a dedicated Worker in every editor tab, beating
|
|
3
|
+
* once a second over a socket of its own, and the server end that listens.
|
|
4
|
+
*
|
|
5
|
+
* WHY A WORKER, and not the page. Three properties, none of which the page's
|
|
6
|
+
* own control socket has:
|
|
7
|
+
*
|
|
8
|
+
* - It keeps beating while the page's MAIN THREAD IS BLOCKED. That is not a
|
|
9
|
+
* hypothetical: a cold editor boot blocked a real tab for 60-100s on
|
|
10
|
+
* 2026-08-09, and every conclusion the server drew during that window
|
|
11
|
+
* ("did not acknowledge", "disconnected") was wrong.
|
|
12
|
+
* - Its socket is NOT the page's socket, so a page-side reconnect, a Vite
|
|
13
|
+
* reload, or a module flood in the browser's per-origin connection pool
|
|
14
|
+
* cannot take presence down with it.
|
|
15
|
+
* - It DIES EXACTLY WHEN THE TAB DIES. A dedicated worker is owned by its
|
|
16
|
+
* document; close the tab and the beats stop within one interval. No
|
|
17
|
+
* unload handler to miss, no close code to interpret.
|
|
18
|
+
*
|
|
19
|
+
* WHY A STATIC SCRIPT the server hands out, rather than a bundled module: the
|
|
20
|
+
* worker must exist before the module graph does — that is the entire point —
|
|
21
|
+
* so it cannot be part of it. It is plain JS, dependency-free, served from
|
|
22
|
+
* this file's own constant so there is no build step and no file to lose in a
|
|
23
|
+
* packaged build.
|
|
24
|
+
*
|
|
25
|
+
* HIDDEN TABS. Chrome throttles timers in background pages and may throttle
|
|
26
|
+
* workers, so the cadence is NOT assumed to hold. Two things cover it: beats
|
|
27
|
+
* carry the page's last-known visibility (the server extends that tab's
|
|
28
|
+
* grace), and the server PROBES a tab whose beats have gapped. The worker
|
|
29
|
+
* answers a probe from its `message` handler, and message delivery is not
|
|
30
|
+
* throttled — so a hidden tab that is alive stays present indefinitely, and
|
|
31
|
+
* one that is not is departed on the evidence rather than on a guess.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import type { IncomingMessage } from 'node:http';
|
|
35
|
+
import type { WebSocket } from 'ws';
|
|
36
|
+
import type { BlenderTabMetrics } from '@volter/editor-sdk/project/tab-census';
|
|
37
|
+
import type { RawSocketRoute } from './editor-control-socket';
|
|
38
|
+
import type { TabBeat, TabCensus, TabCloseBeacon, TabVisibility } from './tab-presence';
|
|
39
|
+
|
|
40
|
+
/** The worker's own socket path — never the page's. */
|
|
41
|
+
export const TAB_HEARTBEAT_PATH = '/__editor/heartbeat';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Where a page's GOODBYE lands — `pagehide` → `navigator.sendBeacon`.
|
|
45
|
+
*
|
|
46
|
+
* A route of its own, and the tiniest one in the server, for the same reason
|
|
47
|
+
* the heartbeat POST is: it has to be deliverable by a document that is
|
|
48
|
+
* already gone. `sendBeacon` is the one transport the browser promises after
|
|
49
|
+
* unload, and it cannot read a response — so this route answers 204 and the
|
|
50
|
+
* page never learns whether it arrived. That is fine: a lost beacon degrades
|
|
51
|
+
* to `crashed`, which is what the server believed before this existed.
|
|
52
|
+
*/
|
|
53
|
+
export const TAB_CLOSE_PATH = '/__editor/tab/close';
|
|
54
|
+
|
|
55
|
+
/** Where the worker script itself is served from. */
|
|
56
|
+
export const TAB_HEARTBEAT_WORKER_PATH = '/__editor/tab-heartbeat.js';
|
|
57
|
+
|
|
58
|
+
/** The beat cadence the worker uses, and the number the grace is derived from. */
|
|
59
|
+
export const TAB_HEARTBEAT_INTERVAL_MS = 1_000;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The worker source, verbatim.
|
|
63
|
+
*
|
|
64
|
+
* Deliberately tiny and defensive: it is the one piece of this session that
|
|
65
|
+
* must keep running when everything else in the tab has stopped, so it has no
|
|
66
|
+
* imports, no optional chaining on hot paths, and no way to throw out of a
|
|
67
|
+
* timer. `fetch` is the fallback for every beat the socket cannot carry, and
|
|
68
|
+
* reconnection is forever with capped backoff — a heartbeat that gives up is
|
|
69
|
+
* a tab the server will declare departed while the user is looking at it.
|
|
70
|
+
*/
|
|
71
|
+
export const TAB_HEARTBEAT_WORKER_SOURCE = `/* vgai tab heartbeat — served by packages/editor/server/tab-heartbeat.ts */
|
|
72
|
+
'use strict';
|
|
73
|
+
var cfg = null;
|
|
74
|
+
var socket = null;
|
|
75
|
+
var seq = 0;
|
|
76
|
+
var visibility = 'visible';
|
|
77
|
+
var census = null;
|
|
78
|
+
/* undefined: nothing to say; { value } once the page announced a phase. */
|
|
79
|
+
var phase = undefined;
|
|
80
|
+
var retryMs = 250;
|
|
81
|
+
var beatTimer = null;
|
|
82
|
+
var stopped = false;
|
|
83
|
+
|
|
84
|
+
function body() {
|
|
85
|
+
seq += 1;
|
|
86
|
+
var frame = { tabId: cfg.tabId, epoch: cfg.epoch, seq: seq, visibility: visibility };
|
|
87
|
+
/* The page's latest resource profile rides along ONCE and is then dropped
|
|
88
|
+
(server/tab-presence.ts TabCensus). Carried, never sampled here: a worker
|
|
89
|
+
cannot see the document's canvases and performance.memory is a page
|
|
90
|
+
property.
|
|
91
|
+
|
|
92
|
+
WHY IT IS DROPPED — the invariant is that every census arriving at the
|
|
93
|
+
server is a sample the PAGE just took. Echoing the cache on every 1 Hz
|
|
94
|
+
beat made the server's filing stamp mean "the last beat that repeated the
|
|
95
|
+
cache", rather than "the last time the page measured", so a hidden
|
|
96
|
+
tab that stopped sampling half an hour ago still reported a half-second-
|
|
97
|
+
old profile, and the death line's age — whose entire job is to say a
|
|
98
|
+
stale profile is stale — was a plausible falsehood on exactly the path
|
|
99
|
+
that matters most (Chrome kills BACKGROUND tabs under memory pressure).
|
|
100
|
+
The page re-posts every 5s while visible and stops while hidden, so with
|
|
101
|
+
the cache cleared the age simply grows, truthfully.
|
|
102
|
+
|
|
103
|
+
A beat neither transport can deliver loses that one sample; the next is
|
|
104
|
+
5s behind it. Coarser, never a lie: the server stamps only what arrived. */
|
|
105
|
+
if (census !== null) {
|
|
106
|
+
frame.census = census;
|
|
107
|
+
census = null;
|
|
108
|
+
}
|
|
109
|
+
/* What the page's main thread is inside (or null: done), said once per
|
|
110
|
+
change. It rides the beat because the page's own socket cannot send
|
|
111
|
+
while the page is blocked — which is exactly when it matters. */
|
|
112
|
+
if (phase !== undefined) {
|
|
113
|
+
frame.phase = phase.value;
|
|
114
|
+
phase = undefined;
|
|
115
|
+
}
|
|
116
|
+
return frame;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function beat() {
|
|
120
|
+
if (stopped || cfg === null) return;
|
|
121
|
+
var frame = body();
|
|
122
|
+
if (socket !== null && socket.readyState === 1) {
|
|
123
|
+
try {
|
|
124
|
+
socket.send(JSON.stringify(frame));
|
|
125
|
+
return;
|
|
126
|
+
} catch (error) {
|
|
127
|
+
/* fall through to the POST */
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
fetch(cfg.postUrl, {
|
|
132
|
+
method: 'POST',
|
|
133
|
+
headers: { 'Content-Type': 'application/json' },
|
|
134
|
+
body: JSON.stringify(frame),
|
|
135
|
+
keepalive: true,
|
|
136
|
+
}).catch(function () {});
|
|
137
|
+
} catch (error) {
|
|
138
|
+
/* a beat that cannot be sent is a gap the server will see and say so */
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function connect() {
|
|
143
|
+
if (stopped || cfg === null) return;
|
|
144
|
+
var next;
|
|
145
|
+
try {
|
|
146
|
+
next = new WebSocket(cfg.socketUrl);
|
|
147
|
+
} catch (error) {
|
|
148
|
+
setTimeout(connect, retryMs);
|
|
149
|
+
retryMs = Math.min(5000, retryMs * 2);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
socket = next;
|
|
153
|
+
next.onopen = function () {
|
|
154
|
+
retryMs = 250;
|
|
155
|
+
beat();
|
|
156
|
+
};
|
|
157
|
+
next.onmessage = function (event) {
|
|
158
|
+
var frame;
|
|
159
|
+
try {
|
|
160
|
+
frame = JSON.parse(String(event.data));
|
|
161
|
+
} catch (error) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (!frame || typeof frame.type !== 'string') return;
|
|
165
|
+
/* A PROBE is answered right here, in the message handler. That is the
|
|
166
|
+
whole reason a probe exists: message delivery to a worker is not
|
|
167
|
+
throttled the way its timers are, so a hidden tab answers even when
|
|
168
|
+
its beat loop has been slowed to a crawl. */
|
|
169
|
+
if (frame.type === 'probe') {
|
|
170
|
+
beat();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
/* "Duplicate Tab" copied this tab's sessionStorage. The page mints a
|
|
174
|
+
fresh tabId and restarts us. */
|
|
175
|
+
if (frame.type === 're-mint') self.postMessage({ type: 're-mint' });
|
|
176
|
+
};
|
|
177
|
+
next.onclose = function () {
|
|
178
|
+
if (socket === next) socket = null;
|
|
179
|
+
if (stopped) return;
|
|
180
|
+
var wait = retryMs;
|
|
181
|
+
retryMs = Math.min(5000, retryMs * 2);
|
|
182
|
+
setTimeout(connect, wait);
|
|
183
|
+
};
|
|
184
|
+
next.onerror = function () {
|
|
185
|
+
try {
|
|
186
|
+
next.close();
|
|
187
|
+
} catch (error) {
|
|
188
|
+
/* onclose owns the retry */
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
self.onmessage = function (event) {
|
|
194
|
+
var message = event.data;
|
|
195
|
+
if (!message || typeof message !== 'object') return;
|
|
196
|
+
if (message.type === 'start') {
|
|
197
|
+
cfg = {
|
|
198
|
+
tabId: String(message.tabId),
|
|
199
|
+
epoch: String(message.epoch),
|
|
200
|
+
socketUrl: String(message.socketUrl),
|
|
201
|
+
postUrl: String(message.postUrl),
|
|
202
|
+
};
|
|
203
|
+
seq = 0;
|
|
204
|
+
stopped = false;
|
|
205
|
+
if (beatTimer !== null) clearInterval(beatTimer);
|
|
206
|
+
beatTimer = setInterval(beat, ${TAB_HEARTBEAT_INTERVAL_MS});
|
|
207
|
+
connect();
|
|
208
|
+
beat();
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (message.type === 'visibility') {
|
|
212
|
+
visibility = message.visibility === 'hidden' ? 'hidden' : 'visible';
|
|
213
|
+
beat();
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
/* A fresh resource profile from the page. Stored, NOT beaten on: the next
|
|
217
|
+
beat is at most a second away and an extra frame per sample would be
|
|
218
|
+
traffic bought for nothing. */
|
|
219
|
+
if (message.type === 'census') {
|
|
220
|
+
census = message.census === null || typeof message.census !== 'object' ? null : message.census;
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (message.type === 'phase') {
|
|
224
|
+
phase = { value: typeof message.phase === 'string' ? message.phase : null };
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (message.type === 'stop') {
|
|
228
|
+
stopped = true;
|
|
229
|
+
if (beatTimer !== null) clearInterval(beatTimer);
|
|
230
|
+
beatTimer = null;
|
|
231
|
+
if (socket !== null) {
|
|
232
|
+
try {
|
|
233
|
+
socket.close();
|
|
234
|
+
} catch (error) {
|
|
235
|
+
/* going away regardless */
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
`;
|
|
241
|
+
|
|
242
|
+
/** A finite number, or null for anything else (including NaN and a string). */
|
|
243
|
+
function finite(raw: unknown): number | null {
|
|
244
|
+
return typeof raw === 'number' && Number.isFinite(raw) ? raw : null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The Blender block on a census, or undefined when the beat carried none (the
|
|
249
|
+
* usual case — a tab with no Blender session).
|
|
250
|
+
*
|
|
251
|
+
* Parsed with the same posture as the rest of this file: a field the page could
|
|
252
|
+
* not measure stays NULL (no call yet, no Long Tasks API), and the block as a
|
|
253
|
+
* whole is dropped rather than half-filed if the counters are not numbers. A
|
|
254
|
+
* malformed block must never cost the census it rode in on.
|
|
255
|
+
*/
|
|
256
|
+
function parseBlender(raw: unknown): BlenderTabMetrics | undefined {
|
|
257
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) return undefined;
|
|
258
|
+
const record = raw as Record<string, unknown>;
|
|
259
|
+
const callsOver5s = finite(record['callsOver5s']);
|
|
260
|
+
const callsOver30s = finite(record['callsOver30s']);
|
|
261
|
+
const tasksOver100ms = finite(record['tasksOver100ms']);
|
|
262
|
+
if (callsOver5s === null || callsOver30s === null || tasksOver100ms === null) return undefined;
|
|
263
|
+
return {
|
|
264
|
+
inFlightMs: finite(record['inFlightMs']),
|
|
265
|
+
lastCallMs: finite(record['lastCallMs']),
|
|
266
|
+
maxCallMs: finite(record['maxCallMs']),
|
|
267
|
+
callsOver5s,
|
|
268
|
+
callsOver30s,
|
|
269
|
+
longestTaskMs: finite(record['longestTaskMs']),
|
|
270
|
+
tasksOver100ms,
|
|
271
|
+
lastCallLongestTaskMs: finite(record['lastCallLongestTaskMs']),
|
|
272
|
+
wasmMemoryMB: finite(record['wasmMemoryMB']),
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* The resource profile carried on a beat, or null when the frame has none.
|
|
278
|
+
*
|
|
279
|
+
* Strict about the two fields that are always measurable (`canvases`,
|
|
280
|
+
* `canvasMB`) and honest about the rest: a heap the browser will not report
|
|
281
|
+
* stays null, and a renderer count the page could not read stays ABSENT. A
|
|
282
|
+
* zero here would read as "no textures", which is a different claim from
|
|
283
|
+
* "nobody measured".
|
|
284
|
+
*/
|
|
285
|
+
export function parseCensus(raw: unknown): TabCensus | null {
|
|
286
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) return null;
|
|
287
|
+
const record = raw as Record<string, unknown>;
|
|
288
|
+
const canvases = finite(record['canvases']);
|
|
289
|
+
const canvasMB = finite(record['canvasMB']);
|
|
290
|
+
const mountEpochs = finite(record['mountEpochs']);
|
|
291
|
+
if (canvases === null || canvasMB === null || mountEpochs === null) return null;
|
|
292
|
+
const textures = finite(record['textures']);
|
|
293
|
+
const geometries = finite(record['geometries']);
|
|
294
|
+
const programs = finite(record['programs']);
|
|
295
|
+
const blender = parseBlender(record['blender']);
|
|
296
|
+
return {
|
|
297
|
+
heapUsedMB: finite(record['heapUsedMB']),
|
|
298
|
+
heapLimitMB: finite(record['heapLimitMB']),
|
|
299
|
+
mountEpochs,
|
|
300
|
+
canvases,
|
|
301
|
+
canvasMB,
|
|
302
|
+
...(textures === null ? {} : { textures }),
|
|
303
|
+
...(geometries === null ? {} : { geometries }),
|
|
304
|
+
...(programs === null ? {} : { programs }),
|
|
305
|
+
...(blender === undefined ? {} : { blender }),
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** One close beacon, or null when the payload is not one. `persisted` defaults
|
|
310
|
+
* to false: an absent flag is "the page did not say it was cached", never a
|
|
311
|
+
* guess that it was. `reason` defaults to `'pagehide'` for the same reason and
|
|
312
|
+
* one more — that is what index.html's bootstrap beacon has always meant, and
|
|
313
|
+
* it keeps that beacon unchanged. Only the exact word `'session-ended'` is an
|
|
314
|
+
* acknowledgement; anything else is a page going away. */
|
|
315
|
+
export function parseTabClose(raw: unknown): TabCloseBeacon | null {
|
|
316
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) return null;
|
|
317
|
+
const record = raw as Record<string, unknown>;
|
|
318
|
+
const tabId = record['tabId'];
|
|
319
|
+
const epoch = record['epoch'];
|
|
320
|
+
if (typeof tabId !== 'string' || tabId === '' || typeof epoch !== 'string' || epoch === '') {
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
return {
|
|
324
|
+
tabId,
|
|
325
|
+
epoch,
|
|
326
|
+
persisted: record['persisted'] === true,
|
|
327
|
+
reason: record['reason'] === 'session-ended' ? 'session-ended' : 'pagehide',
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** One beat frame, or null when the payload is not one. */
|
|
332
|
+
export function parseBeat(raw: unknown): TabBeat | null {
|
|
333
|
+
// A socket frame arrives as a Buffer, which IS an object — so "already an
|
|
334
|
+
// object, use it as-is" has to exclude binary or every WebSocket beat is
|
|
335
|
+
// read as an empty record and silently dropped. Only a POST body (already
|
|
336
|
+
// JSON-parsed by express) takes the fast path.
|
|
337
|
+
const isParsedBody =
|
|
338
|
+
typeof raw === 'object' &&
|
|
339
|
+
raw !== null &&
|
|
340
|
+
!Array.isArray(raw) &&
|
|
341
|
+
!ArrayBuffer.isView(raw) &&
|
|
342
|
+
!(raw instanceof ArrayBuffer);
|
|
343
|
+
let frame: unknown;
|
|
344
|
+
try {
|
|
345
|
+
frame = isParsedBody ? raw : JSON.parse(String(raw));
|
|
346
|
+
} catch {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
if (!frame || typeof frame !== 'object') return null;
|
|
350
|
+
const record = frame as Record<string, unknown>;
|
|
351
|
+
const tabId = record['tabId'];
|
|
352
|
+
const epoch = record['epoch'];
|
|
353
|
+
if (typeof tabId !== 'string' || tabId === '' || typeof epoch !== 'string' || epoch === '') {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
const visibility: TabVisibility = record['visibility'] === 'hidden' ? 'hidden' : 'visible';
|
|
357
|
+
const seq = Number(record['seq']);
|
|
358
|
+
const census = parseCensus(record['census']);
|
|
359
|
+
const rawPhase = record['phase'];
|
|
360
|
+
const phase = rawPhase === null || typeof rawPhase === 'string' ? rawPhase : undefined;
|
|
361
|
+
return {
|
|
362
|
+
tabId,
|
|
363
|
+
epoch,
|
|
364
|
+
seq: Number.isSafeInteger(seq) ? seq : 0,
|
|
365
|
+
visibility,
|
|
366
|
+
// A malformed census must never cost a beat: presence is the beat's job,
|
|
367
|
+
// and the profile is a passenger.
|
|
368
|
+
...(census === null ? {} : { census }),
|
|
369
|
+
...(phase === undefined ? {} : { phase }),
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export interface TabHeartbeatOptions {
|
|
374
|
+
/** Same origin gate the control-socket upgrade uses. */
|
|
375
|
+
authorize(request: IncomingMessage, url: URL): string | null;
|
|
376
|
+
/**
|
|
377
|
+
* One beat. Returns `'re-mint'` when this tab's sessionStorage was copied
|
|
378
|
+
* and the sender must take a fresh identity.
|
|
379
|
+
*/
|
|
380
|
+
beat(beat: TabBeat): 're-mint' | null;
|
|
381
|
+
/** A heartbeat socket opened or closed (a reconcile hint, never a verdict). */
|
|
382
|
+
hint?(): void;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export interface TabHeartbeatServer extends RawSocketRoute {
|
|
386
|
+
/**
|
|
387
|
+
* Ask every tab whose beats have gapped to answer NOW. Called by the
|
|
388
|
+
* reconciler, not by a timer of its own — probing is a question the TABLE
|
|
389
|
+
* asks, so the table decides who is worth asking.
|
|
390
|
+
*/
|
|
391
|
+
probe(tabIds: readonly string[]): void;
|
|
392
|
+
/** How many heartbeat sockets this tab currently holds (diagnostics/tests). */
|
|
393
|
+
socketCount(tabId: string): number;
|
|
394
|
+
close(): void;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* The server end. It owns sockets and nothing else: every beat goes straight
|
|
399
|
+
* to `options.beat`, and no presence decision is made here. That separation
|
|
400
|
+
* is the point — a transport that also decided would be a second opinion
|
|
401
|
+
* about who is present, and two opinions is exactly the bug this replaces.
|
|
402
|
+
*/
|
|
403
|
+
export function createTabHeartbeatServer(options: TabHeartbeatOptions): TabHeartbeatServer {
|
|
404
|
+
const socketsByTab = new Map<string, Set<WebSocket>>();
|
|
405
|
+
|
|
406
|
+
const forget = (tabId: string, socket: WebSocket): void => {
|
|
407
|
+
const set = socketsByTab.get(tabId);
|
|
408
|
+
if (!set) return;
|
|
409
|
+
set.delete(socket);
|
|
410
|
+
if (set.size === 0) socketsByTab.delete(tabId);
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
return {
|
|
414
|
+
path: TAB_HEARTBEAT_PATH,
|
|
415
|
+
authorize: options.authorize,
|
|
416
|
+
open(socket, url) {
|
|
417
|
+
const declaredTabId = url.searchParams.get('tabId') ?? '';
|
|
418
|
+
let tabId = declaredTabId;
|
|
419
|
+
if (tabId !== '') {
|
|
420
|
+
const set = socketsByTab.get(tabId) ?? new Set<WebSocket>();
|
|
421
|
+
set.add(socket);
|
|
422
|
+
socketsByTab.set(tabId, set);
|
|
423
|
+
}
|
|
424
|
+
options.hint?.();
|
|
425
|
+
socket.on('message', (raw) => {
|
|
426
|
+
const beat = parseBeat(raw);
|
|
427
|
+
if (beat === null) return;
|
|
428
|
+
if (beat.tabId !== tabId) {
|
|
429
|
+
if (tabId !== '') forget(tabId, socket);
|
|
430
|
+
tabId = beat.tabId;
|
|
431
|
+
const set = socketsByTab.get(tabId) ?? new Set<WebSocket>();
|
|
432
|
+
set.add(socket);
|
|
433
|
+
socketsByTab.set(tabId, set);
|
|
434
|
+
}
|
|
435
|
+
if (options.beat(beat) === 're-mint') {
|
|
436
|
+
try {
|
|
437
|
+
socket.send(JSON.stringify({ type: 're-mint' }));
|
|
438
|
+
} catch {
|
|
439
|
+
/* the tab will re-mint on its next beat, or depart */
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
const onClosed = (): void => {
|
|
444
|
+
if (tabId !== '') forget(tabId, socket);
|
|
445
|
+
options.hint?.();
|
|
446
|
+
};
|
|
447
|
+
socket.on('close', onClosed);
|
|
448
|
+
socket.on('error', onClosed);
|
|
449
|
+
},
|
|
450
|
+
probe(tabIds) {
|
|
451
|
+
for (const tabId of tabIds) {
|
|
452
|
+
for (const socket of socketsByTab.get(tabId) ?? []) {
|
|
453
|
+
try {
|
|
454
|
+
socket.send(JSON.stringify({ type: 'probe' }));
|
|
455
|
+
} catch {
|
|
456
|
+
/* an unsendable probe is a gap the table already sees */
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
socketCount(tabId) {
|
|
462
|
+
return socketsByTab.get(tabId)?.size ?? 0;
|
|
463
|
+
},
|
|
464
|
+
close() {
|
|
465
|
+
for (const set of socketsByTab.values()) {
|
|
466
|
+
for (const socket of set) {
|
|
467
|
+
try {
|
|
468
|
+
socket.close(1001, 'editor session ended');
|
|
469
|
+
} catch {
|
|
470
|
+
/* best effort */
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
socketsByTab.clear();
|
|
475
|
+
},
|
|
476
|
+
};
|
|
477
|
+
}
|