UNPKG

@wordpress/upload-media

Version:
8 lines (7 loc) 19.7 kB
{ "version": 3, "sources": ["../../src/store/actions.ts"], "sourcesContent": ["/**\n * External dependencies\n */\nimport { v4 as uuidv4 } from 'uuid';\n\n/**\n * WordPress dependencies\n */\nimport type { createRegistry } from '@wordpress/data';\nimport { __ } from '@wordpress/i18n';\n\ntype WPDataRegistry = ReturnType< typeof createRegistry >;\n\n/**\n * Internal dependencies\n */\nimport type {\n\tAdditionalData,\n\tCancelAction,\n\tOnBatchSuccessHandler,\n\tOnChangeHandler,\n\tOnErrorHandler,\n\tOnSuccessHandler,\n\tQueueItemId,\n\tRetryItemAction,\n\tScheduleRetryAction,\n\tState,\n} from './types';\nimport { ItemStatus, OperationType, Type } from './types';\nimport {\n\tcalculateRetryDelay,\n\tclearRetryTimer,\n\tretryTimers,\n\tshouldRetryError,\n} from './utils/retry';\nimport type {\n\taddItem,\n\tprocessItem,\n\tremoveItem,\n\trevokeBlobUrls,\n} from './private-actions';\nimport { maybeRecycleVipsWorker, vipsCancelOperations } from './utils';\nimport { cancelGifToVideoOperations } from './utils/video-conversion';\nimport { debug } from './utils/debug-logger';\nimport { ErrorCode, UploadError } from '../upload-error';\nimport { validateMimeType } from '../validate-mime-type';\nimport { validateMimeTypeForUser } from '../validate-mime-type-for-user';\nimport { validateFileSize } from '../validate-file-size';\n\ntype ActionCreators = {\n\taddItem: typeof addItem;\n\taddItems: typeof addItems;\n\tremoveItem: typeof removeItem;\n\tprocessItem: typeof processItem;\n\tcancelItem: typeof cancelItem;\n\tretryItem: typeof retryItem;\n\tscheduleRetry: typeof scheduleRetry;\n\texecuteRetry: typeof executeRetry;\n\trevokeBlobUrls: typeof revokeBlobUrls;\n\t< T = Record< string, unknown > >( args: T ): void;\n};\n\ntype AllSelectors = typeof import('./selectors') &\n\ttypeof import('./private-selectors');\ntype CurriedState< F > = F extends ( state: State, ...args: infer P ) => infer R\n\t? ( ...args: P ) => R\n\t: F;\ntype Selectors = {\n\t[ key in keyof AllSelectors ]: CurriedState< AllSelectors[ key ] >;\n};\n\ntype ThunkArgs = {\n\tselect: Selectors;\n\tdispatch: ActionCreators;\n\tregistry: WPDataRegistry;\n};\n\ninterface AddItemsArgs {\n\tfiles: File[];\n\tonChange?: OnChangeHandler;\n\tonSuccess?: OnSuccessHandler;\n\tonBatchSuccess?: OnBatchSuccessHandler;\n\tonError?: OnErrorHandler;\n\tadditionalData?: AdditionalData;\n\tallowedTypes?: string[];\n}\n\n/**\n * Adds a new item to the upload queue.\n *\n * @param $0\n * @param $0.files Files\n * @param [$0.onChange] Function called each time a file or a temporary representation of the file is available.\n * @param [$0.onSuccess] Function called after the file is uploaded.\n * @param [$0.onBatchSuccess] Function called after a batch of files is uploaded.\n * @param [$0.onError] Function called when an error happens.\n * @param [$0.additionalData] Additional data to include in the request.\n * @param [$0.allowedTypes] Array with the types of media that can be uploaded, if unset all types are allowed.\n */\nexport function addItems( {\n\tfiles,\n\tonChange,\n\tonSuccess,\n\tonError,\n\tonBatchSuccess,\n\tadditionalData,\n\tallowedTypes,\n}: AddItemsArgs ) {\n\treturn async ( { select, dispatch }: ThunkArgs ) => {\n\t\tconst batchId = uuidv4();\n\t\tfor ( const file of files ) {\n\t\t\t/*\n\t\t\t Check if the caller (e.g. a block) supports this mime type.\n\t\t\t Special case for file types such as HEIC which will be converted before upload anyway.\n\t\t\t Another check will be done before upload.\n\t\t\t*/\n\t\t\ttry {\n\t\t\t\tvalidateMimeType( file, allowedTypes );\n\t\t\t\tvalidateMimeTypeForUser(\n\t\t\t\t\tfile,\n\t\t\t\t\tselect.getSettings().allowedMimeTypes\n\t\t\t\t);\n\t\t\t} catch ( error: unknown ) {\n\t\t\t\tonError?.( error as Error );\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tvalidateFileSize(\n\t\t\t\t\tfile,\n\t\t\t\t\tselect.getSettings().maxUploadFileSize\n\t\t\t\t);\n\t\t\t} catch ( error: unknown ) {\n\t\t\t\tonError?.( error as Error );\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tdispatch.addItem( {\n\t\t\t\tfile,\n\t\t\t\tbatchId,\n\t\t\t\tonChange,\n\t\t\t\tonSuccess,\n\t\t\t\tonBatchSuccess,\n\t\t\t\tonError,\n\t\t\t\tadditionalData,\n\t\t\t} );\n\t\t}\n\t};\n}\n\n/**\n * Cancels an item in the queue based on an error.\n *\n * If the error is retryable and the item hasn't exceeded the maximum\n * retry attempts, it will be scheduled for automatic retry instead\n * of being cancelled.\n *\n * @param id Item ID.\n * @param error Error instance.\n * @param silent Whether to cancel the item silently,\n * without invoking its `onError` callback.\n */\nexport function cancelItem( id: QueueItemId, error: Error, silent = false ) {\n\treturn async ( { select, dispatch }: ThunkArgs ) => {\n\t\tconst item = select.getItem( id );\n\n\t\tif ( ! item ) {\n\t\t\t/*\n\t\t\t * Do nothing if item has already been removed.\n\t\t\t * This can happen if an upload is cancelled manually\n\t\t\t * while transcoding with vips is still in progress.\n\t\t\t * Then, cancelItem() is once invoked manually and once\n\t\t\t * by the error handler in optimizeImageItem().\n\t\t\t */\n\t\t\treturn;\n\t\t}\n\n\t\t// Clear any pending retry timer for this item.\n\t\tclearRetryTimer( id );\n\n\t\t// Check if we should automatically retry instead of cancelling.\n\t\t// Child sideload items are excluded: the parent owns the upload\n\t\t// lifecycle and decides whether a sub-size failure should cancel\n\t\t// the whole attachment or keep the partially-uploaded sub-sizes.\n\t\t// Items whose primary upload already finished (attachment exists)\n\t\t// are also excluded — the cancellation is cleanup, not a retry.\n\t\tif ( ! silent && error && ! item.parentId && ! item.attachment?.id ) {\n\t\t\tconst settings = select.getSettings();\n\t\t\tconst retrySettings = settings.retry;\n\n\t\t\tif ( retrySettings ) {\n\t\t\t\tconst retryCount = item.retryCount ?? 0;\n\t\t\t\tconst maxRetries = retrySettings.maxRetryAttempts;\n\n\t\t\t\tif ( shouldRetryError( error, retryCount, maxRetries ) ) {\n\t\t\t\t\tdispatch.scheduleRetry( id, error );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\titem.abortController?.abort();\n\n\t\t// Cancel any ongoing vips operations for this item.\n\t\tawait vipsCancelOperations( id );\n\n\t\t/*\n\t\t * Cancel any ongoing GIF-to-video conversion for this item so a\n\t\t * cancelled upload does not leave the encoder running off-thread.\n\t\t */\n\t\tawait cancelGifToVideoOperations( id );\n\n\t\tif ( ! silent ) {\n\t\t\tconst { onError } = item;\n\t\t\tonError?.( error ?? new Error( 'Upload cancelled' ) );\n\t\t\tif ( ! onError && error && ! item.parentId ) {\n\t\t\t\t// Log errors for top-level items without an onError handler.\n\t\t\t\t// Child sideload errors are suppressed here because the\n\t\t\t\t// parent will be notified and surface the error to the user.\n\t\t\t\t// eslint-disable-next-line no-console -- Deliberately log errors here.\n\t\t\t\tconsole.error( 'Upload cancelled', error );\n\t\t\t}\n\t\t} else {\n\t\t\tdebug(\n\t\t\t\t`Item cancelled: ${ item.file.name } (item ${ id }): ${\n\t\t\t\t\terror instanceof Error ? error.message : error\n\t\t\t\t}`\n\t\t\t);\n\t\t}\n\n\t\tconst { currentOperation, parentId, batchId } = item;\n\n\t\tdispatch< CancelAction >( {\n\t\t\ttype: Type.Cancel,\n\t\t\tid,\n\t\t\terror,\n\t\t} );\n\t\tdispatch.removeItem( id );\n\t\tdispatch.revokeBlobUrls( id );\n\n\t\t// A concurrency slot just freed up. Kick any items that were\n\t\t// waiting in the queue, mirroring finishOperation's behavior.\n\t\tif (\n\t\t\tcurrentOperation === OperationType.ResizeCrop ||\n\t\t\tcurrentOperation === OperationType.Rotate\n\t\t) {\n\t\t\tfor ( const pending of select.getPendingImageProcessing() ) {\n\t\t\t\tdispatch.processItem( pending.id );\n\t\t\t}\n\t\t}\n\t\tif ( currentOperation === OperationType.Upload ) {\n\t\t\tfor ( const pending of select.getPendingUploads() ) {\n\t\t\t\tdispatch.processItem( pending.id );\n\t\t\t}\n\t\t}\n\t\tif ( currentOperation === OperationType.TranscodeGif ) {\n\t\t\tfor ( const pending of select.getPendingVideoProcessing() ) {\n\t\t\t\tdispatch.processItem( pending.id );\n\t\t\t}\n\t\t}\n\n\t\t// Failed vips ops also leak WASM memory, so count them toward the\n\t\t// recycle budget. Without this, a long burst of failures (e.g. a\n\t\t// gallery of unsupported AVIFs) could grow memory unbounded.\n\t\tif (\n\t\t\tcurrentOperation === OperationType.ResizeCrop ||\n\t\t\tcurrentOperation === OperationType.Rotate ||\n\t\t\tcurrentOperation === OperationType.TranscodeImage\n\t\t) {\n\t\t\tmaybeRecycleVipsWorker( select.getActiveImageProcessingCount() );\n\t\t}\n\n\t\t// If this was a child sideload item, handle the parent.\n\t\tif ( parentId ) {\n\t\t\tconst parentItem = select.getItem( parentId );\n\t\t\tif ( parentItem ) {\n\t\t\t\t/*\n\t\t\t\t * The converted video and its poster are optional companions\n\t\t\t\t * of an animated GIF: the parent GIF attachment is fine\n\t\t\t\t * without them. Their failure must never be treated as a total\n\t\t\t\t * parent failure (which would delete the already-uploaded GIF),\n\t\t\t\t * even when the companion is the only child sideload.\n\t\t\t\t */\n\t\t\t\tconst isOptionalCompanion =\n\t\t\t\t\titem.additionalData?.image_size === 'animated_video' ||\n\t\t\t\t\titem.additionalData?.image_size === 'animated_video_poster';\n\n\t\t\t\tif ( select.hasPendingItemsByParentId( parentId ) ) {\n\t\t\t\t\t// Other children remain — just notify the parent so\n\t\t\t\t\t// it can re-check the Finalize gate.\n\t\t\t\t\tif (\n\t\t\t\t\t\tparentItem.operations &&\n\t\t\t\t\t\tparentItem.operations.length > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tdispatch.processItem( parentId );\n\t\t\t\t\t}\n\t\t\t\t} else if (\n\t\t\t\t\t( parentItem.subSizes && parentItem.subSizes.length > 0 ) ||\n\t\t\t\t\tisOptionalCompanion\n\t\t\t\t) {\n\t\t\t\t\t/*\n\t\t\t\t\t * Partial success: at least one child sideload succeeded\n\t\t\t\t\t * (its sub-size is already accumulated on the parent), or\n\t\t\t\t\t * the failed child was an optional companion. Keep the\n\t\t\t\t\t * parent attachment and finalize with whichever sub-sizes\n\t\t\t\t\t * did succeed — matching WordPress core's best-effort\n\t\t\t\t\t * behavior when individual sub-size generations fail.\n\t\t\t\t\t */\n\t\t\t\t\tif (\n\t\t\t\t\t\tparentItem.operations &&\n\t\t\t\t\t\tparentItem.operations.length > 0\n\t\t\t\t\t) {\n\t\t\t\t\t\tdispatch.processItem( parentId );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Total failure: no child succeeded. The parent file\n\t\t\t\t\t// already uploaded — delete the orphaned attachment\n\t\t\t\t\t// from the server so it doesn't appear in the media\n\t\t\t\t\t// library.\n\t\t\t\t\tconst parentAttachmentId = parentItem.attachment?.id;\n\t\t\t\t\tconst { mediaDelete } = select.getSettings();\n\t\t\t\t\tif ( parentAttachmentId && mediaDelete ) {\n\t\t\t\t\t\tmediaDelete( parentAttachmentId ).catch( () => {\n\t\t\t\t\t\t\t// Best-effort cleanup; surface nothing to the\n\t\t\t\t\t\t\t// user if the delete itself fails.\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Cancel the parent too so the block resets rather\n\t\t\t\t\t// than showing a partial upload. Propagate the\n\t\t\t\t\t// underlying error's code and message — vips\n\t\t\t\t\t// processing failures already carry an actionable\n\t\t\t\t\t// hint at their source; network/server failures\n\t\t\t\t\t// surface their real cause. Awaited so the cascade\n\t\t\t\t\t// fully settles (parent removed, onError fired) before\n\t\t\t\t\t// this thunk resolves and the batch-completion check\n\t\t\t\t\t// below runs.\n\t\t\t\t\tawait dispatch.cancelItem(\n\t\t\t\t\t\tparentId,\n\t\t\t\t\t\tnew UploadError( {\n\t\t\t\t\t\t\tcode:\n\t\t\t\t\t\t\t\t( error instanceof UploadError &&\n\t\t\t\t\t\t\t\t\terror.code ) ||\n\t\t\t\t\t\t\t\tErrorCode.GENERAL,\n\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\terror?.message ||\n\t\t\t\t\t\t\t\t__( 'The image could not be uploaded.' ),\n\t\t\t\t\t\t\tfile: parentItem.file,\n\t\t\t\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t\t\t\t} )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// All items of this batch were cancelled or finished.\n\t\tif ( batchId && select.isBatchUploaded( batchId ) ) {\n\t\t\tdebug( `Batch completed: ${ batchId }` );\n\t\t\titem.onBatchSuccess?.();\n\t\t}\n\t};\n}\n\n/**\n * Retries a failed item in the queue.\n *\n * @param id Item ID.\n */\nexport function retryItem( id: QueueItemId ) {\n\treturn async ( { select, dispatch }: ThunkArgs ) => {\n\t\tconst item = select.getItem( id );\n\n\t\tif ( ! item ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Only retry items that have an error.\n\t\tif ( ! item.error ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdispatch< RetryItemAction >( {\n\t\t\ttype: Type.RetryItem,\n\t\t\tid,\n\t\t} );\n\n\t\tdispatch.processItem( id );\n\t};\n}\n\n/**\n * Schedules an automatic retry for a failed item.\n *\n * Uses exponential backoff with jitter to determine the retry delay.\n * The item will be placed in PendingRetry status and automatically\n * retried after the calculated delay.\n *\n * @param id Item ID.\n * @param error The error that caused the failure.\n */\nexport function scheduleRetry( id: QueueItemId, error: Error ) {\n\treturn async ( { select, dispatch }: ThunkArgs ) => {\n\t\tconst item = select.getItem( id );\n\t\tif ( ! item ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst settings = select.getSettings();\n\t\tconst retrySettings = settings.retry;\n\n\t\tif ( ! retrySettings ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst currentRetryCount = item.retryCount ?? 0;\n\n\t\tconst delay = calculateRetryDelay( {\n\t\t\tattempt: currentRetryCount + 1,\n\t\t\tinitialDelay: retrySettings.initialRetryDelayMs,\n\t\t\tmaxDelay: retrySettings.maxRetryDelayMs,\n\t\t\tmultiplier: retrySettings.backoffMultiplier,\n\t\t\tjitter: retrySettings.retryJitter,\n\t\t} );\n\n\t\t// Schedule the retry execution and store timer ID for cleanup.\n\t\tconst timerId = setTimeout( () => {\n\t\t\tretryTimers.delete( id );\n\t\t\tdispatch.executeRetry( id );\n\t\t}, delay );\n\t\tretryTimers.set( id, timerId );\n\n\t\tdispatch< ScheduleRetryAction >( {\n\t\t\ttype: Type.ScheduleRetry,\n\t\t\tid,\n\t\t\terror,\n\t\t\tretryCount: currentRetryCount,\n\t\t\tnextRetryTimestamp: Date.now() + delay,\n\t\t} );\n\t};\n}\n\n/**\n * Executes a scheduled retry for an item.\n *\n * This is called by the timer set in scheduleRetry.\n * It verifies the item is still in PendingRetry status before\n * proceeding with the retry.\n *\n * @param id Item ID.\n */\nexport function executeRetry( id: QueueItemId ) {\n\treturn async ( { select, dispatch }: ThunkArgs ) => {\n\t\tconst item = select.getItem( id );\n\n\t\t// Verify item exists and is still pending retry\n\t\t// (user may have manually cancelled or retried).\n\t\tif ( ! item || item.status !== ItemStatus.PendingRetry ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If the queue is paused, leave the item in PendingRetry without\n\t\t// mutating state. resumeQueue will re-trigger executeRetry for\n\t\t// items in this status when the queue resumes.\n\t\tif ( select.isPaused() ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Reset the item to Processing status and clear the error.\n\t\tdispatch< RetryItemAction >( {\n\t\t\ttype: Type.RetryItem,\n\t\t\tid,\n\t\t} );\n\n\t\t// Re-process the item.\n\t\tdispatch.processItem( id );\n\t};\n}\n"], "mappings": "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", "names": [] }