@gentbajko/slopify 3.25.8 → 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.
Files changed (604) hide show
  1. package/dist/adapters/account-limits.js +30 -0
  2. package/dist/adapters/alignment/cache.js +3 -5
  3. package/dist/adapters/alignment/ctc.js +1 -2
  4. package/dist/adapters/alignment/lock.js +4 -3
  5. package/dist/adapters/alignment/multilingual.js +0 -3
  6. package/dist/adapters/alignment/prefetch.js +2 -1
  7. package/dist/adapters/alignment/worker.js +2 -1
  8. package/dist/adapters/explain.js +0 -3
  9. package/dist/adapters/ffmpeg.js +19 -1
  10. package/dist/adapters/host-cli/index.js +19 -3
  11. package/dist/adapters/http-failure.js +53 -0
  12. package/dist/adapters/image/codex.js +36 -4
  13. package/dist/adapters/image/fal.js +17 -50
  14. package/dist/adapters/image/google.js +31 -55
  15. package/dist/adapters/image/openai.js +20 -47
  16. package/dist/adapters/image/reference.js +36 -0
  17. package/dist/adapters/image/replicate.js +18 -47
  18. package/dist/adapters/interest/search-interest.js +113 -0
  19. package/dist/adapters/key-probes.js +53 -2
  20. package/dist/adapters/llm/antigravity.js +4 -0
  21. package/dist/adapters/llm/assistant-cli.js +388 -0
  22. package/dist/adapters/llm/child-session.js +83 -0
  23. package/dist/adapters/llm/claude-code-models.js +51 -98
  24. package/dist/adapters/llm/claude-code.js +13 -2
  25. package/dist/adapters/llm/codex-limits.js +27 -68
  26. package/dist/adapters/llm/codex-server-models.js +61 -109
  27. package/dist/adapters/llm/codex.js +12 -1
  28. package/dist/adapters/llm/openrouter.js +10 -47
  29. package/dist/adapters/llm/run-cli.js +6 -22
  30. package/dist/adapters/llm/sse-lines.js +5 -1
  31. package/dist/adapters/model-access.js +37 -0
  32. package/dist/adapters/tts/cartesia.js +15 -46
  33. package/dist/adapters/tts/elevenlabs.js +20 -52
  34. package/dist/adapters/tts/gemini.js +19 -40
  35. package/dist/adapters/tts/inworld-async.js +4 -1
  36. package/dist/adapters/tts/inworld.js +3 -0
  37. package/dist/adapters/tts/openai.js +20 -50
  38. package/dist/assets/models-lifecycle.yaml +6 -0
  39. package/dist/assistant-wiring.js +60 -0
  40. package/dist/autopilot-timers.js +59 -0
  41. package/dist/catalog/lifecycle.js +52 -0
  42. package/dist/catalog/propose.js +204 -0
  43. package/dist/catalog/registry.js +3 -1
  44. package/dist/catalog/schema.js +2 -0
  45. package/dist/catalog/store.js +39 -0
  46. package/dist/edge/autostart/native.js +3 -5
  47. package/dist/edge/autostart/prompt.js +2 -1
  48. package/dist/edge/autostart/service.js +3 -4
  49. package/dist/edge/cli-args.js +3 -4
  50. package/dist/edge/cli.js +2 -1
  51. package/dist/edge/docker-install/apply.js +11 -11
  52. package/dist/edge/docker-install/run.js +2 -1
  53. package/dist/edge/docker-install/state.js +4 -3
  54. package/dist/edge/docker-install/tree.js +2 -4
  55. package/dist/edge/docker-install/volume.js +3 -2
  56. package/dist/edge/docker.js +5 -4
  57. package/dist/edge/events/hub.js +5 -5
  58. package/dist/edge/http/actions.js +4 -25
  59. package/dist/edge/http/actor.js +5 -3
  60. package/dist/edge/http/app.js +85 -10
  61. package/dist/edge/http/assistant.js +127 -0
  62. package/dist/edge/http/audio-preview.js +4 -11
  63. package/dist/edge/http/auditions.js +1 -1
  64. package/dist/edge/http/autostart.js +5 -5
  65. package/dist/edge/http/backups.js +1 -3
  66. package/dist/edge/http/channel-memory.js +7 -20
  67. package/dist/edge/http/channels.js +13 -26
  68. package/dist/edge/http/checkpoints.js +33 -17
  69. package/dist/edge/http/design-templates.js +167 -0
  70. package/dist/edge/http/designs.js +178 -0
  71. package/dist/edge/http/diagnostics.js +5 -1
  72. package/dist/edge/http/document-themes.js +2 -11
  73. package/dist/edge/http/draft-files.js +1 -3
  74. package/dist/edge/http/draft-problem.js +4 -9
  75. package/dist/edge/http/drafts.js +3 -3
  76. package/dist/edge/http/entries.js +6 -9
  77. package/dist/edge/http/extension-auth.js +27 -0
  78. package/dist/edge/http/external-reviews.js +12 -11
  79. package/dist/edge/http/files.js +5 -11
  80. package/dist/edge/http/folder-location.js +1 -4
  81. package/dist/edge/http/fonts.js +0 -7
  82. package/dist/edge/http/home.js +38 -13
  83. package/dist/edge/http/host-cli.js +18 -8
  84. package/dist/edge/http/ids.js +8 -0
  85. package/dist/edge/http/keywords.js +35 -0
  86. package/dist/edge/http/model-checks.js +132 -0
  87. package/dist/edge/http/narration-peaks.js +5 -13
  88. package/dist/edge/http/onboarding.js +1 -14
  89. package/dist/edge/http/open-folder.js +5 -10
  90. package/dist/edge/http/outputs.js +4 -12
  91. package/dist/edge/http/patch-notes.js +4 -10
  92. package/dist/edge/http/planning.js +2 -6
  93. package/dist/edge/http/problem.js +2 -4
  94. package/dist/edge/http/project-create.js +1 -0
  95. package/dist/edge/http/project-templates.js +29 -17
  96. package/dist/edge/http/projects.js +2 -12
  97. package/dist/edge/http/prompts.js +7 -14
  98. package/dist/edge/http/pronunciations.js +1 -2
  99. package/dist/edge/http/providers.js +39 -24
  100. package/dist/edge/http/refusal.js +29 -0
  101. package/dist/edge/http/remote-access.js +40 -0
  102. package/dist/edge/http/remote-guard.js +71 -0
  103. package/dist/edge/http/request-guard.js +91 -0
  104. package/dist/edge/http/reviews.js +11 -24
  105. package/dist/edge/http/revision-files.js +5 -10
  106. package/dist/edge/http/revisions.js +10 -15
  107. package/dist/edge/http/run-cost.js +1 -2
  108. package/dist/edge/http/same-page.js +80 -0
  109. package/dist/edge/http/schedules.js +59 -32
  110. package/dist/edge/http/settings.js +22 -13
  111. package/dist/edge/http/social.js +282 -0
  112. package/dist/edge/http/staging.js +2 -4
  113. package/dist/edge/http/storage-files.js +5 -7
  114. package/dist/edge/http/storage.js +23 -23
  115. package/dist/edge/http/studio.js +23 -50
  116. package/dist/edge/http/style-preview.js +1 -4
  117. package/dist/edge/http/subtitles.js +3 -17
  118. package/dist/edge/http/template-studio.js +433 -0
  119. package/dist/edge/http/trash.js +10 -11
  120. package/dist/edge/http/tutorial.js +1 -2
  121. package/dist/edge/http/tutorials.js +5 -11
  122. package/dist/edge/http/update.js +7 -13
  123. package/dist/edge/http/waveform.js +3 -6
  124. package/dist/edge/http/youtube-edits.js +2 -3
  125. package/dist/edge/mcp/assistant.js +279 -0
  126. package/dist/edge/mcp/attribution.js +8 -2
  127. package/dist/edge/mcp/call-route.js +11 -2
  128. package/dist/edge/mcp/excluded-routes.js +25 -0
  129. package/dist/edge/mcp/http.js +11 -2
  130. package/dist/edge/mcp/instructions.js +5 -3
  131. package/dist/edge/mcp/library-tools.js +1 -0
  132. package/dist/edge/mcp/route-tool.js +35 -15
  133. package/dist/edge/mcp/server.js +13 -8
  134. package/dist/edge/mcp/tools-channels.js +2 -0
  135. package/dist/edge/mcp/tools-designs.js +165 -0
  136. package/dist/edge/mcp/tools-library.js +14 -2
  137. package/dist/edge/mcp/tools-planning.js +23 -4
  138. package/dist/edge/mcp/tools-projects.js +28 -1
  139. package/dist/edge/mcp/tools-runs.js +14 -1
  140. package/dist/edge/mcp/tools-schedules.js +28 -4
  141. package/dist/edge/mcp/tools-setup.js +61 -3
  142. package/dist/edge/mcp/tools-social.js +46 -0
  143. package/dist/edge/mcp/tools-storage.js +8 -0
  144. package/dist/edge/mcp/tools-template-studio.js +166 -0
  145. package/dist/edge/mcp/tools.js +6 -0
  146. package/dist/edge/remote-access/cli.js +71 -0
  147. package/dist/edge/remote-access/model.js +32 -0
  148. package/dist/edge/remote-access/rules.js +207 -0
  149. package/dist/edge/remote-access/service.js +203 -0
  150. package/dist/edge/remote-access/store.js +44 -0
  151. package/dist/edge/remote-access/views.js +43 -0
  152. package/dist/extension/slopify-studio-chrome.zip +0 -0
  153. package/dist/extension/slopify-studio-firefox.zip +0 -0
  154. package/dist/host-cli/install.js +2 -2
  155. package/dist/host-cli/open-folder.js +2 -2
  156. package/dist/host-cli/paths.js +2 -4
  157. package/dist/host-cli/server.js +4 -4
  158. package/dist/host-cli/service.js +3 -3
  159. package/dist/host-cli/status.js +7 -7
  160. package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
  161. package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
  162. package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
  163. package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
  164. package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
  165. package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
  166. package/dist/kernel/db/migrations/0070-designs.sql +53 -0
  167. package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
  168. package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
  169. package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
  170. package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
  171. package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
  172. package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
  173. package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
  174. package/dist/kernel/db/tx.js +2 -4
  175. package/dist/kernel/errors.js +27 -1
  176. package/dist/kernel/json-answer.js +15 -0
  177. package/dist/kernel/lock.js +4 -9
  178. package/dist/kernel/paths.js +8 -0
  179. package/dist/kernel/ports/assistant-cli.js +4 -0
  180. package/dist/kernel/ports/host-cli.js +3 -0
  181. package/dist/kernel/ports/interest.js +4 -0
  182. package/dist/kernel/ports/languages.js +0 -3
  183. package/dist/kernel/ports/model.js +2 -0
  184. package/dist/kernel/runner/attempt.js +3 -1
  185. package/dist/kernel/runner/audition.js +3 -1
  186. package/dist/kernel/runner/checkpoint-authority.js +2 -1
  187. package/dist/kernel/runner/index.js +8 -10
  188. package/dist/kernel/runner/model-access.js +40 -0
  189. package/dist/kernel/runner/model-check.js +153 -0
  190. package/dist/kernel/runner/providers.js +15 -10
  191. package/dist/kernel/runner/standalone.js +9 -5
  192. package/dist/main.js +334 -19
  193. package/dist/model-checks.js +166 -0
  194. package/dist/patch-notes/3.25.9.md +5 -0
  195. package/dist/patch-notes/4.0.0.md +51 -0
  196. package/dist/patch-notes/index.json +12 -0
  197. package/dist/slices/admission/heads.js +2 -1
  198. package/dist/slices/admission/repo.js +2 -1
  199. package/dist/slices/admission/rules.js +43 -8
  200. package/dist/slices/admission/schema.js +8 -0
  201. package/dist/slices/admission/stage-writes.js +0 -3
  202. package/dist/slices/admission/start.js +48 -31
  203. package/dist/slices/admission/substitute.js +7 -4
  204. package/dist/slices/agents/attention-posts.js +31 -0
  205. package/dist/slices/agents/attention-templates.js +33 -0
  206. package/dist/slices/agents/attention.js +10 -1
  207. package/dist/slices/agents/connection.js +2 -6
  208. package/dist/slices/agents/model.js +6 -3
  209. package/dist/slices/agents/repo.js +15 -7
  210. package/dist/slices/article/continuation.js +0 -63
  211. package/dist/slices/article/plain.js +3 -2
  212. package/dist/slices/article/segments.js +2 -62
  213. package/dist/slices/assistant/access.js +1 -0
  214. package/dist/slices/assistant/asks.js +80 -0
  215. package/dist/slices/assistant/cost.js +54 -0
  216. package/dist/slices/assistant/gate.js +222 -0
  217. package/dist/slices/assistant/model.js +79 -0
  218. package/dist/slices/assistant/names.js +23 -0
  219. package/dist/slices/assistant/prompt.js +74 -0
  220. package/dist/slices/assistant/repo.js +74 -0
  221. package/dist/slices/assistant/tokens.js +18 -0
  222. package/dist/slices/assistant/turn.js +342 -0
  223. package/dist/slices/autopilot/buffer.js +76 -0
  224. package/dist/slices/autopilot/model.js +14 -0
  225. package/dist/slices/autopilot/notify.js +27 -0
  226. package/dist/slices/autopilot/repo.js +34 -0
  227. package/dist/slices/autopilot/signals.js +194 -0
  228. package/dist/slices/autopilot/warnings.js +85 -0
  229. package/dist/slices/autopilot/weekly.js +100 -0
  230. package/dist/slices/backups/files.js +2 -6
  231. package/dist/slices/backups/repo.js +3 -15
  232. package/dist/slices/backups/service.js +4 -3
  233. package/dist/slices/channels/cast-images.js +2 -1
  234. package/dist/slices/channels/model.js +0 -1
  235. package/dist/slices/channels/rebrand.js +0 -3
  236. package/dist/slices/channels/repo.js +4 -0
  237. package/dist/slices/channels/schema.js +6 -0
  238. package/dist/slices/channels/service.js +10 -0
  239. package/dist/slices/channels/videos.js +2 -14
  240. package/dist/slices/checkpoints/index.js +0 -1
  241. package/dist/slices/control/providers.js +0 -26
  242. package/dist/slices/designs/artwork.js +66 -0
  243. package/dist/slices/designs/budget.js +23 -0
  244. package/dist/slices/designs/calls.js +124 -0
  245. package/dist/slices/designs/check-context.js +38 -0
  246. package/dist/slices/designs/check-text.js +43 -0
  247. package/dist/slices/designs/fields.js +88 -0
  248. package/dist/slices/designs/frames.js +34 -0
  249. package/dist/slices/designs/gate.js +128 -0
  250. package/dist/slices/designs/layout.js +293 -0
  251. package/dist/slices/designs/model.js +35 -0
  252. package/dist/slices/designs/pdf-job.js +23 -0
  253. package/dist/slices/designs/pdf-pages.js +30 -0
  254. package/dist/slices/designs/pdf-runner.js +68 -0
  255. package/dist/slices/designs/pdf-worker.js +24 -0
  256. package/dist/slices/designs/picture-size.js +79 -0
  257. package/dist/slices/designs/pictures.js +55 -0
  258. package/dist/slices/designs/quote.js +24 -0
  259. package/dist/slices/designs/render-args.js +36 -0
  260. package/dist/slices/designs/render-input.js +59 -0
  261. package/dist/slices/designs/render.js +215 -0
  262. package/dist/slices/designs/repo.js +101 -0
  263. package/dist/slices/designs/requests.js +80 -0
  264. package/dist/slices/designs/runner.js +239 -0
  265. package/dist/slices/designs/sample-repo.js +91 -0
  266. package/dist/slices/designs/sample.js +222 -0
  267. package/dist/slices/designs/schema.js +87 -0
  268. package/dist/slices/designs/sections.js +44 -0
  269. package/dist/slices/designs/service.js +233 -0
  270. package/dist/slices/designs/steps-repo.js +102 -0
  271. package/dist/slices/designs/studio-kind.js +39 -0
  272. package/dist/slices/designs/template-checks.js +44 -0
  273. package/dist/slices/designs/template-make.js +118 -0
  274. package/dist/slices/designs/templates.js +218 -0
  275. package/dist/slices/document/fonts.js +2 -1
  276. package/dist/slices/episodes/summarize.js +5 -1
  277. package/dist/slices/estimate/index.js +45 -7
  278. package/dist/slices/fonts/catalog.js +3 -2
  279. package/dist/slices/fonts/discovery.js +3 -2
  280. package/dist/slices/fonts/files.js +2 -6
  281. package/dist/slices/fonts/index.js +0 -1
  282. package/dist/slices/fonts/sfnt.js +45 -10
  283. package/dist/slices/images/appearance.js +6 -15
  284. package/dist/slices/images/scenes.js +100 -27
  285. package/dist/slices/keywords/digest.js +84 -0
  286. package/dist/slices/keywords/facts.js +92 -0
  287. package/dist/slices/keywords/fill.js +80 -0
  288. package/dist/slices/keywords/model.js +75 -0
  289. package/dist/slices/keywords/rules.js +187 -0
  290. package/dist/slices/keywords/schema.js +28 -0
  291. package/dist/slices/keywords/specs.js +260 -0
  292. package/dist/slices/keywords/values.js +74 -0
  293. package/dist/slices/library/lint.js +29 -12
  294. package/dist/slices/library/model.js +2 -0
  295. package/dist/slices/library/photorealistic.js +4 -12
  296. package/dist/slices/library/rename.js +9 -7
  297. package/dist/slices/library/save.js +14 -10
  298. package/dist/slices/library/slots.js +37 -11
  299. package/dist/slices/library/transfer.js +2 -1
  300. package/dist/slices/library/used-by.js +25 -10
  301. package/dist/slices/loudness/loudnorm.js +51 -11
  302. package/dist/slices/model-checks/cost.js +61 -0
  303. package/dist/slices/model-checks/listing.js +124 -0
  304. package/dist/slices/model-checks/model.js +20 -0
  305. package/dist/slices/model-checks/record.js +32 -0
  306. package/dist/slices/model-checks/repo.js +120 -0
  307. package/dist/slices/model-checks/rules.js +112 -0
  308. package/dist/slices/model-checks/run.js +143 -0
  309. package/dist/slices/model-checks/service.js +198 -0
  310. package/dist/slices/model-upkeep/switch.js +70 -25
  311. package/dist/slices/model-upkeep/usage.js +26 -11
  312. package/dist/slices/narration/breaths.js +2 -1
  313. package/dist/slices/narration/clean-pieces.js +2 -1
  314. package/dist/slices/narration/concat.js +2 -1
  315. package/dist/slices/narration/peaks.js +3 -4
  316. package/dist/slices/narration/pronunciation-chunks.js +4 -3
  317. package/dist/slices/narration/pronunciation.js +3 -2
  318. package/dist/slices/narration/steering.js +4 -3
  319. package/dist/slices/notifications/notifier.js +4 -3
  320. package/dist/slices/notifications/rules.js +5 -2
  321. package/dist/slices/notifications/settings.js +4 -12
  322. package/dist/slices/notifications/subject.js +2 -1
  323. package/dist/slices/onboarding/copy.js +2 -1
  324. package/dist/slices/onboarding/first-run.js +3 -2
  325. package/dist/slices/onboarding/full-video.js +3 -2
  326. package/dist/slices/onboarding/install.js +4 -3
  327. package/dist/slices/onboarding/model.js +0 -16
  328. package/dist/slices/onboarding/packs.js +22 -22
  329. package/dist/slices/onboarding/quick-short.js +2 -1
  330. package/dist/slices/onboarding/sample.js +0 -1
  331. package/dist/slices/onboarding/state.js +2 -11
  332. package/dist/slices/onboarding/template.js +2 -1
  333. package/dist/slices/patch-notes/library.js +3 -2
  334. package/dist/slices/play-drafts/convert.js +4 -0
  335. package/dist/slices/play-drafts/review-inputs.js +8 -2
  336. package/dist/slices/play-drafts/review.js +5 -4
  337. package/dist/slices/play-drafts/schema.js +4 -0
  338. package/dist/slices/project-templates/from-project.js +9 -2
  339. package/dist/slices/project-templates/repo.js +6 -1
  340. package/dist/slices/project-templates/setup.js +8 -0
  341. package/dist/slices/project-templates/stand-ins.js +22 -0
  342. package/dist/slices/rebuild/activity.js +2 -0
  343. package/dist/slices/rebuild/admission-repo.js +3 -2
  344. package/dist/slices/rebuild/narration-history.js +4 -5
  345. package/dist/slices/rebuild/narration-retry.js +2 -1
  346. package/dist/slices/rebuild/preview-details.js +27 -9
  347. package/dist/slices/rebuild/preview-plan.js +3 -8
  348. package/dist/slices/rebuild/recipe-build.js +8 -3
  349. package/dist/slices/rebuild/recipe-describe.js +3 -3
  350. package/dist/slices/rebuild/recipe-digest.js +58 -0
  351. package/dist/slices/rebuild/recipe-input-schema.js +10 -0
  352. package/dist/slices/rebuild/recipe-keywords.js +71 -0
  353. package/dist/slices/rebuild/recipe-legacy.js +5 -1
  354. package/dist/slices/rebuild/recipe-model.js +4 -0
  355. package/dist/slices/rebuild/recipe-narration-text.js +2 -1
  356. package/dist/slices/rebuild/recipe-preparation.js +3 -3
  357. package/dist/slices/rebuild/recipe-reference.js +8 -4
  358. package/dist/slices/rebuild/recipe-reviews.js +27 -7
  359. package/dist/slices/rebuild/recipe-save.js +6 -3
  360. package/dist/slices/rebuild/recipe-scenes.js +40 -11
  361. package/dist/slices/rebuild/recipe-shorts.js +8 -8
  362. package/dist/slices/rebuild/recipe-social.js +46 -0
  363. package/dist/slices/rebuild/recipe-text.js +64 -20
  364. package/dist/slices/rebuild/recipe-validation.js +98 -28
  365. package/dist/slices/rebuild/recipe-visual.js +55 -16
  366. package/dist/slices/rebuild/recipe-work.js +15 -3
  367. package/dist/slices/rebuild/recipe-youtube.js +4 -3
  368. package/dist/slices/rebuild/recovery-selection.js +3 -1
  369. package/dist/slices/rebuild/recovery.js +3 -2
  370. package/dist/slices/rebuild/repo.js +4 -3
  371. package/dist/slices/rebuild/review-promise.js +25 -0
  372. package/dist/slices/rebuild/review-redo.js +2 -1
  373. package/dist/slices/rebuild/runtime-admission.js +4 -3
  374. package/dist/slices/rebuild/runtime-agent-review.js +11 -5
  375. package/dist/slices/rebuild/runtime-animate.js +9 -8
  376. package/dist/slices/rebuild/runtime-article.js +3 -2
  377. package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
  378. package/dist/slices/rebuild/runtime-document.js +8 -11
  379. package/dist/slices/rebuild/runtime-export-bed.js +6 -11
  380. package/dist/slices/rebuild/runtime-export-edit.js +6 -15
  381. package/dist/slices/rebuild/runtime-export-inputs.js +7 -7
  382. package/dist/slices/rebuild/runtime-export-short.js +8 -4
  383. package/dist/slices/rebuild/runtime-export.js +34 -12
  384. package/dist/slices/rebuild/runtime-figure-card.js +2 -1
  385. package/dist/slices/rebuild/runtime-image.js +4 -9
  386. package/dist/slices/rebuild/runtime-instructions.js +2 -0
  387. package/dist/slices/rebuild/runtime-keywords.js +59 -0
  388. package/dist/slices/rebuild/runtime-lines.js +2 -11
  389. package/dist/slices/rebuild/runtime-local.js +14 -20
  390. package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
  391. package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
  392. package/dist/slices/rebuild/runtime-narration-text.js +10 -15
  393. package/dist/slices/rebuild/runtime-pictures.js +2 -4
  394. package/dist/slices/rebuild/runtime-piece-label.js +10 -6
  395. package/dist/slices/rebuild/runtime-plan.js +31 -5
  396. package/dist/slices/rebuild/runtime-provider.js +60 -19
  397. package/dist/slices/rebuild/runtime-publication.js +10 -9
  398. package/dist/slices/rebuild/runtime-review.js +33 -28
  399. package/dist/slices/rebuild/runtime-run.js +4 -1
  400. package/dist/slices/rebuild/runtime-shorts.js +34 -50
  401. package/dist/slices/rebuild/runtime-store.js +3 -8
  402. package/dist/slices/rebuild/runtime-subtitles.js +16 -14
  403. package/dist/slices/rebuild/runtime-voices.js +8 -15
  404. package/dist/slices/rebuild/runtime-youtube.js +11 -29
  405. package/dist/slices/rebuild/transition-repo.js +6 -5
  406. package/dist/slices/rebuild/work-records.js +6 -0
  407. package/dist/slices/reruns/cascade.js +1 -2
  408. package/dist/slices/reruns/index.js +6 -9
  409. package/dist/slices/reviews/external-model.js +3 -0
  410. package/dist/slices/reviews/external-repo.js +2 -1
  411. package/dist/slices/reviews/external-rows.js +2 -3
  412. package/dist/slices/reviews/model.js +26 -8
  413. package/dist/slices/reviews/repo.js +2 -1
  414. package/dist/slices/reviews/rules.js +1 -0
  415. package/dist/slices/reviews/view.js +5 -2
  416. package/dist/slices/revisions/downloads.js +4 -5
  417. package/dist/slices/revisions/mutation-assets.js +7 -4
  418. package/dist/slices/revisions/mutation-cues.js +2 -5
  419. package/dist/slices/revisions/mutations.js +0 -1
  420. package/dist/slices/revisions/repo.js +3 -1
  421. package/dist/slices/revisions/schema.js +1 -0
  422. package/dist/slices/revisions/view.js +20 -0
  423. package/dist/slices/run-cost/limits.js +5 -2
  424. package/dist/slices/run-cost/meter.js +12 -5
  425. package/dist/slices/run-cost/panel.js +8 -74
  426. package/dist/slices/run-cost/plan-readings.js +127 -0
  427. package/dist/slices/run-cost/plan-use.js +169 -0
  428. package/dist/slices/run-cost/pricing.js +3 -3
  429. package/dist/slices/run-cost/week.js +32 -4
  430. package/dist/slices/schedules/agenda.js +11 -2
  431. package/dist/slices/schedules/by-date.js +42 -0
  432. package/dist/slices/schedules/calendar.js +5 -0
  433. package/dist/slices/schedules/design-agenda.js +36 -0
  434. package/dist/slices/schedules/design-check.js +41 -0
  435. package/dist/slices/schedules/design-run.js +126 -0
  436. package/dist/slices/schedules/next-run.js +62 -0
  437. package/dist/slices/schedules/prepare.js +18 -2
  438. package/dist/slices/schedules/repo.js +24 -16
  439. package/dist/slices/schedules/rescore.js +35 -0
  440. package/dist/slices/schedules/scheduler.js +13 -3
  441. package/dist/slices/schedules/schema.js +54 -3
  442. package/dist/slices/schedules/score.js +107 -0
  443. package/dist/slices/schedules/service.js +57 -24
  444. package/dist/slices/schedules/topic-list.js +15 -0
  445. package/dist/slices/schedules/topic-scores.js +104 -0
  446. package/dist/slices/schedules/topics.js +48 -36
  447. package/dist/slices/settings/cli-paths.js +4 -6
  448. package/dist/slices/settings/first-run.js +2 -11
  449. package/dist/slices/settings/model-reach.js +3 -17
  450. package/dist/slices/settings/model.js +10 -0
  451. package/dist/slices/settings/playback.js +33 -22
  452. package/dist/slices/settings/probe-read.js +16 -0
  453. package/dist/slices/settings/repo.js +33 -0
  454. package/dist/slices/settings/tutorial.js +2 -2
  455. package/dist/slices/settings/voices.js +4 -12
  456. package/dist/slices/shorts/pick.js +2 -15
  457. package/dist/slices/shorts/prompts.js +2 -13
  458. package/dist/slices/shorts/render.js +3 -0
  459. package/dist/slices/social/channel.js +44 -0
  460. package/dist/slices/social/defaults.js +17 -0
  461. package/dist/slices/social/due.js +36 -0
  462. package/dist/slices/social/extension.js +18 -0
  463. package/dist/slices/social/fit.js +115 -0
  464. package/dist/slices/social/limits.js +186 -0
  465. package/dist/slices/social/links.js +21 -0
  466. package/dist/slices/social/media.js +131 -0
  467. package/dist/slices/social/model.js +75 -0
  468. package/dist/slices/social/notice.js +19 -0
  469. package/dist/slices/social/pack.js +176 -0
  470. package/dist/slices/social/post-prompt.js +55 -0
  471. package/dist/slices/social/queue.js +31 -0
  472. package/dist/slices/social/repo.js +133 -0
  473. package/dist/slices/social/reshape.js +97 -0
  474. package/dist/slices/social/rules.js +5 -0
  475. package/dist/slices/social/schema.js +70 -0
  476. package/dist/slices/social/serve.js +51 -0
  477. package/dist/slices/social/service.js +128 -0
  478. package/dist/slices/social/settings.js +21 -0
  479. package/dist/slices/social/sources.js +114 -0
  480. package/dist/slices/social/state.js +110 -0
  481. package/dist/slices/social/text.js +149 -0
  482. package/dist/slices/storage/arrange.js +3 -1
  483. package/dist/slices/storage/assets.js +8 -10
  484. package/dist/slices/storage/backup-designs.js +74 -0
  485. package/dist/slices/storage/backup-export.js +8 -3
  486. package/dist/slices/storage/backup-format.js +10 -0
  487. package/dist/slices/storage/backup-import.js +20 -2
  488. package/dist/slices/storage/delete-project.js +6 -5
  489. package/dist/slices/storage/files-location.js +6 -8
  490. package/dist/slices/storage/layout.js +13 -2
  491. package/dist/slices/storage/model.js +3 -0
  492. package/dist/slices/storage/portable.js +16 -11
  493. package/dist/slices/storage/schema.js +2 -0
  494. package/dist/slices/storage/staging-refs.js +2 -1
  495. package/dist/slices/storage/staging.js +6 -9
  496. package/dist/slices/storage/trim.js +10 -3
  497. package/dist/slices/studio/calendar.js +4 -1
  498. package/dist/slices/studio/pick.js +2 -11
  499. package/dist/slices/studio/plan.js +6 -15
  500. package/dist/slices/studio/queue.js +3 -14
  501. package/dist/slices/studio/releases.js +26 -0
  502. package/dist/slices/studio/settings.js +14 -51
  503. package/dist/slices/studio/videos.js +12 -0
  504. package/dist/slices/style-preview/render.js +34 -13
  505. package/dist/slices/style-preview/schema.js +13 -0
  506. package/dist/slices/style-preview/service.js +2 -1
  507. package/dist/slices/style-preview/settings.js +33 -5
  508. package/dist/slices/telemetry/collector-client.js +2 -4
  509. package/dist/slices/telemetry/flush.js +2 -4
  510. package/dist/slices/telemetry/model.js +0 -7
  511. package/dist/slices/telemetry/record.js +10 -3
  512. package/dist/slices/template-studio/anatomy-view.js +118 -0
  513. package/dist/slices/template-studio/anatomy.js +73 -0
  514. package/dist/slices/template-studio/bakeoff-make.js +225 -0
  515. package/dist/slices/template-studio/bakeoff-repo.js +83 -0
  516. package/dist/slices/template-studio/bakeoff.js +333 -0
  517. package/dist/slices/template-studio/budget.js +103 -0
  518. package/dist/slices/template-studio/checks.js +273 -0
  519. package/dist/slices/template-studio/document-sample.js +56 -0
  520. package/dist/slices/template-studio/edit.js +15 -0
  521. package/dist/slices/template-studio/for-all.js +161 -0
  522. package/dist/slices/template-studio/free-video.js +31 -0
  523. package/dist/slices/template-studio/free.js +176 -0
  524. package/dist/slices/template-studio/gate.js +40 -0
  525. package/dist/slices/template-studio/hidden.js +20 -0
  526. package/dist/slices/template-studio/jobs.js +79 -0
  527. package/dist/slices/template-studio/loudness.js +111 -0
  528. package/dist/slices/template-studio/make.js +40 -0
  529. package/dist/slices/template-studio/model.js +54 -0
  530. package/dist/slices/template-studio/pack-import.js +253 -0
  531. package/dist/slices/template-studio/pack-samples.js +60 -0
  532. package/dist/slices/template-studio/pack.js +205 -0
  533. package/dist/slices/template-studio/paid-view.js +66 -0
  534. package/dist/slices/template-studio/paid.js +348 -0
  535. package/dist/slices/template-studio/quote.js +148 -0
  536. package/dist/slices/template-studio/ready.js +104 -0
  537. package/dist/slices/template-studio/repo.js +134 -0
  538. package/dist/slices/template-studio/reviews-path.js +58 -0
  539. package/dist/slices/template-studio/runner.js +84 -0
  540. package/dist/slices/template-studio/save.js +236 -0
  541. package/dist/slices/template-studio/say-it-as.js +248 -0
  542. package/dist/slices/template-studio/schedule-gate.js +34 -0
  543. package/dist/slices/template-studio/schedule-price.js +30 -0
  544. package/dist/slices/template-studio/schedule-sample.js +87 -0
  545. package/dist/slices/template-studio/schema.js +218 -0
  546. package/dist/slices/template-studio/scope.js +124 -0
  547. package/dist/slices/template-studio/sections.js +176 -0
  548. package/dist/slices/template-studio/service.js +173 -0
  549. package/dist/slices/template-studio/status.js +174 -0
  550. package/dist/slices/template-studio/topic.js +223 -0
  551. package/dist/slices/trash/designs.js +76 -0
  552. package/dist/slices/trash/model.js +13 -4
  553. package/dist/slices/trash/service.js +52 -2
  554. package/dist/slices/tutorials/library.js +3 -2
  555. package/dist/slices/video/ass-text.js +17 -0
  556. package/dist/slices/video/audio-export.js +2 -64
  557. package/dist/slices/video/encoding.js +160 -0
  558. package/dist/slices/video/ffmpeg.js +23 -21
  559. package/dist/slices/video/figure-card.js +1 -15
  560. package/dist/slices/video/slideshow.js +43 -18
  561. package/dist/slices/voices/palette.js +0 -3
  562. package/dist/slices/youtube/answer.js +2 -15
  563. package/dist/slices/youtube/edits-repo.js +2 -11
  564. package/dist/tutorials/Agents-MCP.md +2 -1
  565. package/dist/tutorials/Assistant.md +42 -0
  566. package/dist/tutorials/Channels.md +2 -0
  567. package/dist/tutorials/Home-and-Projects.md +19 -0
  568. package/dist/tutorials/Install.md +1 -0
  569. package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
  570. package/dist/tutorials/Models.md +33 -1
  571. package/dist/tutorials/Notifications.md +6 -0
  572. package/dist/tutorials/Play-Images.md +4 -0
  573. package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
  574. package/dist/tutorials/Prompts.md +10 -6
  575. package/dist/tutorials/Remote-Access.md +63 -0
  576. package/dist/tutorials/Reviews-and-Checkpoints.md +13 -2
  577. package/dist/tutorials/Schedules.md +21 -1
  578. package/dist/tutorials/Settings-Reference.md +50 -8
  579. package/dist/tutorials/Template-Studio.md +125 -0
  580. package/dist/tutorials/Templates.md +3 -0
  581. package/dist/tutorials/_Sidebar.md +5 -0
  582. package/dist/updater/work-in-progress.js +42 -12
  583. package/dist/web/assets/index-CkAI_2E7.css +1 -0
  584. package/dist/web/assets/index-DcD0cdfo.js +334 -0
  585. package/dist/web/assets/{pdf-T7MCwjIv.js → pdf-TODRwF31.js} +1 -1
  586. package/dist/web/index.html +2 -2
  587. package/package.json +5 -1
  588. package/dist/slices/article/provided-entries.js +0 -66
  589. package/dist/slices/article/run.js +0 -145
  590. package/dist/slices/images/run.js +0 -234
  591. package/dist/slices/narration/legacy-plan.js +0 -58
  592. package/dist/slices/narration/run.js +0 -270
  593. package/dist/slices/rebuild/runtime-actions.js +0 -90
  594. package/dist/slices/research/run.js +0 -224
  595. package/dist/slices/subtitles/prepare.js +0 -194
  596. package/dist/slices/subtitles/transcript.js +0 -34
  597. package/dist/slices/thumbnail/run.js +0 -219
  598. package/dist/slices/video/audio-inputs.js +0 -33
  599. package/dist/slices/video/reuse-audio.js +0 -62
  600. package/dist/slices/video/run.js +0 -78
  601. package/dist/slices/video/write-export.js +0 -158
  602. package/dist/slices/video/write-subtitles.js +0 -59
  603. package/dist/web/assets/index-BadsoORk.css +0 -1
  604. package/dist/web/assets/index-D8LqNsCl.js +0 -326
