123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- import ErrorWithCause from '@uppy/utils/lib/ErrorWithCause'
- import type { Body, Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
- import type { AssemblyParameters, Opts, AssemblyOptions as Options } from '.'
- /**
- * Check that Assembly parameters are present and include all required fields.
- */
- function validateParams(params?: AssemblyParameters | null): void {
- if (params == null) {
- throw new Error('Transloadit: The `params` option is required.')
- }
- if (typeof params === 'string') {
- try {
- // eslint-disable-next-line no-param-reassign
- params = JSON.parse(params)
- } catch (err) {
- // Tell the user that this is not an Uppy bug!
- throw new ErrorWithCause(
- 'Transloadit: The `params` option is a malformed JSON string.',
- { cause: err },
- )
- }
- }
- if (!params!.auth || !params!.auth.key) {
- throw new Error(
- 'Transloadit: The `params.auth.key` option is required. ' +
- 'You can find your Transloadit API key at https://transloadit.com/c/template-credentials',
- )
- }
- }
- export type OptionsWithRestructuredFields = Omit<Options, 'fields'> & {
- fields: Record<string, string | number>
- }
- /**
- * Combine Assemblies with the same options into a single Assembly for all the
- * relevant files.
- */
- function dedupe(
- list: Array<
- { fileIDs: string[]; options: OptionsWithRestructuredFields } | undefined
- >,
- ) {
- const dedupeMap: Record<
- string,
- { fileIDArrays: string[][]; options: OptionsWithRestructuredFields }
- > = Object.create(null)
- for (const { fileIDs, options } of list.filter(Boolean) as Array<{
- fileIDs: string[]
- options: OptionsWithRestructuredFields
- }>) {
- const id = JSON.stringify(options)
- if (id in dedupeMap) {
- dedupeMap[id].fileIDArrays.push(fileIDs)
- } else {
- dedupeMap[id] = {
- options,
- fileIDArrays: [fileIDs],
- }
- }
- }
- return Object.values(dedupeMap).map(({ options, fileIDArrays }) => ({
- options,
- fileIDs: fileIDArrays.flat(1),
- }))
- }
- async function getAssemblyOptions<M extends Meta, B extends Body>(
- file: UppyFile<M, B> | null,
- options: Opts<M, B>,
- ): Promise<OptionsWithRestructuredFields> {
- const assemblyOptions = (
- typeof options.assemblyOptions === 'function' ?
- await options.assemblyOptions(file, options)
- : options.assemblyOptions) as OptionsWithRestructuredFields
- validateParams(assemblyOptions.params)
- const { fields } = assemblyOptions
- if (Array.isArray(fields)) {
- assemblyOptions.fields =
- file == null ?
- {}
- : Object.fromEntries(
- fields.map((fieldName) => [fieldName, file.meta[fieldName]]),
- )
- } else if (fields == null) {
- assemblyOptions.fields = {}
- }
- return assemblyOptions
- }
- /**
- * Turn Transloadit plugin options and a list of files into a list of Assembly
- * options.
- */
- class AssemblyOptions<M extends Meta, B extends Body> {
- opts: Opts<M, B>
- files: UppyFile<M, B>[]
- constructor(files: UppyFile<M, B>[], opts: Opts<M, B>) {
- this.files = files
- this.opts = opts
- }
- /**
- * Generate a set of Assemblies that will handle the upload.
- * Returns a Promise for an object with keys:
- * - fileIDs - an array of file IDs to add to this Assembly
- * - options - Assembly options
- */
- async build(): Promise<
- { fileIDs: string[]; options: OptionsWithRestructuredFields }[]
- > {
- const options = this.opts
- if (this.files.length > 0) {
- return Promise.all(
- 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
- return {
- fileIDs: [file.id],
- options: assemblyOptions,
- }
- }),
- ).then(dedupe)
- }
- if (options.alwaysRunAssembly) {
- // No files, just generate one Assembly
- const assemblyOptions = await getAssemblyOptions(null, options)
- return [
- {
- fileIDs: [],
- options: assemblyOptions,
- },
- ]
- }
- // If there are no files and we do not `alwaysRunAssembly`,
- // don't do anything.
- return []
- }
- }
- export default AssemblyOptions
- export { validateParams }
|