@skyphusion-labs/vivijure-core 0.9.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 (267) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +87 -0
  3. package/dist/audio-routing.d.ts +2 -0
  4. package/dist/audio-routing.d.ts.map +1 -0
  5. package/dist/audio-routing.js +4 -0
  6. package/dist/audio-routing.js.map +1 -0
  7. package/dist/audio-stage.d.ts +4 -0
  8. package/dist/audio-stage.d.ts.map +1 -0
  9. package/dist/audio-stage.js +25 -0
  10. package/dist/audio-stage.js.map +1 -0
  11. package/dist/beat-analyze.d.ts +22 -0
  12. package/dist/beat-analyze.d.ts.map +1 -0
  13. package/dist/beat-analyze.js +111 -0
  14. package/dist/beat-analyze.js.map +1 -0
  15. package/dist/beat-sync-types.d.ts +33 -0
  16. package/dist/beat-sync-types.d.ts.map +1 -0
  17. package/dist/beat-sync-types.js +4 -0
  18. package/dist/beat-sync-types.js.map +1 -0
  19. package/dist/bundle-assembler.d.ts +54 -0
  20. package/dist/bundle-assembler.d.ts.map +1 -0
  21. package/dist/bundle-assembler.js +376 -0
  22. package/dist/bundle-assembler.js.map +1 -0
  23. package/dist/bundle-durations.d.ts +5 -0
  24. package/dist/bundle-durations.d.ts.map +1 -0
  25. package/dist/bundle-durations.js +68 -0
  26. package/dist/bundle-durations.js.map +1 -0
  27. package/dist/bundle-storyboard.d.ts +11 -0
  28. package/dist/bundle-storyboard.d.ts.map +1 -0
  29. package/dist/bundle-storyboard.js +82 -0
  30. package/dist/bundle-storyboard.js.map +1 -0
  31. package/dist/captions.d.ts +25 -0
  32. package/dist/captions.d.ts.map +1 -0
  33. package/dist/captions.js +56 -0
  34. package/dist/captions.js.map +1 -0
  35. package/dist/cast-db.d.ts +61 -0
  36. package/dist/cast-db.d.ts.map +1 -0
  37. package/dist/cast-db.js +324 -0
  38. package/dist/cast-db.js.map +1 -0
  39. package/dist/cast-lora-train.d.ts +18 -0
  40. package/dist/cast-lora-train.d.ts.map +1 -0
  41. package/dist/cast-lora-train.js +215 -0
  42. package/dist/cast-lora-train.js.map +1 -0
  43. package/dist/cast-loras.d.ts +21 -0
  44. package/dist/cast-loras.d.ts.map +1 -0
  45. package/dist/cast-loras.js +69 -0
  46. package/dist/cast-loras.js.map +1 -0
  47. package/dist/clip-content-validate.d.ts +43 -0
  48. package/dist/clip-content-validate.d.ts.map +1 -0
  49. package/dist/clip-content-validate.js +115 -0
  50. package/dist/clip-content-validate.js.map +1 -0
  51. package/dist/clip-job-model.d.ts +42 -0
  52. package/dist/clip-job-model.d.ts.map +1 -0
  53. package/dist/clip-job-model.js +8 -0
  54. package/dist/clip-job-model.js.map +1 -0
  55. package/dist/clip-validate.d.ts +33 -0
  56. package/dist/clip-validate.d.ts.map +1 -0
  57. package/dist/clip-validate.js +247 -0
  58. package/dist/clip-validate.js.map +1 -0
  59. package/dist/d1-retry.d.ts +20 -0
  60. package/dist/d1-retry.d.ts.map +1 -0
  61. package/dist/d1-retry.js +67 -0
  62. package/dist/d1-retry.js.map +1 -0
  63. package/dist/db-env.d.ts +6 -0
  64. package/dist/db-env.d.ts.map +1 -0
  65. package/dist/db-env.js +2 -0
  66. package/dist/db-env.js.map +1 -0
  67. package/dist/dialogue-lines.d.ts +23 -0
  68. package/dist/dialogue-lines.d.ts.map +1 -0
  69. package/dist/dialogue-lines.js +84 -0
  70. package/dist/dialogue-lines.js.map +1 -0
  71. package/dist/film-advance-lease.d.ts +9 -0
  72. package/dist/film-advance-lease.d.ts.map +1 -0
  73. package/dist/film-advance-lease.js +19 -0
  74. package/dist/film-advance-lease.js.map +1 -0
  75. package/dist/film-model.d.ts +415 -0
  76. package/dist/film-model.d.ts.map +1 -0
  77. package/dist/film-model.js +541 -0
  78. package/dist/film-model.js.map +1 -0
  79. package/dist/film-orchestrator.d.ts +216 -0
  80. package/dist/film-orchestrator.d.ts.map +1 -0
  81. package/dist/film-orchestrator.js +2204 -0
  82. package/dist/film-orchestrator.js.map +1 -0
  83. package/dist/film-render-bridge.d.ts +26 -0
  84. package/dist/film-render-bridge.d.ts.map +1 -0
  85. package/dist/film-render-bridge.js +176 -0
  86. package/dist/film-render-bridge.js.map +1 -0
  87. package/dist/finish-hash.d.ts +10 -0
  88. package/dist/finish-hash.d.ts.map +1 -0
  89. package/dist/finish-hash.js +60 -0
  90. package/dist/finish-hash.js.map +1 -0
  91. package/dist/index.d.ts +48 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +45 -0
  94. package/dist/index.js.map +1 -0
  95. package/dist/key-safety.d.ts +5 -0
  96. package/dist/key-safety.d.ts.map +1 -0
  97. package/dist/key-safety.js +23 -0
  98. package/dist/key-safety.js.map +1 -0
  99. package/dist/lora-bundle.d.ts +19 -0
  100. package/dist/lora-bundle.d.ts.map +1 -0
  101. package/dist/lora-bundle.js +75 -0
  102. package/dist/lora-bundle.js.map +1 -0
  103. package/dist/lora-keys.d.ts +2 -0
  104. package/dist/lora-keys.d.ts.map +1 -0
  105. package/dist/lora-keys.js +4 -0
  106. package/dist/lora-keys.js.map +1 -0
  107. package/dist/modules/conformance.d.ts +58 -0
  108. package/dist/modules/conformance.d.ts.map +1 -0
  109. package/dist/modules/conformance.js +369 -0
  110. package/dist/modules/conformance.js.map +1 -0
  111. package/dist/modules/manifest-validate.d.ts +5 -0
  112. package/dist/modules/manifest-validate.d.ts.map +1 -0
  113. package/dist/modules/manifest-validate.js +60 -0
  114. package/dist/modules/manifest-validate.js.map +1 -0
  115. package/dist/modules/registry.d.ts +184 -0
  116. package/dist/modules/registry.d.ts.map +1 -0
  117. package/dist/modules/registry.js +653 -0
  118. package/dist/modules/registry.js.map +1 -0
  119. package/dist/modules/render-pipeline.d.ts +38 -0
  120. package/dist/modules/render-pipeline.d.ts.map +1 -0
  121. package/dist/modules/render-pipeline.js +40 -0
  122. package/dist/modules/render-pipeline.js.map +1 -0
  123. package/dist/modules/types.d.ts +544 -0
  124. package/dist/modules/types.d.ts.map +1 -0
  125. package/dist/modules/types.js +57 -0
  126. package/dist/modules/types.js.map +1 -0
  127. package/dist/operator-config.d.ts +20 -0
  128. package/dist/operator-config.d.ts.map +1 -0
  129. package/dist/operator-config.js +85 -0
  130. package/dist/operator-config.js.map +1 -0
  131. package/dist/output-extract.d.ts +8 -0
  132. package/dist/output-extract.d.ts.map +1 -0
  133. package/dist/output-extract.js +129 -0
  134. package/dist/output-extract.js.map +1 -0
  135. package/dist/planner-prompt.d.ts +12 -0
  136. package/dist/planner-prompt.d.ts.map +1 -0
  137. package/dist/planner-prompt.js +337 -0
  138. package/dist/planner-prompt.js.map +1 -0
  139. package/dist/planner-yaml.d.ts +15 -0
  140. package/dist/planner-yaml.d.ts.map +1 -0
  141. package/dist/planner-yaml.js +157 -0
  142. package/dist/planner-yaml.js.map +1 -0
  143. package/dist/platform/fetcher.d.ts +3 -0
  144. package/dist/platform/fetcher.d.ts.map +1 -0
  145. package/dist/platform/fetcher.js +7 -0
  146. package/dist/platform/fetcher.js.map +1 -0
  147. package/dist/platform/index.d.ts +6 -0
  148. package/dist/platform/index.d.ts.map +1 -0
  149. package/dist/platform/index.js +5 -0
  150. package/dist/platform/index.js.map +1 -0
  151. package/dist/platform/object-store-r2.d.ts +26 -0
  152. package/dist/platform/object-store-r2.d.ts.map +1 -0
  153. package/dist/platform/object-store-r2.js +74 -0
  154. package/dist/platform/object-store-r2.js.map +1 -0
  155. package/dist/platform/orchestrator-context.d.ts +20 -0
  156. package/dist/platform/orchestrator-context.d.ts.map +1 -0
  157. package/dist/platform/orchestrator-context.js +28 -0
  158. package/dist/platform/orchestrator-context.js.map +1 -0
  159. package/dist/platform/r2-types.d.ts +41 -0
  160. package/dist/platform/r2-types.d.ts.map +1 -0
  161. package/dist/platform/r2-types.js +3 -0
  162. package/dist/platform/r2-types.js.map +1 -0
  163. package/dist/platform/types.d.ts +90 -0
  164. package/dist/platform/types.d.ts.map +1 -0
  165. package/dist/platform/types.js +23 -0
  166. package/dist/platform/types.js.map +1 -0
  167. package/dist/preflight.d.ts +57 -0
  168. package/dist/preflight.d.ts.map +1 -0
  169. package/dist/preflight.js +243 -0
  170. package/dist/preflight.js.map +1 -0
  171. package/dist/presign.d.ts +5 -0
  172. package/dist/presign.d.ts.map +1 -0
  173. package/dist/presign.js +24 -0
  174. package/dist/presign.js.map +1 -0
  175. package/dist/public-id.d.ts +8 -0
  176. package/dist/public-id.d.ts.map +1 -0
  177. package/dist/public-id.js +25 -0
  178. package/dist/public-id.js.map +1 -0
  179. package/dist/render-adopt.d.ts +3 -0
  180. package/dist/render-adopt.d.ts.map +1 -0
  181. package/dist/render-adopt.js +92 -0
  182. package/dist/render-adopt.js.map +1 -0
  183. package/dist/render-log.d.ts +25 -0
  184. package/dist/render-log.d.ts.map +1 -0
  185. package/dist/render-log.js +139 -0
  186. package/dist/render-log.js.map +1 -0
  187. package/dist/render-module-config.d.ts +28 -0
  188. package/dist/render-module-config.d.ts.map +1 -0
  189. package/dist/render-module-config.js +124 -0
  190. package/dist/render-module-config.js.map +1 -0
  191. package/dist/render-mux.d.ts +18 -0
  192. package/dist/render-mux.d.ts.map +1 -0
  193. package/dist/render-mux.js +69 -0
  194. package/dist/render-mux.js.map +1 -0
  195. package/dist/render-orchestrator.d.ts +71 -0
  196. package/dist/render-orchestrator.d.ts.map +1 -0
  197. package/dist/render-orchestrator.js +376 -0
  198. package/dist/render-orchestrator.js.map +1 -0
  199. package/dist/render-sweep.d.ts +5 -0
  200. package/dist/render-sweep.d.ts.map +1 -0
  201. package/dist/render-sweep.js +62 -0
  202. package/dist/render-sweep.js.map +1 -0
  203. package/dist/renders-db.d.ts +129 -0
  204. package/dist/renders-db.d.ts.map +1 -0
  205. package/dist/renders-db.js +752 -0
  206. package/dist/renders-db.js.map +1 -0
  207. package/dist/runpod-submit.d.ts +151 -0
  208. package/dist/runpod-submit.d.ts.map +1 -0
  209. package/dist/runpod-submit.js +469 -0
  210. package/dist/runpod-submit.js.map +1 -0
  211. package/dist/runpod-types.d.ts +2 -0
  212. package/dist/runpod-types.d.ts.map +1 -0
  213. package/dist/runpod-types.js +4 -0
  214. package/dist/runpod-types.js.map +1 -0
  215. package/dist/scatter-notify.d.ts +4 -0
  216. package/dist/scatter-notify.d.ts.map +1 -0
  217. package/dist/scatter-notify.js +43 -0
  218. package/dist/scatter-notify.js.map +1 -0
  219. package/dist/scatter-orchestrator-types.d.ts +56 -0
  220. package/dist/scatter-orchestrator-types.d.ts.map +1 -0
  221. package/dist/scatter-orchestrator-types.js +3 -0
  222. package/dist/scatter-orchestrator-types.js.map +1 -0
  223. package/dist/scatter-orchestrator.d.ts +70 -0
  224. package/dist/scatter-orchestrator.d.ts.map +1 -0
  225. package/dist/scatter-orchestrator.js +614 -0
  226. package/dist/scatter-orchestrator.js.map +1 -0
  227. package/dist/scatter.d.ts +35 -0
  228. package/dist/scatter.d.ts.map +1 -0
  229. package/dist/scatter.js +171 -0
  230. package/dist/scatter.js.map +1 -0
  231. package/dist/secret-store.d.ts +5 -0
  232. package/dist/secret-store.d.ts.map +1 -0
  233. package/dist/secret-store.js +19 -0
  234. package/dist/secret-store.js.map +1 -0
  235. package/dist/shot-durations-parse.d.ts +3 -0
  236. package/dist/shot-durations-parse.d.ts.map +1 -0
  237. package/dist/shot-durations-parse.js +43 -0
  238. package/dist/shot-durations-parse.js.map +1 -0
  239. package/dist/srt.d.ts +11 -0
  240. package/dist/srt.d.ts.map +1 -0
  241. package/dist/srt.js +54 -0
  242. package/dist/srt.js.map +1 -0
  243. package/dist/storyboard-ids.d.ts +2 -0
  244. package/dist/storyboard-ids.d.ts.map +1 -0
  245. package/dist/storyboard-ids.js +12 -0
  246. package/dist/storyboard-ids.js.map +1 -0
  247. package/dist/storyboard-projects-db.d.ts +31 -0
  248. package/dist/storyboard-projects-db.d.ts.map +1 -0
  249. package/dist/storyboard-projects-db.js +153 -0
  250. package/dist/storyboard-projects-db.js.map +1 -0
  251. package/dist/storyboard-validate.d.ts +72 -0
  252. package/dist/storyboard-validate.d.ts.map +1 -0
  253. package/dist/storyboard-validate.js +595 -0
  254. package/dist/storyboard-validate.js.map +1 -0
  255. package/dist/structured-events.d.ts +6 -0
  256. package/dist/structured-events.d.ts.map +1 -0
  257. package/dist/structured-events.js +15 -0
  258. package/dist/structured-events.js.map +1 -0
  259. package/dist/tar.d.ts +9 -0
  260. package/dist/tar.d.ts.map +1 -0
  261. package/dist/tar.js +151 -0
  262. package/dist/tar.js.map +1 -0
  263. package/dist/voices.d.ts +12 -0
  264. package/dist/voices.d.ts.map +1 -0
  265. package/dist/voices.js +37 -0
  266. package/dist/voices.js.map +1 -0
  267. package/package.json +71 -0
