UNPKG

pushduck

Version:

The fastest way to add file uploads to any web application. Enterprise security, edge-ready. Works with 16+ frameworks and 5+ storage providers. No heavy AWS SDK required.

22 lines (19 loc) 23.7 kB
const e=require(`./chunk-CEIYHHoD.js`),t=require(`./client-aUAn-ExZ.js`);function n(e){return(t={})=>{let n={provider:e.provider};for(let[r]of Object.entries(e.configKeys))n[r]=t[r]||e.defaults[r]||``;e.customLogic&&Object.assign(n,e.customLogic(t,n));let r=a(n);if(!r.valid)throw Error(`Provider validation failed: ${r.errors.join(`, `)}`);return n}}const r={aws:{provider:`aws`,configKeys:{region:[`AWS_REGION`,`S3_REGION`],bucket:[`AWS_S3_BUCKET`,`S3_BUCKET`,`S3_BUCKET_NAME`],accessKeyId:[`AWS_ACCESS_KEY_ID`,`S3_ACCESS_KEY_ID`],secretAccessKey:[`AWS_SECRET_ACCESS_KEY`,`S3_SECRET_ACCESS_KEY`],sessionToken:[`AWS_SESSION_TOKEN`],acl:[`S3_ACL`],customDomain:[`S3_CUSTOM_DOMAIN`]},defaults:{region:`us-east-1`,acl:`private`}},cloudflareR2:{provider:`cloudflare-r2`,configKeys:{accountId:[`CLOUDFLARE_ACCOUNT_ID`,`R2_ACCOUNT_ID`],bucket:[`CLOUDFLARE_R2_BUCKET`,`R2_BUCKET`],accessKeyId:[`CLOUDFLARE_R2_ACCESS_KEY_ID`,`R2_ACCESS_KEY_ID`],secretAccessKey:[`CLOUDFLARE_R2_SECRET_ACCESS_KEY`,`R2_SECRET_ACCESS_KEY`],endpoint:[`CLOUDFLARE_R2_ENDPOINT`,`R2_ENDPOINT`],customDomain:[`R2_CUSTOM_DOMAIN`],acl:[]},defaults:{region:`auto`,acl:`private`},customLogic:(e,t)=>({endpoint:t.endpoint||(t.accountId?`https://${t.accountId}.r2.cloudflarestorage.com`:``)})},digitalOceanSpaces:{provider:`digitalocean-spaces`,configKeys:{region:[`DO_SPACES_REGION`,`DIGITALOCEAN_SPACES_REGION`],bucket:[`DO_SPACES_BUCKET`,`DIGITALOCEAN_SPACES_BUCKET`],accessKeyId:[`DO_SPACES_ACCESS_KEY_ID`,`DIGITALOCEAN_SPACES_ACCESS_KEY_ID`],secretAccessKey:[`DO_SPACES_SECRET_ACCESS_KEY`,`DIGITALOCEAN_SPACES_SECRET_ACCESS_KEY`],endpoint:[`DO_SPACES_ENDPOINT`,`DIGITALOCEAN_SPACES_ENDPOINT`],customDomain:[`DO_SPACES_CUSTOM_DOMAIN`],acl:[]},defaults:{region:`nyc3`,acl:`private`},customLogic:(e,t)=>({endpoint:t.endpoint||`https://${t.region}.digitaloceanspaces.com`})},minio:{provider:`minio`,configKeys:{endpoint:[`MINIO_ENDPOINT`],bucket:[`MINIO_BUCKET`],accessKeyId:[`MINIO_ACCESS_KEY_ID`,`MINIO_ACCESS_KEY`],secretAccessKey:[`MINIO_SECRET_ACCESS_KEY`,`MINIO_SECRET_KEY`],region:[`MINIO_REGION`],customDomain:[`MINIO_CUSTOM_DOMAIN`],acl:[]},defaults:{endpoint:`localhost:9000`,region:`us-east-1`,acl:`private`},customLogic:(e,t)=>({useSSL:e.useSSL??!1,port:e.port?Number(e.port):void 0})},gcs:{provider:`gcs`,configKeys:{projectId:[`GOOGLE_CLOUD_PROJECT_ID`,`GCS_PROJECT_ID`],bucket:[`GCS_BUCKET`,`GOOGLE_CLOUD_STORAGE_BUCKET`],keyFilename:[`GOOGLE_APPLICATION_CREDENTIALS`,`GCS_KEY_FILE`],region:[`GCS_REGION`],customDomain:[`GCS_CUSTOM_DOMAIN`],acl:[]},defaults:{region:`us-central1`,acl:`private`},customLogic:e=>({credentials:e.credentials})},s3Compatible:{provider:`s3-compatible`,configKeys:{endpoint:[`S3_ENDPOINT`,`S3_COMPATIBLE_ENDPOINT`],bucket:[`S3_BUCKET`,`S3_BUCKET_NAME`],accessKeyId:[`S3_ACCESS_KEY_ID`,`ACCESS_KEY_ID`],secretAccessKey:[`S3_SECRET_ACCESS_KEY`,`SECRET_ACCESS_KEY`],region:[`S3_REGION`,`REGION`],customDomain:[`S3_CUSTOM_DOMAIN`],acl:[`S3_ACL`]},defaults:{region:`us-east-1`,acl:`private`,forcePathStyle:!0}}};function i(e,t={}){let i=r[e];if(!i)throw Error(`Unknown provider type: ${e}`);return n(i)(t)}function a(e){let t=[];switch(e.bucket||t.push(`Bucket name is required`),e.provider){case`aws`:e.accessKeyId||t.push(`AWS Access Key ID is required`),e.secretAccessKey||t.push(`AWS Secret Access Key is required`),e.region||t.push(`AWS Region is required`);break;case`cloudflare-r2`:e.accountId||t.push(`Cloudflare Account ID is required`),e.accessKeyId||t.push(`R2 Access Key ID is required`),e.secretAccessKey||t.push(`R2 Secret Access Key is required`);break;case`digitalocean-spaces`:e.accessKeyId||t.push(`DigitalOcean Spaces Access Key ID is required`),e.secretAccessKey||t.push(`DigitalOcean Spaces Secret Access Key is required`),e.region||t.push(`DigitalOcean Spaces Region is required`);break;case`minio`:e.endpoint||t.push(`MinIO Endpoint is required`),e.accessKeyId||t.push(`MinIO Access Key ID is required`),e.secretAccessKey||t.push(`MinIO Secret Access Key is required`);break;case`gcs`:e.projectId||t.push(`Google Cloud Project ID is required`),!e.keyFilename&&!e.credentials&&t.push(`Google Cloud credentials (keyFilename or credentials object) are required`);break;case`s3-compatible`:e.endpoint||t.push(`S3-compatible endpoint is required`),e.accessKeyId||t.push(`Access Key ID is required`),e.secretAccessKey||t.push(`Secret Access Key is required`);break}return{valid:t.length===0,errors:t}}function o(e){switch(e.provider){case`aws`:return`https://s3.${e.region}.amazonaws.com`;case`cloudflare-r2`:return e.endpoint||`https://${e.accountId}.r2.cloudflarestorage.com`;case`digitalocean-spaces`:return e.endpoint||`https://${e.region}.digitaloceanspaces.com`;case`minio`:{let t=e.useSSL===!1?`http`:`https`,n=e.port?`:${e.port}`:``;return`${t}://${e.endpoint}${n}`}case`gcs`:return`https://storage.googleapis.com`;case`s3-compatible`:return e.endpoint;default:return``}}function s(e,t){async function n(n){try{let t=new URL(n.url),r=t.searchParams.get(`route`),i=t.searchParams.get(`action`)||`presign`;if(!r)return new Response(JSON.stringify({error:`Route parameter is required`}),{status:400,headers:{"Content-Type":`application/json`}});if(!e.getRouteNames().includes(r))return new Response(JSON.stringify({error:`Route "${r}" not found`}),{status:404,headers:{"Content-Type":`application/json`}});let a=await n.json();if(i===`presign`){let{files:t}=a;if(!Array.isArray(t))return new Response(JSON.stringify({error:`Files array is required`}),{status:400,headers:{"Content-Type":`application/json`}});let i=c(n),o=await e.generatePresignedUrls(r,i,t);return new Response(JSON.stringify({success:!0,results:o}),{status:200,headers:{"Content-Type":`application/json`}})}else if(i===`complete`){let{completions:t}=a;if(!Array.isArray(t))return new Response(JSON.stringify({error:`Completions array is required`}),{status:400,headers:{"Content-Type":`application/json`}});let i=c(n),o=await e.handleUploadComplete(r,i,t);return new Response(JSON.stringify({success:!0,results:o}),{status:200,headers:{"Content-Type":`application/json`}})}else return new Response(JSON.stringify({error:`Unknown action: ${i}`}),{status:400,headers:{"Content-Type":`application/json`}})}catch(e){let n=e instanceof Error?e:Error(`Unknown error`);return console.error(`S3 Handler Error:`,n),new Response(JSON.stringify({success:!1,error:n.message,details:t.debug?e:void 0}),{status:500,headers:{"Content-Type":`application/json`}})}}async function r(t){let n=e.getRouteNames();return new Response(JSON.stringify({success:!0,routes:n.map(e=>({name:e,type:`s3-upload`}))}),{status:200,headers:{"Content-Type":`application/json`}})}return{GET:r,POST:n}}function c(e){if(e.constructor.name===`NextRequest`)return e;let t=Object.create(e);return t}var l=e.__toESM(t.require_defineProperty(),1),u=class e{constructor(e,t={}){this.schema=e,this.config=t}middleware(t){let n={middleware:[...this.config.middleware||[],t]};return new e(this.schema,n)}paths(e){return this.config.paths={...this.config.paths,...e},this}onUploadStart(e){return this.config.onUploadStart=e,this}onUploadProgress(e){return this.config.onUploadProgress=e,this}onUploadComplete(e){return this.config.onUploadComplete=e,this}onUploadError(e){return this.config.onUploadError=e,this}_getConfig(){return{...this.config,schema:this.schema}}};function d(e,n,r,i,a,o){let s={file:e,metadata:n,globalConfig:a||{},routeName:r};if(i?.generateKey)return i.generateKey(s);let c=[],l=a?.prefix||`uploads`;c.push(l),i?.prefix&&c.push(i.prefix);let u;return a?.generateKey?(u=a.generateKey(e,n),u.startsWith(l+`/`)&&(u=u.substring(l.length+1))):u=t.generateFileKey(o,{originalName:e.name,userId:n?.userId||n?.user?.id,prefix:``}),c.push(u),i?.suffix&&c.push(i.suffix),c.join(`/`).replace(/\/+/g,`/`)}var f=class{constructor(e,t){(0,l.default)(this,`config`,void 0),(0,l.default)(this,`routes`,void 0),this.routes=e,this.config=t}getRoute(e){return this.routes[e]}getRouteNames(){return Object.keys(this.routes)}get handlers(){return s(this,this.config)}async generatePresignedUrls(e,n,r){let i=this.getRoute(e);if(!i)throw Error(`Route "${String(e)}" not found`);let a=i._getConfig(),o=this.config,s=[];for(let i of r)try{let r={},c=a.middleware||[];for(let e of c)r=await e({req:n,file:i,metadata:r});let l=new File([],i.name,{type:i.type});Object.defineProperty(l,`size`,{value:i.size});let u=await a.schema.validate(l);if(!u.success)throw Error(u.error?.message||`Validation failed`);a.onUploadStart&&await a.onUploadStart({file:i,metadata:r});let f=d({name:i.name,type:i.type},r,String(e),a.paths,o.paths,o),p=await t.generatePresignedUploadUrl(o,{key:f,contentType:i.type,contentLength:i.size,metadata:{originalName:i.name,userId:r.userId||r.user?.id||`anonymous`,routeName:String(e)}});s.push({success:!0,file:i,presignedUrl:p.url,key:p.key,metadata:r})}catch(e){let t=e instanceof Error?e:Error(`Failed to generate presigned URL`);a.onUploadError&&await a.onUploadError({file:i,metadata:{},error:t}),s.push({success:!1,file:i,error:t.message})}return s}async handleUploadComplete(e,n,r){let i=this.getRoute(e);if(!i)throw Error(`Route "${String(e)}" not found`);let a=i._getConfig(),o=[];for(let e of r)try{let n=t.getFileUrl(this.config,e.key);a.onUploadComplete&&await a.onUploadComplete({file:e.file,metadata:e.metadata||{},url:n,key:e.key}),o.push({success:!0,key:e.key,url:n,file:e.file})}catch(t){let n=t instanceof Error?t:Error(`Upload completion failed`);a.onUploadError&&await a.onUploadError({file:e.file,metadata:e.metadata||{},error:n}),o.push({success:!1,key:e.key,error:n.message})}return o}};function p(e,t){return new f(e,t)}var m=e.__toESM(t.require_defineProperty(),1),h=class{constructor(){(0,m.default)(this,`_constraints`,{}),(0,m.default)(this,`_transforms`,[]),(0,m.default)(this,`_validators`,[]),(0,m.default)(this,`_optional`,!1)}async validate(e,t){try{if(this._optional&&e==null)return{success:!0,data:void 0};let n=await this._parse(e);if(!n.success)return n;for(let n of this._validators){let r=await n({file:e,fieldName:t?.fieldName||`unknown`,allFiles:t?.allFiles});if(!r.success)return r}let r=n.data;for(let n of this._transforms)r=await n({file:e,metadata:t,originalData:r});return{success:!0,data:r}}catch(e){return{success:!1,error:{code:`VALIDATION_ERROR`,message:e instanceof Error?e.message:`Unknown validation error`,path:[t?.fieldName||`unknown`]}}}}optional(){let e=this._clone();return e._optional=!0,e}transform(e){let t=this._clone();return t._transforms.push(e),t}refine(e,t){let n=this._clone();return n._validators.push(async n=>{let r=await e(n);return r?{success:!0}:{success:!1,error:{code:`CUSTOM_VALIDATION`,message:t,path:[n.fieldName]}}}),n}},g=class e extends h{constructor(e={}){super(),this.constraints=e,(0,m.default)(this,`_type`,`file`),this._constraints={...e}}_parse(e){if(!(e instanceof File))return{success:!1,error:{code:`INVALID_TYPE`,message:`Expected File object`,path:[]}};if(this.constraints.maxSize){let t=this._parseSize(this.constraints.maxSize);if(e.size>t)return{success:!1,error:{code:`FILE_TOO_LARGE`,message:`File size ${this._formatSize(e.size)} exceeds maximum ${this._formatSize(t)}`,path:[]}}}if(this.constraints.minSize){let t=this._parseSize(this.constraints.minSize);if(e.size<t)return{success:!1,error:{code:`FILE_TOO_SMALL`,message:`File size ${this._formatSize(e.size)} is below minimum ${this._formatSize(t)}`,path:[]}}}if(this.constraints.allowedTypes?.length){let t=this.constraints.allowedTypes.some(t=>t.endsWith(`/*`)?e.type.startsWith(t.slice(0,-1)):e.type===t);if(!t)return{success:!1,error:{code:`INVALID_FILE_TYPE`,message:`File type ${e.type} is not allowed. Allowed types: ${this.constraints.allowedTypes.join(`, `)}`,path:[]}}}if(this.constraints.allowedExtensions?.length){let t=e.name.split(`.`).pop()?.toLowerCase();if(!t||!this.constraints.allowedExtensions.includes(t))return{success:!1,error:{code:`INVALID_FILE_EXTENSION`,message:`File extension .${t} is not allowed. Allowed extensions: ${this.constraints.allowedExtensions.join(`, `)}`,path:[]}}}return{success:!0,data:e}}max(t){return new e({...this.constraints,maxSize:t})}min(t){return new e({...this.constraints,minSize:t})}types(t){return new e({...this.constraints,allowedTypes:t})}extensions(t){return new e({...this.constraints,allowedExtensions:t})}array(e){return new v(this,e)}_clone(){return new e(this.constraints)}middleware(e){return new u(this).middleware(e)}onUploadStart(e){return new u(this).onUploadStart(e)}onUploadComplete(e){return new u(this).onUploadComplete(e)}onUploadError(e){return new u(this).onUploadError(e)}_parseSize(e){if(typeof e==`number`)return e;let t=e.match(/^(\d+(?:\.\d+)?)\s*(B|KB|MB|GB|TB)?$/i);if(!t)throw Error(`Invalid size format: ${e}`);let n=parseFloat(t[1]),r=(t[2]||`B`).toUpperCase(),i={B:1,KB:1024,MB:1024**2,GB:1024**3,TB:1024**4};return n*(i[r]||1)}_formatSize(e){let t=[`B`,`KB`,`MB`,`GB`,`TB`],n=e,r=0;for(;n>=1024&&r<t.length-1;)n/=1024,r++;return`${n.toFixed(r===0?0:1)}${t[r]}`}},_=class e extends g{constructor(e={}){let t={allowedTypes:[`image/*`],...e};super(t)}formats(t){let n=t.map(e=>{let t={jpg:`image/jpeg`,jpeg:`image/jpeg`,png:`image/png`,gif:`image/gif`,webp:`image/webp`,avif:`image/avif`,svg:`image/svg+xml`};return t[e.toLowerCase()]||`image/${e}`});return new e({...this.constraints,allowedTypes:n})}max(t){return new e({...this.constraints,maxSize:t})}min(t){return new e({...this.constraints,minSize:t})}types(t){return new e({...this.constraints,allowedTypes:t})}extensions(t){return new e({...this.constraints,allowedExtensions:t})}array(e){return new v(this,e)}_clone(){return new e(this.constraints)}},v=class e extends h{constructor(e,t={}){super(),this.elementSchema=e,this.arrayConstraints=t,(0,m.default)(this,`_type`,`array`)}async _parse(e){if(!Array.isArray(e))return{success:!1,error:{code:`INVALID_TYPE`,message:`Expected array of files`,path:[]}};if(this.arrayConstraints.min!==void 0&&e.length<this.arrayConstraints.min)return{success:!1,error:{code:`ARRAY_TOO_SHORT`,message:`Array must have at least ${this.arrayConstraints.min} items`,path:[]}};if(this.arrayConstraints.max!==void 0&&e.length>this.arrayConstraints.max)return{success:!1,error:{code:`ARRAY_TOO_LONG`,message:`Array must have at most ${this.arrayConstraints.max} items`,path:[]}};if(this.arrayConstraints.length!==void 0&&e.length!==this.arrayConstraints.length)return{success:!1,error:{code:`ARRAY_WRONG_LENGTH`,message:`Array must have exactly ${this.arrayConstraints.length} items`,path:[]}};let t=[];for(let n=0;n<e.length;n++){let r=await this.elementSchema.validate(e[n],{fieldName:`[${n}]`});if(!r.success)return{success:!1,error:{...r.error,path:[`[${n}]`,...r.error.path]}};t.push(r.data)}return{success:!0,data:t}}min(t){return new e(this.elementSchema,{...this.arrayConstraints,min:t})}max(t){return new e(this.elementSchema,{...this.arrayConstraints,max:t})}length(t){return new e(this.elementSchema,{...this.arrayConstraints,length:t})}_clone(){return new e(this.elementSchema,this.arrayConstraints)}},y=class e extends h{constructor(e){super(),this.shape=e,(0,m.default)(this,`_type`,`object`)}async _parse(e){if(!e||typeof e!=`object`)return{success:!1,error:{code:`INVALID_TYPE`,message:`Expected object`,path:[]}};let t={},n=e;for(let[e,r]of Object.entries(this.shape)){let i=await r.validate(n[e],{fieldName:e,allFiles:n});if(!i.success)return{success:!1,error:{...i.error,path:[e,...i.error.path]}};i.data!==void 0&&(t[e]=i.data)}return{success:!0,data:t}}_clone(){return new e(this.shape)}},b=e.__toESM(t.require_defineProperty(),1),x=class{constructor(e){if((0,b.default)(this,`config`,void 0),(0,b.default)(this,`list`,{files:e=>t.listFiles(this.config,e),paginated:e=>t.listFilesPaginated(this.config,e),byExtension:(e,n)=>t.listFilesByExtension(this.config,e,n),bySize:(e,n,r)=>t.listFilesBySize(this.config,e,n,r),byDate:(e,n,r)=>t.listFilesByDate(this.config,e,n,r),directories:e=>t.listDirectories(this.config,e),paginatedGenerator:e=>t.listFilesPaginatedGenerator(this.config,e)}),(0,b.default)(this,`metadata`,{getInfo:e=>t.getFileInfo(this.config,e),getBatch:e=>t.getFilesInfo(this.config,e),getSize:e=>t.getFileSize(this.config,e),getContentType:e=>t.getFileContentType(this.config,e),getLastModified:e=>t.getFileLastModified(this.config,e),getCustom:e=>t.getFileMetadata(this.config,e),setCustom:(e,n)=>t.setFileMetadata(this.config,e,n)}),(0,b.default)(this,`download`,{presignedUrl:(e,n)=>t.generatePresignedDownloadUrl(this.config,e,n),url:e=>t.getFileUrl(this.config,e)}),(0,b.default)(this,`upload`,{file:(e,n,r)=>t.uploadFileToS3(this.config,e,n,r),presignedUrl:e=>t.generatePresignedUploadUrl(this.config,e),presignedBatch:e=>t.generatePresignedUploadUrls(this.config,e),generateKey:e=>t.generateFileKey(this.config,e)}),(0,b.default)(this,`validation`,{exists:e=>t.checkFileExists(this.config,e),existsWithInfo:e=>t.fileExistsWithInfo(this.config,e),validateFile:(e,n)=>t.validateFile(this.config,e,n),validateFiles:(e,n)=>t.validateFiles(this.config,e,n),connection:()=>t.validateS3Connection(this.config)}),(0,b.default)(this,`delete`,{file:e=>t.deleteFile(this.config,e),files:e=>t.deleteFiles(this.config,e),byPrefix:(e,n)=>t.deleteFilesByPrefix(this.config,e,n)}),!e)throw Error(`StorageInstance requires a valid configuration`);this.config=Object.freeze(e)}getConfig(){return this.config}getProviderInfo(){return{provider:this.config.provider.provider,bucket:this.config.provider.bucket,region:this.config.provider.region}}};function S(e){return new x(e)}var C=e.__toESM(t.require_defineProperty(),1),w=class{constructor(e={}){(0,C.default)(this,`metrics`,[]),(0,C.default)(this,`maxMetricsHistory`,1e3),(0,C.default)(this,`isEnabled`,void 0),this.isEnabled=e.enabled??!1}startOperation(e,t){if(!this.isEnabled)return``;let n=`${e}_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,r={operation:e,startTime:performance.now(),success:!1,metadata:{operationId:n,...t}};return this.metrics.push(r),this.trimMetricsHistory(),n}endOperation(e,t,n){if(!this.isEnabled||!e)return;let r=this.metrics.find(t=>t.metadata?.operationId===e);if(!r)return;let i=performance.now();r.endTime=i,r.duration=i-r.startTime,r.success=t,r.fileSize=n?.fileSize,r.provider=n?.provider,r.errorCode=n?.errorCode,n?.metadata&&(r.metadata={...r.metadata,...n.metadata})}recordOperation(e,t,n,r){if(!this.isEnabled)return;let i={operation:e,startTime:performance.now()-t,endTime:performance.now(),duration:t,success:n,fileSize:r?.fileSize,provider:r?.provider,errorCode:r?.errorCode,metadata:r?.metadata};this.metrics.push(i),this.trimMetricsHistory()}getAggregatedMetrics(e){let t=e?Date.now()-e:0,n=this.metrics.filter(e=>e.endTime&&e.startTime>=t),r=n.length,i=n.filter(e=>e.success).length,a=r-i,o=r>0?i/r*100:0,s=n.filter(e=>e.duration!==void 0).map(e=>e.duration),c=s.length>0?s.reduce((e,t)=>e+t,0)/s.length:0,l=n.filter(e=>e.fileSize!==void 0).reduce((e,t)=>e+(t.fileSize||0),0),u=n.reduce((e,t)=>(e[t.operation]=(e[t.operation]||0)+1,e),{}),d=n.filter(e=>!e.success&&e.errorCode).reduce((e,t)=>(e[t.errorCode]=(e[t.errorCode]||0)+1,e),{}),f=n.filter(e=>e.provider).reduce((e,t)=>(e[t.provider]=(e[t.provider]||0)+1,e),{});return{totalOperations:r,successfulOperations:i,failedOperations:a,successRate:o,averageDuration:c,totalDataTransferred:l,operationsByType:u,errorsByCode:d,providerUsage:f}}getRawMetrics(){return[...this.metrics]}clearMetrics(){this.metrics=[]}getPerformanceSummary(){let e=this.getAggregatedMetrics();return` 📊 Pushduck Performance Summary ================================ Total Operations: ${e.totalOperations} Success Rate: ${e.successRate.toFixed(1)}% Average Duration: ${e.averageDuration.toFixed(1)}ms Data Transferred: ${this.formatBytes(e.totalDataTransferred)} Operations by Type: ${Object.entries(e.operationsByType).map(([e,t])=>` ${e}: ${t}`).join(` `)} ${Object.keys(e.errorsByCode).length>0?` Errors by Code: ${Object.entries(e.errorsByCode).map(([e,t])=>` ${e}: ${t}`).join(` `)} `:``} Provider Usage: ${Object.entries(e.providerUsage).map(([e,t])=>` ${e}: ${t}`).join(` `)} `.trim()}trimMetricsHistory(){this.metrics.length>this.maxMetricsHistory&&(this.metrics=this.metrics.slice(-this.maxMetricsHistory))}formatBytes(e){if(e===0)return`0 Bytes`;let t=1024,n=[`Bytes`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/t**+r).toFixed(2))+` `+n[r]}setEnabled(e){this.isEnabled=e}isMetricsEnabled(){return this.isEnabled}};const T=new w,E=(e,t)=>T.startOperation(e,t),D=(e,t,n)=>T.endOperation(e,t,n),O=(e,t,n,r)=>T.recordOperation(e,t,n,r);function k(e){return function(t,n,r){let i=r.value;return r.value=async function(...t){let r=E(e,{method:n,args:t.length});try{let e=await i.apply(this,t);return D(r,!0),e}catch(e){throw D(r,!1,{errorCode:e instanceof Error?e.name:`UNKNOWN_ERROR`}),e}},r}}var A=e.__toESM(t.require_defineProperty(),1);function j(e,t){let n={};for(let[t,r]of Object.entries(e))r instanceof g||r instanceof _||r instanceof y?n[t]=new u(r):n[t]=r;return p(n,t)}function M(e){return{file:e=>new g(e),image:e=>new _(e),object:e=>new y(e),createRouter:t=>j(t,e)}}var N=class{constructor(){(0,A.default)(this,`config`,{})}provider(e,t){return typeof e==`string`?this.config.provider=i(e,t):this.config.provider=e,this}defaults(e){return this.config.defaults={...this.config.defaults,...e},this}paths(e){return this.config.paths={...this.config.paths,...e},this}security(e){return this.config.security={...this.config.security,...e},this}hooks(e){return this.config.hooks={...this.config.hooks,...e},this}debug(e=!0){return this.config.debug=e,this}metrics(e=!0){return this.config.enableMetrics=e,this}build(){if(!this.config.provider)throw Error(`Provider configuration is required`);let e=a(this.config.provider);if(!e.valid)throw Error(`Invalid provider configuration: ${e.errors.join(`, `)}`);let n=this.config;n.debug!==void 0&&t.logger.setDebugMode(n.debug),n.enableMetrics!==void 0&&T.setEnabled(n.enableMetrics);let r=S(n),i=M(n);return t.logger.info(`📦 Upload configuration initialized`,{provider:n.provider.provider}),{config:n,storage:r,s3:i}}};function P(){return new N}Object.defineProperty(exports,`S3ArraySchema`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`S3FileSchema`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`S3ImageSchema`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`S3ObjectSchema`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`S3Route`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`S3Schema`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`StorageInstance`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`createProvider`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`createS3RouterWithConfig`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`createStorage`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`createUploadConfig`,{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,`endOperation`,{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,`getProviderEndpoint`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`metrics`,{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,`recordOperation`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`startOperation`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,`trackOperation`,{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,`validateProviderConfig`,{enumerable:!0,get:function(){return a}});