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.

1 lines 4.41 kB
"use client";const e=require(`./chunk-CEIYHHoD.js`),t=e.__toESM(require(`react`));function n(e){return e<60?`${Math.round(e)}s`:e<3600?`${Math.round(e/60)}m`:`${Math.round(e/3600)}h`}function r(e){let t=[`B/s`,`KB/s`,`MB/s`,`GB/s`],n=e,r=0;for(;n>=1024&&r<t.length-1;)n/=1024,r++;return`${n.toFixed(1)} ${t[r]}`}async function i(e,t,n){return new Promise((r,i)=>{let a=new XMLHttpRequest,o=Date.now();a.upload.onprogress=e=>{if(e.lengthComputable&&n){let t=Math.round(e.loaded/e.total*100),r=(Date.now()-o)/1e3,i=e.loaded/r,a=e.total-e.loaded,s=a/i;n(t,i,s)}},a.onload=()=>{a.status>=200&&a.status<300?r():i(Error(`Upload failed with status: ${a.status}`))},a.onerror=()=>i(Error(`Upload failed`)),a.onabort=()=>i(Error(`Upload aborted`)),a.open(`PUT`,t),a.setRequestHeader(`Content-Type`,e.type),a.send(e)})}function a(e,n={}){let[r,a]=(0,t.useState)([]),[o,s]=(0,t.useState)(!1),[c,l]=(0,t.useState)([]),[u,d]=(0,t.useState)(0),[f,p]=(0,t.useState)(0),[m,h]=(0,t.useState)(0),g=(0,t.useRef)(new Map),_=(0,t.useCallback)(e=>{if(e.length===0){d(0),p(0),h(0);return}let t=e.filter(e=>e.status===`uploading`||e.status===`success`);if(t.length===0){d(0),p(0),h(0);return}let r=t.reduce((e,t)=>e+t.size,0),i=t.reduce((e,t)=>{let n=t.status===`success`?100:t.progress||0;return e+t.size*n/100},0),a=r>0?i/r*100:0,o=t.reduce((e,t)=>e+(t.uploadSpeed||0),0),s=r-i,c=o>0?s/o:0,l=Math.min(100,Math.max(0,a));d(l),p(o),h(c),n.onProgress?.(l)},[n.onProgress]),v=(0,t.useCallback)(()=>{g.current.forEach(e=>e.abort()),g.current.clear(),a([]),l([]),s(!1),d(0),p(0),h(0)},[]),y=(0,t.useCallback)((e,t,n,r)=>{a(i=>{let a=i.map(i=>i.id===e?{...i,progress:t,uploadSpeed:n,eta:r}:i);return _(a),a})},[_]),b=(0,t.useCallback)((e,t,n={})=>{a(r=>{let i=r.map(r=>r.id===e?{...r,status:t,...n}:r);return _(i),i})},[_]),x=(0,t.useCallback)(async t=>{if(!t.length){s(!1);return}try{s(!0),l([]);let r=t.map(e=>({name:e.name,size:e.size,type:e.type})),o=t.map((e,t)=>({id:`${Date.now()}-${t}`,name:e.name,size:e.size,type:e.type,status:`pending`,progress:0,file:e}));a(o);let c=n.endpoint||`/api/s3-upload`,u=await fetch(`${c}?route=${String(e)}&action=presign`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({files:r})});if(!u.ok){let e=await u.json(),t=e.error||`Server error: ${u.statusText}`;a(e=>e.map(e=>({...e,status:`error`,error:t}))),n.onError?.(Error(t));return}let d=await u.json();if(!d.success){let e=d.error||`Failed to get presigned URLs`;a(t=>t.map(t=>({...t,status:`error`,error:e}))),n.onError?.(Error(e));return}n.onStart&&await n.onStart(r),n.onProgress?.(0);let f=d.results.map(async(e,r)=>{let a=t[r],s=o[r];if(!e.success){let t=e.error||`Failed to get presigned URL`;return b(s.id,`error`,{error:t}),n.onError?.(Error(t)),null}try{return b(s.id,`uploading`,{uploadStartTime:Date.now()}),await i(a,e.presignedUrl,(e,t,n)=>y(s.id,e,t,n)),b(s.id,`success`,{progress:100,key:e.key}),{key:e.key,file:{name:a.name,size:a.size,type:a.type},metadata:e.metadata}}catch(e){let t=e instanceof Error?e.message:`Upload failed`;return b(s.id,`error`,{error:t}),n.onError?.(e instanceof Error?e:Error(t)),null}}),p=await Promise.all(f),m=p.filter(Boolean);if(m.length>0)try{let t=await fetch(`${c}?route=${String(e)}&action=complete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({completions:m})});if(t.ok){let e=await t.json();e.success&&e.results&&e.results.forEach(e=>{if(e.success&&e.key){let t=m.find(t=>t?.key===e.key);if(t){let n=o.find(e=>e.name===t.file.name&&e.size===t.file.size);n&&b(n.id,`success`,{url:e.url,key:e.key,presignedUrl:e.presignedUrl,progress:100})}}})}}catch(e){console.warn(`Failed to notify server of upload completion:`,e)}n.onSuccess&&a(e=>{let t=e.filter(e=>e.status===`success`);return t.length>0&&n.onSuccess?.(t),e})}catch(e){let t=e instanceof Error?e.message:`Upload failed`;l(e=>[...e,t]),a(e=>e.map(e=>e.status===`success`||e.status===`error`?e:{...e,status:`error`,error:t})),n.onError?.(e instanceof Error?e:Error(t))}finally{s(!1),g.current.clear()}},[e,n,y,b]);return{files:r,uploadFiles:x,reset:v,isUploading:o,errors:c,progress:u,uploadSpeed:f,eta:m}}Object.defineProperty(exports,`formatETA`,{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,`formatUploadSpeed`,{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,`useUploadRoute`,{enumerable:!0,get:function(){return a}});