@mevdragon/vidfarm-devcli 0.2.1 → 0.2.3
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 +6 -39
- package/GETTING_STARTED.developers.md +87 -0
- package/README.md +94 -238
- package/SKILL.developer.md +430 -104
- package/dist/src/account-pages.js +1 -1
- package/dist/src/app.js +93 -5
- package/dist/src/cli.js +456 -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 +5 -6
- package/templates/template_0000/README.md +8 -52
- package/templates/template_0000/SKILL.md +35 -3
- package/templates/template_0000/package.json +3 -6
- 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 +7 -12
- package/AWS_REMOTION_HANDOFF.md +0 -311
- package/PLATFORM_SPEC.md +0 -1039
- package/SKILL.director.md +0 -599
- package/dist/infra/cdk/bin/vidfarm-prod.js +0 -59
- package/dist/infra/cdk/lib/vidfarm-prod-stack.js +0 -212
- package/templates/template_0000/package-lock.json +0 -5505
- package/templates/template_0000/scripts/create-site.mjs +0 -27
- package/templates/template_0000/scripts/render-cloud.mjs +0 -72
package/dist/src/app.js
CHANGED
|
@@ -60,6 +60,11 @@ const settingsProfileFormSchema = z.object({
|
|
|
60
60
|
groupchat_url: z.union([z.literal(""), z.string().url()]).optional(),
|
|
61
61
|
flockposter_api_key: z.string().max(1000).optional()
|
|
62
62
|
});
|
|
63
|
+
const developerPreviewPresignSchema = z.object({
|
|
64
|
+
file_name: z.string().min(1).max(255),
|
|
65
|
+
content_type: z.string().trim().min(1).max(255).optional(),
|
|
66
|
+
directory: z.string().trim().max(500).optional()
|
|
67
|
+
});
|
|
63
68
|
const listJobsQuerySchema = z.object({
|
|
64
69
|
tracer: z.string().min(1).optional(),
|
|
65
70
|
start_time: z.string().min(1).optional(),
|
|
@@ -195,6 +200,56 @@ function isAllowedAttachment(fileName, contentType) {
|
|
|
195
200
|
|| contentType === "text/plain"
|
|
196
201
|
|| contentType === "text/markdown";
|
|
197
202
|
}
|
|
203
|
+
function sanitizeStorageSubpath(value) {
|
|
204
|
+
if (!value) {
|
|
205
|
+
return "";
|
|
206
|
+
}
|
|
207
|
+
return value
|
|
208
|
+
.split("/")
|
|
209
|
+
.map((segment) => segment.trim().replace(/[^\w.-]+/g, "_"))
|
|
210
|
+
.filter((segment) => segment && segment !== "." && segment !== "..")
|
|
211
|
+
.join("/");
|
|
212
|
+
}
|
|
213
|
+
function inferAttachmentContentType(fileName) {
|
|
214
|
+
switch (path.extname(fileName).toLowerCase()) {
|
|
215
|
+
case ".png":
|
|
216
|
+
return "image/png";
|
|
217
|
+
case ".gif":
|
|
218
|
+
return "image/gif";
|
|
219
|
+
case ".jpg":
|
|
220
|
+
case ".jpeg":
|
|
221
|
+
return "image/jpeg";
|
|
222
|
+
case ".webp":
|
|
223
|
+
return "image/webp";
|
|
224
|
+
case ".svg":
|
|
225
|
+
return "image/svg+xml";
|
|
226
|
+
case ".mp4":
|
|
227
|
+
case ".m4v":
|
|
228
|
+
return "video/mp4";
|
|
229
|
+
case ".mov":
|
|
230
|
+
return "video/quicktime";
|
|
231
|
+
case ".webm":
|
|
232
|
+
return "video/webm";
|
|
233
|
+
case ".mp3":
|
|
234
|
+
return "audio/mpeg";
|
|
235
|
+
case ".wav":
|
|
236
|
+
return "audio/wav";
|
|
237
|
+
case ".m4a":
|
|
238
|
+
return "audio/mp4";
|
|
239
|
+
case ".aac":
|
|
240
|
+
return "audio/aac";
|
|
241
|
+
case ".ogg":
|
|
242
|
+
return "audio/ogg";
|
|
243
|
+
case ".pdf":
|
|
244
|
+
return "application/pdf";
|
|
245
|
+
case ".md":
|
|
246
|
+
return "text/markdown; charset=utf-8";
|
|
247
|
+
case ".txt":
|
|
248
|
+
return "text/plain; charset=utf-8";
|
|
249
|
+
default:
|
|
250
|
+
return "application/octet-stream";
|
|
251
|
+
}
|
|
252
|
+
}
|
|
198
253
|
function isFormFile(value) {
|
|
199
254
|
return Boolean(value
|
|
200
255
|
&& typeof value === "object"
|
|
@@ -563,7 +618,7 @@ function requireCustomer(c) {
|
|
|
563
618
|
}
|
|
564
619
|
const requireAuth = async (c, next) => {
|
|
565
620
|
try {
|
|
566
|
-
const customer = auth.authenticate(c.req.header("vidfarm-
|
|
621
|
+
const customer = auth.authenticate(c.req.header("vidfarm-api-key"));
|
|
567
622
|
c.set("customer", customer);
|
|
568
623
|
await next();
|
|
569
624
|
}
|
|
@@ -877,7 +932,7 @@ app.get(`${TEMPLATES_PREFIX}/:templateId/jobs/:jobId`, (c) => {
|
|
|
877
932
|
}
|
|
878
933
|
return c.json(serializeJob(job));
|
|
879
934
|
});
|
|
880
|
-
app.get(`${TEMPLATES_PREFIX}/:templateId/jobs/:jobId/logs`, (c) => {
|
|
935
|
+
app.get(`${TEMPLATES_PREFIX}/:templateId/jobs/:jobId/logs`, async (c) => {
|
|
881
936
|
const customer = requireCustomer(c);
|
|
882
937
|
const template = templateRegistry.get(c.req.param("templateId"));
|
|
883
938
|
if (!template) {
|
|
@@ -892,7 +947,7 @@ app.get(`${TEMPLATES_PREFIX}/:templateId/jobs/:jobId/logs`, (c) => {
|
|
|
892
947
|
end_time: c.req.query("end_time"),
|
|
893
948
|
limit: c.req.query("limit")
|
|
894
949
|
});
|
|
895
|
-
const logs = jobs.listLogs({
|
|
950
|
+
const logs = await jobs.listLogs({
|
|
896
951
|
jobId: job.id,
|
|
897
952
|
startTime: query.start_time,
|
|
898
953
|
endTime: query.end_time,
|
|
@@ -914,6 +969,39 @@ app.post(`${TEMPLATES_PREFIX}/:templateId/jobs/:jobId/cancel`, (c) => {
|
|
|
914
969
|
return c.json({ ok: true, job_id: job.id, status: "cancelled" });
|
|
915
970
|
});
|
|
916
971
|
app.get(`${USER_PREFIX}/me`, (c) => c.json({ customer: requireCustomer(c) }));
|
|
972
|
+
app.post(`${USER_PREFIX}/me/developer/preview-media/presign`, async (c) => {
|
|
973
|
+
try {
|
|
974
|
+
const customer = requireCustomer(c);
|
|
975
|
+
const body = developerPreviewPresignSchema.parse(await c.req.json());
|
|
976
|
+
const fileName = sanitizeFileName(body.file_name);
|
|
977
|
+
const contentType = body.content_type?.trim() || inferAttachmentContentType(fileName);
|
|
978
|
+
if (!isAllowedAttachment(fileName, contentType)) {
|
|
979
|
+
return c.json({ error: `Unsupported preview media type: ${fileName}` }, 400);
|
|
980
|
+
}
|
|
981
|
+
const directory = sanitizeStorageSubpath(body.directory);
|
|
982
|
+
const storageKey = storage.developerPreviewMediaKey(customer.id, directory, createId("preview"), fileName);
|
|
983
|
+
const upload = await storage.createWriteUrl(storageKey, {
|
|
984
|
+
contentType,
|
|
985
|
+
publicRead: false,
|
|
986
|
+
expiresIn: 3600
|
|
987
|
+
});
|
|
988
|
+
return c.json({
|
|
989
|
+
file_name: fileName,
|
|
990
|
+
content_type: contentType,
|
|
991
|
+
storage_key: storageKey,
|
|
992
|
+
preview_media_url: buildAbsoluteUrl(c, `/template-media?key=${encodeURIComponent(storageKey)}`),
|
|
993
|
+
upload: {
|
|
994
|
+
method: upload.method,
|
|
995
|
+
url: upload.url,
|
|
996
|
+
headers: upload.headers,
|
|
997
|
+
expires_in_seconds: upload.expiresIn
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
catch (error) {
|
|
1002
|
+
return c.json({ error: error instanceof Error ? error.message : "Unable to create preview upload URL." }, 400);
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
917
1005
|
app.get(`${USER_PREFIX}/me/jobs`, (c) => {
|
|
918
1006
|
const query = listJobsQuerySchema.parse({
|
|
919
1007
|
template_id: c.req.query("template_id"),
|
|
@@ -969,8 +1057,8 @@ app.post(`${TEMPLATES_PREFIX}/sources`, async (c) => {
|
|
|
969
1057
|
slug_id: z.string().min(3).regex(/^[a-z0-9_]+$/i, "slug_id must contain only letters, numbers, and underscores."),
|
|
970
1058
|
repo_url: z.string().url(),
|
|
971
1059
|
branch: z.string().min(1).default("production"),
|
|
972
|
-
template_module_path: z.string().
|
|
973
|
-
skill_path: z.string().min(1).
|
|
1060
|
+
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."),
|
|
1061
|
+
skill_path: z.string().min(1).optional(),
|
|
974
1062
|
install_command: z.string().min(1).default("npm install"),
|
|
975
1063
|
build_command: z.string().min(1).default("npm run build")
|
|
976
1064
|
}).parse(await c.req.json());
|