offline-data-manager 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
var V="offline-data-manager",Z=1,L=null,i={REGISTRY:"registry",DOWNLOAD_QUEUE:"downloadQueue"};async function J(e,t){V=e??"offline-data-manager",Z=t??1}async function U(){return L||(L=await new Promise((e,t)=>{let r=indexedDB.open(V,Z);r.onupgradeneeded=a=>{let o=a.target.result;if(!o.objectStoreNames.contains(i.REGISTRY)){let n=o.createObjectStore(i.REGISTRY,{keyPath:"id"});n.createIndex("protected","protected",{unique:!1}),n.createIndex("priority","priority",{unique:!1})}if(!o.objectStoreNames.contains(i.DOWNLOAD_QUEUE)){let n=o.createObjectStore(i.DOWNLOAD_QUEUE,{keyPath:"id"});n.createIndex("status","status",{unique:!1}),n.createIndex("priority","priority",{unique:!1})}},r.onsuccess=()=>e(r.result),r.onerror=()=>t(r.error)}),L)}async function p(e,t){let r=await U();return new Promise((a,o)=>{let n=r.transaction(e,"readonly").objectStore(e).get(t);n.onsuccess=()=>a(n.result),n.onerror=()=>o(n.error)})}async function E(e){let t=await U();return new Promise((r,a)=>{let o=t.transaction(e,"readonly").objectStore(e).getAll();o.onsuccess=()=>r(o.result),o.onerror=()=>a(o.error)})}async function N(e){let t=await U();return new Promise((r,a)=>{let o=t.transaction(e,"readonly").objectStore(e).getAllKeys();o.onsuccess=()=>r(o.result),o.onerror=()=>a(o.error)})}async function y(e,t){let r=await U();return new Promise((a,o)=>{let n=r.transaction(e,"readwrite").objectStore(e).put(t);n.onsuccess=()=>a(),n.onerror=()=>o(n.error),n.onerror=()=>o(n.error)})}async function S(e,t){let r=await U();return new Promise((a,o)=>{let n=r.transaction(e,"readwrite").objectStore(e).delete(t);n.onsuccess=()=>a(),n.onerror=()=>o(n.error)})}var T=new Map;function q(e,t){return T.has(e)||T.set(e,new Set),T.get(e).add(t),()=>P(e,t)}function P(e,t){T.get(e)?.delete(t)}function u(e,t){T.get(e)?.forEach(r=>{try{r(t)}catch(a){console.error(`[offline-data-manager] Error in "${e}" listener:`,a)}})}function ee(e,t){let r=a=>{t(a),P(e,r)};q(e,r)}async function I(){if(!navigator?.storage?.estimate)return{usage:0,quota:1/0,available:1/0};let{usage:e=0,quota:t=1/0}=await navigator.storage.estimate();return{usage:e,quota:t,available:t-e}}async function te(e){let{available:t,quota:r}=await I();return t-r*.1>=e}async function re(){return navigator?.storage?.persist?navigator.storage.persist():!1}async function ne(){return navigator?.storage?.persisted?navigator.storage.persisted():!1}function M(e){return e===1/0?"\u221E":e<1024?`${e} B`:e<1024**2?`${(e/1024).toFixed(1)} KB`:e<1024**3?`${(e/1024**2).toFixed(1)} MB`:`${(e/1024**3).toFixed(2)} GB`}var G=null,B=null,v=!1,W=!0;function oe(){u("connectivity",{online:!1}),G?.()}function ae(){u("connectivity",{online:!0}),B?.()}function ie({pauseAll:e,resumeAll:t}){v||!window||(G=e,B=t,window&&(window.addEventListener("offline",oe),window.addEventListener("online",ae)),v=!0)}function $(){window&&(window.removeEventListener("offline",oe),window.removeEventListener("online",ae)),G=null,B=null,v=!1}function _(){return window?navigator.onLine??!0:W}function Y(){return v}function se(e){W=e,v&&(W?B?.():G?.())}var Oe=2*1024*1024,xe=5*1024*1024,Ue=2,le=5,Te=1e3,g=new Map,b=!1,C=null;function ue(){return new Promise(e=>{C=e})}function h(){if(C){let e=C;C=null,e()}}var Ie=e=>new Promise(t=>setTimeout(t,e)),ve=e=>Te*Math.pow(2,e);async function m(e,t){let r=await p(i.DOWNLOAD_QUEUE,e);r&&await y(i.DOWNLOAD_QUEUE,{...r,...t})}async function _e(e,t){try{let r=await fetch(e,{method:"HEAD",signal:t}),a=r.headers.get("Accept-Ranges")==="bytes",o=r.headers.get("Content-Encoding"),n=!!o&&o!=="identity",s=r.headers.get("Content-Length"),l=s&&!n?parseInt(s,10):null,c=de(r.headers.get("Content-Type"));return{supportsRange:a,totalBytes:l,mimeType:c}}catch{return{supportsRange:!1,totalBytes:null,mimeType:null}}}function de(e){return e&&e.split(";")[0].trim()||null}function ce(e){let t=e.reduce((o,n)=>o+n.byteLength,0),r=new Uint8Array(t),a=0;for(let o of e)r.set(o,a),a+=o.byteLength;return r}async function Le(e){let{id:t,downloadUrl:r,ttl:a}=e,o=new AbortController;g.set(t,o);let n=await p(i.DOWNLOAD_QUEUE,t),s=n?.retryCount??0;for(;s<=le;)try{await m(t,{status:d.IN_PROGRESS,lastAttemptAt:Date.now(),retryCount:s,errorMessage:null}),u("status",{id:t,status:d.IN_PROGRESS}),n=await p(i.DOWNLOAD_QUEUE,t);let l=n?.byteOffset??0,c=!1,f=n?.totalBytes??e.totalBytes??null,w=e.mimeType??null;if(l===0){let R=await _e(r,o.signal);c=R.supportsRange,R.totalBytes&&(f=R.totalBytes,await m(t,{totalBytes:f})),!w&&R.mimeType&&(w=R.mimeType)}else c=!0;let D=c&&f&&f>xe,A,x=null;if(D)A=await Pe(t,r,l,f,o.signal);else{let R=await Ne(t,r,o.signal);A=R.uint8,x=R.mimeType}let K=w??x??"application/octet-stream",F=A.buffer,z=Date.now(),he=ye(z,a);await m(t,{status:d.COMPLETE,data:F,mimeType:K,bytesDownloaded:F.byteLength,byteOffset:F.byteLength,completedAt:z,expiresAt:he,errorMessage:null,deferredReason:null}),u("complete",{id:t,mimeType:K}),g.delete(t);return}catch(l){if(l?.name==="QuotaExceededError"){await k(),await m(t,{status:d.DEFERRED,deferredReason:"insufficient-storage"}),u("error",{id:t,reason:"insufficient-storage",willRetry:!1});return}else if(l?.name==="AbortError"){await m(t,{status:d.PAUSED}),u("status",{id:t,status:d.PAUSED}),g.delete(t);return}if(s++,s>le){await m(t,{status:d.FAILED,retryCount:s,errorMessage:l.message}),u("error",{id:t,error:l,retryCount:s}),g.delete(t);return}let c=ve(s-1);console.warn(`[offline-data-manager] "${t}" failed (attempt ${s}), retrying in ${c}ms:`,l.message),u("error",{id:t,error:l,retryCount:s,willRetry:!0}),await m(t,{status:d.PENDING,retryCount:s,errorMessage:l.message}),await Ie(c)}}async function Ne(e,t,r){let a=await fetch(t,{signal:r});if(!a.ok)throw new Error(`HTTP ${a.status} ${a.statusText}`);let o=a.headers.get("Content-Encoding"),n=!!o&&o!=="identity",s=a.headers.get("Content-Length"),l=s&&!n?parseInt(s,10):null,c=de(a.headers.get("Content-Type")),f=a.body.getReader(),w=[],D=0;for(;;){let{done:A,value:x}=await f.read();if(A)break;w.push(x),D+=x.byteLength,await m(e,{bytesDownloaded:D,totalBytes:l}),u("progress",{id:e,bytesDownloaded:D,totalBytes:l,percent:l?Math.round(D/l*100):null})}return{uint8:ce(w),mimeType:c}}async function Pe(e,t,r,a,o){let n=r,s=[],l=r;for(;n<a;){let c=Math.min(n+Oe-1,a-1),f=await fetch(t,{signal:o,headers:{Range:`bytes=${n}-${c}`}});if(!f.ok&&f.status!==206)throw new Error(`HTTP ${f.status} on Range bytes=${n}-${c}`);let w=new Uint8Array(await f.arrayBuffer());s.push(w),n+=w.byteLength,l+=w.byteLength,await m(e,{bytesDownloaded:l,byteOffset:n}),u("progress",{id:e,bytesDownloaded:l,totalBytes:a,percent:Math.round(l/a*100)})}return ce(s)}async function Me(e){await Ee();let[t,r]=await Promise.all([E(i.REGISTRY),E(i.DOWNLOAD_QUEUE)]),a=new Map(t.map(l=>[l.id,l])),o=r.filter(l=>[d.PENDING,d.IN_PROGRESS,d.PAUSED,d.DEFERRED,d.EXPIRED].includes(l.status)).sort((l,c)=>(a.get(l.id)?.priority??10)-(a.get(c.id)?.priority??10));if(o.length===0)return;let n=[...o],s=new Set;await new Promise(l=>{function c(){if(!b){l();return}if(n.length===0){s.size===0&&l();return}if(s.size>=e)return;let f=n.shift(),w=a.get(f.id);if(!w){c();return}let D=(async()=>{let A=w.totalBytes??f.totalBytes??0;if(A>0&&!await te(A)){await m(f.id,{status:d.DEFERRED,deferredReason:"insufficient-storage"}),u("deferred",{id:f.id,reason:"insufficient-storage"});return}await Le(w)})().finally(()=>{s.delete(D),c()});s.add(D),c()}c()})}function fe({concurrency:e=Ue}={}){b||(b=!0,(async()=>{for(;b;){if(!_()){let t=await E(i.DOWNLOAD_QUEUE);for(let r of t)r.status===d.IN_PROGRESS&&(g.get(r.id)?.abort(),g.delete(r.id),await m(r.id,{status:d.PAUSED,deferredReason:"network-offline"}));u("connectivity",{online:!1}),await ue();continue}await Me(e),b&&await ue()}})())}async function k(){b=!1,h(),await O(),u("stopped",{})}async function pe(){let e=await E(i.DOWNLOAD_QUEUE);for(let t of e)t.status===d.FAILED&&await m(t.id,{status:d.PENDING,retryCount:0,errorMessage:null});h()}function we(){return b}async function Q(e){g.get(e)?.abort(),g.delete(e)}async function O(){for(let[e,t]of g)t.abort(),g.delete(e)}function me(){ie({pauseAll:O,resumeAll:h})}var d={PENDING:"pending",IN_PROGRESS:"in-progress",PAUSED:"paused",COMPLETE:"complete",EXPIRED:"expired",FAILED:"failed",DEFERRED:"deferred"},j=new Set([d.COMPLETE,d.EXPIRED]);function Ge(e){if(!e||typeof e!="object")throw new Error("Registry entry must be an object.");if(!e.id||typeof e.id!="string")throw new Error('Registry entry must have a string "id".');if(!e.downloadUrl||typeof e.downloadUrl!="string")throw new Error(`Entry "${e.id}" must have a string "downloadUrl".`);if(e.mimeType!==void 0&&e.mimeType!==null&&typeof e.mimeType!="string")throw new Error(`Entry "${e.id}" mimeType must be a string or omitted.`);if(typeof e.version!="number"||!Number.isInteger(e.version)||e.version<0)throw new Error(`Entry "${e.id}" version must be a non-negative integer.`);if(e.ttl!==void 0&&(typeof e.ttl!="number"||e.ttl<0))throw new Error(`Entry "${e.id}" ttl must be a non-negative number (seconds).`)}function ge(e){return{id:e,status:d.PENDING,data:null,bytesDownloaded:0,totalBytes:null,byteOffset:0,retryCount:0,lastAttemptAt:null,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}}function ye(e,t){return t?e+t*1e3:null}function Be(e){return e?Date.now()>=e:!1}async function H(e){try{Ge(e);let t=Date.now(),r=await p(i.REGISTRY,e.id),a=await p(i.DOWNLOAD_QUEUE,e.id),o={id:e.id,downloadUrl:e.downloadUrl,mimeType:e.mimeType??null,version:e.version,protected:e.protected??!1,priority:e.priority??10,ttl:e.ttl??0,totalBytes:e.totalBytes??null,metadata:e.metadata??{},registeredAt:r?.registeredAt??t,updatedAt:t};if(r){if(e.version>r.version){await y(i.REGISTRY,o);let n=a?{...a,status:d.PENDING,bytesDownloaded:0,byteOffset:0,retryCount:0,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}:ge(e.id);await y(i.DOWNLOAD_QUEUE,n),u("registered",{id:e.id,reason:"version-updated"}),h()}return}await y(i.REGISTRY,o),await y(i.DOWNLOAD_QUEUE,ge(e.id)),u("registered",{id:e.id,reason:"new"}),h()}catch(t){if(t?.name==="QuotaExceededError"){u("error",{id,reason:"insufficient-storage",willRetry:!1});return}else u("error",{id,reason:t?.message??t,willRetry:!1})}}async function De(e){if(!Array.isArray(e))throw new Error("registerFiles expects an array.");let t=new Set(e.map(o=>o.id)),r=await E(i.REGISTRY),a=[];for(let o of r)!t.has(o.id)&&!o.protected&&(await S(i.REGISTRY,o.id),await S(i.DOWNLOAD_QUEUE,o.id),a.push(o.id),u("deleted",{id:o.id,registryRemoved:!0}));for(let o of e)await H(o);return{registered:e.map(o=>o.id),removed:a}}async function Ce(e,t){try{if(e&&t){let r=await p(i.REGISTRY,entry.id);r&&(r.metadata={...r.metadata??{},...t},await y(i.REGISTRY,r))}}catch(r){if(r?.name==="QuotaExceededError"){u("error",{id:e,reason:"insufficient-storage",willRetry:!1});return}else u("error",{id:e,reason:r?.message??r,willRetry:!1})}}async function Ee(){let e=await E(i.DOWNLOAD_QUEUE),t=[];for(let r of e)r.status===d.COMPLETE&&Be(r.expiresAt)&&(await y(i.DOWNLOAD_QUEUE,{...r,status:d.EXPIRED}),t.push(r.id),u("expired",{id:r.id}));return t}async function Ae(){let[e,t,r]=await Promise.all([E(i.REGISTRY),E(i.DOWNLOAD_QUEUE),I()]),a=new Map(t.map(n=>[n.id,n]));return{items:e.map(n=>{let s=a.get(n.id)??null;return{id:n.id,downloadUrl:n.downloadUrl,mimeType:n.mimeType,version:n.version,protected:n.protected,priority:n.priority,ttl:n.ttl,totalBytes:n.totalBytes,metadata:n.metadata,registeredAt:n.registeredAt,updatedAt:n.updatedAt,downloadStatus:s?.status??null,bytesDownloaded:s?.bytesDownloaded??0,storedBytes:s?.data?.length??null,progress:s?.totalBytes&&s?.bytesDownloaded?Math.round(s.bytesDownloaded/s.totalBytes*100):null,retryCount:s?.retryCount??0,lastAttemptAt:s?.lastAttemptAt??null,errorMessage:s?.errorMessage??null,deferredReason:s?.deferredReason??null,completedAt:s?.completedAt??null,expiresAt:s?.expiresAt??null}}).sort((n,s)=>n.priority-s.priority),storage:{usageBytes:r.usage,quotaBytes:r.quota,availableBytes:r.available,usageFormatted:M(r.usage),quotaFormatted:M(r.quota),availableFormatted:M(r.available)}}}async function Re(e){let[t,r]=await Promise.all([p(i.REGISTRY,e),p(i.DOWNLOAD_QUEUE,e)]);return t?{id:t.id,downloadUrl:t.downloadUrl,mimeType:t.mimeType??null,version:t.version,protected:t.protected,priority:t.priority,ttl:t.ttl,totalBytes:t.totalBytes,metadata:t.metadata,registeredAt:t.registeredAt,updatedAt:t.updatedAt,downloadStatus:r?.status??null,bytesDownloaded:r?.bytesDownloaded??0,storedBytes:r?.data?.length??null,progress:r?.totalBytes&&r?.bytesDownloaded?Math.round(r.bytesDownloaded/r.totalBytes*100):null,retryCount:r?.retryCount??0,lastAttemptAt:r?.lastAttemptAt??null,errorMessage:r?.errorMessage??null,deferredReason:r?.deferredReason??null,completedAt:r?.completedAt??null,expiresAt:r?.expiresAt??null}:null}async function be(e){let t=await p(i.DOWNLOAD_QUEUE,e);return j.has(t?.status)}async function Qe(e){let t=await p(i.DOWNLOAD_QUEUE,e);t&&await y(i.DOWNLOAD_QUEUE,{...t,status:d.PENDING,data:null,bytesDownloaded:0,byteOffset:0,retryCount:0,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null})}async function X(e,{removeProtected:t=!1}={}){let r=await p(i.REGISTRY,e);if(!r)throw new Error(`deleteFile: No registered file with id "${e}".`);await Q(e);let a=t||!r.protected;return a?(await S(i.REGISTRY,e),await S(i.DOWNLOAD_QUEUE,e)):await Qe(e),u("deleted",{id:e,registryRemoved:a}),{id:e,registryRemoved:a}}async function Se({removeProtected:e=!1}={}){await O();let t=await N(i.REGISTRY);return Promise.all(t.map(r=>X(r,{removeProtected:e})))}async function Fe(e){let[t,r]=await Promise.all([p(i.REGISTRY,e),p(i.DOWNLOAD_QUEUE,e)]);if(!t)throw new Error(`retrieve: No registered file with id "${e}".`);if(!j.has(r?.status)||!r?.data)throw new Error(`retrieve: File "${e}" has no data yet (status: ${r?.status??"unknown"}).`);return{data:r.data,mimeType:r.mimeType}}var qe={setDBInfo:J,dbGetAllIds:N,registerFile:H,registerFiles:De,startDownloads:fe,stopDownloads:k,retryFailed:pe,isDownloading:we,abortDownload:Q,abortAllDownloads:O,startMonitoring:me,stopMonitoring:$,isOnline:_,isMonitoring:Y,updateConnectivityStatus:se,retrieve:Fe,getAllStatus:Ae,getStatus:Re,isReady:be,delete:X,deleteAll:Se,on:q,off:P,once:ee,getStorageEstimate:I,requestPersistentStorage:re,isPersistentStorage:ne},Dt=qe;export{O as abortAllDownloads,Q as abortDownload,Dt as default,Se as deleteAllFiles,X as deleteFile,u as emit,Ae as getAllStatus,Re as getStatus,I as getStorageEstimate,we as isDownloading,Y as isMonitoring,_ as isOnline,ne as isPersistentStorage,be as isReady,P as off,q as on,ee as once,H as registerFile,De as registerFiles,re as requestPersistentStorage,Fe as retrieve,pe as retryFailed,fe as startDownloads,me as startMonitoring,k as stopDownloads,$ as stopMonitoring,se as updateConnectivityStatus,Ce as updateRegistryMetadata};
|
|
1
|
+
var Z="offline-data-manager",J=1,_=null,s={REGISTRY:"registry",DOWNLOAD_QUEUE:"downloadQueue"};async function tt(t,e){Z=t??"offline-data-manager",J=e??1}async function T(){return _||(_=await new Promise((t,e)=>{let r=indexedDB.open(Z,J);r.onupgradeneeded=o=>{let n=o.target.result;if(!n.objectStoreNames.contains(s.REGISTRY)){let a=n.createObjectStore(s.REGISTRY,{keyPath:"id"});a.createIndex("protected","protected",{unique:!1}),a.createIndex("priority","priority",{unique:!1})}if(!n.objectStoreNames.contains(s.DOWNLOAD_QUEUE)){let a=n.createObjectStore(s.DOWNLOAD_QUEUE,{keyPath:"id"});a.createIndex("status","status",{unique:!1}),a.createIndex("priority","priority",{unique:!1})}},r.onsuccess=()=>t(r.result),r.onerror=()=>e(r.error)}),_)}async function p(t,e){let r=await T();return new Promise((o,n)=>{let a=r.transaction(t,"readonly").objectStore(t).get(e);a.onsuccess=()=>o(a.result),a.onerror=()=>n(a.error)})}async function D(t){let e=await T();return new Promise((r,o)=>{let n=e.transaction(t,"readonly").objectStore(t).getAll();n.onsuccess=()=>r(n.result),n.onerror=()=>o(n.error)})}async function L(t){let e=await T();return new Promise((r,o)=>{let n=e.transaction(t,"readonly").objectStore(t).getAllKeys();n.onsuccess=()=>r(n.result),n.onerror=()=>o(n.error)})}async function m(t,e){let r=await T();return new Promise((o,n)=>{let a=r.transaction(t,"readwrite").objectStore(t).put(e);a.onsuccess=()=>o(),a.onerror=()=>n(a.error),a.onerror=()=>n(a.error)})}async function S(t,e){let r=await T();return new Promise((o,n)=>{let a=r.transaction(t,"readwrite").objectStore(t).delete(e);a.onsuccess=()=>o(),a.onerror=()=>n(a.error)})}var U=new Map;function q(t,e){return U.has(t)||U.set(t,new Set),U.get(t).add(e),()=>M(t,e)}function M(t,e){U.get(t)?.delete(e)}function u(t,e){U.get(t)?.forEach(r=>{try{r(e)}catch(o){console.error(`[offline-data-manager] Error in "${t}" listener:`,o)}})}function et(t,e){let r=o=>{e(o),M(t,r)};q(t,r)}async function I(){if(!navigator?.storage?.estimate)return{usage:0,quota:1/0,available:1/0};let{usage:t=0,quota:e=1/0}=await navigator.storage.estimate();return{usage:t,quota:e,available:e-t}}async function rt(t){let{available:e,quota:r}=await I();return e-r*.1>=t}async function ot(){return navigator?.storage?.persist?navigator.storage.persist():!1}async function nt(){return navigator?.storage?.persisted?navigator.storage.persisted():!1}function G(t){return t===1/0?"\u221E":t<1024?`${t} B`:t<1024**2?`${(t/1024).toFixed(1)} KB`:t<1024**3?`${(t/1024**2).toFixed(1)} MB`:`${(t/1024**3).toFixed(2)} GB`}var C=null,B=null,v=!1,Y=!0;function at(){u("connectivity",{online:!1}),C?.()}function st(){u("connectivity",{online:!0}),B?.()}function it({pauseAll:t,resumeAll:e}){v||(C=t,B=e,window&&(window.addEventListener("offline",at),window.addEventListener("online",st)),v=!0)}function $(){globalThis.window&&(window.removeEventListener("offline",at),window.removeEventListener("online",st)),C=null,B=null,v=!1}function N(){return globalThis.window?navigator.onLine??!0:Y}function k(){return v}function lt(t){Y=t,v&&(Y?B?.():C?.())}var Ot=2*1024*1024,Tt=5*1024*1024,Ut=2,ut=5,It=1e3,E=new Map,b=!1,Q=null;function dt(){return new Promise(t=>{Q=t})}function h(){if(Q){let t=Q;Q=null,t()}}var vt=t=>new Promise(e=>setTimeout(e,t)),Nt=t=>It*Math.pow(2,t);async function y(t,e){let r=await p(s.DOWNLOAD_QUEUE,t);if(!r)return;await m(s.DOWNLOAD_QUEUE,{...r,...e});let{data:o,...n}=e;Object.keys(n).length>0&&await W(t,n)}async function Pt(t,e){try{let r=await fetch(t,{method:"HEAD",signal:e}),o=r.headers.get("Accept-Ranges")==="bytes",n=r.headers.get("Content-Encoding"),a=!!n&&n!=="identity",d=r.headers.get("Content-Length"),i=d&&!a?parseInt(d,10):null,c=ct(r.headers.get("Content-Type"));return{supportsRange:o,totalBytes:i,mimeType:c}}catch{return{supportsRange:!1,totalBytes:null,mimeType:null}}}function ct(t){return t&&t.split(";")[0].trim()||null}function ft(t){let e=t.reduce((n,a)=>n+a.byteLength,0),r=new Uint8Array(e),o=0;for(let n of t)r.set(n,o),o+=n.byteLength;return r}async function _t(t){let{id:e,downloadUrl:r,ttl:o}=t,n=new AbortController;E.set(e,n);let a=await p(s.DOWNLOAD_QUEUE,e),d=a?.retryCount??0;for(;d<=ut;)try{await y(e,{status:l.IN_PROGRESS,lastAttemptAt:Date.now(),retryCount:d,errorMessage:null}),u("status",{id:e,status:l.IN_PROGRESS}),a=await p(s.DOWNLOAD_QUEUE,e);let i=a?.byteOffset??0,c=!1,f=a?.totalBytes??t.totalBytes??null,w=t.mimeType??null;if(i===0){let R=await Pt(r,n.signal);c=R.supportsRange,R.totalBytes&&(f=R.totalBytes,await y(e,{totalBytes:f})),!w&&R.mimeType&&(w=R.mimeType)}else c=!0;let g=c&&f&&f>Tt,A,O=null;if(g)A=await Mt(e,r,i,f,n.signal);else{let R=await Lt(e,r,n.signal);A=R.uint8,O=R.mimeType}let z=w??O??"application/octet-stream",P=A.buffer,V=Date.now(),xt=Et(V,o);await y(e,{status:l.COMPLETE,data:P,mimeType:z,bytesDownloaded:P.byteLength,byteOffset:P.byteLength,storedBytes:P?.byteLength,completedAt:V,expiresAt:xt,errorMessage:null,deferredReason:null}),u("complete",{id:e,mimeType:z}),E.delete(e);return}catch(i){if(i?.name==="QuotaExceededError"){await j(),await y(e,{status:l.DEFERRED,deferredReason:"insufficient-storage"}),u("error",{id:e,reason:"insufficient-storage",willRetry:!1});return}else if(i?.name==="AbortError"){await y(e,{status:l.PAUSED}),u("status",{id:e,status:l.PAUSED}),E.delete(e);return}if(d++,d>ut){await y(e,{status:l.FAILED,retryCount:d,errorMessage:i.message}),u("error",{id:e,error:i,retryCount:d}),E.delete(e);return}let c=Nt(d-1);console.warn(`[offline-data-manager] "${e}" failed (attempt ${d}), retrying in ${c}ms:`,i.message),u("error",{id:e,error:i,retryCount:d,willRetry:!0}),await y(e,{status:l.PENDING,retryCount:d,errorMessage:i.message}),await vt(c)}}async function Lt(t,e,r){let o=await fetch(e,{signal:r});if(!o.ok)throw new Error(`HTTP ${o.status} ${o.statusText}`);let n=o.headers.get("Content-Encoding"),a=!!n&&n!=="identity",d=o.headers.get("Content-Length"),i=d&&!a?parseInt(d,10):null,c=ct(o.headers.get("Content-Type")),f=o.body.getReader(),w=[],g=0;for(;;){let{done:A,value:O}=await f.read();if(A)break;w.push(O),g+=O.byteLength,await y(t,{bytesDownloaded:g,totalBytes:i}),u("progress",{id:t,bytesDownloaded:g,totalBytes:i,percent:i?Math.round(g/i*100):null})}return{uint8:ft(w),mimeType:c}}async function Mt(t,e,r,o,n){let a=r,d=[],i=r;for(;a<o;){let c=Math.min(a+Ot-1,o-1),f=await fetch(e,{signal:n,headers:{Range:`bytes=${a}-${c}`}});if(!f.ok&&f.status!==206)throw new Error(`HTTP ${f.status} on Range bytes=${a}-${c}`);let w=new Uint8Array(await f.arrayBuffer());d.push(w),a+=w.byteLength,i+=w.byteLength,await y(t,{bytesDownloaded:i,byteOffset:a}),u("progress",{id:t,bytesDownloaded:i,totalBytes:o,percent:Math.round(i/o*100)})}return ft(d)}async function Gt(t){await gt();let[e,r]=await Promise.all([D(s.REGISTRY),D(s.DOWNLOAD_QUEUE)]),o=new Map(e.map(i=>[i.id,i])),n=r.filter(i=>[l.PENDING,l.IN_PROGRESS,l.PAUSED,l.DEFERRED,l.EXPIRED].includes(i.status)).sort((i,c)=>(o.get(i.id)?.priority??10)-(o.get(c.id)?.priority??10));if(n.length===0)return;let a=[...n],d=new Set;await new Promise(i=>{function c(){if(!b){i();return}if(a.length===0){d.size===0&&i();return}if(d.size>=t)return;let f=a.shift(),w=o.get(f.id);if(!w){c();return}let g=(async()=>{let A=w.totalBytes??f.totalBytes??0;if(A>0&&!await rt(A)){await y(f.id,{status:l.DEFERRED,deferredReason:"insufficient-storage"}),u("deferred",{id:f.id,reason:"insufficient-storage"});return}await _t(w)})().finally(()=>{d.delete(g),c()});d.add(g),c()}c()})}function pt({concurrency:t=Ut}={}){b||(b=!0,(async()=>{for(;b;){if(!N()){let e=await D(s.DOWNLOAD_QUEUE);for(let r of e)r.status===l.IN_PROGRESS&&(E.get(r.id)?.abort(),E.delete(r.id),await y(r.id,{status:l.PAUSED,deferredReason:"network-offline"}));u("connectivity",{online:!1}),await dt();continue}await Gt(t),b&&await dt()}})())}async function j(){b=!1,h(),await x(),u("stopped",{})}async function wt(){let t=await D(s.DOWNLOAD_QUEUE);for(let e of t)e.status===l.FAILED&&await y(e.id,{status:l.PENDING,retryCount:0,errorMessage:null});h()}function mt(){return b}async function F(t){E.get(t)?.abort(),E.delete(t)}async function x(){for(let[t,e]of E)e.abort(),E.delete(t)}function yt(){it({pauseAll:x,resumeAll:h})}var l={PENDING:"pending",IN_PROGRESS:"in-progress",PAUSED:"paused",COMPLETE:"complete",EXPIRED:"expired",FAILED:"failed",DEFERRED:"deferred"},H=new Set([l.COMPLETE,l.EXPIRED]);function Ct(t){if(!t||typeof t!="object")throw new Error("Registry entry must be an object.");if(!t.id||typeof t.id!="string")throw new Error('Registry entry must have a string "id".');if(!t.downloadUrl||typeof t.downloadUrl!="string")throw new Error(`Entry "${t.id}" must have a string "downloadUrl".`);if(t.mimeType!==void 0&&t.mimeType!==null&&typeof t.mimeType!="string")throw new Error(`Entry "${t.id}" mimeType must be a string or omitted.`);if(typeof t.version!="number"||!Number.isInteger(t.version)||t.version<0)throw new Error(`Entry "${t.id}" version must be a non-negative integer.`);if(t.ttl!==void 0&&(typeof t.ttl!="number"||t.ttl<0))throw new Error(`Entry "${t.id}" ttl must be a non-negative number (seconds).`)}function Dt(t){return{id:t,status:l.PENDING,data:null,bytesDownloaded:0,totalBytes:null,byteOffset:0,retryCount:0,lastAttemptAt:null,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}}async function W(t,e){let r=await p(s.REGISTRY,t);r&&await m(s.REGISTRY,{...r,...e})}function Et(t,e){return e?t+e*1e3:null}function Bt(t){return t?Date.now()>=t:!1}async function X(t){try{Ct(t);let e=Date.now(),r=await p(s.REGISTRY,t.id),o=await p(s.DOWNLOAD_QUEUE,t.id),n={id:t.id,downloadUrl:t.downloadUrl,mimeType:t.mimeType??null,version:t.version,protected:t.protected??!1,priority:t.priority??10,ttl:t.ttl??0,totalBytes:t.totalBytes??null,metadata:t.metadata??{},registeredAt:r?.registeredAt??e,updatedAt:e,...r?{}:{status:l.PENDING,bytesDownloaded:0,retryCount:0,lastAttemptAt:null,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}};if(r){if(t.version>r.version){await m(s.REGISTRY,n);let a=o?{...o,status:l.PENDING,bytesDownloaded:0,byteOffset:0,retryCount:0,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}:Dt(t.id);await m(s.DOWNLOAD_QUEUE,a),await W(t.id,{status:l.PENDING,bytesDownloaded:0,retryCount:0,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}),u("registered",{id:t.id,reason:"version-updated"}),h()}return}await m(s.REGISTRY,n),await m(s.DOWNLOAD_QUEUE,Dt(t.id)),u("registered",{id:t.id,reason:"new"}),h()}catch(e){if(e?.name==="QuotaExceededError"){u("error",{id,reason:"insufficient-storage",willRetry:!1});return}else u("error",{id,reason:e?.message??e,willRetry:!1})}}async function At(t){if(!Array.isArray(t))throw new Error("registerFiles expects an array.");let e=new Set(t.map(n=>n.id)),r=await D(s.REGISTRY),o=[];for(let n of r)!e.has(n.id)&&!n.protected&&(await S(s.REGISTRY,n.id),await S(s.DOWNLOAD_QUEUE,n.id),o.push(n.id),u("deleted",{id:n.id,registryRemoved:!0}));for(let n of t)await X(n);return{registered:t.map(n=>n.id),removed:o}}async function Qt(t,e){try{if(t&&e){let r=await p(s.REGISTRY,entry.id);r&&(r.metadata={...r.metadata??{},...e},await m(s.REGISTRY,r))}}catch(r){if(r?.name==="QuotaExceededError"){u("error",{id:t,reason:"insufficient-storage",willRetry:!1});return}else u("error",{id:t,reason:r?.message??r,willRetry:!1})}}async function gt(){let t=await D(s.DOWNLOAD_QUEUE),e=[];for(let r of t)r.status===l.COMPLETE&&Bt(r.expiresAt)&&(await m(s.DOWNLOAD_QUEUE,{...r,status:l.EXPIRED}),await W(r.id,{status:l.EXPIRED}),e.push(r.id),u("expired",{id:r.id}));return e}async function Rt(){let[t,e]=await Promise.all([D(s.REGISTRY),I()]);return{items:t.map(o=>({id:o.id,downloadUrl:o.downloadUrl,mimeType:o.mimeType,version:o.version,protected:o.protected,priority:o.priority,ttl:o.ttl,totalBytes:o.totalBytes,metadata:o.metadata,registeredAt:o.registeredAt,updatedAt:o.updatedAt,downloadStatus:o.status??null,bytesDownloaded:o.bytesDownloaded??0,progress:o.totalBytes&&o.bytesDownloaded?Math.round(o.bytesDownloaded/o.totalBytes*100):null,retryCount:o.retryCount??0,lastAttemptAt:o.lastAttemptAt??null,errorMessage:o.errorMessage??null,deferredReason:o.deferredReason??null,completedAt:o.completedAt??null,expiresAt:o.expiresAt??null})).sort((o,n)=>o.priority-n.priority),storage:{usageBytes:e.usage,quotaBytes:e.quota,availableBytes:e.available,usageFormatted:G(e.usage),quotaFormatted:G(e.quota),availableFormatted:G(e.available)}}}async function bt(t){let e=await p(s.REGISTRY,t);return e?{id:e.id,downloadUrl:e.downloadUrl,mimeType:e.mimeType??null,version:e.version,protected:e.protected,priority:e.priority,ttl:e.ttl,totalBytes:e.totalBytes,metadata:e.metadata,registeredAt:e.registeredAt,updatedAt:e.updatedAt,downloadStatus:e.status??null,bytesDownloaded:e.bytesDownloaded??0,progress:e.totalBytes&&e.bytesDownloaded?Math.round(e.bytesDownloaded/e.totalBytes*100):null,retryCount:e.retryCount??0,lastAttemptAt:e.lastAttemptAt??null,errorMessage:e.errorMessage??null,deferredReason:e.deferredReason??null,completedAt:e.completedAt??null,expiresAt:e.expiresAt??null}:null}async function St(t){let e=await p(s.DOWNLOAD_QUEUE,t);return H.has(e?.status)}async function Ft(t){let e=await p(s.DOWNLOAD_QUEUE,t);e&&await m(s.DOWNLOAD_QUEUE,{...e,status:l.PENDING,data:null,bytesDownloaded:0,byteOffset:0,retryCount:0,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null})}async function K(t,{removeProtected:e=!1}={}){let r=await p(s.REGISTRY,t);if(!r)throw new Error(`deleteFile: No registered file with id "${t}".`);await F(t);let o=e||!r.protected;return o?(await S(s.REGISTRY,t),await S(s.DOWNLOAD_QUEUE,t)):await Ft(t),u("deleted",{id:t,registryRemoved:o}),{id:t,registryRemoved:o}}async function ht({removeProtected:t=!1}={}){await x();let e=await L(s.REGISTRY);return Promise.all(e.map(r=>K(r,{removeProtected:t})))}async function Wt(t){let[e,r]=await Promise.all([p(s.REGISTRY,t),p(s.DOWNLOAD_QUEUE,t)]);if(!e)throw new Error(`retrieve: No registered file with id "${t}".`);if(!H.has(r?.status)||!r?.data)throw new Error(`retrieve: File "${t}" has no data yet (status: ${r?.status??"unknown"}).`);return{data:r.data,mimeType:r.mimeType}}var qt={setDBInfo:tt,dbGetAllIds:L,registerFile:X,registerFiles:At,startDownloads:pt,stopDownloads:j,retryFailed:wt,isDownloading:mt,abortDownload:F,abortAllDownloads:x,startMonitoring:yt,stopMonitoring:$,isOnline:N,isMonitoring:k,updateConnectivityStatus:lt,retrieve:Wt,getAllStatus:Rt,getStatus:bt,isReady:St,delete:K,deleteAll:ht,on:q,off:M,once:et,getStorageEstimate:I,requestPersistentStorage:ot,isPersistentStorage:nt},Ae=qt;export{x as abortAllDownloads,F as abortDownload,Ae as default,ht as deleteAllFiles,K as deleteFile,u as emit,Rt as getAllStatus,bt as getStatus,I as getStorageEstimate,mt as isDownloading,k as isMonitoring,N as isOnline,nt as isPersistentStorage,St as isReady,M as off,q as on,et as once,X as registerFile,At as registerFiles,ot as requestPersistentStorage,Wt as retrieve,wt as retryFailed,pt as startDownloads,yt as startMonitoring,j as stopDownloads,$ as stopMonitoring,lt as updateConnectivityStatus,Qt as updateRegistryMetadata};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var offlineMapData=(()=>{var H=Object.defineProperty;var Te=Object.getOwnPropertyDescriptor;var Ie=Object.getOwnPropertyNames;var ve=Object.prototype.hasOwnProperty;var _e=(e,t)=>{for(var r in t)H(e,r,{get:t[r],enumerable:!0})},Le=(e,t,r,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Ie(t))!ve.call(e,n)&&n!==r&&H(e,n,{get:()=>t[n],enumerable:!(a=Te(t,n))||a.enumerable});return e};var Ne=e=>Le(H({},"__esModule",{value:!0}),e);var ze={};_e(ze,{abortAllDownloads:()=>S,abortDownload:()=>N,default:()=>Ke,deleteAllFiles:()=>le,deleteFile:()=>k,emit:()=>u,getAllStatus:()=>ae,getStatus:()=>ie,getStorageEstimate:()=>O,isDownloading:()=>te,isMonitoring:()=>q,isOnline:()=>x,isPersistentStorage:()=>z,isReady:()=>se,off:()=>_,on:()=>G,once:()=>X,registerFile:()=>Y,registerFiles:()=>oe,requestPersistentStorage:()=>K,retrieve:()=>xe,retryFailed:()=>ee,startDownloads:()=>J,startMonitoring:()=>re,stopDownloads:()=>$,stopMonitoring:()=>F,updateConnectivityStatus:()=>Z,updateRegistryMetadata:()=>Oe});var ce="offline-data-manager",fe=1,P=null,i={REGISTRY:"registry",DOWNLOAD_QUEUE:"downloadQueue"};async function pe(e,t){ce=e??"offline-data-manager",fe=t??1}async function I(){return P||(P=await new Promise((e,t)=>{let r=indexedDB.open(ce,fe);r.onupgradeneeded=a=>{let n=a.target.result;if(!n.objectStoreNames.contains(i.REGISTRY)){let o=n.createObjectStore(i.REGISTRY,{keyPath:"id"});o.createIndex("protected","protected",{unique:!1}),o.createIndex("priority","priority",{unique:!1})}if(!n.objectStoreNames.contains(i.DOWNLOAD_QUEUE)){let o=n.createObjectStore(i.DOWNLOAD_QUEUE,{keyPath:"id"});o.createIndex("status","status",{unique:!1}),o.createIndex("priority","priority",{unique:!1})}},r.onsuccess=()=>e(r.result),r.onerror=()=>t(r.error)}),P)}async function p(e,t){let r=await I();return new Promise((a,n)=>{let o=r.transaction(e,"readonly").objectStore(e).get(t);o.onsuccess=()=>a(o.result),o.onerror=()=>n(o.error)})}async function E(e){let t=await I();return new Promise((r,a)=>{let n=t.transaction(e,"readonly").objectStore(e).getAll();n.onsuccess=()=>r(n.result),n.onerror=()=>a(n.error)})}async function M(e){let t=await I();return new Promise((r,a)=>{let n=t.transaction(e,"readonly").objectStore(e).getAllKeys();n.onsuccess=()=>r(n.result),n.onerror=()=>a(n.error)})}async function y(e,t){let r=await I();return new Promise((a,n)=>{let o=r.transaction(e,"readwrite").objectStore(e).put(t);o.onsuccess=()=>a(),o.onerror=()=>n(o.error),o.onerror=()=>n(o.error)})}async function h(e,t){let r=await I();return new Promise((a,n)=>{let o=r.transaction(e,"readwrite").objectStore(e).delete(t);o.onsuccess=()=>a(),o.onerror=()=>n(o.error)})}var v=new Map;function G(e,t){return v.has(e)||v.set(e,new Set),v.get(e).add(t),()=>_(e,t)}function _(e,t){v.get(e)?.delete(t)}function u(e,t){v.get(e)?.forEach(r=>{try{r(t)}catch(a){console.error(`[offline-data-manager] Error in "${e}" listener:`,a)}})}function X(e,t){let r=a=>{t(a),_(e,r)};G(e,r)}async function O(){if(!navigator?.storage?.estimate)return{usage:0,quota:1/0,available:1/0};let{usage:e=0,quota:t=1/0}=await navigator.storage.estimate();return{usage:e,quota:t,available:t-e}}async function we(e){let{available:t,quota:r}=await O();return t-r*.1>=e}async function K(){return navigator?.storage?.persist?navigator.storage.persist():!1}async function z(){return navigator?.storage?.persisted?navigator.storage.persisted():!1}function B(e){return e===1/0?"\u221E":e<1024?`${e} B`:e<1024**2?`${(e/1024).toFixed(1)} KB`:e<1024**3?`${(e/1024**2).toFixed(1)} MB`:`${(e/1024**3).toFixed(2)} GB`}var C=null,Q=null,L=!1,V=!0;function me(){u("connectivity",{online:!1}),C?.()}function ye(){u("connectivity",{online:!0}),Q?.()}function Ee({pauseAll:e,resumeAll:t}){L||!window||(C=e,Q=t,window&&(window.addEventListener("offline",me),window.addEventListener("online",ye)),L=!0)}function F(){window&&(window.removeEventListener("offline",me),window.removeEventListener("online",ye)),C=null,Q=null,L=!1}function x(){return window?navigator.onLine??!0:V}function q(){return L}function Z(e){V=e,L&&(V?Q?.():C?.())}var Pe=2*1024*1024,Me=5*1024*1024,Ge=2,ge=5,Be=1e3,g=new Map,b=!1,W=null;function De(){return new Promise(e=>{W=e})}function U(){if(W){let e=W;W=null,e()}}var Ce=e=>new Promise(t=>setTimeout(t,e)),Qe=e=>Be*Math.pow(2,e);async function m(e,t){let r=await p(i.DOWNLOAD_QUEUE,e);r&&await y(i.DOWNLOAD_QUEUE,{...r,...t})}async function Fe(e,t){try{let r=await fetch(e,{method:"HEAD",signal:t}),a=r.headers.get("Accept-Ranges")==="bytes",n=r.headers.get("Content-Encoding"),o=!!n&&n!=="identity",s=r.headers.get("Content-Length"),l=s&&!o?parseInt(s,10):null,c=Ae(r.headers.get("Content-Type"));return{supportsRange:a,totalBytes:l,mimeType:c}}catch{return{supportsRange:!1,totalBytes:null,mimeType:null}}}function Ae(e){return e&&e.split(";")[0].trim()||null}function Re(e){let t=e.reduce((n,o)=>n+o.byteLength,0),r=new Uint8Array(t),a=0;for(let n of e)r.set(n,a),a+=n.byteLength;return r}async function qe(e){let{id:t,downloadUrl:r,ttl:a}=e,n=new AbortController;g.set(t,n);let o=await p(i.DOWNLOAD_QUEUE,t),s=o?.retryCount??0;for(;s<=ge;)try{await m(t,{status:d.IN_PROGRESS,lastAttemptAt:Date.now(),retryCount:s,errorMessage:null}),u("status",{id:t,status:d.IN_PROGRESS}),o=await p(i.DOWNLOAD_QUEUE,t);let l=o?.byteOffset??0,c=!1,f=o?.totalBytes??e.totalBytes??null,w=e.mimeType??null;if(l===0){let R=await Fe(r,n.signal);c=R.supportsRange,R.totalBytes&&(f=R.totalBytes,await m(t,{totalBytes:f})),!w&&R.mimeType&&(w=R.mimeType)}else c=!0;let D=c&&f&&f>Me,A,T=null;if(D)A=await $e(t,r,l,f,n.signal);else{let R=await We(t,r,n.signal);A=R.uint8,T=R.mimeType}let ue=w??T??"application/octet-stream",j=A.buffer,de=Date.now(),Ue=be(de,a);await m(t,{status:d.COMPLETE,data:j,mimeType:ue,bytesDownloaded:j.byteLength,byteOffset:j.byteLength,completedAt:de,expiresAt:Ue,errorMessage:null,deferredReason:null}),u("complete",{id:t,mimeType:ue}),g.delete(t);return}catch(l){if(l?.name==="QuotaExceededError"){await $(),await m(t,{status:d.DEFERRED,deferredReason:"insufficient-storage"}),u("error",{id:t,reason:"insufficient-storage",willRetry:!1});return}else if(l?.name==="AbortError"){await m(t,{status:d.PAUSED}),u("status",{id:t,status:d.PAUSED}),g.delete(t);return}if(s++,s>ge){await m(t,{status:d.FAILED,retryCount:s,errorMessage:l.message}),u("error",{id:t,error:l,retryCount:s}),g.delete(t);return}let c=Qe(s-1);console.warn(`[offline-data-manager] "${t}" failed (attempt ${s}), retrying in ${c}ms:`,l.message),u("error",{id:t,error:l,retryCount:s,willRetry:!0}),await m(t,{status:d.PENDING,retryCount:s,errorMessage:l.message}),await Ce(c)}}async function We(e,t,r){let a=await fetch(t,{signal:r});if(!a.ok)throw new Error(`HTTP ${a.status} ${a.statusText}`);let n=a.headers.get("Content-Encoding"),o=!!n&&n!=="identity",s=a.headers.get("Content-Length"),l=s&&!o?parseInt(s,10):null,c=Ae(a.headers.get("Content-Type")),f=a.body.getReader(),w=[],D=0;for(;;){let{done:A,value:T}=await f.read();if(A)break;w.push(T),D+=T.byteLength,await m(e,{bytesDownloaded:D,totalBytes:l}),u("progress",{id:e,bytesDownloaded:D,totalBytes:l,percent:l?Math.round(D/l*100):null})}return{uint8:Re(w),mimeType:c}}async function $e(e,t,r,a,n){let o=r,s=[],l=r;for(;o<a;){let c=Math.min(o+Pe-1,a-1),f=await fetch(t,{signal:n,headers:{Range:`bytes=${o}-${c}`}});if(!f.ok&&f.status!==206)throw new Error(`HTTP ${f.status} on Range bytes=${o}-${c}`);let w=new Uint8Array(await f.arrayBuffer());s.push(w),o+=w.byteLength,l+=w.byteLength,await m(e,{bytesDownloaded:l,byteOffset:o}),u("progress",{id:e,bytesDownloaded:l,totalBytes:a,percent:Math.round(l/a*100)})}return Re(s)}async function Ye(e){await Se();let[t,r]=await Promise.all([E(i.REGISTRY),E(i.DOWNLOAD_QUEUE)]),a=new Map(t.map(l=>[l.id,l])),n=r.filter(l=>[d.PENDING,d.IN_PROGRESS,d.PAUSED,d.DEFERRED,d.EXPIRED].includes(l.status)).sort((l,c)=>(a.get(l.id)?.priority??10)-(a.get(c.id)?.priority??10));if(n.length===0)return;let o=[...n],s=new Set;await new Promise(l=>{function c(){if(!b){l();return}if(o.length===0){s.size===0&&l();return}if(s.size>=e)return;let f=o.shift(),w=a.get(f.id);if(!w){c();return}let D=(async()=>{let A=w.totalBytes??f.totalBytes??0;if(A>0&&!await we(A)){await m(f.id,{status:d.DEFERRED,deferredReason:"insufficient-storage"}),u("deferred",{id:f.id,reason:"insufficient-storage"});return}await qe(w)})().finally(()=>{s.delete(D),c()});s.add(D),c()}c()})}function J({concurrency:e=Ge}={}){b||(b=!0,(async()=>{for(;b;){if(!x()){let t=await E(i.DOWNLOAD_QUEUE);for(let r of t)r.status===d.IN_PROGRESS&&(g.get(r.id)?.abort(),g.delete(r.id),await m(r.id,{status:d.PAUSED,deferredReason:"network-offline"}));u("connectivity",{online:!1}),await De();continue}await Ye(e),b&&await De()}})())}async function $(){b=!1,U(),await S(),u("stopped",{})}async function ee(){let e=await E(i.DOWNLOAD_QUEUE);for(let t of e)t.status===d.FAILED&&await m(t.id,{status:d.PENDING,retryCount:0,errorMessage:null});U()}function te(){return b}async function N(e){g.get(e)?.abort(),g.delete(e)}async function S(){for(let[e,t]of g)t.abort(),g.delete(e)}function re(){Ee({pauseAll:S,resumeAll:U})}var d={PENDING:"pending",IN_PROGRESS:"in-progress",PAUSED:"paused",COMPLETE:"complete",EXPIRED:"expired",FAILED:"failed",DEFERRED:"deferred"},ne=new Set([d.COMPLETE,d.EXPIRED]);function ke(e){if(!e||typeof e!="object")throw new Error("Registry entry must be an object.");if(!e.id||typeof e.id!="string")throw new Error('Registry entry must have a string "id".');if(!e.downloadUrl||typeof e.downloadUrl!="string")throw new Error(`Entry "${e.id}" must have a string "downloadUrl".`);if(e.mimeType!==void 0&&e.mimeType!==null&&typeof e.mimeType!="string")throw new Error(`Entry "${e.id}" mimeType must be a string or omitted.`);if(typeof e.version!="number"||!Number.isInteger(e.version)||e.version<0)throw new Error(`Entry "${e.id}" version must be a non-negative integer.`);if(e.ttl!==void 0&&(typeof e.ttl!="number"||e.ttl<0))throw new Error(`Entry "${e.id}" ttl must be a non-negative number (seconds).`)}function he(e){return{id:e,status:d.PENDING,data:null,bytesDownloaded:0,totalBytes:null,byteOffset:0,retryCount:0,lastAttemptAt:null,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}}function be(e,t){return t?e+t*1e3:null}function je(e){return e?Date.now()>=e:!1}async function Y(e){try{ke(e);let t=Date.now(),r=await p(i.REGISTRY,e.id),a=await p(i.DOWNLOAD_QUEUE,e.id),n={id:e.id,downloadUrl:e.downloadUrl,mimeType:e.mimeType??null,version:e.version,protected:e.protected??!1,priority:e.priority??10,ttl:e.ttl??0,totalBytes:e.totalBytes??null,metadata:e.metadata??{},registeredAt:r?.registeredAt??t,updatedAt:t};if(r){if(e.version>r.version){await y(i.REGISTRY,n);let o=a?{...a,status:d.PENDING,bytesDownloaded:0,byteOffset:0,retryCount:0,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}:he(e.id);await y(i.DOWNLOAD_QUEUE,o),u("registered",{id:e.id,reason:"version-updated"}),U()}return}await y(i.REGISTRY,n),await y(i.DOWNLOAD_QUEUE,he(e.id)),u("registered",{id:e.id,reason:"new"}),U()}catch(t){if(t?.name==="QuotaExceededError"){u("error",{id,reason:"insufficient-storage",willRetry:!1});return}else u("error",{id,reason:t?.message??t,willRetry:!1})}}async function oe(e){if(!Array.isArray(e))throw new Error("registerFiles expects an array.");let t=new Set(e.map(n=>n.id)),r=await E(i.REGISTRY),a=[];for(let n of r)!t.has(n.id)&&!n.protected&&(await h(i.REGISTRY,n.id),await h(i.DOWNLOAD_QUEUE,n.id),a.push(n.id),u("deleted",{id:n.id,registryRemoved:!0}));for(let n of e)await Y(n);return{registered:e.map(n=>n.id),removed:a}}async function Oe(e,t){try{if(e&&t){let r=await p(i.REGISTRY,entry.id);r&&(r.metadata={...r.metadata??{},...t},await y(i.REGISTRY,r))}}catch(r){if(r?.name==="QuotaExceededError"){u("error",{id:e,reason:"insufficient-storage",willRetry:!1});return}else u("error",{id:e,reason:r?.message??r,willRetry:!1})}}async function Se(){let e=await E(i.DOWNLOAD_QUEUE),t=[];for(let r of e)r.status===d.COMPLETE&&je(r.expiresAt)&&(await y(i.DOWNLOAD_QUEUE,{...r,status:d.EXPIRED}),t.push(r.id),u("expired",{id:r.id}));return t}async function ae(){let[e,t,r]=await Promise.all([E(i.REGISTRY),E(i.DOWNLOAD_QUEUE),O()]),a=new Map(t.map(o=>[o.id,o]));return{items:e.map(o=>{let s=a.get(o.id)??null;return{id:o.id,downloadUrl:o.downloadUrl,mimeType:o.mimeType,version:o.version,protected:o.protected,priority:o.priority,ttl:o.ttl,totalBytes:o.totalBytes,metadata:o.metadata,registeredAt:o.registeredAt,updatedAt:o.updatedAt,downloadStatus:s?.status??null,bytesDownloaded:s?.bytesDownloaded??0,storedBytes:s?.data?.length??null,progress:s?.totalBytes&&s?.bytesDownloaded?Math.round(s.bytesDownloaded/s.totalBytes*100):null,retryCount:s?.retryCount??0,lastAttemptAt:s?.lastAttemptAt??null,errorMessage:s?.errorMessage??null,deferredReason:s?.deferredReason??null,completedAt:s?.completedAt??null,expiresAt:s?.expiresAt??null}}).sort((o,s)=>o.priority-s.priority),storage:{usageBytes:r.usage,quotaBytes:r.quota,availableBytes:r.available,usageFormatted:B(r.usage),quotaFormatted:B(r.quota),availableFormatted:B(r.available)}}}async function ie(e){let[t,r]=await Promise.all([p(i.REGISTRY,e),p(i.DOWNLOAD_QUEUE,e)]);return t?{id:t.id,downloadUrl:t.downloadUrl,mimeType:t.mimeType??null,version:t.version,protected:t.protected,priority:t.priority,ttl:t.ttl,totalBytes:t.totalBytes,metadata:t.metadata,registeredAt:t.registeredAt,updatedAt:t.updatedAt,downloadStatus:r?.status??null,bytesDownloaded:r?.bytesDownloaded??0,storedBytes:r?.data?.length??null,progress:r?.totalBytes&&r?.bytesDownloaded?Math.round(r.bytesDownloaded/r.totalBytes*100):null,retryCount:r?.retryCount??0,lastAttemptAt:r?.lastAttemptAt??null,errorMessage:r?.errorMessage??null,deferredReason:r?.deferredReason??null,completedAt:r?.completedAt??null,expiresAt:r?.expiresAt??null}:null}async function se(e){let t=await p(i.DOWNLOAD_QUEUE,e);return ne.has(t?.status)}async function He(e){let t=await p(i.DOWNLOAD_QUEUE,e);t&&await y(i.DOWNLOAD_QUEUE,{...t,status:d.PENDING,data:null,bytesDownloaded:0,byteOffset:0,retryCount:0,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null})}async function k(e,{removeProtected:t=!1}={}){let r=await p(i.REGISTRY,e);if(!r)throw new Error(`deleteFile: No registered file with id "${e}".`);await N(e);let a=t||!r.protected;return a?(await h(i.REGISTRY,e),await h(i.DOWNLOAD_QUEUE,e)):await He(e),u("deleted",{id:e,registryRemoved:a}),{id:e,registryRemoved:a}}async function le({removeProtected:e=!1}={}){await S();let t=await M(i.REGISTRY);return Promise.all(t.map(r=>k(r,{removeProtected:e})))}async function xe(e){let[t,r]=await Promise.all([p(i.REGISTRY,e),p(i.DOWNLOAD_QUEUE,e)]);if(!t)throw new Error(`retrieve: No registered file with id "${e}".`);if(!ne.has(r?.status)||!r?.data)throw new Error(`retrieve: File "${e}" has no data yet (status: ${r?.status??"unknown"}).`);return{data:r.data,mimeType:r.mimeType}}var Xe={setDBInfo:pe,dbGetAllIds:M,registerFile:Y,registerFiles:oe,startDownloads:J,stopDownloads:$,retryFailed:ee,isDownloading:te,abortDownload:N,abortAllDownloads:S,startMonitoring:re,stopMonitoring:F,isOnline:x,isMonitoring:q,updateConnectivityStatus:Z,retrieve:xe,getAllStatus:ae,getStatus:ie,isReady:se,delete:k,deleteAll:le,on:G,off:_,once:X,getStorageEstimate:O,requestPersistentStorage:K,isPersistentStorage:z},Ke=Xe;return Ne(ze);})();
|
|
1
|
+
"use strict";var offlineMapData=(()=>{var X=Object.defineProperty;var It=Object.getOwnPropertyDescriptor;var vt=Object.getOwnPropertyNames;var Nt=Object.prototype.hasOwnProperty;var Pt=(t,e)=>{for(var r in e)X(t,r,{get:e[r],enumerable:!0})},_t=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of vt(e))!Nt.call(t,n)&&n!==r&&X(t,n,{get:()=>e[n],enumerable:!(o=It(e,n))||o.enumerable});return t};var Lt=t=>_t(X({},"__esModule",{value:!0}),t);var Vt={};Pt(Vt,{abortAllDownloads:()=>S,abortDownload:()=>_,default:()=>zt,deleteAllFiles:()=>ut,deleteFile:()=>H,emit:()=>u,getAllStatus:()=>st,getStatus:()=>it,getStorageEstimate:()=>x,isDownloading:()=>rt,isMonitoring:()=>q,isOnline:()=>O,isPersistentStorage:()=>V,isReady:()=>lt,off:()=>N,on:()=>C,once:()=>K,registerFile:()=>j,registerFiles:()=>at,requestPersistentStorage:()=>z,retrieve:()=>Tt,retryFailed:()=>et,startDownloads:()=>tt,startMonitoring:()=>ot,stopDownloads:()=>$,stopMonitoring:()=>W,updateConnectivityStatus:()=>J,updateRegistryMetadata:()=>Ot});var ft="offline-data-manager",pt=1,M=null,s={REGISTRY:"registry",DOWNLOAD_QUEUE:"downloadQueue"};async function wt(t,e){ft=t??"offline-data-manager",pt=e??1}async function I(){return M||(M=await new Promise((t,e)=>{let r=indexedDB.open(ft,pt);r.onupgradeneeded=o=>{let n=o.target.result;if(!n.objectStoreNames.contains(s.REGISTRY)){let a=n.createObjectStore(s.REGISTRY,{keyPath:"id"});a.createIndex("protected","protected",{unique:!1}),a.createIndex("priority","priority",{unique:!1})}if(!n.objectStoreNames.contains(s.DOWNLOAD_QUEUE)){let a=n.createObjectStore(s.DOWNLOAD_QUEUE,{keyPath:"id"});a.createIndex("status","status",{unique:!1}),a.createIndex("priority","priority",{unique:!1})}},r.onsuccess=()=>t(r.result),r.onerror=()=>e(r.error)}),M)}async function p(t,e){let r=await I();return new Promise((o,n)=>{let a=r.transaction(t,"readonly").objectStore(t).get(e);a.onsuccess=()=>o(a.result),a.onerror=()=>n(a.error)})}async function D(t){let e=await I();return new Promise((r,o)=>{let n=e.transaction(t,"readonly").objectStore(t).getAll();n.onsuccess=()=>r(n.result),n.onerror=()=>o(n.error)})}async function G(t){let e=await I();return new Promise((r,o)=>{let n=e.transaction(t,"readonly").objectStore(t).getAllKeys();n.onsuccess=()=>r(n.result),n.onerror=()=>o(n.error)})}async function m(t,e){let r=await I();return new Promise((o,n)=>{let a=r.transaction(t,"readwrite").objectStore(t).put(e);a.onsuccess=()=>o(),a.onerror=()=>n(a.error),a.onerror=()=>n(a.error)})}async function h(t,e){let r=await I();return new Promise((o,n)=>{let a=r.transaction(t,"readwrite").objectStore(t).delete(e);a.onsuccess=()=>o(),a.onerror=()=>n(a.error)})}var v=new Map;function C(t,e){return v.has(t)||v.set(t,new Set),v.get(t).add(e),()=>N(t,e)}function N(t,e){v.get(t)?.delete(e)}function u(t,e){v.get(t)?.forEach(r=>{try{r(e)}catch(o){console.error(`[offline-data-manager] Error in "${t}" listener:`,o)}})}function K(t,e){let r=o=>{e(o),N(t,r)};C(t,r)}async function x(){if(!navigator?.storage?.estimate)return{usage:0,quota:1/0,available:1/0};let{usage:t=0,quota:e=1/0}=await navigator.storage.estimate();return{usage:t,quota:e,available:e-t}}async function mt(t){let{available:e,quota:r}=await x();return e-r*.1>=t}async function z(){return navigator?.storage?.persist?navigator.storage.persist():!1}async function V(){return navigator?.storage?.persisted?navigator.storage.persisted():!1}function B(t){return t===1/0?"\u221E":t<1024?`${t} B`:t<1024**2?`${(t/1024).toFixed(1)} KB`:t<1024**3?`${(t/1024**2).toFixed(1)} MB`:`${(t/1024**3).toFixed(2)} GB`}var Q=null,F=null,P=!1,Z=!0;function yt(){u("connectivity",{online:!1}),Q?.()}function Et(){u("connectivity",{online:!0}),F?.()}function gt({pauseAll:t,resumeAll:e}){P||(Q=t,F=e,window&&(window.addEventListener("offline",yt),window.addEventListener("online",Et)),P=!0)}function W(){globalThis.window&&(window.removeEventListener("offline",yt),window.removeEventListener("online",Et)),Q=null,F=null,P=!1}function O(){return globalThis.window?navigator.onLine??!0:Z}function q(){return P}function J(t){Z=t,P&&(Z?F?.():Q?.())}var Mt=2*1024*1024,Gt=5*1024*1024,Ct=2,Dt=5,Bt=1e3,E=new Map,b=!1,Y=null;function At(){return new Promise(t=>{Y=t})}function T(){if(Y){let t=Y;Y=null,t()}}var Qt=t=>new Promise(e=>setTimeout(e,t)),Ft=t=>Bt*Math.pow(2,t);async function y(t,e){let r=await p(s.DOWNLOAD_QUEUE,t);if(!r)return;await m(s.DOWNLOAD_QUEUE,{...r,...e});let{data:o,...n}=e;Object.keys(n).length>0&&await k(t,n)}async function Wt(t,e){try{let r=await fetch(t,{method:"HEAD",signal:e}),o=r.headers.get("Accept-Ranges")==="bytes",n=r.headers.get("Content-Encoding"),a=!!n&&n!=="identity",d=r.headers.get("Content-Length"),i=d&&!a?parseInt(d,10):null,c=Rt(r.headers.get("Content-Type"));return{supportsRange:o,totalBytes:i,mimeType:c}}catch{return{supportsRange:!1,totalBytes:null,mimeType:null}}}function Rt(t){return t&&t.split(";")[0].trim()||null}function bt(t){let e=t.reduce((n,a)=>n+a.byteLength,0),r=new Uint8Array(e),o=0;for(let n of t)r.set(n,o),o+=n.byteLength;return r}async function qt(t){let{id:e,downloadUrl:r,ttl:o}=t,n=new AbortController;E.set(e,n);let a=await p(s.DOWNLOAD_QUEUE,e),d=a?.retryCount??0;for(;d<=Dt;)try{await y(e,{status:l.IN_PROGRESS,lastAttemptAt:Date.now(),retryCount:d,errorMessage:null}),u("status",{id:e,status:l.IN_PROGRESS}),a=await p(s.DOWNLOAD_QUEUE,e);let i=a?.byteOffset??0,c=!1,f=a?.totalBytes??t.totalBytes??null,w=t.mimeType??null;if(i===0){let R=await Wt(r,n.signal);c=R.supportsRange,R.totalBytes&&(f=R.totalBytes,await y(e,{totalBytes:f})),!w&&R.mimeType&&(w=R.mimeType)}else c=!0;let g=c&&f&&f>Gt,A,U=null;if(g)A=await $t(e,r,i,f,n.signal);else{let R=await Yt(e,r,n.signal);A=R.uint8,U=R.mimeType}let dt=w??U??"application/octet-stream",L=A.buffer,ct=Date.now(),Ut=St(ct,o);await y(e,{status:l.COMPLETE,data:L,mimeType:dt,bytesDownloaded:L.byteLength,byteOffset:L.byteLength,storedBytes:L?.byteLength,completedAt:ct,expiresAt:Ut,errorMessage:null,deferredReason:null}),u("complete",{id:e,mimeType:dt}),E.delete(e);return}catch(i){if(i?.name==="QuotaExceededError"){await $(),await y(e,{status:l.DEFERRED,deferredReason:"insufficient-storage"}),u("error",{id:e,reason:"insufficient-storage",willRetry:!1});return}else if(i?.name==="AbortError"){await y(e,{status:l.PAUSED}),u("status",{id:e,status:l.PAUSED}),E.delete(e);return}if(d++,d>Dt){await y(e,{status:l.FAILED,retryCount:d,errorMessage:i.message}),u("error",{id:e,error:i,retryCount:d}),E.delete(e);return}let c=Ft(d-1);console.warn(`[offline-data-manager] "${e}" failed (attempt ${d}), retrying in ${c}ms:`,i.message),u("error",{id:e,error:i,retryCount:d,willRetry:!0}),await y(e,{status:l.PENDING,retryCount:d,errorMessage:i.message}),await Qt(c)}}async function Yt(t,e,r){let o=await fetch(e,{signal:r});if(!o.ok)throw new Error(`HTTP ${o.status} ${o.statusText}`);let n=o.headers.get("Content-Encoding"),a=!!n&&n!=="identity",d=o.headers.get("Content-Length"),i=d&&!a?parseInt(d,10):null,c=Rt(o.headers.get("Content-Type")),f=o.body.getReader(),w=[],g=0;for(;;){let{done:A,value:U}=await f.read();if(A)break;w.push(U),g+=U.byteLength,await y(t,{bytesDownloaded:g,totalBytes:i}),u("progress",{id:t,bytesDownloaded:g,totalBytes:i,percent:i?Math.round(g/i*100):null})}return{uint8:bt(w),mimeType:c}}async function $t(t,e,r,o,n){let a=r,d=[],i=r;for(;a<o;){let c=Math.min(a+Mt-1,o-1),f=await fetch(e,{signal:n,headers:{Range:`bytes=${a}-${c}`}});if(!f.ok&&f.status!==206)throw new Error(`HTTP ${f.status} on Range bytes=${a}-${c}`);let w=new Uint8Array(await f.arrayBuffer());d.push(w),a+=w.byteLength,i+=w.byteLength,await y(t,{bytesDownloaded:i,byteOffset:a}),u("progress",{id:t,bytesDownloaded:i,totalBytes:o,percent:Math.round(i/o*100)})}return bt(d)}async function kt(t){await ht();let[e,r]=await Promise.all([D(s.REGISTRY),D(s.DOWNLOAD_QUEUE)]),o=new Map(e.map(i=>[i.id,i])),n=r.filter(i=>[l.PENDING,l.IN_PROGRESS,l.PAUSED,l.DEFERRED,l.EXPIRED].includes(i.status)).sort((i,c)=>(o.get(i.id)?.priority??10)-(o.get(c.id)?.priority??10));if(n.length===0)return;let a=[...n],d=new Set;await new Promise(i=>{function c(){if(!b){i();return}if(a.length===0){d.size===0&&i();return}if(d.size>=t)return;let f=a.shift(),w=o.get(f.id);if(!w){c();return}let g=(async()=>{let A=w.totalBytes??f.totalBytes??0;if(A>0&&!await mt(A)){await y(f.id,{status:l.DEFERRED,deferredReason:"insufficient-storage"}),u("deferred",{id:f.id,reason:"insufficient-storage"});return}await qt(w)})().finally(()=>{d.delete(g),c()});d.add(g),c()}c()})}function tt({concurrency:t=Ct}={}){b||(b=!0,(async()=>{for(;b;){if(!O()){let e=await D(s.DOWNLOAD_QUEUE);for(let r of e)r.status===l.IN_PROGRESS&&(E.get(r.id)?.abort(),E.delete(r.id),await y(r.id,{status:l.PAUSED,deferredReason:"network-offline"}));u("connectivity",{online:!1}),await At();continue}await kt(t),b&&await At()}})())}async function $(){b=!1,T(),await S(),u("stopped",{})}async function et(){let t=await D(s.DOWNLOAD_QUEUE);for(let e of t)e.status===l.FAILED&&await y(e.id,{status:l.PENDING,retryCount:0,errorMessage:null});T()}function rt(){return b}async function _(t){E.get(t)?.abort(),E.delete(t)}async function S(){for(let[t,e]of E)e.abort(),E.delete(t)}function ot(){gt({pauseAll:S,resumeAll:T})}var l={PENDING:"pending",IN_PROGRESS:"in-progress",PAUSED:"paused",COMPLETE:"complete",EXPIRED:"expired",FAILED:"failed",DEFERRED:"deferred"},nt=new Set([l.COMPLETE,l.EXPIRED]);function jt(t){if(!t||typeof t!="object")throw new Error("Registry entry must be an object.");if(!t.id||typeof t.id!="string")throw new Error('Registry entry must have a string "id".');if(!t.downloadUrl||typeof t.downloadUrl!="string")throw new Error(`Entry "${t.id}" must have a string "downloadUrl".`);if(t.mimeType!==void 0&&t.mimeType!==null&&typeof t.mimeType!="string")throw new Error(`Entry "${t.id}" mimeType must be a string or omitted.`);if(typeof t.version!="number"||!Number.isInteger(t.version)||t.version<0)throw new Error(`Entry "${t.id}" version must be a non-negative integer.`);if(t.ttl!==void 0&&(typeof t.ttl!="number"||t.ttl<0))throw new Error(`Entry "${t.id}" ttl must be a non-negative number (seconds).`)}function xt(t){return{id:t,status:l.PENDING,data:null,bytesDownloaded:0,totalBytes:null,byteOffset:0,retryCount:0,lastAttemptAt:null,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}}async function k(t,e){let r=await p(s.REGISTRY,t);r&&await m(s.REGISTRY,{...r,...e})}function St(t,e){return e?t+e*1e3:null}function Ht(t){return t?Date.now()>=t:!1}async function j(t){try{jt(t);let e=Date.now(),r=await p(s.REGISTRY,t.id),o=await p(s.DOWNLOAD_QUEUE,t.id),n={id:t.id,downloadUrl:t.downloadUrl,mimeType:t.mimeType??null,version:t.version,protected:t.protected??!1,priority:t.priority??10,ttl:t.ttl??0,totalBytes:t.totalBytes??null,metadata:t.metadata??{},registeredAt:r?.registeredAt??e,updatedAt:e,...r?{}:{status:l.PENDING,bytesDownloaded:0,retryCount:0,lastAttemptAt:null,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}};if(r){if(t.version>r.version){await m(s.REGISTRY,n);let a=o?{...o,status:l.PENDING,bytesDownloaded:0,byteOffset:0,retryCount:0,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}:xt(t.id);await m(s.DOWNLOAD_QUEUE,a),await k(t.id,{status:l.PENDING,bytesDownloaded:0,retryCount:0,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null}),u("registered",{id:t.id,reason:"version-updated"}),T()}return}await m(s.REGISTRY,n),await m(s.DOWNLOAD_QUEUE,xt(t.id)),u("registered",{id:t.id,reason:"new"}),T()}catch(e){if(e?.name==="QuotaExceededError"){u("error",{id,reason:"insufficient-storage",willRetry:!1});return}else u("error",{id,reason:e?.message??e,willRetry:!1})}}async function at(t){if(!Array.isArray(t))throw new Error("registerFiles expects an array.");let e=new Set(t.map(n=>n.id)),r=await D(s.REGISTRY),o=[];for(let n of r)!e.has(n.id)&&!n.protected&&(await h(s.REGISTRY,n.id),await h(s.DOWNLOAD_QUEUE,n.id),o.push(n.id),u("deleted",{id:n.id,registryRemoved:!0}));for(let n of t)await j(n);return{registered:t.map(n=>n.id),removed:o}}async function Ot(t,e){try{if(t&&e){let r=await p(s.REGISTRY,entry.id);r&&(r.metadata={...r.metadata??{},...e},await m(s.REGISTRY,r))}}catch(r){if(r?.name==="QuotaExceededError"){u("error",{id:t,reason:"insufficient-storage",willRetry:!1});return}else u("error",{id:t,reason:r?.message??r,willRetry:!1})}}async function ht(){let t=await D(s.DOWNLOAD_QUEUE),e=[];for(let r of t)r.status===l.COMPLETE&&Ht(r.expiresAt)&&(await m(s.DOWNLOAD_QUEUE,{...r,status:l.EXPIRED}),await k(r.id,{status:l.EXPIRED}),e.push(r.id),u("expired",{id:r.id}));return e}async function st(){let[t,e]=await Promise.all([D(s.REGISTRY),x()]);return{items:t.map(o=>({id:o.id,downloadUrl:o.downloadUrl,mimeType:o.mimeType,version:o.version,protected:o.protected,priority:o.priority,ttl:o.ttl,totalBytes:o.totalBytes,metadata:o.metadata,registeredAt:o.registeredAt,updatedAt:o.updatedAt,downloadStatus:o.status??null,bytesDownloaded:o.bytesDownloaded??0,progress:o.totalBytes&&o.bytesDownloaded?Math.round(o.bytesDownloaded/o.totalBytes*100):null,retryCount:o.retryCount??0,lastAttemptAt:o.lastAttemptAt??null,errorMessage:o.errorMessage??null,deferredReason:o.deferredReason??null,completedAt:o.completedAt??null,expiresAt:o.expiresAt??null})).sort((o,n)=>o.priority-n.priority),storage:{usageBytes:e.usage,quotaBytes:e.quota,availableBytes:e.available,usageFormatted:B(e.usage),quotaFormatted:B(e.quota),availableFormatted:B(e.available)}}}async function it(t){let e=await p(s.REGISTRY,t);return e?{id:e.id,downloadUrl:e.downloadUrl,mimeType:e.mimeType??null,version:e.version,protected:e.protected,priority:e.priority,ttl:e.ttl,totalBytes:e.totalBytes,metadata:e.metadata,registeredAt:e.registeredAt,updatedAt:e.updatedAt,downloadStatus:e.status??null,bytesDownloaded:e.bytesDownloaded??0,progress:e.totalBytes&&e.bytesDownloaded?Math.round(e.bytesDownloaded/e.totalBytes*100):null,retryCount:e.retryCount??0,lastAttemptAt:e.lastAttemptAt??null,errorMessage:e.errorMessage??null,deferredReason:e.deferredReason??null,completedAt:e.completedAt??null,expiresAt:e.expiresAt??null}:null}async function lt(t){let e=await p(s.DOWNLOAD_QUEUE,t);return nt.has(e?.status)}async function Xt(t){let e=await p(s.DOWNLOAD_QUEUE,t);e&&await m(s.DOWNLOAD_QUEUE,{...e,status:l.PENDING,data:null,bytesDownloaded:0,byteOffset:0,retryCount:0,errorMessage:null,deferredReason:null,completedAt:null,expiresAt:null})}async function H(t,{removeProtected:e=!1}={}){let r=await p(s.REGISTRY,t);if(!r)throw new Error(`deleteFile: No registered file with id "${t}".`);await _(t);let o=e||!r.protected;return o?(await h(s.REGISTRY,t),await h(s.DOWNLOAD_QUEUE,t)):await Xt(t),u("deleted",{id:t,registryRemoved:o}),{id:t,registryRemoved:o}}async function ut({removeProtected:t=!1}={}){await S();let e=await G(s.REGISTRY);return Promise.all(e.map(r=>H(r,{removeProtected:t})))}async function Tt(t){let[e,r]=await Promise.all([p(s.REGISTRY,t),p(s.DOWNLOAD_QUEUE,t)]);if(!e)throw new Error(`retrieve: No registered file with id "${t}".`);if(!nt.has(r?.status)||!r?.data)throw new Error(`retrieve: File "${t}" has no data yet (status: ${r?.status??"unknown"}).`);return{data:r.data,mimeType:r.mimeType}}var Kt={setDBInfo:wt,dbGetAllIds:G,registerFile:j,registerFiles:at,startDownloads:tt,stopDownloads:$,retryFailed:et,isDownloading:rt,abortDownload:_,abortAllDownloads:S,startMonitoring:ot,stopMonitoring:W,isOnline:O,isMonitoring:q,updateConnectivityStatus:J,retrieve:Tt,getAllStatus:st,getStatus:it,isReady:lt,delete:H,deleteAll:ut,on:C,off:N,once:K,getStorageEstimate:x,requestPersistentStorage:z,isPersistentStorage:V},zt=Kt;return Lt(Vt);})();
|
package/package.json
CHANGED
package/types/registry.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patches status fields onto the registry record so status reads
|
|
3
|
+
* only need to query the registry store, never the download queue.
|
|
4
|
+
* Exported so downloader.js can call it via updateQueue.
|
|
5
|
+
* @param {string} id
|
|
6
|
+
* @param {object} patch
|
|
7
|
+
*/
|
|
8
|
+
export function syncStatusToRegistry(id: string, patch: object): Promise<void>;
|
|
1
9
|
/**
|
|
2
10
|
* Computes the expiresAt timestamp from a completedAt time and a ttl (seconds).
|
|
3
11
|
* Returns null if ttl is absent, zero, or falsy (meaning never expires).
|
|
@@ -56,7 +64,8 @@ export function updateRegistryMetadata(id: string, metadata: Object): Promise<vo
|
|
|
56
64
|
export function evaluateExpiry(): Promise<string[]>;
|
|
57
65
|
/**
|
|
58
66
|
* Returns a merged view of all registry entries with their current download
|
|
59
|
-
* state, plus a storage summary.
|
|
67
|
+
* state, plus a storage summary. Status fields are read directly from the
|
|
68
|
+
* registry — the download queue is not consulted.
|
|
60
69
|
*
|
|
61
70
|
* @returns {Promise<{ items: object[], storage: object }>}
|
|
62
71
|
*/
|
|
@@ -66,7 +75,8 @@ export function getAllStatus(): Promise<{
|
|
|
66
75
|
}>;
|
|
67
76
|
/**
|
|
68
77
|
* Returns the full merged status object for a single registered file,
|
|
69
|
-
* or null if not registered.
|
|
78
|
+
* or null if not registered. Status fields are read directly from the
|
|
79
|
+
* registry — the download queue is not consulted.
|
|
70
80
|
*
|
|
71
81
|
* @param {string} id
|
|
72
82
|
* @returns {Promise<object|null>}
|