@@ -1,20 +1,14 @@
1
1
  import { zValidator } from "@hono/zod-validator";
2
2
  import { Hono } from "hono";
3
- import { z } from "zod";
3
+ import { errorText } from "../../kernel/errors.js";
4
4
  import { narrationAudio } from "../../slices/narration/peaks.js";
5
5
  import { assetPath } from "../../slices/revisions/mutation-assets.js";
6
6
  import { currentRevisionId } from "../../slices/revisions/repo.js";
7
7
  import { getRevisionView } from "../../slices/revisions/view.js";
8
8
  import { outputPath } from "../../slices/storage/layout.js";
9
9
  import { projectTitle } from "../../slices/storage/repo.js";
10
- import { onInvalid, problem, titleOf } from "./problem.js";
11
- const projectParam = z.object({
12
- projectId: z
13
- .string()
14
- .min(1)
15
- .max(64)
16
- .regex(/^[0-9A-Za-z_-]+$/),
17
- });
10
+ import { projectIdParam } from "./ids.js";
11
+ import { onInvalid, problem } from "./problem.js";
18
12
  // ceiling: a few projects' worth of pieces. An asset never changes, so a cached row is never
19
13
  // stale; the oldest goes first.
20
14
  const cachedPieces = 400;
@@ -22,12 +16,11 @@ const cachedPieces = 400;
22
16
  // version, fetched again each time a `narration.piece` event says one landed.
