@mevdragon/vidfarm-devcli 0.2.14 → 0.3.1

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 (204) hide show
  1. package/README.md +11 -4
  2. package/SKILL.director.md +100 -0
  3. package/SKILL.platform.md +66 -6
  4. package/dist/src/cli.js +135 -1527
  5. package/package.json +5 -24
  6. package/.env.example +0 -60
  7. package/auto-create-hyperframe-templates/AUTO_CREATE_HYPERFRAME_TEMPLATES.md +0 -275
  8. package/auto-create-hyperframe-templates/extractor-system-prompt.md +0 -128
  9. package/auto-create-hyperframe-templates/input-manifest.schema.json +0 -56
  10. package/auto-create-hyperframe-templates/lambda-memory-estimator.md +0 -118
  11. package/auto-create-hyperframe-templates/production-graph.schema.json +0 -314
  12. package/auto-create-hyperframe-templates/runbook.md +0 -198
  13. package/auto-create-hyperframe-templates/scripts/create-hyperframe-template.mjs +0 -368
  14. package/auto-create-hyperframe-templates/template-plan.schema.json +0 -311
  15. package/auto-create-hyperframe-templates/template-planner-prompt.md +0 -144
  16. package/auto-create-templates/AUTO_CREATE_TEMPLATES.md +0 -599
  17. package/auto-create-templates/extractor-system-prompt.md +0 -119
  18. package/auto-create-templates/production-graph.schema.json +0 -276
  19. package/auto-create-templates/runbook.md +0 -140
  20. package/auto-create-templates/template-plan.schema.json +0 -301
  21. package/auto-create-templates/template-planner-prompt.md +0 -137
  22. package/dist/src/account-pages-legacy.js +0 -9338
  23. package/dist/src/account-pages-legacy.js.map +0 -1
  24. package/dist/src/account-pages.js +0 -52
  25. package/dist/src/account-pages.js.map +0 -1
  26. package/dist/src/app.js +0 -13711
  27. package/dist/src/app.js.map +0 -1
  28. package/dist/src/cli.js.map +0 -1
  29. package/dist/src/composition-runtime.js +0 -581
  30. package/dist/src/composition-runtime.js.map +0 -1
  31. package/dist/src/config.js +0 -140
  32. package/dist/src/config.js.map +0 -1
  33. package/dist/src/context.js +0 -492
  34. package/dist/src/context.js.map +0 -1
  35. package/dist/src/dev-app-legacy.js +0 -694
  36. package/dist/src/dev-app-legacy.js.map +0 -1
  37. package/dist/src/dev-app.js +0 -6
  38. package/dist/src/dev-app.js.map +0 -1
  39. package/dist/src/dev-serve.js.map +0 -1
  40. package/dist/src/domain.js +0 -2
  41. package/dist/src/domain.js.map +0 -1
  42. package/dist/src/editor-chat-history.js +0 -82
  43. package/dist/src/editor-chat-history.js.map +0 -1
  44. package/dist/src/editor-chat.js +0 -312
  45. package/dist/src/editor-chat.js.map +0 -1
  46. package/dist/src/editor-dark-theme.js +0 -1128
  47. package/dist/src/editor-dark-theme.js.map +0 -1
  48. package/dist/src/frontend/flockposter-cache-store.js +0 -124
  49. package/dist/src/frontend/flockposter-cache-store.js.map +0 -1
  50. package/dist/src/frontend/homepage-client.js +0 -117
  51. package/dist/src/frontend/homepage-client.js.map +0 -1
  52. package/dist/src/frontend/homepage-shared.js +0 -4
  53. package/dist/src/frontend/homepage-shared.js.map +0 -1
  54. package/dist/src/frontend/homepage-store.js +0 -28
  55. package/dist/src/frontend/homepage-store.js.map +0 -1
  56. package/dist/src/frontend/homepage-view.js +0 -260
  57. package/dist/src/frontend/homepage-view.js.map +0 -1
  58. package/dist/src/frontend/page-runtime-client.js +0 -124
  59. package/dist/src/frontend/page-runtime-client.js.map +0 -1
  60. package/dist/src/frontend/page-runtime-store.js +0 -9
  61. package/dist/src/frontend/page-runtime-store.js.map +0 -1
  62. package/dist/src/frontend/sentry.js +0 -42
  63. package/dist/src/frontend/sentry.js.map +0 -1
  64. package/dist/src/frontend/template-editor-chat.js +0 -3760
  65. package/dist/src/frontend/template-editor-chat.js.map +0 -1
  66. package/dist/src/help-page.js +0 -333
  67. package/dist/src/help-page.js.map +0 -1
  68. package/dist/src/homepage.js +0 -919
  69. package/dist/src/homepage.js.map +0 -1
  70. package/dist/src/hyperframes/composition.js +0 -180
  71. package/dist/src/hyperframes/composition.js.map +0 -1
  72. package/dist/src/index.js +0 -16
  73. package/dist/src/index.js.map +0 -1
  74. package/dist/src/instrument.js +0 -30
  75. package/dist/src/instrument.js.map +0 -1
  76. package/dist/src/lib/crypto.js +0 -45
  77. package/dist/src/lib/crypto.js.map +0 -1
  78. package/dist/src/lib/dev-log.js +0 -54
  79. package/dist/src/lib/dev-log.js.map +0 -1
  80. package/dist/src/lib/display-name.js +0 -11
  81. package/dist/src/lib/display-name.js.map +0 -1
  82. package/dist/src/lib/ids.js +0 -24
  83. package/dist/src/lib/ids.js.map +0 -1
  84. package/dist/src/lib/images.js +0 -19
  85. package/dist/src/lib/images.js.map +0 -1
  86. package/dist/src/lib/json.js +0 -15
  87. package/dist/src/lib/json.js.map +0 -1
  88. package/dist/src/lib/template-dna.js +0 -543
  89. package/dist/src/lib/template-dna.js.map +0 -1
  90. package/dist/src/lib/template-paths.js +0 -28
  91. package/dist/src/lib/template-paths.js.map +0 -1
  92. package/dist/src/lib/template-style-options.js +0 -203
  93. package/dist/src/lib/template-style-options.js.map +0 -1
  94. package/dist/src/lib/time.js +0 -7
  95. package/dist/src/lib/time.js.map +0 -1
  96. package/dist/src/lib/video-quality-harness.js +0 -60
  97. package/dist/src/lib/video-quality-harness.js.map +0 -1
  98. package/dist/src/page-runtime.js +0 -2
  99. package/dist/src/page-runtime.js.map +0 -1
  100. package/dist/src/page-shell.js +0 -1315
  101. package/dist/src/page-shell.js.map +0 -1
  102. package/dist/src/primitive-context.js +0 -299
  103. package/dist/src/primitive-context.js.map +0 -1
  104. package/dist/src/primitive-registry.js +0 -2181
  105. package/dist/src/primitive-registry.js.map +0 -1
  106. package/dist/src/primitive-sdk.js +0 -4
  107. package/dist/src/primitive-sdk.js.map +0 -1
  108. package/dist/src/primitives/remotion/html-image.js +0 -30
  109. package/dist/src/primitives/remotion/html-image.js.map +0 -1
  110. package/dist/src/primitives/remotion/media-slideshow.js +0 -60
  111. package/dist/src/primitives/remotion/media-slideshow.js.map +0 -1
  112. package/dist/src/react-page-shell.js +0 -35
  113. package/dist/src/react-page-shell.js.map +0 -1
  114. package/dist/src/ready-post-schedule-component.js +0 -1515
  115. package/dist/src/ready-post-schedule-component.js.map +0 -1
  116. package/dist/src/registry.js +0 -296
  117. package/dist/src/registry.js.map +0 -1
  118. package/dist/src/runtime.js +0 -31
  119. package/dist/src/runtime.js.map +0 -1
  120. package/dist/src/services/api-call-history.js +0 -249
  121. package/dist/src/services/api-call-history.js.map +0 -1
  122. package/dist/src/services/auth.js +0 -152
  123. package/dist/src/services/auth.js.map +0 -1
  124. package/dist/src/services/billing.js +0 -231
  125. package/dist/src/services/billing.js.map +0 -1
  126. package/dist/src/services/chat-threads.js +0 -92
  127. package/dist/src/services/chat-threads.js.map +0 -1
  128. package/dist/src/services/fork-access.js +0 -93
  129. package/dist/src/services/fork-access.js.map +0 -1
  130. package/dist/src/services/fork-manifest.js +0 -43
  131. package/dist/src/services/fork-manifest.js.map +0 -1
  132. package/dist/src/services/ghostcut.js +0 -132
  133. package/dist/src/services/ghostcut.js.map +0 -1
  134. package/dist/src/services/hyperframes.js +0 -1014
  135. package/dist/src/services/hyperframes.js.map +0 -1
  136. package/dist/src/services/job-capacity.js +0 -14
  137. package/dist/src/services/job-capacity.js.map +0 -1
  138. package/dist/src/services/job-logs.js +0 -197
  139. package/dist/src/services/job-logs.js.map +0 -1
  140. package/dist/src/services/jobs.js +0 -136
  141. package/dist/src/services/jobs.js.map +0 -1
  142. package/dist/src/services/media-processing.js +0 -743
  143. package/dist/src/services/media-processing.js.map +0 -1
  144. package/dist/src/services/primitive-media-lambda.js +0 -280
  145. package/dist/src/services/primitive-media-lambda.js.map +0 -1
  146. package/dist/src/services/providers.js +0 -2870
  147. package/dist/src/services/providers.js.map +0 -1
  148. package/dist/src/services/rate-limits.js +0 -237
  149. package/dist/src/services/rate-limits.js.map +0 -1
  150. package/dist/src/services/remotion.js +0 -688
  151. package/dist/src/services/remotion.js.map +0 -1
  152. package/dist/src/services/serverless-auth.js +0 -374
  153. package/dist/src/services/serverless-auth.js.map +0 -1
  154. package/dist/src/services/serverless-jobs.js +0 -1074
  155. package/dist/src/services/serverless-jobs.js.map +0 -1
  156. package/dist/src/services/serverless-provider-keys.js +0 -401
  157. package/dist/src/services/serverless-provider-keys.js.map +0 -1
  158. package/dist/src/services/serverless-records.js +0 -1088
  159. package/dist/src/services/serverless-records.js.map +0 -1
  160. package/dist/src/services/serverless-template-configs.js +0 -67
  161. package/dist/src/services/serverless-template-configs.js.map +0 -1
  162. package/dist/src/services/storage.js +0 -383
  163. package/dist/src/services/storage.js.map +0 -1
  164. package/dist/src/services/template-certification.js +0 -475
  165. package/dist/src/services/template-certification.js.map +0 -1
  166. package/dist/src/services/template-loader.js +0 -99
  167. package/dist/src/services/template-loader.js.map +0 -1
  168. package/dist/src/services/template-runtime-bundles.js +0 -217
  169. package/dist/src/services/template-runtime-bundles.js.map +0 -1
  170. package/dist/src/services/template-sources.js +0 -1017
  171. package/dist/src/services/template-sources.js.map +0 -1
  172. package/dist/src/services/video-normalization.js +0 -2
  173. package/dist/src/services/video-normalization.js.map +0 -1
  174. package/dist/src/services/webhooks.js +0 -62
  175. package/dist/src/services/webhooks.js.map +0 -1
  176. package/dist/src/template-editor-pages.js +0 -2491
  177. package/dist/src/template-editor-pages.js.map +0 -1
  178. package/dist/src/template-editor-shell.js +0 -2702
  179. package/dist/src/template-editor-shell.js.map +0 -1
  180. package/dist/src/template-sdk.js +0 -4
  181. package/dist/src/template-sdk.js.map +0 -1
  182. package/dist/src/worker.js +0 -17
  183. package/dist/src/worker.js.map +0 -1
  184. package/public/assets/homepage-app.js +0 -54
  185. package/public/assets/homepage-client-app.js +0 -80
  186. package/public/assets/page-runtime-client-app.js +0 -94
  187. package/readme.secret.md +0 -89
  188. package/templates/vidfarm_template_0000/README.md +0 -106
  189. package/templates/vidfarm_template_0000/SKILL.md +0 -266
  190. package/templates/vidfarm_template_0000/assets/Abel-Regular.ttf +0 -0
  191. package/templates/vidfarm_template_0000/assets/DMSerifDisplay-Regular.ttf +0 -0
  192. package/templates/vidfarm_template_0000/assets/Montserrat[wght].ttf +0 -0
  193. package/templates/vidfarm_template_0000/assets/SourceCodePro[wght].ttf +0 -0
  194. package/templates/vidfarm_template_0000/assets/TikTokSans-SemiBold.ttf +0 -0
  195. package/templates/vidfarm_template_0000/assets/Yesteryear-Regular.ttf +0 -0
  196. package/templates/vidfarm_template_0000/composition.json +0 -11
  197. package/templates/vidfarm_template_0000/src/lib/images.js +0 -221
  198. package/templates/vidfarm_template_0000/src/remotion/Root.js +0 -33
  199. package/templates/vidfarm_template_0000/src/remotion/index.js +0 -3
  200. package/templates/vidfarm_template_0000/src/sdk.js +0 -3
  201. package/templates/vidfarm_template_0000/src/style-options.js +0 -200
  202. package/templates/vidfarm_template_0000/src/template-dna.js +0 -9
  203. package/templates/vidfarm_template_0000/src/template.js +0 -1566
  204. package/templates/vidfarm_template_0000/template.config.json +0 -21
