@mevdragon/vidfarm-devcli 0.2.3 → 0.2.5
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/README.md +1 -1
- package/SKILL.developer.md +2 -2
- package/dist/src/app.js +6 -3
- package/dist/src/cli.js +22 -1
- package/dist/src/services/storage.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ The local CLI runs the same template contract used by the hosted platform, but w
|
|
|
51
51
|
|
|
52
52
|
Use `vidfarm session` to print reusable auth headers and a sample `curl` request for the local REST API.
|
|
53
53
|
|
|
54
|
-
For hosted preview-media uploads, use `vidfarm-devcli presign-preview-media`. It calls the authenticated Vidfarm API with `VIDFARM_API_KEY
|
|
54
|
+
For hosted preview-media uploads, use `vidfarm-devcli presign-preview-media`. It calls the authenticated Vidfarm API with `VIDFARM_API_KEY`, mints a presigned PUT URL under `developer/<user_id>/*`, stores each uploaded file under a UUID path segment while preserving the original filename, uploads the file automatically when `--file` is provided, and returns a public-read media URL for the uploaded object.
|
|
55
55
|
|
|
56
56
|
## What The Hosted Platform Expects From Templates
|
|
57
57
|
|
package/SKILL.developer.md
CHANGED
|
@@ -221,7 +221,7 @@ drafts/
|
|
|
221
221
|
|
|
222
222
|
This is the preferred handoff shape for agent-driven template creation. A Vidfarm developer should be able to drag media into `drafts/preview/`, add rough notes to `drafts/source_notes.md`, then tell the agent to create a template from those relative paths.
|
|
223
223
|
|
|
224
|
-
If the source media is not already present in the repo, upload it into the authenticated developer
|
|
224
|
+
If the source media is not already present in the repo, upload it into the authenticated developer storage namespace first instead of inventing ad hoc external hosting. An agent can take a developer-provided local file path and run this directly:
|
|
225
225
|
|
|
226
226
|
```bash
|
|
227
227
|
npx @mevdragon/vidfarm-devcli presign-preview-media \
|
|
@@ -229,7 +229,7 @@ npx @mevdragon/vidfarm-devcli presign-preview-media \
|
|
|
229
229
|
--directory drafts/preview
|
|
230
230
|
```
|
|
231
231
|
|
|
232
|
-
That command calls the hosted Vidfarm API with the user's `VIDFARM_API_KEY`, mints a presigned PUT URL scoped under `developer/<user_id
|
|
232
|
+
That command calls the hosted Vidfarm API with the user's `VIDFARM_API_KEY`, mints a presigned PUT URL scoped under `developer/<user_id>/*`, stores each uploaded file under a UUID path segment while preserving the original filename, uploads the file automatically when `--file` is provided, and returns both the `storage_key` and a public-read `preview_media_url`. Objects under `developer/<user_id>/*` may be read directly by URL but should not be treated as listable or writable without authenticated API access. Agents should prefer that path for hosted preview uploads whenever the input is a local media file path.
|
|
233
233
|
|
|
234
234
|
### 2. Start local runtime
|
|
235
235
|
|
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";
|
|
@@ -979,17 +980,19 @@ app.post(`${USER_PREFIX}/me/developer/preview-media/presign`, async (c) => {
|
|
|
979
980
|
return c.json({ error: `Unsupported preview media type: ${fileName}` }, 400);
|
|
980
981
|
}
|
|
981
982
|
const directory = sanitizeStorageSubpath(body.directory);
|
|
982
|
-
const storageKey = storage.
|
|
983
|
+
const storageKey = storage.developerScopedKey(customer.id, directory, randomUUID(), fileName);
|
|
983
984
|
const upload = await storage.createWriteUrl(storageKey, {
|
|
984
985
|
contentType,
|
|
985
|
-
publicRead:
|
|
986
|
+
publicRead: true,
|
|
986
987
|
expiresIn: 3600
|
|
987
988
|
});
|
|
989
|
+
const publicUrl = storage.getPublicUrl(storageKey) ?? buildAbsoluteUrl(c, `/template-media?key=${encodeURIComponent(storageKey)}`);
|
|
988
990
|
return c.json({
|
|
989
991
|
file_name: fileName,
|
|
990
992
|
content_type: contentType,
|
|
991
993
|
storage_key: storageKey,
|
|
992
|
-
preview_media_url:
|
|
994
|
+
preview_media_url: publicUrl,
|
|
995
|
+
public_url: publicUrl,
|
|
993
996
|
upload: {
|
|
994
997
|
method: upload.method,
|
|
995
998
|
url: upload.url,
|
package/dist/src/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { execFile } from "node:child_process";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import os from "node:os";
|
|
@@ -516,6 +516,25 @@ async function runPresignPreviewMediaCommand(argv) {
|
|
|
516
516
|
if (!response.ok) {
|
|
517
517
|
throw new Error(typeof payload.error === "string" ? payload.error : `Preview-media presign failed with ${response.status}.`);
|
|
518
518
|
}
|
|
519
|
+
let uploadResult = null;
|
|
520
|
+
if (filePath) {
|
|
521
|
+
const body = readFileSync(filePath);
|
|
522
|
+
const uploadResponse = await fetch(String(payload.upload?.url), {
|
|
523
|
+
method: String(payload.upload?.method ?? "PUT"),
|
|
524
|
+
headers: payload.upload?.headers,
|
|
525
|
+
body
|
|
526
|
+
});
|
|
527
|
+
if (!uploadResponse.ok) {
|
|
528
|
+
const errorText = await uploadResponse.text().catch(() => "");
|
|
529
|
+
throw new Error(`Preview-media upload failed with ${uploadResponse.status}${errorText ? `: ${errorText}` : "."}`);
|
|
530
|
+
}
|
|
531
|
+
uploadResult = {
|
|
532
|
+
uploaded: true,
|
|
533
|
+
size_bytes: statSync(filePath).size,
|
|
534
|
+
method: payload.upload?.method ?? "PUT",
|
|
535
|
+
status: uploadResponse.status
|
|
536
|
+
};
|
|
537
|
+
}
|
|
519
538
|
console.log(JSON.stringify({
|
|
520
539
|
base_url: baseUrl,
|
|
521
540
|
file_path: filePath,
|
|
@@ -523,6 +542,8 @@ async function runPresignPreviewMediaCommand(argv) {
|
|
|
523
542
|
content_type: payload.content_type,
|
|
524
543
|
storage_key: payload.storage_key,
|
|
525
544
|
preview_media_url: payload.preview_media_url,
|
|
545
|
+
public_url: payload.public_url ?? payload.preview_media_url,
|
|
546
|
+
upload_result: uploadResult,
|
|
526
547
|
upload: payload.upload,
|
|
527
548
|
curl_upload_example: [
|
|
528
549
|
`curl -X ${payload.upload.method} '${payload.upload.url}' \\`,
|
|
@@ -20,8 +20,8 @@ export class StorageService {
|
|
|
20
20
|
developerAttachmentKey(customerId, attachmentId, fileName) {
|
|
21
21
|
return joinStorageKey("developer", customerId, "attachments", attachmentId, fileName);
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
return joinStorageKey("developer", customerId,
|
|
23
|
+
developerScopedKey(customerId, ...parts) {
|
|
24
|
+
return joinStorageKey("developer", customerId, ...parts);
|
|
25
25
|
}
|
|
26
26
|
templateJobPrefix(templateId, customerId, jobId) {
|
|
27
27
|
return joinStorageKey("templates", templateId, "users", customerId, "jobs", jobId);
|