{
  "version": 3,
  "sources": ["../src/main.ts", "../src/lib/logger.ts", "../src/lib/upload-file.ts", "../src/lib/upload-image.ts", "../src/lib/virtual-file-input.ts"],
  "sourcesContent": ["import { packageTracer } from '@alwatr/package-tracer';\n\n__dev_mode__: packageTracer.add(__package_name__, __package_version__);\n\nexport * from './lib/upload-file.js';\nexport * from './lib/upload-image.js';\nexport * from './lib/virtual-file-input.js';\n", "import { createLogger } from '@alwatr/logger';\n\nexport const logger = createLogger('@nexim/upload-sdk');\n", "import { logger } from './logger.js';\n\nimport type { ServiceResponse, UserAuth } from '@nexim/upload-types';\n\nexport type UploadFileOptions = {\n  path: string;\n  auth: UserAuth;\n  description: string;\n  apiEndpoint: string;\n  /**\n   * Extra headers to include in the request\n   */\n  extraHeaders?: Record<string, string>;\n\n  /**\n   * Maximum number of retries for the upload request.\n   * @defaultValue 3\n   */\n  maxRetries?: number;\n\n  /**\n   * Delay in milliseconds between retries.\n   * @defaultValue 2000\n   */\n  retryDelay?: number;\n};\n\n/**\n * Uploads a file to the server.\n *\n * @param file - The file to upload.\n * @param options - The upload options.\n * @returns A promise that resolves to the server response.\n *\n * @example\n * ```typescript\n * import { uploadFile } from '@nexim/upload-sdk';\n *\n * // Usually used inside a file picker callback\n * const file = new File(['content'], 'test.txt', { type: 'text/plain' });\n *\n * const options = {\n *   path: 'files/test.txt',\n *   auth: { id: 'user', token: 'token' },\n *   description: 'Test file',\n *   apiEndpoint: 'https://api.example.com/upload',\n * };\n *\n * try {\n *   const response = await uploadFile(file, options);\n *   console.log('Upload success:', response);\n * }\n * catch (err) {\n *   console.error('Upload failed:', err);\n * }\n * ```\n */\nexport async function uploadFile(file: Blob, options: UploadFileOptions): Promise<ServiceResponse<{ files: string[] }>> {\n  logger.logMethodArgs?.('uploadFile', { options });\n\n  const buffer = await file.arrayBuffer();\n\n  const headers: Record<string, string> = {\n    'Content-Type': 'application/octet-stream',\n    authorization: options.auth.token,\n    'x-upload-path': encodeURIComponent(options.path),\n    'x-upload-description': encodeURIComponent(options.description),\n    ...options.extraHeaders,\n  };\n\n  let attempt = 0;\n  const maxRetries = options.maxRetries ?? 3;\n  const retryDelay = options.retryDelay ?? 2_000;\n\n  while (attempt < maxRetries) {\n    try {\n      const response = await fetch(options.apiEndpoint, {\n        method: 'POST',\n        headers,\n        body: buffer,\n      });\n\n      if (!response.ok) {\n        throw new Error(`Upload failed with status: ${response.status}`);\n      }\n\n      const data = (await response.json()) as ServiceResponse<{ files: string[] }>;\n      return data;\n    }\n    catch (err) {\n      attempt++;\n      logger.error('uploadFile', 'upload_failed', { attempt, err });\n\n      if (attempt >= maxRetries) {\n        throw err;\n      }\n\n      await new Promise((resolve) => setTimeout(resolve, retryDelay));\n    }\n  }\n\n  throw new Error('Upload failed after maximum retries'); // This line should never be reached\n}\n", "import { logger } from './logger.js';\nimport { uploadFile, type UploadFileOptions } from './upload-file.js';\n\nimport type { ServiceResponse, UploadImagePreset } from '@nexim/upload-types';\n\nexport type UploadImageOptions = Omit<UploadFileOptions, 'path'> & {\n  path: string;\n  preset: UploadImagePreset;\n  throwOnClientOptimizationError?: boolean;\n};\n\n/**\n * Uploads an image to the server, optimizing it first.\n *\n * @param file - The image file to upload.\n * @param options - The upload options.\n * @returns A promise that resolves to the server response.\n *\n * @example\n * ```typescript\n * import { uploadImage } from '@nexim/upload-sdk';\n *\n * // Usually used inside a file picker callback\n * const file = new File(['image data'], 'photo.jpg', { type: 'image/jpeg' });\n *\n * const options = {\n *   path: 'images/photo',\n *   auth: { id: 'user', token: 'token' },\n *   description: 'User photo',\n *   apiEndpoint: 'https://api.example.com/upload',\n *   preset: {\n *     client: {\n *       width: 800,\n *       height: -1,\n *       quality: 80\n *     },\n *     // ... other preset options\n *   },\n * };\n *\n * await uploadImage(file, options);\n * ```\n */\nexport async function uploadImage(file: Blob, options: UploadImageOptions): Promise<ServiceResponse<{ files: string[] }>> {\n  logger.logMethodArgs?.('uploadImage', { options });\n\n  let fileToUpload = file;\n  try {\n    fileToUpload = await optimizeImage(file, options.preset.client);\n  }\n  catch (err) {\n    logger.error('uploadImage', 'optimization_failed', { err });\n    if (options.throwOnClientOptimizationError) {\n      throw err;\n    }\n    // Fallback to original file\n  }\n\n  return uploadFile(fileToUpload, {\n    ...options,\n    extraHeaders: {\n      'x-upload-preset': btoa(JSON.stringify(options.preset)),\n    },\n  });\n}\n\n/**\n * Optimizes an image on the client side.\n *\n * @param rawImage - The raw image blob.\n * @param clientConfig - The client-side optimization configuration.\n * @returns A promise that resolves to the optimized image blob.\n *\n * @example\n * ```typescript\n * const rawImage = new Blob(['...'], { type: 'image/jpeg' });\n * const config = {\n *   width: 100,\n *   height: 100,\n *   quality: 90\n * };\n *\n * const optimizedBlob = await optimizeImage(rawImage, config);\n * ```\n */\nexport function optimizeImage(rawImage: Blob, clientConfig: UploadImagePreset['client']): Promise<Blob> {\n  logger.logMethod?.('optimizeImage');\n\n  return new Promise((resolve, reject) => {\n    const canvas = document.createElement('canvas');\n    const context = canvas.getContext('2d');\n    if (!context) {\n      resolve(rawImage);\n      return;\n    }\n\n    let width = clientConfig.width;\n    let height = clientConfig.height;\n\n    const image = new Image();\n    const objectUrl = URL.createObjectURL(rawImage);\n\n    image.onload = () => {\n      const aspect = image.width / image.height;\n\n      if (width && height === -1) {\n        height = width / aspect;\n      }\n      else if (height && width === -1) {\n        width = height * aspect;\n      }\n\n      canvas.width = width;\n      canvas.height = height;\n\n      context.drawImage(image, 0, 0, width, height);\n      URL.revokeObjectURL(objectUrl);\n\n      canvas.toBlob(\n        (blob) => {\n          if (blob) {\n            resolve(blob);\n          }\n          else {\n            reject(new Error('Failed to create blob from canvas.'));\n          }\n        },\n        rawImage.type,\n        clientConfig.quality / 100,\n      );\n    };\n\n    image.addEventListener('error', (error) => {\n      URL.revokeObjectURL(objectUrl);\n      reject(new Error(error.message || 'Image load error'));\n    });\n\n    image.src = objectUrl;\n  });\n}\n", "import { logger } from './logger.js';\n\nimport type { MaybePromise } from '@alwatr/type-helper';\n\n/**\n * Creates and triggers a virtual file input element to handle file selection.\n * This utility creates a temporary file input element, attaches event handlers,\n * and removes itself after use.\n *\n * Features:\n * - Creates a hidden file input element\n * - Handles file selection through browser's native interface\n * - Automatically cleans up after selection\n * - Supports async callbacks for processing selected files\n * - Filters files based on accept parameter (MIME types)\n *\n * @param accept - Comma-separated list of allowed file types (e.g., 'image/*', '.pdf', 'image/jpeg,image/png')\n * @param callback - Function to handle the selected file. Can be async for long-running operations.\n *\n * @example\n * ```typescript\n * // Example 1: Pick an image and upload it using uploadImage\n * import { pickAndProcessFile, uploadImage } from '@nexim/upload-sdk';\n *\n * pickAndProcessFile('image/*', async (file) => {\n *   await uploadImage(file, {\n *     path: 'images/user-avatar',\n *     auth: { id: '...', token: '...' },\n *     description: 'User Avatar',\n *     apiEndpoint: 'https://api.example.com/upload',\n *     preset: {\n *       client: { width: 512, height: 512, quality: 90 },\n *       // ...\n *     },\n *   });\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Example 2: Pick a PDF and upload it using uploadFile\n * import { pickAndProcessFile, uploadFile } from '@nexim/upload-sdk';\n *\n * pickAndProcessFile('.pdf', async (file) => {\n *   await uploadFile(file, {\n *     path: 'documents/report.pdf',\n *     auth: { id: '...', token: '...' },\n *     description: 'Monthly Report',\n *     apiEndpoint: 'https://api.example.com/upload',\n *   });\n * });\n * ```\n */\nexport function pickAndProcessFile(accept: string, callback: (file: File) => MaybePromise<void>): void {\n  logger.logMethod?.('pickAndProcessFile');\n\n  const input = document.createElement('input');\n  input.type = 'file';\n  input.accept = accept;\n\n  input.addEventListener('change', async () => {\n    logger.logOther?.('changed');\n    if (input.files === null || input.files.length === 0) return;\n    const file = input.files[0];\n\n    logger.logOther?.('pickAndProcessFile.change', { file });\n\n    input.remove(); // Remove the input element from the DOM to free-up\n\n    await callback(file);\n  });\n\n  input.click();\n}\n"],
  "mappings": ";;qqBAAA,iPAA8B,kCCA9B,kBAA6B,0BAEtB,IAAM,UAAS,4BAAa,mBAAmB,ECuDtD,eAAsB,WAAW,KAAY,QAA2E,CACtH,OAAO,gBAAgB,aAAc,CAAE,OAAQ,CAAC,EAEhD,MAAM,OAAS,MAAM,KAAK,YAAY,EAEtC,MAAM,QAAkC,CACtC,eAAgB,2BAChB,cAAe,QAAQ,KAAK,MAC5B,gBAAiB,mBAAmB,QAAQ,IAAI,EAChD,uBAAwB,mBAAmB,QAAQ,WAAW,EAC9D,GAAG,QAAQ,YACb,EAEA,IAAI,QAAU,EACd,MAAM,WAAa,QAAQ,YAAc,EACzC,MAAM,WAAa,QAAQ,YAAc,IAEzC,MAAO,QAAU,WAAY,CAC3B,GAAI,CACF,MAAM,SAAW,MAAM,MAAM,QAAQ,YAAa,CAChD,OAAQ,OACR,QACA,KAAM,MACR,CAAC,EAED,GAAI,CAAC,SAAS,GAAI,CAChB,MAAM,IAAI,MAAM,8BAA8B,SAAS,MAAM,EAAE,CACjE,CAEA,MAAM,KAAQ,MAAM,SAAS,KAAK,EAClC,OAAO,IACT,OACO,IAAK,CACV,UACA,OAAO,MAAM,aAAc,gBAAiB,CAAE,QAAS,GAAI,CAAC,EAE5D,GAAI,SAAW,WAAY,CACzB,MAAM,GACR,CAEA,MAAM,IAAI,QAAS,SAAY,WAAW,QAAS,UAAU,CAAC,CAChE,CACF,CAEA,MAAM,IAAI,MAAM,qCAAqC,CACvD,CC3DA,eAAsB,YAAY,KAAY,QAA4E,CACxH,OAAO,gBAAgB,cAAe,CAAE,OAAQ,CAAC,EAEjD,IAAI,aAAe,KACnB,GAAI,CACF,aAAe,MAAM,cAAc,KAAM,QAAQ,OAAO,MAAM,CAChE,OACO,IAAK,CACV,OAAO,MAAM,cAAe,sBAAuB,CAAE,GAAI,CAAC,EAC1D,GAAI,QAAQ,+BAAgC,CAC1C,MAAM,GACR,CAEF,CAEA,OAAO,WAAW,aAAc,CAC9B,GAAG,QACH,aAAc,CACZ,kBAAmB,KAAK,KAAK,UAAU,QAAQ,MAAM,CAAC,CACxD,CACF,CAAC,CACH,CAqBO,SAAS,cAAc,SAAgB,aAA0D,CACtG,OAAO,YAAY,eAAe,EAElC,OAAO,IAAI,QAAQ,CAAC,QAAS,SAAW,CACtC,MAAM,OAAS,SAAS,cAAc,QAAQ,EAC9C,MAAM,QAAU,OAAO,WAAW,IAAI,EACtC,GAAI,CAAC,QAAS,CACZ,QAAQ,QAAQ,EAChB,MACF,CAEA,IAAI,MAAQ,aAAa,MACzB,IAAI,OAAS,aAAa,OAE1B,MAAM,MAAQ,IAAI,MAClB,MAAM,UAAY,IAAI,gBAAgB,QAAQ,EAE9C,MAAM,OAAS,IAAM,CACnB,MAAM,OAAS,MAAM,MAAQ,MAAM,OAEnC,GAAI,OAAS,SAAW,GAAI,CAC1B,OAAS,MAAQ,MACnB,SACS,QAAU,QAAU,GAAI,CAC/B,MAAQ,OAAS,MACnB,CAEA,OAAO,MAAQ,MACf,OAAO,OAAS,OAEhB,QAAQ,UAAU,MAAO,EAAG,EAAG,MAAO,MAAM,EAC5C,IAAI,gBAAgB,SAAS,EAE7B,OAAO,OACJ,MAAS,CACR,GAAI,KAAM,CACR,QAAQ,IAAI,CACd,KACK,CACH,OAAO,IAAI,MAAM,oCAAoC,CAAC,CACxD,CACF,EACA,SAAS,KACT,aAAa,QAAU,GACzB,CACF,EAEA,MAAM,iBAAiB,QAAU,OAAU,CACzC,IAAI,gBAAgB,SAAS,EAC7B,OAAO,IAAI,MAAM,MAAM,SAAW,kBAAkB,CAAC,CACvD,CAAC,EAED,MAAM,IAAM,SACd,CAAC,CACH,CCtFO,SAAS,mBAAmB,OAAgB,SAAoD,CACrG,OAAO,YAAY,oBAAoB,EAEvC,MAAM,MAAQ,SAAS,cAAc,OAAO,EAC5C,MAAM,KAAO,OACb,MAAM,OAAS,OAEf,MAAM,iBAAiB,SAAU,SAAY,CAC3C,OAAO,WAAW,SAAS,EAC3B,GAAI,MAAM,QAAU,MAAQ,MAAM,MAAM,SAAW,EAAG,OACtD,MAAM,KAAO,MAAM,MAAM,CAAC,EAE1B,OAAO,WAAW,4BAA6B,CAAE,IAAK,CAAC,EAEvD,MAAM,OAAO,EAEb,MAAM,SAAS,IAAI,CACrB,CAAC,EAED,MAAM,MAAM,CACd,CJvEA,aAAc,oCAAc,IAAI,oBAAkB,OAAmB",
  "names": []
}
