1- import { io , type Socket } from 'socket.io-client ' ;
1+ import path from 'node:path ' ;
22import { Readable } from 'node:stream' ;
3+ import { io , type Socket } from 'socket.io-client' ;
34import { version } from '../package.json' ;
45import JobsResource , { type JobEventData } from './JobsResource' ;
56import SignedUrlResource from './SignedUrlResource' ;
@@ -17,23 +18,26 @@ export type UploadFileSource =
1718 | AsyncIterable < Uint8Array >
1819 | NodeJS . ReadableStream ;
1920
21+ function guessFilename ( source : UploadFileSource ) : string | undefined {
22+ return 'path' in source && typeof source . path === 'string'
23+ ? path . basename ( source . path )
24+ : undefined ;
25+ }
26+
2027export class UploadFile {
2128 private readonly attributes : Array < [ key : string , value : unknown ] > = [ ] ;
2229 private readonly data : AsyncIterable < Uint8Array > ;
2330 constructor (
2431 data : UploadFileSource ,
25- private readonly filename ?: string
32+ private readonly filename = guessFilename ( data )
2633 ) {
2734 this . data = UploadFile . unifySources ( data ) ;
2835 }
2936 add ( key : string , value : unknown ) {
3037 this . attributes . push ( [ key , value ] ) ;
3138 }
32- async * stream ( ) {
39+ async * stream ( boundary : string ) {
3340 const enc = new TextEncoder ( ) ;
34- const boundary = `----------${ Array . from ( Array ( 32 ) )
35- . map ( ( ) => Math . random ( ) . toString ( 36 ) [ 2 ] || 0 )
36- . join ( '' ) } `;
3741 // Start multipart/form-data protocol
3842 yield enc . encode ( `--${ boundary } \r\n` ) ;
3943 // Send all attributes
@@ -117,22 +121,32 @@ export default class CloudConvert {
117121 async call (
118122 method : 'GET' | 'POST' | 'DELETE' ,
119123 route : string ,
120- parameters ?: UploadFile | object
124+ parameters ?: UploadFile | object ,
125+ options ?: { presigned ?: boolean ; flat ?: boolean }
121126 ) {
122127 const baseURL = this . useSandbox
123128 ? 'https://api.sandbox.cloudconvert.com/v2/'
124129 : `https://${
125130 this . region ? this . region + '.' : ''
126131 } api.cloudconvert.com/v2/`;
127- return await this . callWithBase ( baseURL , method , route , parameters ) ;
132+ return await this . callWithBase (
133+ baseURL ,
134+ method ,
135+ route ,
136+ parameters ,
137+ options
138+ ) ;
128139 }
129140
130141 async callWithBase (
131142 baseURL : string ,
132143 method : 'GET' | 'POST' | 'DELETE' ,
133144 route : string ,
134- parameters ?: UploadFile | object
145+ parameters ?: UploadFile | object ,
146+ options ?: { presigned ?: boolean ; flat ?: boolean }
135147 ) {
148+ const presigned = options ?. presigned ?? false ;
149+ const flat = options ?. flat ?? false ;
136150 const url = new URL ( route , baseURL ) ;
137151 const { contentType, search, body } = prepareParameters (
138152 method ,
@@ -142,8 +156,8 @@ export default class CloudConvert {
142156 url . search = search ;
143157 }
144158 const headers = {
145- Authorization : `Bearer ${ this . apiKey } ` ,
146159 'User-Agent' : `cloudconvert-node/v${ version } (https://github.com/cloudconvert/cloudconvert-node)` ,
160+ ...( ! presigned ? { Authorization : `Bearer ${ this . apiKey } ` } : { } ) ,
147161 ...( contentType ? { 'Content-Type' : contentType } : { } )
148162 } ;
149163 const res = await fetch ( url , {
@@ -154,20 +168,20 @@ export default class CloudConvert {
154168 duplex : 'half'
155169 } ) ;
156170 if ( ! res . ok ) {
157- console . error ( 'SND:' , url , method , headers ) ;
158- console . error ( 'RCV:' , res , await res . text ( ) ) ;
159171 // @ts -expect-error cause not present in types yet
160172 throw new Error ( res . statusText , { cause : res } ) ;
161173 }
162174
163175 if (
164- res . headers . get ( 'Content-Type' ) ?. toLowerCase ( ) !==
165- 'application/json'
176+ ! res . headers
177+ . get ( 'content-type' )
178+ ?. toLowerCase ( )
179+ . includes ( 'application/json' )
166180 ) {
167181 return undefined ;
168182 }
169- const { data } = await res . json ( ) ;
170- return data ;
183+ const json = await res . json ( ) ;
184+ return flat ? json : json . data ;
171185 }
172186
173187 subscribe (
@@ -231,9 +245,12 @@ function prepareParameters(
231245 }
232246
233247 if ( data instanceof UploadFile ) {
248+ const boundary = `----------${ Array . from ( Array ( 32 ) )
249+ . map ( ( ) => Math . random ( ) . toString ( 36 ) [ 2 ] || 0 )
250+ . join ( '' ) } `;
234251 return {
235- contentType : ' multipart/form-data' ,
236- body : asyncIterableToReadableStream ( data . stream ( ) )
252+ contentType : ` multipart/form-data; boundary= ${ boundary } ` ,
253+ body : asyncIterableToReadableStream ( data . stream ( boundary ) )
237254 } ;
238255 }
239256
0 commit comments