@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,324 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ProjectRenderEncoderRecipeSchema,
|
|
5
|
+
ProjectRenderOutputRequestSchema,
|
|
6
|
+
ProjectRenderSyncPolicySchema,
|
|
7
|
+
ProjectRenderTargetSchema,
|
|
8
|
+
ProjectRenderToolchainSchema,
|
|
9
|
+
resolveProjectRenderEncoderRecipe,
|
|
10
|
+
type ProjectRenderToolchain,
|
|
11
|
+
} from "../../../contracts";
|
|
12
|
+
import {
|
|
13
|
+
canonicalJson,
|
|
14
|
+
canonicalJsonSha256,
|
|
15
|
+
} from "../../../core";
|
|
16
|
+
import {
|
|
17
|
+
CreativeCandidateRevisionReferenceV1Schema,
|
|
18
|
+
} from "../../creative-iteration";
|
|
19
|
+
import { ApplicationError } from "../../errors";
|
|
20
|
+
import type { OperationDefinition } from "../../operation";
|
|
21
|
+
import {
|
|
22
|
+
ProjectRenderPlanReferenceSchema,
|
|
23
|
+
RenderableProjectEditRevisionReferenceSchema,
|
|
24
|
+
} from "../../receipts";
|
|
25
|
+
import { throwIfAborted } from "../shared";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Increment this ABI whenever Slopcamera's project-render implementation can
|
|
29
|
+
* change encoded output without changing the render plan or encoder recipe.
|
|
30
|
+
*/
|
|
31
|
+
export const SLOPCAMERA_PROJECT_RENDERER_ABI =
|
|
32
|
+
"slopcamera-project-renderer-abi-v1" as const;
|
|
33
|
+
|
|
34
|
+
export const CandidateProjectRendererAbiSchema = z.string()
|
|
35
|
+
.min(1)
|
|
36
|
+
.max(80)
|
|
37
|
+
.regex(/^slopcamera-project-renderer-abi-v[1-9][0-9]*$/u);
|
|
38
|
+
|
|
39
|
+
const CandidateRenderDerivationBodyV1Schema = z.strictObject({
|
|
40
|
+
binding: ProjectRenderToolchainSchema,
|
|
41
|
+
candidateRevision: CreativeCandidateRevisionReferenceV1Schema,
|
|
42
|
+
encoderRecipe: ProjectRenderEncoderRecipeSchema,
|
|
43
|
+
kind: z.union([
|
|
44
|
+
z.literal("slopcamera.candidate-render-derivation"),
|
|
45
|
+
]),
|
|
46
|
+
maximumBytes: ProjectRenderOutputRequestSchema.shape.maximumBytes,
|
|
47
|
+
plan: ProjectRenderPlanReferenceSchema,
|
|
48
|
+
rendererAbi: CandidateProjectRendererAbiSchema,
|
|
49
|
+
revision: RenderableProjectEditRevisionReferenceSchema,
|
|
50
|
+
schemaVersion: z.literal(1),
|
|
51
|
+
syncPolicy: ProjectRenderSyncPolicySchema,
|
|
52
|
+
target: ProjectRenderTargetSchema,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export const CandidateRenderDerivationV1Schema =
|
|
56
|
+
CandidateRenderDerivationBodyV1Schema.extend({
|
|
57
|
+
derivationSha256: z.string().regex(/^[a-f0-9]{64}$/u),
|
|
58
|
+
}).strict().superRefine((derivation, context) => {
|
|
59
|
+
const body = CandidateRenderDerivationBodyV1Schema.parse({
|
|
60
|
+
binding: derivation.binding,
|
|
61
|
+
candidateRevision: derivation.candidateRevision,
|
|
62
|
+
encoderRecipe: derivation.encoderRecipe,
|
|
63
|
+
kind: derivation.kind,
|
|
64
|
+
maximumBytes: derivation.maximumBytes,
|
|
65
|
+
plan: derivation.plan,
|
|
66
|
+
rendererAbi: derivation.rendererAbi,
|
|
67
|
+
revision: derivation.revision,
|
|
68
|
+
schemaVersion: derivation.schemaVersion,
|
|
69
|
+
syncPolicy: derivation.syncPolicy,
|
|
70
|
+
target: derivation.target,
|
|
71
|
+
});
|
|
72
|
+
if (candidateRenderDerivationSha256(body) !== derivation.derivationSha256) {
|
|
73
|
+
context.addIssue({
|
|
74
|
+
code: "custom",
|
|
75
|
+
message: "Candidate render derivation hash does not match its exact inputs.",
|
|
76
|
+
path: ["derivationSha256"],
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (!candidateRenderRelationshipsAgree(derivation)) {
|
|
80
|
+
context.addIssue({
|
|
81
|
+
code: "custom",
|
|
82
|
+
message: "Candidate revision, renderable revision, and render plan must describe one exact derivation.",
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (
|
|
86
|
+
canonicalJson(derivation.encoderRecipe)
|
|
87
|
+
!== canonicalJson(resolveProjectRenderEncoderRecipe(derivation.target.tier))
|
|
88
|
+
) {
|
|
89
|
+
context.addIssue({
|
|
90
|
+
code: "custom",
|
|
91
|
+
message: "Candidate render encoder recipe must match its exact target tier.",
|
|
92
|
+
path: ["encoderRecipe"],
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
export const BindCandidateRenderOutputInputRequestSchema = z.strictObject({
|
|
98
|
+
binding: ProjectRenderToolchainSchema.optional(),
|
|
99
|
+
candidateRevision: CreativeCandidateRevisionReferenceV1Schema,
|
|
100
|
+
maximumBytes: ProjectRenderOutputRequestSchema.shape.maximumBytes,
|
|
101
|
+
plan: ProjectRenderPlanReferenceSchema,
|
|
102
|
+
rendererAbi: CandidateProjectRendererAbiSchema.optional(),
|
|
103
|
+
revision: RenderableProjectEditRevisionReferenceSchema,
|
|
104
|
+
syncPolicy: ProjectRenderSyncPolicySchema,
|
|
105
|
+
target: ProjectRenderTargetSchema,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
export const BindCandidateRenderOutputInputSchema =
|
|
109
|
+
BindCandidateRenderOutputInputRequestSchema.extend({
|
|
110
|
+
binding: ProjectRenderToolchainSchema,
|
|
111
|
+
rendererAbi: CandidateProjectRendererAbiSchema,
|
|
112
|
+
}).strict();
|
|
113
|
+
|
|
114
|
+
export const CandidateProjectRenderInputSchema = z.strictObject({
|
|
115
|
+
binding: ProjectRenderToolchainSchema,
|
|
116
|
+
derivation: CandidateRenderDerivationV1Schema,
|
|
117
|
+
output: ProjectRenderOutputRequestSchema,
|
|
118
|
+
plan: ProjectRenderPlanReferenceSchema,
|
|
119
|
+
syncPolicy: ProjectRenderSyncPolicySchema,
|
|
120
|
+
target: ProjectRenderTargetSchema,
|
|
121
|
+
}).superRefine((input, context) => {
|
|
122
|
+
if (
|
|
123
|
+
input.output.maximumBytes !== input.derivation.maximumBytes
|
|
124
|
+
|| canonicalJson(input.binding) !== canonicalJson(input.derivation.binding)
|
|
125
|
+
|| canonicalJson(input.plan) !== canonicalJson(input.derivation.plan)
|
|
126
|
+
|| input.syncPolicy !== input.derivation.syncPolicy
|
|
127
|
+
|| canonicalJson(input.target) !== canonicalJson(input.derivation.target)
|
|
128
|
+
) {
|
|
129
|
+
context.addIssue({
|
|
130
|
+
code: "custom",
|
|
131
|
+
message: "Candidate render request does not match its complete derivation.",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
const expectedPath = candidateRenderOutputPath(input.derivation);
|
|
135
|
+
if (input.output.path !== expectedPath) {
|
|
136
|
+
context.addIssue({
|
|
137
|
+
code: "custom",
|
|
138
|
+
message: "Candidate render output path is not addressed by its complete derivation.",
|
|
139
|
+
path: ["output", "path"],
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
export type BindCandidateRenderOutputInput = z.infer<
|
|
145
|
+
typeof BindCandidateRenderOutputInputSchema
|
|
146
|
+
>;
|
|
147
|
+
export type BindCandidateRenderOutputInputRequest = z.infer<
|
|
148
|
+
typeof BindCandidateRenderOutputInputRequestSchema
|
|
149
|
+
>;
|
|
150
|
+
export type CandidateProjectRenderInput = z.infer<
|
|
151
|
+
typeof CandidateProjectRenderInputSchema
|
|
152
|
+
>;
|
|
153
|
+
export type CandidateRenderDerivationV1 = z.infer<
|
|
154
|
+
typeof CandidateRenderDerivationV1Schema
|
|
155
|
+
>;
|
|
156
|
+
|
|
157
|
+
function candidateRenderRelationshipsAgree(input: {
|
|
158
|
+
readonly candidateRevision: BindCandidateRenderOutputInput["candidateRevision"];
|
|
159
|
+
readonly plan: BindCandidateRenderOutputInput["plan"];
|
|
160
|
+
readonly revision: BindCandidateRenderOutputInput["revision"];
|
|
161
|
+
}): boolean {
|
|
162
|
+
const candidate = input.candidateRevision;
|
|
163
|
+
const revision = input.revision;
|
|
164
|
+
const plan = input.plan;
|
|
165
|
+
return !(
|
|
166
|
+
candidate.projectId !== revision.projectId
|
|
167
|
+
|| candidate.projectSha256 !== revision.projectSha256
|
|
168
|
+
|| candidate.projectStructureSha256 !== revision.projectStructureSha256
|
|
169
|
+
|| candidate.projectEditPlanSha256 !== revision.projectEditPlanSha256
|
|
170
|
+
|| candidate.revisionSha256 !== revision.revisionSha256
|
|
171
|
+
|| candidate.planId !== revision.planId
|
|
172
|
+
|| canonicalJson(candidate.artifact) !== canonicalJson(revision.artifact)
|
|
173
|
+
|| canonicalJson(candidate.base.generation) !== canonicalJson(revision.baseGeneration)
|
|
174
|
+
|| plan.projectId !== revision.projectId
|
|
175
|
+
|| plan.projectSha256 !== revision.projectSha256
|
|
176
|
+
|| plan.projectEditPlanSha256 !== revision.projectEditPlanSha256
|
|
177
|
+
|| plan.revisionSha256 !== revision.revisionSha256
|
|
178
|
+
|| plan.outputGeometrySha256 !== revision.outputGeometrySha256
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function validateCandidateRenderRelationships(
|
|
183
|
+
input: BindCandidateRenderOutputInput,
|
|
184
|
+
): void {
|
|
185
|
+
if (!candidateRenderRelationshipsAgree(input)) {
|
|
186
|
+
throw new ApplicationError(
|
|
187
|
+
"conflict",
|
|
188
|
+
"Candidate revision, renderable revision, and render plan must describe one exact derivation.",
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function assertCurrentCandidateProjectRendererAbi(
|
|
194
|
+
rendererAbi: string,
|
|
195
|
+
): void {
|
|
196
|
+
if (rendererAbi !== SLOPCAMERA_PROJECT_RENDERER_ABI) {
|
|
197
|
+
throw new ApplicationError(
|
|
198
|
+
"incompatible",
|
|
199
|
+
"Candidate renderer ABI differs from the current Slopcamera project renderer.",
|
|
200
|
+
{
|
|
201
|
+
currentRendererAbi: SLOPCAMERA_PROJECT_RENDERER_ABI,
|
|
202
|
+
rendererAbi,
|
|
203
|
+
},
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function candidateRenderDerivationSha256(
|
|
209
|
+
input: z.input<typeof CandidateRenderDerivationBodyV1Schema>,
|
|
210
|
+
): string {
|
|
211
|
+
const body = CandidateRenderDerivationBodyV1Schema.parse(input);
|
|
212
|
+
return canonicalJsonSha256({
|
|
213
|
+
domain: "slopcamera.candidate-render-derivation/v1",
|
|
214
|
+
...body,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function createCandidateRenderDerivationV1(
|
|
219
|
+
input: BindCandidateRenderOutputInput,
|
|
220
|
+
): CandidateRenderDerivationV1 {
|
|
221
|
+
const exact = BindCandidateRenderOutputInputSchema.parse(input);
|
|
222
|
+
assertCurrentCandidateProjectRendererAbi(exact.rendererAbi);
|
|
223
|
+
validateCandidateRenderRelationships(exact);
|
|
224
|
+
const encoderRecipe = resolveProjectRenderEncoderRecipe(exact.target.tier);
|
|
225
|
+
const body = CandidateRenderDerivationBodyV1Schema.parse({
|
|
226
|
+
...exact,
|
|
227
|
+
encoderRecipe,
|
|
228
|
+
kind: "slopcamera.candidate-render-derivation",
|
|
229
|
+
schemaVersion: 1,
|
|
230
|
+
});
|
|
231
|
+
return CandidateRenderDerivationV1Schema.parse({
|
|
232
|
+
...body,
|
|
233
|
+
derivationSha256: candidateRenderDerivationSha256(body),
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function candidateRenderOutputPath(
|
|
238
|
+
derivationInput: CandidateRenderDerivationV1,
|
|
239
|
+
): string {
|
|
240
|
+
const derivation = CandidateRenderDerivationV1Schema.parse(derivationInput);
|
|
241
|
+
return ProjectRenderOutputRequestSchema.shape.path.parse(
|
|
242
|
+
`renders/${derivation.candidateRevision.candidate.namespace}/${derivation.revision.revisionSha256}/derivations/${derivation.derivationSha256}.mp4`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function bindCandidateRenderOutputInput(
|
|
247
|
+
resolvedInput: unknown,
|
|
248
|
+
hostToolchain: ProjectRenderToolchain,
|
|
249
|
+
): BindCandidateRenderOutputInput {
|
|
250
|
+
const requested = BindCandidateRenderOutputInputRequestSchema.parse(
|
|
251
|
+
resolvedInput,
|
|
252
|
+
);
|
|
253
|
+
const binding = ProjectRenderToolchainSchema.parse(hostToolchain);
|
|
254
|
+
if (
|
|
255
|
+
requested.binding !== undefined
|
|
256
|
+
&& canonicalJson(requested.binding) !== canonicalJson(binding)
|
|
257
|
+
) {
|
|
258
|
+
throw new ApplicationError(
|
|
259
|
+
"conflict",
|
|
260
|
+
"Candidate render tool binding changed after exact node planning.",
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
if (requested.rendererAbi !== undefined) {
|
|
264
|
+
assertCurrentCandidateProjectRendererAbi(requested.rendererAbi);
|
|
265
|
+
}
|
|
266
|
+
const exact = BindCandidateRenderOutputInputSchema.parse({
|
|
267
|
+
...requested,
|
|
268
|
+
binding,
|
|
269
|
+
rendererAbi: SLOPCAMERA_PROJECT_RENDERER_ABI,
|
|
270
|
+
});
|
|
271
|
+
validateCandidateRenderRelationships(exact);
|
|
272
|
+
return exact;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export const bindCandidateRenderOutputOperationDefinition = {
|
|
276
|
+
inputSchema: BindCandidateRenderOutputInputSchema,
|
|
277
|
+
inputSchemaId: "slopcamera.operation.render.bind-candidate-output.input/v1",
|
|
278
|
+
kind: "render.bind-candidate-output",
|
|
279
|
+
lifecycle: {
|
|
280
|
+
kind: "pure",
|
|
281
|
+
execute: (context, input) => {
|
|
282
|
+
throwIfAborted(context.abortSignal);
|
|
283
|
+
const derivation = createCandidateRenderDerivationV1(input);
|
|
284
|
+
return Promise.resolve(CandidateProjectRenderInputSchema.parse({
|
|
285
|
+
binding: input.binding,
|
|
286
|
+
derivation,
|
|
287
|
+
output: {
|
|
288
|
+
maximumBytes: input.maximumBytes,
|
|
289
|
+
path: candidateRenderOutputPath(derivation),
|
|
290
|
+
},
|
|
291
|
+
plan: input.plan,
|
|
292
|
+
syncPolicy: input.syncPolicy,
|
|
293
|
+
target: input.target,
|
|
294
|
+
}));
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
outputSchema: CandidateProjectRenderInputSchema,
|
|
298
|
+
outputSchemaId: "slopcamera.operation.render.bind-candidate-output.output/v1",
|
|
299
|
+
policy: {
|
|
300
|
+
cache: "content-addressed",
|
|
301
|
+
cancellable: true,
|
|
302
|
+
effect: "pure",
|
|
303
|
+
maxDurationMs: 5_000,
|
|
304
|
+
maxFanOut: 0,
|
|
305
|
+
maxInputBytes: 64 * 1024,
|
|
306
|
+
maxOutputBytes: 64 * 1024,
|
|
307
|
+
preparation: [],
|
|
308
|
+
resources: [{ amount: 1, resource: "cpu" }],
|
|
309
|
+
resume: "deterministic",
|
|
310
|
+
},
|
|
311
|
+
summarize: output => ({
|
|
312
|
+
fields: {
|
|
313
|
+
derivationSha256: output.derivation.derivationSha256,
|
|
314
|
+
outputPath: output.output.path,
|
|
315
|
+
renderPlanSha256: output.plan.renderPlanSha256,
|
|
316
|
+
},
|
|
317
|
+
kind: "render.bind-candidate-output",
|
|
318
|
+
}),
|
|
319
|
+
version: 1,
|
|
320
|
+
} satisfies OperationDefinition<
|
|
321
|
+
"render.bind-candidate-output",
|
|
322
|
+
BindCandidateRenderOutputInput,
|
|
323
|
+
CandidateProjectRenderInput
|
|
324
|
+
>;
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
canonicalJson,
|
|
5
|
+
sha256Hex,
|
|
6
|
+
} from "../../../core";
|
|
7
|
+
import {
|
|
8
|
+
createDeliveryMaterializationReceiptV1,
|
|
9
|
+
CreativeRenderNameSchema,
|
|
10
|
+
CreativeVariantKeySchema,
|
|
11
|
+
DeliveryMaterializationReceiptReferenceV1Schema,
|
|
12
|
+
DeliveryMaterializationReceiptV1Schema,
|
|
13
|
+
deliveryMaterializationReceiptPath,
|
|
14
|
+
deliveryMaterializationReceiptReferenceV1,
|
|
15
|
+
VariantSelectionReferenceV1Schema,
|
|
16
|
+
type DeliveryMaterializationReceiptV1,
|
|
17
|
+
} from "../../creative-iteration";
|
|
18
|
+
import {
|
|
19
|
+
ProjectRenderOutputPathSchema,
|
|
20
|
+
} from "../../../contracts";
|
|
21
|
+
import type { ApplicationContext } from "../../context";
|
|
22
|
+
import { ApplicationError } from "../../errors";
|
|
23
|
+
import type { OperationDefinition } from "../../operation";
|
|
24
|
+
import { withOutputPublicationLease } from "../../output-publication-lease";
|
|
25
|
+
import { ProjectReferenceSchema, throwIfAborted } from "../shared";
|
|
26
|
+
import {
|
|
27
|
+
creativeProjectFileSystem,
|
|
28
|
+
loadCreativeCandidate,
|
|
29
|
+
loadVariantMatrix,
|
|
30
|
+
loadVariantSelection,
|
|
31
|
+
publishCreativeDocument,
|
|
32
|
+
verifyCandidateRender,
|
|
33
|
+
} from "../iteration/shared";
|
|
34
|
+
import { ProjectRenderOutputReferenceSchema } from "../../receipts";
|
|
35
|
+
|
|
36
|
+
const MaterializeVariantSelectionUnboundInputSchema = z.strictObject({
|
|
37
|
+
deliveryKey: CreativeVariantKeySchema.default("delivery"),
|
|
38
|
+
destinationPath: ProjectRenderOutputPathSchema.optional(),
|
|
39
|
+
project: ProjectReferenceSchema,
|
|
40
|
+
renderName: CreativeRenderNameSchema,
|
|
41
|
+
selection: VariantSelectionReferenceV1Schema,
|
|
42
|
+
}).superRefine((input, context) => {
|
|
43
|
+
if (input.project !== input.selection.base.projectId) {
|
|
44
|
+
context.addIssue({
|
|
45
|
+
code: "custom",
|
|
46
|
+
message: "Delivery materialization project does not match its selection.",
|
|
47
|
+
path: ["project"],
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export const MaterializeVariantSelectionInputSchema =
|
|
53
|
+
MaterializeVariantSelectionUnboundInputSchema.safeExtend({
|
|
54
|
+
destinationPath: ProjectRenderOutputPathSchema,
|
|
55
|
+
}).strict();
|
|
56
|
+
|
|
57
|
+
export const MaterializeVariantSelectionOutputSchema = z.strictObject({
|
|
58
|
+
output: ProjectRenderOutputReferenceSchema,
|
|
59
|
+
receipt: DeliveryMaterializationReceiptReferenceV1Schema,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export type MaterializeVariantSelectionInput = z.infer<
|
|
63
|
+
typeof MaterializeVariantSelectionInputSchema
|
|
64
|
+
>;
|
|
65
|
+
export type MaterializeVariantSelectionOutput = z.infer<
|
|
66
|
+
typeof MaterializeVariantSelectionOutputSchema
|
|
67
|
+
>;
|
|
68
|
+
|
|
69
|
+
export function defaultDeliveryMaterializationPath(input: {
|
|
70
|
+
readonly deliveryKey: string;
|
|
71
|
+
readonly renderName: string;
|
|
72
|
+
readonly selectionSha256: string;
|
|
73
|
+
}): string {
|
|
74
|
+
return ProjectRenderOutputPathSchema.parse(
|
|
75
|
+
`renders/deliveries/selections/${input.selectionSha256}/${
|
|
76
|
+
CreativeVariantKeySchema.parse(input.deliveryKey)
|
|
77
|
+
}/${CreativeRenderNameSchema.parse(input.renderName)}.mp4`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function bindMaterializeVariantSelectionInput(
|
|
82
|
+
_application: ApplicationContext,
|
|
83
|
+
input: unknown,
|
|
84
|
+
): MaterializeVariantSelectionInput {
|
|
85
|
+
const request = MaterializeVariantSelectionUnboundInputSchema.parse(input);
|
|
86
|
+
return MaterializeVariantSelectionInputSchema.parse({
|
|
87
|
+
...request,
|
|
88
|
+
destinationPath: request.destinationPath
|
|
89
|
+
?? defaultDeliveryMaterializationPath({
|
|
90
|
+
deliveryKey: request.deliveryKey,
|
|
91
|
+
renderName: request.renderName,
|
|
92
|
+
selectionSha256: request.selection.selectionSha256,
|
|
93
|
+
}),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function missing(error: unknown): boolean {
|
|
98
|
+
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function loadExistingMaterialization(input: {
|
|
102
|
+
readonly fileSystem: Awaited<ReturnType<typeof creativeProjectFileSystem>>;
|
|
103
|
+
readonly path: string;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
readonly artifact: {
|
|
106
|
+
readonly bytes: number;
|
|
107
|
+
readonly path: string;
|
|
108
|
+
readonly sha256: string;
|
|
109
|
+
};
|
|
110
|
+
readonly receipt: DeliveryMaterializationReceiptV1;
|
|
111
|
+
} | null> {
|
|
112
|
+
let contents: string;
|
|
113
|
+
try {
|
|
114
|
+
contents = await input.fileSystem.readText(input.path);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
if (missing(error)) return null;
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
let value: unknown;
|
|
120
|
+
try {
|
|
121
|
+
value = JSON.parse(contents) as unknown;
|
|
122
|
+
} catch {
|
|
123
|
+
throw new ApplicationError(
|
|
124
|
+
"invalid-data",
|
|
125
|
+
"Delivery materialization receipt is not valid JSON.",
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const receipt = DeliveryMaterializationReceiptV1Schema.parse(value);
|
|
129
|
+
if (contents !== `${canonicalJson(receipt)}\n`) {
|
|
130
|
+
throw new ApplicationError(
|
|
131
|
+
"invalid-data",
|
|
132
|
+
"Delivery materialization receipt is not canonical immutable JSON.",
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
artifact: {
|
|
137
|
+
bytes: new TextEncoder().encode(contents).byteLength,
|
|
138
|
+
path: input.path,
|
|
139
|
+
sha256: sha256Hex(contents),
|
|
140
|
+
},
|
|
141
|
+
receipt,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export const materializeVariantSelectionOperationDefinition = {
|
|
146
|
+
inputSchema: MaterializeVariantSelectionInputSchema,
|
|
147
|
+
inputSchemaId: "slopcamera.operation.render.materialize-selection.input/v1",
|
|
148
|
+
kind: "render.materialize-selection",
|
|
149
|
+
lifecycle: {
|
|
150
|
+
kind: "local-artifact",
|
|
151
|
+
execute: async (context, input) => {
|
|
152
|
+
throwIfAborted(context.abortSignal);
|
|
153
|
+
const fileSystem = await creativeProjectFileSystem(
|
|
154
|
+
context.application,
|
|
155
|
+
input.project,
|
|
156
|
+
);
|
|
157
|
+
const selection = await loadVariantSelection({
|
|
158
|
+
fileSystem,
|
|
159
|
+
reference: input.selection,
|
|
160
|
+
});
|
|
161
|
+
const matrix = await loadVariantMatrix({
|
|
162
|
+
fileSystem,
|
|
163
|
+
reference: selection.matrix,
|
|
164
|
+
});
|
|
165
|
+
const chosen = matrix.candidates.find(candidate => (
|
|
166
|
+
candidate.candidate.candidateId === selection.chosen.candidate.candidateId
|
|
167
|
+
));
|
|
168
|
+
if (
|
|
169
|
+
chosen === undefined
|
|
170
|
+
|| canonicalJson(chosen) !== canonicalJson(selection.chosen)
|
|
171
|
+
) {
|
|
172
|
+
throw new ApplicationError(
|
|
173
|
+
"conflict",
|
|
174
|
+
"Delivery selection is not an exact member of its closed matrix.",
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
const candidate = await loadCreativeCandidate({
|
|
178
|
+
fileSystem,
|
|
179
|
+
reference: chosen,
|
|
180
|
+
});
|
|
181
|
+
const render = candidate.renders.find(item => item.name === input.renderName);
|
|
182
|
+
if (render === undefined) {
|
|
183
|
+
throw new ApplicationError(
|
|
184
|
+
"not-found",
|
|
185
|
+
`Selected candidate has no verified render named ${input.renderName}.`,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
if (!selection.result.renders.some(result => (
|
|
189
|
+
result.name === render.name
|
|
190
|
+
&& result.outputSha256 === render.output.sha256
|
|
191
|
+
&& result.receiptSha256 === render.receipt.receiptSha256
|
|
192
|
+
))) {
|
|
193
|
+
throw new ApplicationError(
|
|
194
|
+
"conflict",
|
|
195
|
+
"Selected render hashes are absent from the immutable selection result.",
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
await verifyCandidateRender({ candidate, fileSystem, render });
|
|
199
|
+
if (render.output.path === input.destinationPath) {
|
|
200
|
+
throw new ApplicationError(
|
|
201
|
+
"conflict",
|
|
202
|
+
"Delivery materialization requires a new output path.",
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
const receipt = createDeliveryMaterializationReceiptV1({
|
|
206
|
+
candidate: chosen,
|
|
207
|
+
destinationPath: input.destinationPath,
|
|
208
|
+
renderName: input.renderName,
|
|
209
|
+
selection: input.selection,
|
|
210
|
+
source: render.output,
|
|
211
|
+
});
|
|
212
|
+
const receiptPath = deliveryMaterializationReceiptPath(
|
|
213
|
+
receipt.materializationSha256,
|
|
214
|
+
);
|
|
215
|
+
throwIfAborted(context.abortSignal);
|
|
216
|
+
return await withOutputPublicationLease(
|
|
217
|
+
context.application,
|
|
218
|
+
{
|
|
219
|
+
outputPath: input.destinationPath,
|
|
220
|
+
projectId: input.project,
|
|
221
|
+
},
|
|
222
|
+
async () => {
|
|
223
|
+
const existing = await loadExistingMaterialization({
|
|
224
|
+
fileSystem,
|
|
225
|
+
path: receiptPath,
|
|
226
|
+
});
|
|
227
|
+
if (existing !== null) {
|
|
228
|
+
if (canonicalJson(existing.receipt) !== canonicalJson(receipt)) {
|
|
229
|
+
throw new ApplicationError(
|
|
230
|
+
"conflict",
|
|
231
|
+
"Delivery materialization receipt path contains another result.",
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
if (fileSystem.inspectFile === undefined) {
|
|
235
|
+
throw new ApplicationError(
|
|
236
|
+
"internal",
|
|
237
|
+
"Project storage does not support delivery verification.",
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
const integrity = await fileSystem.inspectFile(input.destinationPath);
|
|
241
|
+
if (
|
|
242
|
+
integrity.bytes !== receipt.destination.bytes
|
|
243
|
+
|| integrity.sha256 !== receipt.destination.sha256
|
|
244
|
+
) {
|
|
245
|
+
throw new ApplicationError(
|
|
246
|
+
"conflict",
|
|
247
|
+
"Existing materialized delivery no longer matches its receipt.",
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
const reference = deliveryMaterializationReceiptReferenceV1(existing);
|
|
251
|
+
return MaterializeVariantSelectionOutputSchema.parse({
|
|
252
|
+
output: receipt.destination,
|
|
253
|
+
receipt: reference,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (fileSystem.copyFileNoReplace === undefined) {
|
|
257
|
+
throw new ApplicationError(
|
|
258
|
+
"internal",
|
|
259
|
+
"Project storage does not support immutable delivery materialization.",
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
throwIfAborted(context.abortSignal);
|
|
263
|
+
await context.workflow?.beforePublication();
|
|
264
|
+
throwIfAborted(context.abortSignal);
|
|
265
|
+
await fileSystem.copyFileNoReplace(
|
|
266
|
+
render.output.path,
|
|
267
|
+
input.destinationPath,
|
|
268
|
+
render.output,
|
|
269
|
+
);
|
|
270
|
+
// Copy publication is the point of no return. Finalize its deterministic
|
|
271
|
+
// receipt even if cancellation arrives immediately afterward.
|
|
272
|
+
const artifact = await publishCreativeDocument({
|
|
273
|
+
document: receipt,
|
|
274
|
+
fileSystem,
|
|
275
|
+
path: receiptPath,
|
|
276
|
+
schema: DeliveryMaterializationReceiptV1Schema,
|
|
277
|
+
});
|
|
278
|
+
const reference = deliveryMaterializationReceiptReferenceV1({
|
|
279
|
+
artifact,
|
|
280
|
+
receipt,
|
|
281
|
+
});
|
|
282
|
+
return MaterializeVariantSelectionOutputSchema.parse({
|
|
283
|
+
output: receipt.destination,
|
|
284
|
+
receipt: reference,
|
|
285
|
+
});
|
|
286
|
+
},
|
|
287
|
+
);
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
outputSchema: MaterializeVariantSelectionOutputSchema,
|
|
291
|
+
outputSchemaId: "slopcamera.operation.render.materialize-selection.output/v1",
|
|
292
|
+
policy: {
|
|
293
|
+
cache: "none",
|
|
294
|
+
cancellable: true,
|
|
295
|
+
effect: "local-derived-write",
|
|
296
|
+
maxDurationMs: 6 * 60 * 60_000,
|
|
297
|
+
maxFanOut: 0,
|
|
298
|
+
maxInputBytes: 32 * 1024,
|
|
299
|
+
maxOutputBytes: 32 * 1024,
|
|
300
|
+
preparation: ["local-media"],
|
|
301
|
+
resources: [
|
|
302
|
+
{ amount: 1, resource: "local-io" },
|
|
303
|
+
{ amount: 1, resource: "output-publication" },
|
|
304
|
+
],
|
|
305
|
+
resume: "deterministic",
|
|
306
|
+
},
|
|
307
|
+
receiptReference: output => output.receipt.artifact.path,
|
|
308
|
+
summarize: output => ({
|
|
309
|
+
fields: {
|
|
310
|
+
materializationSha256: output.receipt.materializationSha256,
|
|
311
|
+
outputPath: output.output.path,
|
|
312
|
+
outputSha256: output.output.sha256,
|
|
313
|
+
selectionSha256: output.receipt.selectionSha256,
|
|
314
|
+
},
|
|
315
|
+
kind: "render.materialize-selection",
|
|
316
|
+
}),
|
|
317
|
+
version: 1,
|
|
318
|
+
} satisfies OperationDefinition<
|
|
319
|
+
"render.materialize-selection",
|
|
320
|
+
MaterializeVariantSelectionInput,
|
|
321
|
+
MaterializeVariantSelectionOutput
|
|
322
|
+
>;
|