@sweidos/eidos 2.1.0 → 2.3.0
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.
- package/README.md +290 -22
- package/dist/action.d.ts +22 -0
- package/dist/action.js +47 -47
- package/dist/action.js.map +1 -1
- package/dist/async-storage-adapter.d.ts +25 -0
- package/dist/debug.d.ts +46 -0
- package/dist/debug.js +43 -0
- package/dist/debug.js.map +1 -0
- package/dist/devtools.js +350 -21
- package/dist/eidos-sw.js +60 -19
- package/dist/eidos.cjs +5 -5
- package/dist/eidos.cjs.map +1 -1
- package/dist/idb.d.ts +10 -0
- package/dist/index.d.ts +20 -586
- package/dist/index.js +47 -41
- package/dist/internal/url-base64.d.ts +2 -0
- package/dist/query.d.ts +1 -2
- package/dist/queue-storage.d.ts +12 -0
- package/dist/queue-sync.d.ts +32 -0
- package/dist/react/Provider.d.ts +16 -0
- package/dist/react/ProviderRN.d.ts +0 -1
- package/dist/react/hooks.d.ts +51 -0
- package/dist/react/hooks.js +30 -27
- package/dist/react/hooks.js.map +1 -1
- package/dist/replay.d.ts +15 -0
- package/dist/resource.d.ts +32 -0
- package/dist/resource.js +80 -78
- package/dist/resource.js.map +1 -1
- package/dist/runtime-rn.d.ts +0 -1
- package/dist/runtime.d.ts +39 -0
- package/dist/runtime.js +32 -24
- package/dist/runtime.js.map +1 -1
- package/dist/store-slices.d.ts +26 -0
- package/dist/store-slices.js +31 -20
- package/dist/store-slices.js.map +1 -1
- package/dist/store.d.ts +15 -0
- package/dist/store.js +22 -19
- package/dist/store.js.map +1 -1
- package/dist/stores.d.ts +64 -0
- package/dist/stores.js +31 -22
- package/dist/stores.js.map +1 -1
- package/dist/sveltekit.d.ts +0 -1
- package/dist/sw-bridge.d.ts +24 -0
- package/dist/sw-bridge.js +69 -54
- package/dist/sw-bridge.js.map +1 -1
- package/dist/testing.cjs +3 -2
- package/dist/testing.d.ts +1 -2
- package/dist/testing.js +3 -2
- package/dist/types.d.ts +305 -0
- package/dist/types.js +19 -8
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/vite.d.ts +0 -1
- package/package.json +9 -7
package/dist/eidos.cjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let R=require("react"),V=require("react/jsx-runtime");function X(){return{queued:0,succeeded:0,failed:0,retried:0,conflicted:0,cancelled:0}}function z(e){let t=0,n=0,r=0;for(const a of e)a.status==="pending"?t++:a.status==="failed"?n++:a.status==="replaying"&&r++;return{pending:t,failed:n,replaying:r,total:e.length}}function ve(e){return{registerResource:(t,n)=>e(r=>({resources:{...r.resources,[t]:n}})),updateResource:(t,n)=>e(r=>({resources:{...r.resources,[t]:r.resources[t]?{...r.resources[t],...n}:r.resources[t]}})),unregisterResource:t=>e(n=>({resources:Object.fromEntries(Object.entries(n.resources).filter(([r])=>r!==t))}))}}function me(e){return{addQueueItem:t=>e(n=>({queue:[...n.queue,t]})),updateQueueItem:(t,n)=>e(r=>({queue:r.queue.map(a=>a.id===t?{...a,...n}:a)})),batchUpdateQueueItems:t=>e(n=>{const r=new Map(t.map(a=>[a.id,a.update]));return{queue:n.queue.map(a=>{const s=r.get(a.id);return s?{...a,...s}:a})}}),removeQueueItem:t=>e(n=>({queue:n.queue.filter(r=>r.id!==t)})),hydrateQueue:t=>e(()=>({queue:t}))}}function Se(e){return{recordReliabilityEvent:t=>e(n=>({reliability:{...n.reliability,[t]:n.reliability[t]+1}})),resetReliabilityStats:()=>e(()=>({reliability:X()}))}}var w,M=new Set;function Z(){M.forEach(e=>e())}function E(e){w={...w,...e(w)},Z()}w={isOnline:typeof navigator>"u"||navigator.onLine!==!1,swStatus:"idle",swError:void 0,resources:{},queue:[],reliability:X(),setOnline:e=>E(()=>({isOnline:e})),setSwStatus:(e,t)=>E(()=>({swStatus:e,swError:t})),...ve(E),...me(E),...Se(E)};function be(){return w}function Ee(e){return M.add(e),()=>{M.delete(e)}}var o={getState:be,subscribe:Ee,setState:e=>{const t=typeof e=="function"?e(w):e;w={...w,...t},Z()}},h=null,T=[];function H(){return h}async function Re(e,t={skipWaiting:!0}){if(typeof navigator>"u"||!("serviceWorker"in navigator)){o.getState().setSwStatus("unsupported");return}const n=o.getState();n.setSwStatus("registering");try{h=await navigator.serviceWorker.register(e,{scope:"/"}),await Ae(h),n.setSwStatus("active"),navigator.serviceWorker.addEventListener("message",Oe),window.addEventListener("online",()=>n.setOnline(!0)),window.addEventListener("offline",()=>n.setOnline(!1)),qe(),Ce(h,t)}catch(r){n.setSwStatus("error",String(r))}}function Ae(e){return new Promise(t=>{if(e.active){t();return}const n=e.installing??e.waiting;if(!n){t();return}const r=setTimeout(t,1e4);n.addEventListener("statechange",function a(){n.state==="activated"&&(clearTimeout(r),n.removeEventListener("statechange",a),t())})})}function I(e){const t=h?.active;t?t.postMessage(e):T.push(e)}var ee=null;function Ie(e){ee=e}function _e(){try{return typeof navigator<"u"&&"serviceWorker"in navigator&&h!==null&&"sync"in h}catch{return!1}}var U={};function ke(e){U=e}function Oe(e){const t=e.data;if(!t?.type)return;const n=o.getState(),{type:r,url:a}=t;if(r==="EIDOS_BACKGROUND_SYNC"){ee?.();return}if(r==="EIDOS_NOTIFICATION_CLICK"){U.onNotificationClick?.(t.data);return}if(r==="EIDOS_SUBSCRIPTION_EXPIRED"){U.onSubscriptionExpired?.(t.subscription);return}if(a)switch(r){case"EIDOS_CACHE_HIT":{const s=n.resources[a];n.updateResource(a,{status:"fresh",lastEvent:"cache-hit",cacheHits:(s?.cacheHits??0)+1});break}case"EIDOS_CACHE_UPDATED":n.updateResource(a,{status:"fresh",lastEvent:"cache-updated",cachedAt:Date.now()});break;case"EIDOS_NETWORK_ERROR":n.updateResource(a,{status:"error",lastEvent:"network-error"});break}}function xe(e){I({type:"EIDOS_SIMULATE_OFFLINE",enabled:e}),o.getState().setOnline(!e)}function qe(){const e=h?.active;if(e){for(const t of T)e.postMessage(t);T=[]}}function Ce(e,t){const n=r=>{t.skipWaiting?r.waiting?.postMessage({type:"EIDOS_SKIP_WAITING"}):t.onUpdateAvailable?.(r)};e.waiting&&navigator.serviceWorker.controller&&n(e),e.addEventListener("updatefound",()=>{const r=e.installing;r&&r.addEventListener("statechange",()=>{r.state==="installed"&&navigator.serviceWorker.controller&&n(e)})})}function Qe(){h?.waiting?.postMessage({type:"EIDOS_SKIP_WAITING"})}var v=new Map,Q=new Map,te=null;function Pe(e){te=e}function C(e){return e.includes("*")||/:[^/]+/.test(e)}function De(e){return"^"+e.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*\*/g,".+").replace(/\*/g,"[^/]+").replace(/:[^/]+/g,"[^/]+")+"$"}function ne(e,t){const n=Ue(t),r=C(e)?De(e):void 0,a={url:e,config:t,strategy:n,status:"idle",cacheHits:0,cacheMisses:0};return o.getState().registerResource(e,a),I({type:"EIDOS_REGISTER_RESOURCE",url:e,strategy:n.swStrategy,cacheName:n.cacheName,...r!==void 0&&{pattern:r},...t.maxAge!==void 0&&{maxAge:t.maxAge},...t.maxEntries!==void 0&&{maxEntries:t.maxEntries}}),{strategy:n,regexStr:r}}function re(e,t,n){return async()=>{I({type:"EIDOS_CLEAR_CACHE",url:e});const r=await caches.open(t.cacheName).catch(()=>null);if(r){const a=await r.keys(),s=n?new RegExp(n):null,i=e.startsWith("http");await Promise.all(a.filter(c=>{const u=c.url,f=new URL(u).pathname;return s?s.test(i?u:f):i?u===e:u===e||f===e}).map(c=>r.delete(c)))}C(e)||o.getState().updateResource(e,{status:"stale",cachedAt:void 0,lastEvent:"cache-cleared",cacheHits:0,cacheMisses:0}),te?.(["eidos",e])}}function ae(e){return()=>{v.delete(e),I({type:"EIDOS_UNREGISTER_RESOURCE",url:e}),o.getState().unregisterResource(e)}}function Ne(e,t){if(C(e))throw new Error(`[eidos] resource('${e}') is a URL pattern — use resourcePattern('${e}', config) instead. Pattern handles only support invalidate()/unregister(); the SW intercepts matching requests automatically.`);if(v.has(e))return v.get(e);const{strategy:n}=ne(e,t),r={url:e,config:t,strategy:n,fetch:async()=>{const a=Q.get(e);if(a)return a.then(i=>i.clone());const s=Te(e,t,n);return Q.set(e,s),s.finally(()=>Q.delete(e)).catch(()=>{}),s.then(i=>i.clone())},json:async()=>(await r.fetch()).json(),query:()=>({queryKey:["eidos",e],queryFn:()=>r.json()}),prefetch:async()=>{await r.fetch()},invalidate:re(e,n,void 0),unregister:ae(e)};return v.set(e,r),r}function Me(e,t){if(!C(e))throw new Error(`[eidos] resourcePattern('${e}') is not a URL pattern — use resource('${e}', config) instead.`);if(v.has(e))return v.get(e);const{strategy:n,regexStr:r}=ne(e,t),a={url:e,config:t,strategy:n,invalidate:re(e,n,r),unregister:ae(e)};return v.set(e,a),a}async function Te(e,t,n){const r=o.getState();r.updateResource(e,{status:"fetching",fetchedAt:Date.now()});const a=await caches.open(n.cacheName).catch(()=>null);try{if(n.swStrategy!=="network-first"){const c=a?await a.match(e).catch(()=>null):null,u=o.getState().resources[e],f=t.maxAge!==void 0&&u?.cachedAt!==void 0&&Date.now()-u.cachedAt>t.maxAge;if(c&&!f)return r.updateResource(e,{status:"fresh",lastEvent:"cache-hit",cacheHits:(u?.cacheHits??0)+1}),n.swStrategy==="stale-while-revalidate"&&fetch(e,{signal:AbortSignal.timeout(5e3)}).then(async S=>{S.ok&&a&&(await a.put(e,S.clone()),o.getState().updateResource(e,{cachedAt:Date.now(),lastEvent:"cache-updated"}))}).catch(()=>{}),c;const p=o.getState().resources[e];r.updateResource(e,{cacheMisses:(p?.cacheMisses??0)+1})}const s=await fetch(e);if(s.ok)return a&&await a.put(e,s.clone()),r.updateResource(e,{status:"fresh",cachedAt:Date.now(),lastEvent:"cache-updated"}),s;r.updateResource(e,{status:s.status===503?"offline":"error"});const i=s.headers.get("X-Eidos-Offline")==="true";throw new Error(i?`offline: no cached response for ${e}`:`${s.status} ${s.statusText}`)}catch(s){const i=a?await a.match(e).catch(()=>null):null;if(i){const c=o.getState().resources[e];return r.updateResource(e,{status:"fresh",lastEvent:"cache-hit",cacheHits:(c?.cacheHits??0)+1}),i}throw r.updateResource(e,{status:"error"}),s}}function Ue(e){const t=e.strategy;return e.offline?G(t??"stale-while-revalidate",e.cacheName,e.version):G(t??"network-first",e.cacheName,e.version)}var je={"stale-while-revalidate":"StaleWhileRevalidate","cache-first":"CacheFirst","network-first":"NetworkFirst"},Ke={"stale-while-revalidate":{reasoning:"offline: true signals resilience. SWR returns cached data instantly while revalidating in the background — the best tradeoff between speed and freshness for offline-capable resources.",behavior:["Cache hit → return immediately, kick off background revalidation","Cache miss → fetch from network, cache the response, return it","Offline → return cached version if available, 503 if not","Reconnect → next request triggers a background refresh"],equivalentCode:`// Workbox equivalent (maxEntries/maxAge are configured via ResourceConfig)
|
|
2
2
|
new StaleWhileRevalidate({
|
|
3
3
|
cacheName: 'eidos-resources-v1',
|
|
4
|
-
plugins: [new ExpirationPlugin({ maxEntries:
|
|
5
|
-
})`},"cache-first":{reasoning:"cache-first maximises speed and offline availability. Network is consulted only on cache miss. Best for static or infrequently-updated data.",behavior:["Cache hit → return immediately, no network request made","Cache miss → fetch from network, cache the response, return it","Offline → return cached version, 503 if cache is empty","Cache never expires unless explicitly invalidated"],equivalentCode:`// Workbox equivalent
|
|
4
|
+
plugins: [new ExpirationPlugin({ maxEntries: config.maxEntries, maxAgeSeconds: config.maxAge && config.maxAge / 1000 })],
|
|
5
|
+
})`},"cache-first":{reasoning:"cache-first maximises speed and offline availability. Network is consulted only on cache miss. Best for static or infrequently-updated data.",behavior:["Cache hit → return immediately, no network request made","Cache miss → fetch from network, cache the response, return it","Offline → return cached version, 503 if cache is empty","Cache never expires unless maxAge is set or explicitly invalidated"],equivalentCode:`// Workbox equivalent (maxEntries/maxAge are configured via ResourceConfig)
|
|
6
6
|
new CacheFirst({
|
|
7
7
|
cacheName: 'eidos-resources-v1',
|
|
8
|
-
plugins: [new ExpirationPlugin({ maxEntries:
|
|
8
|
+
plugins: [new ExpirationPlugin({ maxEntries: config.maxEntries, maxAgeSeconds: config.maxAge && config.maxAge / 1000 })],
|
|
9
9
|
})`},"network-first":{reasoning:"network-first prioritises fresh data. Cache acts as a safety net when offline. Best for frequently-updated resources where stale data causes problems.",behavior:["Always try network first","Network success → update cache, return fresh response","Network failure → fall back to cached version","Offline with empty cache → return 503 error response"],equivalentCode:`// Workbox equivalent
|
|
10
10
|
new NetworkFirst({
|
|
11
11
|
cacheName: 'eidos-resources-v1',
|
|
12
12
|
networkTimeoutSeconds: 3,
|
|
13
|
-
})`}};function H(e,t,r){const n=Pe[e],a=t??"eidos-resources-v1";return{name:xe[e],swStrategy:e,cacheName:r!==void 0?`${a}-v${r}`:a,reasoning:n.reasoning,behavior:n.behavior,equivalentCode:""}}async function Ne(e){const t=await Promise.allSettled(e.map(n=>n.prefetch())),r=t.filter(n=>n.status==="rejected").map(n=>n.reason);return{warmed:t.filter(n=>n.status==="fulfilled").length,failed:r.length,errors:r}}var De="eidos",Te=1,l="action-queue",x=null;function b(){return x?Promise.resolve(x):new Promise((e,t)=>{const r=indexedDB.open(De,Te);r.onupgradeneeded=n=>{const a=n.target.result;if(!a.objectStoreNames.contains(l)){const s=a.createObjectStore(l,{keyPath:"id"});s.createIndex("status","status",{unique:!1}),s.createIndex("actionId","actionId",{unique:!1})}},r.onsuccess=()=>{x=r.result,e(r.result)},r.onerror=()=>t(r.error)})}async function Me(e){const t=await b();return new Promise((r,n)=>{const a=t.transaction(l,"readwrite");a.objectStore(l).add(e),a.oncomplete=()=>r(),a.onerror=()=>n(a.error)})}async function te(){const e=await b();return new Promise((t,r)=>{const n=e.transaction(l,"readonly").objectStore(l).getAll();n.onsuccess=()=>t(n.result),n.onerror=()=>r(n.error)})}async function je(e,t){const r=await b();return new Promise((n,a)=>{const s=r.transaction(l,"readwrite"),i=s.objectStore(l),c=i.get(e);c.onsuccess=()=>{c.result&&i.put({...c.result,...t})},s.oncomplete=()=>n(),s.onerror=()=>a(s.error)})}async function Ue(e){const t=await b();return new Promise((r,n)=>{const a=t.transaction(l,"readwrite");a.objectStore(l).delete(e),a.oncomplete=()=>r(),a.onerror=()=>n(a.error)})}async function Ke(){const e=await b();function t(a){return new Promise((s,i)=>{const c=e.transaction(l,"readonly").objectStore(l).index("status"),u=[],f=c.openCursor(IDBKeyRange.only(a));f.onsuccess=p=>{const m=p.target.result;m?(u.push(m.value),m.continue()):s(u)},f.onerror=()=>i(f.error)})}const[r,n]=await Promise.all([t("pending"),t("failed")]);return[...r,...n]}async function $e(){const e=await b();return new Promise((t,r)=>{const n=e.transaction(l,"readwrite");n.objectStore(l).clear(),n.oncomplete=()=>t(),n.onerror=()=>r(n.error)})}var ne={add:Me,getAll:te,getPending:Ke,update:je,remove:Ue,clear:$e},re=null;function Le(e){re=e}function W(){return re}var We="eidos-queue-sync",k;function ae(){return k!==void 0||(k=typeof BroadcastChannel>"u"?null:new BroadcastChannel(We)),k}function h(e){ae()?.postMessage(e)}function Be(){const e=ae();if(!e)return()=>{};const t=r=>{const n=o.getState(),a=r.data;switch(a.type){case"update":n.updateQueueItem(a.id,a.update);break;case"batchUpdate":n.batchUpdateQueueItems(a.updates);break;case"remove":n.removeQueueItem(a.id);break}};return e.addEventListener("message",t),()=>e.removeEventListener("message",t)}function se(e){let t=0,r=0,n=0;for(const a of e)a.status==="pending"?t++:a.status==="failed"?r++:a.status==="replaying"&&n++;return{pending:t,failed:r,replaying:n,total:e.length}}var A=new Map,ie=new Map,oe=new Map,ce=new Map,R=new Map;function d(){return W()??ne}function j(){return crypto.randomUUID()}function U(e,t,r){return e(...t,r)}function He(e,t){const r=t.name||e.name||j(),n=t.namespace?`${t.namespace}::${r}`:r;if(A.has(n))throw new Error(`[eidos] duplicate action id "${n}" — an action with this id is already registered. Pass a unique config.name or config.namespace.`);A.set(n,e),ce.set(n,t),t.onRollback&&ie.set(n,t.onRollback),t.conflict&&oe.set(n,t.conflict);const a=async(...s)=>{const{isOnline:i}=o.getState(),c=j();let u;if(t.cancellable){const p=new AbortController;R.set(c,p),u=p.signal}const f={idempotencyKey:c,attempt:0,signal:u};t.onOptimistic?.(...s,f);try{if(t.reliability==="neverLose"){if(!i)return F(n,n,s,t,c);try{return await U(e,s,f)}catch(p){if(de(p))throw p;return F(n,n,s,t,c)}}try{return await U(e,s,f)}catch(p){throw t.onRollback?.(...s,f),p}}finally{t.cancellable&&R.delete(c)}};return Object.defineProperty(a,"id",{value:n,writable:!1}),Object.defineProperty(a,"config",{value:t,writable:!1}),Object.defineProperty(a,"cancel",{value:ue,writable:!1}),a}async function ue(e){const t=R.get(e);if(t)return t.abort(),!0;const r=(await d().getAll()).find(n=>n.idempotencyKey===e&&n.status==="pending");return r?(o.getState().removeQueueItem(r.id),h({type:"remove",id:r.id}),await d().remove(r.id),!0):!1}async function Fe(e){const t=(await d().getAll()).find(n=>n.id===e);if(!t||t.status!=="failed")return!1;const r={status:"pending",error:void 0,nextRetryAt:void 0,retryCount:0};return o.getState().updateQueueItem(e,r),h({type:"update",id:e,update:r}),await d().update(e,r),!0}async function F(e,t,r,n,a){const s=j(),i={schemaVersion:2,id:s,actionId:e,actionName:t,idempotencyKey:a,args:r,queuedAt:Date.now(),retryCount:0,maxRetries:n.maxRetries??3,status:"pending",priority:n.priority??"normal"};await d().add(i),o.getState().addQueueItem(i);try{const c=Y();c&&"sync"in c&&await c.sync.register("eidos-queue-replay")}catch{}return{queued:!0,id:s,message:`"${t}" queued — will execute when online`}}function de(e){return e instanceof DOMException&&e.name==="AbortError"}function Ve(e){if(e instanceof Response)return e.status>=400&&e.status<500;if(typeof e=="object"&&e!==null){const t=e.status;if(typeof t=="number")return t>=400&&t<500}return!1}function Ge(e){return Math.min(2e3*2**e,3e5)*(.8+Math.random()*.4)}function O(){return{attempted:0,succeeded:0,failed:0,retrying:0,skipped:0,conflicted:0,cancelled:0}}var P=!1,Ye="eidos-queue-replay";async function q(){const e=o.getState();if(!e.isOnline)return O();if(typeof navigator<"u"&&navigator.locks)return navigator.locks.request(Ye,{ifAvailable:!0},async t=>t?V(e):O());if(P)return O();P=!0;try{return await V(e)}finally{P=!1}}async function Je(e,t){const r=Date.now();t.updateQueueItem(e.id,{status:"succeeded",completedAt:r}),h({type:"update",id:e.id,update:{status:"succeeded",completedAt:r}}),await d().update(e.id,{status:"succeeded",completedAt:r}),setTimeout(()=>{t.removeQueueItem(e.id),h({type:"remove",id:e.id}),d().remove(e.id)},3e3)}async function Xe(e,t,r){const n=oe.get(e.actionId);let a;if(n)switch(n.strategy){case"serverWins":a="skip";break;case"clientWins":a="retry";break;case"merge":case"custom":{const s={error:r,args:e.args,attempt:e.retryCount,idempotencyKey:e.idempotencyKey};a=n.resolve?.(s)??"retry";break}}if(a==="skip")return t.removeQueueItem(e.id),h({type:"remove",id:e.id}),await d().remove(e.id),"conflicted";a&&typeof a=="object"&&(e.args=a.resolved,t.updateQueueItem(e.id,{args:a.resolved}),h({type:"update",id:e.id,update:{args:a.resolved}}),await d().update(e.id,{args:a.resolved}))}async function ze(e,t,r){const n=e.retryCount+1;if(n>=e.maxRetries){const s={status:"failed",error:String(r),retryCount:n};t.updateQueueItem(e.id,s),h({type:"update",id:e.id,update:s}),await d().update(e.id,s);const i={idempotencyKey:e.idempotencyKey,attempt:n};return ie.get(e.actionId)?.(...e.args,i),"failed"}const a={status:"pending",retryCount:n,nextRetryAt:Date.now()+Ge(n)};return t.updateQueueItem(e.id,a),h({type:"update",id:e.id,update:a}),await d().update(e.id,a),"retrying"}async function Ze(e,t){const r=A.get(e.actionId);if(!r)return"skipped";const n=ce.get(e.actionId)?.cancellable;let a;if(n){const i=new AbortController;R.set(e.idempotencyKey,i),a=i.signal}const s={idempotencyKey:e.idempotencyKey,attempt:e.retryCount,signal:a};try{return await U(r,e.args,s),await Je(e,t),"succeeded"}catch(i){if(de(i))return t.removeQueueItem(e.id),h({type:"remove",id:e.id}),await d().remove(e.id),"cancelled";if(Ve(i)){const c=await Xe(e,t,i);if(c)return c}return ze(e,t,i)}finally{n&&R.delete(e.idempotencyKey)}}async function et(e,t,r){if(e.length===0)return;const n=e.filter(s=>A.has(s.actionId));if(r.skipped+=e.length-n.length,n.length>0){const s=n.map(i=>({id:i.id,update:{status:"replaying"}}));t.batchUpdateQueueItems(s),h({type:"batchUpdate",updates:s});for(const i of n)d().update(i.id,{status:"replaying"})}const a=await Promise.allSettled(n.map(s=>Ze(s,t)));for(const s of a){const i=s.status==="fulfilled"?s.value:"failed";i==="skipped"?r.skipped++:i==="conflicted"?r.conflicted++:i==="cancelled"?r.cancelled++:(r.attempted++,r[i]++)}}async function V(e){const t=await d().getPending(),r=Date.now(),n=t.filter(s=>s.retryCount<s.maxRetries&&(!s.nextRetryAt||s.nextRetryAt<=r)),a=O();for(const s of["high","normal","low"])await et(n.filter(i=>(i.priority??"normal")===s),e,a);return a}async function tt(){await d().clear(),o.getState().hydrateQueue([])}function le(){let e=o.getState().isOnline;const t=o.subscribe(()=>{const{isOnline:a}=o.getState(),s=a&&!e;e=a,s&&setTimeout(q,600)}),r=o.getState(),n=r.queue.some(a=>a.status==="pending");return r.isOnline&&n&&setTimeout(q,1200),t}async function nt(e){if(e.schemaVersion===2&&e.idempotencyKey)return e;const t={...e,schemaVersion:2,idempotencyKey:e.idempotencyKey??crypto.randomUUID()};return await(W()??ne).update(t.id,{schemaVersion:t.schemaVersion,idempotencyKey:t.idempotencyKey}).catch(()=>{}),t}var K=!1,$=null,L=null;async function fe(e={}){if(typeof window>"u"||K)return;K=!0;const t=e.swPath??"/eidos-sw.js",r=e.autoReplay??!0;try{const n=await te();if(n.length>0){const a=await Promise.all(n.map(nt));o.getState().hydrateQueue(a)}}catch{}try{await ve(t)}catch{}Se(()=>{o.getState().isOnline&&setTimeout(q,200)}),r&&($=le()),L=Be()}function rt(){$?.(),$=null,L?.(),L=null,K=!1}var N="@eidos:queue",at=class{constructor(e){this.storage=e}async readAll(){try{const e=await this.storage.getItem(N);return e?JSON.parse(e):[]}catch{return[]}}async writeAll(e){await this.storage.setItem(N,JSON.stringify(e))}async add(e){const t=await this.readAll();t.push(e),await this.writeAll(t)}async getAll(){return this.readAll()}async getPending(){return(await this.readAll()).filter(e=>e.status==="pending"||e.status==="failed")}async update(e,t){const r=await this.readAll(),n=r.findIndex(a=>a.id===e);n!==-1&&(r[n]={...r[n],...t}),await this.writeAll(r)}async remove(e){const t=await this.readAll();await this.writeAll(t.filter(r=>r.id!==e))}async clear(){await this.storage.removeItem(N)}};function st({children:e,swPath:t,autoReplay:r}){return(0,S.useEffect)(()=>{fe({swPath:t,autoReplay:r})},[]),(0,B.jsx)(B.Fragment,{children:e})}function y(e){const t=e??(r=>r);return(0,S.useSyncExternalStore)(o.subscribe,()=>t(o.getState()))}function it(){return y()}function ot(){return y(e=>e.resources)}function ct(e){return y(t=>t.resources[e])}function ut(){return y(e=>e.queue)}function dt(e){return y(t=>t.queue.find(r=>r.id===e))}function lt(){return{isOnline:y(e=>e.isOnline),swStatus:y(e=>e.swStatus),swError:y(e=>e.swError)}}function ft(){const[e,t,r,n]=y(a=>{const{pending:s,failed:i,replaying:c,total:u}=se(a.queue);return`${s},${i},${c},${u}`}).split(",");return{pending:+e,failed:+t,replaying:+r,total:+n}}function pt(e){const t=y(a=>a.queue.length),r=(0,S.useRef)(0),n=(0,S.useRef)(e);(0,S.useEffect)(()=>{n.current=e}),(0,S.useEffect)(()=>{r.current>0&&t===0&&n.current(),r.current=t},[t])}var yt="2.1.0";function ht(e,t){const r=Object.keys(e);if(r.length!==Object.keys(t).length)return!1;for(const n of r)if(e[n]!==t[n])return!1;return!0}function pe(e,t){return ht(e,t)}function E(e,t=Object.is){return{subscribe(r){let n=e(o.getState());return r(n),o.subscribe(()=>{const a=e(o.getState());t(n,a)||(n=a,r(a))})},getState(){return e(o.getState())}}}var gt=E(e=>e),wt=E(e=>e.queue),vt=E(e=>({isOnline:e.isOnline,swStatus:e.swStatus,swError:e.swError}),pe),mt=E(e=>se(e.queue),pe);function St(e){return E(t=>t.resources[e])}function bt(e){return E(t=>t.queue.find(r=>r.id===e))}exports.AsyncStorageQueueStorage=at;exports.EidosProvider=st;exports.VERSION=yt;exports._getQueueStorage=W;exports._resetEidos=rt;exports.action=He;exports.cancelByIdempotencyKey=ue;exports.clearQueue=tt;exports.eidosAction=bt;exports.eidosQueue=wt;exports.eidosQueueStats=mt;exports.eidosResource=St;exports.eidosStatus=vt;exports.eidosStore=gt;exports.getSwRegistration=Y;exports.initEidos=fe;exports.isBgSyncSupported=be;exports.registerPushCallbacks=Ee;exports.replayQueue=q;exports.requeueItem=Fe;exports.resource=Ae;exports.resourcePattern=qe;exports.sendToWorker=I;exports.setOfflineSimulation=Ie;exports.setQueryInvalidator=ke;exports.setQueueStorage=Le;exports.subscribeReplayOnReconnect=le;exports.useEidos=it;exports.useEidosAction=dt;exports.useEidosOnDrain=pt;exports.useEidosQueue=ut;exports.useEidosQueueStats=ft;exports.useEidosResource=ct;exports.useEidosResources=ot;exports.useEidosStatus=lt;exports.useEidosStore=o;exports.warmCache=Ne;
|
|
13
|
+
})`}};function G(e,t,n){const r=Ke[e],a=t??"eidos-resources-v1";return{name:je[e],swStrategy:e,cacheName:n!==void 0?`${a}-v${n}`:a,reasoning:r.reasoning,behavior:r.behavior,equivalentCode:""}}async function We(e){const t=await Promise.allSettled(e.map(r=>r.prefetch())),n=t.filter(r=>r.status==="rejected").map(r=>r.reason);return{warmed:t.filter(r=>r.status==="fulfilled").length,failed:n.length,errors:n}}var Le="eidos",$e=1,l="action-queue",P=null;function b(){return P?Promise.resolve(P):new Promise((e,t)=>{const n=indexedDB.open(Le,$e);n.onupgradeneeded=r=>{const a=r.target.result;if(!a.objectStoreNames.contains(l)){const s=a.createObjectStore(l,{keyPath:"id"});s.createIndex("status","status",{unique:!1}),s.createIndex("actionId","actionId",{unique:!1})}},n.onsuccess=()=>{P=n.result,e(n.result)},n.onerror=()=>t(n.error)})}async function He(e){const t=await b();return new Promise((n,r)=>{const a=t.transaction(l,"readwrite");a.objectStore(l).add(e),a.oncomplete=()=>n(),a.onerror=()=>r(a.error)})}async function se(){const e=await b();return new Promise((t,n)=>{const r=e.transaction(l,"readonly").objectStore(l).getAll();r.onsuccess=()=>t(r.result),r.onerror=()=>n(r.error)})}async function Be(e,t){const n=await b();return new Promise((r,a)=>{const s=n.transaction(l,"readwrite"),i=s.objectStore(l),c=i.get(e);c.onsuccess=()=>{c.result&&i.put({...c.result,...t})},s.oncomplete=()=>r(),s.onerror=()=>a(s.error)})}async function Fe(e){const t=await b();return new Promise((n,r)=>{const a=t.transaction(l,"readwrite");a.objectStore(l).delete(e),a.oncomplete=()=>n(),a.onerror=()=>r(a.error)})}async function Ve(){const e=await b();function t(a){return new Promise((s,i)=>{const c=e.transaction(l,"readonly").objectStore(l).index("status"),u=[],f=c.openCursor(IDBKeyRange.only(a));f.onsuccess=p=>{const S=p.target.result;S?(u.push(S.value),S.continue()):s(u)},f.onerror=()=>i(f.error)})}const[n,r]=await Promise.all([t("pending"),t("failed")]);return[...n,...r]}async function Ge(){const e=await b();return new Promise((t,n)=>{const r=e.transaction(l,"readwrite");r.objectStore(l).clear(),r.oncomplete=()=>t(),r.onerror=()=>n(r.error)})}var ie={add:He,getAll:se,getPending:Ve,update:Be,remove:Fe,clear:Ge},oe=null;function Ye(e){oe=e}function B(){return oe}var Je="eidos-queue-sync",_;function ce(){return _!==void 0||(_=typeof BroadcastChannel>"u"?null:new BroadcastChannel(Je)),_}function g(e){ce()?.postMessage(e)}function Xe(){const e=ce();if(!e)return()=>{};const t=n=>{const r=o.getState(),a=n.data;switch(a.type){case"update":r.updateQueueItem(a.id,a.update);break;case"batchUpdate":r.batchUpdateQueueItems(a.updates);break;case"remove":r.removeQueueItem(a.id);break}};return e.addEventListener("message",t),()=>e.removeEventListener("message",t)}var x=new Map,ue=new Map,de=new Map,le=new Map,A=new Map;function d(){return B()??ie}function j(){return crypto.randomUUID()}function K(e,t,n){return e(...t,n)}function ze(e,t){const n=t.name||e.name||j(),r=t.namespace?`${t.namespace}::${n}`:n;if(x.has(r))throw new Error(`[eidos] duplicate action id "${r}" — an action with this id is already registered. Pass a unique config.name or config.namespace.`);x.set(r,e),le.set(r,t),t.onRollback&&ue.set(r,t.onRollback),t.conflict&&de.set(r,t.conflict);const a=async(...s)=>{const{isOnline:i}=o.getState(),c=j();let u;if(t.cancellable){const p=new AbortController;A.set(c,p),u=p.signal}const f={idempotencyKey:c,attempt:0,signal:u};t.onOptimistic?.(...s,f);try{if(t.reliability==="neverLose"){if(!i)return Y(r,r,s,t,c);try{return await K(e,s,f)}catch(p){if(pe(p))throw p;return Y(r,r,s,t,c)}}try{return await K(e,s,f)}catch(p){throw t.onRollback?.(...s,f),p}}finally{t.cancellable&&A.delete(c)}};return Object.defineProperty(a,"id",{value:r,writable:!1}),Object.defineProperty(a,"config",{value:t,writable:!1}),Object.defineProperty(a,"cancel",{value:fe,writable:!1}),a}async function fe(e){const t=A.get(e);if(t)return t.abort(),!0;const n=(await d().getAll()).find(r=>r.idempotencyKey===e&&r.status==="pending");return n?(o.getState().removeQueueItem(n.id),g({type:"remove",id:n.id}),await d().remove(n.id),!0):!1}async function Ze(e){const t=(await d().getAll()).find(r=>r.id===e);if(!t||t.status!=="failed")return!1;const n={status:"pending",error:void 0,nextRetryAt:void 0,retryCount:0};return o.getState().updateQueueItem(e,n),g({type:"update",id:e,update:n}),await d().update(e,n),!0}async function Y(e,t,n,r,a){const s=j(),i={schemaVersion:2,id:s,actionId:e,actionName:t,idempotencyKey:a,args:n,queuedAt:Date.now(),retryCount:0,maxRetries:r.maxRetries??3,status:"pending",priority:r.priority??"normal"};await d().add(i),o.getState().addQueueItem(i),o.getState().recordReliabilityEvent("queued");try{const c=H();c&&"sync"in c&&await c.sync.register("eidos-queue-replay")}catch{}return{queued:!0,id:s,message:`"${t}" queued — will execute when online`}}function pe(e){return e instanceof DOMException&&e.name==="AbortError"}function et(e){if(e instanceof Response)return e.status>=400&&e.status<500;if(typeof e=="object"&&e!==null){const t=e.status;if(typeof t=="number")return t>=400&&t<500}return!1}function tt(e){return Math.min(2e3*2**e,3e5)*(.8+Math.random()*.4)}function k(){return{attempted:0,succeeded:0,failed:0,retrying:0,skipped:0,conflicted:0,cancelled:0}}var D=!1,nt="eidos-queue-replay";async function q(){const e=o.getState();if(!e.isOnline)return k();if(typeof navigator<"u"&&navigator.locks)return navigator.locks.request(nt,{ifAvailable:!0},async t=>t?J(e):k());if(D)return k();D=!0;try{return await J(e)}finally{D=!1}}async function rt(e,t){const n=Date.now();t.updateQueueItem(e.id,{status:"succeeded",completedAt:n}),t.recordReliabilityEvent("succeeded"),g({type:"update",id:e.id,update:{status:"succeeded",completedAt:n}}),await d().update(e.id,{status:"succeeded",completedAt:n}),setTimeout(()=>{t.removeQueueItem(e.id),g({type:"remove",id:e.id}),d().remove(e.id)},3e3)}async function at(e,t,n){const r=de.get(e.actionId);let a;if(r)switch(r.strategy){case"serverWins":a="skip";break;case"clientWins":a="retry";break;case"merge":case"custom":{const s={error:n,args:e.args,attempt:e.retryCount,idempotencyKey:e.idempotencyKey};a=r.resolve?.(s)??"retry";break}}if(a==="skip")return t.removeQueueItem(e.id),t.recordReliabilityEvent("conflicted"),g({type:"remove",id:e.id}),await d().remove(e.id),"conflicted";a&&typeof a=="object"&&(e.args=a.resolved,t.updateQueueItem(e.id,{args:a.resolved}),g({type:"update",id:e.id,update:{args:a.resolved}}),await d().update(e.id,{args:a.resolved}))}async function st(e,t,n){const r=e.retryCount+1;if(r>=e.maxRetries){const s={status:"failed",error:String(n),retryCount:r};t.updateQueueItem(e.id,s),t.recordReliabilityEvent("failed"),g({type:"update",id:e.id,update:s}),await d().update(e.id,s);const i={idempotencyKey:e.idempotencyKey,attempt:r};return ue.get(e.actionId)?.(...e.args,i),"failed"}const a={status:"pending",retryCount:r,nextRetryAt:Date.now()+tt(r)};return t.updateQueueItem(e.id,a),t.recordReliabilityEvent("retried"),g({type:"update",id:e.id,update:a}),await d().update(e.id,a),"retrying"}async function it(e,t){const n=x.get(e.actionId);if(!n)return"skipped";const r=le.get(e.actionId)?.cancellable;let a;if(r){const i=new AbortController;A.set(e.idempotencyKey,i),a=i.signal}const s={idempotencyKey:e.idempotencyKey,attempt:e.retryCount,signal:a};try{return await K(n,e.args,s),await rt(e,t),"succeeded"}catch(i){if(pe(i))return t.removeQueueItem(e.id),t.recordReliabilityEvent("cancelled"),g({type:"remove",id:e.id}),await d().remove(e.id),"cancelled";if(et(i)){const c=await at(e,t,i);if(c)return c}return st(e,t,i)}finally{r&&A.delete(e.idempotencyKey)}}async function ot(e,t,n){if(e.length===0)return;const r=e.filter(s=>x.has(s.actionId));if(n.skipped+=e.length-r.length,r.length>0){const s=r.map(i=>({id:i.id,update:{status:"replaying"}}));t.batchUpdateQueueItems(s),g({type:"batchUpdate",updates:s});for(const i of r)d().update(i.id,{status:"replaying"})}const a=await Promise.allSettled(r.map(s=>it(s,t)));for(const s of a){const i=s.status==="fulfilled"?s.value:"failed";i==="skipped"?n.skipped++:i==="conflicted"?n.conflicted++:i==="cancelled"?n.cancelled++:(n.attempted++,n[i]++)}}async function J(e){const t=await d().getPending(),n=Date.now(),r=t.filter(s=>s.retryCount<s.maxRetries&&(!s.nextRetryAt||s.nextRetryAt<=n)),a=k();for(const s of["high","normal","low"])await ot(r.filter(i=>(i.priority??"normal")===s),e,a);return a}async function ct(){await d().clear(),o.getState().hydrateQueue([])}function ye(){let e=o.getState().isOnline;const t=o.subscribe(()=>{const{isOnline:a}=o.getState(),s=a&&!e;e=a,s&&setTimeout(q,600)}),n=o.getState(),r=n.queue.some(a=>a.status==="pending");return n.isOnline&&r&&setTimeout(q,1200),t}async function ut(e){if(e.schemaVersion===2&&e.idempotencyKey)return e;const t={...e,schemaVersion:2,idempotencyKey:e.idempotencyKey??crypto.randomUUID()};return await(B()??ie).update(t.id,{schemaVersion:t.schemaVersion,idempotencyKey:t.idempotencyKey}).catch(()=>{}),t}var W=!1,L=null,$=null,O=null;async function ge(e={}){if(typeof window>"u"||W)return;W=!0;const t=e.swPath??"/eidos-sw.js",n=e.autoReplay??!0,r=e.skipWaiting??!0;try{const a=await se();if(a.length>0){const s=await Promise.all(a.map(ut));o.getState().hydrateQueue(s)}}catch{}try{await Re(t,{skipWaiting:r,onUpdateAvailable:e.onUpdateAvailable})}catch{}if(Ie(()=>{o.getState().isOnline&&setTimeout(q,200)}),n&&(L=ye()),$=Xe(),e.onReliabilityReport){const a=e.reliabilityReportInterval??6e4,s=e.onReliabilityReport;O=setInterval(()=>{s(o.getState().reliability)},a)}}function dt(){L?.(),L=null,$?.(),$=null,O&&clearInterval(O),O=null,W=!1}var N="@eidos:queue",lt=class{constructor(e){this.storage=e}async readAll(){try{const e=await this.storage.getItem(N);return e?JSON.parse(e):[]}catch{return[]}}async writeAll(e){await this.storage.setItem(N,JSON.stringify(e))}async add(e){const t=await this.readAll();t.push(e),await this.writeAll(t)}async getAll(){return this.readAll()}async getPending(){return(await this.readAll()).filter(e=>e.status==="pending"||e.status==="failed")}async update(e,t){const n=await this.readAll(),r=n.findIndex(a=>a.id===e);r!==-1&&(n[r]={...n[r],...t}),await this.writeAll(n)}async remove(e){const t=await this.readAll();await this.writeAll(t.filter(n=>n.id!==e))}async clear(){await this.storage.removeItem(N)}};function ft({children:e,swPath:t,autoReplay:n}){return(0,R.useEffect)(()=>{ge({swPath:t,autoReplay:n})},[]),(0,V.jsx)(V.Fragment,{children:e})}function pt(e,t){const n=Object.keys(e);if(n.length!==Object.keys(t).length)return!1;for(const r of n)if(e[r]!==t[r])return!1;return!0}function F(e,t){return pt(e,t)}function m(e,t=Object.is){return{subscribe(n){let r=e(o.getState());return n(r),o.subscribe(()=>{const a=e(o.getState());t(r,a)||(r=a,n(a))})},getState(){return e(o.getState())}}}var yt=m(e=>e),gt=m(e=>e.queue),ht=m(e=>({isOnline:e.isOnline,swStatus:e.swStatus,swError:e.swError}),F),wt=m(e=>z(e.queue),F),vt=m(e=>e.reliability,F);function mt(e){return m(t=>t.resources[e])}function St(e){return m(t=>t.queue.find(n=>n.id===e))}function he(e){let t=o.getState().queue.length;return o.subscribe(()=>{const n=o.getState().queue.length;t>0&&n===0&&e(),t=n})}function y(e){const t=e??(n=>n);return(0,R.useSyncExternalStore)(o.subscribe,()=>t(o.getState()))}function bt(){return y()}function Et(){return y(e=>e.resources)}function Rt(e){return y(t=>t.resources[e])}function At(){return y(e=>e.queue)}function It(e){return y(t=>t.queue.find(n=>n.id===e))}function _t(){return{isOnline:y(e=>e.isOnline),swStatus:y(e=>e.swStatus),swError:y(e=>e.swError)}}function kt(){const[e,t,n,r]=y(a=>{const{pending:s,failed:i,replaying:c,total:u}=z(a.queue);return`${s},${i},${c},${u}`}).split(",");return{pending:+e,failed:+t,replaying:+n,total:+r}}function Ot(){return y(e=>e.reliability)}function xt(e){const t=(0,R.useRef)(e);(0,R.useEffect)(()=>{t.current=e}),(0,R.useEffect)(()=>he(()=>t.current()),[])}var we="2.3.0";function qt(){const e=o.getState(),t=H();return{version:we,swStatus:e.swStatus,...e.swError!==void 0&&{swError:e.swError},isOnline:e.isOnline,resourceCount:Object.keys(e.resources).length,resources:Object.fromEntries(Object.entries(e.resources).map(([n,r])=>[n,{url:r.url,strategy:r.strategy.swStrategy,status:r.status,cacheHits:r.cacheHits,cacheMisses:r.cacheMisses,...r.cachedAt!==void 0&&{cachedAt:r.cachedAt}}])),queue:e.queue.map(n=>({id:n.id,actionId:n.actionId,actionName:n.actionName,status:n.status,retryCount:n.retryCount,maxRetries:n.maxRetries,idempotencyKey:n.idempotencyKey,schemaVersion:n.schemaVersion,queuedAt:n.queuedAt})),reliability:{...e.reliability},swRegistration:t?{scope:t.scope,scriptURL:(t.active??t.waiting??t.installing)?.scriptURL??"",state:t.installing?"installing":t.waiting?"waiting":t.active?"active":null}:null}}exports.AsyncStorageQueueStorage=lt;exports.EidosProvider=ft;exports.VERSION=we;exports._getQueueStorage=B;exports._resetEidos=dt;exports.action=ze;exports.cancelByIdempotencyKey=fe;exports.clearQueue=ct;exports.eidosAction=St;exports.eidosDebug=qt;exports.eidosQueue=gt;exports.eidosQueueStats=wt;exports.eidosReliabilityStats=vt;exports.eidosResource=mt;exports.eidosStatus=ht;exports.eidosStore=yt;exports.getSwRegistration=H;exports.initEidos=ge;exports.isBgSyncSupported=_e;exports.onQueueDrain=he;exports.registerPushCallbacks=ke;exports.replayQueue=q;exports.requeueItem=Ze;exports.resource=Ne;exports.resourcePattern=Me;exports.sendToWorker=I;exports.setOfflineSimulation=xe;exports.setQueryInvalidator=Pe;exports.setQueueStorage=Ye;exports.subscribeReplayOnReconnect=ye;exports.triggerSwUpdate=Qe;exports.useEidos=bt;exports.useEidosAction=It;exports.useEidosOnDrain=xt;exports.useEidosQueue=At;exports.useEidosQueueStats=kt;exports.useEidosReliabilityStats=Ot;exports.useEidosResource=Rt;exports.useEidosResources=Et;exports.useEidosStatus=_t;exports.useEidosStore=o;exports.warmCache=We;
|
|
14
14
|
|
|
15
15
|
//# sourceMappingURL=eidos.cjs.map
|