@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,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folder preview content discovery.
|
|
3
|
+
*
|
|
4
|
+
* Scans a project folder (breadth-first, via the storage-backend-agnostic
|
|
5
|
+
* `listAssets`) and picks up to four representative assets whose thumbnails a
|
|
6
|
+
* folder tile can composite. Selection ranks candidates in two tiers —
|
|
7
|
+
* tier 1 renders a real content thumbnail ('model', 'image' — including
|
|
8
|
+
* capability-kind 'source' files whose extension the model-thumbnail pipeline
|
|
9
|
+
* can render, see FOLDER_PREVIEW_MODEL_EXTENSIONS), tier 2 renders a
|
|
10
|
+
* synthetic glyph ('audio', 'prefab', 'json') — preferring
|
|
11
|
+
* tier 1, then shallower depth, then breadth-first directory listing order.
|
|
12
|
+
*
|
|
13
|
+
* Variety heuristic: within a tier, a first pass takes at most one candidate
|
|
14
|
+
* per top-level subtree (the candidate's first path segment below the scanned
|
|
15
|
+
* folder — a file directly inside the folder is its own subtree); remaining
|
|
16
|
+
* slots are then filled from that tier in rank order. Tier 1 is exhausted
|
|
17
|
+
* (both passes) before tier 2 is consulted, so tier preference dominates
|
|
18
|
+
* variety.
|
|
19
|
+
*
|
|
20
|
+
* Termination: the traversal itself never early-stops on item count — it
|
|
21
|
+
* walks everything the safety caps allow so `totalAssets` stays a useful
|
|
22
|
+
* count, and item selection runs over the collected candidates afterwards.
|
|
23
|
+
* `scannedAll` is false exactly when a cap (depth or listing budget) hid part
|
|
24
|
+
* of the tree, letting the UI render an "N+" style count.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { type AssetEntry, listAssets as defaultListAssets, type Listing } from '../editor-api';
|
|
28
|
+
import { type AssetCapabilityKind, assetCapabilities } from './asset-capabilities';
|
|
29
|
+
|
|
30
|
+
/** Maximum number of preview items a folder summary carries. */
|
|
31
|
+
export const FOLDER_PREVIEW_MAX_ITEMS = 4;
|
|
32
|
+
/** Maximum directory depth entered below the scanned folder (folder itself = 0). */
|
|
33
|
+
export const FOLDER_PREVIEW_MAX_DEPTH = 4;
|
|
34
|
+
/** Maximum number of directory listings a single scan may perform. */
|
|
35
|
+
export const FOLDER_PREVIEW_MAX_LISTINGS = 24;
|
|
36
|
+
/** Bound on concurrent `listAssets` calls within one scan. */
|
|
37
|
+
export const FOLDER_PREVIEW_LIST_CONCURRENCY = 4;
|
|
38
|
+
/** Bound on concurrent scans across all `getFolderPreview` callers. */
|
|
39
|
+
export const FOLDER_PREVIEW_SCAN_CONCURRENCY = 3;
|
|
40
|
+
|
|
41
|
+
/** Kinds that render a real content thumbnail. */
|
|
42
|
+
export const FOLDER_PREVIEW_TIER1_KINDS: ReadonlySet<AssetCapabilityKind> = new Set([
|
|
43
|
+
'model',
|
|
44
|
+
'image',
|
|
45
|
+
]);
|
|
46
|
+
/**
|
|
47
|
+
* File extensions the model-thumbnail pipeline can render live. Some of these
|
|
48
|
+
* are kind 'source' in the capability registry (fbx/obj/dae/stl/ply/3ds/bvh),
|
|
49
|
+
* but they still produce a real content thumbnail, so folder scans promote
|
|
50
|
+
* them to tier-1 'model' candidates. Kept as a local list — importing
|
|
51
|
+
* `modelThumbnailFormat` would drag three.js into this data-only module — and
|
|
52
|
+
* pinned against `modelThumbnailFormat`'s supported set by a test.
|
|
53
|
+
*/
|
|
54
|
+
export const FOLDER_PREVIEW_MODEL_EXTENSIONS: ReadonlySet<string> = new Set([
|
|
55
|
+
'glb',
|
|
56
|
+
'gltf',
|
|
57
|
+
'fbx',
|
|
58
|
+
'obj',
|
|
59
|
+
'dae',
|
|
60
|
+
'stl',
|
|
61
|
+
'ply',
|
|
62
|
+
'spz',
|
|
63
|
+
'bvh',
|
|
64
|
+
'3ds',
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
function hasPreviewableModelExtension(name: string): boolean {
|
|
68
|
+
const dot = name.lastIndexOf('.');
|
|
69
|
+
return dot > 0 && FOLDER_PREVIEW_MODEL_EXTENSIONS.has(name.slice(dot + 1).toLowerCase());
|
|
70
|
+
}
|
|
71
|
+
/** Kinds that render a synthetic glyph thumbnail. */
|
|
72
|
+
export const FOLDER_PREVIEW_TIER2_KINDS: ReadonlySet<AssetCapabilityKind> = new Set([
|
|
73
|
+
'audio',
|
|
74
|
+
'video',
|
|
75
|
+
'prefab',
|
|
76
|
+
'json',
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
export interface FolderPreviewItem {
|
|
80
|
+
/** Path relative to the asset root — usable directly to build the asset URL. */
|
|
81
|
+
path: string;
|
|
82
|
+
name: string;
|
|
83
|
+
kind: AssetCapabilityKind;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface FolderPreviewSummary {
|
|
87
|
+
items: FolderPreviewItem[];
|
|
88
|
+
/** Every non-hidden file seen by the (possibly capped) traversal. */
|
|
89
|
+
totalAssets: number;
|
|
90
|
+
/** False when a safety cap truncated the traversal (render counts as "N+"). */
|
|
91
|
+
scannedAll: boolean;
|
|
92
|
+
/** How many directory listings FAILED during the scan. Non-zero means this
|
|
93
|
+
* summary under-reports for a reason that is not "the folder is empty" —
|
|
94
|
+
* the counts below it are a floor, not a measurement. */
|
|
95
|
+
failedListings: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface FolderPreviewOptions {
|
|
99
|
+
/** Injectable listing function (tests); defaults to the editor API. */
|
|
100
|
+
listAssets?: (root: string, dir: string) => Promise<Listing<AssetEntry>>;
|
|
101
|
+
maxItems?: number;
|
|
102
|
+
maxDepth?: number;
|
|
103
|
+
maxListings?: number;
|
|
104
|
+
listConcurrency?: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Minimal FIFO limiter bounding how many tasks run concurrently. */
|
|
108
|
+
function createLimiter(concurrency: number): <T>(task: () => Promise<T>) => Promise<T> {
|
|
109
|
+
let active = 0;
|
|
110
|
+
const waiting: Array<() => void> = [];
|
|
111
|
+
return async <T>(task: () => Promise<T>): Promise<T> => {
|
|
112
|
+
if (active >= concurrency) await new Promise<void>((release) => waiting.push(release));
|
|
113
|
+
active++;
|
|
114
|
+
try {
|
|
115
|
+
return await task();
|
|
116
|
+
} finally {
|
|
117
|
+
active--;
|
|
118
|
+
waiting.shift()?.();
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function normalizeFolderPath(path: string): string {
|
|
124
|
+
// Strip only explicit `./` and `/` prefixes — a bare `[./]+` class would eat
|
|
125
|
+
// the leading dot of a real top-level dot-folder name (`.generated` →
|
|
126
|
+
// `generated`: wrong directory AND a cache-key collision with `generated`).
|
|
127
|
+
return path.replace(/^(?:\.\/|\/)+/, '').replace(/\/+$/, '');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** First path segment below the scanned folder; a direct file is its own subtree. */
|
|
131
|
+
function subtreeKey(base: string, path: string): string {
|
|
132
|
+
const relative = base ? path.slice(base.length + 1) : path;
|
|
133
|
+
return relative.split('/', 1)[0] ?? relative;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
interface Candidate extends FolderPreviewItem {
|
|
137
|
+
tier: 1 | 2;
|
|
138
|
+
depth: number;
|
|
139
|
+
seq: number;
|
|
140
|
+
subtree: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function rank(a: Candidate, b: Candidate): number {
|
|
144
|
+
return a.tier - b.tier || a.depth - b.depth || a.seq - b.seq;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Variety pass (one candidate per subtree) then a fill pass, both in rank order. */
|
|
148
|
+
function pickFromTier(
|
|
149
|
+
tierList: Candidate[],
|
|
150
|
+
picked: Candidate[],
|
|
151
|
+
usedSubtrees: Set<string>,
|
|
152
|
+
maxItems: number,
|
|
153
|
+
): void {
|
|
154
|
+
for (const candidate of tierList) {
|
|
155
|
+
if (picked.length >= maxItems) break;
|
|
156
|
+
if (usedSubtrees.has(candidate.subtree)) continue;
|
|
157
|
+
usedSubtrees.add(candidate.subtree);
|
|
158
|
+
picked.push(candidate);
|
|
159
|
+
}
|
|
160
|
+
for (const candidate of tierList) {
|
|
161
|
+
if (picked.length >= maxItems) break;
|
|
162
|
+
if (!picked.includes(candidate)) picked.push(candidate);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function selectItems(candidates: Candidate[], maxItems: number): FolderPreviewItem[] {
|
|
167
|
+
const sorted = [...candidates].sort(rank);
|
|
168
|
+
const picked: Candidate[] = [];
|
|
169
|
+
const usedSubtrees = new Set<string>();
|
|
170
|
+
for (const tier of [1, 2] as const) {
|
|
171
|
+
const tierList = sorted.filter((candidate) => candidate.tier === tier);
|
|
172
|
+
pickFromTier(tierList, picked, usedSubtrees, maxItems);
|
|
173
|
+
}
|
|
174
|
+
picked.sort(rank);
|
|
175
|
+
return picked.map(({ path, name, kind }) => ({ path, name, kind }));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function previewTier(kind: AssetCapabilityKind): 0 | 1 | 2 {
|
|
179
|
+
if (FOLDER_PREVIEW_TIER1_KINDS.has(kind)) return 1;
|
|
180
|
+
return FOLDER_PREVIEW_TIER2_KINDS.has(kind) ? 2 : 0;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
interface PendingDir {
|
|
184
|
+
dir: string;
|
|
185
|
+
depth: number;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
interface ScanState {
|
|
189
|
+
base: string;
|
|
190
|
+
maxDepth: number;
|
|
191
|
+
candidates: Candidate[];
|
|
192
|
+
totalAssets: number;
|
|
193
|
+
truncated: boolean;
|
|
194
|
+
failedListings: number;
|
|
195
|
+
seq: number;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Fold one directory listing into the scan, queueing subdirectories on `next`. */
|
|
199
|
+
function ingestListing(
|
|
200
|
+
state: ScanState,
|
|
201
|
+
entry: PendingDir,
|
|
202
|
+
assets: AssetEntry[],
|
|
203
|
+
next: PendingDir[],
|
|
204
|
+
): void {
|
|
205
|
+
for (const asset of assets) {
|
|
206
|
+
if (asset.name.startsWith('.')) continue; // hidden, including .vgai
|
|
207
|
+
const path = entry.dir ? `${entry.dir}/${asset.name}` : asset.name;
|
|
208
|
+
if (asset.type === 'directory') {
|
|
209
|
+
if (entry.depth + 1 > state.maxDepth) state.truncated = true;
|
|
210
|
+
else next.push({ dir: path, depth: entry.depth + 1 });
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
state.totalAssets++;
|
|
214
|
+
const kind = hasPreviewableModelExtension(asset.name)
|
|
215
|
+
? 'model'
|
|
216
|
+
: assetCapabilities(asset.name).kind;
|
|
217
|
+
const tier = previewTier(kind);
|
|
218
|
+
if (tier === 0) continue;
|
|
219
|
+
state.candidates.push({
|
|
220
|
+
path,
|
|
221
|
+
name: asset.name,
|
|
222
|
+
kind,
|
|
223
|
+
tier,
|
|
224
|
+
depth: entry.depth,
|
|
225
|
+
seq: state.seq++,
|
|
226
|
+
subtree: subtreeKey(state.base, path),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Breadth-first scan of `folderPath` (relative to `root`) producing a
|
|
233
|
+
* deterministic preview summary. Hidden entries (leading '.', including
|
|
234
|
+
* `.vgai`) are skipped entirely; safety caps bound depth and listing count.
|
|
235
|
+
*/
|
|
236
|
+
export async function collectFolderPreview(
|
|
237
|
+
root: string,
|
|
238
|
+
folderPath: string,
|
|
239
|
+
options: FolderPreviewOptions = {},
|
|
240
|
+
): Promise<FolderPreviewSummary> {
|
|
241
|
+
const list = options.listAssets ?? defaultListAssets;
|
|
242
|
+
const maxItems = options.maxItems ?? FOLDER_PREVIEW_MAX_ITEMS;
|
|
243
|
+
const maxListings = options.maxListings ?? FOLDER_PREVIEW_MAX_LISTINGS;
|
|
244
|
+
const limit = createLimiter(options.listConcurrency ?? FOLDER_PREVIEW_LIST_CONCURRENCY);
|
|
245
|
+
const base = normalizeFolderPath(folderPath);
|
|
246
|
+
const state: ScanState = {
|
|
247
|
+
base,
|
|
248
|
+
maxDepth: options.maxDepth ?? FOLDER_PREVIEW_MAX_DEPTH,
|
|
249
|
+
candidates: [],
|
|
250
|
+
totalAssets: 0,
|
|
251
|
+
truncated: false,
|
|
252
|
+
failedListings: 0,
|
|
253
|
+
seq: 0,
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
let listings = 0;
|
|
257
|
+
let level: PendingDir[] = [{ dir: base, depth: 0 }];
|
|
258
|
+
while (level.length > 0) {
|
|
259
|
+
const budget = Math.max(0, maxListings - listings);
|
|
260
|
+
const toList = level.slice(0, budget);
|
|
261
|
+
if (toList.length < level.length) state.truncated = true;
|
|
262
|
+
listings += toList.length;
|
|
263
|
+
// Concurrency is bounded by `limit`; Promise.all preserves queue order, so
|
|
264
|
+
// results are processed deterministically regardless of resolution order.
|
|
265
|
+
const results = await Promise.all(toList.map((entry) => limit(() => list(root, entry.dir))));
|
|
266
|
+
const next: PendingDir[] = [];
|
|
267
|
+
for (const [index, entry] of toList.entries()) {
|
|
268
|
+
const listing = results[index];
|
|
269
|
+
// A listing that FAILED is counted, not folded in as an empty directory.
|
|
270
|
+
// Treating it as empty is how a backend hiccup rendered as "this folder
|
|
271
|
+
// has nothing in it" — with `scannedAll: true` beside it, claiming the
|
|
272
|
+
// traversal was complete.
|
|
273
|
+
if (!listing || !listing.ok) {
|
|
274
|
+
state.failedListings += 1;
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
ingestListing(state, entry, listing.entries, next);
|
|
278
|
+
}
|
|
279
|
+
level = next;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
items: selectItems(state.candidates, maxItems),
|
|
284
|
+
totalAssets: state.totalAssets,
|
|
285
|
+
scannedAll: !state.truncated && state.failedListings === 0,
|
|
286
|
+
failedListings: state.failedListings,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const CACHE_KEY_SEPARATOR = '\u0000';
|
|
291
|
+
const previewCache = new Map<string, Promise<FolderPreviewSummary>>();
|
|
292
|
+
const sharedScanLimiter = createLimiter(FOLDER_PREVIEW_SCAN_CONCURRENCY);
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Memoized `collectFolderPreview` per root+path. Concurrent calls for the same
|
|
296
|
+
* folder share one in-flight scan, and scans across different folders are
|
|
297
|
+
* bounded by a shared limiter so many visible tiles cannot stampede the
|
|
298
|
+
* storage backend. A failed scan is evicted so the next call retries.
|
|
299
|
+
*/
|
|
300
|
+
export function getFolderPreview(
|
|
301
|
+
root: string,
|
|
302
|
+
folderPath: string,
|
|
303
|
+
options?: FolderPreviewOptions,
|
|
304
|
+
): Promise<FolderPreviewSummary> {
|
|
305
|
+
const key = `${root}${CACHE_KEY_SEPARATOR}${normalizeFolderPath(folderPath)}`;
|
|
306
|
+
const cached = previewCache.get(key);
|
|
307
|
+
if (cached) return cached;
|
|
308
|
+
const promise = sharedScanLimiter(() => collectFolderPreview(root, folderPath, options));
|
|
309
|
+
previewCache.set(key, promise);
|
|
310
|
+
const evict = () => {
|
|
311
|
+
if (previewCache.get(key) === promise) previewCache.delete(key);
|
|
312
|
+
};
|
|
313
|
+
promise.then((summary) => {
|
|
314
|
+
// A scan whose listings FAILED is not a folder that is empty; serve what we
|
|
315
|
+
// got, but never memoize it — the next call retries. (An empty summary is
|
|
316
|
+
// evicted too: re-checking a genuinely empty folder is one cheap listing,
|
|
317
|
+
// and it is cheaper than pinning a stale emptiness.)
|
|
318
|
+
if (summary.failedListings > 0) evict();
|
|
319
|
+
else if (summary.items.length === 0 && summary.totalAssets === 0) evict();
|
|
320
|
+
}, evict);
|
|
321
|
+
return promise;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/** True when one path is an ancestor of, equal to, or a descendant of the other. */
|
|
325
|
+
function pathsRelated(a: string, b: string): boolean {
|
|
326
|
+
return a === b || a === '' || b === '' || a.startsWith(`${b}/`) || b.startsWith(`${a}/`);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Drop cached previews. With no argument, clears everything. Given a changed
|
|
331
|
+
* path, drops every cached entry that is an ancestor of, equal to, or a
|
|
332
|
+
* descendant of that path — ancestors' composites may include the changed
|
|
333
|
+
* subtree's contents, and descendants may themselves have changed.
|
|
334
|
+
*/
|
|
335
|
+
export function invalidateFolderPreviews(changedPath?: string): void {
|
|
336
|
+
if (changedPath === undefined) {
|
|
337
|
+
previewCache.clear();
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const changed = normalizeFolderPath(changedPath);
|
|
341
|
+
for (const key of [...previewCache.keys()]) {
|
|
342
|
+
const cachedPath = key.slice(key.indexOf(CACHE_KEY_SEPARATOR) + 1);
|
|
343
|
+
if (pathsRelated(cachedPath, changed)) previewCache.delete(key);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Materialize a project's DECLARED asset packs (`asset-manifest.json`, D-AP1)
|
|
3
|
+
* from the `cloud-asset-library` Worker into a `StorageBackend`, recording
|
|
4
|
+
* the same provenance ledger (`.vgai/assets.json`, D-AP3) every other
|
|
5
|
+
* materialization site writes.
|
|
6
|
+
*
|
|
7
|
+
* This is the D-AP4 mechanism: a project's DECLARED packs are materialized
|
|
8
|
+
* from the `cloud-asset-library` worker (existing manifest + object routes),
|
|
9
|
+
* writing the same ledger.
|
|
10
|
+
*
|
|
11
|
+
* Exported for the open path to CALL rather than
|
|
12
|
+
* wired into `seedIfEmpty` here, so any declared pack (in the template or an
|
|
13
|
+
* example) reuses it without change. The template's `asset-manifest.json` is
|
|
14
|
+
* `{"packs": {}}` today, so calling this against the shipped template is a
|
|
15
|
+
* documented, harmless no-op: `declared` reports 0 and nothing is fetched.
|
|
16
|
+
*
|
|
17
|
+
* FAIL CLOSED AND LOUD, never fabricate (the anti-shim rule): a network
|
|
18
|
+
* failure, a 404, or a sha256 mismatch aborts THAT entry only — nothing is
|
|
19
|
+
* written for it — and is reported in the returned result; it never blocks
|
|
20
|
+
* the other declared entries and never substitutes placeholder bytes.
|
|
21
|
+
*
|
|
22
|
+
* ## The expected digest comes from the DECLARATION, never from the response
|
|
23
|
+
*
|
|
24
|
+
* Every entry pins `sha256` in `asset-manifest.json` (see
|
|
25
|
+
* `asset-pack-manifest.ts`), and that pin is the only authority here. Reading
|
|
26
|
+
* the expected digest out of the worker's own `/v1/assets/<id>` record instead
|
|
27
|
+
* would authenticate nothing on the FIRST fetch — a moved or tampered library
|
|
28
|
+
* answers self-consistently (its record and its bytes agree), the bytes get
|
|
29
|
+
* written, and its digest becomes the project's permanent `sourceHash` in the
|
|
30
|
+
* ledger. So: the record's digest must MATCH the pin (a disagreement is a
|
|
31
|
+
* refusal naming the asset), the fetched bytes are verified against the pin,
|
|
32
|
+
* and the pin is what the ledger records.
|
|
33
|
+
*
|
|
34
|
+
* ## "Already materialized" means the FILE is there, not just the record
|
|
35
|
+
*
|
|
36
|
+
* Idempotent and retry-safe: an entry is skipped only when the ledger has it
|
|
37
|
+
* AND its destination exists. Skipping on the ledger record alone made the
|
|
38
|
+
* broken case unrepairable — a project whose bytes were deleted, or whose
|
|
39
|
+
* ledger outlived a failed write, reported success forever, and the reopen
|
|
40
|
+
* retry (`project-manager.ts`) plus the Retry banner both skipped exactly the
|
|
41
|
+
* entry they existed to refetch.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
import { sha256Hex } from '../bytes-codec';
|
|
45
|
+
import type { StorageBackend } from '../storage/types';
|
|
46
|
+
import { normalizeLedgerPath } from './asset-ledger';
|
|
47
|
+
import {
|
|
48
|
+
readAssetLedgerFromBackend,
|
|
49
|
+
recordAssetMaterializationInBackend,
|
|
50
|
+
} from './asset-ledger-backend';
|
|
51
|
+
/** Project-relative path of the pack declaration (D-AP1) — sibling of
|
|
52
|
+
* `vgai.project.json` in the template/every example, and (per D-AP4) one of
|
|
53
|
+
* the plain-text files the browser build's seed writes alongside the rest
|
|
54
|
+
* of the template source. */
|
|
55
|
+
import {
|
|
56
|
+
ASSET_MANIFEST_PATH,
|
|
57
|
+
type FlattenedPackEntry,
|
|
58
|
+
flattenAssetPacks,
|
|
59
|
+
parseAssetPackManifest,
|
|
60
|
+
} from './asset-pack-manifest';
|
|
61
|
+
import {
|
|
62
|
+
cloudAssetObjectUrl,
|
|
63
|
+
DEFAULT_CLOUD_ASSET_BASE_URL,
|
|
64
|
+
fetchCloudAssetRecord,
|
|
65
|
+
} from './cloud-asset-client';
|
|
66
|
+
|
|
67
|
+
export { ASSET_MANIFEST_PATH };
|
|
68
|
+
|
|
69
|
+
export interface AssetPackMaterializationFailure {
|
|
70
|
+
readonly entry: FlattenedPackEntry;
|
|
71
|
+
readonly reason: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface AssetPackMaterializationResult {
|
|
75
|
+
/** Total entries declared across every pack. */
|
|
76
|
+
readonly declared: number;
|
|
77
|
+
readonly materialized: FlattenedPackEntry[];
|
|
78
|
+
/** Recorded in the ledger AND present on disk — nothing to do, not a failure. */
|
|
79
|
+
readonly alreadyPresent: FlattenedPackEntry[];
|
|
80
|
+
readonly failed: AssetPackMaterializationFailure[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface MaterializeAssetPacksOptions {
|
|
84
|
+
/** Test-only override of the deployed worker's base URL. */
|
|
85
|
+
readonly baseUrl?: string;
|
|
86
|
+
readonly signal?: AbortSignal;
|
|
87
|
+
/** Called once per entry, after it is attempted. */
|
|
88
|
+
readonly onProgress?: (
|
|
89
|
+
entry: FlattenedPackEntry,
|
|
90
|
+
outcome: 'materialized' | 'already-present' | 'failed',
|
|
91
|
+
) => void;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Materialize every pack entry `backend` declares in its own
|
|
96
|
+
* `asset-manifest.json` that is not already in the ledger.
|
|
97
|
+
*
|
|
98
|
+
* Reads the manifest from `backend` itself (not the repo), whichever backend
|
|
99
|
+
* the caller is already using.
|
|
100
|
+
*/
|
|
101
|
+
export async function materializeDeclaredAssetPacks(
|
|
102
|
+
backend: StorageBackend,
|
|
103
|
+
options: MaterializeAssetPacksOptions = {},
|
|
104
|
+
): Promise<AssetPackMaterializationResult> {
|
|
105
|
+
const entries = await declaredPackEntries(backend);
|
|
106
|
+
const result: AssetPackMaterializationResult = {
|
|
107
|
+
declared: entries.length,
|
|
108
|
+
materialized: [],
|
|
109
|
+
alreadyPresent: [],
|
|
110
|
+
failed: [],
|
|
111
|
+
};
|
|
112
|
+
if (entries.length === 0) return result;
|
|
113
|
+
|
|
114
|
+
const ledger = await readAssetLedgerFromBackend(backend);
|
|
115
|
+
for (const entry of entries) {
|
|
116
|
+
if (options.signal?.aborted) break;
|
|
117
|
+
// A ledger record is a record, not the bytes — see the module header.
|
|
118
|
+
if (ledger[normalizeLedgerPath(entry.dest)] && (await backend.exists(entry.dest))) {
|
|
119
|
+
result.alreadyPresent.push(entry);
|
|
120
|
+
options.onProgress?.(entry, 'already-present');
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
await materializeOne(backend, entry, options);
|
|
125
|
+
result.materialized.push(entry);
|
|
126
|
+
options.onProgress?.(entry, 'materialized');
|
|
127
|
+
} catch (error) {
|
|
128
|
+
result.failed.push({ entry, reason: error instanceof Error ? error.message : String(error) });
|
|
129
|
+
options.onProgress?.(entry, 'failed');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function declaredPackEntries(backend: StorageBackend): Promise<FlattenedPackEntry[]> {
|
|
136
|
+
if (!(await backend.exists(ASSET_MANIFEST_PATH))) return [];
|
|
137
|
+
const raw = await backend.read(ASSET_MANIFEST_PATH);
|
|
138
|
+
let parsed: unknown;
|
|
139
|
+
try {
|
|
140
|
+
parsed = JSON.parse(raw);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
`${ASSET_MANIFEST_PATH} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return flattenAssetPacks(parseAssetPackManifest(parsed));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function materializeOne(
|
|
150
|
+
backend: StorageBackend,
|
|
151
|
+
entry: FlattenedPackEntry,
|
|
152
|
+
options: MaterializeAssetPacksOptions,
|
|
153
|
+
): Promise<void> {
|
|
154
|
+
const fetched = await fetchVerifiedPackEntry(entry, options);
|
|
155
|
+
await backend.write(entry.dest, fetched.bytes);
|
|
156
|
+
await recordAssetMaterializationInBackend(backend, {
|
|
157
|
+
destPath: entry.dest,
|
|
158
|
+
key: entry.key,
|
|
159
|
+
license: fetched.license,
|
|
160
|
+
// The PIN, not the library's reported digest — identical here by the
|
|
161
|
+
// check inside `fetchVerifiedPackEntry`, and the pin is the fact this
|
|
162
|
+
// project reviewed.
|
|
163
|
+
sourceSha256: entry.sha256,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** The bytes of one declared pack entry, plus the library's license string. */
|
|
168
|
+
export interface VerifiedPackEntryBytes {
|
|
169
|
+
readonly bytes: Uint8Array;
|
|
170
|
+
/** The library's own license string, for the ledger. */
|
|
171
|
+
readonly license: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Fetch and VERIFY one declared pack entry, writing nothing.
|
|
176
|
+
*
|
|
177
|
+
* This is the whole network + trust sequence — record lookup, pin/record
|
|
178
|
+
* cross-check, byte fetch, digest verification — with the destination IO left
|
|
179
|
+
* to the caller, because the two materialization sites differ only in where the
|
|
180
|
+
* bytes land: this module writes through a `StorageBackend` (browser/hosted),
|
|
181
|
+
* and `packages/vgai-cli/src/asset-packs.ts` writes to the filesystem for an
|
|
182
|
+
* on-disk project `vgai add` just declared a pack into. Extracted so neither
|
|
183
|
+
* site can drift from the other on the part that matters — a second copy of
|
|
184
|
+
* "fetch then trust" is exactly how trust-on-first-use gets reintroduced.
|
|
185
|
+
*
|
|
186
|
+
* Throws on every failure and never returns partial bytes.
|
|
187
|
+
*/
|
|
188
|
+
export async function fetchVerifiedPackEntry(
|
|
189
|
+
entry: FlattenedPackEntry,
|
|
190
|
+
options: MaterializeAssetPacksOptions = {},
|
|
191
|
+
): Promise<VerifiedPackEntryBytes> {
|
|
192
|
+
const separator = entry.key.indexOf(':');
|
|
193
|
+
if (separator < 0) throw new Error(`Malformed asset key "${entry.key}" (expected "source:id").`);
|
|
194
|
+
const source = entry.key.slice(0, separator);
|
|
195
|
+
const assetId = entry.key.slice(separator + 1);
|
|
196
|
+
if (source !== 'local') {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`Asset key "${entry.key}": only the "local" (cloud-hosted) source can be materialized ` +
|
|
199
|
+
'from the cloud worker.',
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
const baseUrl = options.baseUrl ?? DEFAULT_CLOUD_ASSET_BASE_URL;
|
|
203
|
+
const fetchOptions = options.signal ? { baseUrl, signal: options.signal } : { baseUrl };
|
|
204
|
+
const record = await fetchCloudAssetRecord(assetId, fetchOptions);
|
|
205
|
+
if (!record) throw new Error(`"${entry.key}" is not hosted by the cloud asset library.`);
|
|
206
|
+
const file = record.files[0];
|
|
207
|
+
if (!file) throw new Error(`"${entry.key}" has no files in the cloud library.`);
|
|
208
|
+
if (file.dependencies.length > 0) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
`"${entry.key}" has ${file.dependencies.length} dependency file(s) — a pack entry names ` +
|
|
211
|
+
'exactly one destination file.',
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
// The cloud record must AGREE with the checked-in pin before a byte is
|
|
215
|
+
// fetched. A library that has moved on is a legitimate event; silently
|
|
216
|
+
// adopting its new bytes is not (see the module header).
|
|
217
|
+
if (file.main.sha256 !== entry.sha256) {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`"${entry.key}" → ${entry.dest}: the cloud library reports sha256:${file.main.sha256} but ` +
|
|
220
|
+
`${ASSET_MANIFEST_PATH} pins sha256:${entry.sha256}. Nothing was fetched or written; ` +
|
|
221
|
+
'the pin is only re-cut by a reviewed change to the declaration.',
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
const url = cloudAssetObjectUrl(baseUrl, assetId, 0);
|
|
225
|
+
const response = await fetch(url, options.signal ? { signal: options.signal } : {});
|
|
226
|
+
if (!response.ok) throw new Error(`${url} returned ${response.status} ${response.statusText}.`);
|
|
227
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
228
|
+
const actual = await sha256Hex(bytes);
|
|
229
|
+
if (actual !== entry.sha256) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
`"${entry.key}" → ${entry.dest}: ${url} delivered sha256:${actual} but the declaration ` +
|
|
232
|
+
`pins sha256:${entry.sha256}. Nothing was written.`,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
return { bytes, license: record.license };
|
|
236
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integer zoom for pixel art. Transcribed from the sprite-lab stage
|
|
3
|
+
* (`fitScale`): a fractional factor resamples the art, and a resampled
|
|
4
|
+
* sheet is a blur with the correct pixels still in the file.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Largest scale that fits `src` inside `box` without resampling. */
|
|
8
|
+
export function integerFitScale(
|
|
9
|
+
srcWidth: number,
|
|
10
|
+
srcHeight: number,
|
|
11
|
+
boxWidth: number,
|
|
12
|
+
boxHeight: number,
|
|
13
|
+
): number {
|
|
14
|
+
if (srcWidth <= 0 || srcHeight <= 0 || boxWidth <= 0 || boxHeight <= 0) return 1;
|
|
15
|
+
const growX = srcWidth <= boxWidth ? Math.floor(boxWidth / srcWidth) : 0;
|
|
16
|
+
const growY = srcHeight <= boxHeight ? Math.floor(boxHeight / srcHeight) : 0;
|
|
17
|
+
const grow = Math.min(growX, growY);
|
|
18
|
+
if (grow >= 1) return grow;
|
|
19
|
+
return 1 / Math.max(Math.ceil(srcWidth / boxWidth), Math.ceil(srcHeight / boxHeight));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type ImageScaleMode = 'fit' | 1 | 4 | 8;
|
|
23
|
+
|
|
24
|
+
export function resolveImageScale(
|
|
25
|
+
mode: ImageScaleMode,
|
|
26
|
+
srcWidth: number,
|
|
27
|
+
srcHeight: number,
|
|
28
|
+
boxWidth: number,
|
|
29
|
+
boxHeight: number,
|
|
30
|
+
): number {
|
|
31
|
+
return mode === 'fit' ? integerFitScale(srcWidth, srcHeight, boxWidth, boxHeight) : mode;
|
|
32
|
+
}
|