{
  "version": 3,
  "sources": ["../../../src/store/utils/index.ts"],
  "sourcesContent": ["/**\n * Internal dependencies\n */\nimport { ImageFile } from '../../image-file';\nimport { getFileBasename } from '../../utils';\nimport type { ImageSizeCrop, QueueItemId } from '../types';\n\n/**\n * Cached dynamic import promise for @wordpress/vips/worker.\n *\n * The module contains ~10MB of inlined WASM code. By using a dynamic import,\n * the WASM is only loaded when vips functions are actually called at image\n * processing time, rather than at module parse time.\n *\n * The promise is cached so the module is only resolved once.\n */\nlet vipsModulePromise:\n\t| Promise< typeof import('@wordpress/vips/worker') >\n\t| undefined;\n\n/**\n * The resolved module reference, available synchronously after the first\n * load completes. Used by terminateVipsWorker() and vipsCancelOperations().\n */\nlet vipsModule: typeof import('@wordpress/vips/worker') | undefined;\n\n/**\n * Lazily loads and caches the @wordpress/vips/worker module.\n *\n * @return The vips worker module.\n */\nfunction loadVipsModule(): Promise< typeof import('@wordpress/vips/worker') > {\n\tif ( ! vipsModulePromise ) {\n\t\tvipsModulePromise = import( '@wordpress/vips/worker' ).then(\n\t\t\t( mod ) => {\n\t\t\t\tvipsModule = mod;\n\t\t\t\treturn mod;\n\t\t\t}\n\t\t);\n\t}\n\treturn vipsModulePromise;\n}\n\n/**\n * Converts an image to a different format using vips in a web worker.\n *\n * @param id         Queue item ID.\n * @param file       File object.\n * @param type       Output mime type.\n * @param quality    Desired quality (0-1).\n * @param interlaced Whether to use interlaced/progressive mode.\n * @return Converted file.\n */\nexport async function vipsConvertImageFormat(\n\tid: QueueItemId,\n\tfile: File,\n\ttype:\n\t\t| 'image/jpeg'\n\t\t| 'image/png'\n\t\t| 'image/webp'\n\t\t| 'image/avif'\n\t\t| 'image/gif',\n\tquality: number,\n\tinterlaced?: boolean\n) {\n\tconst { vipsConvertImageFormat: convertImageFormat } =\n\t\tawait loadVipsModule();\n\tconst buffer = await convertImageFormat(\n\t\tid,\n\t\tawait file.arrayBuffer(),\n\t\tfile.type,\n\t\ttype,\n\t\tquality,\n\t\tinterlaced\n\t);\n\tconst ext = type.split( '/' )[ 1 ];\n\tconst fileName = `${ getFileBasename( file.name ) }.${ ext }`;\n\treturn new File( [ new Blob( [ buffer as ArrayBuffer ] ) ], fileName, {\n\t\ttype,\n\t} );\n}\n\n/**\n * Compresses an image using vips in a web worker.\n *\n * @param id         Queue item ID.\n * @param file       File object.\n * @param quality    Desired quality (0-1).\n * @param interlaced Whether to use interlaced/progressive mode.\n * @return Compressed file.\n */\nexport async function vipsCompressImage(\n\tid: QueueItemId,\n\tfile: File,\n\tquality: number,\n\tinterlaced?: boolean\n) {\n\tconst { vipsCompressImage: compressImage } = await loadVipsModule();\n\tconst buffer = await compressImage(\n\t\tid,\n\t\tawait file.arrayBuffer(),\n\t\tfile.type,\n\t\tquality,\n\t\tinterlaced\n\t);\n\treturn new File(\n\t\t[ new Blob( [ buffer as ArrayBuffer ], { type: file.type } ) ],\n\t\tfile.name,\n\t\t{ type: file.type }\n\t);\n}\n\n/**\n * Checks whether an image has transparency using vips in a web worker.\n *\n * @param url Image URL.\n * @return Whether the image has transparency.\n */\nexport async function vipsHasTransparency( url: string ) {\n\tconst { vipsHasTransparency: hasTransparency } = await loadVipsModule();\n\tconst response = await fetch( url );\n\tif ( ! response.ok ) {\n\t\tthrow new Error( `Failed to fetch image: ${ response.status }` );\n\t}\n\treturn hasTransparency( await response.arrayBuffer() );\n}\n\n/**\n * Probes a JPEG buffer for UltraHDR (ISO 21496-1 gain map) support using vips\n * in a web worker.\n *\n * @param buffer Image buffer to probe.\n * @return UltraHDR info if the buffer is a valid UltraHDR JPEG, otherwise null.\n */\nexport async function vipsGetUltraHdrInfo( buffer: ArrayBuffer ) {\n\tconst { vipsGetUltraHdrInfo: getUltraHdrInfo } = await loadVipsModule();\n\treturn getUltraHdrInfo( buffer );\n}\n\n/**\n * Resizes an image using vips in a web worker.\n *\n * UltraHDR JPEGs are auto-detected by libvips and their gain map is\n * preserved through the resize.\n *\n * @param id           Queue item ID.\n * @param file         File object.\n * @param resize       Resize options (width, height, crop).\n * @param smartCrop    Whether to use smart cropping (saliency-aware).\n * @param addSuffix    Whether to add dimension suffix to filename.\n * @param signal       Optional abort signal to cancel the operation.\n * @param scaledSuffix Whether to add '-scaled' suffix instead of dimensions (for big image threshold).\n * @param quality      Desired quality (0-1). Defaults to 0.82.\n * @return Resized ImageFile with dimension metadata.\n */\nexport async function vipsResizeImage(\n\tid: QueueItemId,\n\tfile: File,\n\tresize: ImageSizeCrop,\n\tsmartCrop: boolean,\n\taddSuffix: boolean,\n\tsignal?: AbortSignal,\n\tscaledSuffix?: boolean,\n\tquality?: number\n) {\n\tif ( signal?.aborted ) {\n\t\tthrow new Error( 'Operation aborted' );\n\t}\n\n\tconst { vipsResizeImage: resizeImage } = await loadVipsModule();\n\tconst { buffer, width, height, originalWidth, originalHeight } =\n\t\tawait resizeImage(\n\t\t\tid,\n\t\t\tawait file.arrayBuffer(),\n\t\t\tfile.type,\n\t\t\tresize,\n\t\t\tsmartCrop,\n\t\t\tquality\n\t\t);\n\n\tlet fileName = file.name;\n\tconst wasResized = originalWidth > width || originalHeight > height;\n\n\tif ( wasResized ) {\n\t\tconst basename = getFileBasename( file.name );\n\t\tif ( scaledSuffix ) {\n\t\t\t// Add '-scaled' suffix for big image threshold resizing.\n\t\t\t// This matches WordPress core's behavior in wp_create_image_subsizes().\n\t\t\tfileName = file.name.replace( basename, `${ basename }-scaled` );\n\t\t} else if ( addSuffix ) {\n\t\t\t// Add dimension suffix for thumbnails.\n\t\t\tfileName = file.name.replace(\n\t\t\t\tbasename,\n\t\t\t\t`${ basename }-${ width }x${ height }`\n\t\t\t);\n\t\t}\n\t}\n\n\tconst resultFile = new ImageFile(\n\t\tnew File(\n\t\t\t[ new Blob( [ buffer as ArrayBuffer ], { type: file.type } ) ],\n\t\t\tfileName,\n\t\t\t{\n\t\t\t\ttype: file.type,\n\t\t\t}\n\t\t),\n\t\twidth,\n\t\theight,\n\t\toriginalWidth,\n\t\toriginalHeight\n\t);\n\n\treturn resultFile;\n}\n\n/**\n * Rotates an image based on EXIF orientation using vips in a web worker.\n *\n * This applies the correct rotation/flip transformation based on the EXIF\n * orientation value (1-8), and adds a '-rotated' suffix to the filename.\n * This matches WordPress core's behavior when rotating images based on EXIF.\n *\n * @param id          Queue item ID.\n * @param file        File object.\n * @param orientation EXIF orientation value (1-8).\n * @param signal      Optional abort signal to cancel the operation.\n * @return Rotated ImageFile with updated dimensions.\n */\nexport async function vipsRotateImage(\n\tid: QueueItemId,\n\tfile: File,\n\torientation: number,\n\tsignal?: AbortSignal\n) {\n\tif ( signal?.aborted ) {\n\t\tthrow new Error( 'Operation aborted' );\n\t}\n\n\t// If orientation is 1 (normal), no rotation needed.\n\tif ( orientation === 1 ) {\n\t\treturn file;\n\t}\n\n\tconst { vipsRotateImage: rotateImage } = await loadVipsModule();\n\tconst { buffer, width, height } = await rotateImage(\n\t\tid,\n\t\tawait file.arrayBuffer(),\n\t\tfile.type,\n\t\torientation\n\t);\n\n\t// Add '-rotated' suffix to filename, matching WordPress core behavior.\n\tconst basename = getFileBasename( file.name );\n\tconst fileName = file.name.replace( basename, `${ basename }-rotated` );\n\n\tconst resultFile = new ImageFile(\n\t\tnew File(\n\t\t\t[ new Blob( [ buffer as ArrayBuffer ], { type: file.type } ) ],\n\t\t\tfileName,\n\t\t\t{\n\t\t\t\ttype: file.type,\n\t\t\t}\n\t\t),\n\t\twidth,\n\t\theight\n\t);\n\n\treturn resultFile;\n}\n\n/**\n * Cancels all ongoing image operations for the given item.\n *\n * If the vips module has not been loaded yet, there can be no active\n * operations to cancel.\n *\n * @param id Queue item ID to cancel operations for.\n * @return Whether any operation was cancelled.\n */\nexport async function vipsCancelOperations( id: QueueItemId ) {\n\tif ( ! vipsModule ) {\n\t\treturn false;\n\t}\n\treturn vipsModule.vipsCancelOperations( id );\n}\n\n/**\n * Terminates the vips worker if it has been loaded.\n *\n * If the vips module has not been loaded yet (i.e., no image processing\n * has occurred), this is a no-op since there is no worker to terminate.\n *\n * The worker itself is recreated lazily by `getWorkerAPI()` inside\n * `@wordpress/vips/worker` on the next vips call — the module reference\n * cached here can keep pointing at the same module since re-importing\n * returns the same instance from the JS module cache.\n */\nexport function terminateVipsWorker(): void {\n\tif ( vipsModule ) {\n\t\tvipsModule.terminateVipsWorker();\n\t}\n}\n\n/**\n * Tracks the number of completed vips image processing operations across\n * both the success path (`finishOperation`) and the failure path\n * (`cancelItem`). Used to periodically recycle the WASM worker to reclaim\n * memory, since WASM linear memory can only grow and never shrink.\n */\nlet completedVipsOperations = 0;\n\n/**\n * Maximum number of vips operations before recycling the worker.\n * Each operation can consume 50-100MB+ of WASM memory for large images.\n */\nconst MAX_VIPS_OPS_BEFORE_RECYCLE = 50;\n\n/**\n * Records that a vips operation has completed and recycles the worker if\n * the threshold has been reached and no other vips operations are in\n * flight. Call this from both success and failure paths so that a burst\n * of failures can't bypass the recycle budget.\n *\n * @param activeImageProcessingCount Number of vips operations currently\n *                                   in flight. Recycling is deferred while\n *                                   any are running so an in-flight worker\n *                                   isn't killed mid-operation.\n */\nexport function maybeRecycleVipsWorker(\n\tactiveImageProcessingCount: number\n): void {\n\tcompletedVipsOperations++;\n\n\tif (\n\t\tcompletedVipsOperations >= MAX_VIPS_OPS_BEFORE_RECYCLE &&\n\t\tactiveImageProcessingCount === 0\n\t) {\n\t\tterminateVipsWorker();\n\t\tcompletedVipsOperations = 0;\n\t}\n}\n"],
  "mappings": "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",
  "names": []
}
