{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import type { ReadStream } from 'node:fs';\nimport { v2 as cloudinary, ConfigOptions, UploadApiOptions } from 'cloudinary';\nimport intoStream from 'into-stream';\nimport * as utils from '@strapi/utils';\n\ninterface File {\n  name: string;\n  alternativeText?: string;\n  caption?: string;\n  width?: number;\n  height?: number;\n  formats?: Record<string, unknown>;\n  hash: string;\n  ext?: string;\n  mime: string;\n  size: number;\n  sizeInBytes: number;\n  url: string;\n  previewUrl?: string;\n  path?: string;\n  provider?: string;\n  provider_metadata?: Record<string, unknown>;\n  stream?: ReadStream;\n  buffer?: Buffer;\n}\n\nexport default {\n  init(options: ConfigOptions) {\n    cloudinary.config(options);\n\n    const upload = (file: File, customConfig = {}): Promise<void> => {\n      return new Promise((resolve, reject) => {\n        const config: Partial<UploadApiOptions> = {\n          resource_type: 'auto',\n          public_id: file.hash,\n        };\n\n        if (file.ext) {\n          config.filename = `${file.hash}${file.ext}`;\n        }\n\n        if (file.path) {\n          config.folder = file.path;\n        }\n\n        // For files smaller than 99 MB use regular upload as it tends to be faster\n        // and fallback to chunked upload for larger files as that's required by Cloudinary.\n        // https://support.cloudinary.com/hc/en-us/community/posts/360009586100-Upload-movie-video-with-large-size?page=1#community_comment_360002140099\n        // The Cloudinary's max limit for regular upload is actually 100 MB but add some headroom\n        // for size counting shenanigans. (Strapi provides the size in kilobytes rounded to two decimal places here).\n        const uploadMethod =\n          file.size && file.size < 1000 * 99\n            ? cloudinary.uploader.upload_stream\n            : cloudinary.uploader.upload_chunked_stream;\n\n        const uploadStream = uploadMethod({ ...config, ...customConfig }, (err, image) => {\n          if (err) {\n            if (err.message.includes('File size too large')) {\n              reject(new utils.errors.PayloadTooLargeError());\n            } else {\n              reject(new Error(`Error uploading to cloudinary: ${err.message}`));\n            }\n            return;\n          }\n\n          if (!image) {\n            return;\n          }\n\n          if (image.resource_type === 'video') {\n            file.previewUrl = cloudinary.url(`${image.public_id}.gif`, {\n              video_sampling: 6,\n              delay: 200,\n              width: 250,\n              crop: 'scale',\n              resource_type: 'video',\n            });\n          }\n\n          file.url = image.secure_url;\n          file.provider_metadata = {\n            public_id: image.public_id,\n            resource_type: image.resource_type,\n          };\n\n          resolve();\n        });\n\n        if (file.stream) {\n          file.stream.pipe(uploadStream);\n        } else if (file.buffer) {\n          intoStream(file.buffer).pipe(uploadStream);\n        } else {\n          throw new Error('Missing file stream or buffer');\n        }\n      });\n    };\n\n    return {\n      uploadStream(file: File, customConfig = {}) {\n        return upload(file, customConfig);\n      },\n      upload(file: File, customConfig = {}) {\n        return upload(file, customConfig);\n      },\n      async delete(file: File, customConfig = {}) {\n        try {\n          const { resource_type: resourceType, public_id: publicId } = file.provider_metadata ?? {};\n          const deleteConfig = {\n            resource_type: (resourceType || 'image') as string,\n            invalidate: true,\n            ...customConfig,\n          };\n\n          const response = await cloudinary.uploader.destroy(`${publicId}`, deleteConfig);\n\n          if (response.result !== 'ok' && response.result !== 'not found') {\n            throw new Error(response.result);\n          }\n        } catch (error) {\n          if (error instanceof Error) {\n            throw new Error(`Error deleting on cloudinary: ${error.message}`);\n          }\n\n          throw error;\n        }\n      },\n    };\n  },\n};\n"],"names":["cloudinary"],"mappings":";;;AA0BA,MAAe,QAAA;AAAA,EACb,KAAK,SAAwB;AAC3BA,OAAW,OAAO,OAAO;AAEzB,UAAM,SAAS,CAAC,MAAY,eAAe,CAAA,MAAsB;AAC/D,aAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,cAAM,SAAoC;AAAA,UACxC,eAAe;AAAA,UACf,WAAW,KAAK;AAAA,QAAA;AAGlB,YAAI,KAAK,KAAK;AACZ,iBAAO,WAAW,GAAG,KAAK,IAAI,GAAG,KAAK,GAAG;AAAA,QAC3C;AAEA,YAAI,KAAK,MAAM;AACb,iBAAO,SAAS,KAAK;AAAA,QACvB;AAOM,cAAA,eACJ,KAAK,QAAQ,KAAK,OAAO,MAAO,KAC5BA,GAAW,SAAS,gBACpBA,GAAW,SAAS;AAEpB,cAAA,eAAe,aAAa,EAAE,GAAG,QAAQ,GAAG,aAAa,GAAG,CAAC,KAAK,UAAU;AAChF,cAAI,KAAK;AACP,gBAAI,IAAI,QAAQ,SAAS,qBAAqB,GAAG;AAC/C,qBAAO,IAAI,MAAM,OAAO,qBAAsB,CAAA;AAAA,YAAA,OACzC;AACL,qBAAO,IAAI,MAAM,kCAAkC,IAAI,OAAO,EAAE,CAAC;AAAA,YACnE;AACA;AAAA,UACF;AAEA,cAAI,CAAC,OAAO;AACV;AAAA,UACF;AAEI,cAAA,MAAM,kBAAkB,SAAS;AACnC,iBAAK,aAAaA,GAAW,IAAI,GAAG,MAAM,SAAS,QAAQ;AAAA,cACzD,gBAAgB;AAAA,cAChB,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM;AAAA,cACN,eAAe;AAAA,YAAA,CAChB;AAAA,UACH;AAEA,eAAK,MAAM,MAAM;AACjB,eAAK,oBAAoB;AAAA,YACvB,WAAW,MAAM;AAAA,YACjB,eAAe,MAAM;AAAA,UAAA;AAGf;QAAA,CACT;AAED,YAAI,KAAK,QAAQ;AACV,eAAA,OAAO,KAAK,YAAY;AAAA,QAAA,WACpB,KAAK,QAAQ;AACtB,qBAAW,KAAK,MAAM,EAAE,KAAK,YAAY;AAAA,QAAA,OACpC;AACC,gBAAA,IAAI,MAAM,+BAA+B;AAAA,QACjD;AAAA,MAAA,CACD;AAAA,IAAA;AAGI,WAAA;AAAA,MACL,aAAa,MAAY,eAAe,IAAI;AACnC,eAAA,OAAO,MAAM,YAAY;AAAA,MAClC;AAAA,MACA,OAAO,MAAY,eAAe,IAAI;AAC7B,eAAA,OAAO,MAAM,YAAY;AAAA,MAClC;AAAA,MACA,MAAM,OAAO,MAAY,eAAe,IAAI;AACtC,YAAA;AACI,gBAAA,EAAE,eAAe,cAAc,WAAW,aAAa,KAAK,qBAAqB;AACvF,gBAAM,eAAe;AAAA,YACnB,eAAgB,gBAAgB;AAAA,YAChC,YAAY;AAAA,YACZ,GAAG;AAAA,UAAA;AAGC,gBAAA,WAAW,MAAMA,GAAW,SAAS,QAAQ,GAAG,QAAQ,IAAI,YAAY;AAE9E,cAAI,SAAS,WAAW,QAAQ,SAAS,WAAW,aAAa;AACzD,kBAAA,IAAI,MAAM,SAAS,MAAM;AAAA,UACjC;AAAA,iBACO,OAAO;AACd,cAAI,iBAAiB,OAAO;AAC1B,kBAAM,IAAI,MAAM,iCAAiC,MAAM,OAAO,EAAE;AAAA,UAClE;AAEM,gBAAA;AAAA,QACR;AAAA,MACF;AAAA,IAAA;AAAA,EAEJ;AACF;"}