@wordpress/upload-media
Version:
Core media upload logic.
230 lines (229 loc) • 6.87 kB
JavaScript
// packages/upload-media/src/store/actions.ts
import { v4 as uuidv4 } from "uuid";
import { __ } from "@wordpress/i18n";
import { ItemStatus, OperationType, Type } from "./types.mjs";
import {
calculateRetryDelay,
clearRetryTimer,
retryTimers,
shouldRetryError
} from "./utils/retry.mjs";
import { maybeRecycleVipsWorker, vipsCancelOperations } from "./utils/index.mjs";
import { cancelGifToVideoOperations } from "./utils/video-conversion.mjs";
import { debug } from "./utils/debug-logger.mjs";
import { ErrorCode, UploadError } from "../upload-error.mjs";
import { validateMimeType } from "../validate-mime-type.mjs";
import { validateMimeTypeForUser } from "../validate-mime-type-for-user.mjs";
import { validateFileSize } from "../validate-file-size.mjs";
function addItems({
files,
onChange,
onSuccess,
onError,
onBatchSuccess,
additionalData,
allowedTypes
}) {
return async ({ select, dispatch }) => {
const batchId = uuidv4();
for (const file of files) {
try {
validateMimeType(file, allowedTypes);
validateMimeTypeForUser(
file,
select.getSettings().allowedMimeTypes
);
} catch (error) {
onError?.(error);
continue;
}
try {
validateFileSize(
file,
select.getSettings().maxUploadFileSize
);
} catch (error) {
onError?.(error);
continue;
}
dispatch.addItem({
file,
batchId,
onChange,
onSuccess,
onBatchSuccess,
onError,
additionalData
});
}
};
}
function cancelItem(id, error, silent = false) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
clearRetryTimer(id);
if (!silent && error && !item.parentId && !item.attachment?.id) {
const settings = select.getSettings();
const retrySettings = settings.retry;
if (retrySettings) {
const retryCount = item.retryCount ?? 0;
const maxRetries = retrySettings.maxRetryAttempts;
if (shouldRetryError(error, retryCount, maxRetries)) {
dispatch.scheduleRetry(id, error);
return;
}
}
}
item.abortController?.abort();
await vipsCancelOperations(id);
await cancelGifToVideoOperations(id);
if (!silent) {
const { onError } = item;
onError?.(error ?? new Error("Upload cancelled"));
if (!onError && error && !item.parentId) {
console.error("Upload cancelled", error);
}
} else {
debug(
`Item cancelled: ${item.file.name} (item ${id}): ${error instanceof Error ? error.message : error}`
);
}
const { currentOperation, parentId, batchId } = item;
dispatch({
type: Type.Cancel,
id,
error
});
dispatch.removeItem(id);
dispatch.revokeBlobUrls(id);
if (currentOperation === OperationType.ResizeCrop || currentOperation === OperationType.Rotate) {
for (const pending of select.getPendingImageProcessing()) {
dispatch.processItem(pending.id);
}
}
if (currentOperation === OperationType.Upload) {
for (const pending of select.getPendingUploads()) {
dispatch.processItem(pending.id);
}
}
if (currentOperation === OperationType.TranscodeGif) {
for (const pending of select.getPendingVideoProcessing()) {
dispatch.processItem(pending.id);
}
}
if (currentOperation === OperationType.ResizeCrop || currentOperation === OperationType.Rotate || currentOperation === OperationType.TranscodeImage) {
maybeRecycleVipsWorker(select.getActiveImageProcessingCount());
}
if (parentId) {
const parentItem = select.getItem(parentId);
if (parentItem) {
const isOptionalCompanion = item.additionalData?.image_size === "animated_video" || item.additionalData?.image_size === "animated_video_poster";
if (select.hasPendingItemsByParentId(parentId)) {
if (parentItem.operations && parentItem.operations.length > 0) {
dispatch.processItem(parentId);
}
} else if (parentItem.subSizes && parentItem.subSizes.length > 0 || isOptionalCompanion) {
if (parentItem.operations && parentItem.operations.length > 0) {
dispatch.processItem(parentId);
}
} else {
const parentAttachmentId = parentItem.attachment?.id;
const { mediaDelete } = select.getSettings();
if (parentAttachmentId && mediaDelete) {
mediaDelete(parentAttachmentId).catch(() => {
});
}
await dispatch.cancelItem(
parentId,
new UploadError({
code: error instanceof UploadError && error.code || ErrorCode.GENERAL,
message: error?.message || __("The image could not be uploaded."),
file: parentItem.file,
cause: error instanceof Error ? error : void 0
})
);
}
}
}
if (batchId && select.isBatchUploaded(batchId)) {
debug(`Batch completed: ${batchId}`);
item.onBatchSuccess?.();
}
};
}
function retryItem(id) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
if (!item.error) {
return;
}
dispatch({
type: Type.RetryItem,
id
});
dispatch.processItem(id);
};
}
function scheduleRetry(id, error) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item) {
return;
}
const settings = select.getSettings();
const retrySettings = settings.retry;
if (!retrySettings) {
return;
}
const currentRetryCount = item.retryCount ?? 0;
const delay = calculateRetryDelay({
attempt: currentRetryCount + 1,
initialDelay: retrySettings.initialRetryDelayMs,
maxDelay: retrySettings.maxRetryDelayMs,
multiplier: retrySettings.backoffMultiplier,
jitter: retrySettings.retryJitter
});
const timerId = setTimeout(() => {
retryTimers.delete(id);
dispatch.executeRetry(id);
}, delay);
retryTimers.set(id, timerId);
dispatch({
type: Type.ScheduleRetry,
id,
error,
retryCount: currentRetryCount,
nextRetryTimestamp: Date.now() + delay
});
};
}
function executeRetry(id) {
return async ({ select, dispatch }) => {
const item = select.getItem(id);
if (!item || item.status !== ItemStatus.PendingRetry) {
return;
}
if (select.isPaused()) {
return;
}
dispatch({
type: Type.RetryItem,
id
});
dispatch.processItem(id);
};
}
export {
addItems,
cancelItem,
executeRetry,
retryItem,
scheduleRetry
};
//# sourceMappingURL=actions.mjs.map