diff --git a/packages/@uppy/transloadit/src/AssemblyOptions.js b/packages/@uppy/transloadit/src/AssemblyOptions.js index 3b8946b279..53bc44ecad 100644 --- a/packages/@uppy/transloadit/src/AssemblyOptions.js +++ b/packages/@uppy/transloadit/src/AssemblyOptions.js @@ -48,6 +48,25 @@ function dedupe (list) { })) } +async function getAssemblyOptions (file, options) { + const assemblyOptions = typeof options.assemblyOptions === 'function' + ? await options.assemblyOptions(file, options) + : options.assemblyOptions + + validateParams(assemblyOptions.params) + + return assemblyOptions +} + +function getFields (file, assemblyOptions) { + if (Array.isArray(assemblyOptions.fields)) { + return Object.fromEntries( + assemblyOptions.fields.map((fieldName) => [fieldName, file.meta[fieldName]]), + ) + } + return {} +} + /** * Turn Transloadit plugin options and a list of files into a list of Assembly * options. @@ -58,36 +77,6 @@ class AssemblyOptions { this.opts = opts } - /** - * Get Assembly options for a file. - */ - async #getAssemblyOptions (file) { - if (file == null) return undefined - - const options = this.opts - const assemblyOptions = await options.getAssemblyOptions(file, options) - - // We check if the file is present here again, because it could had been - // removed during the await, e.g. if the user hit cancel while we were - // waiting for the options. - if (file == null) return undefined - - if (Array.isArray(assemblyOptions.fields)) { - assemblyOptions.fields = Object.fromEntries( - assemblyOptions.fields.map((fieldName) => [fieldName, file.meta[fieldName]]), - ) - } else if (assemblyOptions.fields == null) { - assemblyOptions.fields = {} - } - - validateParams(assemblyOptions.params) - - return { - fileIDs: [file.id], - options: assemblyOptions, - } - } - /** * Generate a set of Assemblies that will handle the upload. * Returns a Promise for an object with keys: @@ -99,19 +88,36 @@ class AssemblyOptions { if (this.files.length > 0) { return Promise.all( - this.files.map((file) => this.#getAssemblyOptions(file)), + this.files.map(async (file) => { + if (file == null) return undefined + + const assemblyOptions = await getAssemblyOptions(file, options) + + // We check if the file is present here again, because it could had been + // removed during the await, e.g. if the user hit cancel while we were + // waiting for the options. + if (file == null) return undefined + + assemblyOptions.fields = getFields(file, assemblyOptions) + + return { + fileIDs: [file.id], + options: assemblyOptions, + } + }), ).then(dedupe) } if (options.alwaysRunAssembly) { // No files, just generate one Assembly - const assemblyOptions = await options.getAssemblyOptions(null, options) - - validateParams(assemblyOptions.params) - return [{ - fileIDs: this.files.map((file) => file.id), - options: assemblyOptions, - }] + const assemblyOptions = await getAssemblyOptions(null, options) + + return [ + { + fileIDs: this.files.map((file) => file.id), + options: assemblyOptions, + }, + ] } // If there are no files and we do not `alwaysRunAssembly`, diff --git a/packages/@uppy/transloadit/src/AssemblyOptions.test.js b/packages/@uppy/transloadit/src/AssemblyOptions.test.js index 1f952ce377..98b180d17e 100644 --- a/packages/@uppy/transloadit/src/AssemblyOptions.test.js +++ b/packages/@uppy/transloadit/src/AssemblyOptions.test.js @@ -2,11 +2,11 @@ import { describe, expect, it } from '@jest/globals' import AssemblyOptions from './AssemblyOptions.js' describe('Transloadit/AssemblyOptions', () => { - it('Validates response from getAssemblyOptions()', async () => { + it('Validates response from assemblyOptions()', async () => { const options = new AssemblyOptions([ { name: 'testfile' }, ], { - getAssemblyOptions: (file) => { + assemblyOptions: (file) => { expect(file.name).toBe('testfile') return { params: '{"some":"json"}', @@ -29,7 +29,7 @@ describe('Transloadit/AssemblyOptions', () => { { name: 'c.png', data }, { name: 'd.png', data }, ], { - getAssemblyOptions: (file) => ({ + assemblyOptions: (file) => ({ params: { auth: { key: 'fake key' }, steps: { @@ -57,7 +57,7 @@ describe('Transloadit/AssemblyOptions', () => { { name: 'c.png', data, size: data.byteLength }, { name: 'd.png', data: data2, size: data2.byteLength }, ], { - getAssemblyOptions: (file) => ({ + assemblyOptions: (file) => ({ params: { auth: { key: 'fake key' }, steps: { @@ -77,7 +77,7 @@ describe('Transloadit/AssemblyOptions', () => { it('Does not create an Assembly if no files are being uploaded', async () => { const options = new AssemblyOptions([], { - getAssemblyOptions () { + assemblyOptions () { throw new Error('should not create Assembly') }, }) @@ -88,7 +88,7 @@ describe('Transloadit/AssemblyOptions', () => { it('Creates an Assembly if no files are being uploaded but `alwaysRunAssembly` is enabled', async () => { const options = new AssemblyOptions([], { alwaysRunAssembly: true, - getAssemblyOptions (file) { + async assemblyOptions (file) { expect(file).toBe(null) return { params: { @@ -122,7 +122,7 @@ describe('Transloadit/AssemblyOptions', () => { params: { auth: { key: 'fake key' }, }, - getAssemblyOptions: defaultGetAssemblyOptions, + assemblyOptions: defaultGetAssemblyOptions, }) const assemblies = await options.build() diff --git a/packages/@uppy/transloadit/src/index.js b/packages/@uppy/transloadit/src/index.js index 4784acfa71..f5560eeede 100644 --- a/packages/@uppy/transloadit/src/index.js +++ b/packages/@uppy/transloadit/src/index.js @@ -60,20 +60,26 @@ export default class Transloadit extends BasePlugin { waitForMetadata: false, alwaysRunAssembly: false, importFromUploadURLs: false, + /** @deprecated use `assemblyOptions` instead */ signature: null, + /** @deprecated use `assemblyOptions` instead */ params: null, + /** @deprecated use `assemblyOptions` instead */ fields: {}, + /** @deprecated use `assemblyOptions` instead */ getAssemblyOptions: defaultGetAssemblyOptions, limit: 20, retryDelays: [7_000, 10_000, 15_000, 20_000], } this.opts = { ...defaultOptions, ...opts } + // TODO: move this into `defaultOptions` once we remove the deprecated options + this.opts.assemblyOptions = opts.assemblyOptions ?? this.opts.getAssemblyOptions this.#rateLimitedQueue = new RateLimitedQueue(this.opts.limit) this.i18nInit() - const hasCustomAssemblyOptions = this.opts.getAssemblyOptions !== defaultOptions.getAssemblyOptions + const hasCustomAssemblyOptions = this.opts.assemblyOptions !== defaultOptions.assemblyOptions if (this.opts.params) { validateParams(this.opts.params) } else if (!hasCustomAssemblyOptions) { diff --git a/packages/@uppy/transloadit/types/index.d.ts b/packages/@uppy/transloadit/types/index.d.ts index f3d59985b6..100db01fc5 100644 --- a/packages/@uppy/transloadit/types/index.d.ts +++ b/packages/@uppy/transloadit/types/index.d.ts @@ -2,124 +2,155 @@ import type { PluginOptions, UppyFile, BasePlugin } from '@uppy/core' import TransloaditLocale from './generatedLocale' export interface FileInfo { - id: string, - name: string, - basename: string, - ext: string, - size: number, - mime: string, - type: string, - field: string, - md5hash: string, - is_tus_file: boolean, - original_md5hash: string, - original_id: string, - original_name: string - original_basename: string, - original_path: string, - url: string, - ssl_url: string, - tus_upload_url: string, - meta: Record - } + id: string + name: string + basename: string + ext: string + size: number + mime: string + type: string + field: string + md5hash: string + is_tus_file: boolean + original_md5hash: string + original_id: string + original_name: string + original_basename: string + original_path: string + url: string + ssl_url: string + tus_upload_url: string + meta: Record +} export interface Result extends FileInfo { - cost: number, - execTime: number, - queue: string, - queueTime: number, - localId: string | null - } + cost: number + execTime: number + queue: string + queueTime: number + localId: string | null +} export interface Assembly { - ok?: string, - message?: string, - assembly_id: string, - parent_id?: string, - account_id: string, - template_id?: string, - instance: string, - assembly_url: string, - assembly_ssl_url: string, - uppyserver_url: string, - companion_url: string, - websocket_url: string, - tus_url: string, - bytes_received: number, - bytes_expected: number, - upload_duration: number, - client_agent?: string, - client_ip?: string, - client_referer?: string, - transloadit_client: string, - start_date: string, - upload_meta_data_extracted: boolean, - warnings: any[], - is_infinite: boolean, - has_dupe_jobs: boolean, - execution_start: string, - execution_duration: number, - queue_duration: number, - jobs_queue_duration: number, - notify_start?: any, - notify_url?: string, - notify_status?: any, - notify_response_code?: any, - notify_duration?: any, - last_job_completed?: string, - fields: Record, - running_jobs: any[], - bytes_usage: number, - executing_jobs: any[], - started_jobs: string[], - parent_assembly_status: any, - params: string, - template?: any, - merged_params: string, - uploads: FileInfo[], - results: Record, - build_id: string, - error?: string, - stderr?: string, - stdout?: string, - reason?: string, - } + ok?: string + message?: string + assembly_id: string + parent_id?: string + account_id: string + template_id?: string + instance: string + assembly_url: string + assembly_ssl_url: string + uppyserver_url: string + companion_url: string + websocket_url: string + tus_url: string + bytes_received: number + bytes_expected: number + upload_duration: number + client_agent?: string + client_ip?: string + client_referer?: string + transloadit_client: string + start_date: string + upload_meta_data_extracted: boolean + warnings: any[] + is_infinite: boolean + has_dupe_jobs: boolean + execution_start: string + execution_duration: number + queue_duration: number + jobs_queue_duration: number + notify_start?: any + notify_url?: string + notify_status?: any + notify_response_code?: any + notify_duration?: any + last_job_completed?: string + fields: Record + running_jobs: any[] + bytes_usage: number + executing_jobs: any[] + started_jobs: string[] + parent_assembly_status: any + params: string + template?: any + merged_params: string + uploads: FileInfo[] + results: Record + build_id: string + error?: string + stderr?: string + stdout?: string + reason?: string +} - interface AssemblyParameters { - auth: { - key: string, - expires?: string - } - template_id?: string - steps?: { [step: string]: Record } - notify_url?: string - fields?: { [name: string]: number | string } +interface AssemblyParameters { + auth: { + key: string + expires?: string } + template_id?: string + steps?: { [step: string]: Record } + notify_url?: string +} interface AssemblyOptions { - params: AssemblyParameters - fields?: { [name: string]: number | string } - signature?: string - } + params?: AssemblyParameters + fields?: { [name: string]: number | string } + // TODO (major): move signature into params.auth. + signature?: string +} -interface TransloaditOptionsBase extends PluginOptions { - service?: string - errorReporting?: boolean - waitForEncoding?: boolean - waitForMetadata?: boolean - importFromUploadURLs?: boolean - alwaysRunAssembly?: boolean - locale?: TransloaditLocale - limit?: number +interface Options extends PluginOptions { + service?: string + errorReporting?: boolean + waitForEncoding?: boolean + waitForMetadata?: boolean + importFromUploadURLs?: boolean + alwaysRunAssembly?: boolean + locale?: TransloaditLocale + limit?: number } -// Either have a getAssemblyOptions() that returns an AssemblyOptions, *or* have them embedded in the options -export type TransloaditOptions = TransloaditOptionsBase & - ( - | { - getAssemblyOptions?: (file: UppyFile) => AssemblyOptions | Promise - } - | AssemblyOptions) +export type TransloaditOptions = Options & + ( + | { + assemblyOptions?: AssemblyOptions | ((file: UppyFile) => Promise | AssemblyOptions) + /** @deprecated use `assemblyOptions` instead */ + getAssemblyOptions?: never + /** @deprecated use `assemblyOptions` instead */ + params?: never + /** @deprecated use `assemblyOptions` instead */ + fields?: never + /** @deprecated use `assemblyOptions` instead */ + signature?: never + } + | { + /** @deprecated use `assemblyOptions` instead */ + getAssemblyOptions?: ( + file: UppyFile + ) => AssemblyOptions | Promise + assemblyOptions?: never + /** @deprecated use `assemblyOptions` instead */ + params?: never + /** @deprecated use `assemblyOptions` instead */ + fields?: never + /** @deprecated use `assemblyOptions` instead */ + signature?: never + } + | { + /** @deprecated use `assemblyOptions` instead */ + params?: AssemblyParameters + /** @deprecated use `assemblyOptions` instead */ + fields?: { [name: string]: number | string } + /** @deprecated use `assemblyOptions` instead */ + signature?: string + /** @deprecated use `assemblyOptions` instead */ + getAssemblyOptions?: never + assemblyOptions?: never + } + ) export default class Transloadit extends BasePlugin { /** @deprecated use `import { COMPANION_URL } from '@uppy/transloadit'` instead. */ @@ -134,11 +165,18 @@ export const COMPANION_ALLOWED_HOSTS: RegExp // Events -export type TransloaditAssemblyCreatedCallback = (assembly: Assembly, fileIDs: string[]) => void; -export type TransloaditUploadedCallback = (file: FileInfo, assembly: Assembly) => void; -export type TransloaditAssemblyExecutingCallback = (assembly: Assembly) => void; -export type TransloaditResultCallback = (stepName: string, result: Result, assembly: Assembly) => void; -export type TransloaditCompleteCallback = (assembly: Assembly) => void; +export type TransloaditAssemblyCreatedCallback = ( + assembly: Assembly, + fileIDs: string[] +) => void +export type TransloaditUploadedCallback = (file: FileInfo, assembly: Assembly) => void +export type TransloaditAssemblyExecutingCallback = (assembly: Assembly) => void +export type TransloaditResultCallback = ( + stepName: string, + result: Result, + assembly: Assembly +) => void +export type TransloaditCompleteCallback = (assembly: Assembly) => void declare module '@uppy/core' { export interface UppyEventMap { diff --git a/packages/@uppy/transloadit/types/index.test-d.ts b/packages/@uppy/transloadit/types/index.test-d.ts index 75fac4cdf8..74fde786db 100644 --- a/packages/@uppy/transloadit/types/index.test-d.ts +++ b/packages/@uppy/transloadit/types/index.test-d.ts @@ -22,10 +22,6 @@ const validParams = { waitForEncoding: false, waitForMetadata: true, importFromUploadURLs: false, - params: { - auth: { key: 'abc' }, - steps: {}, - }, }) // Access to both transloadit events and core events uppy.on('transloadit:assembly-created', (assembly) => { @@ -41,15 +37,50 @@ const validParams = { { const uppy = new Uppy() - // must be bools + uppy.use(Transloadit, { + async assemblyOptions (file) { + expectType(file) + return { params: validParams } + }, + }) +} + +{ + const uppy = new Uppy() + uppy.use(Transloadit, { + assemblyOptions: { params: validParams }, + }) +} + +{ + const uppy = new Uppy() expectError( - uppy.use(Transloadit, { waitForEncoding: null, params: validParams }), + uppy.use(Transloadit, { + getAssemblyOptions () { + return { params: validParams } + }, + assemblyOptions: { params: validParams }, + }), ) +} + +{ + const uppy = new Uppy() expectError( - uppy.use(Transloadit, { waitForMetadata: null, params: validParams }), + uppy.use(Transloadit, { + params: validParams, + assemblyOptions: { params: validParams }, + }), ) } +{ + const uppy = new Uppy() + // must be bools + expectError(uppy.use(Transloadit, { waitForEncoding: null, params: validParams })) + expectError(uppy.use(Transloadit, { waitForMetadata: null, params: validParams })) +} + { const uppy = new Uppy() // params.auth.key must be string diff --git a/website/src/docs/transloadit.md b/website/src/docs/transloadit.md index 440182a2a6..a5c22d5051 100644 --- a/website/src/docs/transloadit.md +++ b/website/src/docs/transloadit.md @@ -127,150 +127,108 @@ The value of this constant covers _all_ Transloadit’s Companion servers, so it ## Options -The `@uppy/transloadit` plugin has the following configurable options: +### `id` -### `id: 'Transloadit'` - -A unique identifier for this plugin. It defaults to `'Transloadit'`. +A unique identifier for this plugin (`string`, default: `'Transloadit'`). ### `service` -The Transloadit API URL to use. It defaults to `https://api2.transloadit.com`, which will try to route traffic efficiently based on the location of your users. You can set this to something like `https://api2-us-east-1.transloadit.com` if you want to use a particular region. - -### `params` - -The Assembly parameters to use for the upload. See the Transloadit documentation on [Assembly Instructions](https://transloadit.com/docs/#14-assembly-instructions) for further information. `params` should be a plain JavaScript object, or a JSON string if you are using the [`signature`](#signature) option. - -The `auth.key` Assembly parameter is required. You can also use the `steps` or `template_id` options here as described in the Transloadit documentation. - -```js -uppy.use(Transloadit, { - params: { - auth: { key: 'YOUR_TRANSLOADIT_KEY' }, - steps: { - encode: { - robot: '/video/encode', - use: { - steps: [':original'], - fields: ['file_input_field2'], - }, - preset: 'iphone', - }, - }, - }, -}) -``` - - - -### `waitForEncoding: false` - -By default, the Transloadit plugin uploads files to Assemblies and then marks the files as complete in Uppy. The Assemblies will complete (or error) in the background but Uppy won’t know or care about it. - -When `waitForEncoding` is set to true, the Transloadit plugin waits for Assemblies to complete before the files are marked as completed. This means users have to wait for a potentially long time, depending on how complicated your Assembly instructions are. But, you can receive transcoding results on the client side, and have a fully client-side experience this way. +The Transloadit API URL to use (`string`, default: `https://api2.transloadit.com`). -When this is enabled, you can listen for the [`transloadit:result`](#transloadit-result) and [`transloadit:complete`](#transloadit-complete) events. +The default will try to route traffic efficiently based on the location of your users. You could for instance set it to `https://api2-us-east-1.transloadit.com` if you need the traffic to stay inside a particular region. - +### `limit` -### `waitForMetadata: false` +Limit the amount of uploads going on at the same time (`number`, default: `5`). -By default, the Transloadit plugin uploads files to Assemblies and then marks the files as complete in Uppy. The Assemblies will complete (or error) in the background but Uppy won’t know or care about it. - -When `waitForMetadata` is set to true, the Transloadit plugin waits for Transloadit’s backend to extract metadata from all the uploaded files. This is mostly handy if you want to have a quick user experience (so your users don’t necessarily need to wait for all the encoding to complete), but you do want to let users know about some types of errors that can be caught early on, like file format issues. - -When this is enabled, you can listen for the [`transloadit:upload`](#transloadit-upload) event. - -### `importFromUploadURLs` +Setting this to `0` means no limit on concurrent uploads, but we recommend a value between `5` and `20`. This option is passed through to the [`@uppy/tus`](/docs/upload-strategies/tus) plugin, which this plugin uses internally. -Instead of uploading to Transloadit’s servers directly, allow another plugin to upload files, and then import those files into the Transloadit Assembly. This is set to `false` by default. +### `assemblyOptions` -When enabling this option, Transloadit will _not_ configure the Tus plugin to upload to Transloadit. Instead, a separate upload plugin must be used. Once the upload completes, the Transloadit plugin adds the uploaded file to the Assembly. +Configure the [Assembly Instructions](https://transloadit.com/docs/topics/assembly-instructions/), the fields to send along to the assembly, and authentication (`object | function`, default: `null`). -For example, to upload files to an S3 bucket and then transcode them: +The object you can pass or return from a function has this structure: -```js -uppy.use(AwsS3, { - getUploadParameters (file) { - return { /* upload parameters */ } +```json +{ + "params": { + "auth": { "key": "key-from-transloadit" }, + "template_id": "id-from-transloadit", + "steps": { + // Overruling Template at runtime + }, + "notify_url": "https://your-domain.com/assembly-status", }, -}) -uppy.use(Transloadit, { - importFromUploadURLs: true, - params: { - auth: { key: 'YOUR_API_KEY' }, - template_id: 'YOUR_TEMPLATE_ID', + "signature": "generated-signature", + "fields": { + // Dynamic or static fields to send along to the assembly }, -}) +} ``` -For this to work, the upload plugin must assign a publically accessible `uploadURL` property to the uploaded file object. The Tus and S3 plugins both do this automatically. For the XHRUpload plugin, you may have to specify a custom `getResponseData` function. - -### `alwaysRunAssembly` - -When set to true, always create and run an Assembly when `uppy.upload()` is called, even if no files were selected. This allows running Assemblies that do not receive files, but instead use a robot like [`/s3/import`](https://transloadit.com/docs/transcoding/#s3-import) to download the files from elsewhere, for example, for a bulk transcoding job. - -### `signature` - -An optional signature for the Assembly parameters. See the Transloadit documentation on [Signature Authentication](https://transloadit.com/docs/#26-signature-authentication) for further information. +* `params` is used to authenticate with Transloadit and using your desired [template](https://transloadit.com/docs/topics/templates/). + * `auth.key` _(required)_ is your authentication key which you can find on the “Credentials” page of your account. + * `template_id` _(required)_ is the unique identifier to use the right template from your account. + * `steps` _(optional)_ can be used to [overrule Templates at runtime](https://transloadit.com/docs/topics/templates/#overruling-templates-at-runtime). + A typical use case might be changing the storage path on the fly based on the session user id. For most use cases, we recommend to let your Templates handle dynamic cases (they can accept `fields` and execute arbitrary JavaScript as well), and not pass in `steps` from a browser. The template editor also has extra validations and context. + * `notify_url` _(optional)_ is a pingback with the assembly status as JSON. For instance, if you don’t want to block the user experience by letting them wait for your template to complete with [`waitForEncoding`](#waitForEncoding), but you do want to want to asynchrounously have an update, you can provide an URL which will be “pinged” with the assembly status. +* `signature` _(optional, but recommended)_ is a cryptographic signature to provide further trust in unstrusted environments. Refer to “[Signature Authentication”](https://transloadit.com/docs/topics/signature-authentication/) for more information. +* `fields` _(optional)_ can be used to to send along key/value pairs, which can be [used dynamically in your template](https://transloadit.com/docs/topics/assembly-instructions/#form-fields-in-instructions). -If a `signature` is provided, `params` should be a JSON string instead of a JavaScript object, as otherwise the generated JSON in the browser may be different from the JSON string that was used to generate the signature. +> When you go to production always make sure to set the `signature`. +> **Not using [Signature Authentication](https://transloadit.com/docs/topics/signature-authentication/) can be a security risk**. +> Signature Authentication is a security measure that can prevent outsiders from tampering with your Assembly Instructions. +> While Signature Authentication is not implemented (yet), +> we recommend to enable `allow_steps_override` in your Templates to avoid outsiders being able to pass in any Instructions and storage targets on your behalf. -### `fields` +**Example as a function** -An object of form fields to send along to the Assembly. Keys are field names, and values are field values. See also the Transloadit documentation on [Form Fields In Instructions](https://transloadit.com/docs/#23-form-fields-in-instructions). +A custom `assemblyOptions()` option should return an object or a promise for an object. ```js uppy.use(Transloadit, { - // ... - fields: { - message: 'This is a form field', + assemblyOptions (file) { + return { + params: { + auth: { key: 'TRANSLOADIT_AUTH_KEY_HERE' }, + template_id: 'xyz', + }, + fields: { + caption: file.meta.caption, + }, + } }, }) ``` -You can also pass an array of field names to send global or file metadata along to the Assembly. Global metadata is set using the [`meta` option](/docs/uppy/#meta) in the Uppy constructor, or using the [`setMeta` method](/docs/uppy/#uppy-setMeta-data). File metadata is set using the [`setFileMeta`](/docs/uppy/#uppy-setFileMeta-fileID-data) method. The [Form](/docs/form) plugin also sets global metadata based on the values of ``s in the form, providing a handy way to use values from HTML form fields: +The `${fields.caption}` variable will be available in the Assembly spawned from Template `xyz`. You can use this to dynamically watermark images for example. + +`assemblyOptions()` may also return a Promise, so it could retrieve signed Assembly parameters from a server. For example, assuming an endpoint `/transloadit-params` that responds with a JSON object with `{ params, signature }` properties: ```js -uppy.use(Form, { target: 'form#upload-form', getMetaFromForm: true }) uppy.use(Transloadit, { - fields: ['field_name', 'other_field_name'], - params: { /* ... */ }, + async assemblyOptions (file) { + const res = await fetch('/transloadit-params') + return response.json() + }, }) ``` -Form fields can also be computed dynamically using custom logic, by using the [`getAssemblyOptions(file)`](/docs/transloadit/#getAssemblyOptions-file) option. +**Example as an object** -### `getAssemblyOptions(file)` - -While `params`, `signature`, and `fields` must be determined ahead of time, the `getAssemblyOptions` allows using dynamically generated values for these options. This way, it’s possible to use different Assembly parameters for different files, or to use some user input in an Assembly. - -A custom `getAssemblyOptions()` option should return an object or a Promise for an object with properties `{ params, signature, fields }`. For example, to add a field with some user-provided data from the `MetaData` plugin: +If you don’t need to change anything dynamically, you can also pass an object directly. ```js -uppy.use(MetaData, { - fields: [ - { id: 'caption' }, - ], -}) uppy.use(Transloadit, { - getAssemblyOptions (file) { - return { - params: { - auth: { key: 'TRANSLOADIT_AUTH_KEY_HERE' }, - template_id: 'xyz', - }, - fields: { - caption: file.meta.caption, - }, - } + assemblyOptions: { + params: { auth: { key: 'transloadit-key' } }, }, }) ``` -Now, the `${fields.caption}` variable will be available in the Assembly template. +**Example with @uppy/form** -Combine the `getAssemblyOptions()` option with the [Form](/docs/form) plugin to pass user input from a `
` to a Transloadit Assembly: +Combine the `assemblyOptions()` option with the [Form](/docs/form) plugin to pass user input from a `` to a Transloadit Assembly: ```js // This will add form field values to each file's `.meta` object: @@ -288,21 +246,52 @@ uppy.use(Transloadit, { }) ``` -`getAssemblyOptions()` may also return a Promise, so it could retrieve signed Assembly parameters from a server. For example, assuming an endpoint `/transloadit-params` that responds with a JSON object with `{ params, signature }` properties: +### `waitForEncoding: false` + +By default, the Transloadit plugin uploads files to Assemblies and then marks the files as complete in Uppy. The Assemblies will complete (or error) in the background but Uppy won’t know or care about it. + +When `waitForEncoding` is set to true, the Transloadit plugin waits for Assemblies to complete before the files are marked as completed. This means users have to wait for a potentially long time, depending on how complicated your Assembly instructions are. But, you can receive transcoding results on the client side, and have a fully client-side experience this way. + +When this is enabled, you can listen for the [`transloadit:result`](#transloadit-result) and [`transloadit:complete`](#transloadit-complete) events. + + + +### `waitForMetadata: false` + +By default, the Transloadit plugin uploads files to Assemblies and then marks the files as complete in Uppy. The Assemblies will complete (or error) in the background but Uppy won’t know or care about it. + +When `waitForMetadata` is set to true, the Transloadit plugin waits for Transloadit’s backend to extract metadata from all the uploaded files. This is mostly handy if you want to have a quick user experience (so your users don’t necessarily need to wait for all the encoding to complete), but you do want to let users know about some types of errors that can be caught early on, like file format issues. + +When this is enabled, you can listen for the [`transloadit:upload`](#transloadit-upload) event. + +### `importFromUploadURLs` + +Instead of uploading to Transloadit’s servers directly, allow another plugin to upload files, and then import those files into the Transloadit Assembly. This is set to `false` by default. + +When enabling this option, Transloadit will _not_ configure the Tus plugin to upload to Transloadit. Instead, a separate upload plugin must be used. Once the upload completes, the Transloadit plugin adds the uploaded file to the Assembly. + +For example, to upload files to an S3 bucket and then transcode them: ```js +uppy.use(AwsS3, { + getUploadParameters (file) { + return { /* upload parameters */ } + }, +}) uppy.use(Transloadit, { - getAssemblyOptions (file) { - return fetch('/transloadit-params').then((response) => { - return response.json() - }) + importFromUploadURLs: true, + params: { + auth: { key: 'YOUR_API_KEY' }, + template_id: 'YOUR_TEMPLATE_ID', }, }) ``` -### `limit: 0` +For this to work, the upload plugin must assign a publically accessible `uploadURL` property to the uploaded file object. The Tus and S3 plugins both do this automatically. For the XHRUpload plugin, you may have to specify a custom `getResponseData` function. + +### `alwaysRunAssembly` -Limit the amount of uploads going on at the same time. Setting this to `0` means no limit on concurrent uploads. This option is passed through to the [`@uppy/tus`](/docs/tus) plugin that Transloadit plugin uses internally. +When set to true, always create and run an Assembly when `uppy.upload()` is called, even if no files were selected. This allows running Assemblies that do not receive files, but instead use a robot like [`/s3/import`](https://transloadit.com/docs/transcoding/#s3-import) to download the files from elsewhere, for example, for a bulk transcoding job. ### `locale: {}` @@ -320,6 +309,12 @@ export default { } ``` +### Deprecated options + +`getAssemblyOptions`, `params`, `signature`, and `fields` have been deprecated in favor of [`assemblyOptions`](#assemblyoptions), which we now recommend for all use cases. You can still use these options, but they will be removed in the next major version. + +You can view the old docs for them [here](https://github.com/transloadit/uppy/blob/ff32dde1fd71af6dd5cd1927a1408dba36ab5329/website/src/docs/transloadit.md?plain=1). + ## Errors If an error occurs when an Assembly has already started, you can find the Assembly Status on the error object’s `assembly` property.