23
17
  export function narrationPeakRoutes(deps) {
24
18
  const cache = new Map();
25
- return new Hono().get("/:projectId/narration/peaks", zValidator("param", projectParam, onInvalid), async (c) => {
19
+ return new Hono().get("/:projectId/narration/peaks", zValidator("param", projectIdParam, onInvalid), async (c) => {
26
20
  const { projectId } = c.req.valid("param");
27
21
  if (projectTitle(deps.db, projectId) === undefined)
28
22
  return problem(c, {
29
23
  status: 404,
30
- title: titleOf(404),
31
24
  detail: "This project no longer exists. Go back to Projects to pick another.",
32
25
  });
33
26
  c.header("Cache-Control", "no-store");
@@ -43,7 +36,6 @@ export function narrationPeakRoutes(deps) {
43
36
  if (decode === undefined)
44
37
  return problem(c, {
45
38
  status: 503,
46
- title: titleOf(503),
47
39
  detail: "Slopify can't draw the narration waveform because ffmpeg isn't available. Restart Slopify; if it keeps happening, use Download diagnostics in Settings and report it.",
48
40
  });
49
41
  const audio = narrationAudio(view);
@@ -58,7 +50,7 @@ export function narrationPeakRoutes(deps) {
58
50
  deps.log.write("warn", "narration.peaks", {
59
51
  projectId,
60
52
  stage: "audio",
61
- detail: error instanceof Error ? error.message : String(error),
53
+ detail: errorText(error),
62
54
  });
63
55
  continue;
64
56
  }
@@ -18,7 +18,7 @@ import { providerStatuses } from "../../slices/settings/readiness.js";
18
18
  import { listVoices } from "../../slices/settings/repo.js";
19
19
  import { addVoice } from "../../slices/settings/voices.js";
20
20
  import { projectTitle } from "../../slices/storage/repo.js";
21
- import { onInvalid, problem, titleOf } from "./problem.js";
21
+ import { onInvalid, problem } from "./problem.js";
22
22
  import { createProject } from "./project-create.js";
23
23
  const packParam = z.object({ id: z.string().min(1).max(40) });
24
24
  // The first five minutes: the first-run screen's state, starter packs, "Make a 60-second
@@ -64,7 +64,6 @@ export function onboardingRoutes(deps) {
64
64
  if (!installed.ok)
65
65
  return problem(c, {
66
66
  status: 404,
67
- title: titleOf(404),
68
67
  detail: "Slopify doesn't have that starter pack. Reload the page and pick one of the packs listed.",
69
68
  });
70
69
  return c.json(installed.value);
@@ -78,14 +77,12 @@ export function onboardingRoutes(deps) {
78
77
  if (pack === undefined)
79
78
  return problem(c, {
80
79
  status: 404,
81
- title: titleOf(404),
82
80
  detail: "Slopify doesn't have that starter pack. Reload the page and pick one of the packs listed.",
83
81
  });
84
82
  const modelsFor = deps.modelsFor;
85
83
  if (modelsFor === undefined)
86
84
  return problem(c, {
87
85
  status: 503,
88
- title: titleOf(503),
89
86
  detail: "Slopify can't list the models on this machine right now. Restart Slopify and try again.",
90
87
  });
91
88
  const plan = await planShortProviders({
@@ -98,7 +95,6 @@ export function onboardingRoutes(deps) {
98
95
  if (!plan.ok)
99
96
  return problem(c, {
100
97
  status: 409,
101
- title: titleOf(409),
102
98
  detail: plan.gaps.map((gap) => gap.message).join(" "),
103
99
  extensions: { gaps: plan.gaps },
104
100
  });
@@ -106,7 +102,6 @@ export function onboardingRoutes(deps) {
106
102
  if (!installed.ok)
107
103
  return problem(c, {
108
104
  status: 404,
109
- title: titleOf(404),
110
105
  detail: "Slopify doesn't have that starter pack. Reload the page and pick one of the packs listed.",
111
106
  });
112
107
  // The computer's voice is saved like any other, so Play and a later rebuild offer it.
@@ -135,7 +130,6 @@ export function onboardingRoutes(deps) {
135
130
  if (!created.ok)
136
131
  return problem(c, {
137
132
  status: created.status,
138
- title: titleOf(created.status),
139
133
  detail: `${created.detail} ${created.fields.map((field) => field.message).join(" ")}`.trim(),
140
134
  ...(created.fields.length === 0 ? {} : { extensions: { fields: created.fields } }),
141
135
  });
@@ -151,18 +145,15 @@ export function onboardingRoutes(deps) {
151
145
  if (made.reason === "not-found")
152
146
  return problem(c, {
153
147
  status: 404,
154
- title: titleOf(404),
155
148
  detail: "This short or its starter pack is no longer here, so Play couldn't be set up from it. Open Play and pick a template yourself.",
156
149
  });
157
150
  if (made.reason === "not-short")
158
151
  return problem(c, {
159
152
  status: 409,
160
- title: titleOf(409),
161
153
  detail: "This project is already a long video. Open Play to start another one on a new topic.",
162
154
  });
163
155
  return problem(c, {
164
156
  status: 409,
165
- title: titleOf(409),
166
157
  detail: "Slopify couldn't open a Play draft for the full video. Press Make the full video on this topic again; if it keeps failing, open Play and pick the pack's template in Library → Templates.",
167
158
  extensions: { reason: made.reason },
168
159
  });
@@ -176,7 +167,6 @@ export function onboardingRoutes(deps) {
176
167
  if (!restored.ok)
177
168
  return problem(c, {
178
169
  status: restored.status,
179
- title: titleOf(restored.status),
180
170
  detail: restored.detail,
181
171
  });
182
172
  return c.json({ projectId: restored.samples.library, samples: restored.samples });
@@ -188,7 +178,6 @@ export function onboardingRoutes(deps) {
188
178
  if (!input.success)
189
179
  return problem(c, {
190
180
  status: 400,
191
- title: titleOf(400),
192
181
  detail: "Slopify couldn't tell which sample to copy. Reload the page and try again.",
193
182
  });
194
183
  const catalogue = deps.catalogue;
@@ -196,14 +185,12 @@ export function onboardingRoutes(deps) {
196
185
  if (catalogue === undefined || id === undefined)
197
186
  return problem(c, {
198
187
  status: 404,
199
- title: titleOf(404),
200
188
  detail: "The sample project isn't here. Bring it back with Settings → Backup & storage → Restore samples, then press Make my own copy.",
201
189
  });
202
190
  const copied = copySample({ ...sample, catalogue: catalogue.read() }, id);
203
191
  if (!copied.ok)
204
192
  return problem(c, {
205
193
  status: copied.status,
206
- title: titleOf(copied.status),
207
194
  detail: copied.detail,
208
195
  });
209
196
  deps.hub.emitGlobal({ type: "project.updated", projectId: copied.projectId });
@@ -4,25 +4,21 @@ import { z } from "zod";
4
4
  import { assetOf, findDownload } from "../../slices/storage/downloads.js";
5
5
  import { outputsOf } from "../../slices/storage/repo.js";
6
6
  import { replyForFolder } from "./folder-location.js";
7
- import { onInvalid, problem, titleOf } from "./problem.js";
7
+ import { idString } from "./ids.js";
8
+ import { onInvalid, problem } from "./problem.js";
9
+ import { fromSlopifyPage } from "./same-page.js";
8
10
  export function openFolderRoutes(deps) {
9
11
  return new Hono().post("/:id/open-folder", zValidator("param", z.object({
10
- id: z
11
- .string()
12
- .min(1)
13
- .max(64)
14
- .regex(/^[0-9A-Za-z_-]+$/),
12
+ id: idString,
15
13
  }), onInvalid), zValidator("json", z.object({
16
14
  asset: z
17
15
  .string()
18
16
  .max(64)
19
17
  .regex(/^(?:[a-z0-9-]+|images\.zip)$/),
20
18
  }), onInvalid), async (c) => {
21
- const origin = c.req.header("origin");
22
- if (origin !== undefined && origin !== new URL(c.req.url).origin) {
19
+ if (!fromSlopifyPage(c, deps.remoteAccess?.remoteHost)) {
23
20
  return problem(c, {
24
21
  status: 403,
25
- title: titleOf(403),
26
22
  detail: "For your safety, folders can only be opened from the Slopify page itself. Open Slopify and try again there.",
27
23
  });
28
24
  }
@@ -40,7 +36,6 @@ export function openFolderRoutes(deps) {
40
36
  if (download === undefined || !download.ok) {
41
37
  return problem(c, {
42
38
  status: 404,
43
- title: titleOf(404),
44
39
  detail: "This output's file was deleted or moved. Use More → make it again in its section on the project page to make it again.",
45
40
  });
46
41
  }
@@ -1,17 +1,10 @@
1
1
  import { zValidator } from "@hono/zod-validator";
2
2
  import { Hono } from "hono";
3
- import { z } from "zod";
4
3
  import { addOutputPreviewRequestSchema, addOutputRequestSchema, } from "../../slices/outputs/model.js";
5
4
  import { addOutput, previewAddedOutput, } from "../../slices/outputs/service.js";
6
5
  import { currentRevisionId } from "../../slices/revisions/repo.js";
7
- import { onInvalid, problem, titleOf } from "./problem.js";
8
- const projectParam = z.object({
9
- id: z
10
- .string()
11
- .min(1)
12
- .max(64)
13
- .regex(/^[0-9A-Za-z_-]+$/),
14
- });
6
+ import { idParam } from "./ids.js";
7
+ import { onInvalid, problem } from "./problem.js";
15
8
  const statuses = {
16
9
  "no-project": 404,
17
10
  "no-revision": 404,
@@ -41,7 +34,6 @@ export function outputRoutes(deps) {
41
34
  const status = statuses[value.reason];
42
35
  return problem(c, {
43
36
  status,
44
- title: titleOf(status),
45
37
  detail: value.message ?? details[value.reason],
46
38
  extensions: {
47
39
  reason: value.reason,
@@ -51,12 +43,12 @@ export function outputRoutes(deps) {
51
43
  });
52
44
  };
53
45
  return new Hono()
54
- .post("/:id/outputs/preview", zValidator("param", projectParam, onInvalid), zValidator("json", addOutputPreviewRequestSchema, onInvalid), (c) => {
46
+ .post("/:id/outputs/preview", zValidator("param", idParam, onInvalid), zValidator("json", addOutputPreviewRequestSchema, onInvalid), (c) => {
55
47
  const projectId = c.req.valid("param").id;
56
48
  const result = previewAddedOutput(service, { projectId, ...c.req.valid("json") });
57
49
  return result.ok ? c.json(result.value) : refused(c, projectId, result);
58
50
  })
59
- .post("/:id/outputs", zValidator("param", projectParam, onInvalid), zValidator("json", addOutputRequestSchema, onInvalid), async (c) => {
51
+ .post("/:id/outputs", zValidator("param", idParam, onInvalid), zValidator("json", addOutputRequestSchema, onInvalid), async (c) => {
60
52
  const projectId = c.req.valid("param").id;
61
53
  const result = await addOutput(service, { projectId, ...c.req.valid("json") });
62
54
  if (!result.ok)
@@ -1,13 +1,8 @@
1
1
  import { Hono } from "hono";
2
2
  import { bundledPatchNotesDir, PatchNotesMissing, readPatchNote, } from "../../slices/patch-notes/library.js";
3
3
  import { markPatchNotesSeen, readPatchNotes } from "../../slices/patch-notes/seen.js";
4
- import { problem, titleOf } from "./problem.js";
5
- // A build without its notes says so in plain words; anything else is the app's error handler's.
6
- function missing(c, error) {
7
- if (!(error instanceof PatchNotesMissing))
8
- throw error;
9
- return problem(c, { status: 500, title: titleOf(500), detail: error.message });
10
- }
4
+ import { problem } from "./problem.js";
5
+ import { bundleMissing } from "./refusal.js";
11
6
  // Settings → Patch notes: the list (with which note is due to open by itself), one note's
12
7
  // Markdown, and recording that the note that opened by itself was closed.
13
8
  // Preserve Hono's inferred route types for the web client.
@@ -19,7 +14,7 @@ export function patchNotesRoutes(deps) {
19
14
  return c.json(await readPatchNotes(deps.db, dir, deps.version));
20
15
  }
21
16
  catch (error) {
22
- return missing(c, error);
17
+ return bundleMissing(c, error, PatchNotesMissing);
23
18
  }
24
19
  })
25
20
  .post("/seen", (c) => {
@@ -32,12 +27,11 @@ export function patchNotesRoutes(deps) {
32
27
  markdown = await readPatchNote(dir, c.req.param("id"));
33
28
  }
34
29
  catch (error) {
35
- return missing(c, error);
30
+ return bundleMissing(c, error, PatchNotesMissing);
36
31
  }
37
32
  if (markdown === undefined)
38
33
  return problem(c, {
39
34
  status: 404,
40
- title: titleOf(404),
41
35
  detail: "These patch notes are not in this version of Slopify. Open Settings → Patch notes and pick one from the list.",
42
36
  });
43
37
  return c.body(markdown, 200, { "content-type": "text/markdown; charset=utf-8" });
@@ -10,7 +10,7 @@ import { estimateRun } from "../../slices/estimate/index.js";
10
10
  import { resolveFont } from "../../slices/fonts/index.js";
11
11
  import { pickTemplates, renderPicked } from "../../slices/library/slots.js";
12
12
  import { stagedFiles } from "../../slices/storage/repo.js";
13
- import { onInvalid, problem, titleOf } from "./problem.js";
13
+ import { onInvalid, problem } from "./problem.js";
14
14
  const planningBody = z.object({
15
15
  draft: runDraftSchema,
16
16
  expectedWords: z.number().int().min(1).max(100000).default(1500),
@@ -42,6 +42,7 @@ export function planningRoutes(deps) {
42
42
  draft: picked.draft,
43
43
  staged: stagedFiles(deps.db),
44
44
  requiredSlots: picked.requiredSlots,
45
+ keywordUses: picked.keywordUses,
45
46
  });
46
47
  const accepted = admitted.ok ? admitted.draft : picked.draft;
47
48
  const fields = [
@@ -69,7 +70,6 @@ export function planningRoutes(deps) {
69
70
  return c.json({ queue: result.queue });
70
71
  return problem(c, {
71
72
  status: 409,
72
- title: titleOf(409),
73
73
  detail: result.reason === "edge"
74
74
  ? "This video is already at that end of the waiting videos, so it can't move further."
75
75
  : "This video has already started or left the queue, so its place can't change. The queue has been read again.",
@@ -82,7 +82,6 @@ export function planningRoutes(deps) {
82
82
  if (fields.length)
83
83
  return problem(c, {
84
84
  status: 400,
85
- title: titleOf(400),
86
85
  detail: "Some settings need fixing before Slopify can estimate the cost. Fix the highlighted fields.",
87
86
  extensions: { fields },
88
87
  });
@@ -95,7 +94,6 @@ export function planningRoutes(deps) {
95
94
  if (input.draft.checkpoints?.length)
96
95
  return problem(c, {
97
96
  status: 409,
98
- title: titleOf(409),
99
97
  detail: "Videos with checkpoints turned on cannot be queued. Start them one at a time from Play with Review and start.",
100
98
  });
101
99
  if (batchExists(deps.db, input.requestId))
@@ -108,7 +106,6 @@ export function planningRoutes(deps) {
108
106
  catch {
109
107
  return problem(c, {
110
108
  status: 400,
111
- title: titleOf(400),
112
109
  detail: "The subtitle font you picked is no longer available. Choose another font before starting.",
113
110
  });
114
111
  }
@@ -118,7 +115,6 @@ export function planningRoutes(deps) {
118
115
  if (fields.length)
119
116
  return problem(c, {
120
117
  status: 400,
121
- title: titleOf(400),
122
118
  detail: "No videos were queued. Fix the highlighted fields, then try again.",
123
119
  extensions: { fields },
124
120
  });
@@ -1,6 +1,7 @@
1
1
  import { HTTPException } from "hono/http-exception";
2
2
  const titles = {
3
3
  400: "Bad Request",
4
+ 403: "Forbidden",
4
5
  404: "Not Found",
5
6
  409: "Conflict",
6
7
  415: "Unsupported Media Type",
@@ -12,7 +13,7 @@ export function problem(c, init) {
12
13
  // Extensions go first so a route cannot shadow a member RFC 9457 reserves.
13
14
  ...init.extensions,
14
15
  type: init.type ?? "about:blank",
15
- title: init.title,
16
+ title: init.title ?? titleOf(init.status),
16
17
  status: init.status,
17
18
  ...(init.detail === undefined ? {} : { detail: init.detail }),
18
19
  instance: c.req.path,
@@ -25,7 +26,6 @@ export function problemFromError(c, error, deps) {
25
26
  if (error instanceof HTTPException) {
26
27
  return problem(c, {
27
28
  status: error.status,
28
- title: titleOf(error.status),
29
29
  detail: error.message === "" ? undefined : error.message,
30
30
  });
31
31
  }
@@ -38,7 +38,6 @@ export function problemFromError(c, error, deps) {
38
38
  });
39
39
  return problem(c, {
40
40
  status: 500,
41
- title: titleOf(500),
42
41
  detail: `Slopify hit an internal error while handling this request. Try again; if it keeps happening, use Download diagnostics in Settings and report it (reference ${correlationId}).`,
43
42
  extensions: { correlationId },
44
43
  });
@@ -54,7 +53,6 @@ export function onInvalid(result, c) {
54
53
  }
55
54
  return problem(c, {
56
55
  status: 400,
57
- title: titleOf(400),
58
56
  detail: "Slopify could not read this request, which usually means the page is out of date. Reload the page and try again.",
59
57
  extensions: {
60
58
  errors: result.error.issues.map((issue) => ({
@@ -47,6 +47,7 @@ export async function createProject(deps, sent) {
47
47
  draft: picked.draft,
48
48
  staged: stagedFiles(deps.db),
49
49
  requiredSlots: picked.requiredSlots,
50
+ keywordUses: picked.keywordUses,
50
51
  });
51
52
  const modelErrors = modelFields(picked.draft, deps.catalogue);
52
53
  if (!admitted.ok || picked.missing.length > 0 || modelErrors.length > 0)
@@ -6,17 +6,22 @@ import { createTemplateFromProject, templateFromProjectSchema, } from "../../sli
6
6
  import { makeNextChapter, nextChapterSchema } from "../../slices/project-templates/next-chapter.js";
7
7
  import { templateCreateSchema, templateDeleteSchema, templateInstantiateSchema, templateUpdateSchema, } from "../../slices/project-templates/schema.js";
8
8
  import { createTemplate, deleteTemplate, instantiateTemplate, listTemplates, readTemplate, updateTemplate, } from "../../slices/project-templates/service.js";
9
- import { onInvalid, problem, titleOf } from "./problem.js";
9
+ import { templateGate } from "../../slices/template-studio/schedule-gate.js";
10
+ import { onInvalid, problem } from "./problem.js";
11
+ import { refusal } from "./refusal.js";
10
12
  const param = z.object({ id: z.uuid() });
13
+ // The JSON bodies; the id or project the path names is not part of them.
14
+ export const templateFromProjectBody = templateFromProjectSchema.unwrap().omit({ projectId: true });
15
+ export const nextChapterBody = nextChapterSchema.unwrap().omit({ projectId: true });
16
+ export const templateUpdateBody = templateUpdateSchema.unwrap().omit({ id: true });
17
+ export const templateDeleteBody = templateDeleteSchema.unwrap().omit({ id: true });
18
+ export const templateInstantiateBody = templateInstantiateSchema
19
+ .unwrap()
20
+ .omit({ templateId: true });
11
21
  function refused(c, result) {
12
- const status = result.reason === "not-found"
13
- ? 404
14
- : ["conflict", "referenced-by-schedule"].includes(result.reason)
15
- ? 409
16
- : 400;
17
- return problem(c, {
18
- status,
19
- title: titleOf(status),
22
+ return refusal(c, result.reason, {
23
+ statuses: { "not-found": 404, conflict: 409, "referenced-by-schedule": 409 },
24
+ otherwise: 400,
20
25
  detail: result.reason === "referenced-by-schedule"
21
26
  ? "Some schedules still use this template. In Library > Schedules, cancel and delete them first; their run history is kept."
22
27
  : result.reason === "missing-prompt"
@@ -26,7 +31,6 @@ function refused(c, result) {
26
31
  : result.reason === "conflict"
27
32
  ? "This template or its project changed while you were editing. Reload the page to see the latest, then make your change again."
28
33
  : "Some template settings are not valid, for example an image you supplied yourself. Check the template's settings and try again.",
29
- extensions: { reason: result.reason },
30
34
  });
31
35
  }
32
36
  export function projectTemplateRoutes(deps) {
@@ -39,8 +43,17 @@ function routes(deps) {
39
43
  return deps;
40
44
  };
41
45
  return (new Hono()
42
- .get("/", (c) => c.json({ templates: listTemplates(service()) }))
43
- .post("/from-project/:projectId", zValidator("param", templateFromProjectSchema.unwrap().pick({ projectId: true }), onInvalid), zValidator("json", templateFromProjectSchema.unwrap().omit({ projectId: true }), onInvalid), (c) => {
46
+ // Each with the version its schedules run (`template-studio/schedule-gate.ts`).
47
+ .get("/", (c) => {
48
+ const db = service().db;
49
+ return c.json({
50
+ templates: listTemplates(service()).map((template) => {
51
+ const gate = templateGate(db, template.id);
52
+ return gate === undefined ? template : { ...template, gate };
53
+ }),
54
+ });
55
+ })
56
+ .post("/from-project/:projectId", zValidator("param", templateFromProjectSchema.unwrap().pick({ projectId: true }), onInvalid), zValidator("json", templateFromProjectBody, onInvalid), (c) => {
44
57
  const result = createTemplateFromProject(service(), {
45
58
  ...c.req.valid("json"),
46
59
  projectId: c.req.valid("param").projectId,
@@ -48,7 +61,7 @@ function routes(deps) {
48
61
  return result.ok ? c.json(result.value, 201) : refused(c, result);
49
62
  })
50
63
  // A finished audiobook chapter's "Make the next chapter": a new Play draft for the book.
51
- .post("/next-chapter/:projectId", zValidator("param", nextChapterSchema.unwrap().pick({ projectId: true }), onInvalid), zValidator("json", nextChapterSchema.unwrap().omit({ projectId: true }), onInvalid), (c) => {
64
+ .post("/next-chapter/:projectId", zValidator("param", nextChapterSchema.unwrap().pick({ projectId: true }), onInvalid), zValidator("json", nextChapterBody, onInvalid), (c) => {
52
65
  const result = makeNextChapter(service(), {
53
66
  ...c.req.valid("json"),
54
67
  projectId: c.req.valid("param").projectId,
@@ -58,7 +71,6 @@ function routes(deps) {
58
71
  const status = result.reason === "not-found" ? 404 : result.reason === "conflict" ? 409 : 400;
59
72
  return problem(c, {
60
73
  status,
61
- title: titleOf(status),
62
74
  detail: result.message,
63
75
  extensions: { reason: result.reason },
64
76
  });
@@ -71,21 +83,21 @@ function routes(deps) {
71
83
  const result = readTemplate(service(), c.req.valid("param").id, c.req.valid("query").version);
72
84
  return result.ok ? c.json(result.value) : refused(c, result);
73
85
  })
74
- .put("/:id", zValidator("param", param, onInvalid), zValidator("json", templateUpdateSchema.unwrap().omit({ id: true }), onInvalid), (c) => {
86
+ .put("/:id", zValidator("param", param, onInvalid), zValidator("json", templateUpdateBody, onInvalid), (c) => {
75
87
  const result = updateTemplate(service(), {
76
88
  ...c.req.valid("json"),
77
89
  id: c.req.valid("param").id,
78
90
  });
79
91
  return result.ok ? c.json(result.value) : refused(c, result);
80
92
  })
81
- .delete("/:id", zValidator("param", param, onInvalid), zValidator("json", templateDeleteSchema.unwrap().omit({ id: true }), onInvalid), (c) => {
93
+ .delete("/:id", zValidator("param", param, onInvalid), zValidator("json", templateDeleteBody, onInvalid), (c) => {
82
94
  const result = deleteTemplate(service(), {
83
95
  ...c.req.valid("json"),
84
96
  id: c.req.valid("param").id,
85
97
  });
86
98
  return result.ok ? c.json(result.value) : refused(c, result);
87
99
  })
88
- .post("/:id/instantiate", zValidator("param", param, onInvalid), zValidator("json", templateInstantiateSchema.unwrap().omit({ templateId: true }), onInvalid), (c) => {
100
+ .post("/:id/instantiate", zValidator("param", param, onInvalid), zValidator("json", templateInstantiateBody, onInvalid), (c) => {
89
101
  const result = instantiateTemplate(service(), {
90
102
  ...c.req.valid("json"),
91
103
  templateId: c.req.valid("param").id,
@@ -20,15 +20,9 @@ import { outputsOf } from "../../slices/storage/repo.js";
20
20
  import { trashProject } from "../../slices/trash/service.js";
21
21
  import { setAsideProjects, uploadedAndSettled, uploadedProjects, } from "../../slices/uploads/repo.js";
22
22
  import { settledStatus } from "../../slices/uploads/rules.js";
23
- import { onInvalid, problem, titleOf } from "./problem.js";
23
+ import { idParam } from "./ids.js";
24
+ import { onInvalid, problem } from "./problem.js";
24
25
  import { createProject } from "./project-create.js";
25
- const idParam = z.object({
26
- id: z
27
- .string()
28
- .min(1)
29
- .max(64)
30
- .regex(/^[0-9A-Za-z_-]+$/),
31
- });
32
26
  // The return type is inferred so Hono keeps the route types the SPA's client is
33
27
  // generated from; see stagingRoutes.
34
28
  export function projectRoutes(deps) {
@@ -54,7 +48,6 @@ export function projectRoutes(deps) {
54
48
  if (!created.ok)
55
49
  return problem(c, {
56
50
  status: created.status,
57
- title: titleOf(created.status),
58
51
  detail: created.detail,
59
52
  ...(created.fields.length === 0 ? {} : { extensions: { fields: created.fields } }),
60
53
  });
@@ -106,7 +99,6 @@ export function projectRoutes(deps) {
106
99
  if (project === undefined) {
107
100
  return problem(c, {
108
101
  status: 404,
109
- title: titleOf(404),
110
102
  detail: projectTrashed(deps.db, c.req.valid("param").id)
111
103
  ? "This project is in the trash. Restore it in Settings → Trash to open it again."
112
104
  : "This project no longer exists. Go back to Projects to pick another.",
@@ -152,7 +144,6 @@ export function projectRoutes(deps) {
152
144
  if (channelById(deps.db, channelId) === undefined)
153
145
  return problem(c, {
154
146
  status: 404,
155
- title: titleOf(404),
156
147
  detail: "That channel no longer exists. Reload the page and pick one from the list, or make it again in Channels.",
157
148
  });
158
149
  const live = new Set(listProjectHeads(deps.db).map((project) => project.id));
@@ -172,7 +163,6 @@ export function projectRoutes(deps) {
172
163
  const status = result.reason === "running" ? 409 : 404;
173
164
  return problem(c, {
174
165
  status,
175
- title: titleOf(status),
176
166
  detail: result.reason === "running"
177
167
  ? "This project is still running. Use Cancel run on the project page first, then delete it."
178
168
  : "This project no longer exists. Go back to Projects to pick another.",
@@ -8,14 +8,8 @@ import { formerNames } from "../../slices/library/rename.js";
8
8
  import { listPrompts, promptById } from "../../slices/library/repo.js";
9
9
  import { createPrompt, removePrompt, restorePrompt, updatePrompt, } from "../../slices/library/save.js";
10
10
  import { usedBy } from "../../slices/library/used-by.js";
11
- import { onInvalid, problem, titleOf } from "./problem.js";
12
- const idParam = z.object({
13
- id: z
14
- .string()
15
- .min(1)
16
- .max(64)
17
- .regex(/^[0-9A-Za-z_-]+$/),
18
- });
11
+ import { idParam } from "./ids.js";
12
+ import { onInvalid, problem } from "./problem.js";
19
13
  // History's Restore names the version by its number.
20
14
  export const versionParam = idParam.extend({ version: z.coerce.number().int().positive() });
21
15
  // Shape only. The rules - trimming, emptiness, length, the slot lint - are the slice's,
@@ -25,6 +19,8 @@ const promptBody = z.object({
25
19
  name: z.string(),
26
20
  body: z.string(),
27
21
  });
22
+ // Duplicate names the prompt it copies, whose old keyword names the copy may keep.
23
+ const promptCreateBody = promptBody.extend({ copyOf: z.string().min(1).max(100).optional() });
28
24
  // The return type is inferred so Hono keeps the route types the SPA's client is
29
25
  // generated from; see stagingRoutes.
30
26
  export function promptRoutes(deps) {
@@ -33,8 +29,9 @@ export function promptRoutes(deps) {
33
29
  // Every kind in one list: 04 Prompts filters by tab, and Duplicate needs the body it
34
30
  // is copying.
35
31
  .get("/", (c) => c.json({ prompts: withPhotorealistic(deps.db, listPrompts(deps.db)) }))
36
- .post("/", zValidator("json", promptBody, onInvalid), (c) => {
37
- const result = createPrompt(library, c.req.valid("json"));
32
+ .post("/", zValidator("json", promptCreateBody, onInvalid), (c) => {
33
+ const { copyOf, ...draft } = c.req.valid("json");
34
+ const result = createPrompt(library, draft, copyOf);
38
35
  return result.ok ? c.json(result.value, 201) : refused(c, result, "prompt");
39
36
  })
40
37
  .put("/:id", zValidator("param", idParam, onInvalid), zValidator("json", promptBody, onInvalid), (c) => {
@@ -50,7 +47,6 @@ export function promptRoutes(deps) {
50
47
  ? refused(c, { ok: false, reason: "not-found" }, "prompt")
51
48
  : problem(c, {
52
49
  status: 400,
53
- title: titleOf(400),
54
50
  detail: "Only an Image prompt can be marked photorealistic. Open the prompt from the Image tab in Library → Prompts.",
55
51
  });
56
52
  })
@@ -87,7 +83,6 @@ export function refused(c, failure, noun) {
87
83
  case "invalid":
88
84
  return problem(c, {
89
85
  status: 400,
90
- title: titleOf(400),
91
86
  detail: `This ${noun} cannot be saved yet. Fix the highlighted fields and try again.`,
92
87
  extensions: { fields: failure.fields },
93
88
  });
@@ -95,7 +90,6 @@ export function refused(c, failure, noun) {
95
90
  case "duplicate-name":
96
91
  return problem(c, {
97
92
  status: 409,
98
- title: titleOf(409),
99
93
  detail: `Another ${noun} already has this name. Choose a different name.`,
100
94
  extensions: {
101
95
  fields: [
@@ -109,7 +103,6 @@ export function refused(c, failure, noun) {
109
103
  case "not-found":
110
104
  return problem(c, {
111
105
  status: 404,
112
- title: titleOf(404),
113
106
  detail: `This ${noun} no longer exists; it may have been deleted. Go back to the Library to pick another.`,
114
107
  });
115
108
  }
@@ -4,7 +4,7 @@ import { z } from "zod";
4
4
  import { aliasCountMax } from "../../kernel/ports/narration-aliases.js";
5
5
  import { listNarrationAliases, saveNarrationAliases, } from "../../slices/narration/aliases-library.js";
6
6
  import { collectSharedGlossary } from "../../slices/narration/shared-glossary.js";
7
- import { onInvalid, problem, titleOf } from "./problem.js";
7
+ import { onInvalid, problem } from "./problem.js";
8
8
  // The pronunciations of every project's glossary, merged, for Edit project to copy into a
9
9
  // project that shares them. `except` leaves out the project being edited, whose own glossary
10
10
  // already comes first. Library → Aliases lives here too: the other way to change how a word
@@ -28,7 +28,6 @@ export function pronunciationRoutes(deps) {
28
28
  return c.json({ aliases: result.aliases });
29
29
  return problem(c, {
30
30
  status: 400,
31
- title: titleOf(400),
32
31
  detail: `These aliases can't be saved yet: ${result.fields.map((field) => field.message).join(" ")}`,
33
32
  extensions: { fields: result.fields },
34
33
  });