@mevdragon/vidfarm-devcli 0.2.2 → 0.2.4
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/GETTING_STARTED.developers.md +51 -142
- package/README.md +44 -4
- package/SKILL.developer.md +428 -101
- package/dist/src/account-pages.js +1 -1
- package/dist/src/app.js +94 -5
- package/dist/src/cli.js +476 -8
- package/dist/src/config.js +3 -2
- package/dist/src/context.js +30 -11
- package/dist/src/db.js +2 -57
- package/dist/src/dev-app.js +0 -1
- package/dist/src/index.js +4 -2
- package/dist/src/lib/template-paths.js +21 -0
- package/dist/src/runtime.js +3 -1
- package/dist/src/services/auth.js +4 -4
- package/dist/src/services/job-logs.js +186 -0
- package/dist/src/services/jobs.js +3 -2
- package/dist/src/services/providers.js +14 -6
- package/dist/src/services/storage.js +85 -2
- package/dist/src/services/template-sources.js +29 -3
- package/dist/templates/template_0000/src/lib/images.js +46 -86
- package/dist/templates/template_0000/src/template.js +277 -53
- package/package.json +2 -2
- package/templates/template_0000/README.md +2 -1
- package/templates/template_0000/SKILL.md +32 -0
- package/templates/template_0000/src/lib/images.js +46 -86
- package/templates/template_0000/src/lib/images.ts +55 -98
- package/templates/template_0000/src/template-dna.js +9 -0
- package/templates/template_0000/src/template.js +523 -199
- package/templates/template_0000/src/template.ts +356 -61
- package/templates/template_0000/template.config.json +1 -1
package/dist/src/app.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import { readFileSync, statSync } from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { Hono } from "hono";
|
|
@@ -60,6 +61,11 @@ const settingsProfileFormSchema = z.object({
|
|
|
60
61
|
groupchat_url: z.union([z.literal(""), z.string().url()]).optional(),
|
|
61
62
|
flockposter_api_key: z.string().max(1000).optional()
|
|
62
63
|
});
|
|
64
|
+
const developerPreviewPresignSchema = z.object({
|
|
65
|
+
file_name: z.string().min(1).max(255),
|
|
66
|
+
content_type: z.string().trim().min(1).max(255).optional(),
|
|
67
|
+
directory: z.string().trim().max(500).optional()
|
|
68
|
+
});
|
|
63
69
|
const listJobsQuerySchema = z.object({
|
|
64
70
|
tracer: z.string().min(1).optional(),
|
|
65
71
|
start_time: z.string().min(1).optional(),
|
|
@@ -195,6 +201,56 @@ function isAllowedAttachment(fileName, contentType) {
|
|
|
195
201
|
|| contentType === "text/plain"
|
|
196
202
|
|| contentType === "text/markdown";
|
|
197
203
|
}
|
|
204
|
+
function sanitizeStorageSubpath(value) {
|
|
205
|
+
if (!value) {
|
|
206
|
+
return "";
|
|
207
|
+
}
|
|
208
|
+
return value
|
|
209
|
+
.split("/")
|
|
210
|
+
.map((segment) => segment.trim().replace(/[^\w.-]+/g, "_"))
|
|
211
|
+
.filter((segment) => segment && segment !== "." && segment !== "..")
|
|
212
|
+
.join("/");
|
|
213
|
+
}
|
|
214
|
+
function inferAttachmentContentType(fileName) {
|
|
215
|
+
switch (path.extname(fileName).toLowerCase()) {
|
|
216
|
+
case ".png":
|
|
217
|
+
return "image/png";
|
|
218
|
+
case ".gif":
|
|
219
|
+
return "image/gif";
|
|
220
|
+
case ".jpg":
|
|
221
|
+
case ".jpeg":
|
|
222
|
+
return "image/jpeg";
|
|
223
|
+
case ".webp":
|
|
224
|
+
return "image/webp";
|
|
225
|
+
case ".svg":
|
|
226
|
+
return "image/svg+xml";
|
|
227
|
+
case ".mp4":
|
|
228
|
+
case ".m4v":
|
|
229
|
+
return "video/mp4";
|
|
230
|
+
case ".mov":
|
|
231
|
+
return "video/quicktime";
|
|
232
|
+
case ".webm":
|
|
233
|
+
return "video/webm";
|
|
234
|
+
case ".mp3":
|
|
235
|
+
return "audio/mpeg";
|
|
236
|
+
case ".wav":
|
|
237
|
+
return "audio/wav";
|
|
238
|
+
case ".m4a":
|
|
239
|
+
return "audio/mp4";
|
|
240
|
+
case ".aac":
|
|
241
|
+
return "audio/aac";
|
|
242
|
+
case ".ogg":
|
|
243
|
+
return "audio/ogg";
|
|
244
|
+
case ".pdf":
|
|
245
|
+
return "application/pdf";
|
|
246
|
+
case ".md":
|
|
247
|
+
return "text/markdown; charset=utf-8";
|
|
248
|
+
case ".txt":
|
|
249
|
+
return "text/plain; charset=utf-8";
|
|
250
|
+
default:
|
|
251
|
+
return "application/octet-stream";
|
|
252
|
+
}
|
|
253
|
+
}
|
|
198
254
|
function isFormFile(value) {
|
|
199
255
|
return Boolean(value
|
|
200
256
|
&& typeof value === "object"
|
|
@@ -563,7 +619,7 @@ function requireCustomer(c) {
|
|
|
563
619
|
}
|
|
564
620
|
const requireAuth = async (c, next) => {
|
|
565
621
|
try {
|
|
566
|
-
const customer = auth.authenticate(c.req.header("vidfarm-
|
|
622
|
+
const customer = auth.authenticate(c.req.header("vidfarm-api-key"));
|
|
567
623
|
c.set("customer", customer);
|
|
568
624
|
await next();
|
|
569
625
|
}
|
|
@@ -877,7 +933,7 @@ app.get(`${TEMPLATES_PREFIX}/:templateId/jobs/:jobId`, (c) => {
|
|
|
877
933
|
}
|
|
878
934
|
return c.json(serializeJob(job));
|
|
879
935
|
});
|
|
880
|
-
app.get(`${TEMPLATES_PREFIX}/:templateId/jobs/:jobId/logs`, (c) => {
|
|
936
|
+
app.get(`${TEMPLATES_PREFIX}/:templateId/jobs/:jobId/logs`, async (c) => {
|
|
881
937
|
const customer = requireCustomer(c);
|
|
882
938
|
const template = templateRegistry.get(c.req.param("templateId"));
|
|
883
939
|
if (!template) {
|
|
@@ -892,7 +948,7 @@ app.get(`${TEMPLATES_PREFIX}/:templateId/jobs/:jobId/logs`, (c) => {
|
|
|
892
948
|
end_time: c.req.query("end_time"),
|
|
893
949
|
limit: c.req.query("limit")
|
|
894
950
|
});
|
|
895
|
-
const logs = jobs.listLogs({
|
|
951
|
+
const logs = await jobs.listLogs({
|
|
896
952
|
jobId: job.id,
|
|
897
953
|
startTime: query.start_time,
|
|
898
954
|
endTime: query.end_time,
|
|
@@ -914,6 +970,39 @@ app.post(`${TEMPLATES_PREFIX}/:templateId/jobs/:jobId/cancel`, (c) => {
|
|
|
914
970
|
return c.json({ ok: true, job_id: job.id, status: "cancelled" });
|
|
915
971
|
});
|
|
916
972
|
app.get(`${USER_PREFIX}/me`, (c) => c.json({ customer: requireCustomer(c) }));
|
|
973
|
+
app.post(`${USER_PREFIX}/me/developer/preview-media/presign`, async (c) => {
|
|
974
|
+
try {
|
|
975
|
+
const customer = requireCustomer(c);
|
|
976
|
+
const body = developerPreviewPresignSchema.parse(await c.req.json());
|
|
977
|
+
const fileName = sanitizeFileName(body.file_name);
|
|
978
|
+
const contentType = body.content_type?.trim() || inferAttachmentContentType(fileName);
|
|
979
|
+
if (!isAllowedAttachment(fileName, contentType)) {
|
|
980
|
+
return c.json({ error: `Unsupported preview media type: ${fileName}` }, 400);
|
|
981
|
+
}
|
|
982
|
+
const directory = sanitizeStorageSubpath(body.directory);
|
|
983
|
+
const storageKey = storage.developerScopedKey(customer.id, directory, randomUUID(), fileName);
|
|
984
|
+
const upload = await storage.createWriteUrl(storageKey, {
|
|
985
|
+
contentType,
|
|
986
|
+
publicRead: false,
|
|
987
|
+
expiresIn: 3600
|
|
988
|
+
});
|
|
989
|
+
return c.json({
|
|
990
|
+
file_name: fileName,
|
|
991
|
+
content_type: contentType,
|
|
992
|
+
storage_key: storageKey,
|
|
993
|
+
preview_media_url: buildAbsoluteUrl(c, `/template-media?key=${encodeURIComponent(storageKey)}`),
|
|
994
|
+
upload: {
|
|
995
|
+
method: upload.method,
|
|
996
|
+
url: upload.url,
|
|
997
|
+
headers: upload.headers,
|
|
998
|
+
expires_in_seconds: upload.expiresIn
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
catch (error) {
|
|
1003
|
+
return c.json({ error: error instanceof Error ? error.message : "Unable to create preview upload URL." }, 400);
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
917
1006
|
app.get(`${USER_PREFIX}/me/jobs`, (c) => {
|
|
918
1007
|
const query = listJobsQuerySchema.parse({
|
|
919
1008
|
template_id: c.req.query("template_id"),
|
|
@@ -969,8 +1058,8 @@ app.post(`${TEMPLATES_PREFIX}/sources`, async (c) => {
|
|
|
969
1058
|
slug_id: z.string().min(3).regex(/^[a-z0-9_]+$/i, "slug_id must contain only letters, numbers, and underscores."),
|
|
970
1059
|
repo_url: z.string().url(),
|
|
971
1060
|
branch: z.string().min(1).default("production"),
|
|
972
|
-
template_module_path: z.string().
|
|
973
|
-
skill_path: z.string().min(1).
|
|
1061
|
+
template_module_path: z.string().regex(/(^|\/)vidfarm_template_[^/]+\/src\/template\.ts$/i, "template_module_path must point at a template entrypoint inside a folder that starts with vidfarm_template_, for example templates/vidfarm_template_example/src/template.ts."),
|
|
1062
|
+
skill_path: z.string().min(1).optional(),
|
|
974
1063
|
install_command: z.string().min(1).default("npm install"),
|
|
975
1064
|
build_command: z.string().min(1).default("npm run build")
|
|
976
1065
|
}).parse(await c.req.json());
|