@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,368 +0,0 @@
1
- #!/usr/bin/env node
2
- import { spawn } from "node:child_process";
3
- import { cp, copyFile, mkdir, readFile, stat, writeFile } from "node:fs/promises";
4
- import path from "node:path";
5
- import { fileURLToPath } from "node:url";
6
-
7
- const scriptDir = path.dirname(fileURLToPath(import.meta.url));
8
- const harnessRoot = path.resolve(scriptDir, "..");
9
- const repoRoot = path.resolve(harnessRoot, "..");
10
- const defaultStackName = "hyperframes-vidfarm-prod";
11
- const defaultRegion = "us-east-1";
12
- const memoryBuckets = [2048, 3072, 4096, 6144, 8192, 10240];
13
- const videoExts = new Set([".mp4", ".mov", ".m4v", ".webm"]);
14
- const imageExts = new Set([".png", ".jpg", ".jpeg", ".webp"]);
15
-
16
- const args = process.argv.slice(2);
17
- const stageSite = args.includes("--stage-site");
18
- const inputArg = args.find((arg) => !arg.startsWith("--"));
19
-
20
- if (!inputArg) {
21
- console.error("Usage: node auto-create-hyperframe-templates/scripts/create-hyperframe-template.mjs <media-path|input-manifest.json> [--stage-site]");
22
- process.exit(1);
23
- }
24
-
25
- const manifest = await loadInputManifest(inputArg);
26
- const outputDir = path.resolve(repoRoot, manifest.output_path);
27
- const decomposeInput = await prepareInputForDecomposer(manifest);
28
-
29
- await runCommand(process.execPath, [
30
- path.join(repoRoot, "demo", "scripts", "decompose-static.mjs"),
31
- path.relative(repoRoot, decomposeInput)
32
- ]);
33
-
34
- const decompositionPath = path.join(outputDir, "composition.json");
35
- const decomposition = JSON.parse(await readFile(decompositionPath, "utf8"));
36
- const memoryEstimate = estimateLambdaMemory(decomposition, manifest);
37
- const lambdaSite = await buildLambdaSiteManifest(manifest, outputDir, memoryEstimate, stageSite);
38
-
39
- decomposition.schema = "vidfarm.hyperframe-decomposition.v1";
40
- decomposition.lambda_memory_estimate = memoryEstimate;
41
- decomposition.lambda_site = lambdaSite;
42
-
43
- await writeFile(decompositionPath, `${JSON.stringify(decomposition, null, 2)}\n`);
44
- await writeFile(path.join(outputDir, "lambda-site.json"), `${JSON.stringify(lambdaSite, null, 2)}\n`);
45
-
46
- console.log(`Wrote ${path.relative(repoRoot, path.join(outputDir, "composition.html"))}`);
47
- console.log(`Wrote ${path.relative(repoRoot, decompositionPath)}`);
48
- console.log(`Wrote ${path.relative(repoRoot, path.join(outputDir, "lambda-site.json"))}`);
49
- console.log(`Lambda memory estimate: ${memoryEstimate.recommended_memory_mb} MB (${memoryEstimate.confidence} confidence)`);
50
- if (lambdaSite.site_id) {
51
- console.log(`Lambda site id: ${lambdaSite.site_id}`);
52
- }
53
-
54
- async function loadInputManifest(input) {
55
- const inputPath = path.resolve(repoRoot, input);
56
- const inputStats = await stat(inputPath);
57
- if (inputStats.isFile() && path.extname(inputPath).toLowerCase() === ".json") {
58
- const parsed = JSON.parse(await readFile(inputPath, "utf8"));
59
- if (parsed.mode === "autocreate-hyperframe-template") {
60
- return normalizeManifest(parsed, inputPath);
61
- }
62
- }
63
-
64
- const outputPath = inputStats.isDirectory() ? inputPath : path.dirname(inputPath);
65
- return normalizeManifest({
66
- mode: "autocreate-hyperframe-template",
67
- input_path: path.relative(repoRoot, inputPath),
68
- output_path: path.relative(repoRoot, outputPath),
69
- slug_id: path.basename(outputPath),
70
- source_mode: "auto",
71
- render_defaults: {
72
- width: 720,
73
- height: 1280,
74
- fps: 30
75
- },
76
- lambda: {
77
- stack_name: defaultStackName,
78
- region: defaultRegion,
79
- memory_strategy: "estimate"
80
- },
81
- publish: {
82
- prestage_site: false,
83
- output_url_policy: "signed_https_final_output_only"
84
- }
85
- }, inputPath);
86
- }
87
-
88
- function normalizeManifest(manifest, manifestPath) {
89
- if (manifest.mode !== "autocreate-hyperframe-template") {
90
- throw new Error(`Invalid manifest mode in ${manifestPath}`);
91
- }
92
- return {
93
- ...manifest,
94
- output_path: manifest.output_path || path.dirname(manifest.input_path),
95
- source_mode: manifest.source_mode || "auto",
96
- render_defaults: {
97
- width: Number(manifest.render_defaults?.width || 720),
98
- height: Number(manifest.render_defaults?.height || 1280),
99
- fps: Number(manifest.render_defaults?.fps || 30)
100
- },
101
- lambda: {
102
- stack_name: manifest.lambda?.stack_name || defaultStackName,
103
- region: manifest.lambda?.region || defaultRegion,
104
- memory_strategy: manifest.lambda?.memory_strategy || "estimate",
105
- fixed_memory_mb: manifest.lambda?.fixed_memory_mb
106
- },
107
- publish: {
108
- prestage_site: Boolean(manifest.publish?.prestage_site),
109
- output_url_policy: "signed_https_final_output_only"
110
- }
111
- };
112
- }
113
-
114
- async function prepareInputForDecomposer(manifest) {
115
- const inputPath = path.resolve(repoRoot, manifest.input_path);
116
- const outputPath = path.resolve(repoRoot, manifest.output_path);
117
- const inputStats = await stat(inputPath);
118
-
119
- if (inputStats.isDirectory()) {
120
- if (path.resolve(inputPath) !== path.resolve(outputPath)) {
121
- await mkdir(outputPath, { recursive: true });
122
- await cp(inputPath, outputPath, { recursive: true, force: true });
123
- return outputPath;
124
- }
125
- return inputPath;
126
- }
127
-
128
- const ext = path.extname(inputPath).toLowerCase();
129
- if (!videoExts.has(ext) && !imageExts.has(ext)) {
130
- throw new Error(`Unsupported input media: ${inputPath}`);
131
- }
132
-
133
- if (path.resolve(path.dirname(inputPath)) !== path.resolve(outputPath)) {
134
- await mkdir(outputPath, { recursive: true });
135
- const target = path.join(outputPath, path.basename(inputPath));
136
- await copyFile(inputPath, target);
137
- return target;
138
- }
139
-
140
- return inputPath;
141
- }
142
-
143
- function estimateLambdaMemory(decomposition, manifest) {
144
- const renderDefaults = manifest.render_defaults;
145
- const layers = Array.isArray(decomposition.editor_layers) ? decomposition.editor_layers : [];
146
- const assets = Array.isArray(decomposition.source_assets) ? decomposition.source_assets : [];
147
- const firstAsset = assets[0] || {};
148
- const width = Number(renderDefaults?.width || firstAsset.width || 720);
149
- const height = Number(renderDefaults?.height || firstAsset.height || 1280);
150
- const outputPixels = width * height;
151
- const durationSeconds = layers.reduce((max, layer) => {
152
- return Math.max(max, Number(layer.start || 0) + Number(layer.duration || 0));
153
- }, Number(firstAsset.duration || firstAsset.duration_seconds || 0));
154
- const videoLayers = layers.filter((layer) => layer.type === "video" || layer.kind === "video");
155
- const audioLayers = layers.filter((layer) => layer.type === "audio" || layer.kind === "audio");
156
- const textLayers = layers.filter((layer) => ["caption", "text", "shape", "html"].includes(layer.type || layer.kind));
157
- const uniqueVideoSources = new Set(videoLayers.map((layer) => layer.src || layer.media?.src).filter(Boolean));
158
- const maxSimultaneousVideos = maxOverlap(videoLayers);
159
-
160
- const outputPixelScoreMb = outputPixels <= 1_000_000 ? 0 : outputPixels <= 2_100_000 ? 512 : outputPixels <= 4_000_000 ? 1024 : 2048;
161
- let mediaScoreMb = 0;
162
- if (videoLayers.length > 0 || assets.some((asset) => asset.type === "video")) {
163
- mediaScoreMb += 768;
164
- mediaScoreMb += Math.max(0, maxSimultaneousVideos - 1) * 512;
165
- mediaScoreMb += Math.max(0, uniqueVideoSources.size - 1) * 256;
166
- if (assets.some((asset) => Number(asset.width || 0) * Number(asset.height || 0) > outputPixels * 1.75)) {
167
- mediaScoreMb += 512;
168
- }
169
- }
170
-
171
- let domCaptionScoreMb = layers.length <= 10 ? 0 : layers.length <= 30 ? 256 : 512;
172
- if (textLayers.length >= 4) domCaptionScoreMb += 256;
173
- if (textLayers.some((layer) => String(layer.textBackgroundStyle || layer.background_style || "").includes("highlight"))) {
174
- domCaptionScoreMb += 256;
175
- }
176
-
177
- let effectScoreMb = 0;
178
- if (textLayers.some((layer) => ["outline", "radial_halo"].includes(layer.textBackgroundStyle || layer.background_style))) {
179
- effectScoreMb += 256;
180
- }
181
- if (layers.some((layer) => layer.filter || layer.mask || layer.mixBlendMode || layer.blur)) {
182
- effectScoreMb += 512;
183
- }
184
-
185
- let durationAudioScoreMb = durationSeconds <= 30 ? 0 : durationSeconds <= 60 ? 256 : durationSeconds <= 180 ? 512 : 1024;
186
- if (audioLayers.length > 0 || assets.some((asset) => asset.type === "audio" || asset.type === "video")) {
187
- durationAudioScoreMb += 256;
188
- }
189
- if (audioLayers.length > 1) durationAudioScoreMb += 256;
190
-
191
- const rawEstimateMb = 1536 + outputPixelScoreMb + mediaScoreMb + domCaptionScoreMb + effectScoreMb + durationAudioScoreMb;
192
- let roundedBucketMb = memoryBuckets.find((bucket) => bucket >= rawEstimateMb) || 10240;
193
- if (videoLayers.length === 0 && !assets.some((asset) => asset.type === "video")) {
194
- roundedBucketMb = Math.min(roundedBucketMb, 2048);
195
- }
196
- if ((videoLayers.length > 0 || assets.some((asset) => asset.type === "video")) && maxSimultaneousVideos <= 1 && roundedBucketMb < 3072) {
197
- roundedBucketMb = 3072;
198
- }
199
- if (roundedBucketMb > 4096 && rawEstimateMb < 6144) {
200
- roundedBucketMb = 4096;
201
- }
202
- const fixedMemory = manifest.lambda?.memory_strategy === "fixed"
203
- ? Number(manifest.lambda?.fixed_memory_mb || 0)
204
- : 0;
205
- const recommendedMemoryMb = memoryBuckets.includes(fixedMemory) ? fixedMemory : roundedBucketMb;
206
- const estimatedBilledSeconds = estimateBilledSeconds(durationSeconds, layers.length, videoLayers.length);
207
- const estimatedLambdaGbSeconds = (recommendedMemoryMb / 1024) * estimatedBilledSeconds;
208
- const estimatedCostUsd = estimatedLambdaGbSeconds * 0.0000166667 + 40 * 0.000025;
209
-
210
- const riskFlags = [];
211
- if (videoLayers.length > 0 || assets.some((asset) => asset.type === "video")) riskFlags.push("source_video_decode");
212
- if (maxSimultaneousVideos > 1) riskFlags.push("multiple_simultaneous_video_streams");
213
- if (textLayers.length >= 4) riskFlags.push("caption_or_html_overlay_density");
214
- if (audioLayers.length > 0 || assets.some((asset) => asset.type === "video")) riskFlags.push("continuous_audio");
215
- if (outputPixels > 2_100_000) riskFlags.push("high_output_resolution");
216
-
217
- return {
218
- recommended_memory_mb: recommendedMemoryMb,
219
- confidence: riskFlags.length >= 3 ? "medium" : "high",
220
- complexity_scores: {
221
- output_pixels: outputPixels,
222
- output_pixel_score_mb: outputPixelScoreMb,
223
- max_simultaneous_video_streams: maxSimultaneousVideos,
224
- unique_video_sources: uniqueVideoSources.size,
225
- media_score_mb: mediaScoreMb,
226
- layer_count: layers.length,
227
- text_layer_count: textLayers.length,
228
- dom_caption_score_mb: domCaptionScoreMb,
229
- effect_score_mb: effectScoreMb,
230
- duration_seconds: Number(durationSeconds.toFixed(3)),
231
- duration_audio_score_mb: durationAudioScoreMb,
232
- raw_estimate_mb: rawEstimateMb,
233
- rounded_bucket_mb: roundedBucketMb,
234
- estimated_billed_seconds: estimatedBilledSeconds
235
- },
236
- risk_flags: riskFlags,
237
- rationale: rationaleForEstimate(recommendedMemoryMb, maxSimultaneousVideos, videoLayers.length, outputPixels, textLayers.length),
238
- benchmark_override: null,
239
- estimated_lambda_gb_seconds: Number(estimatedLambdaGbSeconds.toFixed(3)),
240
- estimated_cost_usd: Number(estimatedCostUsd.toFixed(4))
241
- };
242
- }
243
-
244
- function maxOverlap(layers) {
245
- if (layers.length === 0) return 0;
246
- const points = [];
247
- for (const layer of layers) {
248
- const start = Number(layer.start || 0);
249
- const end = start + Number(layer.duration || 0);
250
- if (end > start) {
251
- points.push(start + (end - start) / 2);
252
- points.push(start + 0.001);
253
- }
254
- }
255
- return points.reduce((max, point) => {
256
- const active = layers.filter((layer) => {
257
- const start = Number(layer.start || 0);
258
- const end = start + Number(layer.duration || 0);
259
- return point >= start && point < end;
260
- }).length;
261
- return Math.max(max, active);
262
- }, 0);
263
- }
264
-
265
- function estimateBilledSeconds(durationSeconds, layerCount, videoLayerCount) {
266
- const base = videoLayerCount > 0 ? 90 : 20;
267
- const durationFactor = durationSeconds * (videoLayerCount > 0 ? 8 : 4);
268
- const layerFactor = layerCount * 2;
269
- return Math.ceil(Math.max(base, durationFactor + layerFactor));
270
- }
271
-
272
- function rationaleForEstimate(memoryMb, maxVideos, videoLayerCount, outputPixels, textLayerCount) {
273
- if (videoLayerCount === 0) {
274
- return "No active video decode pressure; simple static/slideshow output fits the 2GB bucket.";
275
- }
276
- if (memoryMb === 3072) {
277
- return "One active social-video stream with deterministic overlays fits the measured 3GB production baseline.";
278
- }
279
- if (memoryMb === 4096) {
280
- return `Raised to 4GB for ${maxVideos} simultaneous video stream(s), ${Math.round(outputPixels / 1_000_000 * 10) / 10}MP output, and ${textLayerCount} text/html layer(s).`;
281
- }
282
- return "Raised above 4GB because composition complexity crosses the normal social-video range.";
283
- }
284
-
285
- async function buildLambdaSiteManifest(manifest, outputDir, memoryEstimate, shouldStageSite) {
286
- const relativeOutput = path.relative(repoRoot, outputDir);
287
- const stackName = manifest.lambda.stack_name || defaultStackName;
288
- const region = manifest.lambda.region || defaultRegion;
289
- const siteUploadCommand = `demo/node_modules/.bin/hyperframes lambda sites create ${shellQuote(relativeOutput)} --stack-name ${shellQuote(stackName)} --region ${shellQuote(region)}`;
290
- const site = {
291
- schema: "vidfarm.hyperframe.lambda-site.v1",
292
- stack_name: stackName,
293
- region,
294
- site_id: null,
295
- project_dir: relativeOutput,
296
- composition_file: "composition.html",
297
- memory_mb: memoryEstimate.recommended_memory_mb,
298
- render_defaults: manifest.render_defaults,
299
- output_url_policy: "signed_https_final_output_only",
300
- prestage_site_requested: Boolean(manifest.publish?.prestage_site),
301
- site_upload_command: siteUploadCommand,
302
- estimated_lambda_gb_seconds: memoryEstimate.estimated_lambda_gb_seconds,
303
- estimated_cost_usd: memoryEstimate.estimated_cost_usd
304
- };
305
-
306
- if (!shouldStageSite) {
307
- return site;
308
- }
309
-
310
- try {
311
- const hyperframesBin = path.join(repoRoot, "demo", "node_modules", ".bin", "hyperframes");
312
- const stdout = await runCommand(hyperframesBin, [
313
- "lambda",
314
- "sites",
315
- "create",
316
- relativeOutput,
317
- "--stack-name",
318
- stackName,
319
- "--region",
320
- region
321
- ]);
322
- site.site_id = parseSiteId(stdout);
323
- site.site_upload_stdout = stdout.trim();
324
- } catch (error) {
325
- site.site_upload_error = error instanceof Error ? error.message : String(error);
326
- }
327
-
328
- return site;
329
- }
330
-
331
- function parseSiteId(stdout) {
332
- const text = String(stdout || "");
333
- const labeled = text.match(/Site ID:\s*([A-Za-z0-9_-]+)/i);
334
- if (labeled) return labeled[1];
335
- const generic = text.match(/\b([a-f0-9]{12,64}|[A-Za-z0-9_-]{12,64})\b/);
336
- return generic ? generic[1] : null;
337
- }
338
-
339
- function runCommand(command, commandArgs) {
340
- return new Promise((resolve, reject) => {
341
- const child = spawn(command, commandArgs, {
342
- cwd: repoRoot,
343
- env: process.env,
344
- stdio: ["ignore", "pipe", "pipe"]
345
- });
346
- let stdout = "";
347
- let stderr = "";
348
- child.stdout.on("data", (chunk) => {
349
- stdout += String(chunk);
350
- process.stdout.write(chunk);
351
- });
352
- child.stderr.on("data", (chunk) => {
353
- stderr += String(chunk);
354
- process.stderr.write(chunk);
355
- });
356
- child.on("error", reject);
357
- child.on("close", (code) => {
358
- if (code === 0) resolve(stdout);
359
- else reject(new Error(`${command} exited ${code}: ${stderr}`));
360
- });
361
- });
362
- }
363
-
364
- function shellQuote(value) {
365
- const text = String(value);
366
- if (/^[A-Za-z0-9_./:=@-]+$/.test(text)) return text;
367
- return `'${text.replaceAll("'", "'\\''")}'`;
368
- }
@@ -1,311 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "title": "HyperFrame Template Plan",
4
- "type": "object",
5
- "required": [
6
- "template",
7
- "composition",
8
- "source_assets",
9
- "layers",
10
- "caption_layout",
11
- "editor_behavior",
12
- "lambda",
13
- "deployment",
14
- "artifacts",
15
- "validation",
16
- "implementation_files"
17
- ],
18
- "properties": {
19
- "template": {
20
- "type": "object",
21
- "required": ["slug_id", "title", "description", "source_folder", "source_type"],
22
- "properties": {
23
- "slug_id": { "type": "string" },
24
- "title": { "type": "string" },
25
- "description": { "type": "string" },
26
- "source_folder": { "type": "string" },
27
- "source_type": { "enum": ["single_video", "scene_split_video", "slideshow", "mixed_media"] },
28
- "viral_dna": { "type": "object" },
29
- "visual_dna": { "type": "object" }
30
- },
31
- "additionalProperties": false
32
- },
33
- "composition": {
34
- "type": "object",
35
- "required": ["composition_id", "width", "height", "fps", "duration_seconds", "background_color", "root_attributes"],
36
- "properties": {
37
- "composition_id": { "type": "string" },
38
- "width": { "type": "integer", "minimum": 1 },
39
- "height": { "type": "integer", "minimum": 1 },
40
- "fps": { "type": "number", "minimum": 1 },
41
- "duration_seconds": { "type": "number", "minimum": 0 },
42
- "background_color": { "type": "string" },
43
- "root_attributes": {
44
- "type": "array",
45
- "items": { "type": "string" }
46
- }
47
- },
48
- "additionalProperties": false
49
- },
50
- "source_assets": {
51
- "type": "array",
52
- "items": { "$ref": "#/$defs/sourceAsset" }
53
- },
54
- "layers": {
55
- "type": "array",
56
- "items": { "$ref": "#/$defs/layer" }
57
- },
58
- "caption_layout": {
59
- "type": "object",
60
- "required": ["safe_areas", "default_style", "surfaces", "rules"],
61
- "properties": {
62
- "safe_areas": { "$ref": "#/$defs/safeAreas" },
63
- "default_style": { "$ref": "#/$defs/textStyle" },
64
- "surfaces": {
65
- "type": "array",
66
- "items": {
67
- "type": "object",
68
- "required": ["id", "layer_ids", "geometry", "rules"],
69
- "properties": {
70
- "id": { "type": "string" },
71
- "layer_ids": { "type": "array", "items": { "type": "string" } },
72
- "geometry": { "$ref": "#/$defs/geometry" },
73
- "rules": { "type": "array", "items": { "type": "string" } }
74
- },
75
- "additionalProperties": false
76
- }
77
- },
78
- "rules": { "type": "array", "items": { "type": "string" } }
79
- },
80
- "additionalProperties": false
81
- },
82
- "editor_behavior": {
83
- "type": "object",
84
- "required": ["publish_source_of_truth", "track_collision_policy", "delete_scene_test"],
85
- "properties": {
86
- "publish_source_of_truth": { "type": "string" },
87
- "preview_playback_source_allowed": { "type": "boolean" },
88
- "track_collision_policy": { "type": "string" },
89
- "delete_scene_test": { "type": "string" }
90
- },
91
- "additionalProperties": false
92
- },
93
- "lambda": {
94
- "type": "object",
95
- "required": ["memory_estimate", "render_defaults"],
96
- "properties": {
97
- "memory_estimate": { "$ref": "#/$defs/lambdaMemoryEstimate" },
98
- "render_defaults": {
99
- "type": "object",
100
- "required": ["width", "height", "fps"],
101
- "properties": {
102
- "width": { "type": "integer", "minimum": 1 },
103
- "height": { "type": "integer", "minimum": 1 },
104
- "fps": { "type": "number", "minimum": 1 }
105
- },
106
- "additionalProperties": false
107
- },
108
- "estimated_lambda_gb_seconds": { "type": "number", "minimum": 0 },
109
- "estimated_cost_usd": { "type": "number", "minimum": 0 }
110
- },
111
- "additionalProperties": false
112
- },
113
- "deployment": {
114
- "type": "object",
115
- "required": ["prod_lambda_site", "output_url_policy"],
116
- "properties": {
117
- "prod_lambda_site": {
118
- "type": "object",
119
- "required": ["schema", "stack_name", "region", "site_id", "project_dir", "composition_file", "memory_mb"],
120
- "properties": {
121
- "schema": { "const": "vidfarm.hyperframe.lambda-site.v1" },
122
- "stack_name": { "type": "string" },
123
- "region": { "type": "string" },
124
- "site_id": { "type": ["string", "null"] },
125
- "project_dir": { "type": "string" },
126
- "composition_file": { "type": "string" },
127
- "memory_mb": { "enum": [2048, 3072, 4096, 6144, 8192, 10240] },
128
- "render_defaults": {
129
- "type": "object",
130
- "properties": {
131
- "width": { "type": "integer", "minimum": 1 },
132
- "height": { "type": "integer", "minimum": 1 },
133
- "fps": { "type": "number", "minimum": 1 }
134
- },
135
- "additionalProperties": false
136
- },
137
- "output_url_policy": { "enum": ["signed_https_final_output_only"] },
138
- "prestage_site_requested": { "type": "boolean" },
139
- "site_upload_command": { "type": "string" },
140
- "site_upload_api": { "type": "string" },
141
- "site_upload_stdout": { "type": "string" },
142
- "site_upload_error": { "type": "string" },
143
- "estimated_lambda_gb_seconds": { "type": "number", "minimum": 0 },
144
- "estimated_cost_usd": { "type": "number", "minimum": 0 }
145
- },
146
- "additionalProperties": false
147
- },
148
- "output_url_policy": { "enum": ["signed_https_final_output_only"] }
149
- },
150
- "additionalProperties": false
151
- },
152
- "artifacts": {
153
- "type": "object",
154
- "required": ["files", "decomposition_shape", "lambda_site_shape"],
155
- "properties": {
156
- "files": { "type": "array", "items": { "type": "string" } },
157
- "decomposition_shape": { "type": "object" },
158
- "lambda_site_shape": { "type": "object" }
159
- },
160
- "additionalProperties": false
161
- },
162
- "validation": {
163
- "type": "object",
164
- "required": ["artifact_checks", "timeline_checks", "publish_checks", "caption_checks", "lambda_checks", "final_output_checks"],
165
- "properties": {
166
- "artifact_checks": { "type": "array", "items": { "type": "string" } },
167
- "timeline_checks": { "type": "array", "items": { "type": "string" } },
168
- "publish_checks": { "type": "array", "items": { "type": "string" } },
169
- "caption_checks": { "type": "array", "items": { "type": "string" } },
170
- "lambda_checks": { "type": "array", "items": { "type": "string" } },
171
- "final_output_checks": { "type": "array", "items": { "type": "string" } }
172
- },
173
- "additionalProperties": false
174
- },
175
- "implementation_files": {
176
- "type": "array",
177
- "items": {
178
- "type": "object",
179
- "required": ["path", "purpose"],
180
- "properties": {
181
- "path": { "type": "string" },
182
- "purpose": { "type": "string" }
183
- },
184
- "additionalProperties": false
185
- }
186
- }
187
- },
188
- "additionalProperties": false,
189
- "$defs": {
190
- "sourceAsset": {
191
- "type": "object",
192
- "required": ["id", "type", "path"],
193
- "properties": {
194
- "id": { "type": "string" },
195
- "type": { "enum": ["video", "image", "audio", "font", "json", "html"] },
196
- "path": { "type": "string" },
197
- "width": { "type": "integer", "minimum": 0 },
198
- "height": { "type": "integer", "minimum": 0 },
199
- "duration_seconds": { "type": "number", "minimum": 0 },
200
- "role": { "type": "string" }
201
- },
202
- "additionalProperties": false
203
- },
204
- "geometry": {
205
- "type": "object",
206
- "required": ["x", "y", "width", "height"],
207
- "properties": {
208
- "x": { "type": "number" },
209
- "y": { "type": "number" },
210
- "width": { "type": "number", "exclusiveMinimum": 0 },
211
- "height": { "type": "number", "exclusiveMinimum": 0 },
212
- "unit": { "const": "percent" }
213
- },
214
- "additionalProperties": false
215
- },
216
- "safeAreas": {
217
- "type": "object",
218
- "properties": {
219
- "top_percent": { "type": "number", "minimum": 0 },
220
- "right_percent": { "type": "number", "minimum": 0 },
221
- "bottom_percent": { "type": "number", "minimum": 0 },
222
- "left_percent": { "type": "number", "minimum": 0 },
223
- "notes": { "type": "array", "items": { "type": "string" } }
224
- },
225
- "additionalProperties": false
226
- },
227
- "textStyle": {
228
- "type": "object",
229
- "properties": {
230
- "font_family": { "type": "string" },
231
- "font_weight": { "type": "integer" },
232
- "font_size_px": { "type": "number" },
233
- "line_height": { "type": "number" },
234
- "color": { "type": "string" },
235
- "background": { "type": "string" },
236
- "background_style": { "enum": ["plain", "outline", "radial_halo", "highlight_solid", "highlight_translucent", "panel"] },
237
- "text_align": { "enum": ["left", "center", "right"] },
238
- "max_lines": { "type": "integer", "minimum": 1 }
239
- },
240
- "additionalProperties": false
241
- },
242
- "layer": {
243
- "type": "object",
244
- "required": ["id", "kind", "start", "duration", "track", "z", "mode", "source_of_truth", "geometry", "viral_alignment"],
245
- "properties": {
246
- "id": { "type": "string" },
247
- "kind": { "enum": ["video", "image", "audio", "caption", "html", "shape", "effect"] },
248
- "start": { "type": "number", "minimum": 0 },
249
- "duration": { "type": "number", "exclusiveMinimum": 0 },
250
- "track": { "type": "integer", "minimum": 0 },
251
- "z": { "type": "integer" },
252
- "mode": { "enum": ["both", "editor", "publish"] },
253
- "source_of_truth": { "enum": ["source_media", "deterministic_html", "generated_asset", "user_asset", "computed_effect"] },
254
- "geometry": { "$ref": "#/$defs/geometry" },
255
- "media": {
256
- "type": "object",
257
- "properties": {
258
- "src": { "type": "string" },
259
- "asset_id": { "type": "string" },
260
- "media_start": { "type": "number", "minimum": 0 },
261
- "media_end": { "type": "number", "minimum": 0 },
262
- "fit": { "enum": ["cover", "contain", "fill", "none"] },
263
- "muted": { "type": "boolean" },
264
- "volume": { "type": "number", "minimum": 0 }
265
- },
266
- "additionalProperties": false
267
- },
268
- "text": {
269
- "type": "object",
270
- "properties": {
271
- "content": { "type": "string" },
272
- "style": { "$ref": "#/$defs/textStyle" }
273
- },
274
- "additionalProperties": false
275
- },
276
- "html_contract": {
277
- "type": "object",
278
- "properties": {
279
- "description": { "type": "string" },
280
- "required_classes": { "type": "array", "items": { "type": "string" } },
281
- "editable_fields": { "type": "array", "items": { "type": "string" } }
282
- },
283
- "additionalProperties": false
284
- },
285
- "viral_alignment": { "type": "string" },
286
- "publish_notes": { "type": "string" }
287
- },
288
- "additionalProperties": false
289
- },
290
- "lambdaMemoryEstimate": {
291
- "type": "object",
292
- "required": ["recommended_memory_mb", "confidence", "complexity_scores", "rationale", "risk_flags"],
293
- "properties": {
294
- "recommended_memory_mb": { "enum": [2048, 3072, 4096, 6144, 8192, 10240] },
295
- "confidence": { "enum": ["low", "medium", "high"] },
296
- "complexity_scores": { "type": "object", "additionalProperties": { "type": ["number", "integer", "string", "boolean"] } },
297
- "rationale": { "type": "string" },
298
- "risk_flags": { "type": "array", "items": { "type": "string" } },
299
- "benchmark_override": {
300
- "type": ["object", "null"],
301
- "properties": {
302
- "memory_mb": { "enum": [2048, 3072, 4096, 6144, 8192, 10240] },
303
- "reason": { "type": "string" }
304
- },
305
- "additionalProperties": false
306
- }
307
- },
308
- "additionalProperties": false
309
- }
310
- }
311
- }