@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,1162 @@
|
|
|
1
|
+
import { faCircleInfo } from '@fortawesome/free-solid-svg-icons';
|
|
2
|
+
import { Button, Checkbox, EditorIcon, Select, TextInput } from '@volter/editor-sdk/widgets';
|
|
3
|
+
import type {
|
|
4
|
+
AccountCatalog,
|
|
5
|
+
AccountPlanId,
|
|
6
|
+
AccountSpendPolicy,
|
|
7
|
+
AccountUsageEntry,
|
|
8
|
+
ProviderCredentialId,
|
|
9
|
+
ProviderCredentialStatus,
|
|
10
|
+
} from '@volter/editor-sdk/account';
|
|
11
|
+
import { useEffect, useState, useSyncExternalStore } from 'react';
|
|
12
|
+
import {
|
|
13
|
+
accountError,
|
|
14
|
+
accountSnapshot,
|
|
15
|
+
accountVersion,
|
|
16
|
+
beginAccountBrowserAuthorization,
|
|
17
|
+
beginAccountDeviceAuthorization,
|
|
18
|
+
checkoutAccountPlan,
|
|
19
|
+
fetchAccountAuthorizationMethods,
|
|
20
|
+
fetchAccountCatalog,
|
|
21
|
+
fetchAccountUsage,
|
|
22
|
+
markAccountAlertsRead,
|
|
23
|
+
openAccountBillingPortal,
|
|
24
|
+
pollAccountBrowserAuthorization,
|
|
25
|
+
pollAccountDeviceAuthorization,
|
|
26
|
+
purchaseAccountCredits,
|
|
27
|
+
quoteCodingInference,
|
|
28
|
+
removeProviderCredential,
|
|
29
|
+
saveProviderCredential,
|
|
30
|
+
signInMockAccount,
|
|
31
|
+
signInTwinAccount,
|
|
32
|
+
signOutAccount,
|
|
33
|
+
subscribeAccount,
|
|
34
|
+
testProviderCredential,
|
|
35
|
+
updateAccountPlan,
|
|
36
|
+
updateAccountSpendPolicy,
|
|
37
|
+
updateCodingInference,
|
|
38
|
+
updatePreferredGenerationRoute,
|
|
39
|
+
} from '../account';
|
|
40
|
+
import { registerDocumentOpener } from '../document-open-registry';
|
|
41
|
+
import { openWorkspaceDocument } from '../workspace-document-registry';
|
|
42
|
+
import { VgaiLogo } from './VgaiLogo';
|
|
43
|
+
|
|
44
|
+
export const ACCOUNT_DOCUMENT_ID = 'account';
|
|
45
|
+
|
|
46
|
+
export function openAccountDocument(): string {
|
|
47
|
+
return openWorkspaceDocument({
|
|
48
|
+
id: ACCOUNT_DOCUMENT_ID,
|
|
49
|
+
title: 'Account',
|
|
50
|
+
kind: 'tool-contribution',
|
|
51
|
+
workspaceRole: 'workspace-task',
|
|
52
|
+
provenance: { origin: 'Volter account' },
|
|
53
|
+
Content: AccountDocument,
|
|
54
|
+
closeable: true,
|
|
55
|
+
presentation: () => ({ kind: 'workspace', id: ACCOUNT_DOCUMENT_ID }),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The account document's own ADDRESS (`document-open-registry.ts`). Its
|
|
61
|
+
* `presentation()` above already says the address is `{ kind: 'workspace', id:
|
|
62
|
+
* 'account' }`; this is the other half — what turns that address back into
|
|
63
|
+
* this document without the presenter importing this module. Registered at
|
|
64
|
+
* module load, the shape `packages/game/src/story-documents/
|
|
65
|
+
* three-story-documents.tsx:239` uses.
|
|
66
|
+
*
|
|
67
|
+
* `null` for any other workspace id: several modules answer the `workspace`
|
|
68
|
+
* address (the project-tools catalog is the other), and every id this one does
|
|
69
|
+
* not own belongs to the host's own workspace-document registry.
|
|
70
|
+
*/
|
|
71
|
+
registerDocumentOpener<{ readonly id: string }>({
|
|
72
|
+
id: 'workspace',
|
|
73
|
+
owner: 'account-documents',
|
|
74
|
+
open: (_store, request) => (request.id === ACCOUNT_DOCUMENT_ID ? openAccountDocument() : null),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
type AccountActionRunner = (action: () => Promise<unknown>, success?: string) => Promise<void>;
|
|
78
|
+
|
|
79
|
+
function providerSource(provider: ProviderCredentialStatus): string {
|
|
80
|
+
if (provider.source === 'environment') {
|
|
81
|
+
return `Environment · ${provider.environmentVariable}`;
|
|
82
|
+
}
|
|
83
|
+
if (provider.source === 'system') return 'Secure system storage';
|
|
84
|
+
if (provider.source === 'session')
|
|
85
|
+
return provider.configured ? 'Session only' : 'Session storage';
|
|
86
|
+
return 'Not configured';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Quiet blue-tinted information strip (spec §4) — one icon, one line. */
|
|
90
|
+
function InfoStrip({ children }: { children: React.ReactNode }) {
|
|
91
|
+
return (
|
|
92
|
+
<div className="vgai-account-infostrip">
|
|
93
|
+
<EditorIcon icon={faCircleInfo} className="vgai-account-infostrip-icon" aria-hidden="true" />
|
|
94
|
+
<span>{children}</span>
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
interface ProviderRowProps {
|
|
100
|
+
provider: ProviderCredentialStatus;
|
|
101
|
+
busy: boolean;
|
|
102
|
+
run: AccountActionRunner;
|
|
103
|
+
editing: boolean;
|
|
104
|
+
removing: boolean;
|
|
105
|
+
onEdit: () => void;
|
|
106
|
+
onStopEditing: () => void;
|
|
107
|
+
onRemoveIntent: (provider: ProviderCredentialId | null) => void;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function ProviderRow({
|
|
111
|
+
provider,
|
|
112
|
+
busy,
|
|
113
|
+
run,
|
|
114
|
+
editing,
|
|
115
|
+
removing,
|
|
116
|
+
onEdit,
|
|
117
|
+
onStopEditing,
|
|
118
|
+
onRemoveIntent,
|
|
119
|
+
}: ProviderRowProps) {
|
|
120
|
+
const [key, setKey] = useState('');
|
|
121
|
+
return (
|
|
122
|
+
<div className="vgai-account-provider" data-configured={provider.configured}>
|
|
123
|
+
<span className="vgai-account-provider-monogram" aria-hidden="true">
|
|
124
|
+
{provider.label.slice(0, 1)}
|
|
125
|
+
</span>
|
|
126
|
+
<div className="vgai-account-provider-main">
|
|
127
|
+
<div className="vgai-account-provider-name">
|
|
128
|
+
<strong>{provider.label}</strong>
|
|
129
|
+
{provider.configured && (
|
|
130
|
+
<>
|
|
131
|
+
<span className="vgai-account-provider-dot" aria-hidden="true" />
|
|
132
|
+
<span className="vgai-account-provider-key">{provider.maskedKey}</span>
|
|
133
|
+
</>
|
|
134
|
+
)}
|
|
135
|
+
</div>
|
|
136
|
+
<span className="vgai-account-provider-source">{providerSource(provider)}</span>
|
|
137
|
+
{provider.source === 'session' && provider.configured && (
|
|
138
|
+
<span className="vgai-account-provider-warning">
|
|
139
|
+
No system credential manager is available. This key will be forgotten when the editor
|
|
140
|
+
stops.
|
|
141
|
+
</span>
|
|
142
|
+
)}
|
|
143
|
+
{provider.problem && (
|
|
144
|
+
<span className="vgai-account-provider-warning" role="alert">
|
|
145
|
+
{provider.problem}
|
|
146
|
+
</span>
|
|
147
|
+
)}
|
|
148
|
+
{provider.source === 'environment' && (
|
|
149
|
+
<span className="vgai-account-provider-source">
|
|
150
|
+
Restart the editor after changing {provider.environmentVariable}.
|
|
151
|
+
</span>
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
{editing ? (
|
|
156
|
+
<form
|
|
157
|
+
className="vgai-account-provider-form"
|
|
158
|
+
onSubmit={(event) => {
|
|
159
|
+
event.preventDefault();
|
|
160
|
+
void run(async () => {
|
|
161
|
+
await saveProviderCredential(provider.provider, key);
|
|
162
|
+
setKey('');
|
|
163
|
+
onStopEditing();
|
|
164
|
+
}, `${provider.label} credential saved.`);
|
|
165
|
+
}}
|
|
166
|
+
>
|
|
167
|
+
<label className="vgai-field">
|
|
168
|
+
<span className="vgai-field-label">{provider.label} API key</span>
|
|
169
|
+
<TextInput
|
|
170
|
+
autoComplete="off"
|
|
171
|
+
autoFocus
|
|
172
|
+
type="password"
|
|
173
|
+
value={key}
|
|
174
|
+
onChange={(event) => setKey(event.target.value)}
|
|
175
|
+
/>
|
|
176
|
+
</label>
|
|
177
|
+
<div className="vgai-account-provider-form-actions">
|
|
178
|
+
<Button type="submit" variant="primary" disabled={busy || key.trim() === ''}>
|
|
179
|
+
Save key
|
|
180
|
+
</Button>
|
|
181
|
+
<Button
|
|
182
|
+
type="button"
|
|
183
|
+
variant="ghost"
|
|
184
|
+
disabled={busy}
|
|
185
|
+
onClick={() => {
|
|
186
|
+
setKey('');
|
|
187
|
+
onStopEditing();
|
|
188
|
+
}}
|
|
189
|
+
>
|
|
190
|
+
Cancel
|
|
191
|
+
</Button>
|
|
192
|
+
</div>
|
|
193
|
+
</form>
|
|
194
|
+
) : (
|
|
195
|
+
<div className="vgai-account-provider-actions">
|
|
196
|
+
{provider.configured && (
|
|
197
|
+
<Button
|
|
198
|
+
size="compact"
|
|
199
|
+
disabled={busy}
|
|
200
|
+
onClick={() =>
|
|
201
|
+
void run(
|
|
202
|
+
() => testProviderCredential(provider.provider),
|
|
203
|
+
`${provider.label} credential is valid.`,
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
>
|
|
207
|
+
Test
|
|
208
|
+
</Button>
|
|
209
|
+
)}
|
|
210
|
+
{provider.editable && (
|
|
211
|
+
<Button
|
|
212
|
+
size="compact"
|
|
213
|
+
/* Spec §3: "Add key" (the row's one constructive action) is a
|
|
214
|
+
* bordered secondary; "Replace" on an already-connected row
|
|
215
|
+
* stays quiet. */
|
|
216
|
+
variant={provider.configured ? 'ghost' : 'secondary'}
|
|
217
|
+
disabled={busy}
|
|
218
|
+
onClick={() => {
|
|
219
|
+
/* A row's editor can be dismissed WITHOUT its Cancel/Save path
|
|
220
|
+
* (opening another row's editor closes this one), which would
|
|
221
|
+
* leave half-typed text to reappear on reopen. Opening always
|
|
222
|
+
* starts from an empty field. */
|
|
223
|
+
setKey('');
|
|
224
|
+
onEdit();
|
|
225
|
+
}}
|
|
226
|
+
>
|
|
227
|
+
{provider.configured ? 'Replace' : 'Add key'}
|
|
228
|
+
</Button>
|
|
229
|
+
)}
|
|
230
|
+
{provider.editable && provider.configured && !removing && (
|
|
231
|
+
<Button
|
|
232
|
+
size="compact"
|
|
233
|
+
variant="ghost"
|
|
234
|
+
disabled={busy}
|
|
235
|
+
onClick={() => onRemoveIntent(provider.provider)}
|
|
236
|
+
>
|
|
237
|
+
Remove
|
|
238
|
+
</Button>
|
|
239
|
+
)}
|
|
240
|
+
{removing && (
|
|
241
|
+
<>
|
|
242
|
+
<Button
|
|
243
|
+
size="compact"
|
|
244
|
+
variant="danger"
|
|
245
|
+
disabled={busy}
|
|
246
|
+
onClick={() =>
|
|
247
|
+
void run(async () => {
|
|
248
|
+
await removeProviderCredential(provider.provider);
|
|
249
|
+
onRemoveIntent(null);
|
|
250
|
+
}, `${provider.label} credential removed.`)
|
|
251
|
+
}
|
|
252
|
+
>
|
|
253
|
+
Confirm remove
|
|
254
|
+
</Button>
|
|
255
|
+
<Button
|
|
256
|
+
size="compact"
|
|
257
|
+
variant="ghost"
|
|
258
|
+
disabled={busy}
|
|
259
|
+
onClick={() => onRemoveIntent(null)}
|
|
260
|
+
>
|
|
261
|
+
Cancel
|
|
262
|
+
</Button>
|
|
263
|
+
</>
|
|
264
|
+
)}
|
|
265
|
+
</div>
|
|
266
|
+
)}
|
|
267
|
+
</div>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function ProviderConnections({ busy, run }: { busy: boolean; run: AccountActionRunner }) {
|
|
272
|
+
const account = accountSnapshot();
|
|
273
|
+
const [editing, setEditing] = useState<ProviderCredentialId | null>(null);
|
|
274
|
+
const [removing, setRemoving] = useState<ProviderCredentialId | null>(null);
|
|
275
|
+
|
|
276
|
+
const connectedCount = account.providerCredentials.filter(
|
|
277
|
+
(provider) => provider.configured,
|
|
278
|
+
).length;
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<section className="vgai-account-card vgai-provider-connections">
|
|
282
|
+
<div className="vgai-account-providers-header">
|
|
283
|
+
<div>
|
|
284
|
+
<h3 className="vgai-account-card-title">Provider connections</h3>
|
|
285
|
+
<p className="vgai-account-card-sub">
|
|
286
|
+
Keys live in this computer's credential manager — never in project files or the
|
|
287
|
+
editor UI.
|
|
288
|
+
</p>
|
|
289
|
+
</div>
|
|
290
|
+
<span className="vgai-status-dot" data-state={connectedCount > 0 ? 'on' : 'off'}>
|
|
291
|
+
{connectedCount} connected
|
|
292
|
+
</span>
|
|
293
|
+
</div>
|
|
294
|
+
<div className="vgai-account-provider-list">
|
|
295
|
+
{account.providerCredentials.map((provider) => (
|
|
296
|
+
<ProviderRow
|
|
297
|
+
key={provider.provider}
|
|
298
|
+
provider={provider}
|
|
299
|
+
busy={busy}
|
|
300
|
+
run={run}
|
|
301
|
+
editing={editing === provider.provider}
|
|
302
|
+
removing={removing === provider.provider}
|
|
303
|
+
onEdit={() => {
|
|
304
|
+
setRemoving(null);
|
|
305
|
+
setEditing(provider.provider);
|
|
306
|
+
}}
|
|
307
|
+
onStopEditing={() => setEditing(null)}
|
|
308
|
+
onRemoveIntent={setRemoving}
|
|
309
|
+
/>
|
|
310
|
+
))}
|
|
311
|
+
</div>
|
|
312
|
+
</section>
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function CodingInferenceCard({ busy, run }: { busy: boolean; run: AccountActionRunner }) {
|
|
317
|
+
const account = accountSnapshot();
|
|
318
|
+
const settings = account.codingInference;
|
|
319
|
+
const [model, setModel] = useState(settings.model);
|
|
320
|
+
const [quote, setQuote] = useState<Awaited<ReturnType<typeof quoteCodingInference>> | null>(null);
|
|
321
|
+
const [quoteProblem, setQuoteProblem] = useState<string | null>(null);
|
|
322
|
+
useEffect(() => setModel(settings.model), [settings.model]);
|
|
323
|
+
useEffect(() => {
|
|
324
|
+
setQuote(null);
|
|
325
|
+
setQuoteProblem(null);
|
|
326
|
+
}, [model, account.preferredRoute]);
|
|
327
|
+
|
|
328
|
+
const save = (next: { enabled?: boolean; model?: string }) =>
|
|
329
|
+
run(
|
|
330
|
+
() =>
|
|
331
|
+
updateCodingInference({
|
|
332
|
+
...settings,
|
|
333
|
+
...next,
|
|
334
|
+
model: (next.model ?? settings.model).trim(),
|
|
335
|
+
}),
|
|
336
|
+
'Coding inference settings saved.',
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
return (
|
|
340
|
+
<section className="vgai-account-card">
|
|
341
|
+
<h3 className="vgai-account-card-title">Coding inference</h3>
|
|
342
|
+
<p className="vgai-account-card-sub">
|
|
343
|
+
Coding agents run on the login you already did — <code>codex login</code>, Claude's
|
|
344
|
+
device login, <code>grok login</code> — and Volter Editor injects nothing into them. Turn this on
|
|
345
|
+
only for a harness you have no subscription for: it routes that harness through OpenRouter
|
|
346
|
+
on this account's managed credits or your own key, and it takes effect only while
|
|
347
|
+
Preferred route above is Managed or BYOK. Existing sessions keep the route they launched
|
|
348
|
+
with.
|
|
349
|
+
</p>
|
|
350
|
+
<label className="vgai-account-switch-row">
|
|
351
|
+
<Checkbox
|
|
352
|
+
checked={settings.enabled}
|
|
353
|
+
disabled={busy}
|
|
354
|
+
onChange={(event) => void save({ enabled: event.target.checked })}
|
|
355
|
+
/>
|
|
356
|
+
<span className="vgai-account-switch-copy">
|
|
357
|
+
<strong>Use OpenRouter for coding agents</strong>
|
|
358
|
+
<small>
|
|
359
|
+
Codex, Claude Code, OpenCode and Pi are configured per spawned process. Grok takes no
|
|
360
|
+
provider configuration and always runs on its own device login.
|
|
361
|
+
</small>
|
|
362
|
+
</span>
|
|
363
|
+
</label>
|
|
364
|
+
<label className="vgai-field">
|
|
365
|
+
<span className="vgai-field-label">Managed coding model</span>
|
|
366
|
+
<Select
|
|
367
|
+
value={model}
|
|
368
|
+
disabled={busy}
|
|
369
|
+
onChange={(event) => {
|
|
370
|
+
const next = event.target.value;
|
|
371
|
+
setModel(next);
|
|
372
|
+
if (next !== settings.model) void save({ model: next });
|
|
373
|
+
}}
|
|
374
|
+
>
|
|
375
|
+
{!['z-ai/glm-5.2', 'moonshotai/kimi-k3'].includes(model) && (
|
|
376
|
+
<option value={model}>{model} · custom</option>
|
|
377
|
+
)}
|
|
378
|
+
<option value="z-ai/glm-5.2">GLM-5.2 · managed default</option>
|
|
379
|
+
<option value="moonshotai/kimi-k3">Kimi K3 · higher-cost option</option>
|
|
380
|
+
</Select>
|
|
381
|
+
</label>
|
|
382
|
+
{account.preferredRoute === 'managed' ? (
|
|
383
|
+
<div className="vgai-account-card-footer">
|
|
384
|
+
<Button
|
|
385
|
+
size="compact"
|
|
386
|
+
disabled={busy}
|
|
387
|
+
onClick={() => {
|
|
388
|
+
setQuoteProblem(null);
|
|
389
|
+
void quoteCodingInference({ model, promptTokens: 100_000, outputTokens: 20_000 })
|
|
390
|
+
.then(setQuote)
|
|
391
|
+
.catch((cause) =>
|
|
392
|
+
setQuoteProblem(cause instanceof Error ? cause.message : String(cause)),
|
|
393
|
+
);
|
|
394
|
+
}}
|
|
395
|
+
>
|
|
396
|
+
Preflight typical coding session
|
|
397
|
+
</Button>
|
|
398
|
+
{quote && (
|
|
399
|
+
<span className="vgai-account-help">
|
|
400
|
+
Estimate: {quote.estimatedCredits.toLocaleString()} Volter credits ($
|
|
401
|
+
{quote.providerAmountUsd.toFixed(4)} provider cost) for 100k input + 20k output
|
|
402
|
+
tokens.
|
|
403
|
+
</span>
|
|
404
|
+
)}
|
|
405
|
+
{quoteProblem && (
|
|
406
|
+
<span className="vgai-account-provider-warning" role="alert">
|
|
407
|
+
{quoteProblem}
|
|
408
|
+
</span>
|
|
409
|
+
)}
|
|
410
|
+
</div>
|
|
411
|
+
) : account.preferredRoute === 'byok' ? (
|
|
412
|
+
<InfoStrip>
|
|
413
|
+
BYOK coding charges OpenRouter directly and consumes zero Volter credits.
|
|
414
|
+
</InfoStrip>
|
|
415
|
+
) : null}
|
|
416
|
+
<InfoStrip>
|
|
417
|
+
Active account route: {account.preferredRoute}. BYOK requires the OpenRouter connection
|
|
418
|
+
below; managed uses the Volter balance.
|
|
419
|
+
</InfoStrip>
|
|
420
|
+
</section>
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/** Plan/status pills shown beside the email in the identity header. Suppresses
|
|
425
|
+
* a status that merely repeats the plan (the mock account reports plan "Free"
|
|
426
|
+
* with status "free"). */
|
|
427
|
+
function PlanChips({
|
|
428
|
+
plan,
|
|
429
|
+
}: {
|
|
430
|
+
plan: {
|
|
431
|
+
name: string;
|
|
432
|
+
status: string;
|
|
433
|
+
renewsAt?: string | undefined;
|
|
434
|
+
endsAt?: string | undefined;
|
|
435
|
+
};
|
|
436
|
+
}) {
|
|
437
|
+
const status = plan.status.replace('_', ' ');
|
|
438
|
+
const redundant =
|
|
439
|
+
plan.status === 'active' || status.toLowerCase() === plan.name.trim().toLowerCase();
|
|
440
|
+
return (
|
|
441
|
+
<span className="vgai-account-plan-chips">
|
|
442
|
+
<span className="vgai-chip" data-tone="accent">
|
|
443
|
+
{plan.name} plan
|
|
444
|
+
</span>
|
|
445
|
+
{!redundant && (
|
|
446
|
+
<span className="vgai-chip" data-tone={plan.status === 'cancelling' ? 'warn' : undefined}>
|
|
447
|
+
{status}
|
|
448
|
+
</span>
|
|
449
|
+
)}
|
|
450
|
+
{(plan.renewsAt || plan.endsAt) && (
|
|
451
|
+
<span className="vgai-chip">
|
|
452
|
+
{plan.endsAt ? 'Access ends' : 'Renews'}{' '}
|
|
453
|
+
{new Date(plan.endsAt ?? plan.renewsAt!).toLocaleDateString()}
|
|
454
|
+
</span>
|
|
455
|
+
)}
|
|
456
|
+
</span>
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/** Global account subject. It can be hosted either as an editor workspace
|
|
461
|
+
* document or directly by the projectless product shell. Account ownership is
|
|
462
|
+
* product-global, so rendering it must never require an open game project. */
|
|
463
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: One account form intentionally keeps interdependent plan, balance, route, and spend-policy disclosure in a single inspectable document.
|
|
464
|
+
export function AccountDocument() {
|
|
465
|
+
useSyncExternalStore(subscribeAccount, accountVersion, accountVersion);
|
|
466
|
+
const account = accountSnapshot();
|
|
467
|
+
const [email, setEmail] = useState('builder@example.test');
|
|
468
|
+
const [usage, setUsage] = useState<AccountUsageEntry[]>([]);
|
|
469
|
+
const [catalog, setCatalog] = useState<AccountCatalog | null>(null);
|
|
470
|
+
const [selectedPlan, setSelectedPlan] = useState<AccountPlanId>('creator');
|
|
471
|
+
const [selectedPack, setSelectedPack] = useState('');
|
|
472
|
+
const [busy, setBusy] = useState(false);
|
|
473
|
+
const [notice, setNotice] = useState<string | null>(null);
|
|
474
|
+
const [authorization, setAuthorization] = useState<Awaited<
|
|
475
|
+
ReturnType<typeof beginAccountDeviceAuthorization>
|
|
476
|
+
> | null>(null);
|
|
477
|
+
const [browserAuthorization, setBrowserAuthorization] = useState<Awaited<
|
|
478
|
+
ReturnType<typeof beginAccountBrowserAuthorization>
|
|
479
|
+
> | null>(null);
|
|
480
|
+
const [deviceAuthorizationAvailable, setDeviceAuthorizationAvailable] = useState(false);
|
|
481
|
+
|
|
482
|
+
useEffect(() => {
|
|
483
|
+
if (
|
|
484
|
+
account.authenticated ||
|
|
485
|
+
account.backend !== 'live' ||
|
|
486
|
+
account.accountEnvironment === 'development-twin'
|
|
487
|
+
) {
|
|
488
|
+
setDeviceAuthorizationAvailable(false);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
void fetchAccountAuthorizationMethods()
|
|
492
|
+
.then((methods) => setDeviceAuthorizationAvailable(methods.device))
|
|
493
|
+
.catch(() => setDeviceAuthorizationAvailable(false));
|
|
494
|
+
}, [account.authenticated, account.backend]);
|
|
495
|
+
|
|
496
|
+
useEffect(() => {
|
|
497
|
+
if (!browserAuthorization) return;
|
|
498
|
+
const poll = () => {
|
|
499
|
+
void pollAccountBrowserAuthorization(browserAuthorization.authorizationId)
|
|
500
|
+
.then((complete) => {
|
|
501
|
+
if (complete) setBrowserAuthorization(null);
|
|
502
|
+
})
|
|
503
|
+
.catch((cause) => {
|
|
504
|
+
setNotice(cause instanceof Error ? cause.message : String(cause));
|
|
505
|
+
setBrowserAuthorization(null);
|
|
506
|
+
});
|
|
507
|
+
};
|
|
508
|
+
poll();
|
|
509
|
+
const timer = window.setInterval(poll, 1_000);
|
|
510
|
+
return () => window.clearInterval(timer);
|
|
511
|
+
}, [browserAuthorization]);
|
|
512
|
+
|
|
513
|
+
useEffect(() => {
|
|
514
|
+
if (!authorization) return;
|
|
515
|
+
const poll = () => {
|
|
516
|
+
void pollAccountDeviceAuthorization(authorization.deviceCode)
|
|
517
|
+
.then((complete) => {
|
|
518
|
+
if (complete) setAuthorization(null);
|
|
519
|
+
})
|
|
520
|
+
.catch((cause) => {
|
|
521
|
+
setNotice(cause instanceof Error ? cause.message : String(cause));
|
|
522
|
+
setAuthorization(null);
|
|
523
|
+
});
|
|
524
|
+
};
|
|
525
|
+
const timer = window.setInterval(poll, Math.max(1, authorization.intervalSeconds) * 1_000);
|
|
526
|
+
return () => window.clearInterval(timer);
|
|
527
|
+
}, [authorization]);
|
|
528
|
+
|
|
529
|
+
useEffect(() => {
|
|
530
|
+
if (!account.authenticated) {
|
|
531
|
+
setUsage([]);
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
void fetchAccountUsage()
|
|
535
|
+
.then(setUsage)
|
|
536
|
+
.catch(() => setUsage([]));
|
|
537
|
+
}, [
|
|
538
|
+
account.authenticated,
|
|
539
|
+
account.authenticated ? account.user.id : 'signed-out',
|
|
540
|
+
account.authenticated ? account.credits.used : 0,
|
|
541
|
+
]);
|
|
542
|
+
|
|
543
|
+
useEffect(() => {
|
|
544
|
+
if (!account.authenticated) {
|
|
545
|
+
setCatalog(null);
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
void fetchAccountCatalog()
|
|
549
|
+
.then((next) => {
|
|
550
|
+
setCatalog(next);
|
|
551
|
+
const paid = (['creator', 'max', 'ultra'] as const).find((id) => id !== account.plan.id);
|
|
552
|
+
setSelectedPlan(paid ?? 'creator');
|
|
553
|
+
setSelectedPack(Object.keys(next.creditPacks)[0] ?? '');
|
|
554
|
+
})
|
|
555
|
+
.catch(() => setCatalog(null));
|
|
556
|
+
}, [account.authenticated, account.authenticated ? account.user.id : 'signed-out']);
|
|
557
|
+
|
|
558
|
+
const run = async (action: () => Promise<unknown>, success?: string) => {
|
|
559
|
+
setBusy(true);
|
|
560
|
+
setNotice(null);
|
|
561
|
+
try {
|
|
562
|
+
await action();
|
|
563
|
+
if (success) setNotice(success);
|
|
564
|
+
} catch (cause) {
|
|
565
|
+
setNotice(cause instanceof Error ? cause.message : String(cause));
|
|
566
|
+
} finally {
|
|
567
|
+
setBusy(false);
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
if (!account.authenticated) {
|
|
572
|
+
return (
|
|
573
|
+
<div className="vgai-account" data-testid="account-document">
|
|
574
|
+
<div className="vgai-account-signin-stack">
|
|
575
|
+
{/* §4-R cinematic sign-in: the key-lit mark floats on the CANVAS above
|
|
576
|
+
* the card (hub empty-state anatomy) — the card carries only the form. */}
|
|
577
|
+
<div className="vgai-account-signin-hero">
|
|
578
|
+
<span className="vgai-account-signin-mark" aria-hidden="true">
|
|
579
|
+
<VgaiLogo size={52} animation="static" />
|
|
580
|
+
</span>
|
|
581
|
+
<h1 className="vgai-account-signin-title">Sign in to Volter Editor</h1>
|
|
582
|
+
</div>
|
|
583
|
+
{account.accountEnvironment === 'development-twin' ? (
|
|
584
|
+
<form
|
|
585
|
+
className="vgai-account-card vgai-account-signin-card"
|
|
586
|
+
onSubmit={(event) => {
|
|
587
|
+
event.preventDefault();
|
|
588
|
+
void run(() => signInTwinAccount(email), 'Signed in through the local Clerk Twin.');
|
|
589
|
+
}}
|
|
590
|
+
>
|
|
591
|
+
<label className="vgai-field">
|
|
592
|
+
<span className="vgai-field-label">Development email</span>
|
|
593
|
+
<TextInput
|
|
594
|
+
value={email}
|
|
595
|
+
type="email"
|
|
596
|
+
onChange={(event) => setEmail(event.target.value)}
|
|
597
|
+
/>
|
|
598
|
+
</label>
|
|
599
|
+
<Button type="submit" variant="primary" disabled={busy || !email.includes('@')}>
|
|
600
|
+
{busy ? 'Signing in…' : 'Use Clerk Twin account'}
|
|
601
|
+
</Button>
|
|
602
|
+
<InfoStrip>
|
|
603
|
+
Local Clerk and Polar twins — fake identity and checkout, with the real Volter account
|
|
604
|
+
and credit boundaries.
|
|
605
|
+
</InfoStrip>
|
|
606
|
+
</form>
|
|
607
|
+
) : account.backend === 'live' ? (
|
|
608
|
+
<section className="vgai-account-card vgai-account-signin-card">
|
|
609
|
+
<Button
|
|
610
|
+
variant="primary"
|
|
611
|
+
disabled={busy || authorization !== null || browserAuthorization !== null}
|
|
612
|
+
onClick={() =>
|
|
613
|
+
void run(async () => {
|
|
614
|
+
const next = await beginAccountBrowserAuthorization();
|
|
615
|
+
setBrowserAuthorization(next);
|
|
616
|
+
window.open(next.authorizationUrl, '_blank', 'noopener,noreferrer');
|
|
617
|
+
})
|
|
618
|
+
}
|
|
619
|
+
>
|
|
620
|
+
{browserAuthorization ? 'Waiting for browser sign-in…' : 'Continue in browser'}
|
|
621
|
+
</Button>
|
|
622
|
+
{deviceAuthorizationAvailable && (
|
|
623
|
+
<Button
|
|
624
|
+
variant="ghost"
|
|
625
|
+
disabled={busy || authorization !== null || browserAuthorization !== null}
|
|
626
|
+
onClick={() =>
|
|
627
|
+
void run(async () => {
|
|
628
|
+
const next = await beginAccountDeviceAuthorization();
|
|
629
|
+
setAuthorization(next);
|
|
630
|
+
window.open(next.verificationUri, '_blank', 'noopener,noreferrer');
|
|
631
|
+
})
|
|
632
|
+
}
|
|
633
|
+
>
|
|
634
|
+
Use a device code instead
|
|
635
|
+
</Button>
|
|
636
|
+
)}
|
|
637
|
+
{authorization && (
|
|
638
|
+
<div className="vgai-account-device-code">
|
|
639
|
+
<strong>{authorization.userCode}</strong>
|
|
640
|
+
<span>
|
|
641
|
+
Complete authorization in the browser. This editor polls without receiving your
|
|
642
|
+
password.
|
|
643
|
+
</span>
|
|
644
|
+
</div>
|
|
645
|
+
)}
|
|
646
|
+
<InfoStrip>
|
|
647
|
+
Authorization happens in your browser — this editor never sees your password.
|
|
648
|
+
</InfoStrip>
|
|
649
|
+
</section>
|
|
650
|
+
) : (
|
|
651
|
+
<form
|
|
652
|
+
className="vgai-account-card vgai-account-signin-card"
|
|
653
|
+
onSubmit={(event) => {
|
|
654
|
+
event.preventDefault();
|
|
655
|
+
void run(
|
|
656
|
+
() => signInMockAccount(email),
|
|
657
|
+
'Signed in to the zero-charge local account.',
|
|
658
|
+
);
|
|
659
|
+
}}
|
|
660
|
+
>
|
|
661
|
+
<label className="vgai-field">
|
|
662
|
+
<span className="vgai-field-label">Email</span>
|
|
663
|
+
<TextInput
|
|
664
|
+
value={email}
|
|
665
|
+
type="email"
|
|
666
|
+
onChange={(event) => setEmail(event.target.value)}
|
|
667
|
+
/>
|
|
668
|
+
</label>
|
|
669
|
+
<Button type="submit" variant="primary" disabled={busy || !email.includes('@')}>
|
|
670
|
+
{busy ? 'Signing in…' : 'Use local mock account'}
|
|
671
|
+
</Button>
|
|
672
|
+
<InfoStrip>Local mock — no payment, network identity, or provider request.</InfoStrip>
|
|
673
|
+
</form>
|
|
674
|
+
)}
|
|
675
|
+
<ul className="vgai-account-signin-points">
|
|
676
|
+
<li>Every paid generation shows its route and estimate first</li>
|
|
677
|
+
<li>Spend controls and hard limits are on by default</li>
|
|
678
|
+
<li>Provider keys stay in your system credential manager</li>
|
|
679
|
+
</ul>
|
|
680
|
+
<CodingInferenceCard busy={busy} run={run} />
|
|
681
|
+
<ProviderConnections busy={busy} run={run} />
|
|
682
|
+
{(notice || accountError()) && (
|
|
683
|
+
<div className="vgai-account-status" role="status">
|
|
684
|
+
{notice ?? accountError()}
|
|
685
|
+
</div>
|
|
686
|
+
)}
|
|
687
|
+
</div>
|
|
688
|
+
</div>
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
const totalCredits = account.credits.included + account.credits.purchased;
|
|
693
|
+
const usedPercent =
|
|
694
|
+
totalCredits === 0 ? 0 : Math.min(100, (account.credits.used / totalCredits) * 100);
|
|
695
|
+
const reservedPercent =
|
|
696
|
+
totalCredits === 0
|
|
697
|
+
? 0
|
|
698
|
+
: Math.max(0, Math.min(100 - usedPercent, (account.credits.reserved / totalCredits) * 100));
|
|
699
|
+
const overQuota = totalCredits > 0 && account.credits.used > totalCredits;
|
|
700
|
+
const managedAccess = account.backend === 'mock' || account.entitlements.generation;
|
|
701
|
+
const updatePolicy = (patch: Partial<AccountSpendPolicy>) =>
|
|
702
|
+
updateAccountSpendPolicy({ ...account.spendPolicy, ...patch });
|
|
703
|
+
|
|
704
|
+
return (
|
|
705
|
+
<div className="vgai-account" data-testid="account-document">
|
|
706
|
+
<h1 className="vgai-sr-only">Account</h1>
|
|
707
|
+
<div className="vgai-account-stack">
|
|
708
|
+
<header className="vgai-account-identity">
|
|
709
|
+
<span className="vgai-account-avatar" aria-hidden="true">
|
|
710
|
+
{account.user.email.slice(0, 1)}
|
|
711
|
+
</span>
|
|
712
|
+
<div className="vgai-account-identity-main">
|
|
713
|
+
<div className="vgai-account-identity-row">
|
|
714
|
+
<h2 className="vgai-account-identity-email">{account.user.email}</h2>
|
|
715
|
+
<PlanChips plan={account.plan} />
|
|
716
|
+
</div>
|
|
717
|
+
<p className="vgai-account-identity-note">
|
|
718
|
+
{account.accountEnvironment === 'development-twin'
|
|
719
|
+
? 'Clerk + Polar Twin development account'
|
|
720
|
+
: account.backend === 'mock'
|
|
721
|
+
? 'Isolated test account'
|
|
722
|
+
: 'Volter account'}
|
|
723
|
+
</p>
|
|
724
|
+
</div>
|
|
725
|
+
<Button
|
|
726
|
+
variant="ghost"
|
|
727
|
+
className="vgai-account-signout"
|
|
728
|
+
disabled={busy}
|
|
729
|
+
onClick={() => void run(signOutAccount)}
|
|
730
|
+
>
|
|
731
|
+
Sign out
|
|
732
|
+
</Button>
|
|
733
|
+
</header>
|
|
734
|
+
|
|
735
|
+
<section className="vgai-account-card">
|
|
736
|
+
<div className="vgai-account-card-head">
|
|
737
|
+
<h3 className="vgai-account-card-title">Credits</h3>
|
|
738
|
+
{account.plan.id !== 'free' && account.plan.status === 'cancelling' && (
|
|
739
|
+
<Button
|
|
740
|
+
size="compact"
|
|
741
|
+
disabled={busy}
|
|
742
|
+
onClick={() => void run(() => updateAccountPlan('resume'))}
|
|
743
|
+
>
|
|
744
|
+
Resume subscription
|
|
745
|
+
</Button>
|
|
746
|
+
)}
|
|
747
|
+
</div>
|
|
748
|
+
{!managedAccess && (
|
|
749
|
+
<InfoStrip>
|
|
750
|
+
This account has not been admitted to Volter managed services. Signing up or paying does
|
|
751
|
+
not grant provider access; contact the Volter team for admission.
|
|
752
|
+
</InfoStrip>
|
|
753
|
+
)}
|
|
754
|
+
{catalog && (
|
|
755
|
+
<div className="vgai-account-card-footer">
|
|
756
|
+
<label className="vgai-field">
|
|
757
|
+
<span className="vgai-field-label">Subscription tier</span>
|
|
758
|
+
<Select
|
|
759
|
+
value={selectedPlan}
|
|
760
|
+
disabled={busy || !managedAccess}
|
|
761
|
+
onChange={(event) => setSelectedPlan(event.target.value as AccountPlanId)}
|
|
762
|
+
>
|
|
763
|
+
{(Object.keys(catalog.plans) as AccountPlanId[]).map((id) => {
|
|
764
|
+
const plan = catalog.plans[id];
|
|
765
|
+
const price = plan.monthlyPriceUsd;
|
|
766
|
+
return (
|
|
767
|
+
<option key={id} value={id} disabled={id === 'free'}>
|
|
768
|
+
{plan.name}
|
|
769
|
+
{price !== undefined ? ` · $${price}/month` : ''} ·{' '}
|
|
770
|
+
{plan.includedCredits.toLocaleString()} credits
|
|
771
|
+
{id === account.plan.id ? ' · current' : ''}
|
|
772
|
+
</option>
|
|
773
|
+
);
|
|
774
|
+
})}
|
|
775
|
+
</Select>
|
|
776
|
+
</label>
|
|
777
|
+
<Button
|
|
778
|
+
variant="primary"
|
|
779
|
+
size="compact"
|
|
780
|
+
disabled={
|
|
781
|
+
busy ||
|
|
782
|
+
!managedAccess ||
|
|
783
|
+
selectedPlan === account.plan.id ||
|
|
784
|
+
selectedPlan === 'free'
|
|
785
|
+
}
|
|
786
|
+
onClick={() =>
|
|
787
|
+
void run(async () => {
|
|
788
|
+
const checkout = await checkoutAccountPlan(selectedPlan);
|
|
789
|
+
if (checkout.checkoutUrl)
|
|
790
|
+
window.open(checkout.checkoutUrl, '_blank', 'noopener,noreferrer');
|
|
791
|
+
else
|
|
792
|
+
setNotice(
|
|
793
|
+
checkout.mock
|
|
794
|
+
? `Mock ${catalog.plans[selectedPlan].name} upgrade completed. No payment occurred.`
|
|
795
|
+
: `Subscription changed to ${catalog.plans[selectedPlan].name}.`,
|
|
796
|
+
);
|
|
797
|
+
})
|
|
798
|
+
}
|
|
799
|
+
>
|
|
800
|
+
Choose {catalog.plans[selectedPlan].name}
|
|
801
|
+
</Button>
|
|
802
|
+
</div>
|
|
803
|
+
)}
|
|
804
|
+
<div className="vgai-account-credit-figure">
|
|
805
|
+
<span className="vgai-account-credit-number">
|
|
806
|
+
{account.credits.remaining.toLocaleString()}
|
|
807
|
+
</span>
|
|
808
|
+
<span className="vgai-account-credit-unit">credits remaining</span>
|
|
809
|
+
</div>
|
|
810
|
+
<div
|
|
811
|
+
className="vgai-meter"
|
|
812
|
+
role="progressbar"
|
|
813
|
+
aria-label="Credits used"
|
|
814
|
+
aria-valuenow={Math.round(usedPercent)}
|
|
815
|
+
aria-valuemin={0}
|
|
816
|
+
aria-valuemax={100}
|
|
817
|
+
data-state={overQuota ? 'over' : undefined}
|
|
818
|
+
>
|
|
819
|
+
<span className="vgai-meter-fill" style={{ width: `${usedPercent}%` }} />
|
|
820
|
+
{reservedPercent > 0 && (
|
|
821
|
+
<span
|
|
822
|
+
className="vgai-meter-fill"
|
|
823
|
+
data-part="reserved"
|
|
824
|
+
style={{ left: `${usedPercent}%`, width: `${reservedPercent}%` }}
|
|
825
|
+
/>
|
|
826
|
+
)}
|
|
827
|
+
</div>
|
|
828
|
+
<p className="vgai-account-cycle-line">
|
|
829
|
+
{account.credits.used.toLocaleString()} of {totalCredits.toLocaleString()} used this
|
|
830
|
+
cycle
|
|
831
|
+
{account.credits.resetsAt && (
|
|
832
|
+
<> · resets {new Date(account.credits.resetsAt).toLocaleDateString()}</>
|
|
833
|
+
)}
|
|
834
|
+
{overQuota && <span className="vgai-account-cycle-over"> · over allowance</span>}
|
|
835
|
+
</p>
|
|
836
|
+
<div className="vgai-account-legend" data-state={overQuota ? 'over' : undefined}>
|
|
837
|
+
<span className="vgai-account-legend-item" data-part="included">
|
|
838
|
+
<span className="vgai-account-legend-dot" aria-hidden="true" />
|
|
839
|
+
{account.credits.included.toLocaleString()} included
|
|
840
|
+
</span>
|
|
841
|
+
<span className="vgai-account-legend-item" data-part="used">
|
|
842
|
+
<span className="vgai-account-legend-dot" aria-hidden="true" />
|
|
843
|
+
{account.credits.used.toLocaleString()} used
|
|
844
|
+
</span>
|
|
845
|
+
<span className="vgai-account-legend-item" data-part="reserved">
|
|
846
|
+
<span className="vgai-account-legend-dot" aria-hidden="true" />
|
|
847
|
+
{account.credits.reserved.toLocaleString()} reserved
|
|
848
|
+
</span>
|
|
849
|
+
<span className="vgai-account-legend-item" data-part="purchased">
|
|
850
|
+
<span className="vgai-account-legend-dot" aria-hidden="true" />
|
|
851
|
+
{account.credits.purchased.toLocaleString()} purchased
|
|
852
|
+
</span>
|
|
853
|
+
</div>
|
|
854
|
+
{account.credits.purchasedExpiresAt && (
|
|
855
|
+
<p className="vgai-account-help vgai-account-expiry">
|
|
856
|
+
Purchased credits expire{' '}
|
|
857
|
+
{new Date(account.credits.purchasedExpiresAt).toLocaleDateString()}.
|
|
858
|
+
</p>
|
|
859
|
+
)}
|
|
860
|
+
<div className="vgai-account-card-footer">
|
|
861
|
+
{catalog && selectedPack && catalog.creditPacks[selectedPack] && (
|
|
862
|
+
<>
|
|
863
|
+
<Select
|
|
864
|
+
aria-label="Credit pack"
|
|
865
|
+
value={selectedPack}
|
|
866
|
+
disabled={busy || !managedAccess}
|
|
867
|
+
onChange={(event) => setSelectedPack(event.target.value)}
|
|
868
|
+
>
|
|
869
|
+
{Object.entries(catalog.creditPacks).map(([id, pack]) => (
|
|
870
|
+
<option key={id} value={id}>
|
|
871
|
+
{pack.name} · {pack.credits.toLocaleString()} credits
|
|
872
|
+
</option>
|
|
873
|
+
))}
|
|
874
|
+
</Select>
|
|
875
|
+
<Button
|
|
876
|
+
size="compact"
|
|
877
|
+
disabled={busy || !managedAccess}
|
|
878
|
+
onClick={() =>
|
|
879
|
+
void run(async () => {
|
|
880
|
+
const pack = catalog.creditPacks[selectedPack];
|
|
881
|
+
const checkout = await purchaseAccountCredits(selectedPack);
|
|
882
|
+
if (checkout.checkoutUrl)
|
|
883
|
+
window.open(checkout.checkoutUrl, '_blank', 'noopener,noreferrer');
|
|
884
|
+
else
|
|
885
|
+
setNotice(
|
|
886
|
+
`Added ${pack?.credits.toLocaleString() ?? ''} mock credits. No payment occurred.`,
|
|
887
|
+
);
|
|
888
|
+
})
|
|
889
|
+
}
|
|
890
|
+
>
|
|
891
|
+
Buy credits
|
|
892
|
+
</Button>
|
|
893
|
+
</>
|
|
894
|
+
)}
|
|
895
|
+
<Button
|
|
896
|
+
size="compact"
|
|
897
|
+
variant="ghost"
|
|
898
|
+
disabled={busy}
|
|
899
|
+
onClick={() =>
|
|
900
|
+
void run(async () => {
|
|
901
|
+
const portal = await openAccountBillingPortal();
|
|
902
|
+
if (portal.mock) setNotice('Mock billing portal: no payment page was opened.');
|
|
903
|
+
else window.open(portal.url, '_blank', 'noopener,noreferrer');
|
|
904
|
+
})
|
|
905
|
+
}
|
|
906
|
+
>
|
|
907
|
+
Billing and invoices
|
|
908
|
+
</Button>
|
|
909
|
+
{account.plan.id !== 'free' && account.plan.status === 'active' && (
|
|
910
|
+
<Button
|
|
911
|
+
size="compact"
|
|
912
|
+
variant="ghost"
|
|
913
|
+
className="vgai-account-quiet-danger"
|
|
914
|
+
disabled={busy}
|
|
915
|
+
onClick={() => void run(() => updateAccountPlan('cancel'))}
|
|
916
|
+
>
|
|
917
|
+
Cancel at renewal
|
|
918
|
+
</Button>
|
|
919
|
+
)}
|
|
920
|
+
</div>
|
|
921
|
+
</section>
|
|
922
|
+
|
|
923
|
+
<section className="vgai-account-card">
|
|
924
|
+
<h3 className="vgai-account-card-title">Generation routing</h3>
|
|
925
|
+
<p className="vgai-account-card-sub">
|
|
926
|
+
Billing preference for AI usage. Provider libraries apply it automatically; requests
|
|
927
|
+
show the resolved account and cost before submission.
|
|
928
|
+
</p>
|
|
929
|
+
<label className="vgai-field">
|
|
930
|
+
<span className="vgai-field-label">Preferred route</span>
|
|
931
|
+
<Select
|
|
932
|
+
value={account.preferredRoute}
|
|
933
|
+
onChange={(event) =>
|
|
934
|
+
void run(() =>
|
|
935
|
+
updatePreferredGenerationRoute(
|
|
936
|
+
event.target.value as 'auto' | 'mock' | 'managed' | 'byok',
|
|
937
|
+
),
|
|
938
|
+
)
|
|
939
|
+
}
|
|
940
|
+
>
|
|
941
|
+
{account.accountEnvironment === 'test-mock' && (
|
|
942
|
+
<option value="mock">Mock · free and local</option>
|
|
943
|
+
)}
|
|
944
|
+
<option value="auto">Automatic · saved key or Volter account</option>
|
|
945
|
+
<option value="managed" disabled={!account.routes.managed}>
|
|
946
|
+
Managed · Volter credits{account.routes.managed ? '' : ' (unavailable)'}
|
|
947
|
+
</option>
|
|
948
|
+
<option value="byok" disabled={!account.routes.byok}>
|
|
949
|
+
BYOK · provider dollars{account.routes.byok ? '' : ' (no key found)'}
|
|
950
|
+
</option>
|
|
951
|
+
</Select>
|
|
952
|
+
</label>
|
|
953
|
+
</section>
|
|
954
|
+
|
|
955
|
+
<CodingInferenceCard busy={busy} run={run} />
|
|
956
|
+
<ProviderConnections busy={busy} run={run} />
|
|
957
|
+
|
|
958
|
+
{(account.alerts?.length ?? 0) > 0 && (
|
|
959
|
+
<section className="vgai-account-card">
|
|
960
|
+
<div className="vgai-account-card-head">
|
|
961
|
+
<h3 className="vgai-account-card-title">Account alerts</h3>
|
|
962
|
+
{account.alerts?.some((alert) => !alert.readAt) && (
|
|
963
|
+
<Button
|
|
964
|
+
size="compact"
|
|
965
|
+
variant="ghost"
|
|
966
|
+
disabled={busy}
|
|
967
|
+
onClick={() => void run(markAccountAlertsRead)}
|
|
968
|
+
>
|
|
969
|
+
Mark read
|
|
970
|
+
</Button>
|
|
971
|
+
)}
|
|
972
|
+
</div>
|
|
973
|
+
<div className="vgai-account-usage">
|
|
974
|
+
{account.alerts?.map((alert) => (
|
|
975
|
+
<div className="vgai-account-usage-row" key={alert.id}>
|
|
976
|
+
<span>
|
|
977
|
+
<strong>{alert.readAt ? 'Notice' : 'New'}</strong>
|
|
978
|
+
<small>{alert.message}</small>
|
|
979
|
+
</span>
|
|
980
|
+
<span>{new Date(alert.createdAt).toLocaleDateString()}</span>
|
|
981
|
+
</div>
|
|
982
|
+
))}
|
|
983
|
+
</div>
|
|
984
|
+
</section>
|
|
985
|
+
)}
|
|
986
|
+
|
|
987
|
+
<section className="vgai-account-card">
|
|
988
|
+
<h3 className="vgai-account-card-title">Spend controls</h3>
|
|
989
|
+
<p className="vgai-account-card-sub">
|
|
990
|
+
Alerts at {account.spendPolicy.alertThresholds.join('%, ')}% of the available allowance.
|
|
991
|
+
</p>
|
|
992
|
+
<label className="vgai-account-switch-row">
|
|
993
|
+
<Checkbox
|
|
994
|
+
checked={account.spendPolicy.overageEnabled}
|
|
995
|
+
onChange={(event) =>
|
|
996
|
+
void run(() =>
|
|
997
|
+
updatePolicy({
|
|
998
|
+
overageEnabled: event.target.checked,
|
|
999
|
+
monthlyLimitCredits:
|
|
1000
|
+
event.target.checked && account.spendPolicy.monthlyLimitCredits === 0
|
|
1001
|
+
? 1_000
|
|
1002
|
+
: account.spendPolicy.monthlyLimitCredits,
|
|
1003
|
+
}),
|
|
1004
|
+
)
|
|
1005
|
+
}
|
|
1006
|
+
/>
|
|
1007
|
+
<span className="vgai-account-switch-copy">
|
|
1008
|
+
<strong>Allow paid overage</strong>
|
|
1009
|
+
<small>Off by default. Managed requests stop before provider submission.</small>
|
|
1010
|
+
</span>
|
|
1011
|
+
</label>
|
|
1012
|
+
<div className="vgai-account-limit-field">
|
|
1013
|
+
<label className="vgai-field">
|
|
1014
|
+
<span className="vgai-field-label">Monthly overage hard limit</span>
|
|
1015
|
+
<span className="vgai-account-input-suffix">
|
|
1016
|
+
<TextInput
|
|
1017
|
+
key={account.spendPolicy.monthlyLimitCredits}
|
|
1018
|
+
type="number"
|
|
1019
|
+
min={0}
|
|
1020
|
+
defaultValue={account.spendPolicy.monthlyLimitCredits}
|
|
1021
|
+
disabled={!account.spendPolicy.overageEnabled}
|
|
1022
|
+
onBlur={(event) =>
|
|
1023
|
+
void run(() =>
|
|
1024
|
+
updatePolicy({ monthlyLimitCredits: Number(event.target.value) }),
|
|
1025
|
+
)
|
|
1026
|
+
}
|
|
1027
|
+
/>
|
|
1028
|
+
<span className="vgai-account-suffix" aria-hidden="true">
|
|
1029
|
+
credits
|
|
1030
|
+
</span>
|
|
1031
|
+
</span>
|
|
1032
|
+
</label>
|
|
1033
|
+
</div>
|
|
1034
|
+
<label className="vgai-account-switch-row">
|
|
1035
|
+
<Checkbox
|
|
1036
|
+
checked={account.spendPolicy.autoReload?.enabled === true}
|
|
1037
|
+
onChange={(event) =>
|
|
1038
|
+
void run(() =>
|
|
1039
|
+
updatePolicy({
|
|
1040
|
+
autoReload: {
|
|
1041
|
+
enabled: event.target.checked,
|
|
1042
|
+
whenRemainingBelow: account.spendPolicy.autoReload?.whenRemainingBelow ?? 100,
|
|
1043
|
+
reloadTo: account.spendPolicy.autoReload?.reloadTo ?? 500,
|
|
1044
|
+
monthlyLimitCredits:
|
|
1045
|
+
account.spendPolicy.autoReload?.monthlyLimitCredits ?? 2_000,
|
|
1046
|
+
},
|
|
1047
|
+
}),
|
|
1048
|
+
)
|
|
1049
|
+
}
|
|
1050
|
+
/>
|
|
1051
|
+
<span className="vgai-account-switch-copy">
|
|
1052
|
+
<strong>Automatically reload credits</strong>
|
|
1053
|
+
<small>Optional, independently capped, and never enabled by checkout.</small>
|
|
1054
|
+
</span>
|
|
1055
|
+
</label>
|
|
1056
|
+
{account.spendPolicy.autoReload?.enabled && (
|
|
1057
|
+
<div className="vgai-account-policy-fields">
|
|
1058
|
+
<label className="vgai-field">
|
|
1059
|
+
<span className="vgai-field-label">Reload below</span>
|
|
1060
|
+
<span className="vgai-account-input-suffix">
|
|
1061
|
+
<TextInput
|
|
1062
|
+
key={account.spendPolicy.autoReload.whenRemainingBelow}
|
|
1063
|
+
type="number"
|
|
1064
|
+
min={0}
|
|
1065
|
+
defaultValue={account.spendPolicy.autoReload.whenRemainingBelow}
|
|
1066
|
+
onBlur={(event) =>
|
|
1067
|
+
void run(() =>
|
|
1068
|
+
updatePolicy({
|
|
1069
|
+
autoReload: {
|
|
1070
|
+
...account.spendPolicy.autoReload!,
|
|
1071
|
+
whenRemainingBelow: Number(event.target.value),
|
|
1072
|
+
},
|
|
1073
|
+
}),
|
|
1074
|
+
)
|
|
1075
|
+
}
|
|
1076
|
+
/>
|
|
1077
|
+
<span className="vgai-account-suffix" aria-hidden="true">
|
|
1078
|
+
credits
|
|
1079
|
+
</span>
|
|
1080
|
+
</span>
|
|
1081
|
+
</label>
|
|
1082
|
+
<label className="vgai-field">
|
|
1083
|
+
<span className="vgai-field-label">Reload balance to</span>
|
|
1084
|
+
<span className="vgai-account-input-suffix">
|
|
1085
|
+
<TextInput
|
|
1086
|
+
key={account.spendPolicy.autoReload.reloadTo}
|
|
1087
|
+
type="number"
|
|
1088
|
+
min={1}
|
|
1089
|
+
defaultValue={account.spendPolicy.autoReload.reloadTo}
|
|
1090
|
+
onBlur={(event) =>
|
|
1091
|
+
void run(() =>
|
|
1092
|
+
updatePolicy({
|
|
1093
|
+
autoReload: {
|
|
1094
|
+
...account.spendPolicy.autoReload!,
|
|
1095
|
+
reloadTo: Number(event.target.value),
|
|
1096
|
+
},
|
|
1097
|
+
}),
|
|
1098
|
+
)
|
|
1099
|
+
}
|
|
1100
|
+
/>
|
|
1101
|
+
<span className="vgai-account-suffix" aria-hidden="true">
|
|
1102
|
+
credits
|
|
1103
|
+
</span>
|
|
1104
|
+
</span>
|
|
1105
|
+
</label>
|
|
1106
|
+
<label className="vgai-field">
|
|
1107
|
+
<span className="vgai-field-label">Monthly reload cap</span>
|
|
1108
|
+
<span className="vgai-account-input-suffix">
|
|
1109
|
+
<TextInput
|
|
1110
|
+
key={account.spendPolicy.autoReload.monthlyLimitCredits}
|
|
1111
|
+
type="number"
|
|
1112
|
+
min={0}
|
|
1113
|
+
defaultValue={account.spendPolicy.autoReload.monthlyLimitCredits}
|
|
1114
|
+
onBlur={(event) =>
|
|
1115
|
+
void run(() =>
|
|
1116
|
+
updatePolicy({
|
|
1117
|
+
autoReload: {
|
|
1118
|
+
...account.spendPolicy.autoReload!,
|
|
1119
|
+
monthlyLimitCredits: Number(event.target.value),
|
|
1120
|
+
},
|
|
1121
|
+
}),
|
|
1122
|
+
)
|
|
1123
|
+
}
|
|
1124
|
+
/>
|
|
1125
|
+
<span className="vgai-account-suffix" aria-hidden="true">
|
|
1126
|
+
credits
|
|
1127
|
+
</span>
|
|
1128
|
+
</span>
|
|
1129
|
+
</label>
|
|
1130
|
+
</div>
|
|
1131
|
+
)}
|
|
1132
|
+
</section>
|
|
1133
|
+
|
|
1134
|
+
<section className="vgai-account-card">
|
|
1135
|
+
<h3 className="vgai-account-card-title">Current-cycle usage</h3>
|
|
1136
|
+
{usage.length === 0 ? (
|
|
1137
|
+
<p className="vgai-account-help">
|
|
1138
|
+
No managed credit usage has been settled in this account.
|
|
1139
|
+
</p>
|
|
1140
|
+
) : (
|
|
1141
|
+
<div className="vgai-account-usage">
|
|
1142
|
+
{usage.map((entry) => (
|
|
1143
|
+
<div className="vgai-account-usage-row" key={entry.id}>
|
|
1144
|
+
<span>
|
|
1145
|
+
{entry.kind} · {entry.provider} · {entry.operation ?? 'managed operation'}
|
|
1146
|
+
</span>
|
|
1147
|
+
<strong>{entry.credits.toLocaleString()} credits</strong>
|
|
1148
|
+
</div>
|
|
1149
|
+
))}
|
|
1150
|
+
</div>
|
|
1151
|
+
)}
|
|
1152
|
+
</section>
|
|
1153
|
+
|
|
1154
|
+
{(notice || accountError()) && (
|
|
1155
|
+
<div className="vgai-account-status" role="status">
|
|
1156
|
+
{notice ?? accountError()}
|
|
1157
|
+
</div>
|
|
1158
|
+
)}
|
|
1159
|
+
</div>
|
|
1160
|
+
</div>
|
|
1161
|
+
);
|
|
1162
|
+
}
|