@mevdragon/vidfarm-devcli 0.2.8 → 0.2.10

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 (98) hide show
  1. package/.env.example +9 -0
  2. package/GETTING_STARTED.developers.md +1 -26
  3. package/README.md +3 -0
  4. package/SKILL.developer.md +419 -8
  5. package/auto-create-templates/AUTO_CREATE_TEMPLATES.md +475 -0
  6. package/auto-create-templates/extractor-system-prompt.md +113 -0
  7. package/auto-create-templates/production-graph.schema.json +276 -0
  8. package/auto-create-templates/runbook.md +140 -0
  9. package/auto-create-templates/template-plan.schema.json +230 -0
  10. package/auto-create-templates/template-planner-prompt.md +75 -0
  11. package/dist/src/account-pages-legacy.js +9064 -0
  12. package/dist/src/account-pages.js +41 -620
  13. package/dist/src/app.js +6627 -244
  14. package/dist/src/cli.js +386 -26
  15. package/dist/src/config.js +12 -2
  16. package/dist/src/context.js +35 -35
  17. package/dist/src/db.js +1016 -53
  18. package/dist/src/dev-app-legacy.js +693 -0
  19. package/dist/src/dev-app.js +4 -904
  20. package/dist/src/domain.js +1 -1
  21. package/dist/src/editor-chat-history.js +72 -0
  22. package/dist/src/editor-chat.js +202 -0
  23. package/dist/src/frontend/flockposter-cache-store.js +116 -0
  24. package/dist/src/frontend/homepage-client.js +114 -0
  25. package/dist/src/frontend/homepage-shared.js +3 -0
  26. package/dist/src/frontend/homepage-store.js +27 -0
  27. package/dist/src/frontend/homepage-view.js +147 -0
  28. package/dist/src/frontend/page-runtime-client.js +100 -0
  29. package/dist/src/frontend/page-runtime-store.js +8 -0
  30. package/dist/src/frontend/template-editor-chat.js +2261 -0
  31. package/dist/src/homepage.js +695 -371
  32. package/dist/src/lib/template-style-options.js +95 -15
  33. package/dist/src/page-runtime.js +1 -0
  34. package/dist/src/page-shell.js +941 -0
  35. package/dist/src/primitive-context.js +163 -0
  36. package/dist/src/primitive-registry.js +340 -0
  37. package/dist/src/primitive-sdk.js +3 -0
  38. package/dist/src/primitives/remotion/html-image.js +28 -0
  39. package/dist/src/react-page-shell.js +34 -0
  40. package/dist/src/ready-post-schedule-component.js +1514 -0
  41. package/dist/src/registry.js +36 -17
  42. package/dist/src/runtime.js +6 -1
  43. package/dist/src/services/api-call-history.js +245 -0
  44. package/dist/src/services/auth.js +25 -3
  45. package/dist/src/services/billing.js +248 -9
  46. package/dist/src/services/chat-threads.js +88 -0
  47. package/dist/src/services/job-logs.js +14 -7
  48. package/dist/src/services/jobs.js +13 -2
  49. package/dist/src/services/providers.js +552 -133
  50. package/dist/src/services/rate-limits.js +236 -0
  51. package/dist/src/services/remotion.js +143 -16
  52. package/dist/src/services/storage.js +10 -8
  53. package/dist/src/services/template-certification.js +11 -2
  54. package/dist/src/services/template-loader.js +3 -1
  55. package/dist/src/services/template-sources.js +68 -3
  56. package/dist/src/template-editor-pages.js +2309 -0
  57. package/dist/src/template-editor-shell.js +1507 -0
  58. package/dist/src/worker.js +120 -22
  59. package/package.json +27 -4
  60. package/public/assets/homepage-app.js +54 -0
  61. package/public/assets/homepage-client-app.js +54 -0
  62. package/public/assets/page-runtime-client-app.js +68 -0
  63. package/dist/templates/vidfarm_template_0000/src/lib/images.js +0 -202
  64. package/dist/templates/vidfarm_template_0000/src/remotion/Root.js +0 -34
  65. package/dist/templates/vidfarm_template_0000/src/remotion/index.js +0 -3
  66. package/dist/templates/vidfarm_template_0000/src/sdk.js +0 -3
  67. package/dist/templates/vidfarm_template_0000/src/style-options.js +0 -51
  68. package/dist/templates/vidfarm_template_0000/src/template-dna.js +0 -9
  69. package/dist/templates/vidfarm_template_0000/src/template.js +0 -1447
  70. package/templates/vidfarm_template_0000/README.md +0 -100
  71. package/templates/vidfarm_template_0000/SKILL.md +0 -225
  72. package/templates/vidfarm_template_0000/assets/Abel-Regular.ttf +0 -0
  73. package/templates/vidfarm_template_0000/assets/DMSerifDisplay-Regular.ttf +0 -0
  74. package/templates/vidfarm_template_0000/assets/Montserrat[wght].ttf +0 -0
  75. package/templates/vidfarm_template_0000/assets/SourceCodePro[wght].ttf +0 -0
  76. package/templates/vidfarm_template_0000/assets/TikTokSans-SemiBold.ttf +0 -0
  77. package/templates/vidfarm_template_0000/assets/Yesteryear-Regular.ttf +0 -0
  78. package/templates/vidfarm_template_0000/composition.json +0 -11
  79. package/templates/vidfarm_template_0000/package.json +0 -27
  80. package/templates/vidfarm_template_0000/research/preview/.gitkeep +0 -1
  81. package/templates/vidfarm_template_0000/research/source_notes.md +0 -7
  82. package/templates/vidfarm_template_0000/src/lib/images.js +0 -202
  83. package/templates/vidfarm_template_0000/src/lib/images.ts +0 -241
  84. package/templates/vidfarm_template_0000/src/remotion/Root.js +0 -33
  85. package/templates/vidfarm_template_0000/src/remotion/Root.tsx +0 -75
  86. package/templates/vidfarm_template_0000/src/remotion/index.js +0 -3
  87. package/templates/vidfarm_template_0000/src/remotion/index.tsx +0 -4
  88. package/templates/vidfarm_template_0000/src/sdk.js +0 -3
  89. package/templates/vidfarm_template_0000/src/sdk.ts +0 -140
  90. package/templates/vidfarm_template_0000/src/style-options.js +0 -51
  91. package/templates/vidfarm_template_0000/src/style-options.ts +0 -60
  92. package/templates/vidfarm_template_0000/src/template-dna.js +0 -9
  93. package/templates/vidfarm_template_0000/src/template-dna.ts +0 -15
  94. package/templates/vidfarm_template_0000/src/template.js +0 -1447
  95. package/templates/vidfarm_template_0000/src/template.ts +0 -2049
  96. package/templates/vidfarm_template_0000/template.config.json +0 -21
  97. package/templates/vidfarm_template_0000/tmp/solobacterium-moorei-slideshow.request.json +0 -31
  98. package/templates/vidfarm_template_0000/tsconfig.json +0 -19
