@mevdragon/vidfarm-devcli 0.2.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 +2 -2
- package/PLATFORM_SPEC.md +1 -0
- package/SKILL.developer.md +128 -447
- package/SKILL.director.md +599 -0
- package/dist/src/account-pages.js +57 -5
- package/dist/src/app.js +32 -22
- package/dist/src/config.js +1 -1
- package/dist/src/context.js +1 -1
- package/dist/src/services/storage.js +22 -0
- package/dist/templates/template_0000/src/template.js +1 -1
- package/package.json +2 -1
- package/templates/template_0000/package-lock.json +368 -0
- package/templates/template_0000/package.json +1 -0
- package/templates/template_0000/src/lib/images.js +242 -0
- package/templates/template_0000/src/remotion/index.js +3 -0
- package/templates/template_0000/src/sdk.js +3 -0
- package/templates/template_0000/src/template.js +1117 -0
- package/templates/template_0000/src/template.ts +1 -1
package/dist/src/app.js
CHANGED
|
@@ -70,6 +70,17 @@ const listJobsQuerySchema = z.object({
|
|
|
70
70
|
function getLoginMode(value) {
|
|
71
71
|
return value === "password" ? "password" : "otp";
|
|
72
72
|
}
|
|
73
|
+
function readRootSkillFile(...filenames) {
|
|
74
|
+
for (const filename of filenames) {
|
|
75
|
+
try {
|
|
76
|
+
return readFileSync(path.resolve(filename), "utf8");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return "";
|
|
83
|
+
}
|
|
73
84
|
const allowedAttachmentExtensions = new Set([
|
|
74
85
|
".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg",
|
|
75
86
|
".mp4", ".mov", ".webm", ".m4v",
|
|
@@ -361,23 +372,9 @@ app.get("/settings", (c) => {
|
|
|
361
372
|
if (!customer) {
|
|
362
373
|
return redirect(c, "/login");
|
|
363
374
|
}
|
|
364
|
-
const directorSkill = (
|
|
365
|
-
try {
|
|
366
|
-
return readFileSync(path.resolve("SKILL.user.md"), "utf8");
|
|
367
|
-
}
|
|
368
|
-
catch {
|
|
369
|
-
return "";
|
|
370
|
-
}
|
|
371
|
-
})();
|
|
375
|
+
const directorSkill = readRootSkillFile("SKILL.director.md", "SKILL.user.md");
|
|
372
376
|
const developerSkill = customer.isDeveloper
|
|
373
|
-
? (
|
|
374
|
-
try {
|
|
375
|
-
return readFileSync(path.resolve("SKILL.developer.md"), "utf8");
|
|
376
|
-
}
|
|
377
|
-
catch {
|
|
378
|
-
return null;
|
|
379
|
-
}
|
|
380
|
-
})()
|
|
377
|
+
? readRootSkillFile("SKILL.developer.md") || null
|
|
381
378
|
: null;
|
|
382
379
|
return c.html(renderSettingsPage({
|
|
383
380
|
notice: c.req.query("notice") ?? null,
|
|
@@ -476,7 +473,7 @@ app.post("/settings/attachments", async (c) => {
|
|
|
476
473
|
const arrayBuffer = await file.arrayBuffer();
|
|
477
474
|
const buffer = Buffer.from(arrayBuffer);
|
|
478
475
|
const attachmentId = createId("att");
|
|
479
|
-
const storageKey =
|
|
476
|
+
const storageKey = storage.userAttachmentKey(customer.id, attachmentId, fileName);
|
|
480
477
|
const stored = await storage.putBuffer(storageKey, buffer, contentType, { publicRead: true });
|
|
481
478
|
database.createUserAttachment({
|
|
482
479
|
id: attachmentId,
|
|
@@ -610,14 +607,17 @@ function buildAbsoluteUrl(c, pathname) {
|
|
|
610
607
|
}
|
|
611
608
|
function resolveTemplateAboutStorageKey(templateId, entry) {
|
|
612
609
|
const normalizedEntry = entry.replace(/^\/+/, "");
|
|
610
|
+
const templateAboutPrefix = storage.templateAboutKey(templateId, "");
|
|
613
611
|
if (!/^https?:\/\//i.test(entry)) {
|
|
614
|
-
|
|
612
|
+
if (normalizedEntry.startsWith("templates/")) {
|
|
613
|
+
return normalizedEntry;
|
|
614
|
+
}
|
|
615
615
|
if (normalizedEntry.startsWith(templateAboutPrefix)) {
|
|
616
616
|
return normalizedEntry;
|
|
617
617
|
}
|
|
618
618
|
return normalizedEntry.startsWith("about/")
|
|
619
|
-
?
|
|
620
|
-
:
|
|
619
|
+
? joinStoragePath("templates", templateId, normalizedEntry)
|
|
620
|
+
: storage.templateAboutKey(templateId, normalizedEntry);
|
|
621
621
|
}
|
|
622
622
|
try {
|
|
623
623
|
const url = new URL(entry);
|
|
@@ -657,7 +657,7 @@ async function serveTemplateAboutAsset(c, templateId, assetPath) {
|
|
|
657
657
|
if (!normalizedAssetPath) {
|
|
658
658
|
return c.json({ error: "Template about asset path is required" }, 400);
|
|
659
659
|
}
|
|
660
|
-
const key =
|
|
660
|
+
const key = storage.templateAboutKey(template.id, normalizedAssetPath);
|
|
661
661
|
const readUrl = await storage.getReadUrl(key);
|
|
662
662
|
if (config.STORAGE_DRIVER === "s3" && readUrl) {
|
|
663
663
|
return c.redirect(readUrl, 302);
|
|
@@ -742,7 +742,10 @@ function resolveTemplateAboutMediaUrl(c, templateId, entry) {
|
|
|
742
742
|
return entry;
|
|
743
743
|
}
|
|
744
744
|
const normalizedEntry = entry.replace(/^\/+/, "");
|
|
745
|
-
|
|
745
|
+
if (normalizedEntry.startsWith("templates/")) {
|
|
746
|
+
return buildAbsoluteUrl(c, `/template-media?key=${encodeURIComponent(normalizedEntry)}`);
|
|
747
|
+
}
|
|
748
|
+
const templateAboutPrefix = storage.templateAboutKey(templateId, "");
|
|
746
749
|
const aboutPath = normalizedEntry.startsWith(templateAboutPrefix)
|
|
747
750
|
? `about/${normalizedEntry.slice(templateAboutPrefix.length)}`
|
|
748
751
|
: normalizedEntry.startsWith("about/")
|
|
@@ -750,6 +753,13 @@ function resolveTemplateAboutMediaUrl(c, templateId, entry) {
|
|
|
750
753
|
: `about/${normalizedEntry}`;
|
|
751
754
|
return buildAbsoluteUrl(c, `${TEMPLATES_PREFIX}/${templateId}/${aboutPath}`);
|
|
752
755
|
}
|
|
756
|
+
function joinStoragePath(...parts) {
|
|
757
|
+
return parts
|
|
758
|
+
.flatMap((part) => part.split("/"))
|
|
759
|
+
.map((part) => part.trim())
|
|
760
|
+
.filter(Boolean)
|
|
761
|
+
.join("/");
|
|
762
|
+
}
|
|
753
763
|
app.get(TEMPLATES_PREFIX, (c) => c.json({
|
|
754
764
|
templates: templateRegistry.list().map((template) => ({
|
|
755
765
|
...serializeTemplate(c, template),
|
package/dist/src/config.js
CHANGED
|
@@ -26,7 +26,7 @@ const schema = z.object({
|
|
|
26
26
|
AWS_SECRET_ACCESS_KEY: z.string().optional(),
|
|
27
27
|
PUBLIC_BASE_URL: z.string().optional(),
|
|
28
28
|
RESEND_API_KEY: z.string().optional(),
|
|
29
|
-
RESEND_FROM_EMAIL: z.string().default("
|
|
29
|
+
RESEND_FROM_EMAIL: z.string().default("vidfarm@fwd.zoomgtm.com"),
|
|
30
30
|
OPENAI_API_KEY: z.string().optional(),
|
|
31
31
|
OPENROUTER_API_KEY: z.string().optional(),
|
|
32
32
|
GEMINI_API_KEY: z.string().optional(),
|
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,
|
|
@@ -14,6 +14,21 @@ export class StorageService {
|
|
|
14
14
|
constructor() {
|
|
15
15
|
mkdirSync(this.localRoot, { recursive: true });
|
|
16
16
|
}
|
|
17
|
+
userAttachmentKey(customerId, attachmentId, fileName) {
|
|
18
|
+
return joinStorageKey("user", customerId, "attachments", attachmentId, fileName);
|
|
19
|
+
}
|
|
20
|
+
developerAttachmentKey(customerId, attachmentId, fileName) {
|
|
21
|
+
return joinStorageKey("developer", customerId, "attachments", attachmentId, fileName);
|
|
22
|
+
}
|
|
23
|
+
templateJobPrefix(templateId, customerId, jobId) {
|
|
24
|
+
return joinStorageKey("templates", templateId, "users", customerId, "jobs", jobId);
|
|
25
|
+
}
|
|
26
|
+
templateJobKey(templateId, customerId, jobId, key) {
|
|
27
|
+
return joinStorageKey(this.templateJobPrefix(templateId, customerId, jobId), key);
|
|
28
|
+
}
|
|
29
|
+
templateAboutKey(templateId, assetPath) {
|
|
30
|
+
return joinStorageKey("templates", templateId, "about", assetPath);
|
|
31
|
+
}
|
|
17
32
|
async putJson(key, value, options) {
|
|
18
33
|
const body = JSON.stringify(value, null, 2);
|
|
19
34
|
return this.putBuffer(key, Buffer.from(body, "utf8"), "application/json", options);
|
|
@@ -86,6 +101,13 @@ export class StorageService {
|
|
|
86
101
|
return this.getPublicUrl(key);
|
|
87
102
|
}
|
|
88
103
|
}
|
|
104
|
+
function joinStorageKey(...parts) {
|
|
105
|
+
return parts
|
|
106
|
+
.flatMap((part) => part.split("/"))
|
|
107
|
+
.map((part) => part.trim())
|
|
108
|
+
.filter(Boolean)
|
|
109
|
+
.join("/");
|
|
110
|
+
}
|
|
89
111
|
function inferContentType(filePath) {
|
|
90
112
|
switch (path.extname(filePath).toLowerCase()) {
|
|
91
113
|
case ".json":
|
|
@@ -11,7 +11,7 @@ const TEMPLATE_ID = "4c7a7e1a-7f35-4f30-9f86-9c8a63c7f2db";
|
|
|
11
11
|
const TEMPLATE_SLUG_ID = "template_0000";
|
|
12
12
|
const COMPOSITION_ID = "template-0000";
|
|
13
13
|
const TEMPLATE_PREVIEW_MEDIA = [
|
|
14
|
-
"
|
|
14
|
+
"templates/template-0000/about/preview-01.jpg",
|
|
15
15
|
];
|
|
16
16
|
const FRAME = { width: 1080, height: 1920 };
|
|
17
17
|
const TIKTOK_SAFE_AREA = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mevdragon/vidfarm-devcli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Developer CLI for running the Vidfarm local template platform.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"dist",
|
|
12
12
|
"templates/template_0000",
|
|
13
13
|
"README.md",
|
|
14
|
+
"SKILL.director.md",
|
|
14
15
|
"SKILL.developer.md",
|
|
15
16
|
"PLATFORM_SPEC.md",
|
|
16
17
|
"AWS_REMOTION_HANDOFF.md",
|