@@ -0,0 +1,376 @@
1
+ // Render-execution orchestrator: drive the motion.backend module per shot, ASYNC (invoke -> poll)
2
+ // and ACROSS REQUESTS, so a Worker never holds a multi-minute generation. POST starts the job
3
+ // (resolves the chosen motion.backend module, submits each shot, persists the poll tokens to an R2
4
+ // job doc). GET advances it (polls the shots still pending; the module's /poll finalizes a clip to
5
+ // R2 on completion). The caller polls GET until `complete`. Keyframes arrive as URLs -- the GPU
6
+ // keyframe stage feeds them later; for now the clip stage stands alone.
7
+ //
8
+ // State is an R2 json per job. GET only polls shots still pending (done ones are not re-polled, so
9
+ // no re-download). For concurrency-safe progress a Durable Object is the upgrade; this MVP assumes
10
+ // the caller polls sequentially.
11
+ import { discoverModules, invokeModule, pollModule, cancelModule, resolveFetcher, servingForHook, validateConfig, } from "./modules/registry.js";
12
+ import { hookOutputViolation } from "./modules/conformance.js";
13
+ import { emitStructuredEvent } from "./structured-events.js";
14
+ import { summarizeJob, } from "./clip-job-model.js";
15
+ import { validateClipArtifact } from "./clip-validate.js";
16
+ export { summarizeJob };
17
+ const jobKey = (jobId) => `renders/${jobId}/clips-job.json`;
18
+ /** Pure: aggregate the per-shot failure reasons into one honest string (#754). */
19
+ export function describeClipFailures(job) {
20
+ const failed = job.shots.filter((s) => s.status === "failed");
21
+ if (!failed.length)
22
+ return "";
23
+ return failed.map((s) => `${s.shot_id}: ${s.error || "unknown error"}`).join("; ");
24
+ }
25
+ /** Pure: is a poll/invoke error TRANSIENT or DETERMINISTIC? Shared classifier (#719). */
26
+ export function classifyTransientFailure(error) {
27
+ const e = error ?? "";
28
+ const m = e.match(/->\s*(\d{3})\b/);
29
+ if (m) {
30
+ const s = Number(m[1]);
31
+ return s === 408 || s === 429 || (s >= 500 && s <= 599) ? "transient" : "deterministic";
32
+ }
33
+ if (/unreachable|timed? ?out|timeout|network|econnreset|connection (reset|lost)|fetch failed/i.test(e)) {
34
+ return "transient";
35
+ }
36
+ return "deterministic";
37
+ }
38
+ /** Consecutive transient poll errors a clip shot tolerates before failing loud (#719). */
39
+ export const CLIP_POLL_MAX_ATTEMPTS = 3;
40
+ /** Apply a /poll outcome to a shot (pure): failure -> failed; still pending -> unchanged; output ->
41
+ * done with the clip key. */
42
+ export function applyPoll(shot, r) {
43
+ if (!r.ok) {
44
+ // #719: one TRANSIENT poll failure must not STICKILY fail a healthy in-flight render. Mirror the
45
+ // finish chain's bounded-attempts contract: tolerate up to CLIP_POLL_MAX_ATTEMPTS CONSECUTIVE
46
+ // transient errors (the shot stays pending; the next sweep re-polls; any successful poll resets
47
+ // the count), then fail loud with the real error. A DETERMINISTIC module-reported failure still
48
+ // fails immediately.
49
+ if (classifyTransientFailure(r.error) === "transient") {
50
+ const attempts = (shot.poll_attempts ?? 0) + 1;
51
+ if (attempts < CLIP_POLL_MAX_ATTEMPTS) {
52
+ shot.poll_attempts = attempts;
53
+ return; // stays pending; re-polled next sweep
54
+ }
55
+ shot.status = "failed";
56
+ shot.error = `${r.error} (persisted through ${attempts} consecutive polls, #719)`;
57
+ return;
58
+ }
59
+ shot.status = "failed";
60
+ shot.error = r.error;
61
+ return;
62
+ }
63
+ if (r.pending) {
64
+ if (shot.poll_attempts)
65
+ shot.poll_attempts = 0; // a successful round-trip resets the blip budget
66
+ return; // still running
67
+ }
68
+ const output = r.output;
69
+ const violation = hookOutputViolation(shot.motion_backend ?? "motion.backend", "motion.backend", output);
70
+ if (violation) {
71
+ shot.status = "failed";
72
+ shot.error = violation;
73
+ return;
74
+ } // envelope-ok but off-contract: fail loud, never advance garbage
75
+ shot.status = "done";
76
+ shot.clip_key = output.clip_key;
77
+ // #707: retain what the backend delivered so the film summary can show delivered-vs-planned. The
78
+ // contract has always carried fps+frames; modules with nothing to report send frames=0 (sentinel) --
79
+ // treat that as absent rather than recording a fabricated 0-frame delivery.
80
+ if (typeof output.fps === "number" && output.fps > 0 && typeof output.frames === "number" && output.frames > 0) {
81
+ shot.delivered_fps = output.fps;
82
+ shot.delivered_frames = output.frames;
83
+ }
84
+ // #705: tier honesty rides the same channel, independent of the duration numbers.
85
+ if (typeof output.distilled === "boolean")
86
+ shot.distilled = output.distilled;
87
+ }
88
+ /** Pure: does an R2 clips-object filename belong to this shot? The backend writes a finished motion clip
89
+ * per shot under `renders/<project>/clips/`, named with the shot id followed by a NON-digit separator
90
+ * (e.g. `shot_09_i2v.mp4`, `shot_09_seedance.mp4`). Match the shot id only at a digit boundary so
91
+ * `shot_1` never swallows `shot_10`; exclude `_finished*` (finish-chain outputs, not motion clips);
92
+ * require a video extension. Matches by shot-id boundary, NOT the backend's exact slug, so it stays
93
+ * independent of the backend naming convention (the core never hardcodes where the backend wrote). */
94
+ export function clipFileMatchesShot(file, shotId) {
95
+ if (!file.startsWith(shotId))
96
+ return false;
97
+ const rest = file.slice(shotId.length);
98
+ if (rest.length === 0)
99
+ return false; // need a separator + extension
100
+ if (/^\d/.test(rest))
101
+ return false; // digit boundary: shot_1 must not match shot_10...
102
+ if (/(^|[._-])finished([._-]|$)/i.test(rest))
103
+ return false; // finish-chain output, not a motion clip
104
+ return /\.(mp4|mov|webm|mkv)$/i.test(file); // a video file
105
+ }
106
+ /** Pure: does an R2 clips-object filename belong to this shot's FINISH-chain output? The finish modules
107
+ * write `renders/<project>/clips/<shot_id>_finished.mp4`. Same shot-id digit boundary as the motion-clip
108
+ * matcher, but here the `_finished` marker is REQUIRED (it is the finish output, not the raw motion clip)
109
+ * and a video extension is required. Matches by boundary + the `finished` marker, not a hardcoded full
110
+ * slug, so it stays independent of the backend convention. */
111
+ export function finishedClipFileMatchesShot(file, shotId) {
112
+ if (!file.startsWith(shotId))
113
+ return false;
114
+ const rest = file.slice(shotId.length);
115
+ if (/^\d/.test(rest))
116
+ return false; // digit boundary: shot_1 must not match shot_10...
117
+ if (!/(^|[._-])finished([._-]|$)/i.test(rest))
118
+ return false; // MUST be a finish-chain output
119
+ return /\.(mp4|mov|webm|mkv)$/i.test(file);
120
+ }
121
+ /** Map shot_id -> R2 key for the objects under `renders/<project>/clips/` that match `matches` (by shot-id
122
+ * boundary). Makes R2 PRESENCE the authority on completion: an artifact in R2 beats a module's poll
123
+ * verdict (the backend wrote it even if its RunPod job was later GC'd and the module fast-failed the
124
+ * poll; issue #141). `matches` selects the raw motion clip (default) or the finish output. Only the
125
+ * requested shot ids are returned. */
126
+ export async function listClipsByShotId(env, project, shotIds, matches = clipFileMatchesShot, minUploadedMs = 0) {
127
+ const prefix = `renders/${project}/clips/`;
128
+ const found = new Map(); // shot_id -> key (first match wins)
129
+ let cursor;
130
+ do {
131
+ const listed = await env.R2_RENDERS.list({ prefix, cursor, limit: 1000 });
132
+ for (const o of listed.objects) {
133
+ // Freshness guard (#661): when a floor is set, skip any clip written BEFORE this run started. A prior
134
+ // render of the same project name leaves clips at the identical renders/<project>/clips/<shot>_<backend>
135
+ // path; without this the stall/fail reclaim adopts a 4-day-old clip and ships wrong content silently
136
+ // (the #245/#249 class). This run own clips always upload AFTER the job created_at, so the legit #141
137
+ // reclaim survives. R2Object.uploaded is a Date; job stamps are epoch ms -- normalize explicitly.
138
+ if (minUploadedMs && o.uploaded.getTime() < minUploadedMs)
139
+ continue;
140
+ const file = o.key.slice(prefix.length);
141
+ for (const shotId of shotIds) {
142
+ if (!found.has(shotId) && matches(file, shotId))
143
+ found.set(shotId, o.key);
144
+ }
145
+ }
146
+ cursor = listed.truncated ? listed.cursor : undefined;
147
+ } while (cursor);
148
+ return found;
149
+ }
150
+ /** Start a clip job: resolve the motion.backend module per shot, submit, persist poll tokens. */
151
+ export async function startClipJob(env, args, preModules) {
152
+ const envRec = env;
153
+ const modules = preModules ?? await discoverModules(envRec);
154
+ const serving = servingForHook(modules, "motion.backend");
155
+ const defaultMb = args.motion_backend
156
+ ? serving.find((m) => m.name === args.motion_backend) ?? null
157
+ : serving[0] ?? null;
158
+ const moduleConfigs = args.module_configs ?? {};
159
+ const defaultConfig = defaultMb
160
+ ? validateConfig(defaultMb.config_schema, args.config ?? moduleConfigs[defaultMb.name])
161
+ : {};
162
+ const job_id = "clips-" + crypto.randomUUID();
163
+ const shots = [];
164
+ for (const sh of args.shots) {
165
+ const shot = { ...sh, status: "pending" };
166
+ const mbName = sh.motion_backend ?? args.motion_backend ?? defaultMb?.name;
167
+ const mb = mbName ? serving.find((m) => m.name === mbName) ?? null : defaultMb;
168
+ const binding = mb ? mb.binding : null;
169
+ shot.binding = binding;
170
+ shot.motion_backend = mb?.name ?? undefined;
171
+ const fetcher = binding ? resolveFetcher(envRec, binding) : null;
172
+ const config = mb
173
+ ? validateConfig(mb.config_schema, moduleConfigs[mb.name] ?? (mb.name === defaultMb?.name ? args.config : undefined) ?? args.config)
174
+ : defaultConfig;
175
+ if (!mb || !fetcher) {
176
+ shot.status = "failed";
177
+ shot.error = mb ? `module ${mb.name} (${binding}) is not bound` : "no motion.backend module installed";
178
+ shots.push(shot);
179
+ continue;
180
+ }
181
+ const r = await invokeModule(fetcher, {
182
+ hook: "motion.backend",
183
+ input: { shot_id: sh.shot_id, keyframe_url: sh.keyframe_url, keyframe_key: sh.keyframe_key, prompt: sh.prompt, seconds: sh.seconds },
184
+ config,
185
+ context: { project: args.project, job_id },
186
+ });
187
+ if (!r.ok) {
188
+ shot.status = "failed";
189
+ shot.error = r.error;
190
+ }
191
+ else if (r.pending) {
192
+ shot.poll = r.poll;
193
+ shot.runpod_job_id = r.jobId; // #536: retain the backend job id for cancel/accounting
194
+ }
195
+ else if ("output" in r) {
196
+ const output = r.output;
197
+ const violation = hookOutputViolation(mb.name, "motion.backend", output);
198
+ if (violation) {
199
+ shot.status = "failed";
200
+ shot.error = violation;
201
+ }
202
+ else {
203
+ shot.status = "done";
204
+ shot.clip_key = output.clip_key;
205
+ }
206
+ }
207
+ else {
208
+ shot.status = "failed";
209
+ shot.error = "module returned neither output nor a poll token";
210
+ }
211
+ shots.push(shot);
212
+ }
213
+ const job = {
214
+ job_id,
215
+ project: args.project,
216
+ motion_backend: defaultMb ? defaultMb.name : null,
217
+ binding: defaultMb ? defaultMb.binding : null,
218
+ module_configs: Object.keys(moduleConfigs).length ? moduleConfigs : undefined,
219
+ shots,
220
+ created_at: Date.now(),
221
+ };
222
+ await env.R2_RENDERS.put(jobKey(job_id), JSON.stringify(job), { httpMetadata: { contentType: "application/json" } });
223
+ return job;
224
+ }
225
+ /** Advance a clip job: poll the shots still pending; the module finalizes a clip to R2 on done. */
226
+ export async function advanceClipJob(env, jobId, preModules) {
227
+ const obj = await env.R2_RENDERS.get(jobKey(jobId));
228
+ if (!obj)
229
+ return null;
230
+ const job = JSON.parse(await obj.text());
231
+ const envRec = env;
232
+ for (const shot of job.shots) {
233
+ if (shot.status !== "pending" || !shot.poll)
234
+ continue;
235
+ const binding = shot.binding ?? job.binding;
236
+ const fetcher = binding ? resolveFetcher(envRec, binding) : null;
237
+ if (!fetcher) {
238
+ shot.status = "failed";
239
+ shot.error = "module binding no longer bound";
240
+ continue;
241
+ }
242
+ const p = await pollModule(fetcher, { poll: shot.poll });
243
+ applyPoll(shot, p);
244
+ }
245
+ // R2 PRESENCE IS AUTHORITATIVE (issue #141): reclaim any FAILED shot whose clip is in R2 -- whether it
246
+ // failed this pass or a prior one -- so a #142 fast-fail can never drop a shot whose clip actually
247
+ // landed. Runs BEFORE the caller's summarizeJob() complete/advance judgment. (The caller also calls
248
+ // reclaimClipsFromR2 again right before its complete-check; both are idempotent + cheap.)
249
+ await reclaimClipsFromR2(env, job);
250
+ // #536: a shot still FAILED that had started a remote job (it held a poll token) may have left the RunPod
251
+ // job running -- fire a best-effort cancel so the backend does not keep burning GPU after the studio gave
252
+ // up (the 307s-of-H200 zombie observed on the S18 gate). reclaimClipsFromR2 ran first, so a shot whose
253
+ // clip actually landed is already done and skipped. A module without /cancel logs an honest orphan.
254
+ await cancelFailedShots(env, job, preModules);
255
+ await validateDoneClips(env, job); // #523 Layer 1: structural gate before the caller advances to finish/upscale spend
256
+ await env.R2_RENDERS.put(jobKey(jobId), JSON.stringify(job), { httpMetadata: { contentType: "application/json" } });
257
+ return job;
258
+ }
259
+ /** #536: fire a best-effort remote cancel for every shot that is FAILED, held a poll token (so a remote
260
+ * job was started), and has not been cancelled yet. Discovers the registry only when there IS an orphan to
261
+ * cancel (the happy path pays nothing); the film tick threads its once-discovered registry in. */
262
+ async function cancelFailedShots(env, job, preModules) {
263
+ const orphans = job.shots.filter((s) => s.status === "failed" && s.poll && !s.cancel_sent);
264
+ if (!orphans.length)
265
+ return;
266
+ const envRec = env;
267
+ const modules = preModules ?? await discoverModules(envRec);
268
+ for (const shot of orphans)
269
+ await cancelShotRemote(envRec, job, shot, modules);
270
+ }
271
+ /** #536: cancel ONE shot in-flight RunPod job via its motion module (cancelModule, keyed by the poll
272
+ * token, exactly as cancelInFlightKeyframe does for the keyframe phase). Records cancel_sent so it fires
273
+ * at most once, and NAMES the RunPod job in every orphan log so a left-running job is actionable. Mirrors
274
+ * the honest-orphan discipline: an unbound module or a module with no cancel primitive logs loudly, it
275
+ * never hides the leak. */
276
+ async function cancelShotRemote(envRec, job, shot, modules) {
277
+ const jobId = shot.runpod_job_id ?? "(job id unknown)";
278
+ const binding = shot.binding ?? job.binding;
279
+ const mb = binding ? (modules.find((m) => m.binding === binding) ?? null) : null;
280
+ const fetcher = binding ? resolveFetcher(envRec, binding) : null;
281
+ shot.cancel_sent = true; // best-effort ONCE, whatever the outcome -- never re-fire every tick
282
+ if (!mb || !fetcher) {
283
+ console.warn(`clip job ${job.job_id}: cannot cancel failed shot ${shot.shot_id} -- module ${binding ?? "?"} not bound; RunPod job ${jobId} left running (ORPHAN) (#536)`);
284
+ return;
285
+ }
286
+ if (!mb.cancelable) {
287
+ console.warn(`clip job ${job.job_id}: motion module ${mb.name} has no cancel primitive (cancelable=false); RunPod job ${jobId} for shot ${shot.shot_id} left running (ORPHAN) (#536)`);
288
+ return;
289
+ }
290
+ const r = await cancelModule(fetcher, { poll: shot.poll });
291
+ if (r.ok)
292
+ console.warn(`clip job ${job.job_id}: cancelled in-flight RunPod job ${jobId} for failed shot ${shot.shot_id} via ${mb.name} (#536)`);
293
+ else
294
+ console.warn(`clip job ${job.job_id}: cancel FAILED (${r.error}) for shot ${shot.shot_id} -- RunPod job ${jobId} left running (ORPHAN) (#536)`);
295
+ }
296
+ /** #536: teardown cancel -- STOP every in-flight (pending, poll-token-bearing) shot RunPod job when a clip
297
+ * job is cancelled/torn down, so a user-cancelled render does not leave the GPU running (the motion-phase
298
+ * sibling of cancelInFlightKeyframe; cancelFilmJob calls this off the clips phase). Persists cancel_sent.
299
+ * No-op when nothing is in flight. */
300
+ export async function cancelInFlightClips(env, jobId, preModules) {
301
+ const obj = await env.R2_RENDERS.get(jobKey(jobId));
302
+ if (!obj)
303
+ return;
304
+ const job = JSON.parse(await obj.text());
305
+ const inflight = job.shots.filter((s) => s.status === "pending" && s.poll && !s.cancel_sent);
306
+ if (!inflight.length)
307
+ return;
308
+ const envRec = env;
309
+ const modules = preModules ?? await discoverModules(envRec);
310
+ for (const shot of inflight)
311
+ await cancelShotRemote(envRec, job, shot, modules);
312
+ await env.R2_RENDERS.put(jobKey(jobId), JSON.stringify(job), { httpMetadata: { contentType: "application/json" } });
313
+ }
314
+ /** R2 PRESENCE IS THE SOURCE OF TRUTH for clip completion. Mutates the clip job in place: any shot that
315
+ * is NOT done but whose motion clip is present in R2 (matched by shot-id boundary) is marked done with
316
+ * that key (pending OR failed -- the artifact overrides a module's premature fast-fail; issue #141). A
317
+ * shot with no R2 clip is left as-is (a genuine non-render). Only lists R2 when there is at least one
318
+ * not-done shot to reclaim (the all-done happy path pays nothing). Returns the number adopted. This is
319
+ * the single reclaim used both inside advanceClipJob AND by the film orchestrator before it judges the
320
+ * clip job complete, so a fast-fail at 150s can never advance the film with a clip dropped. */
321
+ export async function reclaimClipsFromR2(env, job) {
322
+ const notDone = job.shots.filter((s) => s.status !== "done" && s.validated !== "fail");
323
+ if (!notDone.length)
324
+ return 0;
325
+ const present = await listClipsByShotId(env, job.project, notDone.map((s) => s.shot_id), clipFileMatchesShot, job.created_at);
326
+ let adopted = 0;
327
+ for (const shot of notDone) {
328
+ if (present.has(shot.shot_id)) {
329
+ shot.status = "done";
330
+ shot.clip_key = present.get(shot.shot_id);
331
+ shot.poll = undefined;
332
+ shot.error = undefined; // clear a premature failure; the artifact is the source of truth
333
+ shot.validated = undefined; // #523: re-validate the freshly-adopted artifact
334
+ adopted += 1;
335
+ }
336
+ }
337
+ return adopted;
338
+ }
339
+ /** #523 Layer 1: validate each newly-done clip's STRUCTURE (mp4 box tree) before the finish / dialogue /
340
+ * upscale chain spends anything. Engine-agnostic: every motion.backend clip (cloud backend, both local
341
+ * doors, any future module) funnels through this one chokepoint. Idempotent per shot via `validated`, so
342
+ * it runs at most once and can be called from more than one seam. A structural FAILURE flips the shot to
343
+ * failed with the real reason (honest-failure #245/#249: never a silent advance, never applied=[]) and
344
+ * clears its poll token so the orphan-cancel pass ignores a clip that already landed. A "skip" (artifact
345
+ * unreadable / validation disabled) leaves the shot untouched -- an I/O blip must never false-reject a
346
+ * real render. Emits one `clip.validate` structured event per shot (docs/observability.md) so smoke tests
347
+ * assert on the event, not prose. Returns true iff it changed any shot; the CALLER owns the job-doc write.
348
+ *
349
+ * HONEST SCOPE: this catches the STRUCTURAL-corruption class (truncated / empty / zero-frame /
350
+ * zero-duration / non-mp4). It does NOT catch the local-16gb#35 pure-noise clip, which is a structurally
351
+ * valid mp4 -- that needs a pixel decode (Layer 2, a video-finish-container pre-gate, filed separately). */
352
+ export async function validateDoneClips(env, job) {
353
+ let changed = false;
354
+ for (const shot of job.shots) {
355
+ if (shot.status !== "done" || !shot.clip_key || shot.validated)
356
+ continue;
357
+ const res = await validateClipArtifact(env, shot.clip_key, shot.seconds);
358
+ shot.validated = res.verdict;
359
+ emitStructuredEvent({
360
+ ev: "clip.validate",
361
+ job_id: job.job_id,
362
+ shot_id: shot.shot_id,
363
+ verdict: res.verdict,
364
+ checks: res.checks,
365
+ ...(res.reason ? { reason: res.reason } : {}),
366
+ });
367
+ if (res.verdict === "fail") {
368
+ shot.status = "failed";
369
+ shot.error = `clip failed output validation: ${res.reason}`;
370
+ shot.poll = undefined; // it already produced a (bad) artifact; do not fire an orphan cancel
371
+ changed = true;
372
+ }
373
+ }
374
+ return changed;
375
+ }
376
+ //# sourceMappingURL=render-orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-orchestrator.js","sourceRoot":"","sources":["../src/render-orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Env, ExecutionContext } from "./platform/orchestrator-context.js";
2
+ /** Max age for jobs the sweep still tries to resolve (24h, matches RunPod job TTL). */
3
+ export declare const SWEEP_MAX_AGE_SECONDS: number;
4
+ export declare function sweepUnresolvedJobs(env: Env, ctx?: ExecutionContext): Promise<number>;
5
+ //# sourceMappingURL=render-sweep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-sweep.d.ts","sourceRoot":"","sources":["../src/render-sweep.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAMhF,uFAAuF;AACvF,eAAO,MAAM,qBAAqB,QAAY,CAAC;AAE/C,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B3F"}
@@ -0,0 +1,62 @@
1
+ // Background cron sweep: advance film / scatter jobs that have no client polling.
2
+ import { advanceFilmJob, filmJobDocKey } from "./film-orchestrator.js";
3
+ import { filmJobToPollView, isFilmJobId } from "./film-render-bridge.js";
4
+ import { advanceScatterJob, isScatterJobId } from "./scatter-orchestrator.js";
5
+ import { listStrandedPostClipsFilmJobs, listUnresolvedNotifiableJobs, updateRenderFromView } from "./renders-db.js";
6
+ /** Max age for jobs the sweep still tries to resolve (24h, matches RunPod job TTL). */
7
+ export const SWEEP_MAX_AGE_SECONDS = 24 * 3600;
8
+ export async function sweepUnresolvedJobs(env, ctx) {
9
+ // Pass 1: jobs young enough to still be live on RunPod (keyframe / clips can still
10
+ // be polled). This is the common path.
11
+ const jobIds = await listUnresolvedNotifiableJobs(env, SWEEP_MAX_AGE_SECONDS);
12
+ // Pass 2: post-clips film jobs that aged out of pass 1 but stalled before "done"
13
+ // with their clips already rendered to R2. The remaining work (the CPU-only concat)
14
+ // never expires, so we keep re-driving them -- gated on the film-job doc still
15
+ // existing in R2 so we never chase a swept/GC'd job. De-dup against pass 1.
16
+ const seen = new Set(jobIds);
17
+ const stranded = [];
18
+ for (const id of await listStrandedPostClipsFilmJobs(env, SWEEP_MAX_AGE_SECONDS)) {
19
+ if (!seen.has(id) && isFilmJobId(id) && (await filmJobDocExists(env, id))) {
20
+ seen.add(id);
21
+ stranded.push(id);
22
+ }
23
+ }
24
+ let n = 0;
25
+ for (const jobId of [...jobIds, ...stranded]) {
26
+ try {
27
+ const handled = await resolveOneJob(env, jobId, ctx);
28
+ if (handled)
29
+ n += 1;
30
+ }
31
+ catch (e) {
32
+ console.warn(`render sweep failed for ${jobId}: ${e.message}`);
33
+ }
34
+ }
35
+ return n;
36
+ }
37
+ /** Cheap presence check: a stranded film job is only worth re-driving if its job doc
38
+ * (which carries the finished clip keys) is still in R2. A swept doc means the clips
39
+ * are gone too -- nothing to assemble -- so we skip it. */
40
+ async function filmJobDocExists(env, jobId) {
41
+ try {
42
+ return (await env.R2_RENDERS.head(filmJobDocKey(jobId))) !== null;
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ }
48
+ async function resolveOneJob(env, jobId, ctx) {
49
+ if (isScatterJobId(jobId)) {
50
+ const view = await advanceScatterJob(env, jobId, ctx);
51
+ return view !== null;
52
+ }
53
+ if (isFilmJobId(jobId)) {
54
+ const r = await advanceFilmJob(env, jobId);
55
+ if (!r)
56
+ return false;
57
+ await updateRenderFromView(env, filmJobToPollView(r.job, r.clipJob), ctx);
58
+ return true;
59
+ }
60
+ return false;
61
+ }
62
+ //# sourceMappingURL=render-sweep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-sweep.js","sourceRoot":"","sources":["../src/render-sweep.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ import type { Env, ExecutionContext } from "./platform/orchestrator-context.js";
2
+ import type { RunpodJobView } from "./runpod-types.js";
3
+ export interface NewRenderRow {
4
+ jobId: string;
5
+ project: string;
6
+ bundleKey: string;
7
+ qualityTier: string;
8
+ renderOverrides?: Record<string, unknown>;
9
+ status: string;
10
+ mode?: "full" | "keyframes-only" | "finalized" | "cloud-finalized";
11
+ projectId?: number | null;
12
+ parentId?: number | null;
13
+ }
14
+ export interface KeyframeRef {
15
+ shot_id: string;
16
+ key: string;
17
+ }
18
+ export interface RenderRow {
19
+ id: number;
20
+ public_id: string;
21
+ job_id: string;
22
+ project: string;
23
+ bundle_key: string;
24
+ quality_tier: string;
25
+ render_overrides: Record<string, unknown> | null;
26
+ status: string;
27
+ output_key: string | null;
28
+ output: unknown;
29
+ error: string | null;
30
+ execution_time_ms: number | null;
31
+ delay_time_ms: number | null;
32
+ submitted_at: number;
33
+ updated_at: number;
34
+ completed_at: number | null;
35
+ label: string | null;
36
+ keyframes: KeyframeRef[] | null;
37
+ mode: "full" | "keyframes-only" | "finalized" | "cloud-finalized";
38
+ locked_shots: string[] | null;
39
+ project_id: number | null;
40
+ folder_path: string | null;
41
+ tags: string[];
42
+ parent_id: number | null;
43
+ project_public_id: string | null;
44
+ parent_public_id: string | null;
45
+ }
46
+ export type PublicRenderRow = Omit<RenderRow, "id" | "project_id" | "parent_id" | "public_id" | "project_public_id" | "parent_public_id"> & {
47
+ id: string;
48
+ project_id: string | null;
49
+ parent_id: string | null;
50
+ };
51
+ export declare function toPublicRenderRow(row: RenderRow): PublicRenderRow;
52
+ export declare function normalizeProjectIdInput(raw: unknown): number | null;
53
+ export declare function isTerminalStatus(status: string): boolean;
54
+ export declare const PHANTOM_GRACE_SECONDS = 150;
55
+ export type PhantomDecision = "terminal" | "confirming" | "phantom";
56
+ export declare function classifyMissingJob(rowStatus: string, submittedAtSec: number, nowSec: number, graceSec?: number): PhantomDecision;
57
+ /** Build the bound INSERT for a render row, idempotent on job_id (ON CONFLICT DO NOTHING).
58
+ * Returned UNEXECUTED so a caller can `.run()` it directly (insertRender) or compose several
59
+ * into one all-or-nothing `env.DB.batch([...])` -- the atomic scatter submit (#289). */
60
+ export declare function buildInsertRenderStmt(env: Env, row: NewRenderRow): import("./index.js").PreparedStatement;
61
+ export declare function insertRender(env: Env, row: NewRenderRow): Promise<void>;
62
+ export declare function updateRenderFromView(env: Env, view: RunpodJobView, ctx?: ExecutionContext): Promise<void>;
63
+ export declare function setCloudAnimateProgress(env: Env, jobId: string, done: number, total: number): Promise<void>;
64
+ export interface HybridLaneProgress {
65
+ gpu: {
66
+ done: number;
67
+ total: number;
68
+ status?: string;
69
+ };
70
+ cloud: {
71
+ done: number;
72
+ total: number;
73
+ };
74
+ }
75
+ export declare function setHybridProgress(env: Env, jobId: string, lanes: HybridLaneProgress): Promise<void>;
76
+ export interface RenderPollRow {
77
+ status: string;
78
+ submitted_at: number;
79
+ output: unknown;
80
+ output_key: string | null;
81
+ error: string | null;
82
+ }
83
+ export declare function getRenderForPoll(env: Env, jobId: string): Promise<RenderPollRow | null>;
84
+ export declare function markRenderFailedByJobId(env: Env, jobId: string, error: string): Promise<boolean>;
85
+ export declare function claimFinish(env: Env, jobId: string): Promise<boolean>;
86
+ export declare function markFinishDone(env: Env, jobId: string, outputKey: string, outputJson: string): Promise<void>;
87
+ export interface RenderNotifyRow {
88
+ project: string;
89
+ status: string;
90
+ output_key: string | null;
91
+ error: string | null;
92
+ execution_time_ms: number | null;
93
+ mode: string | null;
94
+ }
95
+ export declare function claimRenderNotify(env: Env, jobId: string): Promise<RenderNotifyRow | null>;
96
+ export { FILM_ADVANCE_LEASE_TTL_SECONDS, claimFilmAdvance, releaseFilmAdvance, type FilmAdvanceClaim, } from "./film-advance-lease.js";
97
+ export declare function listUnresolvedNotifiableJobs(env: Env, maxAgeSeconds: number, limit?: number): Promise<string[]>;
98
+ export declare function listStrandedPostClipsFilmJobs(env: Env, maxAgeSeconds: number, limit?: number): Promise<string[]>;
99
+ export declare function markFinishFailed(env: Env, jobId: string, error: string): Promise<void>;
100
+ export declare function getFinishState(env: Env, jobId: string): Promise<{
101
+ finish_state: string | null;
102
+ output_key: string | null;
103
+ } | null>;
104
+ export declare function normalizeLockedShots(raw: unknown): string[];
105
+ export declare function normalizeFolderPath(raw: unknown): string | null;
106
+ export declare function normalizeTags(raw: unknown): string[];
107
+ export declare function normalizeKeyframes(raw: unknown): KeyframeRef[];
108
+ export declare function setRenderAudioOutput(env: Env, id: number, outputKey: string, seconds: number | null): Promise<boolean>;
109
+ export declare function getRenderIdByPublicId(env: Env, publicId: string): Promise<number | null>;
110
+ export declare function getRenderByIdForUser(env: Env, id: number): Promise<RenderRow | null>;
111
+ export declare function setRenderLabel(env: Env, id: number, label: string | null): Promise<boolean>;
112
+ export declare function countOtherRowsWithOutputKey(env: Env, id: number, outputKey: string): Promise<number>;
113
+ export declare function deleteRenderRow(env: Env, id: number): Promise<boolean>;
114
+ /** The renders-list page size when a caller passes no `limit`. ONE source of truth for both the
115
+ * GET /api/storyboard/renders route and this function's default, so they cannot drift (#670: the route
116
+ * said 100, this signature said 50). 50 is a sensible API/MCP page (well under the 200 clamp below);
117
+ * the frontend always sends its own explicit limit, so this governs headless/API/MCP consumers. */
118
+ export declare const DEFAULT_RENDERS_LIMIT = 50;
119
+ export declare function listRendersForUser(env: Env, limit?: number, projectId?: number | null): Promise<RenderRow[]>;
120
+ export declare function setRenderLockedShots(env: Env, id: number, lockedShots: string[]): Promise<boolean>;
121
+ export declare function getRenderIdByJobId(env: Env, jobId: string): Promise<number | null>;
122
+ export declare function getScatterChildren(env: Env, parentId: number): Promise<Array<{
123
+ job_id: string;
124
+ status: string;
125
+ }>>;
126
+ export declare function setRenderFolder(env: Env, id: number, folderPath: string | null): Promise<boolean>;
127
+ export declare function setRenderTags(env: Env, id: number, tags: string[]): Promise<boolean>;
128
+ export declare function listUserTags(env: Env): Promise<string[]>;
129
+ //# sourceMappingURL=renders-db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renders-db.d.ts","sourceRoot":"","sources":["../src/renders-db.ts"],"names":[],"mappings":"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"}