@hraness/slopcamera 3.2.4
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/LICENSE +21 -0
- package/NOTICE.md +60 -0
- package/PRIVACY.md +46 -0
- package/README.md +311 -0
- package/SECURITY.md +21 -0
- package/apps/desktop/README.md +966 -0
- package/apps/desktop/analysis/protocol.ts +223 -0
- package/apps/desktop/application/capability-binding.ts +594 -0
- package/apps/desktop/application/context.ts +97 -0
- package/apps/desktop/application/creative-iteration.ts +1385 -0
- package/apps/desktop/application/default-registry.ts +146 -0
- package/apps/desktop/application/directing-contract.ts +218 -0
- package/apps/desktop/application/directing-plan.ts +178 -0
- package/apps/desktop/application/errors.ts +18 -0
- package/apps/desktop/application/gateway-port.ts +867 -0
- package/apps/desktop/application/html-overlay-browser-runtime.ts +687 -0
- package/apps/desktop/application/html-overlay-integrity.ts +337 -0
- package/apps/desktop/application/html-overlay-renderer.ts +45 -0
- package/apps/desktop/application/index.ts +13 -0
- package/apps/desktop/application/operation-completion-checkpoint.ts +333 -0
- package/apps/desktop/application/operation-effects.ts +94 -0
- package/apps/desktop/application/operation.ts +224 -0
- package/apps/desktop/application/operations/analysis/faces.ts +244 -0
- package/apps/desktop/application/operations/analysis/music.ts +248 -0
- package/apps/desktop/application/operations/analysis/project-auto-zooms.ts +302 -0
- package/apps/desktop/application/operations/analysis/project-inactivity.ts +381 -0
- package/apps/desktop/application/operations/analysis/scenes.ts +272 -0
- package/apps/desktop/application/operations/analysis/shared.ts +202 -0
- package/apps/desktop/application/operations/derive/edit-batch.ts +967 -0
- package/apps/desktop/application/operations/derive/follow-faces.ts +454 -0
- package/apps/desktop/application/operations/edit/bind-candidate-revision.ts +91 -0
- package/apps/desktop/application/operations/edit/create-candidate-revision.ts +377 -0
- package/apps/desktop/application/operations/edit/create-revision.ts +255 -0
- package/apps/desktop/application/operations/edit/freeze-revision.ts +182 -0
- package/apps/desktop/application/operations/gateway/image.ts +41 -0
- package/apps/desktop/application/operations/gateway/index.ts +17 -0
- package/apps/desktop/application/operations/gateway/shared.ts +122 -0
- package/apps/desktop/application/operations/gateway/speech.ts +41 -0
- package/apps/desktop/application/operations/gateway/transcription.ts +42 -0
- package/apps/desktop/application/operations/gateway/video.ts +41 -0
- package/apps/desktop/application/operations/index.ts +31 -0
- package/apps/desktop/application/operations/iteration/create-candidate.ts +240 -0
- package/apps/desktop/application/operations/iteration/create-matrix.ts +117 -0
- package/apps/desktop/application/operations/iteration/select.ts +155 -0
- package/apps/desktop/application/operations/iteration/shared.ts +250 -0
- package/apps/desktop/application/operations/media/audio-effects.ts +376 -0
- package/apps/desktop/application/operations/media/binding.ts +79 -0
- package/apps/desktop/application/operations/media/capabilities.ts +112 -0
- package/apps/desktop/application/operations/media/color-grade.ts +343 -0
- package/apps/desktop/application/operations/media/html-overlay.ts +802 -0
- package/apps/desktop/application/operations/media/index.ts +8 -0
- package/apps/desktop/application/operations/media/ingest.ts +303 -0
- package/apps/desktop/application/operations/media/overlay.ts +729 -0
- package/apps/desktop/application/operations/media/shared.ts +845 -0
- package/apps/desktop/application/operations/media/transform-platform.ts +120 -0
- package/apps/desktop/application/operations/project/commit-edits.ts +2054 -0
- package/apps/desktop/application/operations/project/promote-selection.ts +495 -0
- package/apps/desktop/application/operations/project/snapshot.ts +95 -0
- package/apps/desktop/application/operations/recording/index.ts +5 -0
- package/apps/desktop/application/operations/recording/pause.ts +34 -0
- package/apps/desktop/application/operations/recording/resume.ts +34 -0
- package/apps/desktop/application/operations/recording/shared.ts +199 -0
- package/apps/desktop/application/operations/recording/start.ts +169 -0
- package/apps/desktop/application/operations/recording/stop.ts +34 -0
- package/apps/desktop/application/operations/render/bind-candidate-output.ts +324 -0
- package/apps/desktop/application/operations/render/materialize-selection.ts +322 -0
- package/apps/desktop/application/operations/render/project-caption-plan.ts +287 -0
- package/apps/desktop/application/operations/render/project-plan.ts +939 -0
- package/apps/desktop/application/operations/render/project-spatial-receipt.ts +70 -0
- package/apps/desktop/application/operations/render/project.ts +1922 -0
- package/apps/desktop/application/operations/shared.ts +67 -0
- package/apps/desktop/application/operations/slopcamera-portable.ts +1188 -0
- package/apps/desktop/application/operations/slopcamera-visuals.ts +784 -0
- package/apps/desktop/application/operations/spatial-project.ts +209 -0
- package/apps/desktop/application/operations/spatial-render.ts +415 -0
- package/apps/desktop/application/operations/spatial-scene.ts +97 -0
- package/apps/desktop/application/operations/studio.ts +143 -0
- package/apps/desktop/application/output-publication-lease.ts +163 -0
- package/apps/desktop/application/project-publication-lease.ts +233 -0
- package/apps/desktop/application/project-store.ts +196 -0
- package/apps/desktop/application/receipts.ts +533 -0
- package/apps/desktop/application/registry.ts +182 -0
- package/apps/desktop/application/spatial-assets.ts +675 -0
- package/apps/desktop/application/spatial-compositor-cadence.ts +23 -0
- package/apps/desktop/application/spatial-project-authority.ts +35 -0
- package/apps/desktop/application/spatial-project-lease.ts +126 -0
- package/apps/desktop/application/spatial-project-render-preparation.ts +225 -0
- package/apps/desktop/application/spatial-project-store.ts +286 -0
- package/apps/desktop/application/spatial-render-projection.ts +201 -0
- package/apps/desktop/application/spatial-render.ts +677 -0
- package/apps/desktop/application/spatial-spz.ts +44 -0
- package/apps/desktop/application/spatial-world-import.ts +135 -0
- package/apps/desktop/application/spatial-world-provenance.ts +46 -0
- package/apps/desktop/application/studio-port.ts +58 -0
- package/apps/desktop/application/verified-receipt-reconciliation.ts +1574 -0
- package/apps/desktop/capture/protocol.ts +689 -0
- package/apps/desktop/cli/analyzer.ts +406 -0
- package/apps/desktop/cli/args.ts +3181 -0
- package/apps/desktop/cli/asset-ingest.ts +747 -0
- package/apps/desktop/cli/atomic-render-effects.ts +210 -0
- package/apps/desktop/cli/atomic-render-platform.ts +205 -0
- package/apps/desktop/cli/atomic-render.ts +50 -0
- package/apps/desktop/cli/audio-analysis.ts +252 -0
- package/apps/desktop/cli/bounded-map.ts +39 -0
- package/apps/desktop/cli/bundle-service.ts +256 -0
- package/apps/desktop/cli/capabilities.ts +212 -0
- package/apps/desktop/cli/capture-bundle.ts +1117 -0
- package/apps/desktop/cli/command-host-resources.ts +251 -0
- package/apps/desktop/cli/commands.ts +6836 -0
- package/apps/desktop/cli/directing-blob.ts +291 -0
- package/apps/desktop/cli/directing-media.ts +517 -0
- package/apps/desktop/cli/directing-quote.ts +89 -0
- package/apps/desktop/cli/directing-service.ts +288 -0
- package/apps/desktop/cli/emoji-assets.ts +538 -0
- package/apps/desktop/cli/errors.ts +29 -0
- package/apps/desktop/cli/face-analysis-service.ts +940 -0
- package/apps/desktop/cli/filter-script.ts +76 -0
- package/apps/desktop/cli/gateway-application-port.ts +1142 -0
- package/apps/desktop/cli/gateway-credential.ts +81 -0
- package/apps/desktop/cli/gateway-media-artifacts.ts +723 -0
- package/apps/desktop/cli/gateway-media-catalog.ts +922 -0
- package/apps/desktop/cli/gateway-media-service.ts +3106 -0
- package/apps/desktop/cli/gateway-media-signature.ts +122 -0
- package/apps/desktop/cli/gateway-provider-options.ts +562 -0
- package/apps/desktop/cli/gateway-scene-provider.ts +391 -0
- package/apps/desktop/cli/help.ts +501 -0
- package/apps/desktop/cli/html-overlay-gpu.ts +97 -0
- package/apps/desktop/cli/html-overlay-renderer.ts +2478 -0
- package/apps/desktop/cli/io.ts +290 -0
- package/apps/desktop/cli/main.ts +123 -0
- package/apps/desktop/cli/media-effects-service.ts +885 -0
- package/apps/desktop/cli/media-ingest-model.ts +364 -0
- package/apps/desktop/cli/media-ingest-platform.ts +227 -0
- package/apps/desktop/cli/media-ingest-program.ts +200 -0
- package/apps/desktop/cli/media-ingest.ts +30 -0
- package/apps/desktop/cli/music-analysis-service.ts +434 -0
- package/apps/desktop/cli/mutation-lock.ts +530 -0
- package/apps/desktop/cli/native-assets.d.ts +12 -0
- package/apps/desktop/cli/native-media-runtime.macos.ts +7 -0
- package/apps/desktop/cli/overlay-playback.ts +177 -0
- package/apps/desktop/cli/paths.ts +265 -0
- package/apps/desktop/cli/portable-surface.ts +242 -0
- package/apps/desktop/cli/project-camera-receipt.ts +112 -0
- package/apps/desktop/cli/project-face-camera.ts +394 -0
- package/apps/desktop/cli/project-inactivity-service.ts +552 -0
- package/apps/desktop/cli/project-media-integrity.ts +121 -0
- package/apps/desktop/cli/project-renderer.ts +1526 -0
- package/apps/desktop/cli/project-service.ts +519 -0
- package/apps/desktop/cli/project-state-transaction.ts +520 -0
- package/apps/desktop/cli/query-limits.ts +1 -0
- package/apps/desktop/cli/recording-controller.ts +1567 -0
- package/apps/desktop/cli/recording-daemon.ts +931 -0
- package/apps/desktop/cli/recording-ref.ts +56 -0
- package/apps/desktop/cli/renamed-environment.ts +6 -0
- package/apps/desktop/cli/renderer.ts +1439 -0
- package/apps/desktop/cli/run-cli-test-helper.ts +60 -0
- package/apps/desktop/cli/scene-analysis-service.ts +879 -0
- package/apps/desktop/cli/spatial-compositor-verifier.ts +213 -0
- package/apps/desktop/cli/spatial-project-service.ts +90 -0
- package/apps/desktop/cli/spatial-scene-service.ts +105 -0
- package/apps/desktop/cli/spatial-world-service.ts +39 -0
- package/apps/desktop/cli/speech-analysis-service.ts +682 -0
- package/apps/desktop/cli/studio-assemble.ts +58 -0
- package/apps/desktop/cli/studio-command.ts +60 -0
- package/apps/desktop/cli/studio-custody.ts +60 -0
- package/apps/desktop/cli/studio-encode.ts +216 -0
- package/apps/desktop/cli/studio-exr.ts +52 -0
- package/apps/desktop/cli/studio-files.ts +179 -0
- package/apps/desktop/cli/studio-output-validation.ts +162 -0
- package/apps/desktop/cli/studio-process.ts +145 -0
- package/apps/desktop/cli/studio-runtime.ts +77 -0
- package/apps/desktop/cli/studio-scaffold.ts +70 -0
- package/apps/desktop/cli/studio-service.ts +301 -0
- package/apps/desktop/cli/studio-spatial-asset.ts +248 -0
- package/apps/desktop/cli/studio-template-names.ts +3 -0
- package/apps/desktop/cli/studio-workflow.ts +19 -0
- package/apps/desktop/cli/time.ts +25 -0
- package/apps/desktop/cli/workflow-code.ts +584 -0
- package/apps/desktop/cli/workflow-runs.ts +576 -0
- package/apps/desktop/code/advanced.ts +139 -0
- package/apps/desktop/code/application-node-planner.ts +1288 -0
- package/apps/desktop/code/compiler.ts +329 -0
- package/apps/desktop/code/contracts.ts +13 -0
- package/apps/desktop/code/creative-recipes.ts +94 -0
- package/apps/desktop/code/define-workflow.ts +115 -0
- package/apps/desktop/code/editing.ts +284 -0
- package/apps/desktop/code/file-candidate-provenance.ts +420 -0
- package/apps/desktop/code/file-candidate.ts +69 -0
- package/apps/desktop/code/graph-builder.ts +10 -0
- package/apps/desktop/code/host-resource-policy.ts +55 -0
- package/apps/desktop/code/plan-contracts.ts +159 -0
- package/apps/desktop/code/planning.ts +361 -0
- package/apps/desktop/code/public.ts +134 -0
- package/apps/desktop/code/reference-projection.ts +62 -0
- package/apps/desktop/code/run-contracts.ts +466 -0
- package/apps/desktop/code/run-store.ts +2478 -0
- package/apps/desktop/code/runtime-identity.ts +328 -0
- package/apps/desktop/code/scheduler.ts +3067 -0
- package/apps/desktop/code/semantic-builder.ts +1436 -0
- package/apps/desktop/code/source-bundle.ts +1641 -0
- package/apps/desktop/code/source-typecheck.ts +211 -0
- package/apps/desktop/code/testing.ts +79 -0
- package/apps/desktop/code/worker-client.ts +1675 -0
- package/apps/desktop/code/worker-effects.ts +141 -0
- package/apps/desktop/code/worker-entry.ts +435 -0
- package/apps/desktop/code/worker-lease-guardian.ts +179 -0
- package/apps/desktop/code/worker-process-identity.ts +484 -0
- package/apps/desktop/code/worker-protocol.ts +211 -0
- package/apps/desktop/code/workflow-effects.ts +132 -0
- package/apps/desktop/contracts/analysis.ts +949 -0
- package/apps/desktop/contracts/edit.ts +576 -0
- package/apps/desktop/contracts/index.ts +9 -0
- package/apps/desktop/contracts/media-effects.ts +139 -0
- package/apps/desktop/contracts/project-render.ts +644 -0
- package/apps/desktop/contracts/project.ts +740 -0
- package/apps/desktop/contracts/recording.ts +1434 -0
- package/apps/desktop/contracts/render.ts +334 -0
- package/apps/desktop/contracts/runtime.ts +155 -0
- package/apps/desktop/contracts/spatial-compositor.ts +58 -0
- package/apps/desktop/contracts/spatial-project.ts +159 -0
- package/apps/desktop/contracts/spatial-world.ts +48 -0
- package/apps/desktop/contracts/video-effects.ts +120 -0
- package/apps/desktop/core/alignment-apply.ts +400 -0
- package/apps/desktop/core/audio-alignment.ts +466 -0
- package/apps/desktop/core/auto-zoom.ts +209 -0
- package/apps/desktop/core/canonical-json.ts +14 -0
- package/apps/desktop/core/emoji.ts +210 -0
- package/apps/desktop/core/events.ts +409 -0
- package/apps/desktop/core/face-framing.ts +533 -0
- package/apps/desktop/core/face-tracks.ts +326 -0
- package/apps/desktop/core/inactivity.ts +137 -0
- package/apps/desktop/core/index.ts +30 -0
- package/apps/desktop/core/intervals.ts +123 -0
- package/apps/desktop/core/montage.ts +236 -0
- package/apps/desktop/core/music-analysis.ts +518 -0
- package/apps/desktop/core/plan.ts +244 -0
- package/apps/desktop/core/project-auto-zoom.ts +75 -0
- package/apps/desktop/core/project-camera-spatial.ts +676 -0
- package/apps/desktop/core/project-camera.ts +403 -0
- package/apps/desktop/core/project-captions.ts +888 -0
- package/apps/desktop/core/project-inactivity.ts +125 -0
- package/apps/desktop/core/project-metadata.ts +927 -0
- package/apps/desktop/core/project-plan.ts +375 -0
- package/apps/desktop/core/project-render-plan.ts +303 -0
- package/apps/desktop/core/project-time.ts +469 -0
- package/apps/desktop/core/render-plan.ts +442 -0
- package/apps/desktop/core/scene-cache.ts +174 -0
- package/apps/desktop/core/scene-sampling.ts +448 -0
- package/apps/desktop/core/spatial-compositor.ts +22 -0
- package/apps/desktop/core/spatial-durability.ts +99 -0
- package/apps/desktop/core/spatial-project.ts +169 -0
- package/apps/desktop/core/spatial-shot-clock.ts +32 -0
- package/apps/desktop/core/speech-analysis.ts +333 -0
- package/apps/desktop/core/storage.ts +970 -0
- package/apps/desktop/core/time-map.ts +91 -0
- package/apps/desktop/core/time.ts +61 -0
- package/apps/desktop/core/video-effects.ts +660 -0
- package/apps/desktop/dist/cli/NebulaSans-Bold-26se8aek.otf +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Book-5ax05zvn.woff2 +0 -0
- package/apps/desktop/dist/cli/NebulaSans-Book-8cenzchw.otf +0 -0
- package/apps/desktop/dist/cli/main.js +5086 -0
- package/apps/desktop/html-overlay/catalog.ts +171 -0
- package/apps/desktop/html-overlay/contracts.ts +372 -0
- package/apps/desktop/html-overlay/execution-profile.ts +77 -0
- package/apps/desktop/html-overlay/index.ts +98 -0
- package/apps/desktop/html-overlay/libraries.ts +263 -0
- package/apps/desktop/html-overlay/random.ts +49 -0
- package/apps/desktop/html-overlay/runtime.ts +813 -0
- package/apps/desktop/html-overlay/scaffolds.ts +792 -0
- package/apps/desktop/html-overlay/spark-runtime.ts +88 -0
- package/apps/desktop/html-overlay/spatial-splat-runtime.ts +60 -0
- package/apps/desktop/html-overlay/spatial.ts +720 -0
- package/apps/desktop/studio/assets/README.md +39 -0
- package/apps/desktop/studio/assets/contracts.ts +129 -0
- package/apps/desktop/studio/assets/network.ts +64 -0
- package/apps/desktop/studio/assets/poly-haven.ts +148 -0
- package/apps/desktop/studio/drivers/blender_driver.py +466 -0
- package/apps/desktop/studio/drivers/cadquery_driver.py +176 -0
- package/apps/desktop/studio/education/driver.py +308 -0
- package/apps/desktop/studio/education/lesson.py +180 -0
- package/apps/desktop/studio/education/toolkit.py +249 -0
- package/apps/desktop/workflows/chaptered-demo.ts +48 -0
- package/apps/desktop/workflows/creative-iteration.ts +107 -0
- package/apps/desktop/workflows/creative-selection.ts +92 -0
- package/apps/desktop/workflows/fragments.ts +486 -0
- package/apps/desktop/workflows/index.ts +93 -0
- package/apps/desktop/workflows/polished-screen-demo.ts +128 -0
- package/apps/desktop/workflows/scene-direction.ts +12 -0
- package/apps/desktop/workflows/social-variants.ts +75 -0
- package/apps/desktop/workflows/talking-head-cleanup.ts +53 -0
- package/dist/NebulaSans-Bold-26se8aek.otf +0 -0
- package/dist/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
- package/dist/NebulaSans-Book-5ax05zvn.woff2 +0 -0
- package/dist/NebulaSans-Book-8cenzchw.otf +0 -0
- package/dist/cli.js +479 -0
- package/dist/code/advanced.js +270 -0
- package/dist/code/index.js +2240 -0
- package/dist/generate.js +24 -0
- package/dist/host-resources.js +26 -0
- package/dist/index-42zsesc1.js +2257 -0
- package/dist/index-7308egqr.js +48 -0
- package/dist/index-8txs6fkn.js +712 -0
- package/dist/index-mcy8z0br.js +192 -0
- package/dist/index-p63wavx0.js +2029 -0
- package/dist/index-r7gdhmsp.js +424 -0
- package/dist/index-sh6xbav6.js +1219 -0
- package/dist/index-z1w83f81.js +4 -0
- package/dist/index-z7239b4h.js +2363 -0
- package/dist/index-zfeg9hmw.js +2013 -0
- package/dist/index.js +241 -0
- package/dist/operations.js +29 -0
- package/dist/skill-install-dh0ntqba.js +10 -0
- package/dist/vectorize/worker.js +142 -0
- package/dist/workflow.js +16 -0
- package/docs/README.md +38 -0
- package/docs/studio.md +215 -0
- package/examples/studio/blender/README.md +26 -0
- package/examples/studio/blender/character.py +152 -0
- package/examples/studio/blender/cloth.py +101 -0
- package/examples/studio/blender/color_chart.py +29 -0
- package/examples/studio/blender/fluid.py +78 -0
- package/examples/studio/blender/import_model.py +74 -0
- package/examples/studio/blender/product.py +53 -0
- package/examples/studio/blender/shaded_street.py +481 -0
- package/examples/studio/blender/studio_scene.py +147 -0
- package/examples/studio/cadquery/README.md +13 -0
- package/examples/studio/cadquery/bracket.py +36 -0
- package/examples/studio/cadquery/import_step.py +12 -0
- package/examples/studio/education/README.md +46 -0
- package/examples/studio/education/lesson.json +99 -0
- package/examples/studio/education/scene.py +7 -0
- package/examples/studio/hybrid-scene.ts +96 -0
- package/examples/studio/native-workflow.ts +14 -0
- package/examples/studio/vgpu/README.md +64 -0
- package/examples/studio/vgpu/heat-field.mjs +290 -0
- package/package.json +304 -0
- package/packages/scene/src/index.ts +1 -0
- package/packages/scene/src/scene.ts +215 -0
- package/schema/diagram.schema.json +334 -0
- package/skills/slopcamera/SKILL.md +45 -0
- package/skills/slopcamera/agents/openai.yaml +4 -0
- package/skills/slopcamera/references/customization.md +77 -0
- package/skills/slopcamera/references/diagrams.md +153 -0
- package/skills/slopcamera/references/directed-scenes.md +42 -0
- package/skills/slopcamera/references/directing-video.md +18 -0
- package/skills/slopcamera/references/educational-video.md +26 -0
- package/skills/slopcamera/references/gateway-media.md +134 -0
- package/skills/slopcamera/references/install.md +62 -0
- package/skills/slopcamera/references/native-studio.md +31 -0
- package/skills/slopcamera/references/reference-led-3d.md +140 -0
- package/skills/slopcamera/references/rubber-stamp-examples/poster-example-1.jpg +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/poster-example-2.jpg +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-1.png +0 -0
- package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-2.png +0 -0
- package/skills/slopcamera/references/rubber-stamp-field-notes.md +144 -0
- package/skills/slopcamera/references/vectorization.md +29 -0
- package/skills/slopcamera/references/video-projects.md +187 -0
- package/skills/slopcamera/references/visual-communication.md +120 -0
- package/skills/slopcamera/references/workflows-sdk.md +45 -0
- package/skills/slopcamera/scripts/compose-rubber-stamp-field-note.ts +229 -0
- package/src/artifacts.ts +106 -0
- package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
- package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
- package/src/assets/fonts/nebula-sans/PROVENANCE.md +21 -0
- package/src/assets.d.ts +9 -0
- package/src/cli.ts +601 -0
- package/src/cloud-errors.ts +26 -0
- package/src/code/advanced.ts +10 -0
- package/src/code/boundary.ts +21 -0
- package/src/code/canonical-json.ts +129 -0
- package/src/code/compiler.ts +953 -0
- package/src/code/contracts.ts +576 -0
- package/src/code/define-workflow.ts +334 -0
- package/src/code/errors.ts +41 -0
- package/src/code/graph-builder.ts +945 -0
- package/src/code/index.ts +121 -0
- package/src/code/json-snapshot.ts +899 -0
- package/src/code/json-utf8.ts +88 -0
- package/src/code/portable-builder.ts +136 -0
- package/src/code/projection.ts +378 -0
- package/src/code/public-operations.ts +450 -0
- package/src/code/runtime.ts +580 -0
- package/src/code/sha256.ts +36 -0
- package/src/config.ts +180 -0
- package/src/desktop.ts +253 -0
- package/src/fs.ts +10 -0
- package/src/generate.ts +704 -0
- package/src/host-resource-posix.ts +161 -0
- package/src/host-resources.ts +1749 -0
- package/src/icons.ts +58 -0
- package/src/index.ts +200 -0
- package/src/label-layout.ts +130 -0
- package/src/layout.ts +413 -0
- package/src/lint.ts +127 -0
- package/src/mcp/boundary.ts +354 -0
- package/src/mcp/index.ts +33 -0
- package/src/mcp/server.ts +272 -0
- package/src/mcp/tools.ts +963 -0
- package/src/mcp/types.ts +71 -0
- package/src/operations.ts +775 -0
- package/src/parse.ts +861 -0
- package/src/process-environment.ts +17 -0
- package/src/render.ts +437 -0
- package/src/skill-install.ts +49 -0
- package/src/spatial-scene/authoring.ts +27 -0
- package/src/spatial-scene/camera-track.ts +83 -0
- package/src/spatial-scene/contracts.ts +277 -0
- package/src/spatial-scene/evaluate.ts +145 -0
- package/src/spatial-scene/gltf.ts +558 -0
- package/src/spatial-scene/identity.ts +260 -0
- package/src/spatial-scene/index.ts +10 -0
- package/src/spatial-scene/inspect.ts +68 -0
- package/src/spatial-scene/math.ts +280 -0
- package/src/spatial-scene/patch.ts +131 -0
- package/src/spatial-scene/time.ts +53 -0
- package/src/studio/contracts.ts +129 -0
- package/src/studio/index.ts +2 -0
- package/src/studio/plan.ts +156 -0
- package/src/studio/shared.ts +41 -0
- package/src/theme.ts +68 -0
- package/src/tldr.ts +474 -0
- package/src/types.ts +212 -0
- package/src/vectorize/archive.ts +101 -0
- package/src/vectorize/command.ts +797 -0
- package/src/vectorize/index.ts +27 -0
- package/src/vectorize/limits.ts +61 -0
- package/src/vectorize/metrics.ts +351 -0
- package/src/vectorize/pixels.ts +323 -0
- package/src/vectorize/supervisor.ts +339 -0
- package/src/vectorize/svg.ts +188 -0
- package/src/vectorize/tool.ts +542 -0
- package/src/vectorize/types.ts +113 -0
- package/src/vectorize/vectorize.ts +634 -0
- package/src/vectorize/worker-protocol.ts +40 -0
- package/src/vectorize/worker.ts +209 -0
- package/src/version.ts +1 -0
- package/src/workflow.ts +409 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
commitProjectEditsOperationDefinition,
|
|
5
|
+
commitProjectEditsOperationDefinitionV2,
|
|
6
|
+
commitProjectEditsOperationDefinitionV3,
|
|
7
|
+
bindCandidateRevisionOperationDefinition,
|
|
8
|
+
createCandidateRevisionOperationDefinition,
|
|
9
|
+
createCreativeCandidateOperationDefinition,
|
|
10
|
+
createVariantMatrixOperationDefinition,
|
|
11
|
+
materializeVariantSelectionOperationDefinition,
|
|
12
|
+
promoteVariantSelectionOperationDefinition,
|
|
13
|
+
bindCandidateRenderOutputOperationDefinition,
|
|
14
|
+
selectVariantOperationDefinition,
|
|
15
|
+
createFacesOperationDefinition,
|
|
16
|
+
createMusicOperationDefinition,
|
|
17
|
+
createProjectEditRevisionOperationDefinition,
|
|
18
|
+
createProjectInactivityOperationDefinition,
|
|
19
|
+
sceneAnalysisOperationDefinition,
|
|
20
|
+
deriveEditBatchOperationDefinition,
|
|
21
|
+
deriveEditBatchOperationDefinitionV2,
|
|
22
|
+
deriveEditBatchOperationDefinitionV3,
|
|
23
|
+
followFacesOperationDefinition,
|
|
24
|
+
freezeProjectEditRevisionOperationDefinition,
|
|
25
|
+
gatewayImageOperationDefinition,
|
|
26
|
+
gatewaySpeechOperationDefinition,
|
|
27
|
+
gatewayTranscriptionOperationDefinition,
|
|
28
|
+
gatewayVideoOperationDefinition,
|
|
29
|
+
mediaAudioEffectsOperationDefinition,
|
|
30
|
+
mediaColorGradeOperationDefinition,
|
|
31
|
+
mediaIngestOperationDefinition,
|
|
32
|
+
createHtmlOverlayOperationDefinition,
|
|
33
|
+
mediaOverlayOperationDefinition,
|
|
34
|
+
projectAutoZoomOperationDefinition,
|
|
35
|
+
projectRenderPlanOperationDefinition,
|
|
36
|
+
projectRenderPlanOperationDefinitionV2,
|
|
37
|
+
projectRenderOperationDefinition,
|
|
38
|
+
projectRenderOperationDefinitionV2,
|
|
39
|
+
projectRenderOperationDefinitionV3,
|
|
40
|
+
projectRenderOperationDefinitionV4,
|
|
41
|
+
projectSnapshotOperationDefinition,
|
|
42
|
+
recordingPauseOperationDefinition,
|
|
43
|
+
recordingResumeOperationDefinition,
|
|
44
|
+
recordingStartOperationDefinition,
|
|
45
|
+
recordingStartOperationDefinitionV1,
|
|
46
|
+
recordingStopOperationDefinition,
|
|
47
|
+
slopcameraDiagramCheckOperationDefinition,
|
|
48
|
+
slopcameraDiagramRenderOperationDefinition,
|
|
49
|
+
slopcameraImageVectorizeOperationDefinition,
|
|
50
|
+
spatialInspectOperationDefinition,
|
|
51
|
+
spatialPatchOperationDefinition,
|
|
52
|
+
spatialEvaluateOperationDefinition,
|
|
53
|
+
spatialRenderOperationDefinition,
|
|
54
|
+
studioRunOperationDefinition,
|
|
55
|
+
spatialProjectSnapshotOperationDefinition,
|
|
56
|
+
spatialProjectMigrateOperationDefinition,
|
|
57
|
+
spatialProjectPatchOperationDefinition,
|
|
58
|
+
spatialProjectRestoreOperationDefinition,
|
|
59
|
+
spatialProjectAddShotOperationDefinition,
|
|
60
|
+
spatialProjectAddCandidateOperationDefinition,
|
|
61
|
+
spatialProjectSelectCandidateOperationDefinition,
|
|
62
|
+
spatialProjectReconcileOperationDefinition,
|
|
63
|
+
} from "./operations";
|
|
64
|
+
import { slopcameraPortableOperationDefinitions } from "./operations/slopcamera-portable";
|
|
65
|
+
import { SLOPCAMERA_APPLICATION_TOOL_VERSION } from "./operation";
|
|
66
|
+
import { OperationRegistry } from "./registry";
|
|
67
|
+
|
|
68
|
+
export interface CreateApplicationOperationRegistryOptions {
|
|
69
|
+
readonly nextAnalysisId?: () => string;
|
|
70
|
+
readonly toolVersion?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function createApplicationOperationRegistry(
|
|
74
|
+
options: CreateApplicationOperationRegistryOptions = {},
|
|
75
|
+
): OperationRegistry {
|
|
76
|
+
const nextAnalysisId = options.nextAnalysisId
|
|
77
|
+
?? (() => `analysis_${randomUUID().replaceAll("-", "")}`);
|
|
78
|
+
const toolVersion = options.toolVersion ?? SLOPCAMERA_APPLICATION_TOOL_VERSION;
|
|
79
|
+
const registry = new OperationRegistry();
|
|
80
|
+
registry.register(spatialInspectOperationDefinition);
|
|
81
|
+
registry.register(spatialPatchOperationDefinition);
|
|
82
|
+
registry.register(spatialEvaluateOperationDefinition);
|
|
83
|
+
registry.register(spatialRenderOperationDefinition);
|
|
84
|
+
registry.register(studioRunOperationDefinition);
|
|
85
|
+
registry.register(spatialProjectSnapshotOperationDefinition);
|
|
86
|
+
registry.register(spatialProjectMigrateOperationDefinition);
|
|
87
|
+
registry.register(spatialProjectPatchOperationDefinition);
|
|
88
|
+
registry.register(spatialProjectRestoreOperationDefinition);
|
|
89
|
+
registry.register(spatialProjectAddShotOperationDefinition);
|
|
90
|
+
registry.register(spatialProjectAddCandidateOperationDefinition);
|
|
91
|
+
registry.register(spatialProjectSelectCandidateOperationDefinition);
|
|
92
|
+
registry.register(spatialProjectReconcileOperationDefinition);
|
|
93
|
+
registry.register(projectSnapshotOperationDefinition);
|
|
94
|
+
registry.register(createProjectInactivityOperationDefinition({
|
|
95
|
+
nextAnalysisId,
|
|
96
|
+
toolVersion,
|
|
97
|
+
}));
|
|
98
|
+
registry.register(createFacesOperationDefinition({ nextAnalysisId }));
|
|
99
|
+
registry.register(createMusicOperationDefinition({ nextAnalysisId, toolVersion }));
|
|
100
|
+
registry.register(sceneAnalysisOperationDefinition);
|
|
101
|
+
registry.register(projectAutoZoomOperationDefinition);
|
|
102
|
+
registry.register(deriveEditBatchOperationDefinition);
|
|
103
|
+
registry.register(deriveEditBatchOperationDefinitionV2);
|
|
104
|
+
registry.register(deriveEditBatchOperationDefinitionV3);
|
|
105
|
+
registry.register(followFacesOperationDefinition);
|
|
106
|
+
registry.register(createCandidateRevisionOperationDefinition);
|
|
107
|
+
registry.register(bindCandidateRevisionOperationDefinition);
|
|
108
|
+
registry.register(freezeProjectEditRevisionOperationDefinition);
|
|
109
|
+
registry.register(createCreativeCandidateOperationDefinition);
|
|
110
|
+
registry.register(createVariantMatrixOperationDefinition);
|
|
111
|
+
registry.register(selectVariantOperationDefinition);
|
|
112
|
+
registry.register(mediaIngestOperationDefinition);
|
|
113
|
+
registry.register(createHtmlOverlayOperationDefinition({ toolVersion }));
|
|
114
|
+
registry.register(mediaOverlayOperationDefinition);
|
|
115
|
+
registry.register(mediaAudioEffectsOperationDefinition);
|
|
116
|
+
registry.register(mediaColorGradeOperationDefinition);
|
|
117
|
+
registry.register(gatewayImageOperationDefinition);
|
|
118
|
+
registry.register(gatewayVideoOperationDefinition);
|
|
119
|
+
registry.register(gatewaySpeechOperationDefinition);
|
|
120
|
+
registry.register(gatewayTranscriptionOperationDefinition);
|
|
121
|
+
registry.register(createProjectEditRevisionOperationDefinition);
|
|
122
|
+
registry.register(commitProjectEditsOperationDefinition);
|
|
123
|
+
registry.register(commitProjectEditsOperationDefinitionV2);
|
|
124
|
+
registry.register(commitProjectEditsOperationDefinitionV3);
|
|
125
|
+
registry.register(promoteVariantSelectionOperationDefinition);
|
|
126
|
+
registry.register(bindCandidateRenderOutputOperationDefinition);
|
|
127
|
+
registry.register(projectRenderPlanOperationDefinition);
|
|
128
|
+
registry.register(projectRenderPlanOperationDefinitionV2);
|
|
129
|
+
registry.register(projectRenderOperationDefinition);
|
|
130
|
+
registry.register(projectRenderOperationDefinitionV2);
|
|
131
|
+
registry.register(projectRenderOperationDefinitionV3);
|
|
132
|
+
registry.register(projectRenderOperationDefinitionV4);
|
|
133
|
+
registry.register(materializeVariantSelectionOperationDefinition);
|
|
134
|
+
registry.register(recordingStartOperationDefinitionV1);
|
|
135
|
+
registry.register(recordingStartOperationDefinition);
|
|
136
|
+
registry.register(recordingPauseOperationDefinition);
|
|
137
|
+
registry.register(recordingResumeOperationDefinition);
|
|
138
|
+
registry.register(recordingStopOperationDefinition);
|
|
139
|
+
registry.register(slopcameraDiagramCheckOperationDefinition);
|
|
140
|
+
registry.register(slopcameraDiagramRenderOperationDefinition);
|
|
141
|
+
registry.register(slopcameraImageVectorizeOperationDefinition);
|
|
142
|
+
for (const definition of slopcameraPortableOperationDefinitions) {
|
|
143
|
+
registry.register(definition);
|
|
144
|
+
}
|
|
145
|
+
return registry;
|
|
146
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { createBoundedJsonValueSnapshot } from "../../../src/code/json-snapshot";
|
|
4
|
+
import { Sha256Schema } from "../contracts";
|
|
5
|
+
import { canonicalJson, canonicalJsonSha256 } from "../core/canonical-json";
|
|
6
|
+
import {
|
|
7
|
+
GatewayMediaSourceReferenceSchema,
|
|
8
|
+
GatewayRequestIdSchema,
|
|
9
|
+
GatewayVideoOperationInputSchema,
|
|
10
|
+
GatewayVideoOperationResultSchema,
|
|
11
|
+
type GatewayMediaSourceReference,
|
|
12
|
+
type GatewayPortRequest,
|
|
13
|
+
} from "./gateway-port";
|
|
14
|
+
|
|
15
|
+
export const DIRECTING_LIMITS = Object.freeze({ shots: 64, recipes: 128, attempts: 1024, stateBytes: 32 * 1024 * 1024 });
|
|
16
|
+
const SlugSchema = z.string().regex(/^[a-z][a-z0-9_-]{0,63}$/u);
|
|
17
|
+
const RecipeIdSchema = z.string().regex(/^direct_[a-z][a-z0-9_-]{0,63}$/u);
|
|
18
|
+
const AttemptIdSchema = z.string().regex(/^take_[a-z][a-z0-9_-]{0,63}$/u);
|
|
19
|
+
const MoneySchema = z.number().int().safe().positive();
|
|
20
|
+
const TextSchema = z.string().min(1).max(100_000).refine(value => value.trim().length > 0 && !/[\u0000-\u0008\u000b\u000c\u000e-\u001f]/u.test(value), "Text must be nonempty and contain no disallowed control characters.");
|
|
21
|
+
const ImageSchema = GatewayMediaSourceReferenceSchema.refine(source => source.mediaType.startsWith("image/") && source.bytes <= 50 * 1024 * 1024, "A directing frame must be an image of at most 50 MiB.");
|
|
22
|
+
const VideoSourceSchema = GatewayMediaSourceReferenceSchema.refine(source => source.mediaType.startsWith("video/") && source.facts?.durationSeconds !== undefined, "Endpoint video sources require a measured duration.");
|
|
23
|
+
|
|
24
|
+
function capture(input: unknown, name: string, maximumBytes: number): unknown {
|
|
25
|
+
return createBoundedJsonValueSnapshot(input, maximumBytes, name, { maximumDepth: 32, maximumValues: 1_000_000 }).value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const DirectingShotSchema = z.strictObject({
|
|
29
|
+
id: SlugSchema,
|
|
30
|
+
prompt: TextSchema,
|
|
31
|
+
model: GatewayVideoOperationInputSchema.shape.model,
|
|
32
|
+
durationSeconds: z.number().int().min(1).max(60),
|
|
33
|
+
resolution: GatewayVideoOperationInputSchema.shape.resolution.unwrap(),
|
|
34
|
+
aspectRatio: GatewayVideoOperationInputSchema.shape.aspectRatio.unwrap(),
|
|
35
|
+
fps: GatewayVideoOperationInputSchema.shape.fps,
|
|
36
|
+
seed: GatewayVideoOperationInputSchema.shape.seed,
|
|
37
|
+
firstFrame: z.discriminatedUnion("kind", [
|
|
38
|
+
z.strictObject({ kind: z.literal("image"), source: ImageSchema }),
|
|
39
|
+
z.strictObject({ kind: z.literal("shot-end"), shotId: SlugSchema }),
|
|
40
|
+
]).optional(),
|
|
41
|
+
lastFrame: ImageSchema.optional(),
|
|
42
|
+
}).superRefine((shot, context) => {
|
|
43
|
+
if (shot.lastFrame !== undefined && shot.firstFrame === undefined) context.addIssue({ code: "custom", message: "A last frame requires an authored first-frame reference." });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export const DirectingRecipeSchema = z.preprocess(input => capture(input, "directing recipe", 8 * 1024 * 1024), z.strictObject({
|
|
47
|
+
kind: z.literal("slopcamera.directing-recipe"),
|
|
48
|
+
schemaVersion: z.literal(1),
|
|
49
|
+
id: RecipeIdSchema,
|
|
50
|
+
title: TextSchema.max(512),
|
|
51
|
+
shots: z.array(DirectingShotSchema).min(1).max(DIRECTING_LIMITS.shots),
|
|
52
|
+
}).superRefine((recipe, context) => {
|
|
53
|
+
const seen = new Set<string>();
|
|
54
|
+
for (const [index, shot] of recipe.shots.entries()) {
|
|
55
|
+
if (seen.has(shot.id)) context.addIssue({ code: "custom", path: ["shots", index, "id"], message: "Shot IDs must be unique." });
|
|
56
|
+
if (shot.firstFrame?.kind === "shot-end" && !seen.has(shot.firstFrame.shotId)) context.addIssue({ code: "custom", path: ["shots", index, "firstFrame"], message: "A shot-end reference must name an earlier shot." });
|
|
57
|
+
seen.add(shot.id);
|
|
58
|
+
}
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
export const DirectingPtsSchema = z.strictObject({
|
|
62
|
+
value: z.string().regex(/^(?:0|-?[1-9][0-9]{0,19})$/u),
|
|
63
|
+
timeBaseNumerator: z.number().int().safe().positive().max(1_000_000_000),
|
|
64
|
+
timeBaseDenominator: z.number().int().safe().positive().max(1_000_000_000),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/** Native PTS can precede zero or start beyond the clip's relative duration. */
|
|
68
|
+
export function directingPtsTimeUs(input: z.infer<typeof DirectingPtsSchema>): number {
|
|
69
|
+
const pts = DirectingPtsSchema.parse(input);
|
|
70
|
+
const numerator = BigInt(pts.value) * BigInt(pts.timeBaseNumerator) * 1_000_000n;
|
|
71
|
+
const denominator = BigInt(pts.timeBaseDenominator), absolute = numerator < 0n ? -numerator : numerator;
|
|
72
|
+
// Round nearest, with exact half-microsecond ties away from zero.
|
|
73
|
+
const rounded = (2n * absolute + denominator) / (2n * denominator);
|
|
74
|
+
const timeUs = Number(numerator < 0n ? -rounded : rounded);
|
|
75
|
+
if (!Number.isSafeInteger(timeUs)) throw new RangeError("Native endpoint PTS exceeds the safe microsecond clock.");
|
|
76
|
+
return timeUs;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const DirectingEndpointSchema = z.strictObject({
|
|
80
|
+
image: ImageSchema,
|
|
81
|
+
source: VideoSourceSchema,
|
|
82
|
+
frameIndex: z.number().int().safe().nonnegative(),
|
|
83
|
+
pts: DirectingPtsSchema,
|
|
84
|
+
timeUs: z.number().int().safe(),
|
|
85
|
+
}).superRefine((endpoint, context) => {
|
|
86
|
+
try {
|
|
87
|
+
if (endpoint.timeUs !== directingPtsTimeUs(endpoint.pts)) context.addIssue({ code: "custom", message: "Endpoint microseconds must match the rounded native rational PTS." });
|
|
88
|
+
} catch {
|
|
89
|
+
context.addIssue({ code: "custom", message: "Native endpoint PTS exceeds the safe microsecond clock." });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
export const DirectingQuoteSchema = z.strictObject({
|
|
94
|
+
catalogSha256: Sha256Schema,
|
|
95
|
+
validatedAt: z.iso.datetime({ offset: true }),
|
|
96
|
+
costMicroUsd: MoneySchema,
|
|
97
|
+
rateMicroUsdPerSecond: MoneySchema,
|
|
98
|
+
});
|
|
99
|
+
export const DirectingDependencySchema = z.strictObject({ shotId: SlugSchema, attemptId: AttemptIdSchema, outputSha256: Sha256Schema });
|
|
100
|
+
const ReviewSchema = z.strictObject({ decision: z.enum(["accepted", "rejected"]), note: TextSchema.max(4096).optional() });
|
|
101
|
+
const FailureSchema = z.string().regex(/^[a-z][a-z0-9-]{0,63}$/u);
|
|
102
|
+
const VideoRequestSchema = z.strictObject({ operation: z.literal("video"), request: GatewayVideoOperationInputSchema }).superRefine((input, context) => {
|
|
103
|
+
const request = input.request;
|
|
104
|
+
if (request.providerOptions !== undefined || request.references !== undefined || request.generateAudio !== undefined || (request.n ?? 1) !== 1 || (request.maxVideosPerCall ?? 1) !== 1) context.addIssue({ code: "custom", message: "Directing uses exactly one video with authored frame conditioning and no provider options." });
|
|
105
|
+
});
|
|
106
|
+
const AttemptBase = {
|
|
107
|
+
id: AttemptIdSchema,
|
|
108
|
+
recipeSha256: Sha256Schema,
|
|
109
|
+
shotId: SlugSchema,
|
|
110
|
+
shotSha256: Sha256Schema,
|
|
111
|
+
requestId: GatewayRequestIdSchema,
|
|
112
|
+
request: VideoRequestSchema,
|
|
113
|
+
quote: DirectingQuoteSchema,
|
|
114
|
+
dependencies: z.array(DirectingDependencySchema).max(1),
|
|
115
|
+
};
|
|
116
|
+
export const DirectingAttemptSchema = z.discriminatedUnion("state", [
|
|
117
|
+
z.strictObject({ ...AttemptBase, state: z.literal("reserved") }),
|
|
118
|
+
z.strictObject({ ...AttemptBase, state: z.literal("completed"), result: GatewayVideoOperationResultSchema, endpoint: DirectingEndpointSchema.optional(), review: ReviewSchema.optional() }),
|
|
119
|
+
z.strictObject({ ...AttemptBase, state: z.literal("not-dispatched"), failure: FailureSchema.optional() }),
|
|
120
|
+
z.strictObject({ ...AttemptBase, state: z.literal("ambiguous"), failure: FailureSchema.optional() }),
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
export type DirectingShot = z.infer<typeof DirectingShotSchema>;
|
|
124
|
+
export type DirectingRecipe = z.infer<typeof DirectingRecipeSchema>;
|
|
125
|
+
export type DirectingEndpoint = z.infer<typeof DirectingEndpointSchema>;
|
|
126
|
+
export type DirectingQuote = z.infer<typeof DirectingQuoteSchema>;
|
|
127
|
+
export type DirectingDependency = z.infer<typeof DirectingDependencySchema>;
|
|
128
|
+
export type DirectingAttempt = z.infer<typeof DirectingAttemptSchema>;
|
|
129
|
+
export type CompletedDirectingAttempt = Extract<DirectingAttempt, { state: "completed" }>;
|
|
130
|
+
|
|
131
|
+
/** Facts are remeasured by the media port; immutable source identity is not. */
|
|
132
|
+
export function sameDirectingSource(left: GatewayMediaSourceReference, right: GatewayMediaSourceReference): boolean {
|
|
133
|
+
return left.path === right.path && left.sha256 === right.sha256 && left.bytes === right.bytes && left.mediaType === right.mediaType;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function directingBoundShotSha256(shot: DirectingShot, dependencies: readonly (DirectingDependency & { readonly shotSha256: string })[]): string {
|
|
137
|
+
return canonicalJsonSha256({ domain: "slopcamera.directing-shot/v1", shot, dependencies });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Bind local reconciliation to the exact prepared request and retained take. */
|
|
141
|
+
export function directingRequestId(input: {
|
|
142
|
+
readonly id: string;
|
|
143
|
+
readonly attemptId: string;
|
|
144
|
+
readonly recipeSha256: string;
|
|
145
|
+
readonly shotSha256: string;
|
|
146
|
+
readonly request: GatewayPortRequest;
|
|
147
|
+
}): string {
|
|
148
|
+
const { id, attemptId, recipeSha256, shotSha256, request } = input;
|
|
149
|
+
return `gateway_${canonicalJsonSha256({ domain: "slopcamera.directing-request/v1", id, attemptId, recipeSha256, shotSha256, request })}`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Verify the submitted request against the authored recipe and retained frames. */
|
|
153
|
+
export function directingRequestMatchesShot(attempt: DirectingAttempt, shot: DirectingShot, firstFrame: GatewayMediaSourceReference | undefined): boolean {
|
|
154
|
+
const request = attempt.request.request;
|
|
155
|
+
for (const key of ["prompt", "model", "durationSeconds", "resolution", "aspectRatio", "fps", "seed"] as const) if (request[key] !== shot[key]) return false;
|
|
156
|
+
const frames = request.frames ?? [];
|
|
157
|
+
const actualFirst = request.promptImage ?? frames.find(frame => frame.frameType === "first_frame")?.source;
|
|
158
|
+
const actualLast = frames.find(frame => frame.frameType === "last_frame")?.source;
|
|
159
|
+
const equal = (left: GatewayMediaSourceReference | undefined, right: GatewayMediaSourceReference | undefined) => left === undefined || right === undefined ? left === right : sameDirectingSource(left, right);
|
|
160
|
+
return equal(firstFrame, actualFirst) && equal(shot.lastFrame, actualLast);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export const DirectingStateSchema = z.preprocess(input => capture(input, "directing state", DIRECTING_LIMITS.stateBytes), z.strictObject({
|
|
164
|
+
kind: z.literal("slopcamera.directing-state"),
|
|
165
|
+
schemaVersion: z.literal(1),
|
|
166
|
+
id: RecipeIdSchema,
|
|
167
|
+
budgetMicroUsd: MoneySchema,
|
|
168
|
+
activeRecipeSha256: Sha256Schema,
|
|
169
|
+
recipes: z.array(z.strictObject({ sha256: Sha256Schema, recipe: DirectingRecipeSchema })).min(1).max(DIRECTING_LIMITS.recipes),
|
|
170
|
+
attempts: z.array(DirectingAttemptSchema).max(DIRECTING_LIMITS.attempts),
|
|
171
|
+
selections: z.record(SlugSchema, AttemptIdSchema),
|
|
172
|
+
}).superRefine((state, context) => {
|
|
173
|
+
const fail = (message: string) => context.addIssue({ code: "custom", message });
|
|
174
|
+
const recipes = new Map<string, DirectingRecipe>();
|
|
175
|
+
for (const item of state.recipes) {
|
|
176
|
+
if (item.recipe.id !== state.id || item.sha256 !== canonicalJsonSha256(item.recipe) || recipes.has(item.sha256)) fail("Retained recipe identities must be unique and bind their exact recipe and directing project.");
|
|
177
|
+
recipes.set(item.sha256, item.recipe);
|
|
178
|
+
}
|
|
179
|
+
if (!recipes.has(state.activeRecipeSha256)) fail("The active recipe must be retained.");
|
|
180
|
+
const attempts = new Map<string, DirectingAttempt>();
|
|
181
|
+
const requestIds = new Set<string>();
|
|
182
|
+
let reserved = 0n;
|
|
183
|
+
for (const attempt of state.attempts) {
|
|
184
|
+
if (attempts.has(attempt.id) || requestIds.has(attempt.requestId)) fail("Attempt and paid request identities must be unique.");
|
|
185
|
+
if (attempt.requestId !== directingRequestId({ id: state.id, attemptId: attempt.id, recipeSha256: attempt.recipeSha256, shotSha256: attempt.shotSha256, request: attempt.request })) fail("A paid request identity must bind the exact directing project, take, recipe, shot, and request.");
|
|
186
|
+
const shot = recipes.get(attempt.recipeSha256)?.shots.find(candidate => candidate.id === attempt.shotId);
|
|
187
|
+
if (shot === undefined) { fail("Each attempt must bind a retained authored shot."); continue; }
|
|
188
|
+
const dependency = attempt.dependencies[0];
|
|
189
|
+
const predecessor = dependency === undefined ? undefined : attempts.get(dependency.attemptId);
|
|
190
|
+
if (shot.firstFrame?.kind === "shot-end") {
|
|
191
|
+
if (dependency === undefined || dependency.shotId !== shot.firstFrame.shotId || predecessor?.shotId !== dependency.shotId || predecessor.state !== "completed" || predecessor.endpoint === undefined || predecessor.result.outputs[0]?.sha256 !== dependency.outputSha256) fail("A continuation must bind an earlier completed take and its exact retained endpoint.");
|
|
192
|
+
} else if (dependency !== undefined) fail("A shot without continuation cannot claim dependencies.");
|
|
193
|
+
const boundDependencies = dependency !== undefined && predecessor !== undefined ? [{ ...dependency, shotSha256: predecessor.shotSha256 }] : [];
|
|
194
|
+
if (attempt.shotSha256 !== directingBoundShotSha256(shot, boundDependencies)) fail("A take must bind its exact authored shot and recursive dependency identity.");
|
|
195
|
+
const firstFrame = shot.firstFrame?.kind === "image" ? shot.firstFrame.source : predecessor?.state === "completed" ? predecessor.endpoint?.image : undefined;
|
|
196
|
+
if (!directingRequestMatchesShot(attempt, shot, firstFrame)) fail("A take's paid request differs from its authored shot or retained conditioning.");
|
|
197
|
+
if (BigInt(attempt.quote.costMicroUsd) !== BigInt(attempt.quote.rateMicroUsdPerSecond) * BigInt(shot.durationSeconds)) fail("A quote must reserve the exact duration at its retained per-second rate.");
|
|
198
|
+
if (attempt.state !== "not-dispatched") reserved += BigInt(attempt.quote.costMicroUsd);
|
|
199
|
+
if (attempt.state === "completed") {
|
|
200
|
+
const output = attempt.result.outputs[0];
|
|
201
|
+
if (attempt.result.requestId !== attempt.requestId || attempt.result.model !== shot.model || attempt.result.outputs.length !== 1 || output === undefined || !output.mediaType.startsWith("video/")) fail("A completed take must retain its exact one-video Gateway result.");
|
|
202
|
+
if (attempt.endpoint !== undefined && (output === undefined || !sameDirectingSource(attempt.endpoint.source, output))) fail("An endpoint must bind the completed video's immutable bytes.");
|
|
203
|
+
if (attempt.review?.decision === "accepted" && attempt.endpoint === undefined) fail("Accepting a take requires its verified endpoint and measured video duration.");
|
|
204
|
+
}
|
|
205
|
+
attempts.set(attempt.id, attempt);
|
|
206
|
+
requestIds.add(attempt.requestId);
|
|
207
|
+
}
|
|
208
|
+
if (reserved > BigInt(state.budgetMicroUsd)) fail("Reserved and potentially spent credits exceed the directing budget.");
|
|
209
|
+
if (Object.keys(state.selections).length > DIRECTING_LIMITS.attempts) fail("Too many retained selections.");
|
|
210
|
+
for (const [shotId, attemptId] of Object.entries(state.selections)) {
|
|
211
|
+
const attempt = attempts.get(attemptId);
|
|
212
|
+
if (attempt?.shotId !== shotId || attempt.state !== "completed" || attempt.review?.decision !== "accepted") fail("Selections must identify accepted completed takes for their own shot.");
|
|
213
|
+
}
|
|
214
|
+
}));
|
|
215
|
+
export type DirectingState = z.infer<typeof DirectingStateSchema>;
|
|
216
|
+
|
|
217
|
+
/** Stable equality is used only after the owned schemas capture foreign JSON. */
|
|
218
|
+
export function equalDirectingValue(left: unknown, right: unknown): boolean { return canonicalJson(left) === canonicalJson(right); }
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { canonicalJsonSha256 } from "../core/canonical-json";
|
|
2
|
+
import type { GatewayMediaSourceReference, GatewayVideoOperationResult } from "./gateway-port";
|
|
3
|
+
import {
|
|
4
|
+
DirectingAttemptSchema, DirectingEndpointSchema, DirectingRecipeSchema, DirectingStateSchema,
|
|
5
|
+
directingBoundShotSha256, equalDirectingValue,
|
|
6
|
+
type CompletedDirectingAttempt, type DirectingAttempt, type DirectingDependency, type DirectingEndpoint,
|
|
7
|
+
type DirectingRecipe, type DirectingShot, type DirectingState,
|
|
8
|
+
} from "./directing-contract";
|
|
9
|
+
|
|
10
|
+
export function parseDirectingRecipe(input: unknown): DirectingRecipe { return DirectingRecipeSchema.parse(input); }
|
|
11
|
+
export function parseDirectingState(input: unknown): DirectingState { return DirectingStateSchema.parse(input); }
|
|
12
|
+
export function directingRecipeSha256(input: unknown): string { return canonicalJsonSha256(parseDirectingRecipe(input)); }
|
|
13
|
+
|
|
14
|
+
export function createDirectingState(recipeInput: unknown, budgetMicroUsd: number): DirectingState {
|
|
15
|
+
const recipe = parseDirectingRecipe(recipeInput), sha256 = directingRecipeSha256(recipe);
|
|
16
|
+
return parseDirectingState({ kind: "slopcamera.directing-state", schemaVersion: 1, id: recipe.id, budgetMicroUsd, activeRecipeSha256: sha256, recipes: [{ sha256, recipe }], attempts: [], selections: {} });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function currentRecipe(state: DirectingState): DirectingRecipe {
|
|
20
|
+
const recipe = state.recipes.find(item => item.sha256 === state.activeRecipeSha256)?.recipe;
|
|
21
|
+
if (recipe === undefined) throw new RangeError("The active directing recipe is missing.");
|
|
22
|
+
return recipe;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ResolvedDirectingShot {
|
|
26
|
+
readonly shot: DirectingShot;
|
|
27
|
+
readonly shotSha256: string;
|
|
28
|
+
readonly dependencies: DirectingDependency[];
|
|
29
|
+
readonly firstFrame?: GatewayMediaSourceReference;
|
|
30
|
+
readonly lastFrame?: GatewayMediaSourceReference;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function resolveShot(shot: DirectingShot, accepted: ReadonlyMap<string, CompletedDirectingAttempt>): ResolvedDirectingShot | undefined {
|
|
34
|
+
const dependencies: DirectingDependency[] = [];
|
|
35
|
+
const boundDependencies: (DirectingDependency & { shotSha256: string })[] = [];
|
|
36
|
+
let firstFrame: GatewayMediaSourceReference | undefined;
|
|
37
|
+
if (shot.firstFrame?.kind === "image") firstFrame = shot.firstFrame.source;
|
|
38
|
+
if (shot.firstFrame?.kind === "shot-end") {
|
|
39
|
+
const predecessor = accepted.get(shot.firstFrame.shotId);
|
|
40
|
+
if (predecessor?.endpoint === undefined) return undefined;
|
|
41
|
+
const dependency = { shotId: predecessor.shotId, attemptId: predecessor.id, outputSha256: predecessor.result.outputs[0]!.sha256 };
|
|
42
|
+
dependencies.push(dependency);
|
|
43
|
+
boundDependencies.push({ ...dependency, shotSha256: predecessor.shotSha256 });
|
|
44
|
+
firstFrame = predecessor.endpoint.image;
|
|
45
|
+
}
|
|
46
|
+
return { shot, shotSha256: directingBoundShotSha256(shot, boundDependencies), dependencies, ...(firstFrame === undefined ? {} : { firstFrame }), ...(shot.lastFrame === undefined ? {} : { lastFrame: shot.lastFrame }) };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function acceptedSelections(state: DirectingState): Map<string, CompletedDirectingAttempt> {
|
|
50
|
+
const attempts = new Map(state.attempts.map(attempt => [attempt.id, attempt]));
|
|
51
|
+
const accepted = new Map<string, CompletedDirectingAttempt>();
|
|
52
|
+
// Recipes only reference earlier shots, so this pass also checks every ancestor.
|
|
53
|
+
for (const shot of currentRecipe(state).shots) {
|
|
54
|
+
const selectedId = Object.hasOwn(state.selections, shot.id) ? state.selections[shot.id] : undefined;
|
|
55
|
+
const attempt = selectedId === undefined ? undefined : attempts.get(selectedId);
|
|
56
|
+
if (attempt?.state !== "completed" || attempt.review?.decision !== "accepted" || attempt.endpoint === undefined) continue;
|
|
57
|
+
const resolved = resolveShot(shot, accepted);
|
|
58
|
+
if (resolved !== undefined && attempt.shotSha256 === resolved.shotSha256 && equalDirectingValue(attempt.dependencies, resolved.dependencies)) accepted.set(shot.id, attempt);
|
|
59
|
+
}
|
|
60
|
+
return accepted;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function activeDirectingSelections(input: DirectingState): Record<string, CompletedDirectingAttempt> {
|
|
64
|
+
const selections: Record<string, CompletedDirectingAttempt> = Object.create(null) as Record<string, CompletedDirectingAttempt>;
|
|
65
|
+
for (const [shotId, attempt] of acceptedSelections(parseDirectingState(input))) selections[shotId] = attempt;
|
|
66
|
+
return selections;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function resolveDirectingShot(input: DirectingState, shotId: string): ResolvedDirectingShot {
|
|
70
|
+
const state = parseDirectingState(input);
|
|
71
|
+
const shot = currentRecipe(state).shots.find(candidate => candidate.id === shotId);
|
|
72
|
+
if (shot === undefined) throw new RangeError(`Unknown directing shot: ${shotId}.`);
|
|
73
|
+
const resolved = resolveShot(shot, acceptedSelections(state));
|
|
74
|
+
if (resolved === undefined) throw new RangeError("A continuation requires a currently accepted predecessor with its retained endpoint.");
|
|
75
|
+
return resolved;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function reviseDirectingRecipe(input: DirectingState, recipeInput: unknown): DirectingState {
|
|
79
|
+
const state = parseDirectingState(input), recipe = parseDirectingRecipe(recipeInput), sha256 = directingRecipeSha256(recipe);
|
|
80
|
+
if (recipe.id !== state.id) throw new RangeError("A directing revision cannot change project identity.");
|
|
81
|
+
return parseDirectingState({ ...state, activeRecipeSha256: sha256, recipes: state.recipes.some(item => item.sha256 === sha256) ? state.recipes : [...state.recipes, { sha256, recipe }] });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Ambiguous, failed-after-dispatch and interrupted calls retain their reservation. */
|
|
85
|
+
export function totalDirectingReservedMicroUsd(input: DirectingState): number {
|
|
86
|
+
const state = parseDirectingState(input);
|
|
87
|
+
return Number(state.attempts.reduce((sum, attempt) => sum + (attempt.state === "not-dispatched" ? 0n : BigInt(attempt.quote.costMicroUsd)), 0n));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function reserveDirectingAttempt(input: DirectingState, attemptInput: unknown): DirectingState {
|
|
91
|
+
const state = parseDirectingState(input), attempt = DirectingAttemptSchema.parse(attemptInput);
|
|
92
|
+
if (attempt.state !== "reserved") throw new RangeError("A new directing take must be reserved before dispatch.");
|
|
93
|
+
const existing = state.attempts.find(candidate => candidate.id === attempt.id);
|
|
94
|
+
if (existing !== undefined) {
|
|
95
|
+
if (equalDirectingValue(existing, attempt)) return state;
|
|
96
|
+
throw new RangeError("A retained take identity cannot be reused for another attempt.");
|
|
97
|
+
}
|
|
98
|
+
const resolved = resolveDirectingShot(state, attempt.shotId);
|
|
99
|
+
if (attempt.recipeSha256 !== state.activeRecipeSha256 || attempt.shotSha256 !== resolved.shotSha256 || !equalDirectingValue(attempt.dependencies, resolved.dependencies)) throw new RangeError("The directing reservation is stale against the active recipe or accepted dependencies.");
|
|
100
|
+
return parseDirectingState({ ...state, attempts: [...state.attempts, attempt] });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function replaceAttempt(state: DirectingState, attempt: DirectingAttempt): DirectingState {
|
|
104
|
+
return parseDirectingState({ ...state, attempts: state.attempts.map(candidate => candidate.id === attempt.id ? attempt : candidate) });
|
|
105
|
+
}
|
|
106
|
+
function findAttempt(state: DirectingState, attemptId: string): DirectingAttempt {
|
|
107
|
+
const attempt = state.attempts.find(candidate => candidate.id === attemptId);
|
|
108
|
+
if (attempt === undefined) throw new RangeError(`Unknown directing take: ${attemptId}.`);
|
|
109
|
+
return attempt;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function completeDirectingAttempt(input: DirectingState, attemptId: string, result: GatewayVideoOperationResult, endpoint?: DirectingEndpoint): DirectingState {
|
|
113
|
+
const state = parseDirectingState(input), attempt = findAttempt(state, attemptId);
|
|
114
|
+
if (attempt.state === "completed") {
|
|
115
|
+
if (!equalDirectingValue(attempt.result, result)) throw new RangeError("A completed take's result is immutable.");
|
|
116
|
+
return endpoint === undefined ? state : attachDirectingEndpoint(state, attemptId, endpoint);
|
|
117
|
+
}
|
|
118
|
+
if (attempt.state === "not-dispatched") throw new RangeError("A proven undispatched take cannot become completed.");
|
|
119
|
+
const { state: _state, ...base } = attempt;
|
|
120
|
+
const { failure: _failure, ...fields } = "failure" in base ? base : { ...base, failure: undefined };
|
|
121
|
+
return replaceAttempt(state, DirectingAttemptSchema.parse({ ...fields, state: "completed", result, ...(endpoint === undefined ? {} : { endpoint }) }));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function attachDirectingEndpoint(input: DirectingState, attemptId: string, endpointInput: unknown): DirectingState {
|
|
125
|
+
const state = parseDirectingState(input), attempt = findAttempt(state, attemptId), endpoint = DirectingEndpointSchema.parse(endpointInput);
|
|
126
|
+
if (attempt.state !== "completed") throw new RangeError("Endpoint extraction requires a completed take.");
|
|
127
|
+
if (attempt.endpoint !== undefined && !equalDirectingValue(attempt.endpoint, endpoint)) throw new RangeError("A retained endpoint is immutable.");
|
|
128
|
+
return replaceAttempt(state, { ...attempt, endpoint });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The adapter must supply durable evidence before choosing not-dispatched. */
|
|
132
|
+
export function settleDirectingAttempt(input: DirectingState, attemptId: string, status: "not-dispatched" | "ambiguous", failure?: string): DirectingState {
|
|
133
|
+
const state = parseDirectingState(input), attempt = findAttempt(state, attemptId);
|
|
134
|
+
if (attempt.state === "completed") throw new RangeError("A completed take cannot release or replace its paid reservation.");
|
|
135
|
+
if (attempt.state === "ambiguous" && status === "not-dispatched") throw new RangeError("An ambiguous take cannot release its reservation; missing local evidence does not prove the paid call was undispatched.");
|
|
136
|
+
if (attempt.state === "not-dispatched" && status !== "not-dispatched") throw new RangeError("A proven undispatched take cannot be dispatched or revived.");
|
|
137
|
+
const { state: _state, ...base } = attempt;
|
|
138
|
+
return replaceAttempt(state, DirectingAttemptSchema.parse({ ...base, state: status, ...(failure === undefined ? {} : { failure }) }));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function reviewDirectingAttempt(input: DirectingState, attemptId: string, decision: "accepted" | "rejected", note?: string): DirectingState {
|
|
142
|
+
const state = parseDirectingState(input), attempt = findAttempt(state, attemptId);
|
|
143
|
+
if (attempt.state !== "completed") throw new RangeError("Only completed takes can be reviewed.");
|
|
144
|
+
if (decision === "accepted") {
|
|
145
|
+
if (attempt.endpoint === undefined) throw new RangeError("Accepting a take requires its retained endpoint and measured duration.");
|
|
146
|
+
const resolved = resolveDirectingShot(state, attempt.shotId);
|
|
147
|
+
if (attempt.shotSha256 !== resolved.shotSha256 || !equalDirectingValue(attempt.dependencies, resolved.dependencies)) throw new RangeError("This take is stale against the active shot or its accepted dependencies.");
|
|
148
|
+
}
|
|
149
|
+
const selections = { ...state.selections };
|
|
150
|
+
if (decision === "accepted") selections[attempt.shotId] = attempt.id;
|
|
151
|
+
else if (Object.hasOwn(selections, attempt.shotId) && selections[attempt.shotId] === attempt.id) delete selections[attempt.shotId];
|
|
152
|
+
const reviewed = DirectingAttemptSchema.parse({ ...attempt, review: { decision, ...(note === undefined ? {} : { note }) } });
|
|
153
|
+
return parseDirectingState({ ...state, selections, attempts: state.attempts.map(candidate => candidate.id === attempt.id ? reviewed : candidate) });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface DirectingTimelineShot {
|
|
157
|
+
readonly shotId: string;
|
|
158
|
+
readonly attemptId: string;
|
|
159
|
+
readonly source: GatewayMediaSourceReference;
|
|
160
|
+
readonly startUs: number;
|
|
161
|
+
readonly endUs: number;
|
|
162
|
+
readonly durationUs: number;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function buildDirectingTimeline(input: DirectingState): DirectingTimelineShot[] {
|
|
166
|
+
const state = parseDirectingState(input), accepted = acceptedSelections(state);
|
|
167
|
+
let timeUs = 0;
|
|
168
|
+
return currentRecipe(state).shots.map(shot => {
|
|
169
|
+
const attempt = accepted.get(shot.id);
|
|
170
|
+
if (attempt?.endpoint === undefined) throw new RangeError(`Shot ${shot.id} requires a currently accepted take before assembly.`);
|
|
171
|
+
const source = attempt.endpoint.source;
|
|
172
|
+
const durationUs = Math.round(source.facts!.durationSeconds! * 1_000_000);
|
|
173
|
+
if (!Number.isSafeInteger(durationUs) || durationUs <= 0 || !Number.isSafeInteger(timeUs + durationUs)) throw new RangeError("Measured clip durations exceed the safe directing timeline.");
|
|
174
|
+
const result = { shotId: shot.id, attemptId: attempt.id, source, startUs: timeUs, endUs: timeUs + durationUs, durationUs };
|
|
175
|
+
timeUs = result.endUs;
|
|
176
|
+
return result;
|
|
177
|
+
});
|
|
178
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SlopcameraCodeError,
|
|
3
|
+
asSlopcameraCodeError,
|
|
4
|
+
slopcameraCodeErrorMessage,
|
|
5
|
+
type SlopcameraCodeErrorCode,
|
|
6
|
+
} from "@hraness/slopcamera/code/advanced";
|
|
7
|
+
|
|
8
|
+
export type ApplicationErrorCode = SlopcameraCodeErrorCode;
|
|
9
|
+
export type ApplicationError = SlopcameraCodeError;
|
|
10
|
+
|
|
11
|
+
/** The complete local host and portable SDK share one error identity. */
|
|
12
|
+
export const ApplicationError = SlopcameraCodeError;
|
|
13
|
+
|
|
14
|
+
export const errorMessage = slopcameraCodeErrorMessage;
|
|
15
|
+
|
|
16
|
+
export function asApplicationError(error: unknown): ApplicationError {
|
|
17
|
+
return asSlopcameraCodeError(error);
|
|
18
|
+
}
|