@@ -0,0 +1,163 @@
1
+ import { config } from "./config.js";
2
+ import { database } from "./db.js";
3
+ import { createId } from "./lib/ids.js";
4
+ import { jobLogStore } from "./services/job-logs.js";
5
+ export function createPrimitiveJobContext(input) {
6
+ const prefix = input.storage.primitiveJobPrefix(input.primitive.id, input.customer.id, input.job.id);
7
+ const buildArtifactUrl = (storageKey, fallbackUrl) => fallbackUrl ?? input.storage.getPublicUrl(storageKey);
8
+ return {
9
+ env: config.isProduction ? "production" : "development",
10
+ customer: input.customer,
11
+ logger: {
12
+ debug(message, metadata = {}) {
13
+ jobLogStore.addEvent({
14
+ id: createId("evt"),
15
+ jobId: input.job.id,
16
+ level: "debug",
17
+ message,
18
+ metadata,
19
+ progress: null,
20
+ artifactKey: null
21
+ });
22
+ },
23
+ info(message, metadata = {}) {
24
+ jobLogStore.addEvent({
25
+ id: createId("evt"),
26
+ jobId: input.job.id,
27
+ level: "info",
28
+ message,
29
+ metadata,
30
+ progress: null,
31
+ artifactKey: null
32
+ });
33
+ },
34
+ warn(message, metadata = {}) {
35
+ jobLogStore.addEvent({
36
+ id: createId("evt"),
37
+ jobId: input.job.id,
38
+ level: "warn",
39
+ message,
40
+ metadata,
41
+ progress: null,
42
+ artifactKey: null
43
+ });
44
+ },
45
+ error(message, metadata = {}) {
46
+ jobLogStore.addEvent({
47
+ id: createId("evt"),
48
+ jobId: input.job.id,
49
+ level: "error",
50
+ message,
51
+ metadata,
52
+ progress: null,
53
+ artifactKey: null
54
+ });
55
+ },
56
+ progress(progress, message, metadata = {}) {
57
+ jobLogStore.addEvent({
58
+ id: createId("evt"),
59
+ jobId: input.job.id,
60
+ level: "info",
61
+ message,
62
+ metadata,
63
+ progress,
64
+ artifactKey: typeof metadata.artifactKey === "string" ? metadata.artifactKey : null
65
+ });
66
+ database.updateJobStatus({
67
+ id: input.job.id,
68
+ status: "running",
69
+ progress
70
+ });
71
+ }
72
+ },
73
+ storage: {
74
+ async putJson(key, value) {
75
+ const stored = await input.storage.putJson(`${prefix}/${key}`, value);
76
+ const artifactUrl = buildArtifactUrl(stored.key, stored.url);
77
+ insertArtifact("json", stored.key, artifactUrl, {});
78
+ return { ...stored, url: artifactUrl };
79
+ },
80
+ async putText(key, value, contentType = "text/plain; charset=utf-8") {
81
+ const stored = await input.storage.putText(`${prefix}/${key}`, value, contentType);
82
+ const artifactUrl = buildArtifactUrl(stored.key, stored.url);
83
+ insertArtifact("text", stored.key, artifactUrl, { contentType });
84
+ return { ...stored, url: artifactUrl };
85
+ },
86
+ async putBuffer(key, value, options = {}) {
87
+ const stored = await input.storage.putBuffer(`${prefix}/${key}`, value, options.contentType);
88
+ const artifactUrl = buildArtifactUrl(stored.key, stored.url);
89
+ insertArtifact(options.kind ?? "binary", stored.key, artifactUrl, {
90
+ ...(options.metadata ?? {}),
91
+ contentType: options.contentType ?? null
92
+ });
93
+ return { ...stored, url: artifactUrl };
94
+ },
95
+ getPublicUrl(key) {
96
+ return input.storage.getPublicUrl(`${prefix}/${key}`);
97
+ }
98
+ },
99
+ billing: {
100
+ async record(record) {
101
+ await input.billing.record({
102
+ customerId: input.customer.id,
103
+ jobId: input.job.id,
104
+ tracer: input.job.tracer,
105
+ templateId: input.primitive.id,
106
+ type: record.type,
107
+ costUsd: record.costUsd,
108
+ chargeUsd: record.chargeUsd ?? Number((record.costUsd * 1.2).toFixed(4)),
109
+ costCenterSlug: record.costCenterSlug,
110
+ idempotencyKey: record.idempotencyKey,
111
+ occurredAtMs: record.occurredAtMs,
112
+ metadata: record.metadata
113
+ });
114
+ }
115
+ },
116
+ providers: {
117
+ async generateImage(request) {
118
+ return input.providers.generateImage({
119
+ customerId: input.customer.id,
120
+ jobId: input.job.id,
121
+ workerId: input.workerId,
122
+ ...request
123
+ });
124
+ },
125
+ async editImage(request) {
126
+ return input.providers.editImage({
127
+ customerId: input.customer.id,
128
+ jobId: input.job.id,
129
+ workerId: input.workerId,
130
+ ...request
131
+ });
132
+ },
133
+ async inpaintImage(request) {
134
+ return input.providers.inpaintImage({
135
+ customerId: input.customer.id,
136
+ jobId: input.job.id,
137
+ workerId: input.workerId,
138
+ ...request
139
+ });
140
+ }
141
+ },
142
+ remotion: {
143
+ async renderStill(request) {
144
+ return input.remotion.renderStill({
145
+ ...request,
146
+ outputKey: request.outputKey ? `${prefix}/${request.outputKey}` : undefined
147
+ });
148
+ }
149
+ }
150
+ };
151
+ function insertArtifact(kind, storageKey, publicUrl, metadata) {
152
+ database.insertArtifact({
153
+ id: createId("art"),
154
+ jobId: input.job.id,
155
+ customerId: input.customer.id,
156
+ templateId: input.primitive.id,
157
+ kind,
158
+ storageKey,
159
+ publicUrl,
160
+ metadata
161
+ });
162
+ }
163
+ }
@@ -0,0 +1,340 @@
1
+ import path from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import sharp from "sharp";
4
+ import { z } from "zod";
5
+ import { definePrimitive } from "./primitive-sdk.js";
6
+ const imageProviderSchema = z.enum(["openai", "gemini", "openrouter"]);
7
+ const outputFormatSchema = z.enum(["png", "jpeg", "webp"]);
8
+ const aspectRatioSchema = z.enum(["1:1", "4:3", "3:4", "16:9", "9:16"]).optional();
9
+ const imageSizeSchema = z.enum(["1K", "2K", "4K"]).optional();
10
+ const generateImagePayloadSchema = z.object({
11
+ provider: imageProviderSchema.default("gemini"),
12
+ model: z.string().min(1).optional(),
13
+ prompt: z.string().min(3).max(8000),
14
+ prompt_attachments: z.array(z.string().url()).max(12).default([]),
15
+ aspect_ratio: aspectRatioSchema,
16
+ size: z.string().min(1).max(40).optional(),
17
+ image_size: imageSizeSchema,
18
+ output_format: outputFormatSchema.default("png")
19
+ });
20
+ const editImagePayloadSchema = z.object({
21
+ provider: imageProviderSchema.default("gemini"),
22
+ model: z.string().min(1).optional(),
23
+ source_image_url: z.string().url(),
24
+ instruction: z.string().min(3).max(8000),
25
+ reference_attachments: z.array(z.string().url()).max(12).default([]),
26
+ aspect_ratio: aspectRatioSchema,
27
+ size: z.string().min(1).max(40).optional(),
28
+ image_size: imageSizeSchema,
29
+ output_format: outputFormatSchema.default("png")
30
+ });
31
+ const inpaintImagePayloadSchema = z.object({
32
+ provider: imageProviderSchema.default("openai"),
33
+ model: z.string().min(1).optional(),
34
+ source_image_url: z.string().url(),
35
+ mask_url: z.string().url(),
36
+ instruction: z.string().min(3).max(8000),
37
+ reference_attachments: z.array(z.string().url()).max(12).default([]),
38
+ aspect_ratio: aspectRatioSchema,
39
+ size: z.string().min(1).max(40).optional(),
40
+ image_size: imageSizeSchema,
41
+ output_format: outputFormatSchema.default("png")
42
+ });
43
+ const renderHtmlImagePayloadSchema = z.object({
44
+ width: z.number().int().min(16).max(4096).default(1080),
45
+ height: z.number().int().min(16).max(4096).default(1920),
46
+ html: z.string().min(1).max(200_000),
47
+ css: z.string().max(200_000).optional(),
48
+ background_color: z.string().min(1).max(64).default("#ffffff"),
49
+ output_format: outputFormatSchema.default("png")
50
+ });
51
+ const PRIMITIVE_IMAGE_GENERATE_ID = "primitive:image_generate";
52
+ const PRIMITIVE_IMAGE_EDIT_ID = "primitive:image_edit";
53
+ const PRIMITIVE_IMAGE_INPAINT_ID = "primitive:image_inpaint";
54
+ const PRIMITIVE_IMAGE_RENDER_HTML_ID = "primitive:image_render_html";
55
+ const HTML_IMAGE_ENTRY_POINT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "primitives", "remotion", "html-image.tsx");
56
+ const HTML_IMAGE_COMPOSITION_ID = "primitive-html-image";
57
+ const imageGeneratePrimitive = definePrimitive({
58
+ id: PRIMITIVE_IMAGE_GENERATE_ID,
59
+ kind: "image_generate",
60
+ operations: {
61
+ run: {
62
+ description: "Generate a new image and persist it as a reusable platform URL.",
63
+ inputSchema: generateImagePayloadSchema,
64
+ workflow: "run"
65
+ }
66
+ },
67
+ jobs: {
68
+ async run(ctx, input) {
69
+ const payload = generateImagePayloadSchema.parse(input);
70
+ ctx.logger.progress(0.12, "Generating primitive image");
71
+ const provider = payload.provider;
72
+ const model = payload.model ?? defaultImageModelForProvider(provider);
73
+ const generated = await ctx.providers.generateImage({
74
+ provider,
75
+ model,
76
+ prompt: payload.prompt,
77
+ promptAttachments: payload.prompt_attachments,
78
+ aspectRatio: payload.aspect_ratio,
79
+ size: payload.size,
80
+ imageSize: payload.image_size
81
+ });
82
+ const normalized = await normalizePrimitiveImageOutput(generated.bytes, payload.output_format);
83
+ const stored = await storePrimitiveImage(ctx, {
84
+ key: `output.${extensionForOutputFormat(payload.output_format)}`,
85
+ bytes: normalized.bytes,
86
+ contentType: normalized.contentType,
87
+ metadata: {
88
+ primitive: "image_generate",
89
+ provider,
90
+ model,
91
+ prompt: payload.prompt,
92
+ revisedPrompt: generated.revisedPrompt
93
+ }
94
+ });
95
+ ctx.logger.progress(1, "Primitive image generation complete");
96
+ return {
97
+ progress: 1,
98
+ output: buildImagePrimitiveOutput({
99
+ fileUrl: stored.url,
100
+ contentType: stored.contentType,
101
+ revisedPrompt: generated.revisedPrompt,
102
+ files: stored.url ? [stored.url] : []
103
+ })
104
+ };
105
+ }
106
+ }
107
+ });
108
+ const imageEditPrimitive = definePrimitive({
109
+ id: PRIMITIVE_IMAGE_EDIT_ID,
110
+ kind: "image_edit",
111
+ operations: {
112
+ run: {
113
+ description: "Edit an existing image into a new reusable platform URL.",
114
+ inputSchema: editImagePayloadSchema,
115
+ workflow: "run"
116
+ }
117
+ },
118
+ jobs: {
119
+ async run(ctx, input) {
120
+ const payload = editImagePayloadSchema.parse(input);
121
+ ctx.logger.progress(0.12, "Editing primitive image");
122
+ const provider = payload.provider;
123
+ const model = payload.model ?? defaultImageModelForProvider(provider);
124
+ const edited = await ctx.providers.editImage({
125
+ provider,
126
+ model,
127
+ sourceImageUrl: payload.source_image_url,
128
+ instruction: payload.instruction,
129
+ referenceAttachments: payload.reference_attachments,
130
+ aspectRatio: payload.aspect_ratio,
131
+ size: payload.size,
132
+ imageSize: payload.image_size
133
+ });
134
+ const normalized = await normalizePrimitiveImageOutput(edited.bytes, payload.output_format);
135
+ const stored = await storePrimitiveImage(ctx, {
136
+ key: `output.${extensionForOutputFormat(payload.output_format)}`,
137
+ bytes: normalized.bytes,
138
+ contentType: normalized.contentType,
139
+ metadata: {
140
+ primitive: "image_edit",
141
+ provider,
142
+ model,
143
+ sourceImageUrl: payload.source_image_url,
144
+ instruction: payload.instruction,
145
+ revisedPrompt: edited.revisedPrompt
146
+ }
147
+ });
148
+ ctx.logger.progress(1, "Primitive image edit complete");
149
+ return {
150
+ progress: 1,
151
+ output: buildImagePrimitiveOutput({
152
+ fileUrl: stored.url,
153
+ contentType: stored.contentType,
154
+ revisedPrompt: edited.revisedPrompt,
155
+ derivedFromUrl: payload.source_image_url,
156
+ files: stored.url ? [stored.url] : []
157
+ })
158
+ };
159
+ }
160
+ }
161
+ });
162
+ const imageInpaintPrimitive = definePrimitive({
163
+ id: PRIMITIVE_IMAGE_INPAINT_ID,
164
+ kind: "image_inpaint",
165
+ operations: {
166
+ run: {
167
+ description: "Inpaint a masked region of an existing image into a new reusable platform URL.",
168
+ inputSchema: inpaintImagePayloadSchema,
169
+ workflow: "run"
170
+ }
171
+ },
172
+ jobs: {
173
+ async run(ctx, input) {
174
+ const payload = inpaintImagePayloadSchema.parse(input);
175
+ ctx.logger.progress(0.12, "Inpainting primitive image");
176
+ const provider = payload.provider;
177
+ const model = payload.model ?? defaultImageModelForProvider(provider);
178
+ const edited = await ctx.providers.inpaintImage({
179
+ provider,
180
+ model,
181
+ sourceImageUrl: payload.source_image_url,
182
+ maskUrl: payload.mask_url,
183
+ instruction: payload.instruction,
184
+ referenceAttachments: payload.reference_attachments,
185
+ aspectRatio: payload.aspect_ratio,
186
+ size: payload.size,
187
+ imageSize: payload.image_size
188
+ });
189
+ const normalized = await normalizePrimitiveImageOutput(edited.bytes, payload.output_format);
190
+ const stored = await storePrimitiveImage(ctx, {
191
+ key: `output.${extensionForOutputFormat(payload.output_format)}`,
192
+ bytes: normalized.bytes,
193
+ contentType: normalized.contentType,
194
+ metadata: {
195
+ primitive: "image_inpaint",
196
+ provider,
197
+ model,
198
+ sourceImageUrl: payload.source_image_url,
199
+ maskUrl: payload.mask_url,
200
+ instruction: payload.instruction,
201
+ revisedPrompt: edited.revisedPrompt
202
+ }
203
+ });
204
+ ctx.logger.progress(1, "Primitive image inpaint complete");
205
+ return {
206
+ progress: 1,
207
+ output: buildImagePrimitiveOutput({
208
+ fileUrl: stored.url,
209
+ contentType: stored.contentType,
210
+ revisedPrompt: edited.revisedPrompt,
211
+ derivedFromUrl: payload.source_image_url,
212
+ maskUrl: payload.mask_url,
213
+ files: stored.url ? [stored.url] : []
214
+ })
215
+ };
216
+ }
217
+ }
218
+ });
219
+ const imageRenderHtmlPrimitive = definePrimitive({
220
+ id: PRIMITIVE_IMAGE_RENDER_HTML_ID,
221
+ kind: "image_render_html",
222
+ operations: {
223
+ run: {
224
+ description: "Render an HTML-driven Remotion still image into a reusable platform URL.",
225
+ inputSchema: renderHtmlImagePayloadSchema,
226
+ workflow: "run"
227
+ }
228
+ },
229
+ jobs: {
230
+ async run(ctx, input) {
231
+ const payload = renderHtmlImagePayloadSchema.parse(input);
232
+ ctx.logger.progress(0.18, "Rendering primitive HTML image");
233
+ const rendered = await ctx.remotion.renderStill({
234
+ compositionId: HTML_IMAGE_COMPOSITION_ID,
235
+ entryPoint: HTML_IMAGE_ENTRY_POINT,
236
+ imageFormat: payload.output_format,
237
+ outputKey: `output.${extensionForOutputFormat(payload.output_format)}`,
238
+ inputProps: {
239
+ width: payload.width,
240
+ height: payload.height,
241
+ html: payload.html,
242
+ css: payload.css ?? "",
243
+ backgroundColor: payload.background_color
244
+ }
245
+ });
246
+ ctx.logger.progress(1, "Primitive HTML image render complete");
247
+ return {
248
+ progress: 1,
249
+ output: {
250
+ files: rendered.outputUrl ? [rendered.outputUrl] : [],
251
+ primary_file_url: rendered.outputUrl,
252
+ image: {
253
+ file_url: rendered.outputUrl,
254
+ content_type: contentTypeForOutputFormat(payload.output_format),
255
+ width: payload.width,
256
+ height: payload.height
257
+ },
258
+ render: rendered
259
+ }
260
+ };
261
+ }
262
+ }
263
+ });
264
+ class PrimitiveRegistry {
265
+ definitions = new Map([
266
+ [imageGeneratePrimitive.id, imageGeneratePrimitive],
267
+ [imageEditPrimitive.id, imageEditPrimitive],
268
+ [imageInpaintPrimitive.id, imageInpaintPrimitive],
269
+ [imageRenderHtmlPrimitive.id, imageRenderHtmlPrimitive]
270
+ ]);
271
+ get(id) {
272
+ return this.definitions.get(id) ?? null;
273
+ }
274
+ list() {
275
+ return [...this.definitions.values()];
276
+ }
277
+ }
278
+ export const primitiveRegistry = new PrimitiveRegistry();
279
+ async function storePrimitiveImage(ctx, input) {
280
+ const stored = await ctx.storage.putBuffer(input.key, input.bytes, {
281
+ contentType: input.contentType,
282
+ kind: "image",
283
+ metadata: input.metadata
284
+ });
285
+ return { ...stored, contentType: input.contentType };
286
+ }
287
+ function buildImagePrimitiveOutput(input) {
288
+ return {
289
+ files: input.files,
290
+ primary_file_url: input.fileUrl,
291
+ image: {
292
+ file_url: input.fileUrl,
293
+ content_type: input.contentType,
294
+ ...(input.revisedPrompt !== undefined ? { revised_prompt: input.revisedPrompt } : {}),
295
+ ...(input.derivedFromUrl ? { derived_from_url: input.derivedFromUrl } : {}),
296
+ ...(input.maskUrl ? { mask_url: input.maskUrl } : {})
297
+ }
298
+ };
299
+ }
300
+ function defaultImageModelForProvider(provider) {
301
+ switch (provider) {
302
+ case "openai":
303
+ return "gpt-image-1";
304
+ case "openrouter":
305
+ return "google/gemini-2.5-flash-image-preview";
306
+ default:
307
+ return "gemini-2.5-flash-image";
308
+ }
309
+ }
310
+ function extensionForOutputFormat(format) {
311
+ return format === "jpeg" ? "jpg" : format;
312
+ }
313
+ function contentTypeForOutputFormat(format, fallback) {
314
+ if (format === "jpeg") {
315
+ return "image/jpeg";
316
+ }
317
+ if (format === "webp") {
318
+ return "image/webp";
319
+ }
320
+ return fallback && fallback !== "image/svg+xml" ? fallback : "image/png";
321
+ }
322
+ async function normalizePrimitiveImageOutput(bytes, format) {
323
+ const buffer = Buffer.isBuffer(bytes) ? bytes : Buffer.from(bytes);
324
+ if (format === "jpeg") {
325
+ return {
326
+ bytes: await sharp(buffer).jpeg({ quality: 92 }).toBuffer(),
327
+ contentType: "image/jpeg"
328
+ };
329
+ }
330
+ if (format === "webp") {
331
+ return {
332
+ bytes: await sharp(buffer).webp({ quality: 92 }).toBuffer(),
333
+ contentType: "image/webp"
334
+ };
335
+ }
336
+ return {
337
+ bytes: await sharp(buffer).png().toBuffer(),
338
+ contentType: "image/png"
339
+ };
340
+ }
@@ -0,0 +1,3 @@
1
+ export function definePrimitive(definition) {
2
+ return definition;
3
+ }
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { AbsoluteFill, Composition } from "remotion";
3
+ const defaultProps = {
4
+ width: 1080,
5
+ height: 1920,
6
+ html: "<div>Empty primitive HTML image.</div>",
7
+ css: "",
8
+ backgroundColor: "#ffffff"
9
+ };
10
+ const HtmlImageComposition = ({ html, css = "", backgroundColor = "#ffffff" }) => {
11
+ return (_jsxs(AbsoluteFill, { style: {
12
+ backgroundColor,
13
+ overflow: "hidden",
14
+ fontFamily: "Arial, sans-serif"
15
+ }, children: [css ? _jsx("style", { dangerouslySetInnerHTML: { __html: css } }) : null, _jsx("div", { style: {
16
+ width: "100%",
17
+ height: "100%"
18
+ }, dangerouslySetInnerHTML: { __html: html } })] }));
19
+ };
20
+ export const PrimitiveHtmlImageRoot = () => {
21
+ return (_jsx(Composition, { id: "primitive-html-image", component: HtmlImageComposition, width: 1080, height: 1920, fps: 30, durationInFrames: 1, defaultProps: defaultProps, calculateMetadata: ({ props }) => ({
22
+ width: typeof props.width === "number" ? Math.max(1, Math.round(props.width)) : 1080,
23
+ height: typeof props.height === "number" ? Math.max(1, Math.round(props.height)) : 1920,
24
+ durationInFrames: 1,
25
+ fps: 30
26
+ }) }));
27
+ };
28
+ export default PrimitiveHtmlImageRoot;
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { renderToStaticMarkup } from "react-dom/server";
3
+ import { escapeHtml } from "./page-shell.js";
4
+ function extractTagContent(documentHtml, tagName) {
5
+ const match = documentHtml.match(new RegExp(`<${tagName}[^>]*>([\\s\\S]*?)<\\/${tagName}>`, "i"));
6
+ return match?.[1] ?? "";
7
+ }
8
+ export function parseLegacyDocument(documentHtml) {
9
+ return {
10
+ title: extractTagContent(documentHtml, "title"),
11
+ bodyHtml: extractTagContent(documentHtml, "body"),
12
+ styleText: extractTagContent(documentHtml, "style")
13
+ };
14
+ }
15
+ function ReactDocument(input) {
16
+ const runtimeBoot = input.runtimeBoot ?? {
17
+ pageKind: "legacy",
18
+ title: input.title || "VidFarm AI"
19
+ };
20
+ return (_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx("meta", { charSet: "utf-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), _jsx("title", { children: input.title }), _jsx("link", { rel: "icon", href: "/assets/favicon.ico", sizes: "any" }), _jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "" }), _jsx("link", { href: "https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Manrope:wght@400;500;600;700;800&display=swap", rel: "stylesheet" }), _jsx("style", { dangerouslySetInnerHTML: { __html: input.styleText } })] }), _jsxs("body", { children: [_jsx("div", { dangerouslySetInnerHTML: { __html: input.bodyHtml } }), _jsx("div", { id: "page-runtime-root", hidden: true }), _jsx("script", { id: "page-runtime-boot", type: "application/json", dangerouslySetInnerHTML: { __html: JSON.stringify(runtimeBoot).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026") } }), _jsx("script", { type: "module", src: "/assets/page-runtime-client-app.js" })] })] }));
21
+ }
22
+ export function renderParsedDocument(input) {
23
+ return `<!doctype html>${renderToStaticMarkup(_jsx(ReactDocument, { ...input }))}`;
24
+ }
25
+ export function renderLegacyPageAsReact(documentHtml, runtimeBoot) {
26
+ const parsed = parseLegacyDocument(documentHtml);
27
+ const safeTitle = parsed.title ? parsed.title : escapeHtml("VidFarm AI");
28
+ return renderParsedDocument({
29
+ title: safeTitle,
30
+ bodyHtml: parsed.bodyHtml,
31
+ styleText: parsed.styleText,
32
+ runtimeBoot
33
+ });
34
+ }