@@ -13,6 +13,7 @@ const intoStream = require('into-stream')
13
13
const isStream = require ( 'is-stream' )
14
14
const assert = require ( 'assert' )
15
15
const pMap = require ( 'p-map' )
16
+ const uuid = require ( 'uuid' )
16
17
17
18
const PaginationStream = require ( './PaginationStream' )
18
19
const { version } = require ( '../package.json' )
@@ -173,7 +174,7 @@ class TransloaditClient {
173
174
* @param {object } opts assembly options
174
175
* @returns {Promise }
175
176
*/
176
- async createAssembly ( opts = { } , arg2 ) {
177
+ createAssembly ( opts = { } , arg2 ) {
177
178
// Warn users of old callback API
178
179
if ( typeof arg2 === 'function' ) {
179
180
throw new TypeError ( 'You are trying to send a function as the second argument. This is no longer valid in this version. Please see github README for usage.' )
@@ -194,90 +195,104 @@ class TransloaditClient {
194
195
// Keep track of how long the request took
195
196
const startTimeMs = getHrTimeMs ( )
196
197
197
- // Undocumented feature to allow specifying the assembly id from the client
198
- // (not recommended for general use due to security)
199
- const urlSuffix = assemblyId != null ? `/assemblies/${ assemblyId } ` : '/assemblies'
198
+ // Undocumented feature to allow specifying a custom assembly id from the client
199
+ // Not recommended for general use due to security. E.g if the user doesn't provide a cryptographically
200
+ // secure ID, then anyone could access the assembly.
201
+ let effectiveAssemblyId
202
+ if ( assemblyId != null ) {
203
+ effectiveAssemblyId = assemblyId
204
+ } else {
205
+ effectiveAssemblyId = uuid . v4 ( ) . replace ( / - / g, '' )
206
+ }
207
+ const urlSuffix = `/assemblies/${ effectiveAssemblyId } `
200
208
201
- this . _lastUsedAssemblyUrl = `${ this . _endpoint } ${ urlSuffix } `
209
+ // We want to be able to return the promise immediately with custom data
210
+ const promise = ( async ( ) => {
211
+ this . _lastUsedAssemblyUrl = `${ this . _endpoint } ${ urlSuffix } `
202
212
203
- // eslint-disable-next-line no-bitwise
204
- await pMap ( Object . entries ( files ) , async ( [ , path ] ) => access ( path , fs . F_OK | fs . R_OK ) , { concurrency : 5 } )
213
+ // eslint-disable-next-line no-bitwise
214
+ await pMap ( Object . entries ( files ) , async ( [ , path ] ) => access ( path , fs . F_OK | fs . R_OK ) , { concurrency : 5 } )
205
215
206
- // Convert uploads to streams
207
- const streamsMap = fromPairs ( Object . entries ( uploads ) . map ( ( [ label , value ] ) => {
208
- const isReadable = isStream . readable ( value )
209
- if ( ! isReadable && isStream ( value ) ) {
210
- // https://github.com/transloadit/node-sdk/issues/92
211
- throw new Error ( `Upload named "${ label } " is not a Readable stream` )
212
- }
216
+ // Convert uploads to streams
217
+ const streamsMap = fromPairs ( Object . entries ( uploads ) . map ( ( [ label , value ] ) => {
218
+ const isReadable = isStream . readable ( value )
219
+ if ( ! isReadable && isStream ( value ) ) {
220
+ // https://github.com/transloadit/node-sdk/issues/92
221
+ throw new Error ( `Upload named "${ label } " is not a Readable stream` )
222
+ }
213
223
214
- return [
215
- label ,
216
- isStream . readable ( value ) ? value : intoStream ( value ) ,
217
- ]
218
- } ) )
224
+ return [
225
+ label ,
226
+ isStream . readable ( value ) ? value : intoStream ( value ) ,
227
+ ]
228
+ } ) )
219
229
220
- // Wrap in object structure (so we can know if it's a pathless stream or not)
221
- const allStreamsMap = fromPairs ( Object . entries ( streamsMap ) . map ( ( [ label , stream ] ) => [ label , { stream } ] ) )
230
+ // Wrap in object structure (so we can know if it's a pathless stream or not)
231
+ const allStreamsMap = fromPairs ( Object . entries ( streamsMap ) . map ( ( [ label , stream ] ) => [ label , { stream } ] ) )
222
232
223
- // Create streams from files too
224
- for ( const [ label , path ] of Object . entries ( files ) ) {
225
- const stream = fs . createReadStream ( path )
226
- allStreamsMap [ label ] = { stream, path } // File streams have path
227
- }
233
+ // Create streams from files too
234
+ for ( const [ label , path ] of Object . entries ( files ) ) {
235
+ const stream = fs . createReadStream ( path )
236
+ allStreamsMap [ label ] = { stream, path } // File streams have path
237
+ }
228
238
229
- const allStreams = Object . values ( allStreamsMap )
239
+ const allStreams = Object . values ( allStreamsMap )
230
240
231
- // Pause all streams
232
- allStreams . forEach ( ( { stream } ) => stream . pause ( ) )
241
+ // Pause all streams
242
+ allStreams . forEach ( ( { stream } ) => stream . pause ( ) )
233
243
234
- // If any stream emits error, we want to handle this and exit with error
235
- const streamErrorPromise = new Promise ( ( resolve , reject ) => {
236
- allStreams . forEach ( ( { stream } ) => stream . on ( 'error' , reject ) )
237
- } )
244
+ // If any stream emits error, we want to handle this and exit with error
245
+ const streamErrorPromise = new Promise ( ( resolve , reject ) => {
246
+ allStreams . forEach ( ( { stream } ) => stream . on ( 'error' , reject ) )
247
+ } )
238
248
239
- const createAssemblyAndUpload = async ( ) => {
240
- const useTus = isResumable && allStreams . every ( isFileBasedStream )
249
+ const createAssemblyAndUpload = async ( ) => {
250
+ const useTus = isResumable && allStreams . every ( isFileBasedStream )
241
251
242
- const requestOpts = {
243
- urlSuffix,
244
- method : 'post' ,
245
- timeout,
246
- params,
247
- }
252
+ const requestOpts = {
253
+ urlSuffix,
254
+ method : 'post' ,
255
+ timeout,
256
+ params,
257
+ }
248
258
249
- if ( useTus ) {
250
- requestOpts . fields = {
251
- tus_num_expected_upload_files : allStreams . length ,
259
+ if ( useTus ) {
260
+ requestOpts . fields = {
261
+ tus_num_expected_upload_files : allStreams . length ,
262
+ }
263
+ } else if ( isResumable ) {
264
+ logWarn ( 'Disabling resumability because the size of one or more streams cannot be determined' )
252
265
}
253
- } else if ( isResumable ) {
254
- logWarn ( 'Disabling resumability because the size of one or more streams cannot be determined' )
255
- }
256
266
257
- // upload as form multipart or tus?
258
- const formUploadStreamsMap = useTus ? { } : allStreamsMap
259
- const tusStreamsMap = useTus ? allStreamsMap : { }
267
+ // upload as form multipart or tus?
268
+ const formUploadStreamsMap = useTus ? { } : allStreamsMap
269
+ const tusStreamsMap = useTus ? allStreamsMap : { }
260
270
261
- const result = await this . _remoteJson ( requestOpts , formUploadStreamsMap , onUploadProgress )
262
- checkResult ( result )
271
+ const result = await this . _remoteJson ( requestOpts , formUploadStreamsMap , onUploadProgress )
272
+ checkResult ( result )
263
273
264
- if ( useTus && Object . keys ( tusStreamsMap ) . length > 0 ) {
265
- await sendTusRequest ( {
266
- streamsMap : tusStreamsMap ,
267
- assembly : result ,
268
- onProgress : onUploadProgress ,
274
+ if ( useTus && Object . keys ( tusStreamsMap ) . length > 0 ) {
275
+ await sendTusRequest ( {
276
+ streamsMap : tusStreamsMap ,
277
+ assembly : result ,
278
+ onProgress : onUploadProgress ,
279
+ } )
280
+ }
281
+
282
+ if ( ! waitForCompletion ) return result
283
+ const awaitResult = await this . awaitAssemblyCompletion ( result . assembly_id , {
284
+ timeout, onAssemblyProgress, startTimeMs,
269
285
} )
286
+ checkResult ( awaitResult )
287
+ return awaitResult
270
288
}
271
289
272
- if ( ! waitForCompletion ) return result
273
- const awaitResult = await this . awaitAssemblyCompletion ( result . assembly_id , {
274
- timeout, onAssemblyProgress, startTimeMs,
275
- } )
276
- checkResult ( awaitResult )
277
- return awaitResult
278
- }
290
+ return Promise . race ( [ createAssemblyAndUpload ( ) , streamErrorPromise ] )
291
+ } ) ( )
279
292
280
- return Promise . race ( [ createAssemblyAndUpload ( ) , streamErrorPromise ] )
293
+ // This allows the user to use or log the assemblyId even before it has been created for easier debugging
294
+ promise . assemblyId = effectiveAssemblyId
295
+ return promise
281
296
}
282
297
283
298
async awaitAssemblyCompletion ( assemblyId , {
0 commit comments