@@ -1,688 +0,0 @@
1
- import { mkdirSync } from "node:fs";
2
- import path from "node:path";
3
- import { bundle } from "@remotion/bundler";
4
- import { getRenderProgress, renderMediaOnLambda } from "@remotion/lambda";
5
- import { getCompositions, renderMedia, renderStill } from "@remotion/renderer";
6
- import { config } from "../config.js";
7
- import { createId } from "../lib/ids.js";
8
- const REQUIRED_VIDEO_FPS = 30;
9
- const RENDER_MARKUP_MULTIPLIER = 1.2;
10
- const RENDER_ASSET_PREFLIGHT_TIMEOUT_MS = 10_000;
11
- const RENDER_ASSET_PREFLIGHT_MAX_FAILURES = 5;
12
- const ABSOLUTE_MAX_REMOTE_VIDEO_DURATION_SECONDS = 10 * 60;
13
- const ABSOLUTE_MAX_DIRECT_REMOTE_VIDEO_BYTES = 50 * 1024 * 1024;
14
- const REMOTE_VIDEO_DOWNLOAD_BUDGET_BYTES = 1250 * 1024 * 1024;
15
- const DEFAULT_PARALLEL_LAMBDA_TARGET = 6;
16
- const MAX_PARALLEL_LAMBDA_TARGET = 24;
17
- const SMALL_REMOTE_VIDEO_BYTES = 12 * 1024 * 1024;
18
- const MEDIUM_REMOTE_VIDEO_BYTES = 25 * 1024 * 1024;
19
- export class RemotionService {
20
- async render(input) {
21
- const fps = input.fps ?? REQUIRED_VIDEO_FPS;
22
- if (fps !== REQUIRED_VIDEO_FPS) {
23
- throw new Error(`Vidfarm renders must be ${REQUIRED_VIDEO_FPS}fps. Received ${fps}fps.`);
24
- }
25
- const preflightAssets = await preflightRenderAssets(input.preflightUrls ?? collectPreflightUrls(input.inputProps), { requireRemoteHttpUrls: Boolean(input.preflightUrls) });
26
- const serveUrl = nonBlank(input.serveUrl) ??
27
- nonBlank(config.REMOTION_SERVE_URL) ??
28
- inferHostedServeUrl(input.compositionId);
29
- const hasHostedLambdaConfig = Boolean(nonBlank(config.REMOTION_FUNCTION_NAME) && serveUrl && nonBlank(config.REMOTION_BUCKET_NAME));
30
- if (config.isProduction && config.REMOTION_MODE !== "lambda") {
31
- throw new Error("Production video rendering must use lambda mode.");
32
- }
33
- if (input.entryPoint
34
- && (config.REMOTION_MODE === "local"
35
- || (config.REMOTION_MODE === "auto" && !hasHostedLambdaConfig)
36
- || (!config.isProduction && config.REMOTION_MODE === "auto"))) {
37
- if (config.isProduction) {
38
- throw new Error("Production video rendering cannot fall back to local mode.");
39
- }
40
- return this.renderLocal({
41
- compositionId: input.compositionId,
42
- entryPoint: input.entryPoint,
43
- outputKey: input.outputKey,
44
- fps,
45
- inputProps: input.inputProps
46
- });
47
- }
48
- if (config.REMOTION_MODE === "mock") {
49
- if (config.isProduction) {
50
- throw new Error("Production video rendering cannot use mock mode.");
51
- }
52
- return {
53
- renderId: createId("render"),
54
- outputUrl: null,
55
- metadata: {
56
- mode: "mock",
57
- compositionId: input.compositionId,
58
- fps,
59
- inputProps: input.inputProps
60
- }
61
- };
62
- }
63
- if (!hasHostedLambdaConfig) {
64
- throw new Error(config.isProduction
65
- ? "Cloud render is not configured."
66
- : "Cloud render is not configured. Set REMOTION_FUNCTION_NAME, REMOTION_SERVE_URL, and REMOTION_BUCKET_NAME, or provide a local entryPoint.");
67
- }
68
- const hostedServeUrl = serveUrl;
69
- const hostedFunctionName = nonBlank(config.REMOTION_FUNCTION_NAME);
70
- const hostedBucketName = nonBlank(config.REMOTION_BUCKET_NAME);
71
- const requestedFramesPerLambda = Number.isFinite(input.framesPerLambda)
72
- ? Math.max(1, Math.floor(input.framesPerLambda))
73
- : 40;
74
- const composition = await this.resolveComposition({
75
- compositionId: input.compositionId,
76
- source: hostedServeUrl,
77
- inputProps: input.inputProps,
78
- });
79
- this.assertExpectedFps({
80
- compositionId: input.compositionId,
81
- actualFps: composition.fps,
82
- expectedFps: fps
83
- });
84
- const renderPolicy = planLambdaRenderPolicy({
85
- inputProps: input.inputProps,
86
- preflightAssets,
87
- requestedFramesPerLambda,
88
- durationInFrames: composition.durationInFrames,
89
- fps
90
- });
91
- const framesPerLambda = renderPolicy.framesPerLambda;
92
- const render = await renderMediaOnLambda({
93
- region: config.REMOTION_REGION,
94
- functionName: hostedFunctionName,
95
- serveUrl: hostedServeUrl,
96
- composition: input.compositionId,
97
- inputProps: input.inputProps,
98
- codec: "h264",
99
- privacy: "public",
100
- forceBucketName: hostedBucketName,
101
- forceWidth: 1080,
102
- forceHeight: 1920,
103
- framesPerLambda,
104
- crf: 18,
105
- overwrite: true
106
- });
107
- const startedAt = Date.now();
108
- for (;;) {
109
- const progress = await getRenderProgress({
110
- region: config.REMOTION_REGION,
111
- functionName: hostedFunctionName,
112
- bucketName: hostedBucketName,
113
- renderId: render.renderId
114
- });
115
- const fatalError = summarizeFatalRenderError(progress);
116
- if (fatalError) {
117
- throw new Error(`Cloud render ${render.renderId} failed: ${fatalError}`);
118
- }
119
- if (progress.done) {
120
- if (!progress.outputFile) {
121
- throw new Error(`Cloud render ${render.renderId} completed without an output file.`);
122
- }
123
- const estimatedCostUsd = progress.costs.accruedSoFar;
124
- const chargeUsd = roundUsd(estimatedCostUsd * RENDER_MARKUP_MULTIPLIER);
125
- return {
126
- renderId: render.renderId,
127
- outputUrl: progress.outputFile,
128
- metadata: {
129
- mode: "lambda",
130
- bucketName: render.bucketName,
131
- compositionId: input.compositionId,
132
- fps,
133
- framesPerLambda,
134
- estimatedLambdaCount: renderPolicy.estimatedLambdaCount,
135
- mediaPolicy: renderPolicy,
136
- serveUrl,
137
- estimatedCostUsd,
138
- chargeUsd,
139
- costDisplay: progress.costs.displayCost,
140
- costCurrency: progress.costs.currency,
141
- costDisclaimer: progress.costs.disclaimer,
142
- estimatedBillingDurationInMilliseconds: progress.estimatedBillingDurationInMilliseconds,
143
- lambdasInvoked: progress.lambdasInvoked,
144
- overallProgress: progress.overallProgress,
145
- renderSize: progress.renderSize
146
- }
147
- };
148
- }
149
- if (Date.now() - startedAt > 10 * 60 * 1000) {
150
- throw new Error(`Timed out waiting for cloud render ${render.renderId} output.`);
151
- }
152
- await new Promise((resolve) => setTimeout(resolve, 5000));
153
- }
154
- }
155
- async renderLocal(input) {
156
- const renderId = createId("render");
157
- const bundled = await getOrCreateBundle(input.entryPoint);
158
- const composition = await this.resolveComposition({
159
- source: bundled,
160
- compositionId: input.compositionId,
161
- inputProps: input.inputProps
162
- });
163
- this.assertExpectedFps({
164
- compositionId: input.compositionId,
165
- actualFps: composition.fps,
166
- expectedFps: input.fps
167
- });
168
- const outputKey = input.outputKey ?? `renders/${renderId}.mp4`;
169
- const outputLocation = path.join(config.VIDFARM_DATA_DIR, "storage", outputKey);
170
- mkdirSync(path.dirname(outputLocation), { recursive: true });
171
- await renderMedia({
172
- serveUrl: bundled,
173
- composition,
174
- codec: "h264",
175
- inputProps: input.inputProps,
176
- outputLocation,
177
- overwrite: true
178
- });
179
- return {
180
- renderId,
181
- outputUrl: `${config.PUBLIC_BASE_URL}/storage/${encodeURIComponent(outputKey)}`,
182
- metadata: {
183
- mode: "local",
184
- compositionId: input.compositionId,
185
- entryPoint: input.entryPoint,
186
- fps: input.fps,
187
- outputKey
188
- }
189
- };
190
- }
191
- async renderStill(input) {
192
- const renderId = createId("render");
193
- const bundled = await getOrCreateBundle(input.entryPoint);
194
- const composition = await this.resolveComposition({
195
- source: bundled,
196
- compositionId: input.compositionId,
197
- inputProps: input.inputProps
198
- });
199
- const format = input.imageFormat ?? "png";
200
- const extension = format === "jpeg" ? "jpg" : format;
201
- const outputKey = input.outputKey ?? `renders/${renderId}.${extension}`;
202
- const outputLocation = path.join(config.VIDFARM_DATA_DIR, "storage", outputKey);
203
- mkdirSync(path.dirname(outputLocation), { recursive: true });
204
- await renderStill({
205
- serveUrl: bundled,
206
- composition,
207
- inputProps: input.inputProps,
208
- output: outputLocation,
209
- imageFormat: format,
210
- overwrite: true
211
- });
212
- return {
213
- renderId,
214
- outputUrl: `${config.PUBLIC_BASE_URL}/storage/${encodeURIComponent(outputKey)}`,
215
- metadata: {
216
- mode: "local_still",
217
- compositionId: input.compositionId,
218
- entryPoint: input.entryPoint,
219
- outputKey,
220
- imageFormat: format
221
- }
222
- };
223
- }
224
- async resolveComposition(input) {
225
- const compositions = await getCompositions(input.source, {
226
- inputProps: input.inputProps
227
- });
228
- const composition = compositions.find((item) => item.id === input.compositionId);
229
- if (!composition) {
230
- throw new Error(`Composition ${input.compositionId} not found in ${input.source}`);
231
- }
232
- return composition;
233
- }
234
- assertExpectedFps(input) {
235
- if (input.actualFps !== input.expectedFps) {
236
- throw new Error(`Composition ${input.compositionId} is ${input.actualFps}fps, but Vidfarm requires ${input.expectedFps}fps output.`);
237
- }
238
- }
239
- }
240
- const bundleCache = new Map();
241
- function getOrCreateBundle(entryPoint) {
242
- const existing = bundleCache.get(entryPoint);
243
- if (existing) {
244
- return existing;
245
- }
246
- const created = bundle({
247
- entryPoint,
248
- onProgress: () => undefined
249
- });
250
- bundleCache.set(entryPoint, created);
251
- return created;
252
- }
253
- function roundUsd(value) {
254
- return Number(value.toFixed(6));
255
- }
256
- function collectPreflightUrls(value, path = "inputProps") {
257
- if (typeof value === "string") {
258
- return isRemoteHttpUrl(value) ? [{ url: value, label: path }] : [];
259
- }
260
- if (Array.isArray(value)) {
261
- return value.flatMap((item, index) => collectPreflightUrls(item, `${path}[${index}]`));
262
- }
263
- if (!value || typeof value !== "object") {
264
- return [];
265
- }
266
- return Object.entries(value).flatMap(([key, item]) => (collectPreflightUrls(item, `${path}.${key}`)));
267
- }
268
- async function preflightRenderAssets(inputs, options = {}) {
269
- const normalized = inputs.map((input, index) => (typeof input === "string" ? { url: input, label: `preflightUrls[${index}]` } : input));
270
- if (options.requireRemoteHttpUrls) {
271
- const invalid = normalized
272
- .filter((input) => input.url.trim() && !isRemoteHttpUrl(input.url))
273
- .map((input) => `${input.label || "asset"} must be an absolute http(s) URL: ${input.url}`);
274
- if (invalid.length) {
275
- throw new Error(`Render asset preflight failed: ${invalid.join("; ")}`);
276
- }
277
- }
278
- const targets = dedupePreflightUrls(normalized.filter((input) => isRemoteHttpUrl(input.url)));
279
- if (!targets.length) {
280
- return [];
281
- }
282
- const failures = [];
283
- const assets = [];
284
- for (const target of targets) {
285
- const result = await preflightOneRenderAsset(target);
286
- assets.push(result.asset);
287
- const failure = result.failure;
288
- if (failure) {
289
- failures.push(failure.message);
290
- }
291
- }
292
- if (failures.length) {
293
- const shown = failures.slice(0, RENDER_ASSET_PREFLIGHT_MAX_FAILURES);
294
- const remaining = failures.length - shown.length;
295
- throw new Error([
296
- "Render asset preflight failed:",
297
- ...shown.map((failure) => `- ${failure}`),
298
- remaining > 0 ? `- ${remaining} more asset${remaining === 1 ? "" : "s"} failed preflight.` : null
299
- ].filter(Boolean).join("\n"));
300
- }
301
- return assets;
302
- }
303
- function dedupePreflightUrls(inputs) {
304
- const seen = new Set();
305
- const deduped = [];
306
- for (const input of inputs) {
307
- const key = `${input.label || ""}\n${input.url}`;
308
- if (seen.has(key)) {
309
- continue;
310
- }
311
- seen.add(key);
312
- deduped.push(input);
313
- }
314
- return deduped;
315
- }
316
- async function preflightOneRenderAsset(input) {
317
- const maxAttempts = isVidfarmTemplateMediaUrl(input.url) ? 4 : 1;
318
- let latest = null;
319
- for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
320
- latest = await preflightOneRenderAssetOnce(input);
321
- if (!latest.failure || !isRetryablePreflightFailure(latest.failure.status, input.url)) {
322
- return latest;
323
- }
324
- if (attempt < maxAttempts - 1) {
325
- await sleep(preflightRetryDelayMs(attempt));
326
- }
327
- }
328
- return latest ?? preflightOneRenderAssetOnce(input);
329
- }
330
- async function preflightOneRenderAssetOnce(input) {
331
- const headFailure = await requestRenderAsset(input, "HEAD");
332
- if (!headFailure.failure) {
333
- return headFailure;
334
- }
335
- if (!headFailure.failure.allowGetFallback) {
336
- return headFailure;
337
- }
338
- const getFailure = await requestRenderAsset(input, "GET");
339
- return {
340
- asset: mergeAssetMetadata(headFailure.asset, getFailure.asset),
341
- failure: getFailure.failure
342
- };
343
- }
344
- async function requestRenderAsset(input, method) {
345
- const controller = new AbortController();
346
- const timeout = setTimeout(() => controller.abort(), RENDER_ASSET_PREFLIGHT_TIMEOUT_MS);
347
- try {
348
- const response = await fetch(input.url, {
349
- method,
350
- signal: controller.signal,
351
- headers: method === "GET" ? { range: "bytes=0-0" } : undefined
352
- });
353
- const asset = extractPreflightAssetMetadata(input, response);
354
- if (response.ok) {
355
- return { asset, failure: null };
356
- }
357
- return {
358
- asset,
359
- failure: {
360
- allowGetFallback: method === "HEAD",
361
- status: response.status,
362
- message: `${input.label || "asset"} returned ${response.status} ${response.statusText || "HTTP error"} for ${formatUrlForError(input.url)}`
363
- }
364
- };
365
- }
366
- catch (error) {
367
- const message = error instanceof Error && error.name === "AbortError"
368
- ? `timed out after ${RENDER_ASSET_PREFLIGHT_TIMEOUT_MS / 1000}s`
369
- : error instanceof Error
370
- ? error.message
371
- : "unknown fetch error";
372
- return {
373
- asset: {
374
- url: input.url,
375
- label: input.label,
376
- contentType: null,
377
- contentLengthBytes: null
378
- },
379
- failure: {
380
- allowGetFallback: false,
381
- status: null,
382
- message: `${input.label || "asset"} could not be reached: ${message} (${formatUrlForError(input.url)})`
383
- }
384
- };
385
- }
386
- finally {
387
- clearTimeout(timeout);
388
- }
389
- }
390
- function isRetryablePreflightFailure(status, url) {
391
- return isVidfarmTemplateMediaUrl(url) && (status === 403 || status === 404 || status === 429 || status == null || status >= 500);
392
- }
393
- function preflightRetryDelayMs(attempt) {
394
- return Math.min(250 * (2 ** attempt), 2_000);
395
- }
396
- function sleep(ms) {
397
- return new Promise((resolve) => setTimeout(resolve, ms));
398
- }
399
- function isVidfarmTemplateMediaUrl(value) {
400
- try {
401
- const url = new URL(value);
402
- return url.pathname === "/template-media" && Boolean(url.searchParams.get("key"));
403
- }
404
- catch {
405
- return false;
406
- }
407
- }
408
- function isRemoteHttpUrl(value) {
409
- try {
410
- const url = new URL(value);
411
- return url.protocol === "http:" || url.protocol === "https:";
412
- }
413
- catch {
414
- return false;
415
- }
416
- }
417
- function formatUrlForError(url) {
418
- return url.length > 300 ? `${url.slice(0, 300)}...` : url;
419
- }
420
- function extractPreflightAssetMetadata(input, response) {
421
- return {
422
- url: input.url,
423
- label: input.label,
424
- contentType: normalizeHeaderValue(response.headers.get("content-type")),
425
- contentLengthBytes: parseContentLength(response.headers)
426
- };
427
- }
428
- function mergeAssetMetadata(primary, fallback) {
429
- return {
430
- ...primary,
431
- contentType: primary.contentType ?? fallback.contentType,
432
- contentLengthBytes: primary.contentLengthBytes ?? fallback.contentLengthBytes
433
- };
434
- }
435
- function normalizeHeaderValue(value) {
436
- const trimmed = value?.trim();
437
- return trimmed ? trimmed : null;
438
- }
439
- function parseContentLength(headers) {
440
- const contentRange = headers.get("content-range");
441
- if (contentRange) {
442
- const match = /\/(\d+)\s*$/u.exec(contentRange);
443
- if (match) {
444
- return Number.parseInt(match[1], 10);
445
- }
446
- }
447
- const contentLength = headers.get("content-length");
448
- if (!contentLength) {
449
- return null;
450
- }
451
- const parsed = Number.parseInt(contentLength, 10);
452
- return Number.isFinite(parsed) && parsed >= 0 ? parsed : null;
453
- }
454
- function planLambdaRenderPolicy(input) {
455
- const durationSeconds = input.durationInFrames / input.fps;
456
- const outputDimensions = inferOutputDimensions(input.inputProps);
457
- const outputPixels = outputDimensions.width != null && outputDimensions.height != null
458
- ? outputDimensions.width * outputDimensions.height
459
- : null;
460
- const remoteVideoAssets = collectRemoteVideoAssets(input.inputProps, input.preflightAssets);
461
- const sourceVideo = remoteVideoAssets.primary;
462
- const totalRemoteVideoBytes = remoteVideoAssets.totalBytes;
463
- if (durationSeconds > ABSOLUTE_MAX_REMOTE_VIDEO_DURATION_SECONDS) {
464
- throw new Error(`Render duration is ${formatDurationSeconds(durationSeconds)}, which exceeds the current Vidfarm remote-video platform limit of ${formatDurationSeconds(ABSOLUTE_MAX_REMOTE_VIDEO_DURATION_SECONDS)}. Trim the source video before rendering.`);
465
- }
466
- const sourceVideoBytes = sourceVideo?.contentLengthBytes ?? null;
467
- if (sourceVideoBytes != null && sourceVideoBytes > ABSOLUTE_MAX_DIRECT_REMOTE_VIDEO_BYTES) {
468
- throw new Error(`Remote video source is ${formatBytes(sourceVideoBytes)}, which exceeds the direct Vidfarm render limit of ${formatBytes(ABSOLUTE_MAX_DIRECT_REMOTE_VIDEO_BYTES)}. Run POST /api/v1/primitives/videos/normalize first, then pass the returned normalizedVideoUrl into the template render.`);
469
- }
470
- const maxSafeSegmentDurationSeconds = inferMaxSafeSegmentDurationSeconds({
471
- sourceVideoBytes,
472
- durationSeconds,
473
- outputPixels
474
- });
475
- const requiredLambdasByDuration = Math.max(1, Math.ceil(durationSeconds / maxSafeSegmentDurationSeconds));
476
- const maxLambdasByDownloadBudget = inferMaxLambdasByDownloadBudget(totalRemoteVideoBytes);
477
- const preferredLambdasByRequestedFrames = Math.max(1, Math.ceil(input.durationInFrames / Math.max(1, input.requestedFramesPerLambda)));
478
- if (requiredLambdasByDuration > maxLambdasByDownloadBudget) {
479
- const sourceDescriptor = sourceVideoBytes == null
480
- ? `${formatDurationSeconds(durationSeconds)} remote-video render`
481
- : `${formatBytes(sourceVideoBytes)} over ${formatDurationSeconds(durationSeconds)}`;
482
- throw new Error(`Remote-video render workload (${sourceDescriptor}) exceeds the current Vidfarm Lambda render envelope. The platform would need about ${requiredLambdasByDuration} chunks to keep per-chunk runtime safe, but remote media download policy caps this workload at ${maxLambdasByDownloadBudget} chunk${maxLambdasByDownloadBudget === 1 ? "" : "s"}. Trim, shorten, or pre-compress the source video before rendering.`);
483
- }
484
- const parallelLambdaTarget = inferParallelLambdaTarget({
485
- sourceVideoBytes,
486
- totalRemoteVideoBytes,
487
- outputPixels,
488
- preferredLambdasByRequestedFrames
489
- });
490
- const targetLambdas = Math.max(requiredLambdasByDuration, Math.min(preferredLambdasByRequestedFrames, maxLambdasByDownloadBudget, parallelLambdaTarget));
491
- const strategy = targetLambdas <= 1 ? "single" : targetLambdas <= 3 ? "few" : "parallel";
492
- const reason = describeLambdaPolicyReason({
493
- targetLambdas,
494
- preferredLambdasByRequestedFrames,
495
- maxSafeSegmentDurationSeconds,
496
- sourceVideoBytes,
497
- totalRemoteVideoBytes,
498
- durationSeconds
499
- });
500
- const adaptiveFramesPerLambda = Math.max(input.requestedFramesPerLambda, Math.ceil(input.durationInFrames / targetLambdas));
501
- return {
502
- framesPerLambda: Math.max(1, adaptiveFramesPerLambda),
503
- estimatedLambdaCount: Math.max(1, Math.ceil(input.durationInFrames / Math.max(1, adaptiveFramesPerLambda))),
504
- strategy,
505
- reason,
506
- sourceVideoUrl: sourceVideo?.url ?? null,
507
- sourceVideoBytes,
508
- totalRemoteVideoBytes,
509
- remoteVideoCount: remoteVideoAssets.assets.length,
510
- durationSeconds,
511
- outputWidth: outputDimensions.width,
512
- outputHeight: outputDimensions.height,
513
- outputPixels
514
- };
515
- }
516
- function collectRemoteVideoAssets(inputProps, assets) {
517
- const prioritizedLabels = new Set(collectRemoteVideoLabels(inputProps));
518
- const prioritized = assets.filter((asset) => prioritizedLabels.has(asset.label ?? ""));
519
- const candidates = prioritized.length ? prioritized : assets;
520
- const videoAssets = candidates.filter((asset) => isLikelyVideoAsset(asset));
521
- const totalBytes = videoAssets.reduce((sum, asset) => (sum == null || asset.contentLengthBytes == null ? null : sum + asset.contentLengthBytes), 0);
522
- return {
523
- primary: videoAssets[0] ?? null,
524
- assets: videoAssets,
525
- totalBytes
526
- };
527
- }
528
- function collectRemoteVideoLabels(value, path = "inputProps") {
529
- if (typeof value === "string") {
530
- return isRemoteVideoLabel(path) && isRemoteHttpUrl(value) ? [path] : [];
531
- }
532
- if (Array.isArray(value)) {
533
- return value.flatMap((item, index) => collectRemoteVideoLabels(item, `${path}[${index}]`));
534
- }
535
- if (!value || typeof value !== "object") {
536
- return [];
537
- }
538
- return Object.entries(value).flatMap(([key, item]) => (collectRemoteVideoLabels(item, `${path}.${key}`)));
539
- }
540
- function isRemoteVideoLabel(label) {
541
- return /(source_video_url|backgroundVideoUrl|background_video_url|video_url)$/u.test(label);
542
- }
543
- function isLikelyVideoAsset(asset) {
544
- if (asset.contentType?.toLowerCase().startsWith("video/")) {
545
- return true;
546
- }
547
- return /\.(mp4|mov|m4v|webm)(?:$|[?#])/iu.test(asset.url);
548
- }
549
- function inferMaxSafeSegmentDurationSeconds(input) {
550
- let maxSafeDurationSeconds = inferBaselineMaxSafeSegmentDurationSeconds({
551
- sourceVideoBytes: input.sourceVideoBytes,
552
- durationSeconds: input.durationSeconds
553
- });
554
- const outputPixels = input.outputPixels;
555
- if (outputPixels != null) {
556
- if (outputPixels >= 1920 * 1080) {
557
- maxSafeDurationSeconds = Math.min(maxSafeDurationSeconds, input.durationSeconds <= 30 ? 24 : 20);
558
- }
559
- else if (outputPixels >= 1280 * 720) {
560
- maxSafeDurationSeconds = Math.min(maxSafeDurationSeconds, input.durationSeconds <= 30 ? 36 : 30);
561
- }
562
- else if (outputPixels >= 854 * 480) {
563
- maxSafeDurationSeconds = Math.min(maxSafeDurationSeconds, 45);
564
- }
565
- }
566
- return maxSafeDurationSeconds;
567
- }
568
- function inferBaselineMaxSafeSegmentDurationSeconds(input) {
569
- const bytes = input.sourceVideoBytes;
570
- if (bytes == null) {
571
- return input.durationSeconds <= 30 ? 45 : 60;
572
- }
573
- if (bytes >= 400 * 1024 * 1024) {
574
- return 30;
575
- }
576
- if (bytes >= 250 * 1024 * 1024) {
577
- return input.durationSeconds <= 30 ? 30 : 25;
578
- }
579
- if (bytes >= 200 * 1024 * 1024) {
580
- return input.durationSeconds <= 30 ? 35 : 25;
581
- }
582
- if (bytes >= 150 * 1024 * 1024) {
583
- return input.durationSeconds <= 45 ? 45 : 30;
584
- }
585
- if (bytes >= 75 * 1024 * 1024) {
586
- return 90;
587
- }
588
- return 120;
589
- }
590
- function inferOutputDimensions(inputProps) {
591
- return {
592
- width: parsePositiveInteger(inputProps.output_width),
593
- height: parsePositiveInteger(inputProps.output_height)
594
- };
595
- }
596
- function parsePositiveInteger(value) {
597
- if (typeof value !== "number" || !Number.isFinite(value)) {
598
- return null;
599
- }
600
- const normalized = Math.floor(value);
601
- return normalized > 0 ? normalized : null;
602
- }
603
- function inferMaxLambdasByDownloadBudget(totalRemoteVideoBytes) {
604
- if (totalRemoteVideoBytes == null || totalRemoteVideoBytes <= 0) {
605
- return DEFAULT_PARALLEL_LAMBDA_TARGET;
606
- }
607
- return Math.max(1, Math.min(MAX_PARALLEL_LAMBDA_TARGET, Math.floor(REMOTE_VIDEO_DOWNLOAD_BUDGET_BYTES / totalRemoteVideoBytes)));
608
- }
609
- function inferParallelLambdaTarget(input) {
610
- const requestedTarget = Math.max(1, input.preferredLambdasByRequestedFrames);
611
- const totalRemoteBytes = input.totalRemoteVideoBytes ?? input.sourceVideoBytes;
612
- const outputPixels = input.outputPixels ?? 0;
613
- if (totalRemoteBytes != null && totalRemoteBytes <= SMALL_REMOTE_VIDEO_BYTES) {
614
- return Math.min(MAX_PARALLEL_LAMBDA_TARGET, Math.max(DEFAULT_PARALLEL_LAMBDA_TARGET, requestedTarget));
615
- }
616
- if (totalRemoteBytes != null
617
- && totalRemoteBytes <= MEDIUM_REMOTE_VIDEO_BYTES
618
- && outputPixels <= 1080 * 1920) {
619
- return Math.min(18, Math.max(DEFAULT_PARALLEL_LAMBDA_TARGET, requestedTarget));
620
- }
621
- if (totalRemoteBytes != null
622
- && totalRemoteBytes <= ABSOLUTE_MAX_DIRECT_REMOTE_VIDEO_BYTES
623
- && outputPixels <= 1080 * 1920) {
624
- return Math.min(12, Math.max(DEFAULT_PARALLEL_LAMBDA_TARGET, requestedTarget));
625
- }
626
- return DEFAULT_PARALLEL_LAMBDA_TARGET;
627
- }
628
- function describeLambdaPolicyReason(input) {
629
- const sourcePart = input.sourceVideoBytes == null ? "unknown source size" : `${formatBytes(input.sourceVideoBytes)} source`;
630
- const totalPart = input.totalRemoteVideoBytes == null ? "unknown total remote bytes" : `${formatBytes(input.totalRemoteVideoBytes)} total remote video`;
631
- return `${sourcePart}, ${formatDurationSeconds(input.durationSeconds)} duration, requested ~${input.preferredLambdasByRequestedFrames} chunk${input.preferredLambdasByRequestedFrames === 1 ? "" : "s"}, target <=${formatDurationSeconds(input.maxSafeSegmentDurationSeconds)} per chunk, ${totalPart}`;
632
- }
633
- function formatBytes(bytes) {
634
- if (bytes >= 1024 * 1024) {
635
- return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
636
- }
637
- if (bytes >= 1024) {
638
- return `${(bytes / 1024).toFixed(1)}KB`;
639
- }
640
- return `${bytes}B`;
641
- }
642
- function formatDurationSeconds(seconds) {
643
- return `${seconds.toFixed(seconds >= 10 ? 0 : 1)}s`;
644
- }
645
- function summarizeFatalRenderError(progress) {
646
- if (!progress || typeof progress !== "object") {
647
- return null;
648
- }
649
- const maybeProgress = progress;
650
- if (maybeProgress.fatalErrorEncountered !== true) {
651
- return null;
652
- }
653
- const errors = Array.isArray(maybeProgress.errors) ? maybeProgress.errors : [];
654
- const messages = errors
655
- .map((error) => summarizeRenderError(error))
656
- .filter(Boolean)
657
- .slice(0, 3);
658
- return messages.length ? messages.join(" | ") : "Remotion reported a fatal render error.";
659
- }
660
- function summarizeRenderError(error) {
661
- if (!error || typeof error !== "object") {
662
- return typeof error === "string" ? error : null;
663
- }
664
- const record = error;
665
- const message = firstString(record.message, record.name, record.stack, record.explanation)
666
- ?? firstString(record.error?.message);
667
- const chunk = typeof record.chunk === "number" || typeof record.chunk === "string"
668
- ? `chunk ${record.chunk}: `
669
- : "";
670
- return message ? `${chunk}${message}` : JSON.stringify(record).slice(0, 500);
671
- }
672
- function firstString(...values) {
673
- return values.find((value) => typeof value === "string" && value.trim().length > 0)?.trim() ?? null;
674
- }
675
- function nonBlank(value) {
676
- const trimmed = value?.trim();
677
- return trimmed ? trimmed : undefined;
678
- }
679
- function inferHostedServeUrl(compositionId) {
680
- const bucketName = nonBlank(config.REMOTION_BUCKET_NAME);
681
- if (!bucketName) {
682
- return undefined;
683
- }
684
- const siteName = nonBlank(config.REMOTION_SITE_NAME) ?? compositionId;
685
- const encodedSiteName = siteName.split("/").map(encodeURIComponent).join("/");
686
- return `https://${bucketName}.s3.${config.REMOTION_REGION}.amazonaws.com/sites/${encodedSiteName}/index.html`;
687
- }
688
- //# sourceMappingURL=remotion.js.map