From 3d8323190c5717b1849878cc528a174614b58c1f Mon Sep 17 00:00:00 2001 From: Abdelrahman Essawy Date: Wed, 10 Jun 2026 17:02:27 +0300 Subject: [PATCH] fix: adopt @rendobar/sdk v3 upload API SDK 3.0.0 removed uploads.upload(). Use uploads.create(), which presigns, uploads, and finalizes in one call and returns the asset. Reference the uploaded file by its stable content URL (asset.url) instead of the old { downloadUrl }. --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- src/__tests__/ffmpeg-command.test.ts | 14 +++++++------- src/__tests__/upload.test.ts | 16 ++++++++-------- src/lib/upload.ts | 4 ++-- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index 0121bb6..dbcccf7 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "check:no-linked-sdk": "node scripts/check-no-linked-sdk.mjs" }, "dependencies": { - "@rendobar/sdk": "^2.0.0", + "@rendobar/sdk": "^3.0.0", "citty": "^0.2.0", "picocolors": "^1.1.1", "@clack/prompts": "^1.2.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 57e2631..c975776 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ importers: specifier: ^1.2.0 version: 1.5.0 '@rendobar/sdk': - specifier: ^2.0.0 - version: 2.2.0 + specifier: ^3.0.0 + version: 3.0.0 citty: specifier: ^0.2.0 version: 0.2.2 @@ -136,8 +136,8 @@ packages: conventional-commits-parser: optional: true - '@rendobar/sdk@2.2.0': - resolution: {integrity: sha512-qZ8FxzOZstg4GA0E+D1Rbzed3nv5tvr2ubfGlyHn+qEUb1v/JvmHBParPT8k87vqDIxtZKARyMi2hxCiXNZxRw==} + '@rendobar/sdk@3.0.0': + resolution: {integrity: sha512-i9RrML7qq7E0j9Tl4oT8QIt5lizwYE+9sqdq7PESE/zcrLYA+/YuMcBF1fMmhKtOHAsEdgzzpGGLIZQjSdBrSw==} engines: {node: '>=18'} '@simple-libs/child-process-utils@1.0.2': @@ -584,7 +584,7 @@ snapshots: optionalDependencies: conventional-commits-parser: 6.4.0 - '@rendobar/sdk@2.2.0': + '@rendobar/sdk@3.0.0': dependencies: partysocket: 1.1.16 transitivePeerDependencies: diff --git a/src/__tests__/ffmpeg-command.test.ts b/src/__tests__/ffmpeg-command.test.ts index d28cc0b..bff3ca7 100644 --- a/src/__tests__/ffmpeg-command.test.ts +++ b/src/__tests__/ffmpeg-command.test.ts @@ -35,7 +35,7 @@ describe("ffmpeg command flow", () => { const rawArgs = ["-i", localPath, "-vf", "scale=640:480", "output.mp4"]; const parsed = parseFfmpegArgs(rawArgs); const mockClient = { - uploads: { upload: mock(() => Promise.resolve({ downloadUrl: "https://cdn.rendobar.com/uploads/abc.mp4" })) }, + uploads: { create: mock(() => Promise.resolve({ url: "https://cdn.rendobar.com/uploads/abc.mp4" })) }, } as unknown as Parameters[2]; const rewritten = await uploadLocalFiles(rawArgs, parsed.inputs, mockClient); const commandString = "ffmpeg " + rewritten.join(" "); @@ -52,7 +52,7 @@ describe("ffmpeg command flow", () => { const rawArgs = ["-i", localPath, "-c:v", "libx264", "-crf", "23", "output.mp4"]; const parsed = parseFfmpegArgs(rawArgs); const mockClient = { - uploads: { upload: mock(() => Promise.resolve({ downloadUrl: "https://cdn.rendobar.com/uploads/xyz.mp4" })) }, + uploads: { create: mock(() => Promise.resolve({ url: "https://cdn.rendobar.com/uploads/xyz.mp4" })) }, } as unknown as Parameters[2]; const rewritten = await uploadLocalFiles(rawArgs, parsed.inputs, mockClient); @@ -78,16 +78,16 @@ describe("ffmpeg command flow", () => { let callIdx = 0; const mockClient = { uploads: { - upload: mock(async () => { + create: mock(async () => { callIdx++; - return { downloadUrl: `https://cdn.rendobar.com/uploads/file${callIdx}.mp4` }; + return { url: `https://cdn.rendobar.com/uploads/file${callIdx}.mp4` }; }), }, } as unknown as Parameters[2]; const rewritten = await uploadLocalFiles(rawArgs, parsed.inputs, mockClient); - expect(mockClient.uploads.upload).toHaveBeenCalledTimes(2); + expect(mockClient.uploads.create).toHaveBeenCalledTimes(2); expect(rewritten[1]).toContain("cdn.rendobar.com"); expect(rewritten[3]).toContain("cdn.rendobar.com"); // Filter complex preserved @@ -103,13 +103,13 @@ describe("ffmpeg command flow", () => { expect(parsed.inputs[1]!.isLocal).toBe(true); const mockClient = { - uploads: { upload: mock(() => Promise.resolve({ downloadUrl: "https://cdn.rendobar.com/uploads/local.png" })) }, + uploads: { create: mock(() => Promise.resolve({ url: "https://cdn.rendobar.com/uploads/local.png" })) }, } as unknown as Parameters[2]; const rewritten = await uploadLocalFiles(rawArgs, parsed.inputs, mockClient); // Only one upload call (the local file) - expect(mockClient.uploads.upload).toHaveBeenCalledTimes(1); + expect(mockClient.uploads.create).toHaveBeenCalledTimes(1); // Remote URL preserved expect(rewritten[1]).toBe("https://example.com/bg.mp4"); // Local file replaced diff --git a/src/__tests__/upload.test.ts b/src/__tests__/upload.test.ts index cbecb5a..d9e5c4a 100644 --- a/src/__tests__/upload.test.ts +++ b/src/__tests__/upload.test.ts @@ -23,8 +23,8 @@ describe("uploadLocalFiles", () => { it("uploads local files and replaces paths in args", async () => { const localPath = createTempFile("video.mp4"); - const mockUpload = mock(() => Promise.resolve({ downloadUrl: "https://cdn.rendobar.com/uploads/abc123.mp4" })); - const mockClient = { uploads: { upload: mockUpload } } as unknown as Parameters[2]; + const mockUpload = mock(() => Promise.resolve({ url: "https://cdn.rendobar.com/uploads/abc123.mp4" })); + const mockClient = { uploads: { create: mockUpload } } as unknown as Parameters[2]; const args = ["-i", localPath, "-vf", "scale=1280:720", "output.mp4"]; const inputs = [{ index: 1, value: localPath, isLocal: true }]; @@ -43,9 +43,9 @@ describe("uploadLocalFiles", () => { let callCount = 0; const mockUpload = mock(async () => { callCount++; - return { downloadUrl: `https://cdn.rendobar.com/uploads/file${callCount}.mp4` }; + return { url: `https://cdn.rendobar.com/uploads/file${callCount}.mp4` }; }); - const mockClient = { uploads: { upload: mockUpload } } as unknown as Parameters[2]; + const mockClient = { uploads: { create: mockUpload } } as unknown as Parameters[2]; const args = ["-i", pathA, "-i", pathB, "output.mp4"]; const inputs = [ @@ -61,8 +61,8 @@ describe("uploadLocalFiles", () => { }); it("skips URL inputs (no upload needed)", async () => { - const mockUpload = mock(() => Promise.resolve({ downloadUrl: "" })); - const mockClient = { uploads: { upload: mockUpload } } as unknown as Parameters[2]; + const mockUpload = mock(() => Promise.resolve({ url: "" })); + const mockClient = { uploads: { create: mockUpload } } as unknown as Parameters[2]; const args = ["-i", "https://example.com/video.mp4", "output.mp4"]; const inputs = [{ index: 1, value: "https://example.com/video.mp4", isLocal: false }]; @@ -74,8 +74,8 @@ describe("uploadLocalFiles", () => { }); it("throws when local file does not exist", async () => { - const mockUpload = mock(() => Promise.resolve({ downloadUrl: "" })); - const mockClient = { uploads: { upload: mockUpload } } as unknown as Parameters[2]; + const mockUpload = mock(() => Promise.resolve({ url: "" })); + const mockClient = { uploads: { create: mockUpload } } as unknown as Parameters[2]; const args = ["-i", "/nonexistent/file.mp4", "output.mp4"]; const inputs = [{ index: 1, value: "/nonexistent/file.mp4", isLocal: true }]; diff --git a/src/lib/upload.ts b/src/lib/upload.ts index 2761412..9850c51 100644 --- a/src/lib/upload.ts +++ b/src/lib/upload.ts @@ -35,10 +35,10 @@ export async function uploadLocalFiles( const filename = path.basename(input.value); callbacks?.onFileStart?.(filename, file.size, i, total); - const { downloadUrl } = await client.uploads.upload(new Uint8Array(buffer), { filename }); + const asset = await client.uploads.create(new Uint8Array(buffer), { filename }); callbacks?.onFileDone?.(filename, i, total); - result[input.index] = downloadUrl; + result[input.index] = asset.url; } return result;