PluginProbe
Gutenberg / 23.4.0
Gutenberg v23.4.0
23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 7.4.0 All 402 releases
gutenberg / build / scripts / upload-media / index.js

index.js in Gutenberg 23.4.0, at build/scripts/upload-media/index.js

2,847 lines 87.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 "use strict";
2 var wp;
3 (wp ||= {}).uploadMedia = (() => {
4 var __create = Object.create;
5 var __defProp = Object.defineProperty;
6 var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7 var __getOwnPropNames = Object.getOwnPropertyNames;
8 var __getProtoOf = Object.getPrototypeOf;
9 var __hasOwnProp = Object.prototype.hasOwnProperty;
10 var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
11 get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
12 }) : x)(function(x) {
13 if (typeof require !== "undefined") return require.apply(this, arguments);
14 throw Error('Dynamic require of "' + x + '" is not supported');
15 });
16 var __commonJS = (cb, mod) => function __require2() {
17 return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
18 };
19 var __export = (target, all) => {
20 for (var name in all)
21 __defProp(target, name, { get: all[name], enumerable: true });
22 };
23 var __copyProps = (to, from, except, desc) => {
24 if (from && typeof from === "object" || typeof from === "function") {
25 for (let key of __getOwnPropNames(from))
26 if (!__hasOwnProp.call(to, key) && key !== except)
27 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
28 }
29 return to;
30 };
31 var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
32 // If the importer is in node compatibility mode or this is not an ESM
33 // file that has been converted to a CommonJS file using a Babel-
34 // compatible transform (i.e. "__esModule" has not been set), then set
35 // "default" to the CommonJS "module.exports" for node compatibility.
36 isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
37 mod
38 ));
39 var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
40
41 // package-external:@wordpress/data
42 var require_data = __commonJS({
43 "package-external:@wordpress/data"(exports, module) {
44 module.exports = window.wp.data;
45 }
46 });
47
48 // package-external:@wordpress/i18n
49 var require_i18n = __commonJS({
50 "package-external:@wordpress/i18n"(exports, module) {
51 module.exports = window.wp.i18n;
52 }
53 });
54
55 // package-external:@wordpress/url
56 var require_url = __commonJS({
57 "package-external:@wordpress/url"(exports, module) {
58 module.exports = window.wp.url;
59 }
60 });
61
62 // package-external:@wordpress/blob
63 var require_blob = __commonJS({
64 "package-external:@wordpress/blob"(exports, module) {
65 module.exports = window.wp.blob;
66 }
67 });
68
69 // package-external:@wordpress/private-apis
70 var require_private_apis = __commonJS({
71 "package-external:@wordpress/private-apis"(exports, module) {
72 module.exports = window.wp.privateApis;
73 }
74 });
75
76 // package-external:@wordpress/element
77 var require_element = __commonJS({
78 "package-external:@wordpress/element"(exports, module) {
79 module.exports = window.wp.element;
80 }
81 });
82
83 // package-external:@wordpress/compose
84 var require_compose = __commonJS({
85 "package-external:@wordpress/compose"(exports, module) {
86 module.exports = window.wp.compose;
87 }
88 });
89
90 // vendor-external:react/jsx-runtime
91 var require_jsx_runtime = __commonJS({
92 "vendor-external:react/jsx-runtime"(exports, module) {
93 module.exports = window.ReactJSXRuntime;
94 }
95 });
96
97 // packages/upload-media/build-module/index.mjs
98 var index_exports = {};
99 __export(index_exports, {
100 MediaUploadProvider: () => provider_default,
101 UploadError: () => UploadError,
102 clearFeatureDetectionCache: () => clearFeatureDetectionCache,
103 detectClientSideMediaSupport: () => detectClientSideMediaSupport,
104 isClientSideMediaSupported: () => isClientSideMediaSupported,
105 isHeicCanvasSupported: () => isHeicCanvasSupported,
106 store: () => store
107 });
108
109 // packages/upload-media/build-module/store/index.mjs
110 var import_data = __toESM(require_data(), 1);
111
112 // packages/upload-media/build-module/store/types.mjs
113 var Type = /* @__PURE__ */ ((Type2) => {
114 Type2["Unknown"] = "REDUX_UNKNOWN";
115 Type2["Add"] = "ADD_ITEM";
116 Type2["Prepare"] = "PREPARE_ITEM";
117 Type2["Cancel"] = "CANCEL_ITEM";
118 Type2["Remove"] = "REMOVE_ITEM";
119 Type2["RetryItem"] = "RETRY_ITEM";
120 Type2["ScheduleRetry"] = "SCHEDULE_RETRY";
121 Type2["PauseItem"] = "PAUSE_ITEM";
122 Type2["ResumeItem"] = "RESUME_ITEM";
123 Type2["PauseQueue"] = "PAUSE_QUEUE";
124 Type2["ResumeQueue"] = "RESUME_QUEUE";
125 Type2["OperationStart"] = "OPERATION_START";
126 Type2["OperationFinish"] = "OPERATION_FINISH";
127 Type2["AddOperations"] = "ADD_OPERATIONS";
128 Type2["CacheBlobUrl"] = "CACHE_BLOB_URL";
129 Type2["RevokeBlobUrls"] = "REVOKE_BLOB_URLS";
130 Type2["UpdateProgress"] = "UPDATE_PROGRESS";
131 Type2["AccumulateSubSize"] = "ACCUMULATE_SUB_SIZE";
132 Type2["UpdateSettings"] = "UPDATE_SETTINGS";
133 return Type2;
134 })(Type || {});
135 var ItemStatus = /* @__PURE__ */ ((ItemStatus2) => {
136 ItemStatus2["Queued"] = "QUEUED";
137 ItemStatus2["Processing"] = "PROCESSING";
138 ItemStatus2["Paused"] = "PAUSED";
139 ItemStatus2["PendingRetry"] = "PENDING_RETRY";
140 ItemStatus2["Uploaded"] = "UPLOADED";
141 ItemStatus2["Error"] = "ERROR";
142 return ItemStatus2;
143 })(ItemStatus || {});
144 var OperationType = /* @__PURE__ */ ((OperationType2) => {
145 OperationType2["Prepare"] = "PREPARE";
146 OperationType2["Upload"] = "UPLOAD";
147 OperationType2["ResizeCrop"] = "RESIZE_CROP";
148 OperationType2["Rotate"] = "ROTATE";
149 OperationType2["TranscodeImage"] = "TRANSCODE_IMAGE";
150 OperationType2["ThumbnailGeneration"] = "THUMBNAIL_GENERATION";
151 OperationType2["Finalize"] = "FINALIZE";
152 OperationType2["DetectUltraHdr"] = "DETECT_ULTRAHDR";
153 return OperationType2;
154 })(OperationType || {});
155
156 // packages/upload-media/build-module/store/constants.mjs
157 var STORE_NAME = "core/upload-media";
158 var DEFAULT_MAX_CONCURRENT_UPLOADS = 5;
159 var DEFAULT_MAX_CONCURRENT_IMAGE_PROCESSING = 2;
160 var DEFAULT_RETRY_SETTINGS = {
161 maxRetryAttempts: 3,
162 initialRetryDelayMs: 1e3,
163 maxRetryDelayMs: 3e4,
164 backoffMultiplier: 2,
165 retryJitter: 0.1
166 };
167 var CLIENT_SIDE_SUPPORTED_MIME_TYPES = [
168 "image/jpeg",
169 "image/png",
170 "image/gif",
171 "image/webp",
172 "image/avif"
173 ];
174 var HEIC_MIME_TYPES = [
175 "image/heic",
176 "image/heif"
177 ];
178
179 // packages/upload-media/build-module/store/reducer.mjs
180 var noop = () => {
181 };
182 var DEFAULT_STATE = {
183 queue: [],
184 queueStatus: "active",
185 blobUrls: {},
186 settings: {
187 mediaUpload: noop,
188 maxConcurrentUploads: DEFAULT_MAX_CONCURRENT_UPLOADS,
189 maxConcurrentImageProcessing: DEFAULT_MAX_CONCURRENT_IMAGE_PROCESSING,
190 retry: { ...DEFAULT_RETRY_SETTINGS }
191 }
192 };
193 function reducer(state = DEFAULT_STATE, action = { type: Type.Unknown }) {
194 switch (action.type) {
195 case Type.PauseQueue: {
196 return {
197 ...state,
198 queueStatus: "paused"
199 };
200 }
201 case Type.ResumeQueue: {
202 return {
203 ...state,
204 queueStatus: "active"
205 };
206 }
207 case Type.PauseItem:
208 return {
209 ...state,
210 queue: state.queue.map(
211 (item) => item.id === action.id ? {
212 ...item,
213 status: ItemStatus.Paused
214 } : item
215 )
216 };
217 case Type.ResumeItem:
218 return {
219 ...state,
220 queue: state.queue.map(
221 (item) => item.id === action.id ? {
222 ...item,
223 status: ItemStatus.Processing
224 } : item
225 )
226 };
227 case Type.Add:
228 return {
229 ...state,
230 queue: [...state.queue, action.item]
231 };
232 case Type.Cancel:
233 return {
234 ...state,
235 queue: state.queue.map(
236 (item) => item.id === action.id ? {
237 ...item,
238 error: action.error
239 } : item
240 )
241 };
242 case Type.RetryItem:
243 return {
244 ...state,
245 queue: state.queue.map(
246 (item) => item.id === action.id ? {
247 ...item,
248 status: ItemStatus.Processing,
249 error: void 0,
250 retryCount: (item.retryCount ?? 0) + 1,
251 abortController: new AbortController()
252 } : item
253 )
254 };
255 case Type.ScheduleRetry:
256 return {
257 ...state,
258 queue: state.queue.map(
259 (item) => item.id === action.id ? {
260 ...item,
261 status: ItemStatus.PendingRetry,
262 error: action.error,
263 retryCount: action.retryCount,
264 nextRetryTimestamp: action.nextRetryTimestamp
265 } : item
266 )
267 };
268 case Type.Remove:
269 return {
270 ...state,
271 queue: state.queue.filter((item) => item.id !== action.id)
272 };
273 case Type.OperationStart: {
274 return {
275 ...state,
276 queue: state.queue.map(
277 (item) => item.id === action.id ? {
278 ...item,
279 currentOperation: action.operation
280 } : item
281 )
282 };
283 }
284 case Type.AddOperations:
285 return {
286 ...state,
287 queue: state.queue.map((item) => {
288 if (item.id !== action.id) {
289 return item;
290 }
291 return {
292 ...item,
293 operations: [
294 ...item.operations || [],
295 ...action.operations
296 ]
297 };
298 })
299 };
300 case Type.OperationFinish:
301 return {
302 ...state,
303 queue: state.queue.map((item) => {
304 if (item.id !== action.id) {
305 return item;
306 }
307 const operations = item.operations ? item.operations.slice(1) : [];
308 const attachment = item.attachment || action.item.attachment ? {
309 ...item.attachment,
310 ...action.item.attachment
311 } : void 0;
312 return {
313 ...item,
314 currentOperation: void 0,
315 operations,
316 ...action.item,
317 attachment,
318 additionalData: {
319 ...item.additionalData,
320 ...action.item.additionalData
321 }
322 };
323 })
324 };
325 case Type.CacheBlobUrl: {
326 const blobUrls = state.blobUrls[action.id] || [];
327 return {
328 ...state,
329 blobUrls: {
330 ...state.blobUrls,
331 [action.id]: [...blobUrls, action.blobUrl]
332 }
333 };
334 }
335 case Type.RevokeBlobUrls: {
336 const newBlobUrls = { ...state.blobUrls };
337 delete newBlobUrls[action.id];
338 return {
339 ...state,
340 blobUrls: newBlobUrls
341 };
342 }
343 case Type.UpdateProgress:
344 return {
345 ...state,
346 queue: state.queue.map(
347 (item) => item.id === action.id ? {
348 ...item,
349 progress: action.progress
350 } : item
351 )
352 };
353 case Type.AccumulateSubSize:
354 return {
355 ...state,
356 queue: state.queue.map(
357 (item) => item.id === action.id ? {
358 ...item,
359 subSizes: [
360 ...item.subSizes || [],
361 action.subSize
362 ]
363 } : item
364 )
365 };
366 case Type.UpdateSettings: {
367 return {
368 ...state,
369 settings: {
370 ...state.settings,
371 ...action.settings
372 }
373 };
374 }
375 }
376 return state;
377 }
378 var reducer_default = reducer;
379
380 // packages/upload-media/build-module/store/selectors.mjs
381 var selectors_exports = {};
382 __export(selectors_exports, {
383 getItems: () => getItems,
384 getSettings: () => getSettings,
385 isUploading: () => isUploading,
386 isUploadingById: () => isUploadingById,
387 isUploadingByUrl: () => isUploadingByUrl
388 });
389 function getItems(state) {
390 return state.queue;
391 }
392 function isUploading(state) {
393 return state.queue.length >= 1;
394 }
395 function isUploadingByUrl(state, url) {
396 return state.queue.some(
397 (item) => item.attachment?.url === url || item.sourceUrl === url
398 );
399 }
400 function isUploadingById(state, attachmentId) {
401 return state.queue.some(
402 (item) => item.attachment?.id === attachmentId || item.sourceAttachmentId === attachmentId
403 );
404 }
405 function getSettings(state) {
406 return state.settings;
407 }
408
409 // packages/upload-media/build-module/store/private-selectors.mjs
410 var private_selectors_exports = {};
411 __export(private_selectors_exports, {
412 getActiveImageProcessingCount: () => getActiveImageProcessingCount,
413 getActiveUploadCount: () => getActiveUploadCount,
414 getAllItems: () => getAllItems,
415 getBlobUrls: () => getBlobUrls,
416 getFailedItems: () => getFailedItems,
417 getItem: () => getItem,
418 getItemProgress: () => getItemProgress,
419 getPendingImageProcessing: () => getPendingImageProcessing,
420 getPendingUploads: () => getPendingUploads,
421 hasPendingItemsByParentId: () => hasPendingItemsByParentId,
422 isBatchUploaded: () => isBatchUploaded,
423 isPaused: () => isPaused
424 });
425 function getAllItems(state) {
426 return state.queue;
427 }
428 function getItem(state, id) {
429 return state.queue.find((item) => item.id === id);
430 }
431 function isBatchUploaded(state, batchId) {
432 const batchItems = state.queue.filter(
433 (item) => batchId === item.batchId
434 );
435 return batchItems.length === 0;
436 }
437 function isPaused(state) {
438 return state.queueStatus === "paused";
439 }
440 function getBlobUrls(state, id) {
441 return state.blobUrls[id] || [];
442 }
443 function getActiveUploadCount(state) {
444 return state.queue.filter(
445 (item) => item.currentOperation === OperationType.Upload
446 ).length;
447 }
448 function getPendingUploads(state) {
449 return state.queue.filter((item) => {
450 const nextOperation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0];
451 return nextOperation === OperationType.Upload && item.currentOperation !== OperationType.Upload;
452 });
453 }
454 function getActiveImageProcessingCount(state) {
455 return state.queue.filter(
456 (item) => item.currentOperation === OperationType.ResizeCrop || item.currentOperation === OperationType.Rotate
457 ).length;
458 }
459 function getPendingImageProcessing(state) {
460 return state.queue.filter((item) => {
461 const nextOperation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0];
462 return (nextOperation === OperationType.ResizeCrop || nextOperation === OperationType.Rotate) && item.currentOperation !== OperationType.ResizeCrop && item.currentOperation !== OperationType.Rotate;
463 });
464 }
465 function getFailedItems(state) {
466 return state.queue.filter((item) => item.error !== void 0);
467 }
468 function hasPendingItemsByParentId(state, parentId) {
469 return state.queue.some((item) => item.parentId === parentId);
470 }
471 function getItemProgress(state, id) {
472 const item = state.queue.find((i) => i.id === id);
473 return item?.progress;
474 }
475
476 // packages/upload-media/build-module/store/actions.mjs
477 var actions_exports = {};
478 __export(actions_exports, {
479 addItems: () => addItems,
480 cancelItem: () => cancelItem,
481 executeRetry: () => executeRetry,
482 retryItem: () => retryItem,
483 scheduleRetry: () => scheduleRetry
484 });
485
486 // node_modules/uuid/dist/stringify.js
487 var byteToHex = [];
488 for (let i = 0; i < 256; ++i) {
489 byteToHex.push((i + 256).toString(16).slice(1));
490 }
491 function unsafeStringify(arr, offset = 0) {
492 return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
493 }
494
495 // node_modules/uuid/dist/rng.js
496 var rnds8 = new Uint8Array(16);
497 function rng() {
498 return crypto.getRandomValues(rnds8);
499 }
500
501 // node_modules/uuid/dist/v4.js
502 function v4(options, buf, offset) {
503 if (!buf && !options && crypto.randomUUID) {
504 return crypto.randomUUID();
505 }
506 return _v4(options, buf, offset);
507 }
508 function _v4(options, buf, offset) {
509 options = options || {};
510 const rnds = options.random ?? options.rng?.() ?? rng();
511 if (rnds.length < 16) {
512 throw new Error("Random bytes length must be >= 16");
513 }
514 rnds[6] = rnds[6] & 15 | 64;
515 rnds[8] = rnds[8] & 63 | 128;
516 if (buf) {
517 offset = offset || 0;
518 if (offset < 0 || offset + 16 > buf.length) {
519 throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
520 }
521 for (let i = 0; i < 16; ++i) {
522 buf[offset + i] = rnds[i];
523 }
524 return buf;
525 }
526 return unsafeStringify(rnds);
527 }
528 var v4_default = v4;
529
530 // packages/upload-media/build-module/store/actions.mjs
531 var import_i18n5 = __toESM(require_i18n(), 1);
532
533 // packages/upload-media/build-module/store/utils/retry.mjs
534 function calculateRetryDelay(options) {
535 const { attempt, initialDelay, maxDelay, multiplier, jitter } = options;
536 const exponentialDelay = initialDelay * Math.pow(multiplier, attempt - 1);
537 const cappedDelay = Math.min(exponentialDelay, maxDelay);
538 const jitterFactor = 1 + (Math.random() * 2 - 1) * jitter;
539 return Math.floor(cappedDelay * jitterFactor);
540 }
541 var RETRYABLE_MESSAGE_PATTERNS = [
542 /network/i,
543 /timeout/i,
544 /ECONNRESET/i,
545 /fetch failed/i,
546 /connection/i,
547 /socket/i,
548 /ETIMEDOUT/i,
549 /ENOTFOUND/i,
550 /Could not get a valid response/i,
551 /Failed to fetch/i,
552 /Load failed/i
553 ];
554 function shouldRetryError(error, retryCount, maxRetries) {
555 if (retryCount >= maxRetries) {
556 return false;
557 }
558 const message = typeof error === "string" ? error : error?.message || "";
559 return RETRYABLE_MESSAGE_PATTERNS.some(
560 (pattern) => pattern.test(message)
561 );
562 }
563 var retryTimers = /* @__PURE__ */ new Map();
564 function clearRetryTimer(id) {
565 const pendingTimer = retryTimers.get(id);
566 if (pendingTimer !== void 0) {
567 clearTimeout(pendingTimer);
568 retryTimers.delete(id);
569 }
570 }
571
572 // packages/upload-media/build-module/image-file.mjs
573 var ImageFile = class extends File {
574 width = 0;
575 height = 0;
576 originalWidth = 0;
577 originalHeight = 0;
578 get wasResized() {
579 return (this.originalWidth || 0) > this.width || (this.originalHeight || 0) > this.height;
580 }
581 constructor(file, width, height, originalWidth, originalHeight) {
582 super([file], file.name, {
583 type: file.type,
584 lastModified: file.lastModified
585 });
586 this.width = width;
587 this.height = height;
588 this.originalWidth = originalWidth;
589 this.originalHeight = originalHeight;
590 }
591 };
592
593 // packages/upload-media/build-module/utils.mjs
594 var import_url = __toESM(require_url(), 1);
595 var import_i18n = __toESM(require_i18n(), 1);
596 function convertBlobToFile(fileOrBlob) {
597 if (fileOrBlob instanceof File) {
598 return fileOrBlob;
599 }
600 if ("name" in fileOrBlob && typeof fileOrBlob.name === "string") {
601 return new File([fileOrBlob], fileOrBlob.name, {
602 type: fileOrBlob.type,
603 lastModified: fileOrBlob.lastModified
604 });
605 }
606 const ext = fileOrBlob.type.split("/")[1];
607 const mediaType = "application/pdf" === fileOrBlob.type ? "document" : fileOrBlob.type.split("/")[0];
608 return new File([fileOrBlob], `${mediaType}.${ext}`, {
609 type: fileOrBlob.type
610 });
611 }
612 function renameFile(file, name) {
613 return new File([file], name, {
614 type: file.type,
615 lastModified: file.lastModified
616 });
617 }
618 function cloneFile(file) {
619 return renameFile(file, file.name);
620 }
621 function getFileBasename(name) {
622 return name.includes(".") ? name.split(".").slice(0, -1).join(".") : name;
623 }
624
625 // packages/upload-media/build-module/store/utils/index.mjs
626 var vipsModulePromise;
627 var vipsModule;
628 function loadVipsModule() {
629 if (!vipsModulePromise) {
630 vipsModulePromise = import("@wordpress/vips/worker").then(
631 (mod) => {
632 vipsModule = mod;
633 return mod;
634 }
635 );
636 }
637 return vipsModulePromise;
638 }
639 async function vipsConvertImageFormat(id, file, type, quality, interlaced) {
640 const { vipsConvertImageFormat: convertImageFormat } = await loadVipsModule();
641 const buffer = await convertImageFormat(
642 id,
643 await file.arrayBuffer(),
644 file.type,
645 type,
646 quality,
647 interlaced
648 );
649 const ext = type.split("/")[1];
650 const fileName = `${getFileBasename(file.name)}.${ext}`;
651 return new File([new Blob([buffer])], fileName, {
652 type
653 });
654 }
655 async function vipsHasTransparency(url) {
656 const { vipsHasTransparency: hasTransparency } = await loadVipsModule();
657 const response = await fetch(url);
658 if (!response.ok) {
659 throw new Error(`Failed to fetch image: ${response.status}`);
660 }
661 return hasTransparency(await response.arrayBuffer());
662 }
663 async function vipsGetUltraHdrInfo(buffer) {
664 const { vipsGetUltraHdrInfo: getUltraHdrInfo } = await loadVipsModule();
665 return getUltraHdrInfo(buffer);
666 }
667 async function vipsResizeImage(id, file, resize, smartCrop, addSuffix, signal, scaledSuffix, quality) {
668 if (signal?.aborted) {
669 throw new Error("Operation aborted");
670 }
671 const { vipsResizeImage: resizeImage } = await loadVipsModule();
672 const { buffer, width, height, originalWidth, originalHeight } = await resizeImage(
673 id,
674 await file.arrayBuffer(),
675 file.type,
676 resize,
677 smartCrop,
678 quality
679 );
680 let fileName = file.name;
681 const wasResized = originalWidth > width || originalHeight > height;
682 if (wasResized) {
683 const basename = getFileBasename(file.name);
684 if (scaledSuffix) {
685 fileName = file.name.replace(basename, `${basename}-scaled`);
686 } else if (addSuffix) {
687 fileName = file.name.replace(
688 basename,
689 `${basename}-${width}x${height}`
690 );
691 }
692 }
693 const resultFile = new ImageFile(
694 new File(
695 [new Blob([buffer], { type: file.type })],
696 fileName,
697 {
698 type: file.type
699 }
700 ),
701 width,
702 height,
703 originalWidth,
704 originalHeight
705 );
706 return resultFile;
707 }
708 async function vipsRotateImage(id, file, orientation, signal) {
709 if (signal?.aborted) {
710 throw new Error("Operation aborted");
711 }
712 if (orientation === 1) {
713 return file;
714 }
715 const { vipsRotateImage: rotateImage } = await loadVipsModule();
716 const { buffer, width, height } = await rotateImage(
717 id,
718 await file.arrayBuffer(),
719 file.type,
720 orientation
721 );
722 const basename = getFileBasename(file.name);
723 const fileName = file.name.replace(basename, `${basename}-rotated`);
724 const resultFile = new ImageFile(
725 new File(
726 [new Blob([buffer], { type: file.type })],
727 fileName,
728 {
729 type: file.type
730 }
731 ),
732 width,
733 height
734 );
735 return resultFile;
736 }
737 async function vipsCancelOperations(id) {
738 if (!vipsModule) {
739 return false;
740 }
741 return vipsModule.vipsCancelOperations(id);
742 }
743 function terminateVipsWorker() {
744 if (vipsModule) {
745 vipsModule.terminateVipsWorker();
746 }
747 }
748 var completedVipsOperations = 0;
749 var MAX_VIPS_OPS_BEFORE_RECYCLE = 50;
750 function maybeRecycleVipsWorker(activeImageProcessingCount) {
751 completedVipsOperations++;
752 if (completedVipsOperations >= MAX_VIPS_OPS_BEFORE_RECYCLE && activeImageProcessingCount === 0) {
753 terminateVipsWorker();
754 completedVipsOperations = 0;
755 }
756 }
757
758 // packages/upload-media/build-module/upload-error.mjs
759 var UploadError = class extends Error {
760 code;
761 file;
762 constructor({ code, message, file, cause }) {
763 super(message, { cause });
764 Object.setPrototypeOf(this, new.target.prototype);
765 this.code = code;
766 this.file = file;
767 }
768 };
769
770 // packages/upload-media/build-module/validate-mime-type.mjs
771 var import_i18n2 = __toESM(require_i18n(), 1);
772 function validateMimeType(file, allowedTypes) {
773 if (!allowedTypes) {
774 return;
775 }
776 const isAllowedType = allowedTypes.some((allowedType) => {
777 if (allowedType.includes("/")) {
778 return allowedType === file.type;
779 }
780 return file.type.startsWith(`${allowedType}/`);
781 });
782 if (file.type && !isAllowedType) {
783 throw new UploadError({
784 code: "MIME_TYPE_NOT_SUPPORTED",
785 message: (0, import_i18n2.sprintf)(
786 // translators: %s: file name.
787 (0, import_i18n2.__)("%s: Sorry, this file type is not supported here."),
788 file.name
789 ),
790 file
791 });
792 }
793 }
794
795 // packages/upload-media/build-module/validate-mime-type-for-user.mjs
796 var import_i18n3 = __toESM(require_i18n(), 1);
797
798 // packages/upload-media/build-module/get-mime-types-array.mjs
799 function getMimeTypesArray(wpMimeTypesObject) {
800 if (!wpMimeTypesObject) {
801 return null;
802 }
803 return Object.entries(wpMimeTypesObject).flatMap(
804 ([extensionsString, mime]) => {
805 const [type] = mime.split("/");
806 const extensions = extensionsString.split("|");
807 return [
808 mime,
809 ...extensions.map(
810 (extension) => `${type}/${extension}`
811 )
812 ];
813 }
814 );
815 }
816
817 // packages/upload-media/build-module/validate-mime-type-for-user.mjs
818 function validateMimeTypeForUser(file, wpAllowedMimeTypes) {
819 const allowedMimeTypesForUser = getMimeTypesArray(wpAllowedMimeTypes);
820 if (!allowedMimeTypesForUser) {
821 return;
822 }
823 const isAllowedMimeTypeForUser = allowedMimeTypesForUser.includes(
824 file.type
825 );
826 if (file.type && !isAllowedMimeTypeForUser) {
827 throw new UploadError({
828 code: "MIME_TYPE_NOT_ALLOWED_FOR_USER",
829 message: (0, import_i18n3.sprintf)(
830 // translators: %s: file name.
831 (0, import_i18n3.__)(
832 "%s: Sorry, you are not allowed to upload this file type."
833 ),
834 file.name
835 ),
836 file
837 });
838 }
839 }
840
841 // packages/upload-media/build-module/validate-file-size.mjs
842 var import_i18n4 = __toESM(require_i18n(), 1);
843 function validateFileSize(file, maxUploadFileSize) {
844 if (file.size <= 0) {
845 throw new UploadError({
846 code: "EMPTY_FILE",
847 message: (0, import_i18n4.sprintf)(
848 // translators: %s: file name.
849 (0, import_i18n4.__)("%s: This file is empty."),
850 file.name
851 ),
852 file
853 });
854 }
855 if (maxUploadFileSize && file.size > maxUploadFileSize) {
856 throw new UploadError({
857 code: "SIZE_ABOVE_LIMIT",
858 message: (0, import_i18n4.sprintf)(
859 // translators: %s: file name.
860 (0, import_i18n4.__)(
861 "%s: This file exceeds the maximum upload size for this site."
862 ),
863 file.name
864 ),
865 file
866 });
867 }
868 }
869
870 // packages/upload-media/build-module/store/actions.mjs
871 function addItems({
872 files,
873 onChange,
874 onSuccess,
875 onError,
876 onBatchSuccess,
877 additionalData,
878 allowedTypes
879 }) {
880 return async ({ select: select2, dispatch }) => {
881 const batchId = v4_default();
882 for (const file of files) {
883 try {
884 validateMimeType(file, allowedTypes);
885 validateMimeTypeForUser(
886 file,
887 select2.getSettings().allowedMimeTypes
888 );
889 } catch (error) {
890 onError?.(error);
891 continue;
892 }
893 try {
894 validateFileSize(
895 file,
896 select2.getSettings().maxUploadFileSize
897 );
898 } catch (error) {
899 onError?.(error);
900 continue;
901 }
902 dispatch.addItem({
903 file,
904 batchId,
905 onChange,
906 onSuccess,
907 onBatchSuccess,
908 onError,
909 additionalData
910 });
911 }
912 };
913 }
914 function cancelItem(id, error, silent = false) {
915 return async ({ select: select2, dispatch }) => {
916 const item = select2.getItem(id);
917 if (!item) {
918 return;
919 }
920 clearRetryTimer(id);
921 if (!silent && error && !item.parentId && !item.attachment?.id) {
922 const settings = select2.getSettings();
923 const retrySettings = settings.retry;
924 if (retrySettings) {
925 const retryCount = item.retryCount ?? 0;
926 const maxRetries = retrySettings.maxRetryAttempts;
927 if (shouldRetryError(error, retryCount, maxRetries)) {
928 dispatch.scheduleRetry(id, error);
929 return;
930 }
931 }
932 }
933 item.abortController?.abort();
934 await vipsCancelOperations(id);
935 if (!silent) {
936 const { onError } = item;
937 onError?.(error ?? new Error("Upload cancelled"));
938 if (!onError && error && !item.parentId) {
939 console.error("Upload cancelled", error);
940 }
941 }
942 const { currentOperation, parentId, batchId } = item;
943 dispatch({
944 type: Type.Cancel,
945 id,
946 error
947 });
948 dispatch.removeItem(id);
949 dispatch.revokeBlobUrls(id);
950 if (currentOperation === OperationType.ResizeCrop || currentOperation === OperationType.Rotate) {
951 for (const pending of select2.getPendingImageProcessing()) {
952 dispatch.processItem(pending.id);
953 }
954 }
955 if (currentOperation === OperationType.Upload) {
956 for (const pending of select2.getPendingUploads()) {
957 dispatch.processItem(pending.id);
958 }
959 }
960 if (currentOperation === OperationType.ResizeCrop || currentOperation === OperationType.Rotate || currentOperation === OperationType.TranscodeImage) {
961 maybeRecycleVipsWorker(select2.getActiveImageProcessingCount());
962 }
963 if (parentId) {
964 const parentItem = select2.getItem(parentId);
965 if (parentItem) {
966 if (select2.hasPendingItemsByParentId(parentId)) {
967 if (parentItem.operations && parentItem.operations.length > 0) {
968 dispatch.processItem(parentId);
969 }
970 } else if (parentItem.subSizes && parentItem.subSizes.length > 0) {
971 if (parentItem.operations && parentItem.operations.length > 0) {
972 dispatch.processItem(parentId);
973 }
974 } else {
975 const parentAttachmentId = parentItem.attachment?.id;
976 const { mediaDelete } = select2.getSettings();
977 if (parentAttachmentId && mediaDelete) {
978 mediaDelete(parentAttachmentId).catch(() => {
979 });
980 }
981 dispatch.cancelItem(
982 parentId,
983 new UploadError({
984 code: error instanceof UploadError && error.code || "UPLOAD_ERROR",
985 message: error?.message || (0, import_i18n5.__)("The image could not be uploaded."),
986 file: parentItem.file,
987 cause: error instanceof Error ? error : void 0
988 })
989 );
990 }
991 }
992 }
993 if (batchId && select2.isBatchUploaded(batchId)) {
994 item.onBatchSuccess?.();
995 }
996 };
997 }
998 function retryItem(id) {
999 return async ({ select: select2, dispatch }) => {
1000 const item = select2.getItem(id);
1001 if (!item) {
1002 return;
1003 }
1004 if (!item.error) {
1005 return;
1006 }
1007 dispatch({
1008 type: Type.RetryItem,
1009 id
1010 });
1011 dispatch.processItem(id);
1012 };
1013 }
1014 function scheduleRetry(id, error) {
1015 return async ({ select: select2, dispatch }) => {
1016 const item = select2.getItem(id);
1017 if (!item) {
1018 return;
1019 }
1020 const settings = select2.getSettings();
1021 const retrySettings = settings.retry;
1022 if (!retrySettings) {
1023 return;
1024 }
1025 const currentRetryCount = item.retryCount ?? 0;
1026 const delay = calculateRetryDelay({
1027 attempt: currentRetryCount + 1,
1028 initialDelay: retrySettings.initialRetryDelayMs,
1029 maxDelay: retrySettings.maxRetryDelayMs,
1030 multiplier: retrySettings.backoffMultiplier,
1031 jitter: retrySettings.retryJitter
1032 });
1033 const timerId = setTimeout(() => {
1034 retryTimers.delete(id);
1035 dispatch.executeRetry(id);
1036 }, delay);
1037 retryTimers.set(id, timerId);
1038 dispatch({
1039 type: Type.ScheduleRetry,
1040 id,
1041 error,
1042 retryCount: currentRetryCount,
1043 nextRetryTimestamp: Date.now() + delay
1044 });
1045 };
1046 }
1047 function executeRetry(id) {
1048 return async ({ select: select2, dispatch }) => {
1049 const item = select2.getItem(id);
1050 if (!item || item.status !== ItemStatus.PendingRetry) {
1051 return;
1052 }
1053 if (select2.isPaused()) {
1054 return;
1055 }
1056 dispatch({
1057 type: Type.RetryItem,
1058 id
1059 });
1060 dispatch.processItem(id);
1061 };
1062 }
1063
1064 // packages/upload-media/build-module/store/private-actions.mjs
1065 var private_actions_exports = {};
1066 __export(private_actions_exports, {
1067 addItem: () => addItem,
1068 addSideloadItem: () => addSideloadItem,
1069 detectUltraHdr: () => detectUltraHdr,
1070 finalizeItem: () => finalizeItem,
1071 finishOperation: () => finishOperation,
1072 generateThumbnails: () => generateThumbnails,
1073 getTranscodeImageOperation: () => getTranscodeImageOperation,
1074 pauseItem: () => pauseItem,
1075 pauseQueue: () => pauseQueue,
1076 prepareItem: () => prepareItem,
1077 processItem: () => processItem,
1078 removeItem: () => removeItem,
1079 resizeCropItem: () => resizeCropItem,
1080 resumeQueue: () => resumeQueue,
1081 revokeBlobUrls: () => revokeBlobUrls,
1082 rotateItem: () => rotateItem,
1083 sideloadItem: () => sideloadItem,
1084 transcodeImageItem: () => transcodeImageItem,
1085 updateItemProgress: () => updateItemProgress,
1086 updateSettings: () => updateSettings,
1087 uploadItem: () => uploadItem
1088 });
1089 var import_blob = __toESM(require_blob(), 1);
1090 var import_i18n6 = __toESM(require_i18n(), 1);
1091
1092 // packages/upload-media/build-module/heic-parser.mjs
1093 var Reader = class {
1094 view;
1095 buffer;
1096 pos;
1097 constructor(buffer, offset = 0) {
1098 this.buffer = buffer;
1099 this.view = new DataView(buffer);
1100 this.pos = offset;
1101 }
1102 u8() {
1103 const v = this.view.getUint8(this.pos);
1104 this.pos += 1;
1105 return v;
1106 }
1107 u16() {
1108 const v = this.view.getUint16(this.pos);
1109 this.pos += 2;
1110 return v;
1111 }
1112 u32() {
1113 const v = this.view.getUint32(this.pos);
1114 this.pos += 4;
1115 return v;
1116 }
1117 u64() {
1118 const hi = this.view.getUint32(this.pos);
1119 const lo = this.view.getUint32(this.pos + 4);
1120 this.pos += 8;
1121 return hi * 4294967296 + lo;
1122 }
1123 /**
1124 * Read a variable-width unsigned integer (0, 4 or 8 bytes).
1125 *
1126 * @param size Byte width to read (0, 4, or 8).
1127 */
1128 uN(size) {
1129 if (size === 0) {
1130 return 0;
1131 }
1132 if (size === 4) {
1133 return this.u32();
1134 }
1135 if (size === 8) {
1136 return this.u64();
1137 }
1138 throw new Error(`Unsupported uint size: ${size}`);
1139 }
1140 str(len) {
1141 let s = "";
1142 for (let i = 0; i < len; i++) {
1143 s += String.fromCharCode(this.view.getUint8(this.pos + i));
1144 }
1145 this.pos += len;
1146 return s;
1147 }
1148 bytes(len) {
1149 const b = new Uint8Array(this.buffer, this.pos, len);
1150 this.pos += len;
1151 return new Uint8Array(b);
1152 }
1153 };
1154 function readBox(r) {
1155 if (r.pos + 8 > r.view.byteLength) {
1156 return null;
1157 }
1158 const offset = r.pos;
1159 let size = r.u32();
1160 const type = r.str(4);
1161 let headerSize = 8;
1162 if (size === 1) {
1163 size = r.u64();
1164 headerSize = 16;
1165 } else if (size === 0) {
1166 size = r.view.byteLength - offset;
1167 }
1168 return { type, offset, size, headerSize };
1169 }
1170 function findBoxes(r, start, end) {
1171 const boxes = [];
1172 r.pos = start;
1173 while (r.pos < end) {
1174 const box = readBox(r);
1175 if (!box || box.size < 8) {
1176 break;
1177 }
1178 boxes.push(box);
1179 r.pos = box.offset + box.size;
1180 }
1181 return boxes;
1182 }
1183 function findBox(r, start, end, type) {
1184 r.pos = start;
1185 while (r.pos < end) {
1186 const box = readBox(r);
1187 if (!box || box.size < 8) {
1188 break;
1189 }
1190 if (box.type === type) {
1191 return box;
1192 }
1193 r.pos = box.offset + box.size;
1194 }
1195 return void 0;
1196 }
1197 function parsePitm(r, box) {
1198 r.pos = box.offset + box.headerSize;
1199 const version = r.u8();
1200 r.pos += 3;
1201 return version === 0 ? r.u16() : r.u32();
1202 }
1203 function parseIloc(r, box) {
1204 r.pos = box.offset + box.headerSize;
1205 const version = r.u8();
1206 r.pos += 3;
1207 const byte1 = r.u8();
1208 const offsetSize = byte1 >> 4 & 15;
1209 const lengthSize = byte1 & 15;
1210 const byte2 = r.u8();
1211 const baseOffsetSize = byte2 >> 4 & 15;
1212 const indexSize = version >= 1 ? byte2 & 15 : 0;
1213 const itemCount = version < 2 ? r.u16() : r.u32();
1214 const items = /* @__PURE__ */ new Map();
1215 for (let i = 0; i < itemCount; i++) {
1216 const itemId = version < 2 ? r.u16() : r.u32();
1217 let constructionMethod = 0;
1218 if (version === 1 || version === 2) {
1219 const cm = r.u16();
1220 constructionMethod = cm & 15;
1221 }
1222 r.u16();
1223 const baseOffset = r.uN(baseOffsetSize);
1224 const extentCount = r.u16();
1225 const extents = [];
1226 for (let j = 0; j < extentCount; j++) {
1227 if (version >= 1) {
1228 r.uN(indexSize);
1229 }
1230 const extOffset = r.uN(offsetSize);
1231 const extLength = r.uN(lengthSize);
1232 extents.push({
1233 offset: baseOffset + extOffset,
1234 length: extLength
1235 });
1236 }
1237 items.set(itemId, { constructionMethod, extents });
1238 }
1239 return items;
1240 }
1241 function parseIpma(r, box) {
1242 r.pos = box.offset + box.headerSize;
1243 const vf = r.u32();
1244 const version = vf >>> 24;
1245 const flags = vf & 16777215;
1246 const largeIndex = (flags & 1) !== 0;
1247 const entryCount = r.u32();
1248 const associations = /* @__PURE__ */ new Map();
1249 for (let i = 0; i < entryCount; i++) {
1250 const itemId = version < 1 ? r.u16() : r.u32();
1251 const assocCount = r.u8();
1252 const indices = [];
1253 for (let j = 0; j < assocCount; j++) {
1254 if (largeIndex) {
1255 indices.push(r.u16() & 32767);
1256 } else {
1257 indices.push(r.u8() & 127);
1258 }
1259 }
1260 associations.set(itemId, indices);
1261 }
1262 return associations;
1263 }
1264 function parseIspe(r, box) {
1265 r.pos = box.offset + box.headerSize + 4;
1266 return { width: r.u32(), height: r.u32() };
1267 }
1268 function parseIrot(r, box) {
1269 r.pos = box.offset + box.headerSize;
1270 return (r.u8() & 3) * 90;
1271 }
1272 function parseIinf(r, box) {
1273 r.pos = box.offset + box.headerSize;
1274 const version = r.u8();
1275 r.pos += 3;
1276 const entryCount = version === 0 ? r.u16() : r.u32();
1277 const itemTypes = /* @__PURE__ */ new Map();
1278 const entriesStart = r.pos;
1279 const boxEnd = box.offset + box.size;
1280 const infeBoxes = findBoxes(r, entriesStart, boxEnd);
1281 for (let i = 0; i < Math.min(entryCount, infeBoxes.length); i++) {
1282 const infe = infeBoxes[i];
1283 if (infe.type !== "infe") {
1284 continue;
1285 }
1286 r.pos = infe.offset + infe.headerSize;
1287 const infeVersion = r.u8();
1288 r.pos += 3;
1289 if (infeVersion >= 2) {
1290 const itemId = infeVersion === 2 ? r.u16() : r.u32();
1291 r.u16();
1292 const itemType = r.str(4);
1293 itemTypes.set(itemId, itemType);
1294 }
1295 }
1296 return itemTypes;
1297 }
1298 function parseIref(r, box, refType) {
1299 r.pos = box.offset + box.headerSize;
1300 const version = r.u8();
1301 r.pos += 3;
1302 const refs = /* @__PURE__ */ new Map();
1303 const boxEnd = box.offset + box.size;
1304 while (r.pos < boxEnd) {
1305 const refBox = readBox(r);
1306 if (!refBox || refBox.size < 8) {
1307 break;
1308 }
1309 r.pos = refBox.offset + refBox.headerSize;
1310 const fromId = version === 0 ? r.u16() : r.u32();
1311 const refCount = r.u16();
1312 const toIds = [];
1313 for (let i = 0; i < refCount; i++) {
1314 toIds.push(version === 0 ? r.u16() : r.u32());
1315 }
1316 if (refBox.type === refType) {
1317 refs.set(fromId, toIds);
1318 }
1319 r.pos = refBox.offset + refBox.size;
1320 }
1321 return refs;
1322 }
1323 function reverseBits32(n) {
1324 n = n >>> 1 & 1431655765 | (n & 1431655765) << 1;
1325 n = n >>> 2 & 858993459 | (n & 858993459) << 2;
1326 n = n >>> 4 & 252645135 | (n & 252645135) << 4;
1327 n = n >>> 8 & 16711935 | (n & 16711935) << 8;
1328 n = n >>> 16 | n << 16;
1329 return n >>> 0;
1330 }
1331 function buildCodecString(r, recordOffset) {
1332 r.pos = recordOffset;
1333 r.u8();
1334 const byte1 = r.u8();
1335 const profileSpace = byte1 >> 6 & 3;
1336 const tierFlag = byte1 >> 5 & 1;
1337 const profileIdc = byte1 & 31;
1338 const compatFlags = r.u32();
1339 const constraintBytes = r.bytes(6);
1340 const levelIdc = r.u8();
1341 const spacePrefix = profileSpace > 0 ? String.fromCharCode(64 + profileSpace) : "";
1342 const compatHex = reverseBits32(compatFlags).toString(16).toUpperCase();
1343 const tierChar = tierFlag ? "H" : "L";
1344 let lastNonZero = -1;
1345 for (let i = 5; i >= 0; i--) {
1346 if (constraintBytes[i] !== 0) {
1347 lastNonZero = i;
1348 break;
1349 }
1350 }
1351 let constraintStr = "";
1352 if (lastNonZero >= 0) {
1353 const parts = [];
1354 for (let i = 0; i <= lastNonZero; i++) {
1355 parts.push(constraintBytes[i].toString(16).toUpperCase());
1356 }
1357 constraintStr = "." + parts.join(".");
1358 }
1359 return `hvc1.${spacePrefix}${profileIdc}.${compatHex}.${tierChar}${levelIdc}${constraintStr}`;
1360 }
1361 function readItemData(buffer, loc, idatOffset) {
1362 const baseOffset = loc.constructionMethod === 1 ? idatOffset : 0;
1363 if (loc.extents.length === 1) {
1364 const ext = loc.extents[0];
1365 const start = baseOffset + ext.offset;
1366 return new Uint8Array(buffer.slice(start, start + ext.length));
1367 }
1368 let totalLength = 0;
1369 for (const ext of loc.extents) {
1370 totalLength += ext.length;
1371 }
1372 const data = new Uint8Array(totalLength);
1373 let pos = 0;
1374 for (const ext of loc.extents) {
1375 const start = baseOffset + ext.offset;
1376 data.set(
1377 new Uint8Array(buffer.slice(start, start + ext.length)),
1378 pos
1379 );
1380 pos += ext.length;
1381 }
1382 return data;
1383 }
1384 function findHvcProperties(propIndices, properties) {
1385 let hvcCBox;
1386 let ispeBox;
1387 let irotBox;
1388 for (const idx of propIndices) {
1389 if (idx < 1 || idx > properties.length) {
1390 continue;
1391 }
1392 const prop = properties[idx - 1];
1393 if (prop.type === "hvcC" && !hvcCBox) {
1394 hvcCBox = prop;
1395 }
1396 if (prop.type === "ispe" && !ispeBox) {
1397 ispeBox = prop;
1398 }
1399 if (prop.type === "irot" && !irotBox) {
1400 irotBox = prop;
1401 }
1402 }
1403 if (!hvcCBox) {
1404 throw new Error("No HEVC configuration (hvcC) found");
1405 }
1406 if (!ispeBox) {
1407 throw new Error("No image dimensions (ispe) found");
1408 }
1409 return { hvcCBox, ispeBox, irotBox };
1410 }
1411 function parseHeic(buffer) {
1412 const r = new Reader(buffer);
1413 const fileEnd = buffer.byteLength;
1414 const metaBox = findBox(r, 0, fileEnd, "meta");
1415 if (!metaBox) {
1416 throw new Error("No meta box found in HEIC file");
1417 }
1418 const metaChildStart = metaBox.offset + metaBox.headerSize + 4;
1419 const metaEnd = metaBox.offset + metaBox.size;
1420 const children = findBoxes(r, metaChildStart, metaEnd);
1421 const pitmBox = children.find((b) => b.type === "pitm");
1422 const ilocBox = children.find((b) => b.type === "iloc");
1423 const iprpBox = children.find((b) => b.type === "iprp");
1424 const iinfBox = children.find((b) => b.type === "iinf");
1425 const irefBox = children.find((b) => b.type === "iref");
1426 const idatBox = children.find((b) => b.type === "idat");
1427 const idatOffset = idatBox ? idatBox.offset + idatBox.headerSize : 0;
1428 if (!pitmBox || !ilocBox || !iprpBox) {
1429 throw new Error("Missing required boxes (pitm, iloc, iprp) in HEIC");
1430 }
1431 const primaryId = parsePitm(r, pitmBox);
1432 const locations = parseIloc(r, ilocBox);
1433 const iprpStart = iprpBox.offset + iprpBox.headerSize;
1434 const iprpEnd = iprpBox.offset + iprpBox.size;
1435 const iprpChildren = findBoxes(r, iprpStart, iprpEnd);
1436 const ipcoBox = iprpChildren.find((b) => b.type === "ipco");
1437 const ipmaBox = iprpChildren.find((b) => b.type === "ipma");
1438 if (!ipcoBox || !ipmaBox) {
1439 throw new Error("Missing ipco or ipma in HEIC properties");
1440 }
1441 const allAssoc = parseIpma(r, ipmaBox);
1442 const ipcoStart = ipcoBox.offset + ipcoBox.headerSize;
1443 const ipcoEnd = ipcoBox.offset + ipcoBox.size;
1444 const properties = findBoxes(r, ipcoStart, ipcoEnd);
1445 let primaryItemType = "hvc1";
1446 if (iinfBox) {
1447 const itemTypes = parseIinf(r, iinfBox);
1448 const t = itemTypes.get(primaryId);
1449 if (t) {
1450 primaryItemType = t;
1451 }
1452 }
1453 if (primaryItemType === "grid") {
1454 return parseGridImage(
1455 r,
1456 buffer,
1457 primaryId,
1458 locations,
1459 allAssoc,
1460 properties,
1461 irefBox,
1462 idatOffset
1463 );
1464 }
1465 const primaryLoc = locations.get(primaryId);
1466 if (!primaryLoc || primaryLoc.extents.length === 0) {
1467 throw new Error(`No location data for primary item ${primaryId}`);
1468 }
1469 const primaryPropIndices = allAssoc.get(primaryId);
1470 if (!primaryPropIndices || primaryPropIndices.length === 0) {
1471 throw new Error("No property associations for primary item");
1472 }
1473 const { hvcCBox, ispeBox, irotBox } = findHvcProperties(
1474 primaryPropIndices,
1475 properties
1476 );
1477 const hvcCDataStart = hvcCBox.offset + hvcCBox.headerSize;
1478 const hvcCDataSize = hvcCBox.size - hvcCBox.headerSize;
1479 const description = new Uint8Array(
1480 buffer.slice(hvcCDataStart, hvcCDataStart + hvcCDataSize)
1481 );
1482 const codecString = buildCodecString(r, hvcCDataStart);
1483 const { width, height } = parseIspe(r, ispeBox);
1484 const rotation = irotBox ? parseIrot(r, irotBox) : 0;
1485 return {
1486 codecString,
1487 description,
1488 tiles: [
1489 {
1490 data: readItemData(buffer, primaryLoc, idatOffset),
1491 x: 0,
1492 y: 0
1493 }
1494 ],
1495 tileWidth: width,
1496 tileHeight: height,
1497 outputWidth: width,
1498 outputHeight: height,
1499 rotation
1500 };
1501 }
1502 function parseGridImage(r, buffer, gridItemId, locations, allAssoc, properties, irefBox, idatOffset) {
1503 const gridLoc = locations.get(gridItemId);
1504 if (!gridLoc || gridLoc.extents.length === 0) {
1505 throw new Error("No location data for grid item");
1506 }
1507 const gridData = readItemData(buffer, gridLoc, idatOffset);
1508 const largeFields = gridData.length > 1 && (gridData[1] & 1) !== 0;
1509 const minGridSize = largeFields ? 12 : 8;
1510 if (gridData.length < minGridSize) {
1511 throw new Error(
1512 `Grid descriptor too short: ${gridData.length} bytes`
1513 );
1514 }
1515 const rows = gridData[2] + 1;
1516 const columns = gridData[3] + 1;
1517 const gv = new DataView(gridData.buffer, gridData.byteOffset);
1518 let outputWidth;
1519 let outputHeight;
1520 if (largeFields) {
1521 outputWidth = gv.getUint32(4);
1522 outputHeight = gv.getUint32(8);
1523 } else {
1524 outputWidth = gv.getUint16(4);
1525 outputHeight = gv.getUint16(6);
1526 }
1527 if (!irefBox) {
1528 throw new Error("Grid image requires iref box");
1529 }
1530 const dimgRefs = parseIref(r, irefBox, "dimg");
1531 const tileItemIds = dimgRefs.get(gridItemId);
1532 if (!tileItemIds || tileItemIds.length === 0) {
1533 throw new Error("No tile references found for grid item");
1534 }
1535 const expectedTiles = rows * columns;
1536 if (tileItemIds.length < expectedTiles) {
1537 throw new Error(
1538 `Grid expects ${expectedTiles} tiles but found ${tileItemIds.length}`
1539 );
1540 }
1541 const firstTileProps = allAssoc.get(tileItemIds[0]);
1542 if (!firstTileProps || firstTileProps.length === 0) {
1543 throw new Error("No property associations for tile item");
1544 }
1545 const { hvcCBox, ispeBox } = findHvcProperties(
1546 firstTileProps,
1547 properties
1548 );
1549 const gridProps = allAssoc.get(gridItemId) || [];
1550 let irotBox;
1551 for (const idx of gridProps) {
1552 if (idx >= 1 && idx <= properties.length) {
1553 const prop = properties[idx - 1];
1554 if (prop.type === "irot") {
1555 irotBox = prop;
1556 break;
1557 }
1558 }
1559 }
1560 const hvcCDataStart = hvcCBox.offset + hvcCBox.headerSize;
1561 const hvcCDataSize = hvcCBox.size - hvcCBox.headerSize;
1562 const description = new Uint8Array(
1563 buffer.slice(hvcCDataStart, hvcCDataStart + hvcCDataSize)
1564 );
1565 const codecString = buildCodecString(r, hvcCDataStart);
1566 const { width: tileWidth, height: tileHeight } = parseIspe(r, ispeBox);
1567 const tiles = [];
1568 for (let row = 0; row < rows; row++) {
1569 for (let col = 0; col < columns; col++) {
1570 const tileIdx = row * columns + col;
1571 const tileId = tileItemIds[tileIdx];
1572 const tileLoc = locations.get(tileId);
1573 if (!tileLoc || tileLoc.extents.length === 0) {
1574 throw new Error(`No location data for tile item ${tileId}`);
1575 }
1576 tiles.push({
1577 data: readItemData(buffer, tileLoc, idatOffset),
1578 x: col * tileWidth,
1579 y: row * tileHeight
1580 });
1581 }
1582 }
1583 const rotation = irotBox ? parseIrot(r, irotBox) : 0;
1584 return {
1585 codecString,
1586 description,
1587 tiles,
1588 tileWidth,
1589 tileHeight,
1590 outputWidth,
1591 outputHeight,
1592 rotation
1593 };
1594 }
1595
1596 // packages/upload-media/build-module/canvas-utils.mjs
1597 async function canvasConvertToJpeg(file, quality = 0.82) {
1598 const baseName = getFileBasename(file.name);
1599 try {
1600 const bitmap = await createImageBitmap(file);
1601 try {
1602 const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
1603 const ctx = canvas.getContext("2d");
1604 if (!ctx) {
1605 throw new Error("Could not get canvas 2d context");
1606 }
1607 ctx.drawImage(bitmap, 0, 0);
1608 const jpegBlob = await canvas.convertToBlob({
1609 type: "image/jpeg",
1610 quality
1611 });
1612 return new File([jpegBlob], `${baseName}.jpg`, {
1613 type: "image/jpeg"
1614 });
1615 } finally {
1616 bitmap.close();
1617 }
1618 } catch {
1619 }
1620 if (typeof ImageDecoder !== "undefined") {
1621 const supported = await ImageDecoder.isTypeSupported(file.type);
1622 if (supported) {
1623 const decoder = new ImageDecoder({
1624 type: file.type,
1625 data: file.stream()
1626 });
1627 try {
1628 const { image: videoFrame } = await decoder.decode();
1629 try {
1630 const canvas = new OffscreenCanvas(
1631 videoFrame.displayWidth,
1632 videoFrame.displayHeight
1633 );
1634 const ctx = canvas.getContext("2d");
1635 if (!ctx) {
1636 throw new Error("Could not get canvas 2d context");
1637 }
1638 ctx.drawImage(videoFrame, 0, 0);
1639 const jpegBlob = await canvas.convertToBlob({
1640 type: "image/jpeg",
1641 quality
1642 });
1643 return new File([jpegBlob], `${baseName}.jpg`, {
1644 type: "image/jpeg"
1645 });
1646 } finally {
1647 videoFrame.close();
1648 }
1649 } finally {
1650 decoder.close();
1651 }
1652 }
1653 }
1654 if (typeof VideoDecoder !== "undefined") {
1655 try {
1656 const heicData = parseHeic(await file.arrayBuffer());
1657 const support = await VideoDecoder.isConfigSupported({
1658 codec: heicData.codecString
1659 });
1660 if (support.supported) {
1661 const canvas = new OffscreenCanvas(
1662 heicData.outputWidth,
1663 heicData.outputHeight
1664 );
1665 const ctx = canvas.getContext("2d");
1666 if (!ctx) {
1667 throw new Error("Could not get canvas 2d context");
1668 }
1669 for (const tile of heicData.tiles) {
1670 const frame = await decodeHevcFrame(
1671 heicData.codecString,
1672 heicData.description,
1673 heicData.tileWidth,
1674 heicData.tileHeight,
1675 tile.data
1676 );
1677 try {
1678 ctx.drawImage(frame, tile.x, tile.y);
1679 } finally {
1680 frame.close();
1681 }
1682 }
1683 const outputCanvas = applyRotation(canvas, heicData.rotation);
1684 const jpegBlob = await outputCanvas.convertToBlob({
1685 type: "image/jpeg",
1686 quality
1687 });
1688 return new File([jpegBlob], `${baseName}.jpg`, {
1689 type: "image/jpeg"
1690 });
1691 }
1692 } catch {
1693 }
1694 }
1695 throw new Error(
1696 "This browser cannot decode HEIC images. Please use Safari or convert to JPEG before uploading."
1697 );
1698 }
1699 function applyRotation(source, rotation) {
1700 if (rotation === 0) {
1701 return source;
1702 }
1703 const swap = rotation === 90 || rotation === 270;
1704 const w = swap ? source.height : source.width;
1705 const h = swap ? source.width : source.height;
1706 const rotated = new OffscreenCanvas(w, h);
1707 const ctx = rotated.getContext("2d");
1708 if (!ctx) {
1709 return source;
1710 }
1711 ctx.translate(w / 2, h / 2);
1712 ctx.rotate(-rotation * Math.PI / 180);
1713 ctx.drawImage(source, -source.width / 2, -source.height / 2);
1714 return rotated;
1715 }
1716 function decodeHevcFrame(codec, description, width, height, data) {
1717 return new Promise((resolve, reject) => {
1718 const decoder = new VideoDecoder({
1719 output: (frame) => {
1720 decoder.close();
1721 resolve(frame);
1722 },
1723 error: (e) => {
1724 if (decoder.state !== "closed") {
1725 decoder.close();
1726 }
1727 reject(e);
1728 }
1729 });
1730 decoder.configure({
1731 codec,
1732 codedWidth: width,
1733 codedHeight: height,
1734 description
1735 });
1736 decoder.decode(
1737 new EncodedVideoChunk({
1738 type: "key",
1739 timestamp: 0,
1740 data
1741 })
1742 );
1743 decoder.flush().catch((e) => {
1744 if (decoder.state !== "closed") {
1745 decoder.close();
1746 }
1747 reject(e);
1748 });
1749 });
1750 }
1751
1752 // packages/upload-media/build-module/feature-detection.mjs
1753 var cachedResult = null;
1754 function detectClientSideMediaSupport() {
1755 if (cachedResult !== null) {
1756 return cachedResult;
1757 }
1758 if (typeof WebAssembly === "undefined") {
1759 cachedResult = {
1760 supported: false,
1761 reason: "WebAssembly is not supported in this browser."
1762 };
1763 return cachedResult;
1764 }
1765 if (typeof SharedArrayBuffer === "undefined") {
1766 cachedResult = {
1767 supported: false,
1768 reason: "SharedArrayBuffer is not available. This may be due to missing cross-origin isolation headers."
1769 };
1770 return cachedResult;
1771 }
1772 if (typeof Worker === "undefined") {
1773 cachedResult = {
1774 supported: false,
1775 reason: "Web Workers are not supported in this browser."
1776 };
1777 return cachedResult;
1778 }
1779 if (typeof navigator !== "undefined" && "deviceMemory" in navigator && navigator.deviceMemory <= 2) {
1780 cachedResult = {
1781 supported: false,
1782 reason: "Device has insufficient memory for client-side media processing."
1783 };
1784 return cachedResult;
1785 }
1786 if (typeof navigator !== "undefined" && "hardwareConcurrency" in navigator && navigator.hardwareConcurrency < 2) {
1787 cachedResult = {
1788 supported: false,
1789 reason: "Device has insufficient CPU cores for client-side media processing."
1790 };
1791 return cachedResult;
1792 }
1793 if (typeof navigator !== "undefined") {
1794 const connection = navigator.connection;
1795 if (connection) {
1796 if (connection.saveData) {
1797 cachedResult = {
1798 supported: false,
1799 reason: "Data saver mode is enabled."
1800 };
1801 return cachedResult;
1802 }
1803 if (connection.effectiveType === "slow-2g" || connection.effectiveType === "2g") {
1804 cachedResult = {
1805 supported: false,
1806 reason: "Network connection is too slow for client-side media processing."
1807 };
1808 return cachedResult;
1809 }
1810 }
1811 }
1812 if (typeof window !== "undefined") {
1813 try {
1814 const testBlob = new Blob([""], {
1815 type: "application/javascript"
1816 });
1817 const testUrl = URL.createObjectURL(testBlob);
1818 try {
1819 const testWorker = new Worker(testUrl);
1820 testWorker.terminate();
1821 } finally {
1822 URL.revokeObjectURL(testUrl);
1823 }
1824 } catch {
1825 cachedResult = {
1826 supported: false,
1827 reason: "The site's Content Security Policy (CSP) does not allow blob: workers. The worker-src directive must include blob: to enable client-side media processing."
1828 };
1829 return cachedResult;
1830 }
1831 }
1832 cachedResult = { supported: true };
1833 return cachedResult;
1834 }
1835 function isClientSideMediaSupported() {
1836 return detectClientSideMediaSupport().supported;
1837 }
1838 function isHeicCanvasSupported() {
1839 return typeof createImageBitmap !== "undefined" && typeof OffscreenCanvas !== "undefined";
1840 }
1841 function clearFeatureDetectionCache() {
1842 cachedResult = null;
1843 }
1844 var BYTES_PER_PIXEL = 4;
1845 var INTERLACED_MEMORY_BUDGET = 0.5 * 1024 * 1024 * 1024;
1846 var BASELINE_MEMORY_BUDGET = 0.9 * 1024 * 1024 * 1024;
1847 function exceedsClientProcessingMemory(dimensions) {
1848 const { width, height, interlaced } = dimensions;
1849 const estimatedBytes = width * height * BYTES_PER_PIXEL;
1850 const budget = interlaced ? INTERLACED_MEMORY_BUDGET : BASELINE_MEMORY_BUDGET;
1851 return estimatedBytes > budget;
1852 }
1853
1854 // packages/upload-media/build-module/get-image-dimensions.mjs
1855 var MAX_HEADER_BYTES = 512 * 1024;
1856 function parseJpeg(view) {
1857 let offset = 2;
1858 while (offset < view.byteLength) {
1859 if (view.getUint8(offset) !== 255) {
1860 return null;
1861 }
1862 while (offset < view.byteLength && view.getUint8(offset) === 255) {
1863 offset++;
1864 }
1865 if (offset >= view.byteLength) {
1866 return null;
1867 }
1868 const marker = view.getUint8(offset);
1869 offset++;
1870 if (marker === 1 || marker >= 208 && marker <= 217) {
1871 continue;
1872 }
1873 if (marker === 218) {
1874 return null;
1875 }
1876 if (offset + 2 > view.byteLength) {
1877 return null;
1878 }
1879 const segmentLength = view.getUint16(offset);
1880 if (segmentLength < 2) {
1881 return null;
1882 }
1883 const isStartOfFrame = marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204;
1884 if (isStartOfFrame) {
1885 if (offset + 7 > view.byteLength) {
1886 return null;
1887 }
1888 const height = view.getUint16(offset + 3);
1889 const width = view.getUint16(offset + 5);
1890 const interlaced = marker === 194 || marker === 198 || marker === 202 || marker === 206;
1891 return { width, height, interlaced };
1892 }
1893 offset += segmentLength;
1894 }
1895 return null;
1896 }
1897 function parsePng(view) {
1898 if (view.byteLength < 29) {
1899 return null;
1900 }
1901 const isIhdr = view.getUint8(12) === 73 && // I
1902 view.getUint8(13) === 72 && // H
1903 view.getUint8(14) === 68 && // D
1904 view.getUint8(15) === 82;
1905 if (!isIhdr) {
1906 return null;
1907 }
1908 const width = view.getUint32(16);
1909 const height = view.getUint32(20);
1910 const interlaceMethod = view.getUint8(28);
1911 return { width, height, interlaced: interlaceMethod !== 0 };
1912 }
1913 async function getImageDimensions(file) {
1914 try {
1915 const headerBytes = Math.min(file.size, MAX_HEADER_BYTES);
1916 const buffer = await file.slice(0, headerBytes).arrayBuffer();
1917 const view = new DataView(buffer);
1918 if (view.byteLength >= 3 && view.getUint16(0) === 65496) {
1919 return parseJpeg(view);
1920 }
1921 if (view.byteLength >= 8 && view.getUint32(0) === 2303741511 && view.getUint32(4) === 218765834) {
1922 return parsePng(view);
1923 }
1924 return null;
1925 } catch {
1926 return null;
1927 }
1928 }
1929
1930 // packages/upload-media/build-module/stub-file.mjs
1931 var StubFile = class extends File {
1932 constructor(fileName = "stub-file") {
1933 super([], fileName);
1934 }
1935 };
1936
1937 // packages/upload-media/build-module/store/private-actions.mjs
1938 var DEFAULT_OUTPUT_QUALITY = 0.82;
1939 var ultraHdrItems = /* @__PURE__ */ new Set();
1940 function addItem({
1941 file: fileOrBlob,
1942 batchId,
1943 onChange,
1944 onSuccess,
1945 onBatchSuccess,
1946 onError,
1947 additionalData = {},
1948 sourceUrl,
1949 sourceAttachmentId,
1950 abortController,
1951 operations
1952 }) {
1953 return async ({ dispatch }) => {
1954 const itemId = v4_default();
1955 const file = convertBlobToFile(fileOrBlob);
1956 let blobUrl;
1957 if (!(file instanceof StubFile)) {
1958 blobUrl = (0, import_blob.createBlobURL)(file);
1959 dispatch({
1960 type: Type.CacheBlobUrl,
1961 id: itemId,
1962 blobUrl
1963 });
1964 }
1965 dispatch({
1966 type: Type.Add,
1967 item: {
1968 id: itemId,
1969 batchId,
1970 status: ItemStatus.Processing,
1971 sourceFile: cloneFile(file),
1972 file,
1973 attachment: {
1974 url: blobUrl
1975 },
1976 additionalData: {
1977 generate_sub_sizes: false,
1978 ...additionalData
1979 },
1980 onChange,
1981 onSuccess,
1982 onBatchSuccess,
1983 onError,
1984 sourceUrl,
1985 sourceAttachmentId,
1986 abortController: abortController || new AbortController(),
1987 operations: Array.isArray(operations) ? operations : [OperationType.Prepare]
1988 }
1989 });
1990 dispatch.processItem(itemId);
1991 };
1992 }
1993 function addSideloadItem({
1994 file,
1995 onChange,
1996 additionalData,
1997 operations,
1998 batchId,
1999 parentId
2000 }) {
2001 return ({ dispatch }) => {
2002 const itemId = v4_default();
2003 dispatch({
2004 type: Type.Add,
2005 item: {
2006 id: itemId,
2007 batchId,
2008 status: ItemStatus.Processing,
2009 sourceFile: cloneFile(file),
2010 file,
2011 onChange,
2012 additionalData: {
2013 ...additionalData
2014 },
2015 parentId,
2016 operations: Array.isArray(operations) ? operations : [OperationType.Prepare],
2017 abortController: new AbortController()
2018 }
2019 });
2020 dispatch.processItem(itemId);
2021 };
2022 }
2023 function processItem(id) {
2024 return async ({ select: select2, dispatch }) => {
2025 if (select2.isPaused()) {
2026 return;
2027 }
2028 const item = select2.getItem(id);
2029 if (!item) {
2030 return;
2031 }
2032 const {
2033 attachment,
2034 onChange,
2035 onSuccess,
2036 onBatchSuccess,
2037 batchId,
2038 parentId
2039 } = item;
2040 const operation = Array.isArray(item.operations?.[0]) ? item.operations[0][0] : item.operations?.[0];
2041 const operationArgs = Array.isArray(item.operations?.[0]) ? item.operations[0][1] : void 0;
2042 if (operation === OperationType.Upload) {
2043 const settings = select2.getSettings();
2044 const activeCount = select2.getActiveUploadCount();
2045 if (activeCount >= settings.maxConcurrentUploads) {
2046 return;
2047 }
2048 }
2049 if (operation === OperationType.ResizeCrop || operation === OperationType.Rotate) {
2050 const settings = select2.getSettings();
2051 const activeCount = select2.getActiveImageProcessingCount();
2052 if (activeCount >= settings.maxConcurrentImageProcessing) {
2053 return;
2054 }
2055 }
2056 if (attachment) {
2057 const isHeicUrl = attachment.url && /\.hei[cf]$/i.test(attachment.url);
2058 if (!isHeicUrl) {
2059 onChange?.([attachment]);
2060 }
2061 }
2062 if (!operation) {
2063 if (parentId || !parentId && !select2.hasPendingItemsByParentId(id)) {
2064 if (attachment) {
2065 onSuccess?.([attachment]);
2066 }
2067 dispatch.removeItem(id);
2068 dispatch.revokeBlobUrls(id);
2069 if (batchId && select2.isBatchUploaded(batchId)) {
2070 onBatchSuccess?.();
2071 }
2072 }
2073 if (parentId && batchId && select2.isBatchUploaded(batchId)) {
2074 const parentItem = select2.getItem(parentId);
2075 if (!parentItem) {
2076 return;
2077 }
2078 if (parentItem.operations && parentItem.operations.length > 0) {
2079 dispatch.processItem(parentId);
2080 return;
2081 }
2082 if (attachment) {
2083 parentItem.onSuccess?.([attachment]);
2084 }
2085 dispatch.removeItem(parentId);
2086 dispatch.revokeBlobUrls(parentId);
2087 if (parentItem.batchId && select2.isBatchUploaded(parentItem.batchId)) {
2088 parentItem.onBatchSuccess?.();
2089 }
2090 }
2091 return;
2092 }
2093 if (operation === OperationType.Finalize && select2.hasPendingItemsByParentId(id)) {
2094 return;
2095 }
2096 dispatch({
2097 type: Type.OperationStart,
2098 id,
2099 operation
2100 });
2101 switch (operation) {
2102 case OperationType.Prepare:
2103 dispatch.prepareItem(item.id);
2104 break;
2105 case OperationType.ResizeCrop:
2106 dispatch.resizeCropItem(
2107 item.id,
2108 operationArgs
2109 );
2110 break;
2111 case OperationType.Rotate:
2112 dispatch.rotateItem(
2113 item.id,
2114 operationArgs
2115 );
2116 break;
2117 case OperationType.TranscodeImage:
2118 dispatch.transcodeImageItem(
2119 item.id,
2120 operationArgs
2121 );
2122 break;
2123 case OperationType.Upload:
2124 if (item.parentId) {
2125 dispatch.sideloadItem(id);
2126 } else {
2127 dispatch.uploadItem(id);
2128 }
2129 break;
2130 case OperationType.ThumbnailGeneration:
2131 dispatch.generateThumbnails(id);
2132 break;
2133 case OperationType.Finalize:
2134 dispatch.finalizeItem(id);
2135 break;
2136 case OperationType.DetectUltraHdr:
2137 dispatch.detectUltraHdr(id);
2138 break;
2139 }
2140 };
2141 }
2142 function pauseQueue() {
2143 return {
2144 type: Type.PauseQueue
2145 };
2146 }
2147 function resumeQueue() {
2148 return async ({ select: select2, dispatch }) => {
2149 dispatch({
2150 type: Type.ResumeQueue
2151 });
2152 for (const item of select2.getAllItems()) {
2153 if (item.status === ItemStatus.PendingRetry) {
2154 dispatch.executeRetry(item.id);
2155 } else {
2156 dispatch.processItem(item.id);
2157 }
2158 }
2159 };
2160 }
2161 function pauseItem(id) {
2162 return async ({ dispatch }) => {
2163 dispatch({
2164 type: Type.PauseItem,
2165 id
2166 });
2167 };
2168 }
2169 function removeItem(id) {
2170 return async ({ select: select2, dispatch }) => {
2171 const item = select2.getItem(id);
2172 if (!item) {
2173 return;
2174 }
2175 ultraHdrItems.delete(id);
2176 clearRetryTimer(id);
2177 dispatch({
2178 type: Type.Remove,
2179 id
2180 });
2181 if (select2.getAllItems().length === 0) {
2182 terminateVipsWorker();
2183 }
2184 };
2185 }
2186 function finishOperation(id, updates) {
2187 return async ({ select: select2, dispatch }) => {
2188 const item = select2.getItem(id);
2189 const previousOperation = item?.currentOperation;
2190 dispatch({
2191 type: Type.OperationFinish,
2192 id,
2193 item: updates
2194 });
2195 dispatch.processItem(id);
2196 if (previousOperation === OperationType.Upload) {
2197 const pendingUploads = select2.getPendingUploads();
2198 for (const pendingItem of pendingUploads) {
2199 dispatch.processItem(pendingItem.id);
2200 }
2201 }
2202 if (previousOperation === OperationType.ResizeCrop || previousOperation === OperationType.Rotate) {
2203 const pendingItems = select2.getPendingImageProcessing();
2204 for (const pendingItem of pendingItems) {
2205 dispatch.processItem(pendingItem.id);
2206 }
2207 }
2208 if (previousOperation === OperationType.ResizeCrop || previousOperation === OperationType.Rotate || previousOperation === OperationType.TranscodeImage) {
2209 maybeRecycleVipsWorker(select2.getActiveImageProcessingCount());
2210 }
2211 };
2212 }
2213 var VALID_IMAGE_FORMATS = ["jpeg", "webp", "avif", "png", "gif"];
2214 function isValidImageFormat(format) {
2215 return VALID_IMAGE_FORMATS.includes(format);
2216 }
2217 async function getTranscodeImageOperation(file, outputMimeType, interlaced = false) {
2218 if (file.type === "image/png" && outputMimeType === "image/jpeg") {
2219 const blobUrl = (0, import_blob.createBlobURL)(file);
2220 try {
2221 const hasAlpha = await vipsHasTransparency(blobUrl);
2222 if (hasAlpha) {
2223 return null;
2224 }
2225 } catch {
2226 return null;
2227 } finally {
2228 (0, import_blob.revokeBlobURL)(blobUrl);
2229 }
2230 }
2231 const formatPart = outputMimeType.split("/")[1];
2232 if (!isValidImageFormat(formatPart)) {
2233 return null;
2234 }
2235 return [
2236 OperationType.TranscodeImage,
2237 {
2238 outputFormat: formatPart,
2239 outputQuality: DEFAULT_OUTPUT_QUALITY,
2240 interlaced
2241 }
2242 ];
2243 }
2244 function prepareItem(id) {
2245 return async ({ select: select2, dispatch }) => {
2246 const item = select2.getItem(id);
2247 if (!item) {
2248 return;
2249 }
2250 const { file } = item;
2251 const operations = [];
2252 const settings = select2.getSettings();
2253 let heicJpeg = null;
2254 const isImage = file.type.startsWith("image/");
2255 const isVipsSupported = CLIENT_SIDE_SUPPORTED_MIME_TYPES.includes(
2256 file.type
2257 );
2258 const isHeic = HEIC_MIME_TYPES.includes(file.type);
2259 let tooLargeForClient = false;
2260 if (isImage && isVipsSupported) {
2261 const dimensions = await getImageDimensions(file);
2262 if (dimensions && exceedsClientProcessingMemory(dimensions)) {
2263 tooLargeForClient = true;
2264 }
2265 }
2266 if (file.type === "image/jpeg" && !tooLargeForClient) {
2267 operations.push(OperationType.DetectUltraHdr);
2268 }
2269 if (isImage && isVipsSupported && !tooLargeForClient) {
2270 operations.push(
2271 OperationType.Upload,
2272 OperationType.ThumbnailGeneration,
2273 OperationType.Finalize
2274 );
2275 } else if (isImage && isHeic) {
2276 try {
2277 heicJpeg = await canvasConvertToJpeg(
2278 file,
2279 settings.imageQuality ?? DEFAULT_OUTPUT_QUALITY
2280 );
2281 } catch {
2282 dispatch.cancelItem(
2283 id,
2284 new UploadError({
2285 code: "HEIC_DECODE_ERROR",
2286 message: "This browser cannot decode HEIC images and the server does not support them either. Please convert to JPEG before uploading.",
2287 file
2288 })
2289 );
2290 return;
2291 }
2292 operations.push(
2293 OperationType.Upload,
2294 OperationType.ThumbnailGeneration,
2295 OperationType.Finalize
2296 );
2297 } else {
2298 operations.push(OperationType.Upload);
2299 }
2300 dispatch({
2301 type: Type.AddOperations,
2302 id,
2303 operations
2304 });
2305 let updates;
2306 if (isHeic && heicJpeg) {
2307 const vipsAvailable = isClientSideMediaSupported();
2308 updates = {
2309 file: heicJpeg,
2310 sourceFile: heicJpeg,
2311 originalHeicFile: item.file,
2312 additionalData: {
2313 ...item.additionalData,
2314 generate_sub_sizes: !vipsAvailable,
2315 convert_format: true
2316 }
2317 };
2318 } else if (!isVipsSupported || !isImage || tooLargeForClient) {
2319 updates = {
2320 additionalData: {
2321 ...item.additionalData,
2322 generate_sub_sizes: true,
2323 convert_format: true
2324 }
2325 };
2326 } else {
2327 updates = {
2328 additionalData: {
2329 ...item.additionalData,
2330 generate_sub_sizes: false
2331 }
2332 };
2333 }
2334 dispatch.finishOperation(id, updates);
2335 };
2336 }
2337 function detectUltraHdr(id) {
2338 return async ({ select: select2, dispatch }) => {
2339 const item = select2.getItem(id);
2340 if (!item) {
2341 return;
2342 }
2343 let info;
2344 try {
2345 const buffer = await item.file.arrayBuffer();
2346 info = await vipsGetUltraHdrInfo(buffer);
2347 } catch {
2348 }
2349 if (info) {
2350 ultraHdrItems.add(id);
2351 }
2352 dispatch.finishOperation(id, {});
2353 };
2354 }
2355 function uploadItem(id) {
2356 return async ({ select: select2, dispatch }) => {
2357 const item = select2.getItem(id);
2358 if (!item) {
2359 return;
2360 }
2361 select2.getSettings().mediaUpload({
2362 filesList: [item.file],
2363 additionalData: item.additionalData,
2364 signal: item.abortController?.signal,
2365 onFileChange: ([attachment]) => {
2366 if (attachment && !(0, import_blob.isBlobURL)(attachment.url)) {
2367 dispatch.finishOperation(id, {
2368 attachment
2369 });
2370 }
2371 },
2372 onSuccess: ([attachment]) => {
2373 dispatch.finishOperation(id, {
2374 attachment
2375 });
2376 },
2377 onError: (error) => {
2378 dispatch.cancelItem(id, error);
2379 }
2380 });
2381 };
2382 }
2383 function sideloadItem(id) {
2384 return async ({ select: select2, dispatch }) => {
2385 const item = select2.getItem(id);
2386 if (!item) {
2387 return;
2388 }
2389 const { post, ...additionalData } = item.additionalData;
2390 const mediaSideload = select2.getSettings().mediaSideload;
2391 if (!mediaSideload) {
2392 dispatch.finishOperation(id, {});
2393 return;
2394 }
2395 mediaSideload({
2396 file: item.file,
2397 attachmentId: post,
2398 additionalData,
2399 signal: item.abortController?.signal,
2400 onSuccess: (subSize) => {
2401 if (item.parentId) {
2402 dispatch({
2403 type: Type.AccumulateSubSize,
2404 id: item.parentId,
2405 subSize
2406 });
2407 }
2408 dispatch.finishOperation(id, {});
2409 },
2410 onError: (error) => {
2411 dispatch.cancelItem(id, error);
2412 }
2413 });
2414 };
2415 }
2416 function resizeCropItem(id, args) {
2417 return async ({ select: select2, dispatch }) => {
2418 const item = select2.getItem(id);
2419 if (!item) {
2420 return;
2421 }
2422 if (!args?.resize) {
2423 dispatch.finishOperation(id, {
2424 file: item.file
2425 });
2426 return;
2427 }
2428 const addSuffix = Boolean(item.parentId);
2429 const scaledSuffix = Boolean(args.isThresholdResize);
2430 try {
2431 const file = await vipsResizeImage(
2432 item.id,
2433 item.file,
2434 args.resize,
2435 false,
2436 // smartCrop
2437 addSuffix,
2438 item.abortController?.signal,
2439 scaledSuffix
2440 );
2441 const blobUrl = (0, import_blob.createBlobURL)(file);
2442 dispatch({
2443 type: Type.CacheBlobUrl,
2444 id,
2445 blobUrl
2446 });
2447 dispatch.finishOperation(id, {
2448 file,
2449 attachment: {
2450 url: blobUrl
2451 }
2452 });
2453 } catch (error) {
2454 dispatch.cancelItem(
2455 id,
2456 new UploadError({
2457 code: "IMAGE_TRANSCODING_ERROR",
2458 message: (0, import_i18n6.__)(
2459 "The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading."
2460 ),
2461 file: item.file,
2462 cause: error instanceof Error ? error : void 0
2463 })
2464 );
2465 }
2466 };
2467 }
2468 function rotateItem(id, args) {
2469 return async ({ select: select2, dispatch }) => {
2470 const item = select2.getItem(id);
2471 if (!item) {
2472 return;
2473 }
2474 if (!args?.orientation || args.orientation === 1) {
2475 dispatch.finishOperation(id, {
2476 file: item.file
2477 });
2478 return;
2479 }
2480 try {
2481 const file = await vipsRotateImage(
2482 item.id,
2483 item.file,
2484 args.orientation,
2485 item.abortController?.signal
2486 );
2487 const blobUrl = (0, import_blob.createBlobURL)(file);
2488 dispatch({
2489 type: Type.CacheBlobUrl,
2490 id,
2491 blobUrl
2492 });
2493 dispatch.finishOperation(id, {
2494 file,
2495 attachment: {
2496 url: blobUrl
2497 }
2498 });
2499 } catch (error) {
2500 dispatch.cancelItem(
2501 id,
2502 new UploadError({
2503 code: "IMAGE_ROTATION_ERROR",
2504 message: (0, import_i18n6.__)(
2505 "The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading."
2506 ),
2507 file: item.file,
2508 cause: error instanceof Error ? error : void 0
2509 })
2510 );
2511 }
2512 };
2513 }
2514 function transcodeImageItem(id, args) {
2515 return async ({ select: select2, dispatch }) => {
2516 const item = select2.getItem(id);
2517 if (!item) {
2518 return;
2519 }
2520 if (!args?.outputFormat) {
2521 dispatch.finishOperation(id, {
2522 file: item.file
2523 });
2524 return;
2525 }
2526 const outputMimeType = `image/${args.outputFormat}`;
2527 const quality = args.outputQuality ?? DEFAULT_OUTPUT_QUALITY;
2528 const interlaced = args.interlaced ?? false;
2529 try {
2530 const file = await vipsConvertImageFormat(
2531 item.id,
2532 item.file,
2533 outputMimeType,
2534 quality,
2535 interlaced
2536 );
2537 const blobUrl = (0, import_blob.createBlobURL)(file);
2538 dispatch({
2539 type: Type.CacheBlobUrl,
2540 id,
2541 blobUrl
2542 });
2543 dispatch.finishOperation(id, {
2544 file,
2545 attachment: {
2546 url: blobUrl
2547 }
2548 });
2549 } catch (error) {
2550 dispatch.cancelItem(
2551 id,
2552 new UploadError({
2553 code: "MEDIA_TRANSCODING_ERROR",
2554 message: "Image could not be transcoded to the target format",
2555 file: item.file,
2556 cause: error instanceof Error ? error : void 0
2557 })
2558 );
2559 }
2560 };
2561 }
2562 function generateThumbnails(id) {
2563 return async ({ select: select2, dispatch }) => {
2564 const item = select2.getItem(id);
2565 if (!item) {
2566 return;
2567 }
2568 if (!item.attachment) {
2569 dispatch.finishOperation(id, {});
2570 return;
2571 }
2572 const attachment = item.attachment;
2573 const settings = select2.getSettings();
2574 if (item.originalHeicFile && attachment.id) {
2575 dispatch.addSideloadItem({
2576 file: item.originalHeicFile,
2577 batchId: v4_default(),
2578 parentId: item.id,
2579 additionalData: {
2580 post: attachment.id,
2581 image_size: "original-heic",
2582 convert_format: false
2583 },
2584 operations: [OperationType.Upload]
2585 });
2586 }
2587 {
2588 const needsRotation = attachment.exif_orientation && attachment.exif_orientation !== 1 && !item.file.name.includes("-scaled");
2589 if (needsRotation && attachment.id) {
2590 try {
2591 const rotatedFile = await vipsRotateImage(
2592 item.id,
2593 item.sourceFile,
2594 attachment.exif_orientation,
2595 item.abortController?.signal
2596 );
2597 dispatch.addSideloadItem({
2598 file: rotatedFile,
2599 batchId: v4_default(),
2600 parentId: item.id,
2601 additionalData: {
2602 post: attachment.id,
2603 image_size: "original",
2604 convert_format: false
2605 },
2606 operations: [OperationType.Upload]
2607 });
2608 } catch {
2609 console.warn(
2610 "Failed to rotate image, continuing with thumbnails"
2611 );
2612 }
2613 }
2614 }
2615 if (!item.parentId && attachment.missing_image_sizes && attachment.missing_image_sizes.length > 0) {
2616 const allImageSizes = settings.allImageSizes || {};
2617 const sizesToGenerate = attachment.missing_image_sizes;
2618 const thumbnailSource = item.sourceFile;
2619 const file = attachment.filename ? renameFile(thumbnailSource, attachment.filename) : thumbnailSource;
2620 const batchId = v4_default();
2621 const isUltraHdr = ultraHdrItems.has(item.id);
2622 const outputMimeType = attachment.image_output_format;
2623 const interlaced = attachment.image_save_progressive ?? false;
2624 let thumbnailTranscodeOperation = null;
2625 if (!isUltraHdr && outputMimeType) {
2626 thumbnailTranscodeOperation = await getTranscodeImageOperation(
2627 thumbnailSource,
2628 outputMimeType,
2629 interlaced
2630 );
2631 }
2632 const dimensionGroups = /* @__PURE__ */ new Map();
2633 for (const name of sizesToGenerate) {
2634 const imageSize = allImageSizes[name];
2635 if (!imageSize) {
2636 console.warn(
2637 `Image size "${name}" not found in configuration`
2638 );
2639 continue;
2640 }
2641 const key = `${imageSize.width}x${imageSize.height}x${imageSize.crop}`;
2642 const group = dimensionGroups.get(key);
2643 if (group) {
2644 group.push(name);
2645 } else {
2646 dimensionGroups.set(key, [name]);
2647 }
2648 }
2649 for (const [, names] of dimensionGroups) {
2650 const imageSize = allImageSizes[names[0]];
2651 const thumbnailOperations = [
2652 [OperationType.ResizeCrop, { resize: imageSize }]
2653 ];
2654 if (!isUltraHdr && thumbnailTranscodeOperation) {
2655 thumbnailOperations.push(thumbnailTranscodeOperation);
2656 }
2657 thumbnailOperations.push(OperationType.Upload);
2658 const imageSizeParam = names.length === 1 ? names[0] : names;
2659 dispatch.addSideloadItem({
2660 file,
2661 batchId,
2662 parentId: item.id,
2663 additionalData: {
2664 // Sideloading does not use the parent post ID but the
2665 // attachment ID as the image sizes need to be added to it.
2666 post: attachment.id,
2667 image_size: imageSizeParam,
2668 convert_format: false
2669 },
2670 operations: thumbnailOperations
2671 });
2672 }
2673 {
2674 const { bigImageSizeThreshold } = settings;
2675 if (bigImageSizeThreshold && attachment.id) {
2676 const bitmap = await createImageBitmap(thumbnailSource);
2677 const needsScaling = bitmap.width > bigImageSizeThreshold || bitmap.height > bigImageSizeThreshold;
2678 bitmap.close();
2679 if (needsScaling) {
2680 const sourceForScaled = attachment.filename ? renameFile(thumbnailSource, attachment.filename) : thumbnailSource;
2681 const scaledOperations = [
2682 [
2683 OperationType.ResizeCrop,
2684 {
2685 resize: {
2686 width: bigImageSizeThreshold,
2687 height: bigImageSizeThreshold
2688 },
2689 isThresholdResize: true
2690 }
2691 ]
2692 ];
2693 if (!isUltraHdr && thumbnailTranscodeOperation) {
2694 scaledOperations.push(
2695 thumbnailTranscodeOperation
2696 );
2697 }
2698 scaledOperations.push(OperationType.Upload);
2699 dispatch.addSideloadItem({
2700 file: sourceForScaled,
2701 batchId,
2702 parentId: item.id,
2703 additionalData: {
2704 post: attachment.id,
2705 image_size: "scaled",
2706 convert_format: false
2707 },
2708 operations: scaledOperations
2709 });
2710 }
2711 }
2712 }
2713 }
2714 dispatch.finishOperation(id, {});
2715 };
2716 }
2717 function finalizeItem(id) {
2718 return async ({ select: select2, dispatch }) => {
2719 const item = select2.getItem(id);
2720 if (!item) {
2721 return;
2722 }
2723 const attachment = item.attachment;
2724 const { mediaFinalize } = select2.getSettings();
2725 const updates = {};
2726 if (attachment?.id && mediaFinalize) {
2727 try {
2728 const updatedAttachment = await mediaFinalize(
2729 attachment.id,
2730 item.subSizes || []
2731 );
2732 if (updatedAttachment) {
2733 updates.attachment = updatedAttachment;
2734 }
2735 } catch (error) {
2736 console.warn("Media finalization failed:", error);
2737 }
2738 }
2739 dispatch.finishOperation(id, updates);
2740 };
2741 }
2742 function revokeBlobUrls(id) {
2743 return async ({ select: select2, dispatch }) => {
2744 const blobUrls = select2.getBlobUrls(id);
2745 for (const blobUrl of blobUrls) {
2746 (0, import_blob.revokeBlobURL)(blobUrl);
2747 }
2748 dispatch({
2749 type: Type.RevokeBlobUrls,
2750 id
2751 });
2752 };
2753 }
2754 function updateItemProgress(id, progress) {
2755 return async ({ dispatch }) => {
2756 dispatch({
2757 type: Type.UpdateProgress,
2758 id,
2759 progress
2760 });
2761 };
2762 }
2763 function updateSettings(settings) {
2764 return {
2765 type: Type.UpdateSettings,
2766 settings
2767 };
2768 }
2769
2770 // packages/upload-media/build-module/lock-unlock.mjs
2771 var import_private_apis = __toESM(require_private_apis(), 1);
2772 var { lock, unlock } = (0, import_private_apis.__dangerousOptInToUnstableAPIsOnlyForCoreModules)(
2773 "I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.",
2774 "@wordpress/upload-media"
2775 );
2776
2777 // packages/upload-media/build-module/store/index.mjs
2778 var storeConfig = {
2779 reducer: reducer_default,
2780 selectors: selectors_exports,
2781 actions: actions_exports
2782 };
2783 var store = (0, import_data.createReduxStore)(STORE_NAME, {
2784 reducer: reducer_default,
2785 selectors: selectors_exports,
2786 actions: actions_exports
2787 });
2788 if (!(0, import_data.select)(store)) {
2789 (0, import_data.register)(store);
2790 }
2791 unlock(store).registerPrivateActions(private_actions_exports);
2792 unlock(store).registerPrivateSelectors(private_selectors_exports);
2793
2794 // packages/upload-media/build-module/components/provider/index.mjs
2795 var import_element2 = __toESM(require_element(), 1);
2796 var import_data3 = __toESM(require_data(), 1);
2797
2798 // packages/upload-media/build-module/components/provider/with-registry-provider.mjs
2799 var import_element = __toESM(require_element(), 1);
2800 var import_data2 = __toESM(require_data(), 1);
2801 var import_compose = __toESM(require_compose(), 1);
2802 var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
2803 function getSubRegistry(subRegistries, registry, useSubRegistry) {
2804 if (!useSubRegistry) {
2805 return registry;
2806 }
2807 let subRegistry = subRegistries.get(registry);
2808 if (!subRegistry) {
2809 subRegistry = (0, import_data2.createRegistry)({}, registry);
2810 subRegistry.registerStore(STORE_NAME, storeConfig);
2811 subRegistries.set(registry, subRegistry);
2812 }
2813 return subRegistry;
2814 }
2815 var withRegistryProvider = (0, import_compose.createHigherOrderComponent)(
2816 (WrappedComponent) => ({ useSubRegistry = true, ...props }) => {
2817 const registry = (0, import_data2.useRegistry)();
2818 const [subRegistries] = (0, import_element.useState)(() => /* @__PURE__ */ new WeakMap());
2819 const subRegistry = getSubRegistry(
2820 subRegistries,
2821 registry,
2822 useSubRegistry
2823 );
2824 if (subRegistry === registry) {
2825 return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WrappedComponent, { registry, ...props });
2826 }
2827 return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_data2.RegistryProvider, { value: subRegistry, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WrappedComponent, { registry: subRegistry, ...props }) });
2828 },
2829 "withRegistryProvider"
2830 );
2831 var with_registry_provider_default = withRegistryProvider;
2832
2833 // packages/upload-media/build-module/components/provider/index.mjs
2834 var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
2835 var MediaUploadProvider = with_registry_provider_default((props) => {
2836 const { children, settings } = props;
2837 const { updateSettings: updateSettings2 } = unlock((0, import_data3.useDispatch)(store));
2838 (0, import_element2.useEffect)(() => {
2839 updateSettings2(settings);
2840 }, [settings, updateSettings2]);
2841 return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
2842 });
2843 var provider_default = MediaUploadProvider;
2844 return __toCommonJS(index_exports);
2845 })();
2846 //# sourceMappingURL=index.js.map
2847