@mevdragon/vidfarm-devcli 0.1.0 → 0.2.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.
- package/.env.example +12 -5
- package/PLATFORM_SPEC.md +143 -2
- package/README.md +165 -16
- package/SKILL.developer.md +258 -0
- package/SKILL.director.md +599 -0
- package/dist/infra/cdk/bin/vidfarm-prod.js +59 -0
- package/dist/infra/cdk/lib/vidfarm-prod-stack.js +212 -0
- package/dist/src/account-pages.js +630 -0
- package/dist/src/app.js +897 -66
- package/dist/src/cli.js +284 -5
- package/dist/src/config.js +25 -5
- package/dist/src/context.js +1 -1
- package/dist/src/db.js +427 -18
- package/dist/src/dev-app.js +59 -12
- package/dist/src/homepage.js +441 -0
- package/dist/src/index.js +12 -7
- package/dist/src/lib/crypto.js +14 -0
- package/dist/src/lib/template-dna.js +542 -0
- package/dist/src/lib/template-style-options.js +49 -0
- package/dist/src/registry.js +54 -7
- package/dist/src/runtime.js +3 -1
- package/dist/src/services/auth.js +69 -5
- package/dist/src/services/jobs.js +23 -4
- package/dist/src/services/providers.js +74 -12
- package/dist/src/services/storage.js +74 -18
- package/dist/src/services/template-certification.js +160 -0
- package/dist/src/services/template-loader.js +37 -0
- package/dist/src/services/template-sources.js +135 -0
- package/dist/src/worker.js +19 -7
- package/dist/templates/template_0000/src/lib/images.js +242 -0
- package/dist/templates/template_0000/src/remotion/Root.js +33 -0
- package/dist/templates/template_0000/src/sdk.js +3 -0
- package/dist/templates/template_0000/src/style-options.js +51 -0
- package/dist/templates/template_0000/src/template-dna.js +9 -0
- package/dist/templates/template_0000/src/template.js +1217 -0
- package/package.json +10 -1
- package/templates/template_0000/README.md +121 -0
- package/templates/template_0000/SKILL.md +193 -0
- package/templates/template_0000/assets/Abel-Regular.ttf +0 -0
- package/templates/template_0000/assets/DMSerifDisplay-Regular.ttf +0 -0
- package/templates/template_0000/assets/Montserrat[wght].ttf +0 -0
- package/templates/template_0000/assets/SourceCodePro[wght].ttf +0 -0
- package/templates/template_0000/assets/TikTokSans-SemiBold.ttf +0 -0
- package/templates/template_0000/assets/Yesteryear-Regular.ttf +0 -0
- package/templates/template_0000/composition.json +11 -0
- package/templates/template_0000/package-lock.json +5505 -0
- package/templates/template_0000/package.json +31 -0
- package/templates/template_0000/research/preview/.gitkeep +1 -0
- package/templates/template_0000/research/source_notes.md +7 -0
- package/templates/template_0000/scripts/create-site.mjs +27 -0
- package/templates/template_0000/scripts/render-cloud.mjs +72 -0
- package/templates/template_0000/src/lib/images.js +242 -0
- package/templates/template_0000/src/lib/images.ts +284 -0
- package/templates/template_0000/src/remotion/Root.js +33 -0
- package/templates/template_0000/src/remotion/Root.tsx +75 -0
- package/templates/template_0000/src/remotion/index.js +3 -0
- package/templates/template_0000/src/remotion/index.tsx +4 -0
- package/templates/template_0000/src/sdk.js +3 -0
- package/templates/template_0000/src/sdk.ts +122 -0
- package/templates/template_0000/src/style-options.js +51 -0
- package/templates/template_0000/src/style-options.ts +60 -0
- package/templates/template_0000/src/template-dna.ts +15 -0
- package/templates/template_0000/src/template.js +1117 -0
- package/templates/template_0000/src/template.ts +1747 -0
- package/templates/template_0000/template.config.json +26 -0
- package/templates/template_0000/tsconfig.json +19 -0
- package/dist/templates/template_0000/demo-template.js +0 -196
- package/dist/templates/template_0000/remotion/Root.js +0 -66
- /package/dist/templates/template_0000/{remotion → src/remotion}/index.js +0 -0
package/dist/src/cli.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { parseArgs } from "node:util";
|
|
5
6
|
import dotenv from "dotenv";
|
|
7
|
+
import { STARTER_TEMPLATE_FONT_OPTIONS, STARTER_TEMPLATE_TEXT_BACKGROUND_COLOR_OPTIONS } from "./lib/template-style-options.js";
|
|
8
|
+
import { analyzeTemplateDna, hasTemplatePreviewMedia, stageTemplateDnaInputs, syncTemplateDnaModule } from "./lib/template-dna.js";
|
|
6
9
|
void main().catch((error) => {
|
|
7
10
|
console.error(error instanceof Error ? error.stack ?? error.message : String(error));
|
|
8
11
|
process.exit(1);
|
|
@@ -17,6 +20,26 @@ async function main() {
|
|
|
17
20
|
await runDevCommand(process.argv.slice(3));
|
|
18
21
|
return;
|
|
19
22
|
}
|
|
23
|
+
if (command === "validate-template") {
|
|
24
|
+
await runValidateTemplateCommand(process.argv.slice(3));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (command === "import-source") {
|
|
28
|
+
await runImportSourceCommand(process.argv.slice(3));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (command === "generate-template") {
|
|
32
|
+
await runGenerateTemplateCommand(process.argv.slice(3));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (command === "analyze-viral-dna") {
|
|
36
|
+
await runAnalyzeTemplateDnaCommand("viral", process.argv.slice(3));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (command === "analyze-visual-dna") {
|
|
40
|
+
await runAnalyzeTemplateDnaCommand("visual", process.argv.slice(3));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
20
43
|
throw new Error(`Unknown command: ${command}`);
|
|
21
44
|
}
|
|
22
45
|
async function runDevCommand(argv) {
|
|
@@ -57,6 +80,7 @@ async function runDevCommand(argv) {
|
|
|
57
80
|
process.env.STORAGE_DRIVER = "local";
|
|
58
81
|
process.env.PUBLIC_BASE_URL = `http://127.0.0.1:${port}`;
|
|
59
82
|
process.env.REMOTION_MODE = "local";
|
|
83
|
+
process.env.VIDFARM_ADMIN_EMAILS = process.env.VIDFARM_ADMIN_EMAILS || parsed.values.email;
|
|
60
84
|
process.env.MOCK_PROVIDER_RESPONSES =
|
|
61
85
|
parsed.values["mock-ai"] ? "true" : process.env.MOCK_PROVIDER_RESPONSES ?? (hasProviderEnvKey ? "false" : "true");
|
|
62
86
|
const [{ startRuntime }, { database }, { config }, { createId }, crypto] = await Promise.all([
|
|
@@ -69,13 +93,16 @@ async function runDevCommand(argv) {
|
|
|
69
93
|
const customer = database.getCustomerByEmail(parsed.values.email) ?? database.upsertCustomer({
|
|
70
94
|
id: createId("cus"),
|
|
71
95
|
email: parsed.values.email,
|
|
72
|
-
name: parsed.values.name
|
|
96
|
+
name: parsed.values.name,
|
|
97
|
+
isDeveloper: true,
|
|
98
|
+
isPaidPlan: true
|
|
73
99
|
});
|
|
74
100
|
const rawApiKey = parsed.values["api-key"] ?? `vf_local_${Math.random().toString(36).slice(2, 12)}`;
|
|
75
101
|
database.insertApiKey({
|
|
76
102
|
id: createId("api"),
|
|
77
103
|
customerId: customer.id,
|
|
78
104
|
keyHash: crypto.hashSecret(rawApiKey + config.API_KEY_SALT),
|
|
105
|
+
rawValue: rawApiKey,
|
|
79
106
|
label: "Local CLI session"
|
|
80
107
|
});
|
|
81
108
|
seedEnvProviderKeys({
|
|
@@ -104,7 +131,7 @@ async function runDevCommand(argv) {
|
|
|
104
131
|
sessionPath,
|
|
105
132
|
mockProviders: config.mockProviders
|
|
106
133
|
});
|
|
107
|
-
const runtime = startRuntime();
|
|
134
|
+
const runtime = await startRuntime();
|
|
108
135
|
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
109
136
|
process.on(signal, () => {
|
|
110
137
|
runtime.shutdown();
|
|
@@ -112,6 +139,226 @@ async function runDevCommand(argv) {
|
|
|
112
139
|
});
|
|
113
140
|
}
|
|
114
141
|
}
|
|
142
|
+
async function runValidateTemplateCommand(argv) {
|
|
143
|
+
const parsed = parseArgs({
|
|
144
|
+
args: argv,
|
|
145
|
+
options: {
|
|
146
|
+
"template-id": { type: "string" },
|
|
147
|
+
"module-path": { type: "string" },
|
|
148
|
+
"skill-path": { type: "string" }
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
const [{ templateRegistry }, { TemplateCertificationService }, { loadTemplateFromModule }] = await Promise.all([
|
|
152
|
+
import("./registry.js"),
|
|
153
|
+
import("./services/template-certification.js"),
|
|
154
|
+
import("./services/template-loader.js")
|
|
155
|
+
]);
|
|
156
|
+
const certification = new TemplateCertificationService();
|
|
157
|
+
let template;
|
|
158
|
+
let skillPath;
|
|
159
|
+
if (parsed.values["module-path"]) {
|
|
160
|
+
const modulePath = path.resolve(process.cwd(), parsed.values["module-path"]);
|
|
161
|
+
template = await loadTemplateFromModule(modulePath);
|
|
162
|
+
skillPath = path.resolve(process.cwd(), parsed.values["skill-path"] ?? "SKILL.md");
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
await templateRegistry.ensureInitialized();
|
|
166
|
+
const templateId = parsed.values["template-id"];
|
|
167
|
+
if (!templateId) {
|
|
168
|
+
throw new Error("Provide --template-id or --module-path.");
|
|
169
|
+
}
|
|
170
|
+
template = templateRegistry.get(templateId);
|
|
171
|
+
if (!template) {
|
|
172
|
+
throw new Error(`Unknown template: ${templateId}`);
|
|
173
|
+
}
|
|
174
|
+
skillPath = template.skillPath;
|
|
175
|
+
}
|
|
176
|
+
if (!template || !skillPath) {
|
|
177
|
+
throw new Error("Template or skill path not found for certification.");
|
|
178
|
+
}
|
|
179
|
+
const report = await certification.certify({ template, skillPath });
|
|
180
|
+
console.log(JSON.stringify(report, null, 2));
|
|
181
|
+
if (!report.passed) {
|
|
182
|
+
process.exitCode = 1;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async function runImportSourceCommand(argv) {
|
|
186
|
+
const parsed = parseArgs({
|
|
187
|
+
args: argv,
|
|
188
|
+
options: {
|
|
189
|
+
"template-id": { type: "string" },
|
|
190
|
+
"slug-id": { type: "string" },
|
|
191
|
+
"repo-url": { type: "string" },
|
|
192
|
+
branch: { type: "string", default: "production" },
|
|
193
|
+
"template-module-path": { type: "string" },
|
|
194
|
+
"skill-path": { type: "string", default: "SKILL.md" },
|
|
195
|
+
"install-command": { type: "string", default: "npm install" },
|
|
196
|
+
"build-command": { type: "string", default: "npm run build" },
|
|
197
|
+
"commit-sha": { type: "string" },
|
|
198
|
+
activate: { type: "boolean", default: true }
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
const templateId = parsed.values["template-id"];
|
|
202
|
+
const slugId = parsed.values["slug-id"];
|
|
203
|
+
const repoUrl = parsed.values["repo-url"];
|
|
204
|
+
const templateModulePath = parsed.values["template-module-path"];
|
|
205
|
+
if (!templateId || !slugId || !repoUrl || !templateModulePath) {
|
|
206
|
+
throw new Error("import-source requires --template-id, --slug-id, --repo-url, and --template-module-path.");
|
|
207
|
+
}
|
|
208
|
+
const [{ TemplateSourceService }, { templateRegistry }] = await Promise.all([
|
|
209
|
+
import("./services/template-sources.js"),
|
|
210
|
+
import("./registry.js")
|
|
211
|
+
]);
|
|
212
|
+
const sources = new TemplateSourceService();
|
|
213
|
+
const source = sources.registerSource({
|
|
214
|
+
templateId,
|
|
215
|
+
slugId,
|
|
216
|
+
repoUrl,
|
|
217
|
+
branch: parsed.values.branch,
|
|
218
|
+
templateModulePath,
|
|
219
|
+
skillPath: parsed.values["skill-path"],
|
|
220
|
+
installCommand: parsed.values["install-command"],
|
|
221
|
+
buildCommand: parsed.values["build-command"]
|
|
222
|
+
});
|
|
223
|
+
const release = await sources.importRelease({
|
|
224
|
+
sourceId: source.id,
|
|
225
|
+
commitSha: parsed.values["commit-sha"] ?? null
|
|
226
|
+
});
|
|
227
|
+
let activated = null;
|
|
228
|
+
if (parsed.values.activate) {
|
|
229
|
+
const result = await sources.activateRelease({ releaseId: release.id });
|
|
230
|
+
templateRegistry.registerRuntimeTemplate(result.template);
|
|
231
|
+
activated = result.release;
|
|
232
|
+
}
|
|
233
|
+
console.log(JSON.stringify({
|
|
234
|
+
source,
|
|
235
|
+
release,
|
|
236
|
+
activated_release: activated
|
|
237
|
+
}, null, 2));
|
|
238
|
+
}
|
|
239
|
+
async function runGenerateTemplateCommand(argv) {
|
|
240
|
+
const parsed = parseArgs({
|
|
241
|
+
args: argv,
|
|
242
|
+
options: {
|
|
243
|
+
"template-id": { type: "string" },
|
|
244
|
+
"slug-id": { type: "string" },
|
|
245
|
+
"template-dir": { type: "string" },
|
|
246
|
+
"project-name": { type: "string" },
|
|
247
|
+
"github-repo": { type: "string" },
|
|
248
|
+
"site-name": { type: "string" },
|
|
249
|
+
"link-to-original": { type: "string" },
|
|
250
|
+
"source-notes-path": { type: "string" },
|
|
251
|
+
"source-preview-dir": { type: "string" },
|
|
252
|
+
"dna-env-file": { type: "string", default: ".env" },
|
|
253
|
+
"dna-model": { type: "string" },
|
|
254
|
+
"skip-dna-analysis": { type: "boolean", default: false },
|
|
255
|
+
branch: { type: "string", default: "production" },
|
|
256
|
+
force: { type: "boolean", default: false }
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
const templateId = parsed.values["template-id"] ?? randomUUID();
|
|
260
|
+
const slugId = parsed.values["slug-id"];
|
|
261
|
+
const templateDir = parsed.values["template-dir"];
|
|
262
|
+
if (!slugId || !templateDir) {
|
|
263
|
+
throw new Error("generate-template requires --slug-id and --template-dir. --template-id is optional and defaults to a new UUIDv4.");
|
|
264
|
+
}
|
|
265
|
+
const root = process.cwd();
|
|
266
|
+
const starterDir = resolveStarterTemplateDir();
|
|
267
|
+
const destinationDir = path.resolve(root, templateDir);
|
|
268
|
+
if (!existsSync(starterDir)) {
|
|
269
|
+
throw new Error(`Starter template not found: ${starterDir}`);
|
|
270
|
+
}
|
|
271
|
+
if (existsSync(destinationDir)) {
|
|
272
|
+
if (!parsed.values.force) {
|
|
273
|
+
throw new Error(`Destination already exists: ${destinationDir}`);
|
|
274
|
+
}
|
|
275
|
+
rmSync(destinationDir, { recursive: true, force: true });
|
|
276
|
+
}
|
|
277
|
+
cpSync(starterDir, destinationDir, {
|
|
278
|
+
recursive: true,
|
|
279
|
+
filter: (entry) => {
|
|
280
|
+
const name = path.basename(entry);
|
|
281
|
+
return ![".git", "node_modules", "dist", "package-lock.json"].includes(name);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
const destinationFolderName = path.basename(destinationDir);
|
|
285
|
+
const projectName = parsed.values["project-name"] ?? toProjectName(destinationFolderName);
|
|
286
|
+
const siteName = parsed.values["site-name"] ?? projectName.replace(/_/g, "-");
|
|
287
|
+
const githubRepo = parsed.values["github-repo"] ?? `mevdragon/${projectName}`;
|
|
288
|
+
rewriteTemplateStarter(destinationDir, [
|
|
289
|
+
["mevdragon/vidfarm_template_0000", githubRepo],
|
|
290
|
+
["vidfarm_template_0000", projectName],
|
|
291
|
+
["vidfarm-template-0000", siteName],
|
|
292
|
+
["template_0000", slugId],
|
|
293
|
+
["template-0000", slugId.replace(/_/g, "-")],
|
|
294
|
+
["4c7a7e1a-7f35-4f30-9f86-9c8a63c7f2db", templateId],
|
|
295
|
+
['"production"', JSON.stringify(parsed.values.branch)]
|
|
296
|
+
]);
|
|
297
|
+
const stagedInputs = stageTemplateDnaInputs({
|
|
298
|
+
templateDir: destinationDir,
|
|
299
|
+
sourceNotesPath: parsed.values["source-notes-path"],
|
|
300
|
+
sourcePreviewDir: parsed.values["source-preview-dir"]
|
|
301
|
+
});
|
|
302
|
+
const moduleSync = syncTemplateDnaModule({
|
|
303
|
+
templateDir: destinationDir,
|
|
304
|
+
linkToOriginal: parsed.values["link-to-original"]
|
|
305
|
+
});
|
|
306
|
+
const dnaRuns = [];
|
|
307
|
+
if (!parsed.values["skip-dna-analysis"] && hasTemplatePreviewMedia(destinationDir)) {
|
|
308
|
+
dnaRuns.push(await analyzeTemplateDna({
|
|
309
|
+
mode: "viral",
|
|
310
|
+
templateDir: destinationDir,
|
|
311
|
+
envFile: parsed.values["dna-env-file"],
|
|
312
|
+
model: parsed.values["dna-model"],
|
|
313
|
+
linkToOriginal: parsed.values["link-to-original"]
|
|
314
|
+
}));
|
|
315
|
+
dnaRuns.push(await analyzeTemplateDna({
|
|
316
|
+
mode: "visual",
|
|
317
|
+
templateDir: destinationDir,
|
|
318
|
+
envFile: parsed.values["dna-env-file"],
|
|
319
|
+
model: parsed.values["dna-model"],
|
|
320
|
+
linkToOriginal: parsed.values["link-to-original"]
|
|
321
|
+
}));
|
|
322
|
+
}
|
|
323
|
+
console.log(JSON.stringify({
|
|
324
|
+
template_id: templateId,
|
|
325
|
+
slug_id: slugId,
|
|
326
|
+
template_dir: destinationDir,
|
|
327
|
+
project_name: projectName,
|
|
328
|
+
github_repo: githubRepo,
|
|
329
|
+
site_name: siteName,
|
|
330
|
+
research: stagedInputs,
|
|
331
|
+
template_dna_module: moduleSync,
|
|
332
|
+
dna_analysis_runs: dnaRuns
|
|
333
|
+
}, null, 2));
|
|
334
|
+
}
|
|
335
|
+
async function runAnalyzeTemplateDnaCommand(mode, argv) {
|
|
336
|
+
const parsed = parseArgs({
|
|
337
|
+
args: argv,
|
|
338
|
+
options: {
|
|
339
|
+
"template-dir": { type: "string", default: "." },
|
|
340
|
+
"env-file": { type: "string", default: ".env" },
|
|
341
|
+
model: { type: "string" },
|
|
342
|
+
"notes-path": { type: "string" },
|
|
343
|
+
"preview-dir": { type: "string" },
|
|
344
|
+
"output-path": { type: "string" },
|
|
345
|
+
"link-to-original": { type: "string" },
|
|
346
|
+
"sync-template-module": { type: "boolean", default: true }
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
const result = await analyzeTemplateDna({
|
|
350
|
+
mode,
|
|
351
|
+
templateDir: parsed.values["template-dir"],
|
|
352
|
+
envFile: parsed.values["env-file"],
|
|
353
|
+
model: parsed.values.model,
|
|
354
|
+
notesPath: parsed.values["notes-path"],
|
|
355
|
+
previewDir: parsed.values["preview-dir"],
|
|
356
|
+
outputPath: parsed.values["output-path"],
|
|
357
|
+
linkToOriginal: parsed.values["link-to-original"],
|
|
358
|
+
syncTemplateModule: parsed.values["sync-template-module"]
|
|
359
|
+
});
|
|
360
|
+
console.log(JSON.stringify(result, null, 2));
|
|
361
|
+
}
|
|
115
362
|
async function runSessionCommand(argv) {
|
|
116
363
|
const parsed = parseArgs({
|
|
117
364
|
args: argv,
|
|
@@ -124,17 +371,22 @@ async function runSessionCommand(argv) {
|
|
|
124
371
|
console.log(JSON.stringify({
|
|
125
372
|
base_url: session.baseUrl,
|
|
126
373
|
email: session.email,
|
|
374
|
+
starter_style_options: {
|
|
375
|
+
fonts: STARTER_TEMPLATE_FONT_OPTIONS,
|
|
376
|
+
text_background_colors: STARTER_TEMPLATE_TEXT_BACKGROUND_COLOR_OPTIONS,
|
|
377
|
+
starter_template_file: "templates/template_0000/src/style-options.ts"
|
|
378
|
+
},
|
|
127
379
|
headers: {
|
|
128
380
|
"vidfarm-user-id": session.customerId,
|
|
129
381
|
"vidfarm-api-key": session.apiKey,
|
|
130
382
|
"content-type": "application/json"
|
|
131
383
|
},
|
|
132
384
|
curl_example: [
|
|
133
|
-
`curl -X POST ${session.baseUrl}/templates/
|
|
385
|
+
`curl -X POST ${session.baseUrl}/api/v1/templates/template_0000/operations/create_slideshow \\`,
|
|
134
386
|
` -H 'vidfarm-user-id: ${session.customerId}' \\`,
|
|
135
387
|
` -H 'vidfarm-api-key: ${session.apiKey}' \\`,
|
|
136
388
|
" -H 'content-type: application/json' \\",
|
|
137
|
-
" -d '{\"tracer\":\"local-test\",\"payload\":{\"slides\":[[\"a cinematic founder at a desk\",\"Exact text on slide one\"]],\"
|
|
389
|
+
" -d '{\"tracer\":\"local-test\",\"payload\":{\"slides\":[[\"a cinematic founder at a desk\",\"Exact text on slide one\",2400]],\"meta_details_prompt\":\"Keep it native, casual, and curiosity-driven.\"}}'"
|
|
138
390
|
].join("\n")
|
|
139
391
|
}, null, 2));
|
|
140
392
|
}
|
|
@@ -185,3 +437,30 @@ function printStartupBanner(input) {
|
|
|
185
437
|
console.log(" vidfarm session");
|
|
186
438
|
console.log("");
|
|
187
439
|
}
|
|
440
|
+
function rewriteTemplateStarter(root, replacements) {
|
|
441
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
442
|
+
const target = path.join(root, entry.name);
|
|
443
|
+
if (entry.name === ".git" || entry.name === "node_modules" || entry.name === "dist") {
|
|
444
|
+
continue;
|
|
445
|
+
}
|
|
446
|
+
if (entry.isDirectory()) {
|
|
447
|
+
rewriteTemplateStarter(target, replacements);
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
const original = readFileSync(target, "utf8");
|
|
451
|
+
const next = replacements.reduce((value, [from, to]) => value.split(from).join(to), original);
|
|
452
|
+
if (next !== original) {
|
|
453
|
+
writeFileSync(target, next);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
function toProjectName(folderName) {
|
|
458
|
+
return folderName
|
|
459
|
+
.replace(/[^a-zA-Z0-9_-]+/g, "_")
|
|
460
|
+
.replace(/-+/g, "_")
|
|
461
|
+
.replace(/^_+|_+$/g, "")
|
|
462
|
+
.toLowerCase();
|
|
463
|
+
}
|
|
464
|
+
function resolveStarterTemplateDir() {
|
|
465
|
+
return path.resolve(import.meta.dirname, "..", "..", "templates", "template_0000");
|
|
466
|
+
}
|
package/dist/src/config.js
CHANGED
|
@@ -11,42 +11,62 @@ const schema = z.object({
|
|
|
11
11
|
ENCRYPTION_SECRET: z.string().default("development-encryption-secret-change-me"),
|
|
12
12
|
API_KEY_SALT: z.string().default("development-api-key-salt"),
|
|
13
13
|
WORKER_POLL_MS: z.coerce.number().default(1500),
|
|
14
|
-
WORKER_BATCH_SIZE: z.coerce.number().default(
|
|
14
|
+
WORKER_BATCH_SIZE: z.coerce.number().default(2),
|
|
15
|
+
WORKER_MAX_CONCURRENT_JOBS: z.coerce.number().default(1),
|
|
15
16
|
WEBHOOK_SECRET: z.string().default("development-webhook-secret"),
|
|
16
17
|
DEFAULT_JOB_DELAY_SECONDS: z.coerce.number().default(20),
|
|
18
|
+
MAX_PENDING_JOBS_GLOBAL: z.coerce.number().default(0),
|
|
19
|
+
MAX_PENDING_JOBS_PER_CUSTOMER: z.coerce.number().default(0),
|
|
17
20
|
STORAGE_DRIVER: z.enum(["local", "s3"]).default("local"),
|
|
18
21
|
AWS_REGION: z.string().default("us-east-1"),
|
|
19
22
|
AWS_S3_BUCKET: z.string().default(""),
|
|
23
|
+
AWS_S3_PUBLIC_READ: z.string().default("false"),
|
|
20
24
|
AWS_S3_ENDPOINT: z.string().optional(),
|
|
21
25
|
AWS_ACCESS_KEY_ID: z.string().optional(),
|
|
22
26
|
AWS_SECRET_ACCESS_KEY: z.string().optional(),
|
|
23
27
|
PUBLIC_BASE_URL: z.string().optional(),
|
|
24
28
|
RESEND_API_KEY: z.string().optional(),
|
|
25
|
-
RESEND_FROM_EMAIL: z.string().default("
|
|
29
|
+
RESEND_FROM_EMAIL: z.string().default("vidfarm@fwd.zoomgtm.com"),
|
|
26
30
|
OPENAI_API_KEY: z.string().optional(),
|
|
27
31
|
OPENROUTER_API_KEY: z.string().optional(),
|
|
28
32
|
GEMINI_API_KEY: z.string().optional(),
|
|
29
33
|
PERPLEXITY_API_KEY: z.string().optional(),
|
|
34
|
+
SUPERAGENCY_KEY: z.string().optional(),
|
|
30
35
|
REMOTION_REGION: z.string().default("us-east-1"),
|
|
31
36
|
REMOTION_BUCKET_NAME: z.string().optional(),
|
|
32
37
|
REMOTION_SITE_NAME: z.string().optional(),
|
|
33
38
|
REMOTION_FUNCTION_NAME: z.string().optional(),
|
|
34
39
|
REMOTION_SERVE_URL: z.string().optional(),
|
|
35
|
-
REMOTION_COMPOSITION_ID: z.string().default("
|
|
40
|
+
REMOTION_COMPOSITION_ID: z.string().default("template-0000"),
|
|
36
41
|
REMOTION_AWS_ACCESS_KEY_ID: z.string().optional(),
|
|
37
42
|
REMOTION_AWS_SECRET_ACCESS_KEY: z.string().optional(),
|
|
38
43
|
REMOTION_MODE: z.enum(["auto", "mock", "local", "lambda"]).default("auto"),
|
|
39
|
-
MOCK_PROVIDER_RESPONSES: z.string().default("true")
|
|
44
|
+
MOCK_PROVIDER_RESPONSES: z.string().default("true"),
|
|
45
|
+
VIDFARM_ADMIN_EMAILS: z.string().default(""),
|
|
46
|
+
VIDFARM_DEVELOPER_EMAILS: z.string().default(""),
|
|
47
|
+
TEMPLATE_SOURCE_ROOT: z.string().default("./data/template-sources")
|
|
40
48
|
});
|
|
41
49
|
const parsed = schema.parse(process.env);
|
|
42
50
|
const dataDir = path.resolve(parsed.VIDFARM_DATA_DIR);
|
|
43
51
|
mkdirSync(dataDir, { recursive: true });
|
|
52
|
+
const templateSourceRoot = path.resolve(parsed.TEMPLATE_SOURCE_ROOT);
|
|
53
|
+
mkdirSync(templateSourceRoot, { recursive: true });
|
|
44
54
|
const publicBaseUrl = parsed.PUBLIC_BASE_URL || `http://localhost:${parsed.PORT}`;
|
|
45
55
|
export const config = {
|
|
46
56
|
...parsed,
|
|
47
57
|
VIDFARM_DB_PATH: path.resolve(parsed.VIDFARM_DB_PATH),
|
|
48
58
|
VIDFARM_DATA_DIR: dataDir,
|
|
59
|
+
TEMPLATE_SOURCE_ROOT: templateSourceRoot,
|
|
49
60
|
PUBLIC_BASE_URL: publicBaseUrl,
|
|
50
61
|
isProduction: parsed.NODE_ENV === "production",
|
|
51
|
-
mockProviders: parsed.MOCK_PROVIDER_RESPONSES !== "false"
|
|
62
|
+
mockProviders: parsed.MOCK_PROVIDER_RESPONSES !== "false",
|
|
63
|
+
s3PublicRead: parsed.AWS_S3_PUBLIC_READ === "true",
|
|
64
|
+
adminEmails: parsed.VIDFARM_ADMIN_EMAILS
|
|
65
|
+
.split(",")
|
|
66
|
+
.map((value) => value.trim().toLowerCase())
|
|
67
|
+
.filter(Boolean),
|
|
68
|
+
developerEmails: parsed.VIDFARM_DEVELOPER_EMAILS
|
|
69
|
+
.split(",")
|
|
70
|
+
.map((value) => value.trim().toLowerCase())
|
|
71
|
+
.filter(Boolean)
|
|
52
72
|
};
|
package/dist/src/context.js
CHANGED
|
@@ -3,7 +3,7 @@ import { database } from "./db.js";
|
|
|
3
3
|
import { createId } from "./lib/ids.js";
|
|
4
4
|
export function createTemplateJobContext(input) {
|
|
5
5
|
const templateConfig = database.getTemplateConfig(input.customer.id, input.template.id);
|
|
6
|
-
const prefix =
|
|
6
|
+
const prefix = input.storage.templateJobPrefix(input.template.id, input.customer.id, input.job.id);
|
|
7
7
|
return {
|
|
8
8
|
env: config.isProduction ? "production" : "development",
|
|
9
9
|
customer: input.customer,
|