@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,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `.data.json` DIFF CONTRACT, server-side and unforkable.
|
|
3
|
+
*
|
|
4
|
+
* A data asset's editor UI ships as a COPIED capability (`data-tables`), and a
|
|
5
|
+
* copy can be edited — which is the point, and also the reason none of this
|
|
6
|
+
* may live there. Key order and `$schema`-first serialization are the property
|
|
7
|
+
* that keeps a one-cell edit a one-line git diff; a project that reorganized
|
|
8
|
+
* its own table UI must not be able to reorganize the file's bytes with it. So
|
|
9
|
+
* the client posts PARSED VALUES for a path (`POST /__editor/data-file` with
|
|
10
|
+
* `values`) and this module owns the fold from those values to the exact text
|
|
11
|
+
* written to disk.
|
|
12
|
+
*
|
|
13
|
+
* Ported verbatim (behavior, not shape) from the editor-side data panel that
|
|
14
|
+
* used to own it. Two facts drive every line here:
|
|
15
|
+
*
|
|
16
|
+
* 1. `JSON.parse` REINDEXES integer-like keys. A JS object enumerates "1",
|
|
17
|
+
* "2", "10" numerically-ascending no matter what order the file had, so
|
|
18
|
+
* "the order this file has on disk" can only be recovered from the raw
|
|
19
|
+
* TEXT, before parsing — {@link extractTopLevelKeyOrder}.
|
|
20
|
+
* 2. `JSON.stringify` of a spread-reordered object reindexes them again on the
|
|
21
|
+
* way out, so the writer emits keys one at a time in the caller's order —
|
|
22
|
+
* {@link serializeDataFile}.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/** Scan a (valid-JSON) string literal starting at the opening quote; returns the index just past the closing quote. */
|
|
26
|
+
function skipJsonString(text: string, i: number): number {
|
|
27
|
+
let j = i + 1;
|
|
28
|
+
while (j < text.length) {
|
|
29
|
+
const ch = text[j];
|
|
30
|
+
if (ch === '\\') {
|
|
31
|
+
j += 2;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (ch === '"') return j + 1;
|
|
35
|
+
j++;
|
|
36
|
+
}
|
|
37
|
+
return j;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Scan one JSON value (string/object/array/number/bool/null) starting at `i`; returns the index just past it. Assumes well-formed JSON (only ever called on text `JSON.parse` already accepted). */
|
|
41
|
+
function skipJsonValue(text: string, i: number): number {
|
|
42
|
+
const ch = text[i];
|
|
43
|
+
if (ch === '"') return skipJsonString(text, i);
|
|
44
|
+
if (ch === '{' || ch === '[') {
|
|
45
|
+
const close = ch === '{' ? '}' : ']';
|
|
46
|
+
let depth = 1;
|
|
47
|
+
let j = i + 1;
|
|
48
|
+
while (j < text.length && depth > 0) {
|
|
49
|
+
const c = text[j];
|
|
50
|
+
if (c === '"') {
|
|
51
|
+
j = skipJsonString(text, j);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (c === '{' || c === '[') depth++;
|
|
55
|
+
else if (c === close || c === '}' || c === ']') depth--;
|
|
56
|
+
j++;
|
|
57
|
+
}
|
|
58
|
+
return j;
|
|
59
|
+
}
|
|
60
|
+
// number / true / false / null — run until a structural character.
|
|
61
|
+
let j = i;
|
|
62
|
+
while (j < text.length && !/[,}\]\s]/.test(text[j]!)) j++;
|
|
63
|
+
return j;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Read a top-level JSON object's key order straight off the SOURCE TEXT — see
|
|
68
|
+
* fact #1 in the module header. Only ever called with text `JSON.parse`
|
|
69
|
+
* already accepted, so this can assume well-formed JSON throughout.
|
|
70
|
+
*/
|
|
71
|
+
export function extractTopLevelKeyOrder(text: string): string[] {
|
|
72
|
+
const keys: string[] = [];
|
|
73
|
+
let i = 0;
|
|
74
|
+
const n = text.length;
|
|
75
|
+
const skipWs = () => {
|
|
76
|
+
while (i < n && /\s/.test(text[i]!)) i++;
|
|
77
|
+
};
|
|
78
|
+
skipWs();
|
|
79
|
+
if (text[i] !== '{') return keys;
|
|
80
|
+
i++;
|
|
81
|
+
skipWs();
|
|
82
|
+
while (i < n && text[i] !== '}') {
|
|
83
|
+
if (text[i] !== '"') break;
|
|
84
|
+
const keyEnd = skipJsonString(text, i);
|
|
85
|
+
const key = JSON.parse(text.slice(i, keyEnd)) as string;
|
|
86
|
+
if (!keys.includes(key)) keys.push(key);
|
|
87
|
+
i = keyEnd;
|
|
88
|
+
skipWs();
|
|
89
|
+
if (text[i] !== ':') break;
|
|
90
|
+
i++;
|
|
91
|
+
skipWs();
|
|
92
|
+
i = skipJsonValue(text, i);
|
|
93
|
+
skipWs();
|
|
94
|
+
if (text[i] === ',') {
|
|
95
|
+
i++;
|
|
96
|
+
skipWs();
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
return keys;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Fold a commit's resulting keys into a stable order: `prevOrder` (the order
|
|
106
|
+
* the file currently has on disk) survives for every key still present, and
|
|
107
|
+
* any BRAND NEW key (add-row, a freshly-set nested field) is appended at the
|
|
108
|
+
* end in `Object.keys` order.
|
|
109
|
+
*/
|
|
110
|
+
export function nextKeyOrder(
|
|
111
|
+
prevOrder: string[] | undefined,
|
|
112
|
+
obj: Record<string, unknown>,
|
|
113
|
+
): string[] {
|
|
114
|
+
const existing = prevOrder ?? Object.keys(obj);
|
|
115
|
+
const kept = [...new Set(existing)].filter((k) => k in obj);
|
|
116
|
+
const added = Object.keys(obj).filter((k) => !existing.includes(k));
|
|
117
|
+
return [...kept, ...added];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Serialize per the diff-minimal contract: `"$schema"` first, then every other
|
|
122
|
+
* key in `keyOrder` (falling back to `Object.keys(obj)` when the caller has
|
|
123
|
+
* none — a brand-new file), 2-space indent, trailing newline. Emitting the
|
|
124
|
+
* object key by key is deliberate; see fact #2 in the module header.
|
|
125
|
+
*/
|
|
126
|
+
export function serializeDataFile(obj: Record<string, unknown>, keyOrder?: string[]): string {
|
|
127
|
+
const hasSchema = '$schema' in obj;
|
|
128
|
+
const rest = (keyOrder ?? Object.keys(obj)).filter((k) => k !== '$schema' && k in obj);
|
|
129
|
+
const order = hasSchema ? ['$schema', ...rest] : rest;
|
|
130
|
+
if (order.length === 0) return '{}\n';
|
|
131
|
+
const lines = order.map((k) => {
|
|
132
|
+
const valueJson = JSON.stringify(obj[k], null, 2);
|
|
133
|
+
return ` ${JSON.stringify(k)}: ${valueJson.split('\n').join('\n ')}`;
|
|
134
|
+
});
|
|
135
|
+
return `{\n${lines.join(',\n')}\n}\n`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* The whole server-side fold in one call: the file's CURRENT text (absent for
|
|
140
|
+
* a file that does not exist yet) plus the values the client posted, giving
|
|
141
|
+
* the exact bytes to write.
|
|
142
|
+
*/
|
|
143
|
+
export function foldDataFileText(
|
|
144
|
+
currentText: string | null,
|
|
145
|
+
values: Record<string, unknown>,
|
|
146
|
+
): string {
|
|
147
|
+
let prevOrder: string[] | undefined;
|
|
148
|
+
if (currentText !== null) {
|
|
149
|
+
try {
|
|
150
|
+
JSON.parse(currentText);
|
|
151
|
+
prevOrder = extractTopLevelKeyOrder(currentText);
|
|
152
|
+
} catch {
|
|
153
|
+
// Unparseable file on disk — nothing to carry, so the posted values
|
|
154
|
+
// define the order. Never a reason to refuse the write.
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return serializeDataFile(values, nextKeyOrder(prevOrder, values));
|
|
158
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EDITOR_BRAND,
|
|
3
|
+
editorAppIconSvg,
|
|
4
|
+
editorDocumentTitle,
|
|
5
|
+
} from '@volter/editor-sdk/session/editor-brand';
|
|
6
|
+
|
|
7
|
+
function escapeHtml(value: string): string {
|
|
8
|
+
return value.replace(
|
|
9
|
+
/[&<>"']/g,
|
|
10
|
+
(character) =>
|
|
11
|
+
({
|
|
12
|
+
'&': '&',
|
|
13
|
+
'<': '<',
|
|
14
|
+
'>': '>',
|
|
15
|
+
'"': '"',
|
|
16
|
+
"'": ''',
|
|
17
|
+
})[character] ?? character,
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface EditorBrandPageOptions {
|
|
22
|
+
readonly subject?: string;
|
|
23
|
+
readonly description: string;
|
|
24
|
+
/** Trusted, server-owned markup rendered inside the brand card. */
|
|
25
|
+
readonly contentHtml: string;
|
|
26
|
+
/** Trusted, server-owned script body. */
|
|
27
|
+
readonly scriptHtml?: string;
|
|
28
|
+
readonly socialPreview?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Render the editor's small server-owned HTML surfaces (auth, share, yield).
|
|
33
|
+
* These pages intentionally stay dependency-free because they also appear
|
|
34
|
+
* while the main editor bundle is unavailable.
|
|
35
|
+
*/
|
|
36
|
+
export function renderEditorBrandPage(options: EditorBrandPageOptions): string {
|
|
37
|
+
const title = editorDocumentTitle(options.subject);
|
|
38
|
+
const favicon = `data:image/svg+xml,${encodeURIComponent(editorAppIconSvg())}`;
|
|
39
|
+
const social = options.socialPreview
|
|
40
|
+
? `<meta property="og:type" content="website">
|
|
41
|
+
<meta property="og:site_name" content="${escapeHtml(EDITOR_BRAND.name)}">
|
|
42
|
+
<meta property="og:title" content="${escapeHtml(title)}">
|
|
43
|
+
<meta property="og:description" content="${escapeHtml(options.description)}">
|
|
44
|
+
|
|
45
|
+
<meta name="twitter:card" content="summary">
|
|
46
|
+
<meta name="twitter:title" content="${escapeHtml(title)}">
|
|
47
|
+
<meta name="twitter:description" content="${escapeHtml(options.description)}">
|
|
48
|
+
`
|
|
49
|
+
: '';
|
|
50
|
+
const script = options.scriptHtml ? `<script>${options.scriptHtml}</script>` : '';
|
|
51
|
+
return `<!doctype html>
|
|
52
|
+
<html lang="en">
|
|
53
|
+
<head>
|
|
54
|
+
<meta charset="utf-8">
|
|
55
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
56
|
+
<meta name="theme-color" content="${EDITOR_BRAND.themeColor}">
|
|
57
|
+
<meta name="robots" content="noindex,nofollow">
|
|
58
|
+
<meta name="description" content="${escapeHtml(options.description)}">
|
|
59
|
+
<link rel="icon" href="${favicon}" type="image/svg+xml">
|
|
60
|
+
<title>${escapeHtml(title)}</title>
|
|
61
|
+
${social}
|
|
62
|
+
<style>
|
|
63
|
+
:root{color-scheme:dark;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;background:${EDITOR_BRAND.themeColor};color:#e8edf3}
|
|
64
|
+
*{box-sizing:border-box}body{margin:0;min-height:100vh;display:grid;place-items:center;padding:24px;background:radial-gradient(circle at 50% 30%,#1c2a3a 0,${EDITOR_BRAND.themeColor} 52%,#0b0e13 100%)}
|
|
65
|
+
.brand-card{width:min(440px,100%);padding:34px;text-align:center;border:1px solid rgba(255,255,255,.1);border-radius:20px;background:rgba(23,28,35,.92);box-shadow:0 22px 60px rgba(0,0,0,.38)}
|
|
66
|
+
.brand-mark{width:68px;height:68px;margin:0 auto 20px}.brand-mark svg{display:block;width:100%;height:100%}h1{margin:0 0 10px;font-size:22px;line-height:1.25;color:#f4f6f8}p{margin:0;color:#aeb9c6;font-size:14px;line-height:1.6}
|
|
67
|
+
button,a.brand-action{display:inline-block;margin-top:20px;padding:9px 17px;border:1px solid #3a526c;border-radius:8px;background:#20354c;color:#eaf3ff;font:600 14px inherit;text-decoration:none;cursor:pointer}button:hover,a.brand-action:hover{background:#294561;border-color:${EDITOR_BRAND.accentColor}}
|
|
68
|
+
</style>
|
|
69
|
+
</head>
|
|
70
|
+
<body><main class="brand-card"><div class="brand-mark">${editorAppIconSvg()}</div>${options.contentHtml}</main>${script}</body>
|
|
71
|
+
</html>`;
|
|
72
|
+
}
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor tab's duplex control socket — a WebSocket upgrade on the SAME
|
|
3
|
+
* path as the SSE stream (`/__editor/events`), carrying the SAME named events
|
|
4
|
+
* downstream and the tab's control replies upstream.
|
|
5
|
+
*
|
|
6
|
+
* Why it exists (measured 2026-08-09): a cold editor boot blocked a real
|
|
7
|
+
* tab's main thread for 60-100s. A blocked main thread can neither issue nor
|
|
8
|
+
* answer a `fetch`, so every receipt/result/state POST stopped — and the
|
|
9
|
+
* relay, which could only see silence, refused five plays that all executed
|
|
10
|
+
* later. Two things fix that here:
|
|
11
|
+
*
|
|
12
|
+
* - Upstream control traffic rides the ALREADY-OPEN socket instead of
|
|
13
|
+
* opening new HTTP requests, so it never queues behind a module flood in
|
|
14
|
+
* the browser's per-origin connection pool.
|
|
15
|
+
* - Liveness stops being a guess. The browser's NETWORK stack answers
|
|
16
|
+
* protocol pings while the main thread is blocked, and the page's INLINE
|
|
17
|
+
* bootstrap (index.html, attached before any module loads) answers a
|
|
18
|
+
* `control-echo`. Pong-fresh + echo-silent is "alive but busy" as a
|
|
19
|
+
* measured fact; an unanswered echo can never mean "the listener was not
|
|
20
|
+
* wired up yet", because the responder exists before the module graph does.
|
|
21
|
+
*
|
|
22
|
+
* Deliberately no frame-rate or rendering signal: games legitimately run
|
|
23
|
+
* `frameloop: 'never'` and the engine hidden-pauses loops in a background
|
|
24
|
+
* tab, so anything rAF-shaped would read a healthy tab as dead.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import type { Server as HttpServer, IncomingMessage } from 'node:http';
|
|
28
|
+
import type { Duplex } from 'node:stream';
|
|
29
|
+
import {
|
|
30
|
+
type EditorControlLifecycle,
|
|
31
|
+
parseEditorControlLifecycle,
|
|
32
|
+
} from '@volter/editor-sdk/session/editor-control-lifecycle';
|
|
33
|
+
import { type WebSocket, WebSocketServer } from 'ws';
|
|
34
|
+
import type { EditorSocketClient } from './editor-sse';
|
|
35
|
+
|
|
36
|
+
/** The one path both transports answer on. */
|
|
37
|
+
export const EDITOR_EVENTS_PATH = '/__editor/events';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Protocol-ping cadence. Short enough that a pong age reported in a refusal
|
|
41
|
+
* is meaningful evidence ("answered 3s ago" = the socket is genuinely live),
|
|
42
|
+
* long enough to be invisible next to the keepalive it replaces.
|
|
43
|
+
*/
|
|
44
|
+
export const CONTROL_PING_INTERVAL_MS = 10_000;
|
|
45
|
+
|
|
46
|
+
/** How long the main-thread echo gets before it counts as unanswered. */
|
|
47
|
+
export const CONTROL_ECHO_TIMEOUT_MS = 1_000;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The socket ENDED WITH NO CLOSE FRAME — RFC 6455's 1006, which no endpoint is
|
|
51
|
+
* allowed to send and only an observer can synthesize. It is the shape a
|
|
52
|
+
* KILLED browser renderer process leaves behind (a tab that closes normally
|
|
53
|
+
* sends a frame), so it is also the discriminator the tab-death profile keys
|
|
54
|
+
* off. One owner of the literal: this file synthesizes it below,
|
|
55
|
+
* `editor-server.ts` reads it.
|
|
56
|
+
*/
|
|
57
|
+
export const ABNORMAL_SOCKET_CLOSE = 1006;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The capability frame. Sent ONLY over a native socket, never on the SSE
|
|
61
|
+
* stream — the share tunnel's gateway bridges the SSE stream into its own
|
|
62
|
+
* WebSocket, and that socket does NOT accept upstream control frames. A tab
|
|
63
|
+
* behind the tunnel therefore never sees this and keeps POSTing, which is
|
|
64
|
+
* exactly right.
|
|
65
|
+
*/
|
|
66
|
+
const DUPLEX_READY_EVENT = 'control-duplex';
|
|
67
|
+
|
|
68
|
+
export interface EditorControlConnection {
|
|
69
|
+
/** The pool handle for this socket. */
|
|
70
|
+
readonly client: EditorSocketClient;
|
|
71
|
+
/** The upgrade request's URL, for query parameters. */
|
|
72
|
+
readonly url: URL;
|
|
73
|
+
/** The raw upgrade request, for header-derived identity. */
|
|
74
|
+
readonly request: IncomingMessage;
|
|
75
|
+
/** Deliver one framed event before the client is pooled. */
|
|
76
|
+
send(event: string, data: string, id?: string): void;
|
|
77
|
+
/** Close the socket with a reason (rejected identity, session end). */
|
|
78
|
+
close(code: number, reason: string): void;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Another WebSocket path this session owns (the tab heartbeat).
|
|
83
|
+
*
|
|
84
|
+
* It rides the control socket's ONE `upgrade` listener rather than adding a
|
|
85
|
+
* second, because the fallthrough branch below has to know whether ANY editor
|
|
86
|
+
* path claimed the socket before it destroys it — and `listenerCount` cannot
|
|
87
|
+
* answer that once two of our own listeners are competing to say "not mine".
|
|
88
|
+
*/
|
|
89
|
+
export interface RawSocketRoute {
|
|
90
|
+
readonly path: string;
|
|
91
|
+
/** Same shape as the control socket's own gate; a string refuses with 403. */
|
|
92
|
+
authorize(request: IncomingMessage, url: URL): string | null;
|
|
93
|
+
open(socket: WebSocket, url: URL, request: IncomingMessage): void;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface EditorControlSocketOptions {
|
|
97
|
+
/**
|
|
98
|
+
* Reject the upgrade BEFORE the handshake. Return an error string to
|
|
99
|
+
* refuse (sent as a plain 403 body, the same shape the SSE route answers
|
|
100
|
+
* with), or null to accept.
|
|
101
|
+
*/
|
|
102
|
+
authorize(request: IncomingMessage, url: URL): string | null;
|
|
103
|
+
/**
|
|
104
|
+
* Register the open socket; the returned function runs once on close, and
|
|
105
|
+
* is handed the WebSocket close code/reason. Those two are the only honest
|
|
106
|
+
* answer to "why did this tab's channel go away" — the journal quotes them
|
|
107
|
+
* verbatim rather than inferring a story from the silence.
|
|
108
|
+
*/
|
|
109
|
+
open(connection: EditorControlConnection): (close?: { code: number; reason: string }) => void;
|
|
110
|
+
/** The duplex capability was granted to this socket (journalling hook). */
|
|
111
|
+
duplexGranted?(connection: EditorControlConnection): void;
|
|
112
|
+
/** One upstream control frame from the tab. */
|
|
113
|
+
message(
|
|
114
|
+
type: string,
|
|
115
|
+
payload: Record<string, unknown>,
|
|
116
|
+
connection: EditorControlConnection,
|
|
117
|
+
lifecycle: EditorControlLifecycle | null,
|
|
118
|
+
lifecycleMalformed: boolean,
|
|
119
|
+
): void;
|
|
120
|
+
/** Other WebSocket paths this one upgrade listener also routes. */
|
|
121
|
+
extraRoutes?: readonly RawSocketRoute[] | undefined;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface EditorControlSocketServer {
|
|
125
|
+
/**
|
|
126
|
+
* Handle `upgrade` on this HTTP server.
|
|
127
|
+
*
|
|
128
|
+
* Routes by PATHNAME and passes every other upgrade through untouched —
|
|
129
|
+
* Vite's HMR socket may share this server. When this is the only `upgrade`
|
|
130
|
+
* listener there is nobody to pass to, so the socket is destroyed, which is
|
|
131
|
+
* exactly what Node does by default with no listener at all.
|
|
132
|
+
*/
|
|
133
|
+
attach(server: HttpServer): void;
|
|
134
|
+
/** Close every live control socket (server shutdown). */
|
|
135
|
+
close(): void;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* One upstream `{ type, payload }` frame, or null if it is not one. A
|
|
140
|
+
* malformed frame is dropped, never partially read.
|
|
141
|
+
*
|
|
142
|
+
* The discriminator and the payload live in SEPARATE keys, and that
|
|
143
|
+
* separation is load-bearing in both directions. Flattened
|
|
144
|
+
* (`{ type, ...payload }`) the envelope leaked its own `type` into the state
|
|
145
|
+
* the server stored, so `vgai status` printed a field the tab never
|
|
146
|
+
* reported — on the exact seam this transport promises the POST route
|
|
147
|
+
* cannot drift from. And a payload key named `type` (a state snapshot is an
|
|
148
|
+
* open-ended object) would have overwritten the discriminator on the way
|
|
149
|
+
* out, turning a routine state report into an unknown control frame:
|
|
150
|
+
* dropped silently, health left stale, and the next refusal quoting a
|
|
151
|
+
* silence the tab never chose.
|
|
152
|
+
*/
|
|
153
|
+
function parseControlFrame(raw: unknown): {
|
|
154
|
+
type: string;
|
|
155
|
+
payload: Record<string, unknown>;
|
|
156
|
+
lifecycle: EditorControlLifecycle | null;
|
|
157
|
+
lifecycleMalformed: boolean;
|
|
158
|
+
} | null {
|
|
159
|
+
let frame: unknown;
|
|
160
|
+
try {
|
|
161
|
+
frame = JSON.parse(String(raw));
|
|
162
|
+
} catch {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
if (!frame || typeof frame !== 'object') return null;
|
|
166
|
+
const type = (frame as Record<string, unknown>)['type'];
|
|
167
|
+
if (typeof type !== 'string') return null;
|
|
168
|
+
const body = (frame as Record<string, unknown>)['payload'];
|
|
169
|
+
const rawLifecycle = (frame as Record<string, unknown>)['lifecycle'];
|
|
170
|
+
const lifecycle = parseEditorControlLifecycle(rawLifecycle);
|
|
171
|
+
return {
|
|
172
|
+
type,
|
|
173
|
+
payload: body && typeof body === 'object' ? (body as Record<string, unknown>) : {},
|
|
174
|
+
lifecycle,
|
|
175
|
+
lifecycleMalformed: rawLifecycle !== undefined && lifecycle === null,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function createEditorControlSocket(
|
|
180
|
+
options: EditorControlSocketOptions,
|
|
181
|
+
): EditorControlSocketServer {
|
|
182
|
+
const sockets = new WebSocketServer({ noServer: true });
|
|
183
|
+
|
|
184
|
+
const onUpgrade = (
|
|
185
|
+
server: HttpServer,
|
|
186
|
+
request: IncomingMessage,
|
|
187
|
+
socket: Duplex,
|
|
188
|
+
head: Buffer,
|
|
189
|
+
): void => {
|
|
190
|
+
let url: URL;
|
|
191
|
+
try {
|
|
192
|
+
url = new URL(request.url ?? '/', 'http://editor.local');
|
|
193
|
+
} catch {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const extra = (options.extraRoutes ?? []).find((route) => route.path === url.pathname);
|
|
197
|
+
if (extra) {
|
|
198
|
+
const extraRefusal = extra.authorize(request, url);
|
|
199
|
+
if (extraRefusal !== null) {
|
|
200
|
+
socket.end(
|
|
201
|
+
`HTTP/1.1 403 Forbidden\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\n${extraRefusal}`,
|
|
202
|
+
);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
sockets.handleUpgrade(request, socket, head, (ws) => extra.open(ws, url, request));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (url.pathname !== EDITOR_EVENTS_PATH) {
|
|
209
|
+
// Not ours. Another listener (Vite HMR, the share gateway) owns it — or
|
|
210
|
+
// nobody does, in which case leaving the socket open would leak it.
|
|
211
|
+
if (server.listenerCount('upgrade') <= 1) socket.destroy();
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const refusal = options.authorize(request, url);
|
|
215
|
+
if (refusal !== null) {
|
|
216
|
+
socket.end(
|
|
217
|
+
`HTTP/1.1 403 Forbidden\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\n${refusal}`,
|
|
218
|
+
);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
sockets.handleUpgrade(request, socket, head, (ws) => {
|
|
222
|
+
let closed = false;
|
|
223
|
+
let lastPongAt: number | null = null;
|
|
224
|
+
let echoSequence = 0;
|
|
225
|
+
const pendingEchoes = new Map<string, (answered: boolean) => void>();
|
|
226
|
+
|
|
227
|
+
const sendFrame = (event: string, data: string, id?: string): boolean => {
|
|
228
|
+
if (closed || ws.readyState !== ws.OPEN) return false;
|
|
229
|
+
try {
|
|
230
|
+
ws.send(JSON.stringify(id === undefined ? { event, data } : { event, data, id }));
|
|
231
|
+
return true;
|
|
232
|
+
} catch {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const client: EditorSocketClient = {
|
|
238
|
+
kind: 'socket',
|
|
239
|
+
sendFrame,
|
|
240
|
+
isClosed: () => closed || ws.readyState !== ws.OPEN,
|
|
241
|
+
lastPongAgeMs: () => (lastPongAt === null ? null : Date.now() - lastPongAt),
|
|
242
|
+
echo: (timeoutMs) =>
|
|
243
|
+
new Promise<boolean>((resolve) => {
|
|
244
|
+
if (closed || ws.readyState !== ws.OPEN) {
|
|
245
|
+
resolve(false);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const id = `echo-${++echoSequence}`;
|
|
249
|
+
const timer = setTimeout(() => {
|
|
250
|
+
pendingEchoes.delete(id);
|
|
251
|
+
resolve(false);
|
|
252
|
+
}, timeoutMs);
|
|
253
|
+
timer.unref?.();
|
|
254
|
+
pendingEchoes.set(id, (answered) => {
|
|
255
|
+
clearTimeout(timer);
|
|
256
|
+
resolve(answered);
|
|
257
|
+
});
|
|
258
|
+
if (!sendFrame('control-echo', id)) {
|
|
259
|
+
pendingEchoes.delete(id);
|
|
260
|
+
clearTimeout(timer);
|
|
261
|
+
resolve(false);
|
|
262
|
+
}
|
|
263
|
+
}),
|
|
264
|
+
close: (code, reason) => {
|
|
265
|
+
try {
|
|
266
|
+
ws.close(code, reason);
|
|
267
|
+
} catch {
|
|
268
|
+
/* The close event owns teardown if the socket is still alive. */
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
const connection: EditorControlConnection = {
|
|
274
|
+
client,
|
|
275
|
+
url,
|
|
276
|
+
request,
|
|
277
|
+
send: (event, data, id) => {
|
|
278
|
+
sendFrame(event, data, id);
|
|
279
|
+
},
|
|
280
|
+
close: (code, reason) => {
|
|
281
|
+
try {
|
|
282
|
+
ws.close(code, reason);
|
|
283
|
+
} catch {
|
|
284
|
+
/* already gone */
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const dispose = options.open(connection);
|
|
290
|
+
|
|
291
|
+
// Tell the page this socket takes upstream control frames. Only the
|
|
292
|
+
// native transport ever emits this (see DUPLEX_READY_EVENT).
|
|
293
|
+
if (sendFrame(DUPLEX_READY_EVENT, JSON.stringify({ ok: true }))) {
|
|
294
|
+
options.duplexGranted?.(connection);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Ping immediately so the first refusal in this connection's life can
|
|
298
|
+
// still quote a real pong age, then on the standing cadence.
|
|
299
|
+
ws.on('pong', () => {
|
|
300
|
+
lastPongAt = Date.now();
|
|
301
|
+
});
|
|
302
|
+
const ping = () => {
|
|
303
|
+
if (closed || ws.readyState !== ws.OPEN) return;
|
|
304
|
+
try {
|
|
305
|
+
ws.ping();
|
|
306
|
+
} catch {
|
|
307
|
+
/* the close handler owns teardown */
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
ping();
|
|
311
|
+
const pingTimer = setInterval(ping, CONTROL_PING_INTERVAL_MS);
|
|
312
|
+
pingTimer.unref?.();
|
|
313
|
+
|
|
314
|
+
ws.on('message', (raw) => {
|
|
315
|
+
const frame = parseControlFrame(raw);
|
|
316
|
+
if (!frame) return;
|
|
317
|
+
if (frame.type === 'echo-reply') {
|
|
318
|
+
const id = frame.payload['id'];
|
|
319
|
+
if (typeof id !== 'string') return;
|
|
320
|
+
pendingEchoes.get(id)?.(true);
|
|
321
|
+
pendingEchoes.delete(id);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
options.message(
|
|
325
|
+
frame.type,
|
|
326
|
+
frame.payload,
|
|
327
|
+
connection,
|
|
328
|
+
frame.lifecycle,
|
|
329
|
+
frame.lifecycleMalformed,
|
|
330
|
+
);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
const onClosed = (code?: number, reason?: Buffer | string) => {
|
|
334
|
+
if (closed) return;
|
|
335
|
+
closed = true;
|
|
336
|
+
clearInterval(pingTimer);
|
|
337
|
+
for (const settle of [...pendingEchoes.values()]) settle(false);
|
|
338
|
+
pendingEchoes.clear();
|
|
339
|
+
dispose({
|
|
340
|
+
code: typeof code === 'number' ? code : ABNORMAL_SOCKET_CLOSE,
|
|
341
|
+
reason: reason === undefined ? '' : String(reason),
|
|
342
|
+
});
|
|
343
|
+
};
|
|
344
|
+
ws.on('close', onClosed);
|
|
345
|
+
ws.on('error', () => onClosed());
|
|
346
|
+
});
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
attach(server) {
|
|
351
|
+
server.on('upgrade', (request, socket, head) =>
|
|
352
|
+
onUpgrade(server, request, socket as Duplex, head),
|
|
353
|
+
);
|
|
354
|
+
},
|
|
355
|
+
close() {
|
|
356
|
+
for (const ws of sockets.clients) {
|
|
357
|
+
try {
|
|
358
|
+
ws.close(1001, 'editor session ended');
|
|
359
|
+
} catch {
|
|
360
|
+
/* best effort */
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
sockets.close();
|
|
364
|
+
},
|
|
365
|
+
};
|
|
366
|
+
}
|