@symbo.ls/fetch 3.14.664 → 3.14.666
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/CHANGELOG.md +29 -0
- package/README.md +25 -2
- package/adapters/rest.js +70 -7
- package/dist/cjs/adapters/rest.js +1 -1
- package/dist/cjs/early.js +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/inflight.js +1 -0
- package/dist/esm/adapters/rest.js +1 -1
- package/dist/esm/early.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/inflight.js +1 -0
- package/early.js +69 -23
- package/index.js +217 -110
- package/inflight.js +39 -0
- package/package.json +3 -3
package/dist/esm/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isArray as I,isFunction as f,isObject as H,isString as he,exec as Ve}from"@symbo.ls/utils";import{createEffect as ht}from"@symbo.ls/signal";import{dropEarly as _t}from"./early.js";const yt=["select","rpc","insert","update","upsert","delete","subscribe"],We={rest:()=>import("./adapters/rest.js"),local:()=>import("./adapters/local.js")},_e=Symbol.for("@symbo.ls/fetch:CUSTOM_ADAPTERS"),X=(()=>{if(typeof globalThis<"u"&&globalThis[_e])return globalThis[_e];const e={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,_e,{value:e,writable:!1,configurable:!1,enumerable:!1}),globalThis[_e]}catch{}return e})(),ye=Symbol.for("@symbo.ls/fetch:PENDING_ADAPTERS"),ke=(()=>{if(typeof globalThis<"u"&&globalThis[ye])return globalThis[ye];const e={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,ye,{value:e,writable:!1,configurable:!1,enumerable:!1}),globalThis[ye]}catch{}return e})(),bt=5e3,St=e=>new Promise(t=>{if(X[e])return t(X[e]);const r=ke[e]||=[];let s=!1;const o=()=>{s||(s=!0,t(X[e]||null))};r.push(o),setTimeout(o,bt)}),It=(e,t)=>{X[e]=t;const r=ke[e];if(r&&r.length){ke[e]=[];for(const s of r)s()}},qt=e=>typeof e=="string"&&!!(X[e]||We[e]),Nt=e=>{const t={};for(const r of yt)e[r]&&(t[r]=e[r]);return t.name=e.name||"custom",t},wt=async e=>{if(!e)return null;if(typeof e.select=="function")return e;const{adapter:t,...r}=e,s=typeof t=="string"?t:typeof e=="string"?e:null;if(!s)return null;let o=X[s]||We[s];if(!o&&(o=await St(s),!o))throw new Error(`Unknown db adapter: "${s}". Use registerAdapter() for adapters with optional deps.`);const n=await o();if(!n||typeof n.setup!="function")throw new Error(`Adapter "${s}" loader returned a module without a setup() function. Got keys: [${Object.keys(n||{}).join(", ")}]. Likely a bundler chunk-resolution issue.`);return n.setup(r)},te=e=>{if(!e)return 0;if(typeof e=="number")return e;const t=e.match(/^(\d+)(ms|s|m|h)$/);if(!t)return 0;const r=parseInt(t[1]),s=t[2];return s==="ms"?r:s==="s"?r*1e3:s==="m"?r*6e4:s==="h"?r*36e5:0},m=new Map,Y=new Map,q=new Map;let be=0;const Se=new Map,Oe=new WeakMap,Le=(e,t,r,s,o=e.page,n=e.cursor)=>{if(e.cache?.key)return e.cache.key;const{from:i,method:u,infinite:a}=e,l=r?`${r}:`:"",h=s?`:${s}`:"",p=o?":p"+JSON.stringify(o):"",v=n!=null?":c"+JSON.stringify(n):"";return`${i}:${u}:${l}${JSON.stringify(t||"")}${a?":infinite":""}${p}${v}${h}`},re=e=>m.get(e)||null,se=(e,t,r,s=++be,o=!1)=>{const n={data:t,error:r,time:Date.now(),stale:o,seq:s};m.set(e,n);const i=Y.get(e);if(i)for(const u of i)f(u)&&u(n);return n},we=(e,t)=>{const r=e?m.get(e):null;return r&&!r.error&&r.seq>t?r:null},Re=(e,t)=>(Se.get(e)||0)>t,ge=e=>{Se.set(e,++be)},Je=e=>{m.delete(e),ge(e)},Ut=(e,t)=>(Y.has(e)||Y.set(e,new Set),Y.get(e).add(t),()=>{const r=Y.get(e);r&&(r.delete(t),r.size===0&&Y.delete(e))}),Ie=e=>!e&&e!==!1?{staleTime:6e4,gcTime:3e5}:e===!1?null:e===!0?{staleTime:6e4,gcTime:3e5}:typeof e=="number"?{staleTime:e,gcTime:Math.max(e*5,3e5)}:he(e)?{staleTime:te(e),gcTime:3e5}:{staleTime:te(e.stale||e.staleTime)||6e4,gcTime:te(e.gc||e.gcTime||e.expire)||3e5,key:e.key},B=new Set,He=e=>!!e.ref&&e.element.__ref===e.ref,gt=({config:e,element:t,context:r})=>{try{return Ue(e,t,r)}catch{return null}};let Te=null;const Tt=()=>{Te||(Te=setInterval(()=>{const e=Date.now();for(const[t,r]of m){const s=Y.get(t);!(s&&s.size>0)&&e-r.time>(r.gcTime||3e5)&&m.delete(t)}for(const[t]of Se)!m.has(t)&&!q.has(t)&&Se.delete(t);for(const t of B)He(t)||B.delete(t)},3e4),Te.unref&&Te.unref())};Tt();const Xe=3,qe=e=>Math.min(1e3*2**e,3e4),Ze=(e,t)=>{const r=e.retry;return r===void 0&&t?{count:0}:r===!1?{count:0}:r===!0||r===void 0?{count:Xe,delay:qe}:typeof r=="number"?{count:r,delay:qe}:{count:r.count??Xe,delay:f(r.delay)?r.delay:typeof r.delay=="number"?()=>r.delay:qe}},et=async(e,t)=>{const{count:r,delay:s}=t;let o;for(let n=0;n<=r;n++)try{const i=await e();if(i?.error){if(o=i.error,n<r){const u=f(s)?s(n,o):s;await new Promise(a=>setTimeout(a,u));continue}return i}return i}catch(i){if(o=i,n<r){const u=f(s)?s(n,i):s;await new Promise(a=>setTimeout(a,u));continue}throw i}return{data:null,error:o}},Z={focus:new Set,online:new Set};let tt=!1;const mt=()=>{if(tt||typeof window>"u")return;tt=!0;const e=()=>{for(const r of Z.focus)r()},t=()=>{for(const r of Z.online)r()};window.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&e()}),window.addEventListener("focus",e),window.addEventListener("online",t)},rt=(e,t)=>{const r=t.__ref;if(e===!0)return{from:r.__state||t.key,method:"select",query:!0,on:"create"};if(he(e))return{from:e,method:"select",query:!0,on:"create"};if(H(e)){const s={...e};return s.from=s.from||r.__state||t.key,s.method=s.method||"select",s.on=s.on||"create",s.query===void 0&&(s.query=!0),s}return null},vt=["insert","update","upsert","delete"],st=e=>vt.includes(e),Ne=e=>e.mutation===!0?!0:e.mutation===!1||e.method!=="rpc"?!1:e.on==="submit"||e.on==="click"||e.invalidates!=null,ne=(e,t)=>{const r=e?.state?.root||t?.state?.root;if(r?.lang)return r.lang},me=(e,t)=>{const s=(e?.state?.root||t?.state?.root)?.__fetchScope;return s?String(s):void 0},ve=(e,t,r)=>{let s;if(!e)s=void 0;else if(f(e))s=e(t,t.state);else{s={};for(const o in e){const n=e[o];s[o]=f(n)?n(t,t.state):n}}return s},oe=(e,t)=>f(e)?e(t,t.state):e,Ue=(e,t,r)=>Le(e,ve(e.params,t,r),me(t,r),ne(t,r),oe(e.page,t),oe(e.cursor,t)),Qe=async(e,t)=>{if(!e||e.__authInitialized||(e.__authInitialized=!0,!e.getSession))return;const r=(s,o)=>{const n=t.state?.root;n?.update&&n.update({auth:{user:s,session:o,loading:!1}})};try{const s=await e.getSession();r(s?.user||null,s)}catch(s){console.warn("[fetch] Failed to restore auth session:",s.message)}e.onAuthStateChange&&e.onAuthStateChange((s,o)=>{r(o?.user||null,o)})},$e=async(e,t)=>{if(f(e.select))return e.auth!==!1&&await Qe(e,t),e;if(e.__resolved)return e.auth!==!1&&await Qe(e.__resolved,t),e.__resolved;if(e.__resolving)return e.__resolving;e.__resolving=wt(e);const r=await e.__resolving;return delete e.__resolving,r?(r.auth=e.auth,r.url=e.url,r.key=e.key,e.__resolved=r,t.fetch=r,e.auth!==!1&&await Qe(r,t),r):null},F=(e,t,...r)=>{const s=f(e[t])?e[t]:null;s&&s.call(e,...r,e,e.state,e.context)},k=(e,t,r,...s)=>{const o=e&&f(e[r])?e[r]:null;o&&o.call(t,...s,t,t.state,t.context)},ae=e=>{const t={},r=e.node;if(!r)return t;if(r.tagName==="FORM"){const o=new FormData(r);for(const[n,i]of o.entries())t[n]=i;return t}const s=r.querySelectorAll("input, textarea, select");for(let o=0;o<s.length;o++){const n=s[o],i=n.name||n.getAttribute("name");i&&(n.type==="checkbox"?t[i]=n.checked:n.type==="file"?t[i]=n.files:t[i]=n.value)}return t},Ee=e=>e.responseType==="stream"||e.responseType==="response",Et=["Blob","File","ArrayBuffer","ReadableStream","Response"],ze=e=>e!==null&&typeof e=="object"&&(ArrayBuffer.isView(e)||Et.includes(Object.prototype.toString.call(e).slice(8,-1))),N=(e,t,r,s={})=>{if(!r&&ze(t))return;const o=r&&r.startsWith("~/"),n=o&&e.state?.root||e.state;if(n?.update)if(o){const i=r.slice(2);t&&typeof t=="object"&&!Array.isArray(t)&&!ze(t)&&i in t?n.update(t,{preventFetch:!0,...s}):n.update({[i]:t},{preventFetch:!0,...s})}else{const i=r?{[r]:t}:t;n.update(i,{preventFetch:!0,...s})}},je=Object.freeze({isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"}),Ke=e=>({isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:e,status:"error",fetchStatus:"idle"}),U=(e,t)=>{const r=e?.__ref;r&&(r.__fetchStatus={...t,isError:!!t.error},r.__fetching=t.isFetching,r.__fetchError=t.error)},nt=(e,t,r)=>{const s=e.__pages&&e.__pages.length?e.__pages:[r];f(t.getNextPageParam)&&(e.__nextPageParam=t.getNextPageParam(s[s.length-1],s),e.__hasNextPage=e.__nextPageParam!=null),f(t.getPreviousPageParam)&&(e.__prevPageParam=t.getPreviousPageParam(s[0],s),e.__hasPreviousPage=e.__prevPageParam!=null)},O=async(e,t,r,s={})=>{const o=r?.fetch;if(!o||!t||!t.__ref)return;const n=t.__ref,i=me(t,r);(!n.__fetchScopeOwner||n.__fetchScopeOwner.scope!==i)&&(n.__fetchScopeOwner={scope:i});const u=n.__fetchScopeOwner,a=()=>t.__ref===n&&n.__fetchScopeOwner===u&&me(t,r)===i;if(e.enabled===!1||f(e.enabled)&&!e.enabled(t,t.state)||e.skip===!0||f(e.skip)&&e.skip(t,t.state))return;const l=await $e(o,r);if(!l||!a())return;const{from:h,method:p,query:v,params:Pe,cache:Fe,transform:Q,single:ie,auth:ue,fields:G,as:A,limit:$,offset:L,order:S,headers:ee,baseUrl:E,responseType:x,page:g,cursor:P,infinite:z,placeholderData:V,initialData:W,select:T,keepPreviousData:C}=e,j=c=>(f(T)&&(c=T(c,t,t.state)),Q&&(c=Q(c,t,t.state)),c),R=c=>{U(t,Ke(c)),F(t,"onFetchError",c),k(e,t,"onFetchError",c)};let Ae=he(T)?T:void 0;if(v&&f(t.getQuery)){const c=t.getQuery(l.name||"paths");c&&(Ae=c.select||c.length&&c.join(",")||Ae)}const ce=ve(Pe,t,r),D=oe(g,t),Ce=oe(P,t),fe=Ne(e),le=Ee(e)||fe?null:Ie(Fe),lt=Ze(e,fe||st(p)),Ge=ne(t,r),y=le?Le(e,ce,i,Ge,D,Ce):null;if(!n.__fetchInitialized&&y&&(n.__fetchInitialized=!0,W!==void 0)){const c=f(W)?W():W;se(y,c,null)}if((p==="select"||p==="rpc")&&y&&le&&!s.refresh&&!s.force){const c=re(y);if(c&&!c.error){const d=Date.now()-c.time,w=c.stale||d>(le.staleTime||0);z&&I(c.data)&&!n.__pages&&(n.__pages=[c.data],nt(n,e,c.data));const _=j(c.data);if(!a())return;if(!w){U(t,je),N(t,_,A);return}N(t,_,A)}else if(V!==void 0){const d=f(V)?V(t,t.state):V;d!==void 0&&N(t,d,A)}}const de=y&&!s.force?q.get(y):null;if(de&&!Re(y,Oe.get(de)||0)){try{const c=await Promise.race([de,new Promise((d,w)=>setTimeout(()=>w("DEDUP_TIMEOUT"),15e3))]);if(!a())return;if(c?.error)R(c.error);else if(c?.data!==void 0){const d=!z&&we(y,Oe.get(de)||0),w=j(d?d.data:c.data);if(!a())return;N(t,w,A),F(t,"onFetchComplete",w),k(e,t,"onFetchComplete",w)}}catch(c){if(!a())return;c!=="DEDUP_TIMEOUT"&&R(c)}return}const dt=!re(y)?.data;U(t,{isFetching:!0,isLoading:dt,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),F(t,"onFetchStart"),k(e,t,"onFetchStart");const M=r?.analyze?.emitNetwork,Me=M?typeof performance<"u"?performance.now():Date.now():0;M&&M({phase:"start",mode:"query",from:h,method:p,cacheKey:y,lang:Ge});const pt=async()=>{if(!a())return;if(ue!==!1&&l.auth!==!1&&l.getSession){const _=await l.getSession();if(!a())return;if(ue===!0&&!_){const b={message:"Not authenticated"};return R(b),{data:null,error:b}}}const c=l[p];if(!f(c))return{data:null,error:{message:`Method "${p}" not found on adapter`}};const d={from:h,select:Ae,params:ce,single:ie,limit:$,offset:L,order:S,headers:ee,baseUrl:E};x!==void 0&&(d.responseType=x);const w=ne(t,r);if(w&&(d.headers={...d.headers,"Accept-Language":w}),D!==void 0){if(H(D))D.offset!==void 0&&(d.offset=D.offset),D.limit!==void 0&&(d.limit=D.limit),D.cursor!==void 0&&(d.params={...d.params,cursor:D.cursor});else if(typeof D=="number"){const _=e.pageSize||$||20;d.offset=(D-1)*_,d.limit=_}}if(Ce!==void 0&&(d.params={...d.params,cursor:Ce}),p==="insert"||p==="update"||p==="upsert"){let _;if(G===!0||e.on==="submit")_=ae(t);else if(I(G)){const b=ae(t);_={};for(const K of G)_[K]=b[K]}else t.state?.parse?_=t.state.parse():H(t.state)&&(_={...t.state});Q&&(_=Q(_,t,t.state)),d.data=_}if(p==="rpc"){let _=ce;if(e.on==="submit"){const b=ae(t);_=e.transformParams?e.transformParams(b,t,t.state):b}d.params=_,d.read=!fe&&e.read!==!1}if(p==="subscribe"){if(f(n.__unsubscribe)){const b=n.__unsubscribe;n.__unsubscribe=null;try{b()}catch{}}const _=l.subscribe({from:h,params:ce,on:e.subscribeOn},(b,K,xe)=>{a()&&(N(t,b,A),F(t,"onFetchComplete",b),k(e,t,"onFetchComplete",b))});return a()?(n.__unsubscribe=_,{data:null,error:null,subscribed:!0}):(f(_)&&_(),{data:null,error:null,subscribed:!0})}return c(d)},J=++be,pe=et(pt,lt);Oe.set(pe,J),y&&q.set(y,pe);try{const c=await pe;if(fe&&e.invalidates&&c&&!c.error&&!c.subscribed&&at(e.invalidates,h),!a()||c?.subscribed)return;const{data:d,error:w}=c||{};if(w){y&&!we(y,J)&&se(y,null,w,J),R(w),M&&M({phase:"error",mode:"query",from:h,method:p,cacheKey:y,error:w.message||w,durationMs:(typeof performance<"u"?performance.now():Date.now())-Me});return}if(d!==void 0){let _=d;if((p==="select"||p==="rpc")&&y){const K=!z&&we(y,J);if(K)_=K.data;else{const xe=se(y,d,null,J,Re(y,J));xe.gcTime=le?.gcTime||3e5}}let b=_;if(z&&I(d)&&((!n.__pages||!s.direction)&&(n.__pages=[]),s.direction==="previous"?n.__pages.unshift(d):n.__pages.push(d),b=n.__pages.flat(),nt(n,e,d)),b=j(b),!a())return;U(t,je),(!C||b!==void 0)&&N(t,b,A),F(t,"onFetchComplete",b),k(e,t,"onFetchComplete",b),M&&M({phase:"success",mode:"query",ok:!0,from:h,method:p,cacheKey:y,durationMs:(typeof performance<"u"?performance.now():Date.now())-Me})}}catch(c){if(!a())return;R(c),M&&M({phase:"error",mode:"query",from:h,method:p,cacheKey:y,error:c.message||String(c),durationMs:(typeof performance<"u"?performance.now():Date.now())-Me})}finally{y&&q.get(y)===pe&&q.delete(y)}},Dt=(e,t,r)=>{const s=e.on,o=t.__ref;if(!o)return;o.__fetchListeners||(o.__fetchListeners=[]);const n=e.__runner||O;if(s==="submit"){const i=a=>{a.preventDefault(),n(e,t,r)},u=t.node;u&&(u.addEventListener("submit",i),o.__fetchListeners.push(()=>u.removeEventListener("submit",i)))}else if(s==="click"){const i=()=>n(e,t,r),u=t.node;u&&(u.addEventListener("click",i),o.__fetchListeners.push(()=>u.removeEventListener("click",i)))}else s==="stateChange"&&Pt(e,t,r,n)},Pt=(e,t,r,s)=>{const o=t.__ref;let n;const i=ht(()=>{let u;try{u=JSON.stringify([ve(e.params,t,r)??null,f(e.enabled)?!!e.enabled(t,t.state):e.enabled!==!1,f(e.skip)?!!e.skip(t,t.state):e.skip===!0,oe(e.page,t)??null])}catch{return}if(n===void 0){n=u;return}u!==n&&(n=u,Promise.resolve().then(()=>s(e,t,r)))});Array.isArray(o.__effects)?o.__effects.push(i):o.__fetchListeners.push(()=>i.dispose())},Ft=(e,t,r)=>{const s=t.__ref;s.__fetchCleanups||(s.__fetchCleanups=[]),mt();const o=e.refetchInterval;if(o){const a=typeof o=="number"?o:te(o);if(a>0){const l=setInterval(()=>{(e.refetchIntervalInBackground||typeof document>"u"||document.visibilityState==="visible")&&O(e,t,r,{force:!0})},a);s.__fetchCleanups.push(()=>clearInterval(l))}}const n=Ee(e),i=e.refetchOnWindowFocus===void 0?!n:e.refetchOnWindowFocus!==!1,u=e.refetchOnReconnect===void 0?!n:e.refetchOnReconnect!==!1;if(i){const a=()=>{const l=Ue(e,t,r),h=re(l),p=Ie(e.cache);(!h||h.stale||Date.now()-h.time>(p?.staleTime||0))&&O(e,t,r,{force:!0})};Z.focus.add(a),s.__fetchCleanups.push(()=>Z.focus.delete(a))}if(u){const a=()=>O(e,t,r,{force:!0});Z.online.add(a),s.__fetchCleanups.push(()=>Z.online.delete(a))}},At=(e,t,r)=>{if(!t.optimistic)return null;const s=e.__ref,o=t.as,n=e.state?.parse?e.state.parse():H(e.state)?{...e.state}:e.state;s.__optimisticSnapshot=n;const i=f(t.optimistic)?t.optimistic(r,n,e):t.optimistic;return i!==void 0&&N(e,i,o),n},Ye=(e,t)=>{const r=e.__ref;if(!r||!t.optimistic)return;const s=r.__optimisticSnapshot;s!==void 0&&(N(e,s,t.as),delete r.__optimisticSnapshot)},Be=e=>{if(!e)return()=>!0;if(he(e))return t=>t.includes(e);if(I(e)){const t=e.join(":");return r=>r.includes(t)}return e instanceof RegExp?t=>(e.lastIndex=0,e.test(t)):f(e)?t=>{try{return!!e(t)}catch{return!1}}:()=>!1},Ct=e=>{const t=[];for(const r of B){if(!He(r)){B.delete(r);continue}const s=gt(r);s&&e(s)&&t.push(O(r.config,r.element,r.context,{refresh:!0}))}return Promise.allSettled(t).then(()=>{})},ot=e=>{_t();for(const[t,r]of m)e(t)&&(r.stale=!0,ge(t));for(const[t]of q)!m.has(t)&&e(t)&&ge(t);return Ct(e)},at=(e,t)=>{const r=(I(e)?e:[e]).map(s=>s===!0||s==="*"?o=>o.startsWith(t+":"):s?Be(s):()=>!1);return ot(s=>r.some(o=>o(s)))},it=e=>{for(const[t]of m)e(t)&&Je(t);for(const[t]of q)e(t)&&ge(t)},ut=()=>!0,Mt=async(e,t,r)=>{const s=r?.fetch;if(!s)return;const o=await $e(s,r);if(!o)return;const n=t.__ref,{method:i,from:u,fields:a,transform:l,as:h,on:p,auth:v,headers:Pe,baseUrl:Fe,responseType:Q,invalidates:ie,optimistic:ue,onMutate:G,onSuccess:A,onError:$,onSettled:L}=e;let S;if(a===!0||p==="submit")S=ae(t);else if(I(a)){const g=ae(t);S={};for(const P of a)S[P]=g[P]}else t.state?.parse?S=t.state.parse():H(t.state)&&(S={...t.state});l&&(S=l(S,t,t.state)),f(G)&&G(S,t,t.state);const ee=ue?At(t,e,S):null;U(t,{isFetching:!0,isLoading:!1,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),F(t,"onFetchStart"),k(e,t,"onFetchStart");const E=r?.analyze?.emitNetwork,x=E?typeof performance<"u"?performance.now():Date.now():0;E&&E({phase:"start",mode:"mutation",from:u,method:i});try{if(v!==!1&&o.auth!==!1&&o.getSession){const j=await o.getSession();if(v===!0&&!j){ee!==void 0&&Ye(t,e);const R={message:"Not authenticated"};F(t,"onFetchError",R),k(e,t,"onFetchError",R);return}}const g=o[i];if(!f(g))return;const P={from:u,data:S,headers:Pe,baseUrl:Fe};Q!==void 0&&(P.responseType=Q),e.params&&(P.params=ve(e.params,t,r));const z=ne(t,r);z&&(P.headers={...P.headers,"Accept-Language":z});const V=Ze(e,!0),W=await et(()=>g(P),V),{data:T,error:C}=W||{};if(C){ee!==void 0&&Ye(t,e),U(t,Ke(C)),F(t,"onFetchError",C),f($)&&$(C,S,t),f(L)&&L(null,C,S,t),E&&E({phase:"error",mode:"mutation",from:u,method:i,error:C.message||String(C),durationMs:(typeof performance<"u"?performance.now():Date.now())-x});return}if(delete n.__optimisticSnapshot,U(t,je),T!==void 0&&(h||!ze(T))){const j=h?{[h]:T}:T;t.state?.update&&t.state.update(j,{preventFetch:!0})}F(t,"onFetchComplete",T),k(e,t,"onFetchComplete",T),f(A)&&A(T,S,t),f(L)&&L(T,null,S,t),E&&E({phase:"success",mode:"mutation",ok:!0,from:u,method:i,durationMs:(typeof performance<"u"?performance.now():Date.now())-x}),ie&&at(ie,u)}catch(g){ee!==void 0&&Ye(t,e),U(t,Ke(g)),F(t,"onFetchError",g),k(e,t,"onFetchError",g),f($)&&$(g,S,t),f(L)&&L(null,g,S,t),E&&E({phase:"error",mode:"mutation",from:u,method:i,error:g.message||String(g),durationMs:(typeof performance<"u"?performance.now():Date.now())-x})}finally{n.__fetching=!1}},kt=e=>{const t=r=>{try{r()}catch{}};for(const r of e.__fetchCleanups||[])t(r);for(const r of e.__fetchListeners||[])t(r);f(e.__unsubscribe)&&t(e.__unsubscribe);for(const r of e.__fetchMounted||[])B.delete(r);e.__fetchCleanups=[],e.__fetchListeners=[],e.__unsubscribe=null,e.__fetchMounted=[]},ct=(e,t,r,s)=>{if(!e||!s?.fetch)return;const n=Ve(e,t);if(!n)return;const i=I(n)?n.map(a=>rt(Ve(a,t),t)).filter(Boolean):[rt(n,t)].filter(Boolean),u=t.__ref;if(u.__fetchMounted)for(const a of u.__fetchMounted)B.delete(a);u.__fetchMounted=[],!u.__fetchDisposer&&I(u.__effects)&&(u.__fetchDisposer={dispose:()=>kt(u)},u.__effects.push(u.__fetchDisposer));for(const a of i){const l=st(a.method),h=l?Mt:O,p=!l&&!Ne(a)&&a.method!=="subscribe";if(a.on==="create"?h(a,t,s):Promise.resolve().then(()=>{Dt({...a,__runner:h},t,s)}),p&&a.on==="create"&&((a.refetchInterval||a.refetchOnWindowFocus!==!1||a.refetchOnReconnect!==!1)&&Ft(a,t,s),!Ee(a))){const v={element:t,ref:u,config:a,context:s};B.add(v),u.__fetchMounted.push(v)}}u.refetch=a=>{for(const l of i)O(l,t,s,{force:!0,...a})},u.fetchNextPage=()=>{const a=i[0];if(!a||!a.infinite)return;const l=u.__nextPageParam;if(l==null)return;const h={...a,cursor:l};O(h,t,s,{direction:"next",force:!0})},u.fetchPreviousPage=()=>{const a=i[0];if(!a||!a.infinite)return;const l=u.__prevPageParam;if(l==null)return;const h={...a,cursor:l};O(h,t,s,{direction:"previous",force:!0})}},De={invalidateQueries:e=>ot(Be(e)),removeQueries:e=>{it(e?Be(e):ut)},getQueryData:e=>re(e)?.data??void 0,setQueryData:(e,t)=>{const r=re(e),s=f(t)?t(r?.data):t;se(e,s,null)},prefetchQuery:async(e,t)=>{const r=t?.fetch;if(!r)return;const s=await $e(r,t);if(!s)return;const o=e.method||"select",n=me(null,t),i=ne(null,t),u=Le({...e,method:o},e.params,n,i),a=s[o];if(!f(a))return;const l={from:e.from,params:e.params,limit:e.limit,offset:e.offset,order:e.order,single:e.single,headers:e.headers,baseUrl:e.baseUrl};i&&(l.headers={...l.headers,"Accept-Language":i}),e.responseType!==void 0&&(l.responseType=e.responseType),o==="rpc"&&(l.read=!Ne(e)&&e.read!==!1);const h=++be,p=await a(l);if(p?.data!==void 0&&!p?.error&&!Ee(e)&&!we(u,h)){const v=se(u,p.data,null,h,Re(u,h));v.gcTime=Ie(e.cache)?.gcTime||3e5}return p},getCache:()=>m,clear:()=>it(ut),dropNonLang:e=>{if(!e)return;const t=`:${e}`;for(const[r]of m)r.match(/:([a-z]{2,3})$/i)&&(r.endsWith(t)||Je(r))}},ft=(e,t)=>H(e)?Ue({method:"select",...e},t,t?.context):e,Qt={invalidateQueries(e){return De.invalidateQueries(e)},removeQueries(e){return De.removeQueries(e)},getQueryData(e){return De.getQueryData(ft(e,this))},setQueryData(e,t){return De.setQueryData(ft(e,this),t)}},$t={name:"fetch",create(e){const t=e.fetch;t&&(e.parent||q.clear(),ct(t,e,e.state,e.context))}};import{earlyKey as Yt,EARLY_KEY as Bt,createEarlySeedScript as Gt}from"./early.js";var zt=ct;export{Bt as EARLY_KEY,Nt as createAdapter,Gt as createEarlySeedScript,zt as default,Yt as earlyKey,ct as executeFetch,Qt as fetchFunctions,$t as fetchPlugin,qt as hasAdapter,Qe as initAdapterAuth,te as parseDuration,De as queryClient,It as registerAdapter,wt as resolveDb};
|
|
1
|
+
import{isArray as N,isFunction as d,isObject as X,isString as ye,exec as Ve}from"@symbo.ls/utils";import{createEffect as yt}from"@symbo.ls/signal";import{dropEarly as bt}from"./early.js";import*as St from"./adapters/rest.js";const wt=["select","rpc","insert","update","upsert","delete","subscribe"],xe={rest:()=>Promise.resolve(St),local:()=>import("./adapters/local.js")},be=Symbol.for("@symbo.ls/fetch:CUSTOM_ADAPTERS"),Z=(()=>{if(typeof globalThis<"u"&&globalThis[be])return globalThis[be];const e={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,be,{value:e,writable:!1,configurable:!1,enumerable:!1}),globalThis[be]}catch{}return e})(),Se=Symbol.for("@symbo.ls/fetch:PENDING_ADAPTERS"),Ce=(()=>{if(typeof globalThis<"u"&&globalThis[Se])return globalThis[Se];const e={};if(typeof globalThis<"u")try{return Object.defineProperty(globalThis,Se,{value:e,writable:!1,configurable:!1,enumerable:!1}),globalThis[Se]}catch{}return e})(),gt=5e3,vt=e=>new Promise(t=>{if(Z[e])return t(Z[e]);const r=Ce[e]||=[];let s=!1;const o=()=>{s||(s=!0,t(Z[e]||null))};r.push(o),setTimeout(o,gt)}),Ut=(e,t)=>{Z[e]=t;const r=Ce[e];if(r&&r.length){Ce[e]=[];for(const s of r)s()}},$t=e=>typeof e=="string"&&!!(Z[e]||xe[e]),Qt=e=>{const t={};for(const r of wt)e[r]&&(t[r]=e[r]);return t.name=e.name||"custom",t},mt=async e=>{if(!e)return null;if(typeof e.select=="function")return e;const{adapter:t,...r}=e,s=typeof t=="string"?t:typeof e=="string"?e:null;if(!s)return null;let o=Z[s]||xe[s];if(!o&&(o=await vt(s),!o))throw new Error(`Unknown db adapter: "${s}". Use registerAdapter() for adapters with optional deps.`);const n=await o();if(!n||typeof n.setup!="function")throw new Error(`Adapter "${s}" loader returned a module without a setup() function. Got keys: [${Object.keys(n||{}).join(", ")}]. Likely a bundler chunk-resolution issue.`);return n.setup(r)},re=e=>{if(!e)return 0;if(typeof e=="number")return e;const t=e.match(/^(\d+)(ms|s|m|h)$/);if(!t)return 0;const r=parseInt(t[1]),s=t[2];return s==="ms"?r:s==="s"?r*1e3:s==="m"?r*6e4:s==="h"?r*36e5:0},Je=e=>!!e&&!!e.isolateFetchCache,He=()=>({cache:new Map,subscribers:new Map,active:new Map,invalidatedAt:new Map,mounted:new Set}),A=He(),Xe=new WeakMap,P=e=>{if(!Je(e))return A;let t=Xe.get(e);return t||Xe.set(e,t=He()),t};let we=0;const Me=new WeakMap,ke=(e,t,r,s,o=e.page,n=e.cursor)=>{if(e.cache?.key)return e.cache.key;const{from:a,method:i,infinite:u}=e,y=r?`${r}:`:"",c=s?`:${s}`:"",l=o?":p"+JSON.stringify(o):"",S=n!=null?":c"+JSON.stringify(n):"";return`${a}:${i}:${y}${JSON.stringify(t||"")}${u?":infinite":""}${l}${S}${c}`},se=(e,t)=>e.cache.get(t)||null,ne=(e,t,r,s,o=++we,n=!1)=>{const a={data:r,error:s,time:Date.now(),stale:n,seq:o};e.cache.set(t,a);const i=e.subscribers.get(t);if(i)for(const u of i)d(u)&&u(a);return a},ge=(e,t,r)=>{const s=t?e.cache.get(t):null;return s&&!s.error&&s.seq>r?s:null},Oe=(e,t,r)=>(e.invalidatedAt.get(t)||0)>r,ve=(e,t)=>{e.invalidatedAt.set(t,++we)},Ze=(e,t)=>{e.cache.delete(t),ve(e,t)},zt=(e,t,r)=>{const{subscribers:s}=e;return s.has(t)||s.set(t,new Set),s.get(t).add(r),()=>{const o=s.get(t);o&&(o.delete(r),o.size===0&&s.delete(t))}},Le=e=>!e&&e!==!1?{staleTime:6e4,gcTime:3e5}:e===!1?null:e===!0?{staleTime:6e4,gcTime:3e5}:typeof e=="number"?{staleTime:e,gcTime:Math.max(e*5,3e5)}:ye(e)?{staleTime:re(e),gcTime:3e5}:{staleTime:re(e.stale||e.staleTime)||6e4,gcTime:re(e.gc||e.gcTime||e.expire)||3e5,key:e.key},et=e=>!!e.ref&&e.element.__ref===e.ref,Tt=({config:e,element:t,context:r})=>{try{return qe(e,t,r)}catch{return null}};let me=null;const Et=()=>{me||(me=setInterval(()=>{const e=Date.now(),{cache:t,subscribers:r,active:s,invalidatedAt:o,mounted:n}=A;for(const[a,i]of t){const u=r.get(a);!(u&&u.size>0)&&e-i.time>(i.gcTime||3e5)&&t.delete(a)}for(const[a]of o)!t.has(a)&&!s.has(a)&&o.delete(a);for(const a of n)et(a)||n.delete(a)},3e4),me.unref&&me.unref())};Et();const tt=3,Re=e=>Math.min(1e3*2**e,3e4),rt=(e,t)=>{const r=e.retry;return r===void 0&&t?{count:0}:r===!1?{count:0}:r===!0||r===void 0?{count:tt,delay:Re}:typeof r=="number"?{count:r,delay:Re}:{count:r.count??tt,delay:d(r.delay)?r.delay:typeof r.delay=="number"?()=>r.delay:Re}},st=async(e,t)=>{const{count:r,delay:s}=t;let o;for(let n=0;n<=r;n++)try{const a=await e();if(a?.error){if(o=a.error,n<r){const i=d(s)?s(n,o):s;await new Promise(u=>setTimeout(u,i));continue}return a}return a}catch(a){if(o=a,n<r){const i=d(s)?s(n,a):s;await new Promise(u=>setTimeout(u,i));continue}throw a}return{data:null,error:o}},ee={focus:new Set,online:new Set};let nt=!1;const Dt=()=>{if(nt||typeof window>"u")return;nt=!0;const e=()=>{for(const r of ee.focus)r()},t=()=>{for(const r of ee.online)r()};window.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&e()}),window.addEventListener("focus",e),window.addEventListener("online",t)},ot=(e,t)=>{const r=t.__ref;if(e===!0)return{from:r.__state||t.key,method:"select",query:!0,on:"create"};if(ye(e))return{from:e,method:"select",query:!0,on:"create"};if(X(e)){const s={...e};return s.from=s.from||r.__state||t.key,s.method=s.method||"select",s.on=s.on||"create",s.query===void 0&&(s.query=!0),s}return null},Pt=["insert","update","upsert","delete"],at=e=>Pt.includes(e),Ie=e=>e.mutation===!0?!0:e.mutation===!1||e.method!=="rpc"?!1:e.on==="submit"||e.on==="click"||e.invalidates!=null,oe=(e,t)=>{const r=e?.state?.root||t?.state?.root;if(r?.lang)return r.lang},Te=(e,t)=>{const s=(e?.state?.root||t?.state?.root)?.__fetchScope;return s?String(s):void 0},Ee=(e,t,r)=>{let s;if(!e)s=void 0;else if(d(e))s=e(t,t.state);else{s={};for(const o in e){const n=e[o];s[o]=d(n)?n(t,t.state):n}}return s},ae=(e,t)=>d(e)?e(t,t.state):e,qe=(e,t,r)=>ke(e,Ee(e.params,t,r),Te(t,r),oe(t,r),ae(e.page,t),ae(e.cursor,t)),Ne=async(e,t)=>{if(!e||e.__authInitialized||(e.__authInitialized=!0,!e.getSession))return;const r=(s,o)=>{const n=t.state?.root;n?.update&&n.update({auth:{user:s,session:o,loading:!1}})};try{const s=await e.getSession();r(s?.user||null,s)}catch(s){console.warn("[fetch] Failed to restore auth session:",s.message)}e.onAuthStateChange&&e.onAuthStateChange((s,o)=>{r(o?.user||null,o)})},Ue=async(e,t)=>{if(d(e.select))return e.auth!==!1&&await Ne(e,t),e;if(e.__resolved)return e.auth!==!1&&await Ne(e.__resolved,t),e.__resolved;if(e.__resolving)return e.__resolving;e.__resolving=mt(e);const r=await e.__resolving;return delete e.__resolving,r?(r.auth=e.auth,r.url=e.url,r.key=e.key,e.__resolved=r,t.fetch=r,e.auth!==!1&&await Ne(r,t),r):null},C=(e,t,...r)=>{const s=d(e[t])?e[t]:null;s&&s.call(e,...r,e,e.state,e.context)},L=(e,t,r,...s)=>{const o=e&&d(e[r])?e[r]:null;o&&o.call(t,...s,t,t.state,t.context)},ie=e=>{const t={},r=e.node;if(!r)return t;if(r.tagName==="FORM"){const o=new FormData(r);for(const[n,a]of o.entries())t[n]=a;return t}const s=r.querySelectorAll("input, textarea, select");for(let o=0;o<s.length;o++){const n=s[o],a=n.name||n.getAttribute("name");a&&(n.type==="checkbox"?t[a]=n.checked:n.type==="file"?t[a]=n.files:t[a]=n.value)}return t},De=e=>e.responseType==="stream"||e.responseType==="response",Ft=["Blob","File","ArrayBuffer","ReadableStream","Response"],$e=e=>e!==null&&typeof e=="object"&&(ArrayBuffer.isView(e)||Ft.includes(Object.prototype.toString.call(e).slice(8,-1))),U=(e,t,r,s={})=>{if(!r&&$e(t))return;const o=r&&r.startsWith("~/"),n=o&&e.state?.root||e.state;if(n?.update)if(o){const a=r.slice(2);t&&typeof t=="object"&&!Array.isArray(t)&&!$e(t)&&a in t?n.update(t,{preventFetch:!0,...s}):n.update({[a]:t},{preventFetch:!0,...s})}else{const a=r?{[r]:t}:t;n.update(a,{preventFetch:!0,...s})}},Qe=Object.freeze({isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!0,error:null,status:"success",fetchStatus:"idle"}),ze=e=>({isFetching:!1,isLoading:!1,isStale:!1,isSuccess:!1,error:e,status:"error",fetchStatus:"idle"}),$=(e,t)=>{const r=e?.__ref;r&&(r.__fetchStatus={...t,isError:!!t.error},r.__fetching=t.isFetching,r.__fetchError=t.error)},it=(e,t,r)=>{const s=e.__pages&&e.__pages.length?e.__pages:[r];d(t.getNextPageParam)&&(e.__nextPageParam=t.getNextPageParam(s[s.length-1],s),e.__hasNextPage=e.__nextPageParam!=null),d(t.getPreviousPageParam)&&(e.__prevPageParam=t.getPreviousPageParam(s[0],s),e.__hasPreviousPage=e.__prevPageParam!=null)},R=async(e,t,r,s={})=>{const o=r?.fetch;if(!o||!t||!t.__ref)return;const n=t.__ref,a=Te(t,r);(!n.__fetchScopeOwner||n.__fetchScopeOwner.scope!==a)&&(n.__fetchScopeOwner={scope:a});const i=n.__fetchScopeOwner,u=()=>t.__ref===n&&n.__fetchScopeOwner===i&&Te(t,r)===a;if(e.enabled===!1||d(e.enabled)&&!e.enabled(t,t.state)||e.skip===!0||d(e.skip)&&e.skip(t,t.state))return;const y=await Ue(o,r);if(!y||!u())return;const{from:c,method:l,query:S,params:Q,cache:G,transform:z,single:ue,auth:fe,fields:W,as:M,limit:j,offset:I,order:w,headers:te,baseUrl:E,responseType:V,page:m,cursor:F,infinite:B,placeholderData:x,initialData:J,select:T,keepPreviousData:k}=e,K=f=>(d(T)&&(f=T(f,t,t.state)),z&&(f=z(f,t,t.state)),f),q=f=>{$(t,ze(f)),C(t,"onFetchError",f),L(e,t,"onFetchError",f)};let Pe=ye(T)?T:void 0;if(S&&d(t.getQuery)){const f=t.getQuery(y.name||"paths");f&&(Pe=f.select||f.length&&f.join(",")||Pe)}const le=Ee(Q,t,r),D=ae(m,t),Fe=ae(F,t),de=Ie(e),pe=De(e)||de?null:Le(G),pt=rt(e,de||at(l)),Ge=oe(t,r),_=pe?ke(e,le,a,Ge,D,Fe):null,v=P(r);if(!n.__fetchInitialized&&_&&(n.__fetchInitialized=!0,J!==void 0)){const f=d(J)?J():J;ne(v,_,f,null)}if((l==="select"||l==="rpc")&&_&&pe&&!s.refresh&&!s.force){const f=se(v,_);if(f&&!f.error){const p=Date.now()-f.time,g=f.stale||p>(pe.staleTime||0);B&&N(f.data)&&!n.__pages&&(n.__pages=[f.data],it(n,e,f.data));const h=K(f.data);if(!u())return;if(!g){$(t,Qe),U(t,h,M);return}U(t,h,M)}else if(x!==void 0){const p=d(x)?x(t,t.state):x;p!==void 0&&U(t,p,M)}}const he=_&&!s.force?v.active.get(_):null;if(he&&!Oe(v,_,Me.get(he)||0)){try{const f=await Promise.race([he,new Promise((p,g)=>setTimeout(()=>g("DEDUP_TIMEOUT"),15e3))]);if(!u())return;if(f?.error)q(f.error);else if(f?.data!==void 0){const p=!B&&ge(v,_,Me.get(he)||0),g=K(p?p.data:f.data);if(!u())return;U(t,g,M),C(t,"onFetchComplete",g),L(e,t,"onFetchComplete",g)}}catch(f){if(!u())return;f!=="DEDUP_TIMEOUT"&&q(f)}return}const ht=!se(v,_)?.data;$(t,{isFetching:!0,isLoading:ht,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),C(t,"onFetchStart"),L(e,t,"onFetchStart");const O=r?.analyze?.emitNetwork,Ae=O?typeof performance<"u"?performance.now():Date.now():0;O&&O({phase:"start",mode:"query",from:c,method:l,cacheKey:_,lang:Ge});const _t=async()=>{if(!u())return;if(fe!==!1&&y.auth!==!1&&y.getSession){const h=await y.getSession();if(!u())return;if(fe===!0&&!h){const b={message:"Not authenticated"};return q(b),{data:null,error:b}}}const f=y[l];if(!d(f))return{data:null,error:{message:`Method "${l}" not found on adapter`}};const p={from:c,select:Pe,params:le,single:ue,limit:j,offset:I,order:w,headers:te,baseUrl:E};V!==void 0&&(p.responseType=V);const g=oe(t,r);if(g&&(p.headers={...p.headers,"Accept-Language":g}),D!==void 0){if(X(D))D.offset!==void 0&&(p.offset=D.offset),D.limit!==void 0&&(p.limit=D.limit),D.cursor!==void 0&&(p.params={...p.params,cursor:D.cursor});else if(typeof D=="number"){const h=e.pageSize||j||20;p.offset=(D-1)*h,p.limit=h}}if(Fe!==void 0&&(p.params={...p.params,cursor:Fe}),l==="insert"||l==="update"||l==="upsert"){let h;if(W===!0||e.on==="submit")h=ie(t);else if(N(W)){const b=ie(t);h={};for(const Y of W)h[Y]=b[Y]}else t.state?.parse?h=t.state.parse():X(t.state)&&(h={...t.state});z&&(h=z(h,t,t.state)),p.data=h}if(l==="rpc"){let h=le;if(e.on==="submit"){const b=ie(t);h=e.transformParams?e.transformParams(b,t,t.state):b}p.params=h,p.read=!de&&e.read!==!1}if(l==="subscribe"){if(d(n.__unsubscribe)){const b=n.__unsubscribe;n.__unsubscribe=null;try{b()}catch{}}const h=y.subscribe({from:c,params:le,on:e.subscribeOn},(b,Y,We)=>{u()&&(U(t,b,M),C(t,"onFetchComplete",b),L(e,t,"onFetchComplete",b))});return u()?(n.__unsubscribe=h,{data:null,error:null,subscribed:!0}):(d(h)&&h(),{data:null,error:null,subscribed:!0})}return f(p)},H=++we,_e=st(_t,pt);Me.set(_e,H),_&&v.active.set(_,_e);try{const f=await _e;if(de&&e.invalidates&&f&&!f.error&&!f.subscribed&&ct(v,e.invalidates,c),!u()||f?.subscribed)return;const{data:p,error:g}=f||{};if(g){_&&!ge(v,_,H)&&ne(v,_,null,g,H),q(g),O&&O({phase:"error",mode:"query",from:c,method:l,cacheKey:_,error:g.message||g,durationMs:(typeof performance<"u"?performance.now():Date.now())-Ae});return}if(p!==void 0){let h=p;if((l==="select"||l==="rpc")&&_){const Y=!B&&ge(v,_,H);if(Y)h=Y.data;else{const We=ne(v,_,p,null,H,Oe(v,_,H));We.gcTime=pe?.gcTime||3e5}}let b=h;if(B&&N(p)&&((!n.__pages||!s.direction)&&(n.__pages=[]),s.direction==="previous"?n.__pages.unshift(p):n.__pages.push(p),b=n.__pages.flat(),it(n,e,p)),b=K(b),!u())return;$(t,Qe),(!k||b!==void 0)&&U(t,b,M),C(t,"onFetchComplete",b),L(e,t,"onFetchComplete",b),O&&O({phase:"success",mode:"query",ok:!0,from:c,method:l,cacheKey:_,durationMs:(typeof performance<"u"?performance.now():Date.now())-Ae})}}catch(f){if(!u())return;q(f),O&&O({phase:"error",mode:"query",from:c,method:l,cacheKey:_,error:f.message||String(f),durationMs:(typeof performance<"u"?performance.now():Date.now())-Ae})}finally{_&&v.active.get(_)===_e&&v.active.delete(_)}},At=(e,t,r)=>{const s=e.on,o=t.__ref;if(!o)return;o.__fetchListeners||(o.__fetchListeners=[]);const n=e.__runner||R;if(s==="submit"){const a=u=>{u.preventDefault(),n(e,t,r)},i=t.node;i&&(i.addEventListener("submit",a),o.__fetchListeners.push(()=>i.removeEventListener("submit",a)))}else if(s==="click"){const a=()=>n(e,t,r),i=t.node;i&&(i.addEventListener("click",a),o.__fetchListeners.push(()=>i.removeEventListener("click",a)))}else s==="stateChange"&&Ct(e,t,r,n)},Ct=(e,t,r,s)=>{const o=t.__ref;let n;const a=yt(()=>{let i;try{i=JSON.stringify([Ee(e.params,t,r)??null,d(e.enabled)?!!e.enabled(t,t.state):e.enabled!==!1,d(e.skip)?!!e.skip(t,t.state):e.skip===!0,ae(e.page,t)??null])}catch{return}if(n===void 0){n=i;return}i!==n&&(n=i,queueMicrotask(()=>s(e,t,r)))});Array.isArray(o.__effects)?o.__effects.push(a):o.__fetchListeners.push(()=>a.dispose())},Mt=(e,t,r)=>{const s=t.__ref;s.__fetchCleanups||(s.__fetchCleanups=[]),Dt();const o=e.refetchInterval;if(o){const u=typeof o=="number"?o:re(o);if(u>0){const y=setInterval(()=>{(e.refetchIntervalInBackground||typeof document>"u"||document.visibilityState==="visible")&&R(e,t,r,{force:!0})},u);s.__fetchCleanups.push(()=>clearInterval(y))}}const n=De(e),a=e.refetchOnWindowFocus===void 0?!n:e.refetchOnWindowFocus!==!1,i=e.refetchOnReconnect===void 0?!n:e.refetchOnReconnect!==!1;if(a){const u=()=>{const y=qe(e,t,r),c=se(P(r),y),l=Le(e.cache);(!c||c.stale||Date.now()-c.time>(l?.staleTime||0))&&R(e,t,r,{force:!0})};ee.focus.add(u),s.__fetchCleanups.push(()=>ee.focus.delete(u))}if(i){const u=()=>R(e,t,r,{force:!0});ee.online.add(u),s.__fetchCleanups.push(()=>ee.online.delete(u))}},kt=(e,t,r)=>{if(!t.optimistic)return null;const s=e.__ref,o=t.as,n=e.state?.parse?e.state.parse():X(e.state)?{...e.state}:e.state;s.__optimisticSnapshot=n;const a=d(t.optimistic)?t.optimistic(r,n,e):t.optimistic;return a!==void 0&&U(e,a,o),n},je=(e,t)=>{const r=e.__ref;if(!r||!t.optimistic)return;const s=r.__optimisticSnapshot;s!==void 0&&(U(e,s,t.as),delete r.__optimisticSnapshot)},ce=e=>{if(!e)return()=>!0;if(ye(e))return t=>t.includes(e);if(N(e)){const t=e.join(":");return r=>r.includes(t)}return e instanceof RegExp?t=>(e.lastIndex=0,e.test(t)):d(e)?t=>{try{return!!e(t)}catch{return!1}}:()=>!1},Ot=(e,t)=>{const r=[];for(const s of e.mounted){if(!et(s)){e.mounted.delete(s);continue}const o=Tt(s);o&&t(o)&&r.push(R(s.config,s.element,s.context,{refresh:!0}))}return Promise.allSettled(r).then(()=>{})},Be=(e,t)=>{bt();for(const[r,s]of e.cache)t(r)&&(s.stale=!0,ve(e,r));for(const[r]of e.active)!e.cache.has(r)&&t(r)&&ve(e,r);return Ot(e,t)},ct=(e,t,r)=>{const s=(N(t)?t:[t]).map(o=>o===!0||o==="*"?n=>n.startsWith(r+":"):o?ce(o):()=>!1);return Be(e,o=>s.some(n=>n(o)))},Ke=(e,t)=>{for(const[r]of e.cache)t(r)&&Ze(e,r);for(const[r]of e.active)t(r)&&ve(e,r)},Ye=()=>!0,ut=(e,t)=>se(e,t)?.data??void 0,ft=(e,t,r)=>{const s=se(e,t),o=d(r)?r(s?.data):r;ne(e,t,o,null)},Lt=async(e,t,r)=>{const s=r?.fetch;if(!s)return;const o=await Ue(s,r);if(!o)return;const n=t.__ref,{method:a,from:i,fields:u,transform:y,as:c,on:l,auth:S,headers:Q,baseUrl:G,responseType:z,invalidates:ue,optimistic:fe,onMutate:W,onSuccess:M,onError:j,onSettled:I}=e;let w;if(u===!0||l==="submit")w=ie(t);else if(N(u)){const m=ie(t);w={};for(const F of u)w[F]=m[F]}else t.state?.parse?w=t.state.parse():X(t.state)&&(w={...t.state});y&&(w=y(w,t,t.state)),d(W)&&W(w,t,t.state);const te=fe?kt(t,e,w):null;$(t,{isFetching:!0,isLoading:!1,isStale:!1,isSuccess:!1,error:null,status:"pending",fetchStatus:"fetching"}),C(t,"onFetchStart"),L(e,t,"onFetchStart");const E=r?.analyze?.emitNetwork,V=E?typeof performance<"u"?performance.now():Date.now():0;E&&E({phase:"start",mode:"mutation",from:i,method:a});try{if(S!==!1&&o.auth!==!1&&o.getSession){const K=await o.getSession();if(S===!0&&!K){te!==void 0&&je(t,e);const q={message:"Not authenticated"};C(t,"onFetchError",q),L(e,t,"onFetchError",q);return}}const m=o[a];if(!d(m))return;const F={from:i,data:w,headers:Q,baseUrl:G};z!==void 0&&(F.responseType=z),e.params&&(F.params=Ee(e.params,t,r));const B=oe(t,r);B&&(F.headers={...F.headers,"Accept-Language":B});const x=rt(e,!0),J=await st(()=>m(F),x),{data:T,error:k}=J||{};if(k){te!==void 0&&je(t,e),$(t,ze(k)),C(t,"onFetchError",k),d(j)&&j(k,w,t),d(I)&&I(null,k,w,t),E&&E({phase:"error",mode:"mutation",from:i,method:a,error:k.message||String(k),durationMs:(typeof performance<"u"?performance.now():Date.now())-V});return}if(delete n.__optimisticSnapshot,$(t,Qe),T!==void 0&&(c||!$e(T))){const K=c?{[c]:T}:T;t.state?.update&&t.state.update(K,{preventFetch:!0})}C(t,"onFetchComplete",T),L(e,t,"onFetchComplete",T),d(M)&&M(T,w,t),d(I)&&I(T,null,w,t),E&&E({phase:"success",mode:"mutation",ok:!0,from:i,method:a,durationMs:(typeof performance<"u"?performance.now():Date.now())-V}),ue&&ct(P(r),ue,i)}catch(m){te!==void 0&&je(t,e),$(t,ze(m)),C(t,"onFetchError",m),L(e,t,"onFetchError",m),d(j)&&j(m,w,t),d(I)&&I(null,m,w,t),E&&E({phase:"error",mode:"mutation",from:i,method:a,error:m.message||String(m),durationMs:(typeof performance<"u"?performance.now():Date.now())-V})}finally{n.__fetching=!1}},Rt=e=>{const t=r=>{try{r()}catch{}};for(const r of e.__fetchCleanups||[])t(r);for(const r of e.__fetchListeners||[])t(r);d(e.__unsubscribe)&&t(e.__unsubscribe);for(const r of e.__fetchMounted||[])P(r.context).mounted.delete(r);e.__fetchCleanups=[],e.__fetchListeners=[],e.__unsubscribe=null,e.__fetchMounted=[]},lt=(e,t,r,s)=>{if(!e||!s?.fetch)return;const n=Ve(e,t);if(!n)return;const a=N(n)?n.map(c=>ot(Ve(c,t),t)).filter(Boolean):[ot(n,t)].filter(Boolean),i=t.__ref,u=P(s);if(i.__fetchMounted)for(const c of i.__fetchMounted)u.mounted.delete(c);i.__fetchMounted=[],!i.__fetchDisposer&&N(i.__effects)&&(i.__fetchDisposer={dispose:()=>Rt(i)},i.__effects.push(i.__fetchDisposer));const y=!Je(s);for(const c of a){const l=at(c.method),S=l?Lt:R,Q=!l&&!Ie(c)&&c.method!=="subscribe";if(c.on==="create"?S(c,t,s):queueMicrotask(()=>At({...c,__runner:S},t,s)),Q&&c.on==="create"&&(y&&(c.refetchInterval||c.refetchOnWindowFocus!==!1||c.refetchOnReconnect!==!1)&&Mt(c,t,s),!De(c))){const G={element:t,ref:i,config:c,context:s};u.mounted.add(G),i.__fetchMounted.push(G)}}i.refetch=c=>{for(const l of a)R(l,t,s,{force:!0,...c})},i.fetchNextPage=()=>{const c=a[0];if(!c||!c.infinite)return;const l=i.__nextPageParam;if(l==null)return;const S={...c,cursor:l};R(S,t,s,{direction:"next",force:!0})},i.fetchPreviousPage=()=>{const c=a[0];if(!c||!c.infinite)return;const l=i.__prevPageParam;if(l==null)return;const S={...c,cursor:l};R(S,t,s,{direction:"previous",force:!0})}},jt={invalidateQueries:e=>Be(A,ce(e)),removeQueries:e=>{Ke(A,e?ce(e):Ye)},getQueryData:e=>ut(A,e),setQueryData:(e,t)=>{ft(A,e,t)},prefetchQuery:async(e,t)=>{const r=t?.fetch;if(!r)return;const s=P(t),o=await Ue(r,t);if(!o)return;const n=e.method||"select",a=Te(null,t),i=oe(null,t),u=ke({...e,method:n},e.params,a,i),y=o[n];if(!d(y))return;const c={from:e.from,params:e.params,limit:e.limit,offset:e.offset,order:e.order,single:e.single,headers:e.headers,baseUrl:e.baseUrl};i&&(c.headers={...c.headers,"Accept-Language":i}),e.responseType!==void 0&&(c.responseType=e.responseType),n==="rpc"&&(c.read=!Ie(e)&&e.read!==!1);const l=++we,S=await y(c);if(S?.data!==void 0&&!S?.error&&!De(e)&&!ge(s,u,l)){const Q=ne(s,u,S.data,null,l,Oe(s,u,l));Q.gcTime=Le(e.cache)?.gcTime||3e5}return S},getCache:()=>A.cache,clear:()=>Ke(A,Ye),dropNonLang:e=>{if(!e)return;const t=`:${e}`;for(const[r]of A.cache)r.match(/:([a-z]{2,3})$/i)&&(r.endsWith(t)||Ze(A,r))}},dt=(e,t)=>X(e)?qe({method:"select",...e},t,t?.context):e,Bt={invalidateQueries(e){return Be(P(this?.context),ce(e))},removeQueries(e){Ke(P(this?.context),e?ce(e):Ye)},getQueryData(e){return ut(P(this?.context),dt(e,this))},setQueryData(e,t){ft(P(this?.context),dt(e,this),t)}},Kt={name:"fetch",create(e){const t=e.fetch;t&&(e.parent||P(e.context).active.clear(),lt(t,e,e.state,e.context))}};import{earlyKey as Vt,EARLY_KEY as xt,createEarlySeedScript as Jt,createEarlySeedBlock as Ht,SEED_BLOCK as Xt}from"./early.js";import{requestsInFlight as er,whenRequestsIdle as tr}from"./inflight.js";var Yt=lt;export{xt as EARLY_KEY,Xt as SEED_BLOCK,Qt as createAdapter,Ht as createEarlySeedBlock,Jt as createEarlySeedScript,Yt as default,Vt as earlyKey,lt as executeFetch,Bt as fetchFunctions,Kt as fetchPlugin,$t as hasAdapter,Ne as initAdapterAuth,re as parseDuration,jt as queryClient,Ut as registerAdapter,er as requestsInFlight,mt as resolveDb,tr as whenRequestsIdle};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o=Symbol.for("@symbo.ls/fetch:IN_FLIGHT"),s=()=>globalThis[o]||(globalThis[o]={count:0,waiters:[]}),r=()=>{s().count++},c=()=>{const t=s();if(t.count=t.count>0?t.count-1:0,t.count===0&&t.waiters.length){const e=t.waiters;t.waiters=[];for(const n of e)n()}},i=()=>s().count,u=()=>{const t=s();return t.count===0?Promise.resolve():new Promise(e=>{t.waiters.push(e)})};export{c as requestFinished,r as requestStarted,i as requestsInFlight,u as whenRequestsIdle};
|
package/early.js
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
// self-contained: no reference to anything outside their own parameters and
|
|
25
25
|
// the platform's built-ins (URL, decodeURIComponent, …).
|
|
26
26
|
|
|
27
|
-
import { jsonForScript } from '@symbo.ls/utils'
|
|
27
|
+
import { jsonForScript, readJsonDataBlock } from '@symbo.ls/utils'
|
|
28
28
|
|
|
29
29
|
export const EARLY_KEY = '@symbo.ls/fetch:EARLY'
|
|
30
30
|
|
|
@@ -144,14 +144,17 @@ export const withReads = (early, reads) => {
|
|
|
144
144
|
// No `early` config → null, and the adapter never looks (the opt-in).
|
|
145
145
|
export const openEarly = (config, headers) => {
|
|
146
146
|
const key = registryKey()
|
|
147
|
+
// The page's seed block, if it carries one, fills the registry first.
|
|
148
|
+
readSeedBlock()
|
|
147
149
|
if (!config || typeof config !== 'object') {
|
|
148
|
-
// A server-seeded registry (
|
|
149
|
-
//
|
|
150
|
-
// the page carries the answers,
|
|
151
|
-
//
|
|
152
|
-
//
|
|
150
|
+
// A server-seeded registry (the answers a brender pre-render already
|
|
151
|
+
// got: createEarlySeedBlock, or an older page's createEarlySeedScript)
|
|
152
|
+
// is adoptable without `fetch.early`: the page carries the answers,
|
|
153
|
+
// nothing is sent early. Only a call that sends exactly what the server
|
|
154
|
+
// recorded — an anonymous GET, no header beyond Accept-Language — can
|
|
155
|
+
// take one.
|
|
153
156
|
const seeded = globalThis[key]
|
|
154
|
-
if (seeded && seeded.seeded) return { carried: {}, rpc: false, maxAge: EARLY_MAX_AGE }
|
|
157
|
+
if (seeded && seeded.seeded) return { carried: {}, rpc: false, maxAge: EARLY_MAX_AGE, seeded: true }
|
|
155
158
|
return null
|
|
156
159
|
}
|
|
157
160
|
// Any registry closes the hand-off: the pre-boot script sends nothing once
|
|
@@ -162,7 +165,7 @@ export const openEarly = (config, headers) => {
|
|
|
162
165
|
if (found) carried[header] = value
|
|
163
166
|
}
|
|
164
167
|
const maxAge = typeof config.maxAge === 'number' && config.maxAge >= 0 ? config.maxAge : EARLY_MAX_AGE
|
|
165
|
-
return { carried, rpc: config.rpc === 'get', maxAge }
|
|
168
|
+
return { carried, rpc: config.rpc === 'get', maxAge, seeded: !!globalThis[key].seeded }
|
|
166
169
|
}
|
|
167
170
|
|
|
168
171
|
// The waiting answer for `key`, taken ONCE (a body can be read once; a second
|
|
@@ -170,12 +173,18 @@ export const openEarly = (config, headers) => {
|
|
|
170
173
|
// the early request failed, was refused (a 4xx/5xx may be the early form's
|
|
171
174
|
// own problem — a query-string key or a GET the backend does not serve — so
|
|
172
175
|
// the call's own request decides), or is older than `maxAge`.
|
|
176
|
+
//
|
|
177
|
+
// A seed block's answer (readSeedBlock) resolves to the answer itself —
|
|
178
|
+
// `{ seeded: true, status, type, body }`, always an ok one — which the REST
|
|
179
|
+
// adapter reads without a Response: no body stream, so the data lands in the
|
|
180
|
+
// same task the app booted in, before the first frame paints.
|
|
173
181
|
export const takeEarly = (key, maxAge = EARLY_MAX_AGE) => {
|
|
174
182
|
const registry = globalThis[registryKey()]
|
|
175
183
|
const entry = registry && registry.entries && registry.entries[key]
|
|
176
184
|
if (!entry) return null
|
|
177
185
|
delete registry.entries[key]
|
|
178
186
|
if (!(Date.now() - entry.time <= maxAge)) return null
|
|
187
|
+
if (entry.seeded) return Promise.resolve(entry.seeded)
|
|
179
188
|
return Promise.resolve(entry.answer).then(
|
|
180
189
|
(res) => (res && res.ok && !res.bodyUsed ? res : null),
|
|
181
190
|
() => null
|
|
@@ -191,23 +200,60 @@ export const dropEarly = () => {
|
|
|
191
200
|
|
|
192
201
|
// --- Server-seeded answers (FW-BRENDER-HYDRATION-AND-CF-DEPLOY-PROVIDER-1) ---
|
|
193
202
|
// A @symbo.ls/brender pre-render records the anonymous GETs its fetch
|
|
194
|
-
// adapter made (url, Accept-Language, status, content type, body).
|
|
195
|
-
// carries them
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
//
|
|
199
|
-
// `
|
|
200
|
-
// `entries`: [{ url, lang, status, type, body }].
|
|
201
|
-
|
|
203
|
+
// adapter made (url as sent, Accept-Language, status, content type, body).
|
|
204
|
+
// The page carries them, and they fill the same registry a `fetch.early`
|
|
205
|
+
// pre-boot script fills — keyed with earlyKey, so the REST adapter adopts
|
|
206
|
+
// each answer for the first call that sends exactly that request instead of
|
|
207
|
+
// asking the network again. Marked `seeded`, so an adapter without
|
|
208
|
+
// `fetch.early` adopts them too (openEarly).
|
|
209
|
+
// `entries`: [{ url, lang, status, type, body }].
|
|
210
|
+
|
|
211
|
+
// The recorded answers as the page carries them: `{ k: earlyKey, s: status,
|
|
212
|
+
// t: content type, b: body }`.
|
|
213
|
+
const seedList = (entries) => (Array.isArray(entries) ? entries : [])
|
|
214
|
+
.filter((e) => e && typeof e.url === 'string' && typeof e.body === 'string')
|
|
215
|
+
.map((e) => ({ k: earlyKey(e.url, e.lang || ''), s: e.status || 200, t: e.type || 'application/json', b: e.body }))
|
|
216
|
+
|
|
217
|
+
// The page's answers as a data block — `<script type="application/json"
|
|
218
|
+
// data-fetch-seed>` — which no Content-Security-Policy blocks: XMA's
|
|
219
|
+
// `script-src 'self'` (no 'unsafe-inline') refused the inline
|
|
220
|
+
// createEarlySeedScript below, so a pre-rendered page under it had no seed
|
|
221
|
+
// (XMA report, brender items 1 and 3). The REST adapter reads the block when
|
|
222
|
+
// it opens (readSeedBlock). JSON is embedded with utils jsonForScript, so a
|
|
223
|
+
// body can never close the block.
|
|
224
|
+
export const SEED_BLOCK = 'script[type="application/json"][data-fetch-seed]'
|
|
225
|
+
|
|
226
|
+
export const createEarlySeedBlock = (entries) => {
|
|
227
|
+
const list = seedList(entries)
|
|
228
|
+
if (!list.length) return ''
|
|
229
|
+
return '<script type="application/json" data-fetch-seed>' + jsonForScript(list) + '</script>'
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Fill the registry from the page's seed block — once: the block goes when
|
|
233
|
+
// read. An answer already waiting under the same key (a pre-boot script's)
|
|
234
|
+
// is kept. Each seeded answer is adoptable for EARLY_MAX_AGE from now.
|
|
235
|
+
export const readSeedBlock = () => {
|
|
236
|
+
const read = readJsonDataBlock(globalThis.document, SEED_BLOCK, { remove: true })
|
|
237
|
+
const list = read && read.value
|
|
238
|
+
if (!Array.isArray(list) || !list.length) return
|
|
239
|
+
const key = registryKey()
|
|
240
|
+
const registry = globalThis[key] || (globalThis[key] = { entries: {} })
|
|
241
|
+
if (!registry.entries) registry.entries = {}
|
|
242
|
+
registry.seeded = true
|
|
243
|
+
const time = Date.now()
|
|
244
|
+
for (const e of list) {
|
|
245
|
+
if (!e || typeof e.k !== 'string' || typeof e.b !== 'string' || registry.entries[e.k]) continue
|
|
246
|
+
registry.entries[e.k] = { time, seeded: { seeded: true, status: e.s || 200, type: e.t || 'application/json', body: e.b } }
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// The same answers as an inline script (pages from brender up to 3.14.664;
|
|
251
|
+
// the platform's renderer still ships it). Kept for those: a page under a
|
|
252
|
+
// strict Content-Security-Policy needs createEarlySeedBlock.
|
|
202
253
|
export const createEarlySeedScript = (entries) => {
|
|
203
|
-
const list = (
|
|
254
|
+
const list = seedList(entries)
|
|
204
255
|
if (!list.length) return ''
|
|
205
|
-
const json = jsonForScript(list
|
|
206
|
-
k: earlyKey(e.url, e.lang || ''),
|
|
207
|
-
s: e.status || 200,
|
|
208
|
-
t: e.type || 'application/json',
|
|
209
|
-
b: e.body
|
|
210
|
-
})))
|
|
256
|
+
const json = jsonForScript(list)
|
|
211
257
|
return '<script>(function(){try{var k=Symbol.for(' + JSON.stringify(EARLY_KEY) + '),' +
|
|
212
258
|
'r=globalThis[k]||(globalThis[k]={entries:{}}),t=Date.now(),l=' + json + ';' +
|
|
213
259
|
'r.seeded=true;r.entries=r.entries||{};' +
|