@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
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { zValidator } from "@hono/zod-validator";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { projectById } from "../../slices/admission/repo.js";
|
|
5
|
+
import { webhookBody } from "../../slices/notifications/address.js";
|
|
6
|
+
import { sendFailureText } from "../../slices/notifications/send.js";
|
|
7
|
+
import { readNotificationUrl } from "../../slices/notifications/settings.js";
|
|
8
|
+
import { waitsForRelease } from "../../slices/social/due.js";
|
|
9
|
+
import { postingExtension, writeExtensionSites } from "../../slices/social/extension.js";
|
|
10
|
+
import { platformLabels } from "../../slices/social/model.js";
|
|
11
|
+
import { postReadyNotice } from "../../slices/social/notice.js";
|
|
12
|
+
import { packFor, postPacks } from "../../slices/social/pack.js";
|
|
13
|
+
import { readPost, writeChoice, writeReddit, writeTextEdit } from "../../slices/social/repo.js";
|
|
14
|
+
import { choiceBody, linkBody, platformSchema, redditBody, resultBody, textBody, } from "../../slices/social/schema.js";
|
|
15
|
+
import { serveMedia } from "../../slices/social/serve.js";
|
|
16
|
+
import { duePosts, fillPost, linksToFind, nextPost, notPostingSentence, reportPost, setPostLink, } from "../../slices/social/service.js";
|
|
17
|
+
import { fileResponse } from "./byte-range.js";
|
|
18
|
+
import { extensionAuth } from "./extension-auth.js";
|
|
19
|
+
import { idString } from "./ids.js";
|
|
20
|
+
import { onInvalid, problem } from "./problem.js";
|
|
21
|
+
import { fromSlopifyPage } from "./same-page.js";
|
|
22
|
+
const projectParam = z.object({ projectId: idString });
|
|
23
|
+
const postParam = projectParam.extend({ platform: platformSchema });
|
|
24
|
+
const fileParam = projectParam.extend({
|
|
25
|
+
file: z
|
|
26
|
+
.string()
|
|
27
|
+
.min(1)
|
|
28
|
+
.max(200)
|
|
29
|
+
.regex(/^[A-Za-z0-9_-]+$/),
|
|
30
|
+
});
|
|
31
|
+
const nextQuery = z.object({
|
|
32
|
+
platform: platformSchema,
|
|
33
|
+
projectId: z.string().min(1).max(200).optional(),
|
|
34
|
+
});
|
|
35
|
+
const dueQuery = z.object({ hours: z.coerce.number().int().min(1).max(48).optional() });
|
|
36
|
+
const sitesBody = z.object({ sites: z.array(platformSchema).max(6) });
|
|
37
|
+
export function socialRoutes(deps) {
|
|
38
|
+
const { allowOrigin, allowed, refused } = extensionAuth(deps.db);
|
|
39
|
+
const media = {
|
|
40
|
+
db: deps.db,
|
|
41
|
+
paths: deps.paths,
|
|
42
|
+
reshaper: deps.social?.reshaper,
|
|
43
|
+
...(deps.designs === undefined
|
|
44
|
+
? {}
|
|
45
|
+
: {
|
|
46
|
+
renderDesign: async (designId, format, signal) => {
|
|
47
|
+
const drawn = await deps.designs?.renderer.render(designId, format, "png", signal);
|
|
48
|
+
return drawn?.ok === true
|
|
49
|
+
? { ok: true, path: drawn.value.path }
|
|
50
|
+
: {
|
|
51
|
+
ok: false,
|
|
52
|
+
sentence: drawn?.message ??
|
|
53
|
+
"The design couldn't be drawn. Open it in Library → Designs to check it, then reload Prepare upload.",
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
}),
|
|
57
|
+
};
|
|
58
|
+
const samePage = (c) => fromSlopifyPage(c, deps.remoteAccess?.remoteHost)
|
|
59
|
+
? undefined
|
|
60
|
+
: problem(c, {
|
|
61
|
+
status: 403,
|
|
62
|
+
detail: "For your safety, a project's posts can only be changed from the Slopify page itself. Open Slopify and try again there.",
|
|
63
|
+
});
|
|
64
|
+
const answer = (c, projectId) => {
|
|
65
|
+
const result = postPacks(deps, projectId, deps.clock.now());
|
|
66
|
+
if (!result.ok)
|
|
67
|
+
return unknownProject(c);
|
|
68
|
+
const body = {
|
|
69
|
+
...result.packs,
|
|
70
|
+
extension: postingExtension(deps.db),
|
|
71
|
+
};
|
|
72
|
+
return c.json(body);
|
|
73
|
+
};
|
|
74
|
+
const refusal = (c, refused) => problem(c, { status: refused.status, detail: refused.sentence });
|
|
75
|
+
const posting = (c, projectId, platform) => packFor(deps, projectId, platform, deps.clock.now()) === undefined
|
|
76
|
+
? problem(c, {
|
|
77
|
+
status: 404,
|
|
78
|
+
detail: notPostingSentence(platform),
|
|
79
|
+
})
|
|
80
|
+
: undefined;
|
|
81
|
+
// A post filled at its release time tells the Notification URL, when one is set. Never
|
|
82
|
+
// awaited: the extension's report doesn't wait on it.
|
|
83
|
+
const notify = (text, projectId) => {
|
|
84
|
+
const url = readNotificationUrl(deps.db);
|
|
85
|
+
const send = deps.sendNotification;
|
|
86
|
+
if (url === null || send === undefined)
|
|
87
|
+
return;
|
|
88
|
+
void send(url, webhookBody(text)).then((sent) => {
|
|
89
|
+
if (!sent.ok)
|
|
90
|
+
deps.log.write("warn", "social.notify", { projectId, detail: sendFailureText(sent) });
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
const changed = (projectId) => deps.hub.emit(projectId, { type: "project.updated", projectId });
|
|
94
|
+
return (new Hono()
|
|
95
|
+
.get("/packs/:projectId", zValidator("param", projectParam, onInvalid), (c) => answer(c, c.req.valid("param").projectId))
|
|
96
|
+
// The project's own pick for one site: other settings, not posting there ({off: true}),
|
|
97
|
+
// or back to the template's (null).
|
|
98
|
+
.put("/packs/:projectId/:platform/choice", zValidator("param", postParam, onInvalid), zValidator("json", choiceBody, onInvalid), (c) => {
|
|
99
|
+
const denied = samePage(c);
|
|
100
|
+
if (denied !== undefined)
|
|
101
|
+
return denied;
|
|
102
|
+
const { projectId, platform } = c.req.valid("param");
|
|
103
|
+
if (postPacks(deps, projectId, deps.clock.now()).ok === false)
|
|
104
|
+
return unknownProject(c);
|
|
105
|
+
const { choice } = c.req.valid("json");
|
|
106
|
+
const config = projectById(deps.db, projectId)?.config.social?.[platform];
|
|
107
|
+
if (choice !== null &&
|
|
108
|
+
!("off" in choice) &&
|
|
109
|
+
choice.text === "prompt" &&
|
|
110
|
+
config?.text !== "prompt")
|
|
111
|
+
return problem(c, {
|
|
112
|
+
status: 409,
|
|
113
|
+
detail: `A post written by a post prompt is a paid step, so it is picked in the template, in Template Studio → Upload pack, where Save shows its cost. For this project, pick a free text source in Prepare upload → ${platformLabels[platform]} → Settings.`,
|
|
114
|
+
});
|
|
115
|
+
writeChoice(deps.db, { projectId, platform }, choice, deps.clock.now());
|
|
116
|
+
changed(projectId);
|
|
117
|
+
return answer(c, projectId);
|
|
118
|
+
})
|
|
119
|
+
.put("/packs/:projectId/:platform/text", zValidator("param", postParam, onInvalid), zValidator("json", textBody, onInvalid), (c) => {
|
|
120
|
+
const denied = samePage(c);
|
|
121
|
+
if (denied !== undefined)
|
|
122
|
+
return denied;
|
|
123
|
+
const { projectId, platform } = c.req.valid("param");
|
|
124
|
+
const missing = posting(c, projectId, platform);
|
|
125
|
+
if (missing !== undefined)
|
|
126
|
+
return missing;
|
|
127
|
+
writeTextEdit(deps.db, { projectId, platform }, c.req.valid("json"), deps.clock.now());
|
|
128
|
+
changed(projectId);
|
|
129
|
+
return answer(c, projectId);
|
|
130
|
+
})
|
|
131
|
+
.delete("/packs/:projectId/:platform/text", zValidator("param", postParam, onInvalid), (c) => {
|
|
132
|
+
const denied = samePage(c);
|
|
133
|
+
if (denied !== undefined)
|
|
134
|
+
return denied;
|
|
135
|
+
const { projectId, platform } = c.req.valid("param");
|
|
136
|
+
const missing = posting(c, projectId, platform);
|
|
137
|
+
if (missing !== undefined)
|
|
138
|
+
return missing;
|
|
139
|
+
writeTextEdit(deps.db, { projectId, platform }, null, deps.clock.now());
|
|
140
|
+
changed(projectId);
|
|
141
|
+
return answer(c, projectId);
|
|
142
|
+
})
|
|
143
|
+
.put("/packs/:projectId/:platform/reddit", zValidator("param", postParam, onInvalid), zValidator("json", redditBody, onInvalid), (c) => {
|
|
144
|
+
const denied = samePage(c);
|
|
145
|
+
if (denied !== undefined)
|
|
146
|
+
return denied;
|
|
147
|
+
const { projectId, platform } = c.req.valid("param");
|
|
148
|
+
if (platform !== "reddit")
|
|
149
|
+
return problem(c, {
|
|
150
|
+
status: 400,
|
|
151
|
+
detail: "Only a Reddit post has a subreddit, title and flair. Open the Reddit post instead.",
|
|
152
|
+
});
|
|
153
|
+
const missing = posting(c, projectId, platform);
|
|
154
|
+
if (missing !== undefined)
|
|
155
|
+
return missing;
|
|
156
|
+
writeReddit(deps.db, { projectId, platform }, c.req.valid("json").reddit, deps.clock.now());
|
|
157
|
+
changed(projectId);
|
|
158
|
+
return answer(c, projectId);
|
|
159
|
+
})
|
|
160
|
+
// The post's link, pasted by the person (posted by hand, or the extension missed it); null
|
|
161
|
+
// removes it, so the post can be filled again.
|
|
162
|
+
.put("/packs/:projectId/:platform/link", zValidator("param", postParam, onInvalid), zValidator("json", linkBody, onInvalid), (c) => {
|
|
163
|
+
const denied = samePage(c);
|
|
164
|
+
if (denied !== undefined)
|
|
165
|
+
return denied;
|
|
166
|
+
const { projectId, platform } = c.req.valid("param");
|
|
167
|
+
const result = setPostLink(deps, projectId, platform, c.req.valid("json").url, deps.clock.now());
|
|
168
|
+
if (!result.ok)
|
|
169
|
+
return refusal(c, result);
|
|
170
|
+
changed(projectId);
|
|
171
|
+
return answer(c, projectId);
|
|
172
|
+
})
|
|
173
|
+
// Fill in <site>: never offered to agents or the assistant (`excluded-routes.ts`).
|
|
174
|
+
.post("/packs/:projectId/:platform/fill", zValidator("param", postParam, onInvalid), (c) => {
|
|
175
|
+
const denied = samePage(c);
|
|
176
|
+
if (denied !== undefined)
|
|
177
|
+
return denied;
|
|
178
|
+
const { projectId, platform } = c.req.valid("param");
|
|
179
|
+
const result = fillPost(deps, projectId, platform, deps.clock.now());
|
|
180
|
+
if (!result.ok)
|
|
181
|
+
return refusal(c, result);
|
|
182
|
+
changed(projectId);
|
|
183
|
+
return c.json({
|
|
184
|
+
pack: result.pack,
|
|
185
|
+
waitsForRelease: result.waitsForRelease,
|
|
186
|
+
url: result.pack.composeUrl,
|
|
187
|
+
});
|
|
188
|
+
})
|
|
189
|
+
.get("/media/:projectId/:file", zValidator("param", fileParam, onInvalid), async (c) => {
|
|
190
|
+
const { projectId, file } = c.req.valid("param");
|
|
191
|
+
return served(c, await serveMedia(media, projectId, file, deps.clock.now(), c.req.raw.signal));
|
|
192
|
+
})
|
|
193
|
+
// The extension's routes.
|
|
194
|
+
.options("/ext/*", (c) => {
|
|
195
|
+
allowOrigin(c, false);
|
|
196
|
+
return c.body(null, 204);
|
|
197
|
+
})
|
|
198
|
+
.get("/ext/next", zValidator("query", nextQuery, onInvalid), (c) => {
|
|
199
|
+
allowOrigin(c, false);
|
|
200
|
+
if (!allowed(c))
|
|
201
|
+
return refused(c);
|
|
202
|
+
const { platform, projectId } = c.req.valid("query");
|
|
203
|
+
const next = nextPost(deps, platform, deps.clock.now(), projectId);
|
|
204
|
+
if (next === undefined)
|
|
205
|
+
return problem(c, {
|
|
206
|
+
status: 404,
|
|
207
|
+
detail: "Nothing is waiting to be filled on this site. In Slopify, open the project, press Prepare upload, then Fill in the site's post.",
|
|
208
|
+
});
|
|
209
|
+
changed(next.pack.projectId);
|
|
210
|
+
return c.json(next);
|
|
211
|
+
})
|
|
212
|
+
.get("/ext/packs/:projectId/:platform", zValidator("param", postParam, onInvalid), (c) => {
|
|
213
|
+
allowOrigin(c, false);
|
|
214
|
+
if (!allowed(c))
|
|
215
|
+
return refused(c);
|
|
216
|
+
const { projectId, platform } = c.req.valid("param");
|
|
217
|
+
const pack = packFor(deps, projectId, platform, deps.clock.now());
|
|
218
|
+
return pack === undefined ? unknownPost(c) : c.json(pack);
|
|
219
|
+
})
|
|
220
|
+
.get("/ext/files/:projectId/:file", zValidator("param", fileParam, onInvalid), async (c) => {
|
|
221
|
+
allowOrigin(c, false);
|
|
222
|
+
if (!allowed(c))
|
|
223
|
+
return refused(c);
|
|
224
|
+
const { projectId, file } = c.req.valid("param");
|
|
225
|
+
return served(c, await serveMedia(media, projectId, file, deps.clock.now(), c.req.raw.signal));
|
|
226
|
+
})
|
|
227
|
+
.get("/ext/due", zValidator("query", dueQuery, onInvalid), (c) => {
|
|
228
|
+
allowOrigin(c, false);
|
|
229
|
+
if (!allowed(c))
|
|
230
|
+
return refused(c);
|
|
231
|
+
const hours = c.req.valid("query").hours ?? 24;
|
|
232
|
+
return c.json({ posts: duePosts(deps, deps.clock.now(), hours * 3_600_000) });
|
|
233
|
+
})
|
|
234
|
+
.post("/ext/result", zValidator("json", resultBody, onInvalid), (c) => {
|
|
235
|
+
allowOrigin(c, false);
|
|
236
|
+
if (!allowed(c))
|
|
237
|
+
return refused(c);
|
|
238
|
+
const body = c.req.valid("json");
|
|
239
|
+
const result = reportPost(deps, body, deps.clock.now());
|
|
240
|
+
if (!result.ok)
|
|
241
|
+
return refusal(c, result);
|
|
242
|
+
changed(body.projectId);
|
|
243
|
+
if (body.state === "filled" && waitsForRelease(body.platform) && result.pack !== undefined)
|
|
244
|
+
notify(postReadyNotice(result.pack), body.projectId);
|
|
245
|
+
return c.json({ status: readPost(deps.db, body).state });
|
|
246
|
+
})
|
|
247
|
+
.get("/ext/find-links", (c) => {
|
|
248
|
+
allowOrigin(c, false);
|
|
249
|
+
if (!allowed(c))
|
|
250
|
+
return refused(c);
|
|
251
|
+
return c.json({ posts: linksToFind(deps, deps.clock.now()) });
|
|
252
|
+
})
|
|
253
|
+
// Which sites the extension may post on, as its options last granted them.
|
|
254
|
+
.post("/ext/sites", zValidator("json", sitesBody, onInvalid), (c) => {
|
|
255
|
+
allowOrigin(c, false);
|
|
256
|
+
if (!allowed(c))
|
|
257
|
+
return refused(c);
|
|
258
|
+
writeExtensionSites(deps.db, c.req.valid("json").sites, deps.clock.now());
|
|
259
|
+
return c.json(postingExtension(deps.db));
|
|
260
|
+
}));
|
|
261
|
+
}
|
|
262
|
+
function served(c, result) {
|
|
263
|
+
if (!result.ok)
|
|
264
|
+
return problem(c, { status: result.status, detail: result.sentence });
|
|
265
|
+
return fileResponse(c, result.path, result.bytes, {
|
|
266
|
+
"content-type": result.contentType,
|
|
267
|
+
"content-disposition": `inline; filename="${result.filename.replace(/["\\]/g, "")}"`,
|
|
268
|
+
"x-content-type-options": "nosniff",
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
function unknownProject(c) {
|
|
272
|
+
return problem(c, {
|
|
273
|
+
status: 404,
|
|
274
|
+
detail: "This project no longer exists. Go back to Projects and open it again.",
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function unknownPost(c) {
|
|
278
|
+
return problem(c, {
|
|
279
|
+
status: 404,
|
|
280
|
+
detail: "That project no longer posts to this site. In Slopify, open the project's Prepare upload and press Fill again.",
|
|
281
|
+
});
|
|
282
|
+
}
|
|
@@ -5,7 +5,7 @@ import { uploadableStageKinds } from "../../slices/storage/model.js";
|
|
|
5
5
|
import { stagedFiles } from "../../slices/storage/repo.js";
|
|
6
6
|
import { discardStagedFile, stageUpload } from "../../slices/storage/staging.js";
|
|
7
7
|
import { readMultipart } from "./multipart.js";
|
|
8
|
-
import { onInvalid, problem
|
|
8
|
+
import { onInvalid, problem } from "./problem.js";
|
|
9
9
|
const kindParam = z.object({ kind: z.enum(uploadableStageKinds) });
|
|
10
10
|
const idParam = z.object({ id: z.string().min(1).max(64) });
|
|
11
11
|
// The return type is inferred on purpose: annotating it would erase the route types the
|
|
@@ -33,12 +33,11 @@ export function stagingRoutes(deps) {
|
|
|
33
33
|
if (result === undefined) {
|
|
34
34
|
return problem(c, {
|
|
35
35
|
status: 400,
|
|
36
|
-
title: titleOf(400),
|
|
37
36
|
detail: "No file arrived with the upload. Choose the file again and retry.",
|
|
38
37
|
});
|
|
39
38
|
}
|
|
40
39
|
if (!result.ok) {
|
|
41
|
-
return problem(c, { status: 400,
|
|
40
|
+
return problem(c, { status: 400, detail: detailOf(result.reason) });
|
|
42
41
|
}
|
|
43
42
|
return c.json(result.file, 201);
|
|
44
43
|
})
|
|
@@ -47,7 +46,6 @@ export function stagingRoutes(deps) {
|
|
|
47
46
|
if (!result.ok) {
|
|
48
47
|
return problem(c, {
|
|
49
48
|
status: result.reason === "in-use" ? 409 : 404,
|
|
50
|
-
title: titleOf(result.reason === "in-use" ? 409 : 404),
|
|
51
49
|
detail: result.reason === "in-use"
|
|
52
50
|
? "This file is still attached to a draft in Play. Remove it from the draft first."
|
|
53
51
|
: "This uploaded file no longer exists; it may have been removed already. Reload the page.",
|
|
@@ -2,7 +2,9 @@ import { zValidator } from "@hono/zod-validator";
|
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { HTTPException } from "hono/http-exception";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { onInvalid, problem
|
|
5
|
+
import { onInvalid, problem } from "./problem.js";
|
|
6
|
+
import { fromSlopifyPage } from "./same-page.js";
|
|
7
|
+
export const moveFilesBody = z.object({ target: z.string().min(1).max(4096) }).strict();
|
|
6
8
|
// Settings → Backup & storage → Your files: where projects and backups are, Open folder, and
|
|
7
9
|
// moving them. A move copies and checks every file, so it answers at once and the screen polls.
|
|
8
10
|
export function filesRoutes(deps) {
|
|
@@ -16,23 +18,20 @@ export function filesRoutes(deps) {
|
|
|
16
18
|
c.header("Cache-Control", "no-store");
|
|
17
19
|
return c.json(await files().view());
|
|
18
20
|
})
|
|
19
|
-
.post("/move", zValidator("json",
|
|
21
|
+
.post("/move", zValidator("json", moveFilesBody, onInvalid), async (c) => {
|
|
20
22
|
const started = await files().move(c.req.valid("json").target);
|
|
21
23
|
if (!started.ok)
|
|
22
24
|
return problem(c, {
|
|
23
25
|
status: started.status,
|
|
24
|
-
title: titleOf(started.status),
|
|
25
26
|
detail: started.detail,
|
|
26
27
|
extensions: { field: "target" },
|
|
27
28
|
});
|
|
28
29
|
return c.json(await files().view(), 202);
|
|
29
30
|
})
|
|
30
31
|
.post("/open", async (c) => {
|
|
31
|
-
|
|
32
|
-
if (origin !== undefined && origin !== new URL(c.req.url).origin)
|
|
32
|
+
if (!fromSlopifyPage(c, deps.remoteAccess?.remoteHost))
|
|
33
33
|
return problem(c, {
|
|
34
34
|
status: 403,
|
|
35
|
-
title: titleOf(403),
|
|
36
35
|
detail: "For your safety, folders can only be opened from the Slopify page itself. Open Slopify and try again there.",
|
|
37
36
|
});
|
|
38
37
|
try {
|
|
@@ -42,7 +41,6 @@ export function filesRoutes(deps) {
|
|
|
42
41
|
deps.log.write("warn", "storage.open-files", { detail: String(error) });
|
|
43
42
|
return problem(c, {
|
|
44
43
|
status: 503,
|
|
45
|
-
title: titleOf(503),
|
|
46
44
|
detail: "Slopify could not open a file manager window on the computer it runs on. Make sure you are signed in to that computer's desktop, or open the folder shown in Settings → Backup & storage yourself.",
|
|
47
45
|
});
|
|
48
46
|
}
|
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import { zValidator } from "@hono/zod-validator";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
|
-
import { z } from "zod";
|
|
4
3
|
import { projectExists } from "../../slices/admission/repo.js";
|
|
5
4
|
import { BackupBusyError, planBackup, streamBackup, } from "../../slices/storage/backup-export.js";
|
|
6
5
|
import { BackupImportRefused, importBackup } from "../../slices/storage/backup-import.js";
|
|
7
6
|
import { importPortable, portableMaxArchiveBytes, storageUsage, } from "../../slices/storage/portable.js";
|
|
8
7
|
import { reconcileStorage } from "../../slices/storage/reconcile.js";
|
|
9
8
|
import { cleanUpAll, deleteAllOldVersions, deleteOldVersions, keepOutputsOnly, projectStorage, } from "../../slices/storage/trim.js";
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.string()
|
|
14
|
-
.min(1)
|
|
15
|
-
.max(64)
|
|
16
|
-
.regex(/^[0-9A-Za-z_-]+$/),
|
|
17
|
-
});
|
|
9
|
+
import { sampleOwner } from "../../slices/template-studio/repo.js";
|
|
10
|
+
import { idParam } from "./ids.js";
|
|
11
|
+
import { onInvalid, problem } from "./problem.js";
|
|
18
12
|
const exportFailed = "Slopify could not create the backup. Check there is free disk space and try again; if it keeps failing, use Download diagnostics in Settings and report it.";
|
|
19
13
|
export function storageRoutes(deps) {
|
|
20
14
|
const backup = () => ({
|
|
@@ -25,6 +19,17 @@ export function storageRoutes(deps) {
|
|
|
25
19
|
appVersion: deps.version,
|
|
26
20
|
hasInflight: deps.runner.hasInflight,
|
|
27
21
|
});
|
|
22
|
+
// A template's studio sample keeps its files for the studio's bake-offs and resamples.
|
|
23
|
+
const studioSample = (id) => {
|
|
24
|
+
const owner = sampleOwner(deps.db, id);
|
|
25
|
+
return owner === undefined
|
|
26
|
+
? undefined
|
|
27
|
+
: {
|
|
28
|
+
status: 409,
|
|
29
|
+
detail: `This is the studio sample of ${owner.name}, and the studio keeps its files to make its samples again without paying twice. Change it in its studio instead: Library → Templates → ${owner.name} → Open studio.`,
|
|
30
|
+
extensions: { reason: "template-sample" },
|
|
31
|
+
};
|
|
32
|
+
};
|
|
28
33
|
return (new Hono()
|
|
29
34
|
.get("/", (c) => c.json(storageUsage({ db: deps.db, paths: deps.paths, hasInflight: deps.runner.hasInflight })))
|
|
30
35
|
// One project's split between outputs and working files, and what Keep outputs only
|
|
@@ -34,7 +39,6 @@ export function storageRoutes(deps) {
|
|
|
34
39
|
if (!projectExists(deps.db, id))
|
|
35
40
|
return problem(c, {
|
|
36
41
|
status: 404,
|
|
37
|
-
title: titleOf(404),
|
|
38
42
|
detail: "This project no longer exists. Go back to Projects to pick another.",
|
|
39
43
|
});
|
|
40
44
|
c.header("Cache-Control", "no-store");
|
|
@@ -42,35 +46,37 @@ export function storageRoutes(deps) {
|
|
|
42
46
|
})
|
|
43
47
|
// Keep outputs only: a finished project drops its working files (`slices/storage/trim.ts`).
|
|
44
48
|
.post("/projects/:id/keep-outputs", zValidator("param", idParam, onInvalid), (c) => {
|
|
49
|
+
const refused = studioSample(c.req.valid("param").id);
|
|
50
|
+
if (refused !== undefined)
|
|
51
|
+
return problem(c, refused);
|
|
45
52
|
const result = keepOutputsOnly({ db: deps.db, paths: deps.paths, hasInflight: deps.runner.hasInflight }, c.req.valid("param").id);
|
|
46
53
|
if (result.ok)
|
|
47
54
|
return c.json(result);
|
|
48
55
|
return result.reason === "no-project"
|
|
49
56
|
? problem(c, {
|
|
50
57
|
status: 404,
|
|
51
|
-
title: titleOf(404),
|
|
52
58
|
detail: "This project no longer exists. Reload Settings → Storage to see the current list.",
|
|
53
59
|
})
|
|
54
60
|
: problem(c, {
|
|
55
61
|
status: 409,
|
|
56
|
-
title: titleOf(409),
|
|
57
62
|
detail: "Only a finished project can drop its working files, and this one is running, waiting or has unfinished steps. Let it finish (or cancel it on its project page), then drop the working files again from the project page or Settings → Storage.",
|
|
58
63
|
});
|
|
59
64
|
})
|
|
60
65
|
// Delete old versions: one project's History files (`slices/storage/trim.ts`).
|
|
61
66
|
.post("/projects/:id/old-versions/delete", zValidator("param", idParam, onInvalid), (c) => {
|
|
67
|
+
const refused = studioSample(c.req.valid("param").id);
|
|
68
|
+
if (refused !== undefined)
|
|
69
|
+
return problem(c, refused);
|
|
62
70
|
const result = deleteOldVersions({ db: deps.db, paths: deps.paths, hasInflight: deps.runner.hasInflight }, c.req.valid("param").id);
|
|
63
71
|
if (result.ok)
|
|
64
72
|
return c.json(result);
|
|
65
73
|
return result.reason === "no-project"
|
|
66
74
|
? problem(c, {
|
|
67
75
|
status: 404,
|
|
68
|
-
title: titleOf(404),
|
|
69
76
|
detail: "This project no longer exists. Reload Settings → Backup & storage to see the current list.",
|
|
70
77
|
})
|
|
71
78
|
: problem(c, {
|
|
72
79
|
status: 409,
|
|
73
|
-
title: titleOf(409),
|
|
74
80
|
detail: "This project is running or has steps waiting to run, and its files stay where they are until then. Let it finish, or cancel its run on its project page, then press Delete old versions again.",
|
|
75
81
|
});
|
|
76
82
|
})
|
|
@@ -98,7 +104,7 @@ export function storageRoutes(deps) {
|
|
|
98
104
|
if (error instanceof BackupBusyError)
|
|
99
105
|
return c.json({ ready: false, detail: error.message, busy: error.projects });
|
|
100
106
|
deps.log.write("error", "storage.export", { detail: String(error) });
|
|
101
|
-
return problem(c, { status: 500,
|
|
107
|
+
return problem(c, { status: 500, detail: exportFailed });
|
|
102
108
|
}
|
|
103
109
|
})
|
|
104
110
|
.get("/export", (c) => {
|
|
@@ -108,9 +114,9 @@ export function storageRoutes(deps) {
|
|
|
108
114
|
}
|
|
109
115
|
catch (error) {
|
|
110
116
|
if (error instanceof BackupBusyError)
|
|
111
|
-
return problem(c, { status: 409,
|
|
117
|
+
return problem(c, { status: 409, detail: error.message });
|
|
112
118
|
deps.log.write("error", "storage.export", { detail: String(error) });
|
|
113
|
-
return problem(c, { status: 500,
|
|
119
|
+
return problem(c, { status: 500, detail: exportFailed });
|
|
114
120
|
}
|
|
115
121
|
// Pulled one chunk at a time, so a slow download reads files no faster than it sends.
|
|
116
122
|
const chunks = streamBackup(plan);
|
|
@@ -145,14 +151,12 @@ export function storageRoutes(deps) {
|
|
|
145
151
|
if (!contentType.includes("application/zip"))
|
|
146
152
|
return problem(c, {
|
|
147
153
|
status: 415,
|
|
148
|
-
title: titleOf(415),
|
|
149
154
|
detail: "Choose a Slopify backup file: a .tar made with Export everything, or an older .zip made with Export backup, both in Settings → Backup & storage.",
|
|
150
155
|
});
|
|
151
156
|
const upload = await readPortableUpload(c.req.raw);
|
|
152
157
|
if (!upload.ok)
|
|
153
158
|
return problem(c, {
|
|
154
159
|
status: 413,
|
|
155
|
-
title: titleOf(413),
|
|
156
160
|
detail: "This backup file is empty or larger than 100 MB. Choose a Slopify backup file under 100 MB.",
|
|
157
161
|
});
|
|
158
162
|
try {
|
|
@@ -167,7 +171,6 @@ export function storageRoutes(deps) {
|
|
|
167
171
|
catch {
|
|
168
172
|
return problem(c, {
|
|
169
173
|
status: 400,
|
|
170
|
-
title: titleOf(400),
|
|
171
174
|
detail: "This file is not a complete Slopify backup; it may be damaged or a different kind of ZIP. Choose a backup made with Backup & storage in Settings.",
|
|
172
175
|
});
|
|
173
176
|
}
|
|
@@ -175,7 +178,6 @@ export function storageRoutes(deps) {
|
|
|
175
178
|
if (request.body === null)
|
|
176
179
|
return problem(c, {
|
|
177
180
|
status: 400,
|
|
178
|
-
title: titleOf(400),
|
|
179
181
|
detail: "The backup file arrived empty. Choose the .tar made with Export everything and import it again.",
|
|
180
182
|
});
|
|
181
183
|
const reader = request.body.getReader();
|
|
@@ -186,13 +188,11 @@ export function storageRoutes(deps) {
|
|
|
186
188
|
if (error instanceof BackupImportRefused)
|
|
187
189
|
return problem(c, {
|
|
188
190
|
status: error.status,
|
|
189
|
-
title: titleOf(error.status),
|
|
190
191
|
detail: error.message,
|
|
191
192
|
});
|
|
192
193
|
deps.log.write("error", "storage.import", { detail: String(error) });
|
|
193
194
|
return problem(c, {
|
|
194
195
|
status: 500,
|
|
195
|
-
title: titleOf(500),
|
|
196
196
|
detail: "The backup wasn't imported and nothing in this install changed. Try again; if it keeps failing, use Download diagnostics in Settings and report it.",
|
|
197
197
|
});
|
|
198
198
|
}
|