UNPKG

@happykit/flags

Version:

Feature Flags for Next.js

3 lines (2 loc) 5.96 kB
import{a as k,b as h,c as C,d as I,e as T,f as w}from"./chunk-TMZGICGH.mjs";import*as f from"react";import{nanoid as P}from"nanoid";var j=(()=>{let u=0;return()=>u++})();function x(u,s){let o=j(),e=typeof AbortController<"u"?new AbortController:null,t={effect:"fetch",id:o,controller:e,input:u};return s!=null&&s.controller&&s.controller.abort(),[[t],{id:o,controller:e}]}function A(u){return u.name==="evaluating"||u.name==="revalidating-after-success"||u.name==="revalidating-after-failure"}function D(u){return function(o,e){var O,c,B;let[t]=o;switch(e.type){case"evaluate":{let l=E.get(e.input),[d,p]=x(e.input,t.pending);return[{name:"evaluating",input:e.input,cachedOutcome:l,pending:p},d]}case"revalidate":{if(t.name==="empty")return o;let l=e.input||t.input,[d,p]=x(l,t.pending);return t.name==="succeeded"?[{name:"revalidating-after-success",input:t.input,outcome:t.outcome,cachedOutcome:t.cachedOutcome,pending:p},d]:t.name==="failed"?[{name:"revalidating-after-failure",input:t.input,outcome:t.outcome,cachedOutcome:t.cachedOutcome,pending:p},d]:t.name==="evaluating"?[{name:"evaluating",input:t.input,outcome:t.outcome,cachedOutcome:t.cachedOutcome,pending:p},d]:o}case"settle/failure":{if(!A(t)||((O=t.pending)==null?void 0:O.id)!==e.id)return o;e.thrownError&&(console.error("@happykit/flags: Failed to load flags"),console.error(e.thrownError));let l=E.get(e.input);return[{name:"failed",input:e.input,outcome:e.outcome,cachedOutcome:l},[]]}case"settle/success":{if(!A(t)||((c=t.pending)==null?void 0:c.id)!==e.id)return o;let l=(B=e.outcome.data.visitor)==null?void 0:B.key;if(l){let d=u.serializeVisitorKeyCookie(l);d&&(document.cookie=d)}return E.set(e.input,e.outcome),[{name:"succeeded",input:e.input,outcome:e.outcome},[]]}default:return o}}}function U({config:u,visitorKeyInState:s,generatedVisitorKey:o,user:e,traits:t}){let O=typeof document<"u"?C(document.cookie,"hkvk"):null;return{endpoint:u.endpoint,envKey:u.envKey,requestBody:{visitorKey:O||s||o,user:e,traits:t}}}function L(u){return{...u,requestBody:{...u.requestBody,visitorKey:null}}}function M(u,s){return u&&!u.requestBody.visitorKey?I(L(u),L(s)):I(u,s)}var b=0;function V(){f.useEffect(()=>(b++,b>1&&console.warn(["@happykit/flags: Simultaneous invocations of useFlags() detected","","See https://happykit.dev/notes/1"].join(` `)),()=>{b--}),[])}var E=new T;function W(u,{revalidateOnFocus:s=!0,clientLoadingTimeout:o=3e3}={}){let e=w(u),t=D(e);return function(c={}){V();let[B]=f.useState(P),l=c.user||null,d=c.traits||null,p=c.revalidateOnFocus===void 0?s:c.revalidateOnFocus,S=k(c,"clientLoadingTimeout")?c.clientLoadingTimeout:o,[[n,q],m]=f.useReducer(t,c.initialState,r=>{if(!(r!=null&&r.input))return[{name:"empty"},[]];let a=U({config:e,visitorKeyInState:r.input.requestBody.visitorKey,generatedVisitorKey:B,user:l,traits:d});return r.outcome.error?[{name:"failed",input:r.input,outcome:r.outcome,cachedOutcome:E.get(r.input)},[{effect:"revalidate-input",input:a}]]:(E.set(r.input,r.outcome),[{name:"succeeded",input:r.input,outcome:r.outcome},r.input.requestBody.visitorKey?[]:[{effect:"revalidate-input",input:a}]])});f.useEffect(()=>{var y;let r=U({config:e,visitorKeyInState:(y=n.input)==null?void 0:y.requestBody.visitorKey,generatedVisitorKey:B,user:l,traits:d});if(!c.pause&&!M(n.input,r)&&m({type:"evaluate",input:r}),!p)return;function a(){document.visibilityState==="visible"&&!c.pause&&m({type:"revalidate"})}let i="visibilitychange";return document.addEventListener(i,a),()=>{document.removeEventListener(i,a)}},[n,l,d,p,c.pause]);let v=f.useCallback(()=>m({type:"revalidate"}),[m]);f.useEffect(()=>{q.forEach(r=>{switch(r.effect){case"fetch":{let{id:a,input:i,controller:y}=r,R;y&&S&&(R=setTimeout(()=>y.abort(),S)),fetch([i.endpoint,i.envKey].join("/"),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(i.requestBody),signal:y==null?void 0:y.signal,cache:"no-store"}).then(F=>(clearTimeout(R),F.ok?F.json().then(K=>{m({type:"settle/success",id:a,input:i,outcome:{data:K}})},K=>(m({type:"settle/failure",id:a,input:i,outcome:{error:"invalid-response-body"},thrownError:K}),null)):(m({type:"settle/failure",id:a,input:i,outcome:{error:"response-not-ok"},thrownError:new Error("Response not ok")}),null)),F=>(F instanceof DOMException&&F.name==="AbortError"?m({type:"settle/failure",id:a,input:i,outcome:{error:"request-timed-out"},thrownError:F}):m({type:"settle/failure",id:a,input:i,outcome:{error:"network-error"},thrownError:F}),null));break}case"revalidate-input":m({type:"revalidate",input:r.input});break;default:return}})},[q,m]);let{defaultFlags:g}=e;return f.useMemo(()=>{var r,a,i;switch(n.name){case"evaluating":return{flags:(r=n.cachedOutcome)!=null&&r.data.flags?h(n.cachedOutcome.data.flags,g):null,data:null,error:null,fetching:!0,settled:!1,revalidate:v,visitorKey:n.input.requestBody.visitorKey};case"succeeded":return{flags:h(n.outcome.data.flags,g),data:n.outcome.data,error:null,fetching:!1,settled:Boolean(n.input.requestBody.visitorKey),revalidate:v,visitorKey:n.input.requestBody.visitorKey};case"revalidating-after-success":return{flags:h(n.outcome.data.flags,g),data:n.outcome.data,error:null,fetching:!0,settled:Boolean(n.input.requestBody.visitorKey),revalidate:v,visitorKey:n.input.requestBody.visitorKey};case"failed":return{flags:(a=n.cachedOutcome)!=null&&a.data.flags?h(n.cachedOutcome.data.flags,g):g||null,data:null,error:n.outcome.error,fetching:!1,settled:Boolean(n.input.requestBody.visitorKey),revalidate:v,visitorKey:n.input.requestBody.visitorKey};case"revalidating-after-failure":return{flags:(i=n.cachedOutcome)!=null&&i.data.flags?h(n.cachedOutcome.data.flags,g):g||null,data:null,error:n.outcome.error,fetching:!0,settled:Boolean(n.input.requestBody.visitorKey),revalidate:v,visitorKey:n.input.requestBody.visitorKey};default:case"empty":return{flags:null,data:null,error:null,fetching:!1,settled:!1,revalidate:v,visitorKey:null}}},[n,g,v])}}export{E as cache,W as createUseFlags};