@gentbajko/slopify 3.25.9 → 4.0.0
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/dist/adapters/account-limits.js +30 -0
- package/dist/adapters/alignment/cache.js +3 -5
- package/dist/adapters/alignment/ctc.js +1 -2
- package/dist/adapters/alignment/lock.js +4 -3
- package/dist/adapters/alignment/multilingual.js +0 -3
- package/dist/adapters/alignment/prefetch.js +2 -1
- package/dist/adapters/alignment/worker.js +2 -1
- package/dist/adapters/explain.js +0 -3
- package/dist/adapters/ffmpeg.js +19 -1
- package/dist/adapters/host-cli/index.js +19 -3
- package/dist/adapters/http-failure.js +53 -0
- package/dist/adapters/image/codex.js +36 -4
- package/dist/adapters/image/fal.js +17 -50
- package/dist/adapters/image/google.js +31 -55
- package/dist/adapters/image/openai.js +20 -47
- package/dist/adapters/image/reference.js +36 -0
- package/dist/adapters/image/replicate.js +18 -47
- package/dist/adapters/interest/search-interest.js +113 -0
- package/dist/adapters/key-probes.js +53 -2
- package/dist/adapters/llm/antigravity.js +4 -0
- package/dist/adapters/llm/assistant-cli.js +388 -0
- package/dist/adapters/llm/child-session.js +83 -0
- package/dist/adapters/llm/claude-code-models.js +51 -98
- package/dist/adapters/llm/claude-code.js +13 -2
- package/dist/adapters/llm/codex-limits.js +27 -68
- package/dist/adapters/llm/codex-server-models.js +61 -109
- package/dist/adapters/llm/codex.js +12 -1
- package/dist/adapters/llm/openrouter.js +10 -47
- package/dist/adapters/llm/run-cli.js +6 -22
- package/dist/adapters/llm/sse-lines.js +5 -1
- package/dist/adapters/model-access.js +37 -0
- package/dist/adapters/tts/cartesia.js +15 -46
- package/dist/adapters/tts/elevenlabs.js +20 -52
- package/dist/adapters/tts/gemini.js +19 -40
- package/dist/adapters/tts/inworld-async.js +4 -1
- package/dist/adapters/tts/inworld.js +3 -0
- package/dist/adapters/tts/openai.js +20 -50
- package/dist/assets/models-lifecycle.yaml +6 -0
- package/dist/assistant-wiring.js +60 -0
- package/dist/autopilot-timers.js +59 -0
- package/dist/catalog/lifecycle.js +52 -0
- package/dist/catalog/propose.js +204 -0
- package/dist/catalog/registry.js +3 -1
- package/dist/catalog/schema.js +2 -0
- package/dist/catalog/store.js +39 -0
- package/dist/edge/autostart/native.js +3 -5
- package/dist/edge/autostart/prompt.js +2 -1
- package/dist/edge/autostart/service.js +3 -4
- package/dist/edge/cli-args.js +3 -4
- package/dist/edge/cli.js +2 -1
- package/dist/edge/docker-install/apply.js +11 -11
- package/dist/edge/docker-install/run.js +2 -1
- package/dist/edge/docker-install/state.js +4 -3
- package/dist/edge/docker-install/tree.js +2 -4
- package/dist/edge/docker-install/volume.js +3 -2
- package/dist/edge/docker.js +5 -4
- package/dist/edge/events/hub.js +5 -5
- package/dist/edge/http/actions.js +4 -25
- package/dist/edge/http/actor.js +5 -3
- package/dist/edge/http/app.js +85 -10
- package/dist/edge/http/assistant.js +127 -0
- package/dist/edge/http/audio-preview.js +4 -11
- package/dist/edge/http/auditions.js +1 -1
- package/dist/edge/http/autostart.js +5 -5
- package/dist/edge/http/backups.js +1 -3
- package/dist/edge/http/channel-memory.js +7 -20
- package/dist/edge/http/channels.js +13 -26
- package/dist/edge/http/checkpoints.js +33 -17
- package/dist/edge/http/design-templates.js +167 -0
- package/dist/edge/http/designs.js +178 -0
- package/dist/edge/http/diagnostics.js +5 -1
- package/dist/edge/http/document-themes.js +2 -11
- package/dist/edge/http/draft-files.js +1 -3
- package/dist/edge/http/draft-problem.js +4 -9
- package/dist/edge/http/drafts.js +3 -3
- package/dist/edge/http/entries.js +6 -9
- package/dist/edge/http/extension-auth.js +27 -0
- package/dist/edge/http/external-reviews.js +12 -11
- package/dist/edge/http/files.js +5 -11
- package/dist/edge/http/folder-location.js +1 -4
- package/dist/edge/http/fonts.js +0 -7
- package/dist/edge/http/home.js +38 -13
- package/dist/edge/http/host-cli.js +18 -8
- package/dist/edge/http/ids.js +8 -0
- package/dist/edge/http/keywords.js +35 -0
- package/dist/edge/http/model-checks.js +132 -0
- package/dist/edge/http/narration-peaks.js +5 -13
- package/dist/edge/http/onboarding.js +1 -14
- package/dist/edge/http/open-folder.js +5 -10
- package/dist/edge/http/outputs.js +4 -12
- package/dist/edge/http/patch-notes.js +4 -10
- package/dist/edge/http/planning.js +2 -6
- package/dist/edge/http/problem.js +2 -4
- package/dist/edge/http/project-create.js +1 -0
- package/dist/edge/http/project-templates.js +29 -17
- package/dist/edge/http/projects.js +2 -12
- package/dist/edge/http/prompts.js +7 -14
- package/dist/edge/http/pronunciations.js +1 -2
- package/dist/edge/http/providers.js +39 -24
- package/dist/edge/http/refusal.js +29 -0
- package/dist/edge/http/remote-access.js +40 -0
- package/dist/edge/http/remote-guard.js +71 -0
- package/dist/edge/http/request-guard.js +91 -0
- package/dist/edge/http/reviews.js +11 -24
- package/dist/edge/http/revision-files.js +5 -10
- package/dist/edge/http/revisions.js +10 -15
- package/dist/edge/http/run-cost.js +1 -2
- package/dist/edge/http/same-page.js +80 -0
- package/dist/edge/http/schedules.js +59 -32
- package/dist/edge/http/settings.js +22 -13
- package/dist/edge/http/social.js +282 -0
- package/dist/edge/http/staging.js +2 -4
- package/dist/edge/http/storage-files.js +5 -7
- package/dist/edge/http/storage.js +23 -23
- package/dist/edge/http/studio.js +23 -50
- package/dist/edge/http/style-preview.js +1 -4
- package/dist/edge/http/subtitles.js +3 -17
- package/dist/edge/http/template-studio.js +433 -0
- package/dist/edge/http/trash.js +10 -11
- package/dist/edge/http/tutorial.js +1 -2
- package/dist/edge/http/tutorials.js +5 -11
- package/dist/edge/http/update.js +7 -13
- package/dist/edge/http/waveform.js +3 -6
- package/dist/edge/http/youtube-edits.js +2 -3
- package/dist/edge/mcp/assistant.js +279 -0
- package/dist/edge/mcp/attribution.js +8 -2
- package/dist/edge/mcp/call-route.js +11 -2
- package/dist/edge/mcp/excluded-routes.js +25 -0
- package/dist/edge/mcp/http.js +11 -2
- package/dist/edge/mcp/instructions.js +5 -3
- package/dist/edge/mcp/library-tools.js +1 -0
- package/dist/edge/mcp/route-tool.js +35 -15
- package/dist/edge/mcp/server.js +13 -8
- package/dist/edge/mcp/tools-channels.js +2 -0
- package/dist/edge/mcp/tools-designs.js +165 -0
- package/dist/edge/mcp/tools-library.js +14 -2
- package/dist/edge/mcp/tools-planning.js +23 -4
- package/dist/edge/mcp/tools-projects.js +28 -1
- package/dist/edge/mcp/tools-runs.js +14 -1
- package/dist/edge/mcp/tools-schedules.js +28 -4
- package/dist/edge/mcp/tools-setup.js +61 -3
- package/dist/edge/mcp/tools-social.js +46 -0
- package/dist/edge/mcp/tools-storage.js +8 -0
- package/dist/edge/mcp/tools-template-studio.js +166 -0
- package/dist/edge/mcp/tools.js +6 -0
- package/dist/edge/remote-access/cli.js +71 -0
- package/dist/edge/remote-access/model.js +32 -0
- package/dist/edge/remote-access/rules.js +207 -0
- package/dist/edge/remote-access/service.js +203 -0
- package/dist/edge/remote-access/store.js +44 -0
- package/dist/edge/remote-access/views.js +43 -0
- package/dist/extension/slopify-studio-chrome.zip +0 -0
- package/dist/extension/slopify-studio-firefox.zip +0 -0
- package/dist/host-cli/install.js +2 -2
- package/dist/host-cli/open-folder.js +2 -2
- package/dist/host-cli/paths.js +2 -4
- package/dist/host-cli/server.js +4 -4
- package/dist/host-cli/service.js +3 -3
- package/dist/host-cli/status.js +7 -7
- package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
- package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
- package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
- package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
- package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
- package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
- package/dist/kernel/db/migrations/0070-designs.sql +53 -0
- package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
- package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
- package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
- package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
- package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
- package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
- package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
- package/dist/kernel/db/tx.js +2 -4
- package/dist/kernel/errors.js +27 -1
- package/dist/kernel/json-answer.js +15 -0
- package/dist/kernel/lock.js +4 -9
- package/dist/kernel/paths.js +8 -0
- package/dist/kernel/ports/assistant-cli.js +4 -0
- package/dist/kernel/ports/host-cli.js +3 -0
- package/dist/kernel/ports/interest.js +4 -0
- package/dist/kernel/ports/languages.js +0 -3
- package/dist/kernel/ports/model.js +2 -0
- package/dist/kernel/runner/attempt.js +3 -1
- package/dist/kernel/runner/audition.js +3 -1
- package/dist/kernel/runner/checkpoint-authority.js +2 -1
- package/dist/kernel/runner/index.js +8 -10
- package/dist/kernel/runner/model-access.js +40 -0
- package/dist/kernel/runner/model-check.js +153 -0
- package/dist/kernel/runner/providers.js +15 -10
- package/dist/kernel/runner/standalone.js +9 -5
- package/dist/main.js +334 -19
- package/dist/model-checks.js +166 -0
- package/dist/patch-notes/4.0.0.md +51 -0
- package/dist/patch-notes/index.json +6 -0
- package/dist/slices/admission/heads.js +2 -1
- package/dist/slices/admission/repo.js +2 -1
- package/dist/slices/admission/rules.js +43 -8
- package/dist/slices/admission/schema.js +8 -0
- package/dist/slices/admission/stage-writes.js +0 -3
- package/dist/slices/admission/start.js +48 -31
- package/dist/slices/admission/substitute.js +7 -4
- package/dist/slices/agents/attention-posts.js +31 -0
- package/dist/slices/agents/attention-templates.js +33 -0
- package/dist/slices/agents/attention.js +10 -1
- package/dist/slices/agents/connection.js +2 -6
- package/dist/slices/agents/model.js +6 -3
- package/dist/slices/agents/repo.js +15 -7
- package/dist/slices/article/continuation.js +0 -63
- package/dist/slices/article/plain.js +3 -2
- package/dist/slices/article/segments.js +2 -62
- package/dist/slices/assistant/access.js +1 -0
- package/dist/slices/assistant/asks.js +80 -0
- package/dist/slices/assistant/cost.js +54 -0
- package/dist/slices/assistant/gate.js +222 -0
- package/dist/slices/assistant/model.js +79 -0
- package/dist/slices/assistant/names.js +23 -0
- package/dist/slices/assistant/prompt.js +74 -0
- package/dist/slices/assistant/repo.js +74 -0
- package/dist/slices/assistant/tokens.js +18 -0
- package/dist/slices/assistant/turn.js +342 -0
- package/dist/slices/autopilot/buffer.js +76 -0
- package/dist/slices/autopilot/model.js +14 -0
- package/dist/slices/autopilot/notify.js +27 -0
- package/dist/slices/autopilot/repo.js +34 -0
- package/dist/slices/autopilot/signals.js +194 -0
- package/dist/slices/autopilot/warnings.js +85 -0
- package/dist/slices/autopilot/weekly.js +100 -0
- package/dist/slices/backups/files.js +2 -6
- package/dist/slices/backups/repo.js +3 -15
- package/dist/slices/backups/service.js +4 -3
- package/dist/slices/channels/cast-images.js +2 -1
- package/dist/slices/channels/model.js +0 -1
- package/dist/slices/channels/rebrand.js +0 -3
- package/dist/slices/channels/repo.js +4 -0
- package/dist/slices/channels/schema.js +6 -0
- package/dist/slices/channels/service.js +10 -0
- package/dist/slices/channels/videos.js +2 -14
- package/dist/slices/checkpoints/index.js +0 -1
- package/dist/slices/control/providers.js +0 -26
- package/dist/slices/designs/artwork.js +66 -0
- package/dist/slices/designs/budget.js +23 -0
- package/dist/slices/designs/calls.js +124 -0
- package/dist/slices/designs/check-context.js +38 -0
- package/dist/slices/designs/check-text.js +43 -0
- package/dist/slices/designs/fields.js +88 -0
- package/dist/slices/designs/frames.js +34 -0
- package/dist/slices/designs/gate.js +128 -0
- package/dist/slices/designs/layout.js +293 -0
- package/dist/slices/designs/model.js +35 -0
- package/dist/slices/designs/pdf-job.js +23 -0
- package/dist/slices/designs/pdf-pages.js +30 -0
- package/dist/slices/designs/pdf-runner.js +68 -0
- package/dist/slices/designs/pdf-worker.js +24 -0
- package/dist/slices/designs/picture-size.js +79 -0
- package/dist/slices/designs/pictures.js +55 -0
- package/dist/slices/designs/quote.js +24 -0
- package/dist/slices/designs/render-args.js +36 -0
- package/dist/slices/designs/render-input.js +59 -0
- package/dist/slices/designs/render.js +215 -0
- package/dist/slices/designs/repo.js +101 -0
- package/dist/slices/designs/requests.js +80 -0
- package/dist/slices/designs/runner.js +239 -0
- package/dist/slices/designs/sample-repo.js +91 -0
- package/dist/slices/designs/sample.js +222 -0
- package/dist/slices/designs/schema.js +87 -0
- package/dist/slices/designs/sections.js +44 -0
- package/dist/slices/designs/service.js +233 -0
- package/dist/slices/designs/steps-repo.js +102 -0
- package/dist/slices/designs/studio-kind.js +39 -0
- package/dist/slices/designs/template-checks.js +44 -0
- package/dist/slices/designs/template-make.js +118 -0
- package/dist/slices/designs/templates.js +218 -0
- package/dist/slices/document/fonts.js +2 -1
- package/dist/slices/episodes/summarize.js +5 -1
- package/dist/slices/estimate/index.js +45 -7
- package/dist/slices/fonts/catalog.js +3 -2
- package/dist/slices/fonts/discovery.js +3 -2
- package/dist/slices/fonts/files.js +2 -6
- package/dist/slices/fonts/index.js +0 -1
- package/dist/slices/fonts/sfnt.js +45 -10
- package/dist/slices/images/appearance.js +6 -15
- package/dist/slices/images/scenes.js +100 -27
- package/dist/slices/keywords/digest.js +84 -0
- package/dist/slices/keywords/facts.js +92 -0
- package/dist/slices/keywords/fill.js +80 -0
- package/dist/slices/keywords/model.js +75 -0
- package/dist/slices/keywords/rules.js +187 -0
- package/dist/slices/keywords/schema.js +28 -0
- package/dist/slices/keywords/specs.js +260 -0
- package/dist/slices/keywords/values.js +74 -0
- package/dist/slices/library/lint.js +29 -12
- package/dist/slices/library/model.js +2 -0
- package/dist/slices/library/photorealistic.js +4 -12
- package/dist/slices/library/rename.js +9 -7
- package/dist/slices/library/save.js +14 -10
- package/dist/slices/library/slots.js +37 -11
- package/dist/slices/library/transfer.js +2 -1
- package/dist/slices/library/used-by.js +25 -10
- package/dist/slices/loudness/loudnorm.js +51 -11
- package/dist/slices/model-checks/cost.js +61 -0
- package/dist/slices/model-checks/listing.js +124 -0
- package/dist/slices/model-checks/model.js +20 -0
- package/dist/slices/model-checks/record.js +32 -0
- package/dist/slices/model-checks/repo.js +120 -0
- package/dist/slices/model-checks/rules.js +112 -0
- package/dist/slices/model-checks/run.js +143 -0
- package/dist/slices/model-checks/service.js +198 -0
- package/dist/slices/model-upkeep/switch.js +70 -25
- package/dist/slices/model-upkeep/usage.js +26 -11
- package/dist/slices/narration/breaths.js +2 -1
- package/dist/slices/narration/clean-pieces.js +2 -1
- package/dist/slices/narration/concat.js +2 -1
- package/dist/slices/narration/peaks.js +3 -4
- package/dist/slices/narration/pronunciation-chunks.js +4 -3
- package/dist/slices/narration/pronunciation.js +3 -2
- package/dist/slices/narration/steering.js +4 -3
- package/dist/slices/notifications/notifier.js +4 -3
- package/dist/slices/notifications/rules.js +5 -2
- package/dist/slices/notifications/settings.js +4 -12
- package/dist/slices/notifications/subject.js +2 -1
- package/dist/slices/onboarding/copy.js +2 -1
- package/dist/slices/onboarding/first-run.js +3 -2
- package/dist/slices/onboarding/full-video.js +3 -2
- package/dist/slices/onboarding/install.js +4 -3
- package/dist/slices/onboarding/model.js +0 -16
- package/dist/slices/onboarding/packs.js +22 -22
- package/dist/slices/onboarding/quick-short.js +2 -1
- package/dist/slices/onboarding/sample.js +0 -1
- package/dist/slices/onboarding/state.js +2 -11
- package/dist/slices/onboarding/template.js +2 -1
- package/dist/slices/patch-notes/library.js +3 -2
- package/dist/slices/play-drafts/convert.js +4 -0
- package/dist/slices/play-drafts/review-inputs.js +8 -2
- package/dist/slices/play-drafts/review.js +5 -4
- package/dist/slices/play-drafts/schema.js +4 -0
- package/dist/slices/project-templates/from-project.js +9 -2
- package/dist/slices/project-templates/repo.js +6 -1
- package/dist/slices/project-templates/setup.js +8 -0
- package/dist/slices/project-templates/stand-ins.js +22 -0
- package/dist/slices/rebuild/activity.js +2 -0
- package/dist/slices/rebuild/admission-repo.js +3 -2
- package/dist/slices/rebuild/narration-history.js +4 -5
- package/dist/slices/rebuild/narration-retry.js +2 -1
- package/dist/slices/rebuild/preview-details.js +27 -9
- package/dist/slices/rebuild/preview-plan.js +3 -8
- package/dist/slices/rebuild/recipe-build.js +8 -3
- package/dist/slices/rebuild/recipe-describe.js +3 -3
- package/dist/slices/rebuild/recipe-digest.js +58 -0
- package/dist/slices/rebuild/recipe-input-schema.js +10 -0
- package/dist/slices/rebuild/recipe-keywords.js +71 -0
- package/dist/slices/rebuild/recipe-legacy.js +5 -1
- package/dist/slices/rebuild/recipe-model.js +4 -0
- package/dist/slices/rebuild/recipe-narration-text.js +2 -1
- package/dist/slices/rebuild/recipe-preparation.js +3 -3
- package/dist/slices/rebuild/recipe-reference.js +8 -4
- package/dist/slices/rebuild/recipe-reviews.js +27 -7
- package/dist/slices/rebuild/recipe-save.js +6 -3
- package/dist/slices/rebuild/recipe-scenes.js +40 -11
- package/dist/slices/rebuild/recipe-shorts.js +8 -8
- package/dist/slices/rebuild/recipe-social.js +46 -0
- package/dist/slices/rebuild/recipe-text.js +64 -20
- package/dist/slices/rebuild/recipe-validation.js +98 -28
- package/dist/slices/rebuild/recipe-visual.js +55 -16
- package/dist/slices/rebuild/recipe-work.js +15 -3
- package/dist/slices/rebuild/recipe-youtube.js +4 -3
- package/dist/slices/rebuild/recovery-selection.js +3 -1
- package/dist/slices/rebuild/recovery.js +3 -2
- package/dist/slices/rebuild/repo.js +4 -3
- package/dist/slices/rebuild/review-promise.js +25 -0
- package/dist/slices/rebuild/review-redo.js +2 -1
- package/dist/slices/rebuild/runtime-admission.js +4 -3
- package/dist/slices/rebuild/runtime-agent-review.js +11 -5
- package/dist/slices/rebuild/runtime-animate.js +9 -8
- package/dist/slices/rebuild/runtime-article.js +3 -2
- package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
- package/dist/slices/rebuild/runtime-document.js +8 -11
- package/dist/slices/rebuild/runtime-export-bed.js +6 -11
- package/dist/slices/rebuild/runtime-export-edit.js +6 -15
- package/dist/slices/rebuild/runtime-export-inputs.js +7 -7
- package/dist/slices/rebuild/runtime-export-short.js +8 -4
- package/dist/slices/rebuild/runtime-export.js +34 -12
- package/dist/slices/rebuild/runtime-figure-card.js +2 -1
- package/dist/slices/rebuild/runtime-image.js +4 -9
- package/dist/slices/rebuild/runtime-instructions.js +2 -0
- package/dist/slices/rebuild/runtime-keywords.js +59 -0
- package/dist/slices/rebuild/runtime-lines.js +2 -11
- package/dist/slices/rebuild/runtime-local.js +14 -20
- package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
- package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
- package/dist/slices/rebuild/runtime-narration-text.js +10 -15
- package/dist/slices/rebuild/runtime-pictures.js +2 -4
- package/dist/slices/rebuild/runtime-piece-label.js +10 -6
- package/dist/slices/rebuild/runtime-plan.js +31 -5
- package/dist/slices/rebuild/runtime-provider.js +60 -19
- package/dist/slices/rebuild/runtime-publication.js +10 -9
- package/dist/slices/rebuild/runtime-review.js +33 -28
- package/dist/slices/rebuild/runtime-run.js +4 -1
- package/dist/slices/rebuild/runtime-shorts.js +25 -45
- package/dist/slices/rebuild/runtime-store.js +3 -8
- package/dist/slices/rebuild/runtime-subtitles.js +16 -14
- package/dist/slices/rebuild/runtime-voices.js +8 -15
- package/dist/slices/rebuild/runtime-youtube.js +11 -29
- package/dist/slices/rebuild/transition-repo.js +6 -5
- package/dist/slices/rebuild/work-records.js +6 -0
- package/dist/slices/reruns/cascade.js +1 -2
- package/dist/slices/reruns/index.js +6 -9
- package/dist/slices/reviews/external-model.js +3 -0
- package/dist/slices/reviews/external-repo.js +2 -1
- package/dist/slices/reviews/external-rows.js +2 -3
- package/dist/slices/reviews/model.js +26 -8
- package/dist/slices/reviews/repo.js +2 -1
- package/dist/slices/reviews/rules.js +1 -0
- package/dist/slices/reviews/view.js +5 -2
- package/dist/slices/revisions/downloads.js +4 -5
- package/dist/slices/revisions/mutation-assets.js +7 -4
- package/dist/slices/revisions/mutation-cues.js +2 -5
- package/dist/slices/revisions/mutations.js +0 -1
- package/dist/slices/revisions/repo.js +3 -1
- package/dist/slices/revisions/schema.js +1 -0
- package/dist/slices/revisions/view.js +20 -0
- package/dist/slices/run-cost/limits.js +5 -2
- package/dist/slices/run-cost/meter.js +12 -5
- package/dist/slices/run-cost/panel.js +8 -74
- package/dist/slices/run-cost/plan-readings.js +127 -0
- package/dist/slices/run-cost/plan-use.js +169 -0
- package/dist/slices/run-cost/pricing.js +3 -3
- package/dist/slices/run-cost/week.js +32 -4
- package/dist/slices/schedules/agenda.js +11 -2
- package/dist/slices/schedules/by-date.js +42 -0
- package/dist/slices/schedules/calendar.js +5 -0
- package/dist/slices/schedules/design-agenda.js +36 -0
- package/dist/slices/schedules/design-check.js +41 -0
- package/dist/slices/schedules/design-run.js +126 -0
- package/dist/slices/schedules/next-run.js +62 -0
- package/dist/slices/schedules/prepare.js +18 -2
- package/dist/slices/schedules/repo.js +24 -16
- package/dist/slices/schedules/rescore.js +35 -0
- package/dist/slices/schedules/scheduler.js +13 -3
- package/dist/slices/schedules/schema.js +54 -3
- package/dist/slices/schedules/score.js +107 -0
- package/dist/slices/schedules/service.js +57 -24
- package/dist/slices/schedules/topic-list.js +15 -0
- package/dist/slices/schedules/topic-scores.js +104 -0
- package/dist/slices/schedules/topics.js +48 -36
- package/dist/slices/settings/cli-paths.js +4 -6
- package/dist/slices/settings/first-run.js +2 -11
- package/dist/slices/settings/model-reach.js +3 -17
- package/dist/slices/settings/model.js +10 -0
- package/dist/slices/settings/playback.js +33 -22
- package/dist/slices/settings/probe-read.js +16 -0
- package/dist/slices/settings/repo.js +33 -0
- package/dist/slices/settings/tutorial.js +2 -2
- package/dist/slices/settings/voices.js +4 -12
- package/dist/slices/shorts/pick.js +2 -15
- package/dist/slices/shorts/prompts.js +2 -13
- package/dist/slices/shorts/render.js +3 -0
- package/dist/slices/social/channel.js +44 -0
- package/dist/slices/social/defaults.js +17 -0
- package/dist/slices/social/due.js +36 -0
- package/dist/slices/social/extension.js +18 -0
- package/dist/slices/social/fit.js +115 -0
- package/dist/slices/social/limits.js +186 -0
- package/dist/slices/social/links.js +21 -0
- package/dist/slices/social/media.js +131 -0
- package/dist/slices/social/model.js +75 -0
- package/dist/slices/social/notice.js +19 -0
- package/dist/slices/social/pack.js +176 -0
- package/dist/slices/social/post-prompt.js +55 -0
- package/dist/slices/social/queue.js +31 -0
- package/dist/slices/social/repo.js +133 -0
- package/dist/slices/social/reshape.js +97 -0
- package/dist/slices/social/rules.js +5 -0
- package/dist/slices/social/schema.js +70 -0
- package/dist/slices/social/serve.js +51 -0
- package/dist/slices/social/service.js +128 -0
- package/dist/slices/social/settings.js +21 -0
- package/dist/slices/social/sources.js +114 -0
- package/dist/slices/social/state.js +110 -0
- package/dist/slices/social/text.js +149 -0
- package/dist/slices/storage/arrange.js +3 -1
- package/dist/slices/storage/assets.js +8 -10
- package/dist/slices/storage/backup-designs.js +74 -0
- package/dist/slices/storage/backup-export.js +8 -3
- package/dist/slices/storage/backup-format.js +10 -0
- package/dist/slices/storage/backup-import.js +20 -2
- package/dist/slices/storage/delete-project.js +6 -5
- package/dist/slices/storage/files-location.js +6 -8
- package/dist/slices/storage/layout.js +13 -2
- package/dist/slices/storage/model.js +3 -0
- package/dist/slices/storage/portable.js +16 -11
- package/dist/slices/storage/schema.js +2 -0
- package/dist/slices/storage/staging-refs.js +2 -1
- package/dist/slices/storage/staging.js +6 -9
- package/dist/slices/storage/trim.js +10 -3
- package/dist/slices/studio/calendar.js +4 -1
- package/dist/slices/studio/pick.js +2 -11
- package/dist/slices/studio/plan.js +6 -15
- package/dist/slices/studio/queue.js +3 -14
- package/dist/slices/studio/releases.js +26 -0
- package/dist/slices/studio/settings.js +14 -51
- package/dist/slices/studio/videos.js +12 -0
- package/dist/slices/style-preview/render.js +34 -13
- package/dist/slices/style-preview/schema.js +13 -0
- package/dist/slices/style-preview/service.js +2 -1
- package/dist/slices/style-preview/settings.js +33 -5
- package/dist/slices/telemetry/collector-client.js +2 -4
- package/dist/slices/telemetry/flush.js +2 -4
- package/dist/slices/telemetry/model.js +0 -7
- package/dist/slices/telemetry/record.js +10 -3
- package/dist/slices/template-studio/anatomy-view.js +118 -0
- package/dist/slices/template-studio/anatomy.js +73 -0
- package/dist/slices/template-studio/bakeoff-make.js +225 -0
- package/dist/slices/template-studio/bakeoff-repo.js +83 -0
- package/dist/slices/template-studio/bakeoff.js +333 -0
- package/dist/slices/template-studio/budget.js +103 -0
- package/dist/slices/template-studio/checks.js +273 -0
- package/dist/slices/template-studio/document-sample.js +56 -0
- package/dist/slices/template-studio/edit.js +15 -0
- package/dist/slices/template-studio/for-all.js +161 -0
- package/dist/slices/template-studio/free-video.js +31 -0
- package/dist/slices/template-studio/free.js +176 -0
- package/dist/slices/template-studio/gate.js +40 -0
- package/dist/slices/template-studio/hidden.js +20 -0
- package/dist/slices/template-studio/jobs.js +79 -0
- package/dist/slices/template-studio/loudness.js +111 -0
- package/dist/slices/template-studio/make.js +40 -0
- package/dist/slices/template-studio/model.js +54 -0
- package/dist/slices/template-studio/pack-import.js +253 -0
- package/dist/slices/template-studio/pack-samples.js +60 -0
- package/dist/slices/template-studio/pack.js +205 -0
- package/dist/slices/template-studio/paid-view.js +66 -0
- package/dist/slices/template-studio/paid.js +348 -0
- package/dist/slices/template-studio/quote.js +148 -0
- package/dist/slices/template-studio/ready.js +104 -0
- package/dist/slices/template-studio/repo.js +134 -0
- package/dist/slices/template-studio/reviews-path.js +58 -0
- package/dist/slices/template-studio/runner.js +84 -0
- package/dist/slices/template-studio/save.js +236 -0
- package/dist/slices/template-studio/say-it-as.js +248 -0
- package/dist/slices/template-studio/schedule-gate.js +34 -0
- package/dist/slices/template-studio/schedule-price.js +30 -0
- package/dist/slices/template-studio/schedule-sample.js +87 -0
- package/dist/slices/template-studio/schema.js +218 -0
- package/dist/slices/template-studio/scope.js +124 -0
- package/dist/slices/template-studio/sections.js +176 -0
- package/dist/slices/template-studio/service.js +173 -0
- package/dist/slices/template-studio/status.js +174 -0
- package/dist/slices/template-studio/topic.js +223 -0
- package/dist/slices/trash/designs.js +76 -0
- package/dist/slices/trash/model.js +13 -4
- package/dist/slices/trash/service.js +52 -2
- package/dist/slices/tutorials/library.js +3 -2
- package/dist/slices/video/ass-text.js +17 -0
- package/dist/slices/video/audio-export.js +2 -64
- package/dist/slices/video/encoding.js +160 -0
- package/dist/slices/video/ffmpeg.js +23 -21
- package/dist/slices/video/figure-card.js +1 -15
- package/dist/slices/video/slideshow.js +43 -18
- package/dist/slices/voices/palette.js +0 -3
- package/dist/slices/youtube/answer.js +2 -15
- package/dist/slices/youtube/edits-repo.js +2 -11
- package/dist/tutorials/Agents-MCP.md +2 -1
- package/dist/tutorials/Assistant.md +42 -0
- package/dist/tutorials/Channels.md +2 -0
- package/dist/tutorials/Home-and-Projects.md +19 -0
- package/dist/tutorials/Install.md +1 -0
- package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
- package/dist/tutorials/Models.md +33 -1
- package/dist/tutorials/Notifications.md +6 -0
- package/dist/tutorials/Play-Images.md +4 -0
- package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
- package/dist/tutorials/Prompts.md +10 -6
- package/dist/tutorials/Remote-Access.md +63 -0
- package/dist/tutorials/Reviews-and-Checkpoints.md +13 -2
- package/dist/tutorials/Schedules.md +21 -1
- package/dist/tutorials/Settings-Reference.md +50 -8
- package/dist/tutorials/Template-Studio.md +125 -0
- package/dist/tutorials/Templates.md +3 -0
- package/dist/tutorials/_Sidebar.md +5 -0
- package/dist/updater/work-in-progress.js +42 -12
- package/dist/web/assets/index-CkAI_2E7.css +1 -0
- package/dist/web/assets/index-DcD0cdfo.js +334 -0
- package/dist/web/assets/{pdf-T7MCwjIv.js → pdf-TODRwF31.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +5 -1
- package/dist/slices/article/provided-entries.js +0 -66
- package/dist/slices/article/run.js +0 -145
- package/dist/slices/images/run.js +0 -234
- package/dist/slices/narration/legacy-plan.js +0 -58
- package/dist/slices/narration/run.js +0 -270
- package/dist/slices/rebuild/runtime-actions.js +0 -90
- package/dist/slices/research/run.js +0 -224
- package/dist/slices/subtitles/prepare.js +0 -194
- package/dist/slices/subtitles/transcript.js +0 -34
- package/dist/slices/thumbnail/run.js +0 -219
- package/dist/slices/video/audio-inputs.js +0 -33
- package/dist/slices/video/reuse-audio.js +0 -62
- package/dist/slices/video/run.js +0 -78
- package/dist/slices/video/write-export.js +0 -158
- package/dist/slices/video/write-subtitles.js +0 -59
- package/dist/web/assets/index-BadsoORk.css +0 -1
- package/dist/web/assets/index-D8LqNsCl.js +0 -326
|
@@ -7,7 +7,8 @@ import { deleteCastImage, generateCastImage, uploadCastImage, } from "../../slic
|
|
|
7
7
|
import { castImageMaxBytes } from "../../slices/channels/images.js";
|
|
8
8
|
import { imageBlob } from "../../slices/channels/repo.js";
|
|
9
9
|
import { createCastMember, createChannel, deleteCastMember, deleteChannel, listChannels, moveCastMember, moveTemplate, readChannel, setChannelAiDisclosure, updateCastMember, updateChannel, } from "../../slices/channels/service.js";
|
|
10
|
-
import { onInvalid
|
|
10
|
+
import { onInvalid } from "./problem.js";
|
|
11
|
+
import { jsonBody, refusal } from "./refusal.js";
|
|
11
12
|
const idParam = z.object({ id: z.uuid() });
|
|
12
13
|
const memberParam = z.object({ memberId: z.uuid() });
|
|
13
14
|
const imageParam = memberParam.extend({ imageId: z.uuid() });
|
|
@@ -26,7 +27,7 @@ export function channelRoutes(deps) {
|
|
|
26
27
|
return (new Hono()
|
|
27
28
|
.get("/", (c) => c.json({ channels: listChannels(service) }))
|
|
28
29
|
.post("/", async (c) => {
|
|
29
|
-
const result = createChannel(service, await
|
|
30
|
+
const result = createChannel(service, await jsonBody(c));
|
|
30
31
|
return result.ok ? c.json(result.value, 201) : refused(c, result);
|
|
31
32
|
})
|
|
32
33
|
// The pictures by content hash: they never change, so the browser may keep them.
|
|
@@ -41,11 +42,11 @@ export function channelRoutes(deps) {
|
|
|
41
42
|
});
|
|
42
43
|
})
|
|
43
44
|
.put("/templates/:templateId", zValidator("param", templateParam, onInvalid), async (c) => {
|
|
44
|
-
const result = moveTemplate(service, c.req.valid("param").templateId, await
|
|
45
|
+
const result = moveTemplate(service, c.req.valid("param").templateId, await jsonBody(c));
|
|
45
46
|
return result.ok ? c.json(result.value) : refused(c, result);
|
|
46
47
|
})
|
|
47
48
|
.put("/cast/:memberId", zValidator("param", memberParam, onInvalid), async (c) => {
|
|
48
|
-
const result = updateCastMember(service, c.req.valid("param").memberId, await
|
|
49
|
+
const result = updateCastMember(service, c.req.valid("param").memberId, await jsonBody(c));
|
|
49
50
|
return result.ok ? c.json(result.value) : refused(c, result);
|
|
50
51
|
})
|
|
51
52
|
.delete("/cast/:memberId", zValidator("param", memberParam, onInvalid), (c) => {
|
|
@@ -66,7 +67,7 @@ export function channelRoutes(deps) {
|
|
|
66
67
|
return result.ok ? c.json(result.value, 201) : refused(c, result);
|
|
67
68
|
})
|
|
68
69
|
.post("/cast/:memberId/generate", zValidator("param", memberParam, onInvalid), async (c) => {
|
|
69
|
-
const result = generateCastImage(service, c.req.valid("param").memberId, await
|
|
70
|
+
const result = generateCastImage(service, c.req.valid("param").memberId, await jsonBody(c));
|
|
70
71
|
return result.ok ? c.json(result.value, 202) : refused(c, result);
|
|
71
72
|
})
|
|
72
73
|
.delete("/cast/:memberId/images/:imageId", zValidator("param", imageParam, onInvalid), (c) => {
|
|
@@ -79,11 +80,11 @@ export function channelRoutes(deps) {
|
|
|
79
80
|
return result.ok ? c.json(result.value) : refused(c, result);
|
|
80
81
|
})
|
|
81
82
|
.put("/:id", zValidator("param", idParam, onInvalid), async (c) => {
|
|
82
|
-
const result = updateChannel(service, c.req.valid("param").id, await
|
|
83
|
+
const result = updateChannel(service, c.req.valid("param").id, await jsonBody(c));
|
|
83
84
|
return result.ok ? c.json(result.value) : refused(c, result);
|
|
84
85
|
})
|
|
85
86
|
.put("/:id/ai-disclosure", zValidator("param", idParam, onInvalid), async (c) => {
|
|
86
|
-
const result = setChannelAiDisclosure(service, c.req.valid("param").id, await
|
|
87
|
+
const result = setChannelAiDisclosure(service, c.req.valid("param").id, await jsonBody(c));
|
|
87
88
|
return result.ok ? c.json(result.value) : refused(c, result);
|
|
88
89
|
})
|
|
89
90
|
.delete("/:id", zValidator("param", idParam, onInvalid), (c) => {
|
|
@@ -91,23 +92,15 @@ export function channelRoutes(deps) {
|
|
|
91
92
|
return result.ok ? c.body(null, 204) : refused(c, result);
|
|
92
93
|
})
|
|
93
94
|
.post("/:id/cast", zValidator("param", idParam, onInvalid), async (c) => {
|
|
94
|
-
const result = createCastMember(service, c.req.valid("param").id, await
|
|
95
|
+
const result = createCastMember(service, c.req.valid("param").id, await jsonBody(c));
|
|
95
96
|
return result.ok ? c.json(result.value, 201) : refused(c, result);
|
|
96
97
|
})
|
|
97
98
|
// Move up, Move down and their Undo: one member to a place in the cast's order.
|
|
98
99
|
.post("/:id/cast/move", zValidator("param", idParam, onInvalid), async (c) => {
|
|
99
|
-
const result = moveCastMember(service, c.req.valid("param").id, await
|
|
100
|
+
const result = moveCastMember(service, c.req.valid("param").id, await jsonBody(c));
|
|
100
101
|
return result.ok ? c.json({ cast: result.value }) : refused(c, result);
|
|
101
102
|
}));
|
|
102
103
|
}
|
|
103
|
-
async function body(c) {
|
|
104
|
-
try {
|
|
105
|
-
return await c.req.json();
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
return undefined;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
104
|
const details = {
|
|
112
105
|
"not-found": "This channel, cast member or picture no longer exists; it may have been deleted in another tab. Go back to Channels.",
|
|
113
106
|
conflict: "This changed in another tab while you were editing. Reload the page to see the latest, then make your change again.",
|
|
@@ -119,15 +112,9 @@ const details = {
|
|
|
119
112
|
"no-image-provider": "Slopify can't make pictures here yet. Set up an image provider in Settings → Providers, or upload a picture instead.",
|
|
120
113
|
};
|
|
121
114
|
function refused(c, result) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
:
|
|
125
|
-
? 409
|
|
126
|
-
: 400;
|
|
127
|
-
return problem(c, {
|
|
128
|
-
status,
|
|
129
|
-
title: titleOf(status),
|
|
115
|
+
return refusal(c, result.reason, {
|
|
116
|
+
statuses: { "not-found": 404, conflict: 409, "has-templates": 409 },
|
|
117
|
+
otherwise: 400,
|
|
130
118
|
detail: result.message ?? details[result.reason],
|
|
131
|
-
extensions: { reason: result.reason },
|
|
132
119
|
});
|
|
133
120
|
}
|
|
@@ -1,37 +1,44 @@
|
|
|
1
1
|
import { zValidator } from "@hono/zod-validator";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
|
-
import {
|
|
3
|
+
import { errorText } from "../../kernel/errors.js";
|
|
4
|
+
import { projectPaused } from "../../slices/admission/repo.js";
|
|
4
5
|
import { changeCheckpoints, checkpointChangeSchema, readCheckpointStatus, replayCheckpointApproval, validateCheckpointApproval, } from "../../slices/checkpoints/change.js";
|
|
6
|
+
import { listCheckpoints } from "../../slices/checkpoints/repo.js";
|
|
5
7
|
import { checkpointApprovalSchema, checkpointRowSchema } from "../../slices/checkpoints/schema.js";
|
|
6
8
|
import { withProjectControl } from "../../slices/control/lock.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const projectParam = z.object({ id });
|
|
9
|
+
import { projectHolds } from "../../slices/reviews/holds.js";
|
|
10
|
+
import { idParam, idString } from "./ids.js";
|
|
11
|
+
import { onInvalid, problem } from "./problem.js";
|
|
12
|
+
import { refusal } from "./refusal.js";
|
|
13
|
+
const id = idString;
|
|
14
|
+
const projectParam = idParam;
|
|
14
15
|
const approvalParam = projectParam.extend({ checkpointId: id });
|
|
15
|
-
const approvalBody = checkpointApprovalSchema
|
|
16
|
+
export const approvalBody = checkpointApprovalSchema
|
|
16
17
|
.unwrap()
|
|
17
18
|
.omit({ projectId: true, checkpointId: true, approvedAt: true });
|
|
18
19
|
function refused(c, reason) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
title: titleOf(status),
|
|
20
|
+
return refusal(c, reason, {
|
|
21
|
+
statuses: { "not-found": 404, "invalid-input": 400 },
|
|
22
|
+
otherwise: 409,
|
|
23
23
|
detail: reason === "not-found"
|
|
24
24
|
? "This checkpoint no longer exists; the project may have moved on or changed. Reload the page to see where it is now."
|
|
25
25
|
: reason === "invalid-input"
|
|
26
26
|
? "This checkpoint answer could not be read. Reload the page and try again."
|
|
27
27
|
: "This checkpoint changed since the page loaded, for example it was already approved. Reload the page to see its current state, then try again.",
|
|
28
|
-
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
// Taking a checkpoint off that holds the run now would start the paid steps behind it without
|
|
31
|
+
// the review: that goes through Approve, which checks what is approved is what was looked at.
|
|
32
|
+
function heldThere(c, stage) {
|
|
33
|
+
return problem(c, {
|
|
34
|
+
status: 409,
|
|
35
|
+
detail: `The run is waiting at the checkpoint before ${stage}, so it can't be taken off now: that would start the next steps without the review. Look over what is made, then press Approve on the checkpoint (agents: approve_checkpoint).`,
|
|
36
|
+
extensions: { reason: "held-at-checkpoint" },
|
|
29
37
|
});
|
|
30
38
|
}
|
|
31
39
|
function alreadyApproved(c) {
|
|
32
40
|
return problem(c, {
|
|
33
41
|
status: 409,
|
|
34
|
-
title: titleOf(409),
|
|
35
42
|
detail: "This checkpoint was already approved, so nothing changed. Reload the page (or call needs_attention) to see what waits now.",
|
|
36
43
|
extensions: { reason: "already-approved" },
|
|
37
44
|
});
|
|
@@ -47,7 +54,7 @@ function buildCheckpointRoutes(deps) {
|
|
|
47
54
|
catch (error) {
|
|
48
55
|
deps.log.write("error", "checkpoint.notify", {
|
|
49
56
|
projectId,
|
|
50
|
-
detail:
|
|
57
|
+
detail: errorText(error),
|
|
51
58
|
});
|
|
52
59
|
}
|
|
53
60
|
if (wake) {
|
|
@@ -57,7 +64,7 @@ function buildCheckpointRoutes(deps) {
|
|
|
57
64
|
catch (error) {
|
|
58
65
|
deps.log.write("error", "checkpoint.wake", {
|
|
59
66
|
projectId,
|
|
60
|
-
detail:
|
|
67
|
+
detail: errorText(error),
|
|
61
68
|
});
|
|
62
69
|
}
|
|
63
70
|
}
|
|
@@ -95,6 +102,15 @@ function buildCheckpointRoutes(deps) {
|
|
|
95
102
|
const projectId = c.req.valid("param").id;
|
|
96
103
|
const body = c.req.valid("json");
|
|
97
104
|
return withProjectControl(deps.db, projectId, () => {
|
|
105
|
+
// A paused run goes on only through Continue the run, so taking a checkpoint off
|
|
106
|
+
// then releases nothing by itself.
|
|
107
|
+
const holding = projectPaused(deps.db, projectId)
|
|
108
|
+
? []
|
|
109
|
+
: (projectHolds(deps.db, { projectId }).holding.get(projectId) ?? []);
|
|
110
|
+
const removed = listCheckpoints(deps.db, projectId, body.revisionId).filter((row) => !body.stages.includes(row.stage));
|
|
111
|
+
const held = holding.find((hold) => removed.some((row) => row.checkpointId === hold.checkpointId));
|
|
112
|
+
if (held !== undefined)
|
|
113
|
+
return heldThere(c, held.stage);
|
|
98
114
|
const result = changeCheckpoints(deps, { ...body, projectId });
|
|
99
115
|
if (!result.ok)
|
|
100
116
|
return refused(c, result.reason);
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { zValidator } from "@hono/zod-validator";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { designDocumentSchema } from "../../slices/designs/schema.js";
|
|
5
|
+
import { designAffectedSections, sampleNeedsPicture } from "../../slices/designs/sections.js";
|
|
6
|
+
import { freeSample } from "../../slices/designs/studio-kind.js";
|
|
7
|
+
import { makeFromTemplate, quoteDocument, quoteTemplate, } from "../../slices/designs/template-make.js";
|
|
8
|
+
import { createTemplate, getTemplate, listTemplates, markTemplateReady, saveTemplate, } from "../../slices/designs/templates.js";
|
|
9
|
+
import { trashDesignTemplate } from "../../slices/trash/designs.js";
|
|
10
|
+
import { designRefused } from "./designs.js";
|
|
11
|
+
import { idParam } from "./ids.js";
|
|
12
|
+
import { onInvalid, problem } from "./problem.js";
|
|
13
|
+
import { jsonBody } from "./refusal.js";
|
|
14
|
+
export const sampleRequestSchema = z
|
|
15
|
+
.object({
|
|
16
|
+
version: z.number().int().min(1),
|
|
17
|
+
acknowledgedHigh: z.number().min(0).max(1000),
|
|
18
|
+
// That the button said the picture's price is unknown, and the person pressed it anyway.
|
|
19
|
+
acknowledgedUnknown: z.boolean().optional(),
|
|
20
|
+
})
|
|
21
|
+
.strict();
|
|
22
|
+
const quoteBodySchema = z.object({ document: designDocumentSchema }).strict();
|
|
23
|
+
const notFoundRefusal = {
|
|
24
|
+
reason: "not-found",
|
|
25
|
+
message: "This design template no longer exists. Open Library → Designs → Templates to choose another.",
|
|
26
|
+
};
|
|
27
|
+
export function designTemplateRoutes(deps) {
|
|
28
|
+
const unavailable = (c) => problem(c, {
|
|
29
|
+
status: 503,
|
|
30
|
+
detail: "Design templates aren't available in this copy of Slopify. Restart Slopify; if it keeps happening, reinstall it.",
|
|
31
|
+
});
|
|
32
|
+
return new Hono()
|
|
33
|
+
.get("/", (c) => deps === undefined ? unavailable(c) : c.json({ templates: listTemplates(deps.service.db) }))
|
|
34
|
+
.post("/", async (c) => {
|
|
35
|
+
if (deps === undefined)
|
|
36
|
+
return unavailable(c);
|
|
37
|
+
const result = createTemplate(deps.service, await jsonBody(c));
|
|
38
|
+
return result.ok ? c.json(result.value, 201) : designRefused(c, result);
|
|
39
|
+
})
|
|
40
|
+
.get("/:id", zValidator("param", idParam, onInvalid), (c) => {
|
|
41
|
+
if (deps === undefined)
|
|
42
|
+
return unavailable(c);
|
|
43
|
+
const template = getTemplate(deps.service.db, c.req.valid("param").id);
|
|
44
|
+
return template === undefined
|
|
45
|
+
? designRefused(c, {
|
|
46
|
+
reason: "not-found",
|
|
47
|
+
message: "This design template no longer exists. Open Library → Designs → Templates to choose another.",
|
|
48
|
+
})
|
|
49
|
+
: c.json({ ...template, sample: deps.samples?.state?.(template.id) ?? null });
|
|
50
|
+
})
|
|
51
|
+
.put("/:id", zValidator("param", idParam, onInvalid), async (c) => {
|
|
52
|
+
if (deps === undefined)
|
|
53
|
+
return unavailable(c);
|
|
54
|
+
const id = c.req.valid("param").id;
|
|
55
|
+
const body = await jsonBody(c);
|
|
56
|
+
const result = saveTemplate(deps.service, id, body);
|
|
57
|
+
if (!result.ok)
|
|
58
|
+
return designRefused(c, result);
|
|
59
|
+
const { template, saved, before } = result.value;
|
|
60
|
+
if (saved)
|
|
61
|
+
deps.templateChanged?.(id);
|
|
62
|
+
const asked = z
|
|
63
|
+
.object({
|
|
64
|
+
sample: z.enum(["make", "skip"]).optional(),
|
|
65
|
+
acknowledgedHigh: z.number().optional(),
|
|
66
|
+
})
|
|
67
|
+
.catch({})
|
|
68
|
+
.parse(body);
|
|
69
|
+
const sample = deps.samples === undefined || !saved
|
|
70
|
+
? null
|
|
71
|
+
: deps.samples.afterSave({
|
|
72
|
+
templateId: id,
|
|
73
|
+
version: template.headVersion,
|
|
74
|
+
before,
|
|
75
|
+
after: template.document,
|
|
76
|
+
sample: asked.sample ?? "skip",
|
|
77
|
+
acknowledgedHigh: asked.acknowledgedHigh ?? 0,
|
|
78
|
+
});
|
|
79
|
+
return c.json({
|
|
80
|
+
template,
|
|
81
|
+
saved,
|
|
82
|
+
sample: sample === null ? null : sample.ok ? sample.value : { refused: sample.message },
|
|
83
|
+
});
|
|
84
|
+
})
|
|
85
|
+
.delete("/:id", zValidator("param", idParam, onInvalid), (c) => {
|
|
86
|
+
if (deps === undefined)
|
|
87
|
+
return unavailable(c);
|
|
88
|
+
const result = trashDesignTemplate(deps.service, c.req.valid("param").id);
|
|
89
|
+
return result.ok
|
|
90
|
+
? c.body(null, 204)
|
|
91
|
+
: designRefused(c, {
|
|
92
|
+
reason: "not-found",
|
|
93
|
+
message: "This design template no longer exists. Open Library → Designs → Templates to choose another.",
|
|
94
|
+
});
|
|
95
|
+
})
|
|
96
|
+
.post("/:id/quote", zValidator("param", idParam, onInvalid), async (c) => {
|
|
97
|
+
if (deps === undefined)
|
|
98
|
+
return unavailable(c);
|
|
99
|
+
const id = c.req.valid("param").id;
|
|
100
|
+
const body = await jsonBody(c);
|
|
101
|
+
// With a document: what saving it would cost the editor's sample (only a changed
|
|
102
|
+
// picture is paid). Without: what one piece from the newest version costs.
|
|
103
|
+
if (typeof body === "object" && body !== null && Object.keys(body).length > 0) {
|
|
104
|
+
const parsed = quoteBodySchema.safeParse(body);
|
|
105
|
+
if (!parsed.success)
|
|
106
|
+
return designRefused(c, {
|
|
107
|
+
reason: "invalid",
|
|
108
|
+
message: `The template can't be priced: ${parsed.error.issues[0]?.message ?? "a field is missing"}.`,
|
|
109
|
+
});
|
|
110
|
+
const template = getTemplate(deps.service.db, id);
|
|
111
|
+
if (template === undefined)
|
|
112
|
+
return designRefused(c, notFoundRefusal);
|
|
113
|
+
const sample = deps.samples?.state?.(id);
|
|
114
|
+
const sections = designAffectedSections(template.document, parsed.data.document);
|
|
115
|
+
const makesPicture = sampleNeedsPicture(sections) ||
|
|
116
|
+
sample === null ||
|
|
117
|
+
sample === undefined ||
|
|
118
|
+
sample.designId == null ||
|
|
119
|
+
sample.state === "failed";
|
|
120
|
+
const quote = makesPicture
|
|
121
|
+
? quoteDocument(deps.catalogue(), parsed.data.document)
|
|
122
|
+
: freeSample(deps.catalogue());
|
|
123
|
+
return c.json({ ...quote, sections, makesPicture });
|
|
124
|
+
}
|
|
125
|
+
const result = quoteTemplate(deps, id);
|
|
126
|
+
return result.ok ? c.json(result.value) : designRefused(c, result);
|
|
127
|
+
})
|
|
128
|
+
.post("/:id/sample", zValidator("param", idParam, onInvalid), async (c) => {
|
|
129
|
+
if (deps === undefined)
|
|
130
|
+
return unavailable(c);
|
|
131
|
+
const request = deps.samples?.request;
|
|
132
|
+
if (request === undefined)
|
|
133
|
+
return unavailable(c);
|
|
134
|
+
const parsed = sampleRequestSchema.safeParse(await jsonBody(c));
|
|
135
|
+
if (!parsed.success)
|
|
136
|
+
return designRefused(c, {
|
|
137
|
+
reason: "invalid",
|
|
138
|
+
message: "Say which version to make a sample of and the price you saw, then press Make sample.",
|
|
139
|
+
});
|
|
140
|
+
const result = request(c.req.valid("param").id, parsed.data.version, parsed.data.acknowledgedHigh, parsed.data.acknowledgedUnknown);
|
|
141
|
+
return result.ok ? c.json(result.value, 202) : designRefused(c, result);
|
|
142
|
+
})
|
|
143
|
+
.post("/:id/ready", zValidator("param", idParam, onInvalid), async (c) => {
|
|
144
|
+
if (deps === undefined)
|
|
145
|
+
return unavailable(c);
|
|
146
|
+
const id = c.req.valid("param").id;
|
|
147
|
+
const checks = deps.checks;
|
|
148
|
+
const result = await markTemplateReady(deps.service, id, await jsonBody(c), checks === undefined ? undefined : (doc, version) => checks(id, doc, version));
|
|
149
|
+
if (result.ok) {
|
|
150
|
+
deps.templateChanged?.(id);
|
|
151
|
+
return c.json(result.value);
|
|
152
|
+
}
|
|
153
|
+
return result.reason === "not-ready"
|
|
154
|
+
? problem(c, {
|
|
155
|
+
status: 409,
|
|
156
|
+
detail: result.message,
|
|
157
|
+
extensions: { reason: result.reason, checks: result.current },
|
|
158
|
+
})
|
|
159
|
+
: designRefused(c, result);
|
|
160
|
+
})
|
|
161
|
+
.post("/:id/make", zValidator("param", idParam, onInvalid), async (c) => {
|
|
162
|
+
if (deps === undefined)
|
|
163
|
+
return unavailable(c);
|
|
164
|
+
const result = makeFromTemplate(deps, c.req.valid("param").id, await jsonBody(c));
|
|
165
|
+
return result.ok ? c.json(result.value, 202) : designRefused(c, result);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { zValidator } from "@hono/zod-validator";
|
|
3
|
+
import { Hono } from "hono";
|
|
4
|
+
import { bodyLimit } from "hono/body-limit";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { castImageMaxBytes } from "../../slices/channels/images.js";
|
|
7
|
+
import { designFormats } from "../../slices/designs/model.js";
|
|
8
|
+
import { createDesign, getDesign, listDesignViews, setDesignHead, stepPicture, storeUploadedPicture, updateDesignRecord, } from "../../slices/designs/service.js";
|
|
9
|
+
import { trashDesign } from "../../slices/trash/designs.js";
|
|
10
|
+
import { idParam, idString } from "./ids.js";
|
|
11
|
+
import { onInvalid, problem } from "./problem.js";
|
|
12
|
+
import { jsonBody } from "./refusal.js";
|
|
13
|
+
const stepParam = idParam.extend({ stepId: idString });
|
|
14
|
+
const fileParam = idParam.extend({
|
|
15
|
+
file: z.string().regex(new RegExp(`^(?:${designFormats.join("|")})\\.(?:png|pdf)$`)),
|
|
16
|
+
});
|
|
17
|
+
const listQuery = z.object({ projectId: idString.optional() });
|
|
18
|
+
export const designStatuses = {
|
|
19
|
+
"not-found": 404,
|
|
20
|
+
invalid: 400,
|
|
21
|
+
changed: 409,
|
|
22
|
+
"mutation-reused": 409,
|
|
23
|
+
"not-an-image": 400,
|
|
24
|
+
"still-uploading": 409,
|
|
25
|
+
"upload-gone": 404,
|
|
26
|
+
"project-not-found": 404,
|
|
27
|
+
"channel-not-found": 404,
|
|
28
|
+
busy: 409,
|
|
29
|
+
"no-image-provider": 409,
|
|
30
|
+
"cost-changed": 409,
|
|
31
|
+
"missing-values": 400,
|
|
32
|
+
"not-ready": 409,
|
|
33
|
+
};
|
|
34
|
+
export function designRefused(c, result) {
|
|
35
|
+
return problem(c, {
|
|
36
|
+
status: designStatuses[result.reason],
|
|
37
|
+
detail: result.message,
|
|
38
|
+
extensions: {
|
|
39
|
+
reason: result.reason,
|
|
40
|
+
...(result.current === undefined
|
|
41
|
+
? {}
|
|
42
|
+
: result.reason === "cost-changed"
|
|
43
|
+
? { quote: result.current }
|
|
44
|
+
: { current: result.current }),
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const unavailable = (c) => problem(c, {
|
|
49
|
+
status: 503,
|
|
50
|
+
detail: "Designs aren't available in this copy of Slopify. Restart Slopify; if it keeps happening, reinstall it.",
|
|
51
|
+
});
|
|
52
|
+
export function designRoutes(deps) {
|
|
53
|
+
return (new Hono()
|
|
54
|
+
.get("/", zValidator("query", listQuery, onInvalid), (c) => {
|
|
55
|
+
if (deps === undefined)
|
|
56
|
+
return unavailable(c);
|
|
57
|
+
return c.json({
|
|
58
|
+
designs: listDesignViews(deps.service.db, c.req.valid("query").projectId),
|
|
59
|
+
});
|
|
60
|
+
})
|
|
61
|
+
.post("/", async (c) => {
|
|
62
|
+
if (deps === undefined)
|
|
63
|
+
return unavailable(c);
|
|
64
|
+
const result = createDesign(deps.service, await jsonBody(c));
|
|
65
|
+
return result.ok ? c.json(result.value, 201) : designRefused(c, result);
|
|
66
|
+
})
|
|
67
|
+
// The picture's bytes are the body; the answer's sha256 starts a design (fromStepSha).
|
|
68
|
+
.post("/pictures", bodyLimit({
|
|
69
|
+
maxSize: castImageMaxBytes,
|
|
70
|
+
onError: (c) => designRefused(c, {
|
|
71
|
+
reason: "not-an-image",
|
|
72
|
+
message: `This picture is larger than ${String(castImageMaxBytes / 1024 / 1024)} MB. Save it smaller (for example as a JPEG) and upload it again.`,
|
|
73
|
+
}),
|
|
74
|
+
}), async (c) => {
|
|
75
|
+
if (deps === undefined)
|
|
76
|
+
return unavailable(c);
|
|
77
|
+
const result = storeUploadedPicture(deps.service, new Uint8Array(await c.req.arrayBuffer()));
|
|
78
|
+
return result.ok ? c.json(result.value, 201) : designRefused(c, result);
|
|
79
|
+
})
|
|
80
|
+
.get("/:id", zValidator("param", idParam, onInvalid), (c) => {
|
|
81
|
+
if (deps === undefined)
|
|
82
|
+
return unavailable(c);
|
|
83
|
+
const result = getDesign(deps.service, c.req.valid("param").id);
|
|
84
|
+
return result.ok ? c.json(result.value) : designRefused(c, result);
|
|
85
|
+
})
|
|
86
|
+
.put("/:id", zValidator("param", idParam, onInvalid), async (c) => {
|
|
87
|
+
if (deps === undefined)
|
|
88
|
+
return unavailable(c);
|
|
89
|
+
const result = updateDesignRecord(deps.service, c.req.valid("param").id, await jsonBody(c));
|
|
90
|
+
return result.ok ? c.json(result.value) : designRefused(c, result);
|
|
91
|
+
})
|
|
92
|
+
.delete("/:id", zValidator("param", idParam, onInvalid), (c) => {
|
|
93
|
+
if (deps === undefined)
|
|
94
|
+
return unavailable(c);
|
|
95
|
+
const id = c.req.valid("param").id;
|
|
96
|
+
const result = trashDesign(deps.service, id);
|
|
97
|
+
if (!result.ok)
|
|
98
|
+
return designRefused(c, {
|
|
99
|
+
reason: "not-found",
|
|
100
|
+
message: "This design no longer exists. Open Library → Designs to choose another.",
|
|
101
|
+
});
|
|
102
|
+
deps.service.emit?.({ type: "design.changed", designId: id });
|
|
103
|
+
return c.body(null, 204);
|
|
104
|
+
})
|
|
105
|
+
// Quoting records nothing and starts nothing.
|
|
106
|
+
.post("/:id/quote", zValidator("param", idParam, onInvalid), async (c) => {
|
|
107
|
+
if (deps === undefined)
|
|
108
|
+
return unavailable(c);
|
|
109
|
+
const result = deps.runner.quoteEdit(c.req.valid("param").id, await jsonBody(c));
|
|
110
|
+
return result.ok ? c.json(result.value) : designRefused(c, result);
|
|
111
|
+
})
|
|
112
|
+
.post("/:id/artwork/quote", zValidator("param", idParam, onInvalid), (c) => {
|
|
113
|
+
if (deps === undefined)
|
|
114
|
+
return unavailable(c);
|
|
115
|
+
const result = deps.runner.quoteArtwork(c.req.valid("param").id);
|
|
116
|
+
return result.ok ? c.json(result.value) : designRefused(c, result);
|
|
117
|
+
})
|
|
118
|
+
.post("/:id/edit", zValidator("param", idParam, onInvalid), async (c) => {
|
|
119
|
+
if (deps === undefined)
|
|
120
|
+
return unavailable(c);
|
|
121
|
+
const result = deps.runner.edit(c.req.valid("param").id, await jsonBody(c));
|
|
122
|
+
return result.ok ? c.json(result.value, 202) : designRefused(c, result);
|
|
123
|
+
})
|
|
124
|
+
.post("/:id/artwork", zValidator("param", idParam, onInvalid), async (c) => {
|
|
125
|
+
if (deps === undefined)
|
|
126
|
+
return unavailable(c);
|
|
127
|
+
const result = deps.runner.artwork(c.req.valid("param").id, await jsonBody(c));
|
|
128
|
+
return result.ok ? c.json(result.value, 202) : designRefused(c, result);
|
|
129
|
+
})
|
|
130
|
+
.post("/:id/steps/:stepId/retry", zValidator("param", stepParam, onInvalid), async (c) => {
|
|
131
|
+
if (deps === undefined)
|
|
132
|
+
return unavailable(c);
|
|
133
|
+
const { id, stepId } = c.req.valid("param");
|
|
134
|
+
const result = deps.runner.retry(id, stepId, await jsonBody(c));
|
|
135
|
+
return result.ok ? c.json(result.value, 202) : designRefused(c, result);
|
|
136
|
+
})
|
|
137
|
+
.put("/:id/head", zValidator("param", idParam, onInvalid), async (c) => {
|
|
138
|
+
if (deps === undefined)
|
|
139
|
+
return unavailable(c);
|
|
140
|
+
const result = setDesignHead(deps.service, c.req.valid("param").id, await jsonBody(c));
|
|
141
|
+
return result.ok ? c.json(result.value) : designRefused(c, result);
|
|
142
|
+
})
|
|
143
|
+
// A version never changes, so the browser may keep it.
|
|
144
|
+
.get("/:id/steps/:stepId/picture", zValidator("param", stepParam, onInvalid), (c) => {
|
|
145
|
+
if (deps === undefined)
|
|
146
|
+
return unavailable(c);
|
|
147
|
+
const { id, stepId } = c.req.valid("param");
|
|
148
|
+
const picture = stepPicture(deps.service.db, id, stepId);
|
|
149
|
+
if (picture === undefined)
|
|
150
|
+
return designRefused(c, {
|
|
151
|
+
reason: "not-found",
|
|
152
|
+
message: "That version has no picture. Reload the design to see its versions.",
|
|
153
|
+
});
|
|
154
|
+
return c.body(new Uint8Array(picture.bytes), 200, {
|
|
155
|
+
"Content-Type": picture.mime,
|
|
156
|
+
"Cache-Control": "private, max-age=31536000, immutable",
|
|
157
|
+
"X-Content-Type-Options": "nosniff",
|
|
158
|
+
});
|
|
159
|
+
})
|
|
160
|
+
// Drawn on demand in a child ffmpeg (and the PDF worker), then served from the cache.
|
|
161
|
+
.get("/:id/files/:file", zValidator("param", fileParam, onInvalid), async (c) => {
|
|
162
|
+
if (deps === undefined)
|
|
163
|
+
return unavailable(c);
|
|
164
|
+
const { id, file } = c.req.valid("param");
|
|
165
|
+
const format = z.enum(designFormats).parse(file.slice(0, file.lastIndexOf(".")));
|
|
166
|
+
const type = file.endsWith(".pdf") ? "pdf" : "png";
|
|
167
|
+
const result = await deps.renderer.render(id, format, type, c.req.raw.signal);
|
|
168
|
+
if (!result.ok)
|
|
169
|
+
return designRefused(c, result);
|
|
170
|
+
const bytes = await readFile(result.value.path);
|
|
171
|
+
return c.body(new Uint8Array(bytes), 200, {
|
|
172
|
+
"Content-Type": result.value.mime,
|
|
173
|
+
"Content-Disposition": `attachment; filename="${result.value.name.replace(/[^\x20-\x7e]|["\\]/g, "_")}"; filename*=UTF-8''${encodeURIComponent(result.value.name)}`,
|
|
174
|
+
"Cache-Control": "no-store",
|
|
175
|
+
"X-Content-Type-Options": "nosniff",
|
|
176
|
+
});
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import { providerStatuses } from "../../slices/settings/readiness.js";
|
|
3
|
+
import { notTemplateSample } from "../../slices/template-studio/repo.js";
|
|
3
4
|
/**
|
|
4
5
|
* A deliberately boring, secret-free support bundle. It is JSON rather than a
|
|
5
6
|
* filesystem archive so it can be copied from a remote/local browser and is
|
|
@@ -13,7 +14,10 @@ export function diagnosticsRoutes(deps) {
|
|
|
13
14
|
hostCliStatus: deps.hostCliStatus,
|
|
14
15
|
host: deps.speechHost,
|
|
15
16
|
});
|
|
16
|
-
|
|
17
|
+
// The template studio's hidden samples are no projects of the person's.
|
|
18
|
+
const projectCount = deps.db
|
|
19
|
+
.prepare(`SELECT count(*) AS count FROM projects WHERE ${notTemplateSample()}`)
|
|
20
|
+
.get();
|
|
17
21
|
const schema = deps.db.prepare("SELECT max(version) AS version FROM schema_migrations").get();
|
|
18
22
|
c.header("Cache-Control", "no-store");
|
|
19
23
|
c.header("Content-Disposition", 'attachment; filename="slopify-diagnostics.json"');
|
|
@@ -6,14 +6,8 @@ import { documentThemeLabels, documentThemes } from "../../slices/document/model
|
|
|
6
6
|
import { renderSampleDocument } from "../../slices/document/sample.js";
|
|
7
7
|
import { builtInTheme, resolveTheme } from "../../slices/document/theme.js";
|
|
8
8
|
import { documentThemeSchema } from "../../slices/document/theme-schema.js";
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
id: z
|
|
12
|
-
.string()
|
|
13
|
-
.min(1)
|
|
14
|
-
.max(64)
|
|
15
|
-
.regex(/^[0-9A-Za-z_-]+$/),
|
|
16
|
-
});
|
|
9
|
+
import { idParam } from "./ids.js";
|
|
10
|
+
import { onInvalid, problem } from "./problem.js";
|
|
17
11
|
// Shape only: the values' ranges are the slice's, so the editor gets field-by-field sentences.
|
|
18
12
|
const themeBody = z.object({ name: z.string(), values: z.unknown() });
|
|
19
13
|
// Library → Documents. The return type is inferred so Hono keeps the route types the SPA's
|
|
@@ -57,7 +51,6 @@ function refused(c, failure) {
|
|
|
57
51
|
case "invalid":
|
|
58
52
|
return problem(c, {
|
|
59
53
|
status: 400,
|
|
60
|
-
title: titleOf(400),
|
|
61
54
|
detail: "This theme can't be saved yet. Fix the highlighted settings and try again.",
|
|
62
55
|
extensions: { fields: failure.fields },
|
|
63
56
|
});
|
|
@@ -65,7 +58,6 @@ function refused(c, failure) {
|
|
|
65
58
|
const message = "Another PDF theme already has this name. Choose a different name.";
|
|
66
59
|
return problem(c, {
|
|
67
60
|
status: 409,
|
|
68
|
-
title: titleOf(409),
|
|
69
61
|
detail: message,
|
|
70
62
|
extensions: { fields: [{ field: "name", message }] },
|
|
71
63
|
});
|
|
@@ -73,7 +65,6 @@ function refused(c, failure) {
|
|
|
73
65
|
case "not-found":
|
|
74
66
|
return problem(c, {
|
|
75
67
|
status: 404,
|
|
76
|
-
title: titleOf(404),
|
|
77
68
|
detail: "This PDF theme no longer exists; it may have been deleted in another tab. Go back to Library → PDF themes.",
|
|
78
69
|
});
|
|
79
70
|
}
|
|
@@ -10,7 +10,7 @@ import { stagedFileById } from "../../slices/storage/repo.js";
|
|
|
10
10
|
import { fileResponse } from "./byte-range.js";
|
|
11
11
|
import { draftProblem } from "./draft-problem.js";
|
|
12
12
|
import { readMultipart } from "./multipart.js";
|
|
13
|
-
import { onInvalid, problem
|
|
13
|
+
import { onInvalid, problem } from "./problem.js";
|
|
14
14
|
const params = z.object({ id: z.uuid(), attachmentId: z.uuid() });
|
|
15
15
|
const imageTypes = {
|
|
16
16
|
".png": "image/png",
|
|
@@ -30,7 +30,6 @@ export function draftFileRoutes(service) {
|
|
|
30
30
|
if (result === undefined)
|
|
31
31
|
return problem(c, {
|
|
32
32
|
status: 400,
|
|
33
|
-
title: titleOf(400),
|
|
34
33
|
detail: "No file arrived with the upload. Choose the file again and retry.",
|
|
35
34
|
});
|
|
36
35
|
return result.ok
|
|
@@ -55,7 +54,6 @@ export function draftFileRoutes(service) {
|
|
|
55
54
|
contentType === undefined)
|
|
56
55
|
return problem(c, {
|
|
57
56
|
status: 404,
|
|
58
|
-
title: titleOf(404),
|
|
59
57
|
detail: "This attached file has not finished uploading, so it cannot be previewed yet. Wait a moment or attach it again.",
|
|
60
58
|
});
|
|
61
59
|
return fileResponse(c, stagingPath(deps.paths, staged.path), staged.bytes, {
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { refusal } from "./refusal.js";
|
|
2
2
|
export function draftProblem(c, result) {
|
|
3
|
-
const status = result.reason === "not-found"
|
|
4
|
-
? 404
|
|
5
|
-
: ["invalid-edit", "readiness"].includes(result.reason)
|
|
6
|
-
? 400
|
|
7
|
-
: 409;
|
|
8
3
|
const { ok: _ok, ...extensions } = result;
|
|
9
4
|
const details = {
|
|
10
5
|
"not-found": "This draft no longer exists; it may have been started or deleted. Reload the page to start a new one.",
|
|
@@ -16,9 +11,9 @@ export function draftProblem(c, result) {
|
|
|
16
11
|
"stale-review": "Something changed since you reviewed this video, such as a setting or a price. Choose Review and start again to see the latest.",
|
|
17
12
|
readiness: "Slopify is not ready to start this video yet. Fix the highlighted problems, then try again.",
|
|
18
13
|
};
|
|
19
|
-
return
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
return refusal(c, result.reason, {
|
|
15
|
+
statuses: { "not-found": 404, "invalid-edit": 400, readiness: 400 },
|
|
16
|
+
otherwise: 409,
|
|
22
17
|
detail: details[result.reason],
|
|
23
18
|
extensions,
|
|
24
19
|
});
|