@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/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 = `user/${customer.id}/attachments/${attachmentId}/${fileName}`;
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
- const templateAboutPrefix = `templates/${templateId}/about/`;
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
- ? `templates/${templateId}/${normalizedEntry}`
620
- : `templates/${templateId}/about/${normalizedEntry}`;
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 = `templates/${template.id}/about/${normalizedAssetPath}`;
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
- const templateAboutPrefix = `templates/${templateId}/about/`;
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),
@@ -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("noreply@example.com"),
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(),
@@ -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 = `templates/${input.template.id}/users/${input.customer.id}/jobs/${input.job.id}`;
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
- "https://vidfarmprodstack-vidfarmbucket335ee12f-0vsvtd5earqy.s3.us-east-1.amazonaws.com/templates/template-0000/about/preview-01.jpg",
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.0",
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",