UNPKG

payload-cloudinary

Version:
168 lines 6.18 kB
import path from 'path'; import crypto from 'crypto'; import { getResourceType } from './utils'; /** * Get upload options based on file type and versioning settings */ const getUploadOptions = (filename, versioning) => { const ext = path.extname(filename).toLowerCase(); const resourceType = getResourceType(ext); const baseOptions = { resource_type: resourceType, use_filename: true, unique_filename: true, ...(versioning?.autoInvalidate && { invalidate: true }), }; switch (resourceType) { case 'video': return { ...baseOptions, chunk_size: 6000000, eager: [{ format: ext.slice(1), quality: 'auto' }], eager_async: true, }; case 'image': return { ...baseOptions, eager: [{ quality: 'auto' }], eager_async: true, }; case 'raw': // For PDFs, add a pages parameter to count the pages and create a thumbnail if (ext === '.pdf') { return { ...baseOptions, resource_type: 'raw', use_filename: true, pages: true, eager: [{ format: 'jpg', page: 1, quality: 'auto' }], eager_async: true, }; } return { ...baseOptions, resource_type: 'raw', use_filename: true, }; default: return baseOptions; } }; /** * Sanitize a string to be used as part of a public ID */ const sanitizeForPublicID = (str) => { return str .toLowerCase() .replace(/[^a-z0-9]/g, '-') .replace(/-+/g, '-') .replace(/^-|-$/g, ''); }; /** * Generate a public ID based on the publicID options */ const generatePublicID = (filename, folderPath, publicIDOptions) => { if (publicIDOptions?.generatePublicID) { return publicIDOptions.generatePublicID(filename, path.dirname(folderPath), path.basename(folderPath)); } const ext = path.extname(filename).toLowerCase(); const resourceType = getResourceType(ext); const isRawFile = resourceType === 'raw'; if (publicIDOptions?.enabled === false) { const filenameWithoutExt = path.basename(filename, path.extname(filename)); const sanitizedFilename = sanitizeForPublicID(filenameWithoutExt); const finalFilename = isRawFile ? `${sanitizedFilename}${ext}` : sanitizedFilename; return path.posix.join(folderPath, finalFilename); } const useFilename = publicIDOptions?.useFilename !== false; const uniqueFilename = publicIDOptions?.uniqueFilename !== false; const timestamp = uniqueFilename ? `_${Date.now()}` : ''; if (useFilename) { const filenameWithoutExt = path.basename(filename, path.extname(filename)); const sanitizedFilename = sanitizeForPublicID(filenameWithoutExt); const finalFilename = isRawFile ? `${sanitizedFilename}${timestamp}${ext}` : `${sanitizedFilename}${timestamp}`; return path.posix.join(folderPath, finalFilename); } const finalFilename = isRawFile ? `media${timestamp}${ext}` : `media${timestamp}`; return path.posix.join(folderPath, finalFilename); }; /** * Generate a signature for client-side upload to Cloudinary */ export const getGenerateClientUploadSignature = ({ cloudinary, folder, versioning, publicID }) => async ({ filename, prefix = '', }) => { // Construct the folder path with proper handling of prefix const folderPath = prefix ? path.posix.join(folder, prefix) : folder; // Generate the public ID based on options const publicIdValue = generatePublicID(filename, folderPath, publicID); // Get upload options based on file type const uploadOptions = { ...getUploadOptions(filename, versioning), public_id: publicIdValue, use_filename: publicID?.useFilename !== false, unique_filename: publicID?.uniqueFilename !== false, asset_folder: folderPath, }; // Generate timestamp const timestamp = Math.round(new Date().getTime() / 1000); // Create the parameters to sign const paramsToSign = { timestamp, ...uploadOptions, }; // Remove undefined values and non-signable parameters const cleanedParams = Object.entries(paramsToSign).reduce((acc, [key, value]) => { if (value !== undefined && value !== null) { acc[key] = value; } return acc; }, {}); // Generate signature using Cloudinary's signing method const signature = generateSignature(cleanedParams, cloudinary.config().api_secret); // Get the upload URL based on resource type const resourceType = getResourceType(path.extname(filename).toLowerCase()); const cloudName = cloudinary.config().cloud_name; const uploadUrl = `https://api.cloudinary.com/v1_1/${cloudName}/${resourceType}/upload`; return { signature, timestamp, api_key: cloudinary.config().api_key, upload_url: uploadUrl, public_id: publicIdValue, upload_options: cleanedParams, }; }; /** * Generate a signature for Cloudinary upload * This follows Cloudinary's signature generation algorithm */ function generateSignature(paramsToSign, apiSecret) { // Sort parameters alphabetically const sortedParams = Object.keys(paramsToSign) .sort() .map((key) => { const value = paramsToSign[key]; // Handle arrays and objects if (Array.isArray(value)) { return `${key}=${JSON.stringify(value)}`; } if (typeof value === 'object') { return `${key}=${JSON.stringify(value)}`; } return `${key}=${value}`; }) .join('&'); // Create SHA256 hash return crypto .createHash('sha256') .update(sortedParams + apiSecret) .digest('hex'); } //# sourceMappingURL=generateClientUploadSignature.js.map