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) • 21.6 kB
JavaScript
import{A as e,C as t,D as n,E as r,H as i,O as a,S as o,_ as s,a as c,b as l,c as u,d,f,g as p,h as m,i as h,j as g,k as _,l as v,m as y,o as b,p as x,r as S,s as C,t as w,u as T,v as E,w as D,x as O,y as k}from"./client-CPi8kVKS.mjs";function A(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=N(n);if(!r.valid)throw Error(`Provider validation failed: ${r.errors.join(`, `)}`);return n}}const j={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`],forcePathStyle:[`S3_FORCE_PATH_STYLE`]},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 M(e,t={}){let n=j[e];if(!n)throw Error(`Unknown provider type: ${e}`);return A(n)(t)}function N(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 P(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 F(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,metadata:i}=a;if(!Array.isArray(t))return new Response(JSON.stringify({error:`Files array is required`}),{status:400,headers:{"Content-Type":`application/json`}});let o=await e.generatePresignedUrls(r,n,t,i);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=await e.handleUploadComplete(r,n,t);return new Response(JSON.stringify({success:!0,results:i}),{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}}var I=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 L(e,t,n,r,i,a){let o={file:e,metadata:t,globalConfig:i||{},routeName:n};if(r?.generateKey)return r.generateKey(o);let s=[],c=i?.prefix||`uploads`;s.push(c),r?.prefix&&s.push(r.prefix);let l;return i?.generateKey?(l=i.generateKey(e,t),l.startsWith(c+`/`)&&(l=l.substring(c.length+1))):l=C(a,{originalName:e.name,userId:t?.userId||t?.user?.id,prefix:``}),s.push(l),r?.suffix&&s.push(r.suffix),s.join(`/`).replace(/\/+/g,`/`)}var R=class{constructor(e,t){i(this,`config`,void 0),i(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 F(this,this.config)}async generatePresignedUrls(e,t,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 n){let n=r||{};try{let r=a.middleware||[];for(let e of r)n=await e({req:t,file:i,metadata:n});let c=new File([],i.name,{type:i.type});Object.defineProperty(c,`size`,{value:i.size});let l=await a.schema.validate(c);if(!l.success)throw Error(l.error?.message||`Validation failed`);a.onUploadStart&&await a.onUploadStart({file:i,metadata:n});let u=await v(o,{key:L({name:i.name,type:i.type},n,String(e),a.paths,o.paths,o),contentType:i.type,contentLength:i.size,metadata:{originalName:i.name,userId:n.userId||n.user?.id||`anonymous`,routeName:String(e)}});s.push({success:!0,file:i,presignedUrl:u.url,key:u.key,metadata:n})}catch(e){let t=e instanceof Error?e:Error(`Failed to generate presigned URL`);a.onUploadError&&await a.onUploadError({file:i,metadata:n,error:t}),s.push({success:!1,file:i,error:t.message})}}return s}async handleUploadComplete(e,t,n){let r=this.getRoute(e);if(!r)throw Error(`Route "${String(e)}" not found`);let i=r._getConfig(),a=[];for(let e of n)try{let t=p(this.config,e.key),n=await u(this.config,e.key,3600);i.onUploadComplete&&await i.onUploadComplete({file:e.file,metadata:e.metadata||{},url:t,key:e.key}),a.push({success:!0,key:e.key,url:t,presignedUrl:n,file:e.file})}catch(t){let n=t instanceof Error?t:Error(`Upload completion failed`);i.onUploadError&&await i.onUploadError({file:e.file,metadata:e.metadata||{},error:n}),a.push({success:!1,key:e.key,error:n.message})}return a}};function z(e,t){return new R(e,t)}var B=class{constructor(){i(this,`_constraints`,{}),i(this,`_transforms`,[]),i(this,`_validators`,[]),i(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=>await e(n)?{success:!0}:{success:!1,error:{code:`CUSTOM_VALIDATION`,message:t,path:[n.fieldName]}}),n}},V=class e extends B{constructor(e={}){super(),this.constraints=e,i(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&&!this.constraints.allowedTypes.some(t=>t.endsWith(`/*`)?e.type.startsWith(t.slice(0,-1)):e.type===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 console.warn("⚠️ The `max()` method is deprecated. Use `maxFileSize()` instead."),new e({...this.constraints,maxSize:t})}maxFileSize(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})}maxFiles(e){return new U(this,{max:e})}_clone(){return new e(this.constraints)}middleware(e){return new I(this).middleware(e)}onUploadStart(e){return new I(this).onUploadStart(e)}onUploadComplete(e){return new I(this).onUploadComplete(e)}onUploadError(e){return new I(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}`);return parseFloat(t[1])*({B:1,KB:1024,MB:1024**2,GB:1024**3,TB:1024**4}[(t[2]||`B`).toUpperCase()]||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]}`}},H=class e extends V{constructor(e={}){let t={allowedTypes:[`image/*`],...e};super(t)}formats(t){let n=t.map(e=>({jpg:`image/jpeg`,jpeg:`image/jpeg`,png:`image/png`,gif:`image/gif`,webp:`image/webp`,avif:`image/avif`,svg:`image/svg+xml`})[e.toLowerCase()]||`image/${e}`);return new e({...this.constraints,allowedTypes:n})}max(t){return console.warn("⚠️ The `max()` method is deprecated. Use `maxFileSize()` instead."),new e({...this.constraints,maxSize:t})}maxFileSize(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})}maxFiles(e){return new U(this,{max:e})}_clone(){return new e(this.constraints)}},U=class e extends B{constructor(e,t={}){super(),this.elementSchema=e,this.arrayConstraints=t,i(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)}},W=class e extends B{constructor(e){super(),this.shape=e,i(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)}},G=class{constructor(g){if(i(this,`config`,void 0),i(this,`list`,{files:e=>k(this.config,e),paginated:e=>t(this.config,e),byExtension:(e,t)=>O(this.config,e,t),bySize:(e,t,n)=>o(this.config,e,t,n),byDate:(e,t,n)=>l(this.config,e,t,n),directories:e=>E(this.config,e),paginatedGenerator:e=>D(this.config,e)}),i(this,`metadata`,{getInfo:e=>f(this.config,e),getBatch:e=>s(this.config,e),getSize:e=>m(this.config,e),getContentType:e=>d(this.config,e),getLastModified:e=>x(this.config,e),getCustom:e=>y(this.config,e),setCustom:(e,t)=>r(this.config,e,t)}),i(this,`download`,{presignedUrl:(e,t)=>u(this.config,e,t),url:e=>p(this.config,e)}),i(this,`upload`,{file:(e,t,r)=>n(this.config,e,t,r),presignedUrl:e=>v(this.config,e),presignedBatch:e=>T(this.config,e),generateKey:e=>C(this.config,e)}),i(this,`validation`,{exists:e=>w(this.config,e),existsWithInfo:e=>b(this.config,e),validateFile:(e,t)=>a(this.config,e,t),validateFiles:(e,t)=>_(this.config,e,t),connection:()=>e(this.config)}),i(this,`delete`,{file:e=>S(this.config,e),files:e=>h(this.config,e),byPrefix:(e,t)=>c(this.config,e,t)}),!g)throw Error(`StorageInstance requires a valid configuration`);this.config=Object.freeze(g)}getConfig(){return this.config}getProviderInfo(){return{provider:this.config.provider.provider,bucket:this.config.provider.bucket,region:this.config.provider.region}}};function K(e){return new G(e)}const q=new class{constructor(e={}){i(this,`metrics`,[]),i(this,`maxMetricsHistory`,1e3),i(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);return{totalOperations:r,successfulOperations:i,failedOperations:a,successRate:o,averageDuration:s.length>0?s.reduce((e,t)=>e+t,0)/s.length:0,totalDataTransferred:n.filter(e=>e.fileSize!==void 0).reduce((e,t)=>e+(t.fileSize||0),0),operationsByType:n.reduce((e,t)=>(e[t.operation]=(e[t.operation]||0)+1,e),{}),errorsByCode:n.filter(e=>!e.success&&e.errorCode).reduce((e,t)=>(e[t.errorCode]=(e[t.errorCode]||0)+1,e),{}),providerUsage:n.filter(e=>e.provider).reduce((e,t)=>(e[t.provider]=(e[t.provider]||0)+1,e),{})}}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}},J=(e,t)=>q.startOperation(e,t),Y=(e,t,n)=>q.endOperation(e,t,n),X=(e,t,n,r)=>q.recordOperation(e,t,n,r);function Z(e){return function(t,n,r){let i=r.value;return r.value=async function(...t){let r=J(e,{method:n,args:t.length});try{let e=await i.apply(this,t);return Y(r,!0),e}catch(e){throw Y(r,!1,{errorCode:e instanceof Error?e.name:`UNKNOWN_ERROR`}),e}},r}}function Q(e,t){let n={};for(let[t,r]of Object.entries(e))r instanceof V||r instanceof H||r instanceof W?n[t]=new I(r):n[t]=r;return z(n,t)}function $(e){return{file:e=>new V(e),image:e=>new H(e),object:e=>new W(e),createRouter:t=>Q(t,e)}}var ee=class{constructor(){i(this,`config`,{})}provider(e,t){return typeof e==`string`?this.config.provider=M(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=N(this.config.provider);if(!e.valid)throw Error(`Invalid provider configuration: ${e.errors.join(`, `)}`);let t=this.config;return t.debug!==void 0&&g.setDebugMode(t.debug),t.enableMetrics!==void 0&&q.setEnabled(t.enableMetrics),g.info(`📦 Upload configuration initialized`,{provider:t.provider.provider}),{config:t,storage:K(t),s3:$(t)}}};function te(){return new ee}export{P as _,J as a,K as c,H as d,W as f,M as g,z as h,X as i,U as l,I as m,Y as n,Z as o,B as p,q as r,G as s,te as t,V as u,N as v};