Skip to content

Commit 6e3a3f4

Browse files
authored
feat(node): add upload endpoint flags (#303)
* feat(node): add upload endpoint flags * chore: update transloadit parity baseline * chore: format transloadit baseline * chore: refresh transloadit parity baseline
1 parent 9ad04d4 commit 6e3a3f4

8 files changed

Lines changed: 101 additions & 34 deletions

File tree

.changeset/bright-singers-burn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@transloadit/node": minor
3+
---
4+
5+
Add upload CLI flags for create/resume tus endpoints and support expected uploads for out-of-band tus flows.

docs/fingerprint/transloadit-baseline.json

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{
22
"packageDir": "/home/kvz/code/node-sdk/packages/transloadit",
33
"tarball": {
4-
"filename": "transloadit-4.3.0.tgz",
5-
"sizeBytes": 1229255,
6-
"sha256": "0b1adb20b160254719eedb2dbcd6f28c7561b2258840643f20867fa664090531"
4+
"filename": "transloadit-4.3.1.tgz",
5+
"sizeBytes": 1232790,
6+
"sha256": "089e952a8e6665659675b0647fed80d99d3f4252a0f0845863a9ed218ee9d166"
77
},
88
"packageJson": {
99
"name": "transloadit",
10-
"version": "4.3.0",
10+
"version": "4.3.1",
1111
"main": "./dist/Transloadit.js",
1212
"exports": {
1313
".": "./dist/Transloadit.js",
@@ -388,8 +388,8 @@
388388
},
389389
{
390390
"path": "dist/cli/commands/index.js",
391-
"sizeBytes": 1794,
392-
"sha256": "cea0e51dbb809beef425325c681fc3ce087a082f02ff66b6474001a11b2fbd37"
391+
"sizeBytes": 1896,
392+
"sha256": "64bc6458f6f1cd1db339646519dcbab942ccabe965b44d50b1e74dac9ded060a"
393393
},
394394
{
395395
"path": "dist/inputFiles.js",
@@ -583,8 +583,8 @@
583583
},
584584
{
585585
"path": "dist/Transloadit.js",
586-
"sizeBytes": 36726,
587-
"sha256": "1b3ded5575fb9e02032831df6f5ca10b6c33b0181b59cf44a195248f78bd68ef"
586+
"sizeBytes": 36883,
587+
"sha256": "ef4717bcc8930b750f5d8466097eec96b5f636eeeffe314cb5bde141562ae4d5"
588588
},
589589
{
590590
"path": "dist/alphalib/tryCatch.js",
@@ -611,6 +611,11 @@
611611
"sizeBytes": 2710,
612612
"sha256": "0da0cf7c28a54af82ac125af0129f885b111b9e48cd64c477865d5438e29974d"
613613
},
614+
{
615+
"path": "dist/cli/commands/upload.js",
616+
"sizeBytes": 3831,
617+
"sha256": "c9267bff59d4b62ed455773ff56ee915a8c196b46c095ef4e9f2ee9542077a9a"
618+
},
614619
{
615620
"path": "dist/alphalib/types/robots/video-adaptive.js",
616621
"sizeBytes": 6059,
@@ -678,8 +683,8 @@
678683
},
679684
{
680685
"path": "package.json",
681-
"sizeBytes": 2392,
682-
"sha256": "da426af5fcb55e65975b94d1e31b01b3e046ee561db0742e0e2a621d6a837b8b"
686+
"sizeBytes": 2391,
687+
"sha256": "156ee2b53de31d01d43e3a9d5e8299c6e512d63d6ef63ced6428a0685b51effe"
683688
},
684689
{
685690
"path": "dist/alphalib/types/robots/_index.d.ts.map",
@@ -1414,12 +1419,12 @@
14141419
{
14151420
"path": "dist/cli/commands/index.d.ts.map",
14161421
"sizeBytes": 198,
1417-
"sha256": "391845fbe56809711ea35e1667befbf872dd9072875c6983b0990b247d5496cc"
1422+
"sha256": "d9bef1f3fe0f9ff442cdd7e4929e0ec89c711911bc732d337bc557c880a5a6cd"
14181423
},
14191424
{
14201425
"path": "dist/cli/commands/index.js.map",
1421-
"sizeBytes": 1640,
1422-
"sha256": "52cc8c7351fa5905ce7541db198cef4fc55f504a868ca673e843ee8dcb988d16"
1426+
"sizeBytes": 1735,
1427+
"sha256": "d57ecf1ffc0409c294f83829b8deef9e7e369987439d0f6d089db41ddcf8e901"
14231428
},
14241429
{
14251430
"path": "dist/inputFiles.d.ts.map",
@@ -1803,13 +1808,13 @@
18031808
},
18041809
{
18051810
"path": "dist/Transloadit.d.ts.map",
1806-
"sizeBytes": 6364,
1807-
"sha256": "d04fe4e23e6f9c46f828838b60d0e3999a0d3f33f7e7ff0e193d280e5d6e8da5"
1811+
"sizeBytes": 6406,
1812+
"sha256": "51f9faaa4e12826a77c2ab0818cbb850a044e6d27d686c02578b8ff14c414313"
18081813
},
18091814
{
18101815
"path": "dist/Transloadit.js.map",
1811-
"sizeBytes": 26804,
1812-
"sha256": "42b0aada7680ba8686ce130b06b70fff5a0c75f2f81aa28f834eaea49fd58a4a"
1816+
"sizeBytes": 26946,
1817+
"sha256": "33b7676224bfd7d0b2a6c6e448cce67d0929eda5fefc05beb70f57550e6a93d5"
18131818
},
18141819
{
18151820
"path": "dist/alphalib/tryCatch.d.ts.map",
@@ -1861,6 +1866,16 @@
18611866
"sizeBytes": 1547,
18621867
"sha256": "5565507cacaccfbae0ed8af22fa55d0f2e1764db6d5b512ca275d2dc0baa52c7"
18631868
},
1869+
{
1870+
"path": "dist/cli/commands/upload.d.ts.map",
1871+
"sizeBytes": 768,
1872+
"sha256": "787cbbb01c715dc37945cf86faa3429f220a6bdf4fdbd9b7a0d37b9413eb1406"
1873+
},
1874+
{
1875+
"path": "dist/cli/commands/upload.js.map",
1876+
"sizeBytes": 2896,
1877+
"sha256": "ddf7dac4f6d709cd551705e61fb68626d2c54752ca8289dea58831ca0da615c7"
1878+
},
18641879
{
18651880
"path": "dist/alphalib/types/robots/video-adaptive.d.ts.map",
18661881
"sizeBytes": 3703,
@@ -2733,8 +2748,8 @@
27332748
},
27342749
{
27352750
"path": "src/cli/commands/index.ts",
2736-
"sizeBytes": 1711,
2737-
"sha256": "a4646e7d078b97e32d7a3c0c0f61aeb32898d1b25bda89ba20703a23b302f6f2"
2751+
"sizeBytes": 1808,
2752+
"sha256": "f0ab91c3da3ee8de42cc005ef25d4f6972746606082b4030e596d4c946f4963e"
27382753
},
27392754
{
27402755
"path": "dist/inputFiles.d.ts",
@@ -3123,13 +3138,13 @@
31233138
},
31243139
{
31253140
"path": "dist/Transloadit.d.ts",
3126-
"sizeBytes": 11723,
3127-
"sha256": "dee5f012aaf6faef6ca2154f3566c97aeaaf95ff07433e2573628e215dbbf9d3"
3141+
"sizeBytes": 11847,
3142+
"sha256": "5a280d61733d751cb2c9137fb19557dab9e4b2cc8e48c89bfad7474ce0bc0e06"
31283143
},
31293144
{
31303145
"path": "src/Transloadit.ts",
3131-
"sizeBytes": 41153,
3132-
"sha256": "198560ba943a5c33862e8b735b66a2bb7483d76d29e43efdc7354283217202f1"
3146+
"sizeBytes": 41433,
3147+
"sha256": "02d6ca96421b0ec39e31c4fb40a06537f2a61ba87787f9e904907f6463f854ea"
31333148
},
31343149
{
31353150
"path": "dist/alphalib/tryCatch.d.ts",
@@ -3181,6 +3196,16 @@
31813196
"sizeBytes": 3439,
31823197
"sha256": "4bf3de4456a3aa53d370f4568a0ab1c5423ac8f251d83c62b593fe7d8f814a9d"
31833198
},
3199+
{
3200+
"path": "dist/cli/commands/upload.d.ts",
3201+
"sizeBytes": 869,
3202+
"sha256": "6078873d1b89afa675ea4aa6bd6b87b7ae14147d7b1982b8d89f2d5ef55376aa"
3203+
},
3204+
{
3205+
"path": "src/cli/commands/upload.ts",
3206+
"sizeBytes": 3927,
3207+
"sha256": "19ba88a9bccab46628a9c1c0e909ab7cf5a2605b5a08c85ec320d2ff46a4da9f"
3208+
},
31843209
{
31853210
"path": "dist/alphalib/types/robots/video-adaptive.d.ts",
31863211
"sizeBytes": 213318,

docs/fingerprint/transloadit-baseline.package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "transloadit",
3-
"version": "4.3.0",
3+
"version": "4.3.1",
44
"description": "Node.js SDK for Transloadit",
55
"type": "module",
66
"keywords": [
@@ -19,7 +19,7 @@
1919
"dependencies": {
2020
"@aws-sdk/client-s3": "^3.891.0",
2121
"@aws-sdk/s3-request-presigner": "^3.891.0",
22-
"@transloadit/sev-logger": "^0.0.15",
22+
"@transloadit/sev-logger": "^0.1.9",
2323
"@transloadit/utils": "^4.3.0",
2424
"clipanion": "^4.0.0-rc.4",
2525
"debug": "^4.4.3",

packages/mcp-server/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ the request body stays small and no extra MCP/LLM token budget is consumed.
9191
9292
- `path` inputs only work when the MCP server can read the same filesystem (local/stdio).
9393
- Hosted MCP cannot access your disk. Use `url`/`base64` for small files, or upload locally with:
94-
`npx @transloadit/node upload ./file.ext <tus_url> --assembly <assembly_url> --field :original`
94+
`npx -y @transloadit/node upload ./file.ext --create-upload-endpoint <tus_url> --assembly <assembly_url> --field :original`
9595
- For remote flows, create the Assembly with `expected_uploads` so it stays open for out‑of‑band
9696
tus uploads.
9797

packages/mcp-server/src/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ export const createTransloaditMcpServer = (
581581
} catch (error) {
582582
if (isErrnoException(error) && error.code === 'ENOENT') {
583583
return buildToolError('mcp_file_not_found', error.message, {
584-
hint: 'Path inputs only work when the MCP server can read local files. For hosted MCP, use url/base64 or upload via `npx @transloadit/node upload`.',
584+
hint: 'Path inputs only work when the MCP server can read local files. For hosted MCP, use url/base64 or upload via `npx -y @transloadit/node upload`.',
585585
})
586586
}
587587
throw error

packages/node/src/cli/commands/upload.ts

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,36 @@ import { UnauthenticatedCommand } from './BaseCommand.ts'
77

88
export interface UploadOptions {
99
file: string
10-
tusEndpoint: string
10+
createUploadEndpoint?: string
11+
resumeUploadEndpoint?: string
1112
assemblyUrl: string
1213
field?: string
1314
}
1415

16+
const deriveEndpointFromUploadUrl = (uploadUrl: string): string => {
17+
const url = new URL(uploadUrl)
18+
url.pathname = url.pathname.replace(/\/[^/]*$/, '/')
19+
return url.toString()
20+
}
21+
1522
export async function upload(
1623
output: IOutputCtl,
17-
{ file, tusEndpoint, assemblyUrl, field = ':original' }: UploadOptions,
24+
{
25+
file,
26+
createUploadEndpoint,
27+
resumeUploadEndpoint,
28+
assemblyUrl,
29+
field = ':original',
30+
}: UploadOptions,
1831
): Promise<void> {
32+
const tusEndpoint =
33+
createUploadEndpoint ??
34+
(resumeUploadEndpoint ? deriveEndpointFromUploadUrl(resumeUploadEndpoint) : undefined)
35+
36+
if (!tusEndpoint) {
37+
throw new Error('Provide --create-upload-endpoint or --resume-upload-endpoint.')
38+
}
39+
1940
const stream = fs.createReadStream(file)
2041
const streamsMap = {
2142
[field]: { path: file, stream },
@@ -32,6 +53,7 @@ export async function upload(
3253
requestedChunkSize: Number.POSITIVE_INFINITY,
3354
uploadConcurrency: 1,
3455
onProgress: () => {},
56+
uploadUrls: resumeUploadEndpoint ? { [field]: resumeUploadEndpoint } : undefined,
3557
})
3658

3759
const uploadUrl = uploadUrls[field]
@@ -42,6 +64,7 @@ export async function upload(
4264
field,
4365
assembly_url: assemblyUrl,
4466
tus_endpoint: tusEndpoint,
67+
resume_upload_endpoint: resumeUploadEndpoint,
4568
upload_url: uploadUrl,
4669
})
4770
}
@@ -54,23 +77,36 @@ export class UploadCommand extends UnauthenticatedCommand {
5477
description: 'Upload a local file to a tus endpoint for an Assembly',
5578
details: `
5679
Upload a local file to a tus endpoint and attach it to an existing Assembly.
80+
Use --create-upload-endpoint for new uploads or --resume-upload-endpoint to resume.
5781
`,
5882
examples: [
5983
[
6084
'Upload a file to an Assembly',
61-
'transloadit upload ./video.mp4 https://api2.transloadit.com/resumable --assembly https://api2.transloadit.com/assemblies/ASSEMBLY_ID',
85+
'transloadit upload ./video.mp4 --create-upload-endpoint https://api2.transloadit.com/resumable/files/ --assembly https://api2.transloadit.com/assemblies/ASSEMBLY_ID',
86+
],
87+
[
88+
'Resume a file upload',
89+
'transloadit upload ./video.mp4 --resume-upload-endpoint https://api2.transloadit.com/resumable/files/UPLOAD_ID --assembly https://api2.transloadit.com/assemblies/ASSEMBLY_ID',
6290
],
6391
],
6492
})
6593

6694
file = Option.String({ required: true })
67-
tusEndpoint = Option.String({ required: true })
95+
tusEndpoint = Option.String({ required: false })
6896

6997
assemblyUrl = Option.String('--assembly', {
7098
description: 'Assembly URL to attach this upload to',
7199
required: true,
72100
})
73101

102+
createUploadEndpoint = Option.String('--create-upload-endpoint', {
103+
description: 'Tus create endpoint (e.g. https://api2.transloadit.com/resumable/files/)',
104+
})
105+
106+
resumeUploadEndpoint = Option.String('--resume-upload-endpoint', {
107+
description: 'Tus upload URL to resume (e.g. https://.../resumable/files/<id>)',
108+
})
109+
74110
field = Option.String('--field', {
75111
description: 'Field name for the upload (default: :original)',
76112
})
@@ -79,7 +115,8 @@ export class UploadCommand extends UnauthenticatedCommand {
79115
try {
80116
await upload(this.output, {
81117
file: this.file,
82-
tusEndpoint: this.tusEndpoint,
118+
createUploadEndpoint: this.createUploadEndpoint ?? this.tusEndpoint,
119+
resumeUploadEndpoint: this.resumeUploadEndpoint,
83120
assemblyUrl: this.assemblyUrl,
84121
field: this.field,
85122
})

packages/node/test/e2e/cli/upload.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ describe('CLI upload', () => {
2626
await writeFile(filePath, 'hello from CLI upload', 'utf8')
2727

2828
const { stdout, stderr } = await runCli(
29-
`upload ${filePath} ${tusEndpoint} --assembly ${assemblyUrl} --field :original --json`,
29+
`upload ${filePath} --create-upload-endpoint ${tusEndpoint} --assembly ${assemblyUrl} --field :original --json`,
3030
)
3131

3232
expect(stderr).toEqual('')

packages/transloadit/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "transloadit",
3-
"version": "4.3.0",
3+
"version": "4.3.1",
44
"description": "Node.js SDK for Transloadit",
55
"type": "module",
66
"keywords": [

0 commit comments

Comments
 (0)