@picked/client 0.0.37 → 0.0.38-next.2

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/dist/cjs/index.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("effector"),h=require("@withease/factories"),I=require("../experience-instance-CsMhH0DN.cjs"),F=require("../logger-BsmHUUw1.cjs"),v=require("../storage-YlR83AWP.cjs"),_=require("../id-BKIWbSTy.cjs"),q=require("../object-BbFTsGh3.cjs"),S=require("../supports-YvpQZxbh.cjs"),z=g.createDomain("experience"),K=h.createFactory(({client:t,experience:e})=>{const r=z.store(e),n=g.createApi(r,{merge(a,f){return{...a,...f.experience}}}),i=r.map(a=>({name:a.name,decisionLogic:a.condition??a.decide,targetSelectors:a.targets,initializeOpenLogic:e.initializeOpen})),u=t.components.listStore.map(a=>a.find(f=>f.name===`experience:${e.id}`)||a.find(f=>f.name==="experience"),{skipVoid:!1}),o=r.map(a=>({steps:a.steps,nodes:a.nodes,edges:a.edges,conditionals:a.conditionals})),s=e.actions??[];return{id:e.id,configStore:i,treeStore:o,componentStore:u,actions:s,merge:n.merge}});function W(t){return h.invoke(K,t)}const H=h.createFactory(({client:t})=>{const e=z.store({}),r=g.createApi(e,{register(o,s){return{...o,[s.id]:s}}});function n(o){const s=e.getState()[o.id];if(s){s.merge({experience:o,strategy:"override"});return}const a=W({client:t,experience:o});r.register(a)}const i=e.map(o=>Object.values(o));function u(o){return e.map(s=>s[o],{skipVoid:!1})}return{register:n,getById:u,listStore:i}});function G(t){return h.invoke(H,t)}const Y=(t,e)=>{e.register(t)},U=(t,e)=>{const{targetSelectors:r}=e.configStore.getState(),n=I.getTargetElements(r,e.id);n.forEach(({elements:u})=>u.forEach(o=>I.tagTargetElement(o,e.id))),I.createAppHosts(n,e.id).forEach(u=>{t.experienceInstances.spawn(e,u)})},B=async t=>{await Promise.all(t.experiences.listStore.getState().map(async e=>{await J(t,e)&&U(t,e)}))},J=async(t,e)=>{const{decisionLogic:r,targetSelectors:n}=e.configStore.getState();return I.getTargetElements(n,e.id).length<1||n.length===0?!1:r&&I.isRulesLogic(r)?await I.evaluateRuleLogic(t,r)===!0:!0},Q=(t,e,r)=>{const n=e.name,i=e.setup(t);if(i){const u=r[n]??{};r[n]=Object.freeze({...u,...i})}},X=g.createDomain("component"),Z=h.createFactory(({client:t,component:e,name:r})=>{const n=t.frameworks.getByName(e.frameworkName);return{name:r,component:e,frameworkStore:n}});function ee(t){return h.invoke(Z,t)}const te=h.createFactory(({client:t})=>{const e=X.store({}),r=g.createApi(e,{register(o,s){return{...o,[s.name]:s}}});function n(o,s){e.getState()[o]&&F.logger("warn",`Component '${o}' already registered. Registering again will override the previous registration.`);const f=ee({client:t,name:o,component:s});r.register(f)}const i=e.map(o=>Object.values(o));function u(o){return e.map(s=>s[o],{skipVoid:!1})}return{register:n,getByName:u,listStore:i}});function re(t){return h.invoke(te,t)}const D=(t,e,r)=>{r.register(t,e)},ne=g.createDomain("framework"),se=h.createFactory(({client:t})=>{const e=ne.store({}),r=g.createApi(e,{register(o,s){return{...o,[s.name]:s.framework}}});function n(o,s){e.getState()[o]&&F.logger("warn",`Framework '${o}' already registered. Registering again will override the previous registration.`),r.register({name:o,framework:s})}const i=e.map(o=>Object.values(o));function u(o){return e.map(s=>s[o],{skipVoid:!1})}return{register:n,getByName:u,listStore:i}});function ie(t){return h.invoke(se,t)}const oe=(t,e)=>{e.register(t.name,t)},ae=6e3,ce=v.createStorageKey("last_ping","global"),ue=t=>`${t}/api/v1/ping`,de=async t=>{try{const e=Date.now(),r=v.localStore.get(ce);let n=0;if(r.isSet()&&(n=r.json()??0),n&&e-n<ae)return!0;const i=ue(t.apiUrl),u={projectId:t.projectId,path:window.location.pathname},o=JSON.stringify(u),s={"Content-Type":"application/json"},f=document.getElementById("picked_script")?.dataset.verceltoken;f&&(s["x-vercel-protection-bypass"]=f);const b=(await fetch(i,{method:"POST",headers:s,body:o})).ok;return b&&r.set(e),b}catch(e){return F.logger("error",e),!1}};function L(t){const e=typeof window<"u",r={client:t,responses:t.responses.listStore.getState(),fields:t.fields.listStore.getState(),location:e?window.location:void 0,document:e?window.document:void 0,sessionStorage:e?window.sessionStorage:void 0,localStorage:e?window.localStorage:void 0};return Object.freeze(r)}const le=g.createDomain("predicate"),pe=h.createFactory(({client:t})=>{const e=le.store({}),r=g.createApi(e,{register(s,a){return{...s,[a.name]:{name:a.name,predicate:a.predicate}}}});function n(s,a){e.getState()[s]&&F.logger("warn",`Predicate '${s}' already registered. Registering again will override the previous registration.`),r.register(Object.freeze({name:s,predicate:a}))}const i=e.map(s=>Object.values(s));function u(s){return e.map(a=>a[s]?.predicate,{skipVoid:!1})}function o(s){const a=g.createStore(()=>{},{skipVoid:!1}),f=g.createEffect(async()=>{const k=u(s).getState();if(!k)return;const b=L(t);return(...m)=>k({...b,args:m})});return g.sample({source:{responses:t.responses.listStore,fields:t.fields.listStore},target:f}),g.sample({clock:f.doneData,filter:k=>k!==void 0,target:a}),f(),a}return{register:n,getByName:u,listStore:i,getEvokablePredicate:o}});function ge(t){return h.invoke(pe,t)}const fe=(t,e,r)=>{r.register(t,e)},C=g.createDomain("feature"),me=h.createFactory(({client:t})=>{const e=C.store({}),r=C.store([]),n=g.createApi(e,{register(c,d){return{...c,[d.id]:d.feature}}});function i(c,d){e.getState()[c]&&F.logger("warn",`Feature '${c}' already registered. Registering again will override the previous registration.`);const l={id:c,feature:{...d,id:c}};n.register(Object.freeze({id:c,feature:l}))}const u=g.createEffect(async({id:c,key:d,storage:p="local"})=>{const l=v.createStorageKey(`feature:${c}:${d}`,"global"),w=(p==="session"?v.sessionStore:v.localStore).get(l).boolean();return w===null?null:{id:c,key:d,bucket:w,storage:p}}),o=g.createEffect(c=>{if(!c)return null;const d=v.createStorageKey(`feature:${c.id}:${c.key}`,"global");(c.storage==="session"?v.sessionStore:v.localStore).set(d,c.bucket)}),s=new Map,a=g.attach({source:{allFeaturesStore:e,resolvedFeaturesStore:r},effect:async({allFeaturesStore:c,resolvedFeaturesStore:d},{id:p,decide:l,key:y})=>{const w=d.find(R=>R.id===p&&R.key===y);if(w)return w;const E=c[p];if(!E)throw new Error(`Feature with id '${p}' not found`);const j=s.get(`${p}:${y}`);if(j!==void 0){const R=await j;return{id:E.id,bucket:R,key:y,storage:E.feature.storage}}const P=l();s.set(`${p}:${y}`,P);const T=await P;return{id:E.id,bucket:T,key:y,storage:E.feature.storage}}});g.sample({clock:n.register,fn:c=>{const{id:d,feature:p}=c;return{id:d,key:p.feature.key,storage:p.feature.storage}},target:u}),g.sample({source:e,clock:a.doneData,fn:(c,d)=>{const{id:p,bucket:l,storage:y}=d,w=c[p]?.feature.key;return w?{key:w,id:p,bucket:l,storage:y}:null},target:o});const f=g.combine({allFeaturesStore:e,resolvedFeaturesStore:r}).map(({allFeaturesStore:c,resolvedFeaturesStore:d})=>Object.values(c).map(p=>{const l=d.find(y=>y.id===p.id&&y.key===p.feature.key);return l?{id:p.id,name:p.feature.name,key:p.feature.key,getBucket:()=>({id:p.id,bucket:l.bucket}),isResolved:!0}:{id:p.id,name:p.feature.name,key:p.feature.key,getBucket:async()=>await a(p.feature),isResolved:!1}}));g.sample({clock:a.doneData,source:{resolvedFeatures:r},filter:({resolvedFeatures:c},{id:d,key:p})=>!c.some(y=>y.id===d&&y.key===p),fn:(c,d)=>d,target:t.eventBus.prepend(c=>({type:"feature_decide",feature:c}))}),g.sample({clock:[u.doneData,a.doneData],source:r,fn:(c,d)=>!d||c.some(l=>l.id===d.id&&l.key===d.key)?c:[...c,d],target:r});function k(c){return f.map(d=>d.find(p=>p.id===c))}function b(c){return e.map(d=>d[c],{skipVoid:!1})}function m(c){const d=g.createStore(async()=>{},{skipVoid:!1}),p=g.createEffect(async()=>{const l=k(c).getState();if(l)return async()=>(await l.getBucket()).bucket});return g.sample({source:r,filter:l=>l.some(y=>y.id===c),target:p}),g.sample({clock:p.doneData,filter:l=>l!==void 0,target:d}),p(),d}return{register:i,getById:k,getByName:b,listStore:f,getEvokableFeature:m}});function ye(t){return h.invoke(me,t)}const he=(t,e,r)=>{r.register(t,e)},x=g.createDomain("history");function $(t,e){return{id:_.generateId(`history-entry-${Date.now()}-${Math.random()}}`),node:e,at:Date.now(),experienceId:t}}const Se=h.createFactory(()=>{const t=x.store({entries:[]}),e=x.event(),r=x.event(),n=x.event(),i=x.event();t.on(e,(o,s)=>({entries:[...o.entries,$(s.experienceId,s.node)]})),t.on(r,(o,s)=>({entries:[...o.entries.slice(0,-1),$(s.experienceId,s.node)]})),t.on(i,(o,s)=>s);function u(o,s){const a={lastStepIndex:-1,secondLastStepIndex:-1};for(let f=o.length-1;f>=0;f--){const k=o[f],b=k?.node;if(!(!b||!I.isStepNode(b))&&!(s&&k?.experienceId!==s))if(a.lastStepIndex===-1)a.lastStepIndex=f;else{a.secondLastStepIndex=f;break}}return a}return t.on(n,(o,s)=>{const{secondLastStepIndex:a}=u(o.entries,s.experienceId),f=a!==-1?o.entries.slice(0,a+1):o.entries;return{...o,entries:f}}),{push:e,replace:r,back:n,restore:i,entriesStore:t.map(o=>o.entries)}});function ke(){return h.invoke(Se)}const ve=()=>g.createEvent(),we=g.createDomain("field"),Ie=h.createFactory(()=>{const t=we.store({}),e=g.createApi(t,{register(s,a){return{...s,[a.field.id]:a.field}}});function r(s){e.register({field:s})}function n(s,a){const f=u(s).getState();if(!f)return;const k=Object.assign({},f,{...a});e.register({field:{...k}})}const i=t.map(s=>Object.values(s));function u(s){return t.map(a=>a[s]||null)}function o(s){return t.map(a=>Object.values(a).find(f=>f.name===s)||null)}return{register:r,update:n,getById:u,listStore:i,getByName:o}});function be(){return h.invoke(Ie)}const Fe=(t,e)=>{e.register(t)},Ee=g.createDomain("action"),je=h.createFactory(()=>{const t=Ee.store({}),e=g.createApi(t,{register(o,s){return{...o,[s.name]:{name:s.name,action:s.action}}}});function r(o,s){e.register({name:o,action:s})}const n=t.map(o=>Object.values(o));function i(o){return t.map(s=>s[o],{skipVoid:!1})}function u(o){return t.map(s=>{const a=s[o];return a?a.action:void 0},{skipVoid:!1})}return{register:r,getByName:i,listStore:n,getEvokableAction:u}});function xe(){return h.invoke(je)}const Re=(t,e,r)=>{r.register(t,e)};function O(t){return typeof t>"u"||t===null||t===""||Array.isArray(t)&&!t.length}const Ae=g.createDomain("response"),Pe=h.createFactory(({client:t})=>{const e=Ae.store({}),r=g.createEvent(),n=g.createEvent(),i=g.createApi(e,{register(m,c){return{...m,[c.fieldId]:c.response}},registerBatch(m,c){return{...m,...c}},clear(m,c){const{[c]:d,...p}=m;return p},clearAll(){return{}}});function u(m,c){if(typeof m=="string"){if(c===void 0)throw new Error("Response is required when registering a single field");i.register({fieldId:m,response:c})}else i.registerBatch(m)}async function o(m){const c=[];return await Promise.allSettled(Object.entries(m).map(async([d,p])=>{let l=p;const y=t.fields.getById(d).getState();if(!y){c.push({fieldId:d,userMessage:`Field '${d}' not found`,systemMessage:`No field with ID '${d}' exists. Available field IDs are: ${Object.keys(t.fields.listStore.getState()).join(",")}.`,value:l});return}if(y.multiple&&(typeof l=="string"||typeof l=="number"||typeof l=="boolean")&&(l=[l]),y.validation&&!q.isEmpty(y.validation)&&!O(l)){const w=await I.evaluateRuleLogic(t,y.validation,{$input:l});if(typeof w=="string"){c.push({fieldId:d,userMessage:w,systemMessage:`Field validation resulted in an error: ${w}.`,value:l});return}if(w===!1){c.push({fieldId:d,userMessage:"This field is invalid",systemMessage:"Field validation resulted in an unspecified error.",value:l});return}}if(y.required&&O(l)){c.push({fieldId:d,userMessage:"This field is required",systemMessage:"Field is required.",value:l});return}if(!y.multiple&&Array.isArray(l)&&l.length>1){c.push({fieldId:d,userMessage:"This field expects a single response",systemMessage:"Field expects a single response.",value:l});return}if(y.options){const w=y.options.map(j=>j.value),E=Array.isArray(l)?l:[l];Array.isArray(l)&&(E.every(j=>w.includes(j))||c.push({fieldId:d,userMessage:"This field expects a valid option",systemMessage:`Field expects a valid option. Valid options are: ${w.join(", ")}`,value:l}))}})),{responsesToCommit:m,validationErrors:c}}async function s(m){const{responsesToCommit:c,validationErrors:d}=await o(m);return d.length?{errors:d}:(i.registerBatch(c),{errors:[]})}const a=e.map(m=>m),f=e.map(m=>Object.keys(m).map(d=>({fieldId:d,value:m[d]})));function k(m){const c=t.fields.getById(m),d=e.map(p=>p[m]||null);return g.combine({f:c,r:d},({f:p,r:l})=>l||(p?.defaultValue?p.defaultValue:null))}function b(m){const c=t.fields.getByName(m);return g.combine({f:c,s:e},({f:d,s:p})=>{const l=d&&p[d.id]||null;return l||(d?.defaultValue?d.defaultValue:null)})}return g.sample({clock:r,target:i.clearAll}),g.sample({clock:n,target:i.clear}),{register:u,clearAll:r,clear:n,commit:s,getResponsesToCommit:o,listStore:f,getAllStore:a,getByFieldId:k,getByFieldName:b}});function Be(t){return h.invoke(Pe,t)}const De=()=>"0.0.37";function Ce(){if(S.supportsDocument()){const t=[document.currentScript,document.getElementById("picked_script"),document.getElementById("picked"),document.getElementById("cvly"),document.getElementById("cvly-x")];for(const e of t)if(e?.dataset.api)return e.dataset.api}return"https://api.picked.app"}function $e(){if(!S.supportsWindow())return{};const t=new URLSearchParams(window.location.search),e={},r=new Set;for(const[i]of t.entries())i.startsWith("picked-")&&r.add(i);for(const i of r){const u=i.replace("picked-","");e[u]=t.getAll(i)}const n=v.createStorageKey("s");if(r.size>0)v.sessionStore.set(n,e);else{const i=v.sessionStore.get(n);if(i)return i.json()||{}}return e}function Oe(){if(S.supportsCryptoRandomUUID())return crypto.randomUUID();const t=Date.now().toString(36),e=Math.random().toString(36).substring(2,15),r=Math.random().toString(36).substring(2,15),n=Math.random().toString(36).substring(2,15);return`${t}-${e}-${r}-${n}`}const ze=v.createStorageKey("session","global"),Ue=()=>{const t=v.localStore.get(ze);let e;t.isSet()&&(e=t.json());const r=i=>t.set({id:i.id,isUser:i.isUser,identifiers:i.identifiers}),n={id:e?.id??Oe(),isUser:e?.isUser??void 0,identifiers:e?.identifiers??void 0,setIsUser(i){this.isUser=i,r(this)},setIdentifier(i,u){this.identifiers={...this.identifiers,[i]:u},r(this)},removeIdentifier(i){this.identifiers&&(this.identifiers=Object.fromEntries(Object.entries(this.identifiers).filter(([u])=>u!==i)),this.identifiers=Object.keys(this.identifiers).length?this.identifiers:void 0,r(this))}};return r(n),n},Le=()=>S.supportsLocalStorage()?Ue():null;function V(){if(S.supportsWindow())return globalThis.window.pickedConfig}function Ve(){if(!S.supportsWindow())return;const t=V(),e=t?.organizationId,r=t?.projectId;return e&&r?{organizationId:e,projectId:r}:void 0}function Me(){if(!S.supportsDocument())return;const t=document.getElementById("picked_script")||document.querySelector("script#picked")||document.getElementById("cvly");if(!t)return;const e=t.dataset.organizationid||t.getAttribute("organization-id"),r=t.dataset.projectid||t.getAttribute("project-id");return e&&r?{organizationId:e,projectId:r}:void 0}function Ne(t){const{organizationId:e,projectId:r}=t;if(e&&r)return{organizationId:e,projectId:r};const n=Ve();if(n)return n;const i=Me();if(i)return i;throw new Error(`organizationId and projectId are required. You can provide them via one of:
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("effector"),h=require("@withease/factories"),I=require("../experience-instance-CsMhH0DN.cjs"),F=require("../logger-BsmHUUw1.cjs"),v=require("../storage-Be5xWNPC.cjs"),_=require("../id-BKIWbSTy.cjs"),q=require("../object-BbFTsGh3.cjs"),S=require("../supports-YvpQZxbh.cjs"),z=g.createDomain("experience"),K=h.createFactory(({client:t,experience:e})=>{const r=z.store(e),n=g.createApi(r,{merge(a,f){return{...a,...f.experience}}}),i=r.map(a=>({name:a.name,decisionLogic:a.condition??a.decide,targetSelectors:a.targets,initializeOpenLogic:e.initializeOpen})),u=t.components.listStore.map(a=>a.find(f=>f.name===`experience:${e.id}`)||a.find(f=>f.name==="experience"),{skipVoid:!1}),o=r.map(a=>({steps:a.steps,nodes:a.nodes,edges:a.edges,conditionals:a.conditionals})),s=e.actions??[];return{id:e.id,configStore:i,treeStore:o,componentStore:u,actions:s,merge:n.merge}});function W(t){return h.invoke(K,t)}const H=h.createFactory(({client:t})=>{const e=z.store({}),r=g.createApi(e,{register(o,s){return{...o,[s.id]:s}}});function n(o){const s=e.getState()[o.id];if(s){s.merge({experience:o,strategy:"override"});return}const a=W({client:t,experience:o});r.register(a)}const i=e.map(o=>Object.values(o));function u(o){return e.map(s=>s[o],{skipVoid:!1})}return{register:n,getById:u,listStore:i}});function G(t){return h.invoke(H,t)}const Y=(t,e)=>{e.register(t)},U=(t,e)=>{const{targetSelectors:r}=e.configStore.getState(),n=I.getTargetElements(r,e.id);n.forEach(({elements:u})=>u.forEach(o=>I.tagTargetElement(o,e.id))),I.createAppHosts(n,e.id).forEach(u=>{t.experienceInstances.spawn(e,u)})},B=async t=>{await Promise.all(t.experiences.listStore.getState().map(async e=>{await J(t,e)&&U(t,e)}))},J=async(t,e)=>{const{decisionLogic:r,targetSelectors:n}=e.configStore.getState();return I.getTargetElements(n,e.id).length<1||n.length===0?!1:r&&I.isRulesLogic(r)?await I.evaluateRuleLogic(t,r)===!0:!0},Q=(t,e,r)=>{const n=e.name,i=e.setup(t);if(i){const u=r[n]??{};r[n]=Object.freeze({...u,...i})}},X=g.createDomain("component"),Z=h.createFactory(({client:t,component:e,name:r})=>{const n=t.frameworks.getByName(e.frameworkName);return{name:r,component:e,frameworkStore:n}});function ee(t){return h.invoke(Z,t)}const te=h.createFactory(({client:t})=>{const e=X.store({}),r=g.createApi(e,{register(o,s){return{...o,[s.name]:s}}});function n(o,s){e.getState()[o]&&F.logger("warn",`Component '${o}' already registered. Registering again will override the previous registration.`);const f=ee({client:t,name:o,component:s});r.register(f)}const i=e.map(o=>Object.values(o));function u(o){return e.map(s=>s[o],{skipVoid:!1})}return{register:n,getByName:u,listStore:i}});function re(t){return h.invoke(te,t)}const D=(t,e,r)=>{r.register(t,e)},ne=g.createDomain("framework"),se=h.createFactory(({client:t})=>{const e=ne.store({}),r=g.createApi(e,{register(o,s){return{...o,[s.name]:s.framework}}});function n(o,s){e.getState()[o]&&F.logger("warn",`Framework '${o}' already registered. Registering again will override the previous registration.`),r.register({name:o,framework:s})}const i=e.map(o=>Object.values(o));function u(o){return e.map(s=>s[o],{skipVoid:!1})}return{register:n,getByName:u,listStore:i}});function ie(t){return h.invoke(se,t)}const oe=(t,e)=>{e.register(t.name,t)},ae=6e3,ce=v.createStorageKey("last_ping","global"),ue=t=>`${t}/api/v1/ping`,de=async t=>{try{const e=Date.now(),r=v.localStore.get(ce);let n=0;if(r.isSet()&&(n=r.json()??0),n&&e-n<ae)return!0;const i=ue(t.apiUrl),u={projectId:t.projectId,path:window.location.pathname},o=JSON.stringify(u),s={"Content-Type":"application/json"},f=document.getElementById("picked_script")?.dataset.verceltoken;f&&(s["x-vercel-protection-bypass"]=f);const b=(await fetch(i,{method:"POST",headers:s,body:o})).ok;return b&&r.set(e),b}catch(e){return F.logger("error",e),!1}};function L(t){const e=typeof window<"u",r={client:t,responses:t.responses.listStore.getState(),fields:t.fields.listStore.getState(),location:e?window.location:void 0,document:e?window.document:void 0,sessionStorage:e?window.sessionStorage:void 0,localStorage:e?window.localStorage:void 0};return Object.freeze(r)}const le=g.createDomain("predicate"),pe=h.createFactory(({client:t})=>{const e=le.store({}),r=g.createApi(e,{register(s,a){return{...s,[a.name]:{name:a.name,predicate:a.predicate}}}});function n(s,a){e.getState()[s]&&F.logger("warn",`Predicate '${s}' already registered. Registering again will override the previous registration.`),r.register(Object.freeze({name:s,predicate:a}))}const i=e.map(s=>Object.values(s));function u(s){return e.map(a=>a[s]?.predicate,{skipVoid:!1})}function o(s){const a=g.createStore(()=>{},{skipVoid:!1}),f=g.createEffect(async()=>{const k=u(s).getState();if(!k)return;const b=L(t);return(...m)=>k({...b,args:m})});return g.sample({source:{responses:t.responses.listStore,fields:t.fields.listStore},target:f}),g.sample({clock:f.doneData,filter:k=>k!==void 0,target:a}),f(),a}return{register:n,getByName:u,listStore:i,getEvokablePredicate:o}});function ge(t){return h.invoke(pe,t)}const fe=(t,e,r)=>{r.register(t,e)},C=g.createDomain("feature"),me=h.createFactory(({client:t})=>{const e=C.store({}),r=C.store([]),n=g.createApi(e,{register(c,d){return{...c,[d.id]:d.feature}}});function i(c,d){e.getState()[c]&&F.logger("warn",`Feature '${c}' already registered. Registering again will override the previous registration.`);const l={id:c,feature:{...d,id:c}};n.register(Object.freeze({id:c,feature:l}))}const u=g.createEffect(async({id:c,key:d,storage:p="local"})=>{const l=v.createStorageKey(`feature:${c}:${d}`,"global"),w=(p==="session"?v.sessionStore:v.localStore).get(l).boolean();return w===null?null:{id:c,key:d,bucket:w,storage:p}}),o=g.createEffect(c=>{if(!c)return null;const d=v.createStorageKey(`feature:${c.id}:${c.key}`,"global");(c.storage==="session"?v.sessionStore:v.localStore).set(d,c.bucket)}),s=new Map,a=g.attach({source:{allFeaturesStore:e,resolvedFeaturesStore:r},effect:async({allFeaturesStore:c,resolvedFeaturesStore:d},{id:p,decide:l,key:y})=>{const w=d.find(R=>R.id===p&&R.key===y);if(w)return w;const E=c[p];if(!E)throw new Error(`Feature with id '${p}' not found`);const x=s.get(`${p}:${y}`);if(x!==void 0){const R=await x;return{id:E.id,bucket:R,key:y,storage:E.feature.storage}}const P=l();s.set(`${p}:${y}`,P);const T=await P;return{id:E.id,bucket:T,key:y,storage:E.feature.storage}}});g.sample({clock:n.register,fn:c=>{const{id:d,feature:p}=c;return{id:d,key:p.feature.key,storage:p.feature.storage}},target:u}),g.sample({source:e,clock:a.doneData,fn:(c,d)=>{const{id:p,bucket:l,storage:y}=d,w=c[p]?.feature.key;return w?{key:w,id:p,bucket:l,storage:y}:null},target:o});const f=g.combine({allFeaturesStore:e,resolvedFeaturesStore:r}).map(({allFeaturesStore:c,resolvedFeaturesStore:d})=>Object.values(c).map(p=>{const l=d.find(y=>y.id===p.id&&y.key===p.feature.key);return l?{id:p.id,name:p.feature.name,key:p.feature.key,getBucket:()=>({id:p.id,bucket:l.bucket}),isResolved:!0}:{id:p.id,name:p.feature.name,key:p.feature.key,getBucket:async()=>await a(p.feature),isResolved:!1}}));g.sample({clock:a.doneData,source:{resolvedFeatures:r},filter:({resolvedFeatures:c},{id:d,key:p})=>!c.some(y=>y.id===d&&y.key===p),fn:(c,d)=>d,target:t.eventBus.prepend(c=>({type:"feature_decide",feature:c}))}),g.sample({clock:[u.doneData,a.doneData],source:r,fn:(c,d)=>!d||c.some(l=>l.id===d.id&&l.key===d.key)?c:[...c,d],target:r});function k(c){return f.map(d=>d.find(p=>p.id===c))}function b(c){return e.map(d=>d[c],{skipVoid:!1})}function m(c){const d=g.createStore(async()=>{},{skipVoid:!1}),p=g.createEffect(async()=>{const l=k(c).getState();if(l)return async()=>(await l.getBucket()).bucket});return g.sample({source:r,filter:l=>l.some(y=>y.id===c),target:p}),g.sample({clock:p.doneData,filter:l=>l!==void 0,target:d}),p(),d}return{register:i,getById:k,getByName:b,listStore:f,getEvokableFeature:m}});function ye(t){return h.invoke(me,t)}const he=(t,e,r)=>{r.register(t,e)},j=g.createDomain("history");function $(t,e){return{id:_.generateId(`history-entry-${Date.now()}-${Math.random()}}`),node:e,at:Date.now(),experienceId:t}}const Se=h.createFactory(()=>{const t=j.store({entries:[]}),e=j.event(),r=j.event(),n=j.event(),i=j.event();t.on(e,(o,s)=>({entries:[...o.entries,$(s.experienceId,s.node)]})),t.on(r,(o,s)=>({entries:[...o.entries.slice(0,-1),$(s.experienceId,s.node)]})),t.on(i,(o,s)=>s);function u(o,s){const a={lastStepIndex:-1,secondLastStepIndex:-1};for(let f=o.length-1;f>=0;f--){const k=o[f],b=k?.node;if(!(!b||!I.isStepNode(b))&&!(s&&k?.experienceId!==s))if(a.lastStepIndex===-1)a.lastStepIndex=f;else{a.secondLastStepIndex=f;break}}return a}return t.on(n,(o,s)=>{const{secondLastStepIndex:a}=u(o.entries,s.experienceId),f=a!==-1?o.entries.slice(0,a+1):o.entries;return{...o,entries:f}}),{push:e,replace:r,back:n,restore:i,entriesStore:t.map(o=>o.entries)}});function ke(){return h.invoke(Se)}const ve=()=>g.createEvent(),we=g.createDomain("field"),Ie=h.createFactory(()=>{const t=we.store({}),e=g.createApi(t,{register(s,a){return{...s,[a.field.id]:a.field}}});function r(s){e.register({field:s})}function n(s,a){const f=u(s).getState();if(!f)return;const k=Object.assign({},f,{...a});e.register({field:{...k}})}const i=t.map(s=>Object.values(s));function u(s){return t.map(a=>a[s]||null)}function o(s){return t.map(a=>Object.values(a).find(f=>f.name===s)||null)}return{register:r,update:n,getById:u,listStore:i,getByName:o}});function be(){return h.invoke(Ie)}const Fe=(t,e)=>{e.register(t)},Ee=g.createDomain("action"),xe=h.createFactory(()=>{const t=Ee.store({}),e=g.createApi(t,{register(o,s){return{...o,[s.name]:{name:s.name,action:s.action}}}});function r(o,s){e.register({name:o,action:s})}const n=t.map(o=>Object.values(o));function i(o){return t.map(s=>s[o],{skipVoid:!1})}function u(o){return t.map(s=>{const a=s[o];return a?a.action:void 0},{skipVoid:!1})}return{register:r,getByName:i,listStore:n,getEvokableAction:u}});function je(){return h.invoke(xe)}const Re=(t,e,r)=>{r.register(t,e)};function O(t){return typeof t>"u"||t===null||t===""||Array.isArray(t)&&!t.length}const Ae=g.createDomain("response"),Pe=h.createFactory(({client:t})=>{const e=Ae.store({}),r=g.createEvent(),n=g.createEvent(),i=g.createApi(e,{register(m,c){return{...m,[c.fieldId]:c.response}},registerBatch(m,c){return{...m,...c}},clear(m,c){const{[c]:d,...p}=m;return p},clearAll(){return{}}});function u(m,c){if(typeof m=="string"){if(c===void 0)throw new Error("Response is required when registering a single field");i.register({fieldId:m,response:c})}else i.registerBatch(m)}async function o(m){const c=[];return await Promise.allSettled(Object.entries(m).map(async([d,p])=>{let l=p;const y=t.fields.getById(d).getState();if(!y){c.push({fieldId:d,userMessage:`Field '${d}' not found`,systemMessage:`No field with ID '${d}' exists. Available field IDs are: ${Object.keys(t.fields.listStore.getState()).join(",")}.`,value:l});return}if(y.multiple&&(typeof l=="string"||typeof l=="number"||typeof l=="boolean")&&(l=[l]),y.validation&&!q.isEmpty(y.validation)&&!O(l)){const w=await I.evaluateRuleLogic(t,y.validation,{$input:l});if(typeof w=="string"){c.push({fieldId:d,userMessage:w,systemMessage:`Field validation resulted in an error: ${w}.`,value:l});return}if(w===!1){c.push({fieldId:d,userMessage:"This field is invalid",systemMessage:"Field validation resulted in an unspecified error.",value:l});return}}if(y.required&&O(l)){c.push({fieldId:d,userMessage:"This field is required",systemMessage:"Field is required.",value:l});return}if(!y.multiple&&Array.isArray(l)&&l.length>1){c.push({fieldId:d,userMessage:"This field expects a single response",systemMessage:"Field expects a single response.",value:l});return}if(y.options){const w=y.options.map(x=>x.value),E=Array.isArray(l)?l:[l];Array.isArray(l)&&(E.every(x=>w.includes(x))||c.push({fieldId:d,userMessage:"This field expects a valid option",systemMessage:`Field expects a valid option. Valid options are: ${w.join(", ")}`,value:l}))}})),{responsesToCommit:m,validationErrors:c}}async function s(m){const{responsesToCommit:c,validationErrors:d}=await o(m);return d.length?{errors:d}:(i.registerBatch(c),{errors:[]})}const a=e.map(m=>m),f=e.map(m=>Object.keys(m).map(d=>({fieldId:d,value:m[d]})));function k(m){const c=t.fields.getById(m),d=e.map(p=>p[m]||null);return g.combine({f:c,r:d},({f:p,r:l})=>l||(p?.defaultValue?p.defaultValue:null))}function b(m){const c=t.fields.getByName(m);return g.combine({f:c,s:e},({f:d,s:p})=>{const l=d&&p[d.id]||null;return l||(d?.defaultValue?d.defaultValue:null)})}return g.sample({clock:r,target:i.clearAll}),g.sample({clock:n,target:i.clear}),{register:u,clearAll:r,clear:n,commit:s,getResponsesToCommit:o,listStore:f,getAllStore:a,getByFieldId:k,getByFieldName:b}});function Be(t){return h.invoke(Pe,t)}const De=()=>"0.0.38-next.2";function Ce(){if(S.supportsDocument()){const t=[document.currentScript,document.getElementById("picked_script"),document.getElementById("picked"),document.getElementById("cvly"),document.getElementById("cvly-x")];for(const e of t)if(e?.dataset.api)return e.dataset.api}return"https://api.picked.app"}function $e(){if(!S.supportsWindow())return{};const t=new URLSearchParams(window.location.search),e={},r=new Set;for(const[i]of t.entries())i.startsWith("picked-")&&r.add(i);for(const i of r){const u=i.replace("picked-","");e[u]=t.getAll(i)}const n=v.createStorageKey("s");if(r.size>0)v.sessionStore.set(n,e);else{const i=v.sessionStore.get(n);if(i)return i.json()||{}}return e}function Oe(){if(S.supportsCryptoRandomUUID())return crypto.randomUUID();const t=Date.now().toString(36),e=Math.random().toString(36).substring(2,15),r=Math.random().toString(36).substring(2,15),n=Math.random().toString(36).substring(2,15);return`${t}-${e}-${r}-${n}`}const ze=v.createStorageKey("session","global"),Ue=()=>{const t=v.localStore.get(ze);let e;t.isSet()&&(e=t.json());const r=i=>t.set({id:i.id,isUser:i.isUser,identifiers:i.identifiers}),n={id:e?.id??Oe(),isUser:e?.isUser??void 0,identifiers:e?.identifiers??void 0,setIsUser(i){this.isUser=i,r(this)},setIdentifier(i,u){this.identifiers={...this.identifiers,[i]:u},r(this)},removeIdentifier(i){this.identifiers&&(this.identifiers=Object.fromEntries(Object.entries(this.identifiers).filter(([u])=>u!==i)),this.identifiers=Object.keys(this.identifiers).length?this.identifiers:void 0,r(this))}};return r(n),n},Le=()=>S.supportsLocalStorage()?Ue():null;function V(){if(S.supportsWindow())return globalThis.window.pickedConfig}function Ve(){if(!S.supportsWindow())return;const t=V(),e=t?.organizationId,r=t?.projectId;return e&&r?{organizationId:e,projectId:r}:void 0}function Me(){if(!S.supportsDocument())return;const t=document.getElementById("picked_script")||document.querySelector("script#picked")||document.getElementById("cvly");if(!t)return;const e=t.dataset.organizationid||t.getAttribute("organization-id"),r=t.dataset.projectid||t.getAttribute("project-id");return e&&r?{organizationId:e,projectId:r}:void 0}function Ne(t){const{organizationId:e,projectId:r}=t;if(e&&r)return{organizationId:e,projectId:r};const n=Ve();if(n)return n;const i=Me();if(i)return i;throw new Error(`organizationId and projectId are required. You can provide them via one of:
2
2
  (1) createClient({ organizationId, projectId }) options;
3
3
  (2) window.pickedConfig = { organizationId, projectId };
4
- (3) a <script> tag with id 'picked_script', 'picked', or 'cvly' that includes data-organizationid/data-projectid (or organization-id/project-id) attributes.`)}function A(t){return t==null||t===""||Number.isNaN(t)}const Te={default:(t,e)=>A(t)?String(e??""):String(t),append:(t,e)=>e&&!A(t)?`${t} ${e}`:t,prepend:(t,e)=>e&&!A(t)?`${e} ${t}`:t,upper:t=>typeof t=="string"?t.toUpperCase():t,lower:t=>typeof t=="string"?t.toLowerCase():t,capitalize:t=>typeof t=="string"?t.charAt(0).toUpperCase()+t.slice(1):t,list:t=>{if(!t||typeof t!="object")return t;const e=new Intl.ListFormat("en",{style:"long",type:"conjunction"});if(Array.isArray(t))return e.format(t.map(String));if(t instanceof Map){const r=Array.from(t.entries()).map(([n,i])=>`${n}: ${i}`);return e.format(r)}return t instanceof Set?e.format(Array.from(t).map(String)):t}};function _e(t){return typeof t=="object"&&t!==null}function qe(t,e){let r=e;for(const n of t.split("."))if(_e(r)&&n in r)r=r[n];else return;return typeof r=="function"?r():r}function Ke(t,e){const r=t.split("|").map(u=>u.trim()),n=r.shift()??"";let i=qe(n,e);for(const u of r){const[o,...s]=u.split(":"),a=o?.trim()??"",f=s.join(":").trim().replaceAll(/(?:^['"]|['"]$)/g,""),k=Te[a];k&&(i=k(i,f))}return A(i)?"":typeof i=="object"?JSON.stringify(i):String(i)}function We(t,e){let r="",n=0;for(;n<t.length;)if(t[n]==="{"&&t[n+1]==="{"){n+=2;let i="";for(;n<t.length;){if(t[n]==="}"&&t[n+1]==="}"){n+=2;break}i+=t[n++]}r+=Ke(i.trim(),e)}else r+=t[n++];return r}class M{static logger=F.logger;options;isReady=!1;project;plugins={};eventBus=ve();organizationId;projectId;apiUrl;session;precondition;condition;searchParams=$e();history=ke();components=re({client:this});experienceInstances=I.createExperienceInstanceIndex({client:this});experiences=G({client:this});frameworks=ie({client:this});predicates=ge({client:this});features=ye({client:this});responses=Be({client:this});fields=be();actions=xe();constructor(e){F.logger("info","Picked client initializing.");const{organizationId:r,projectId:n}=Ne(e);this.organizationId=r,this.projectId=n,this.options=Object.freeze(e),this.apiUrl=e.apiUrl||Ce(),this.session=Le(),this.setupPlugins(),this.setupFeatures(),this.setupPredicates(),this.setupActions(),this.precondition=e.precondition,this.condition=e.condition,this.eventBus({type:"load",version:De()}),F.logger("info","Picked client initialized.")}start(){de(this),(async()=>{if(!S.supportsDocument())return;let r;typeof this.precondition>"u"?r=!0:typeof this.precondition=="boolean"?r=this.precondition:r=await I.evaluateRuleLogic(this,this.precondition)===!0;let n;r&&(this.condition===void 0?n=!0:typeof this.condition=="boolean"?n=this.condition:n=await I.evaluateRuleLogic(this,this.condition)===!0);const i=r&&n===!0;if(typeof n=="boolean"&&this.session){const u=n;this.session.setIsUser(u),this.eventBus({type:"user_decide",value:u})}this.eventBus({type:"initialize"}),document.body&&i&&B(this),await I.domInteractive(),i&&B(this),this.eventBus({type:"ready"}),this.isReady=!0,this.session&&this.eventBus({type:"session",...this.session})})()}registerFramework(e){oe(e,this.frameworks)}registerComponent(e,r){D(e,r,this.components)}registerPlugin(e){Q(this,e,this.plugins)}registerFeature(e,r){he(e,r,this.features)}registerPredicate(e,r){fe(e,r,this.predicates)}registerField(e){Fe(e,this.fields)}registerAction(e,r){Re(e,r,this.actions)}registerExperience(e){e.component&&D(`experience:${e.id}`,e.component,this.components),Y(e,this.experiences)}getStateSnapshot(){return L(this)}async launchExperienceById(e){const r=this.experiences.getById(e).getState();if(!r){F.logger("warn",`Experience with id '${e}' not found.`);return}U(this,r)}setupPlugins(){this.options.plugins?.forEach(e=>{if(Array.isArray(e)){e.forEach(n=>{this.registerPlugin(n)});return}const r=typeof e=="function"?e():e;if(Array.isArray(r)){r.forEach(n=>this.registerPlugin(n));return}this.registerPlugin(r)})}setupFeatures(){const e=this.options.features;e&&(Object.entries(e).forEach(([r,n])=>{const i=typeof n=="function"?n():n;this.registerFeature(r,i)}),this.searchParams.feature&&this.searchParams.feature.forEach(r=>{try{const[n,i]=r.split(":");if(!n||!i)return;let u=i;u==="true"&&(u=!0),u==="false"&&(u=!1),this.registerFeature(n,{key:`${u}`,name:n,decide:()=>u,storage:"session"})}catch{}}))}setupPredicates(){const e=this.options.predicates;e&&Object.entries(e).forEach(([r,n])=>{if(typeof n!="function"){F.logger("warn",`Predicate "${r}" is not a function.`);return}this.registerPredicate(r,n)})}setupActions(){const e=this.options.actions;e&&Object.entries(e).forEach(([r,n])=>{if(typeof n!="function"){F.logger("warn",`Action "${r}" is not a function.`);return}this.registerAction(r,n)})}getPluginConfig(e){return this.plugins[e]??{}}renderString=(e,r)=>{const n=this.responses.listStore.getState().reduce((i,u)=>(i[u.fieldId]=u.value,i),{});return We(e,{...r,responses:n})}}function N(t){return t.options?.some(e=>"condition"in e)??!1}function He(t){return t.some(e=>e.condition||N(e))}async function Ge(t,e){return e.length===0||!He(e)?e:(await Promise.all(e.map(async n=>{if(!(n.condition?await I.evaluateRuleLogic(t,n.condition):!0))return null;if(!n.options||!N(n))return n;const o=(await Promise.all(n.options.map(async a=>a.condition?await I.evaluateRuleLogic(t,a.condition)?a:null:a))).filter(a=>a!==null);return o.length===n.options.length?n:o.length===0?null:{...n,options:o}}))).filter(n=>n!==null)}const Ye=t=>{const e=new M(t);return S.bindClient(e),e};exports.evaluateRuleLogic=I.evaluateRuleLogic;exports.isPickedRoot=I.isPickedRoot;exports.createStorageKey=v.createStorageKey;exports.localStore=v.localStore;exports.sessionStore=v.sessionStore;exports.subscribe=v.subscribe;exports.supportsCookies=S.supportsCookies;exports.supportsCryptoRandomUUID=S.supportsCryptoRandomUUID;exports.supportsDocument=S.supportsDocument;exports.supportsHistory=S.supportsHistory;exports.supportsIntersectionObserver=S.supportsIntersectionObserver;exports.supportsLocalStorage=S.supportsLocalStorage;exports.supportsLocation=S.supportsLocation;exports.supportsSessionStorage=S.supportsSessionStorage;exports.supportsShadowRoot=S.supportsShadowRoot;exports.supportsWebComponents=S.supportsWebComponents;exports.supportsWindow=S.supportsWindow;exports.Picked=M;exports.createClient=Ye;exports.getPickedConfig=V;exports.getStepFields=Ge;
4
+ (3) a <script> tag with id 'picked_script', 'picked', or 'cvly' that includes data-organizationid/data-projectid (or organization-id/project-id) attributes.`)}function A(t){return t==null||t===""||Number.isNaN(t)}const Te={default:(t,e)=>A(t)?String(e??""):String(t),append:(t,e)=>e&&!A(t)?`${t} ${e}`:t,prepend:(t,e)=>e&&!A(t)?`${e} ${t}`:t,upper:t=>typeof t=="string"?t.toUpperCase():t,lower:t=>typeof t=="string"?t.toLowerCase():t,capitalize:t=>typeof t=="string"?t.charAt(0).toUpperCase()+t.slice(1):t,list:t=>{if(!t||typeof t!="object")return t;const e=new Intl.ListFormat("en",{style:"long",type:"conjunction"});if(Array.isArray(t))return e.format(t.map(String));if(t instanceof Map){const r=Array.from(t.entries()).map(([n,i])=>`${n}: ${i}`);return e.format(r)}return t instanceof Set?e.format(Array.from(t).map(String)):t}};function _e(t){return typeof t=="object"&&t!==null}function qe(t,e){let r=e;for(const n of t.split("."))if(_e(r)&&n in r)r=r[n];else return;return typeof r=="function"?r():r}function Ke(t,e){const r=t.split("|").map(u=>u.trim()),n=r.shift()??"";let i=qe(n,e);for(const u of r){const[o,...s]=u.split(":"),a=o?.trim()??"",f=s.join(":").trim().replaceAll(/(?:^['"]|['"]$)/g,""),k=Te[a];k&&(i=k(i,f))}return A(i)?"":typeof i=="object"?JSON.stringify(i):String(i)}function We(t,e){let r="",n=0;for(;n<t.length;)if(t[n]==="{"&&t[n+1]==="{"){n+=2;let i="";for(;n<t.length;){if(t[n]==="}"&&t[n+1]==="}"){n+=2;break}i+=t[n++]}r+=Ke(i.trim(),e)}else r+=t[n++];return r}class M{static logger=F.logger;options;isReady=!1;project;plugins={};eventBus=ve();organizationId;projectId;apiUrl;session;precondition;condition;searchParams=$e();history=ke();components=re({client:this});experienceInstances=I.createExperienceInstanceIndex({client:this});experiences=G({client:this});frameworks=ie({client:this});predicates=ge({client:this});features=ye({client:this});responses=Be({client:this});fields=be();actions=je();constructor(e){F.logger("info","Picked client initializing.");const{organizationId:r,projectId:n}=Ne(e);this.organizationId=r,this.projectId=n,this.options=Object.freeze(e),this.apiUrl=e.apiUrl||Ce(),this.session=Le(),this.setupPlugins(),this.setupFeatures(),this.setupPredicates(),this.setupActions(),this.precondition=e.precondition,this.condition=e.condition,this.eventBus({type:"load",version:De()}),F.logger("info","Picked client initialized.")}start(){de(this),(async()=>{if(!S.supportsDocument())return;let r;typeof this.precondition>"u"?r=!0:typeof this.precondition=="boolean"?r=this.precondition:r=await I.evaluateRuleLogic(this,this.precondition)===!0;let n;r&&(this.condition===void 0?n=!0:typeof this.condition=="boolean"?n=this.condition:n=await I.evaluateRuleLogic(this,this.condition)===!0);const i=r&&n===!0;if(typeof n=="boolean"&&this.session){const u=n;this.session.setIsUser(u),this.eventBus({type:"user_decide",value:u})}this.eventBus({type:"initialize"}),document.body&&i&&B(this),await I.domInteractive(),i&&B(this),this.eventBus({type:"ready"}),this.isReady=!0,this.session&&this.eventBus({type:"session",...this.session})})()}registerFramework(e){oe(e,this.frameworks)}registerComponent(e,r){D(e,r,this.components)}registerPlugin(e){Q(this,e,this.plugins)}registerFeature(e,r){he(e,r,this.features)}registerPredicate(e,r){fe(e,r,this.predicates)}registerField(e){Fe(e,this.fields)}registerAction(e,r){Re(e,r,this.actions)}registerExperience(e){e.component&&D(`experience:${e.id}`,e.component,this.components),Y(e,this.experiences)}getStateSnapshot(){return L(this)}async launchExperienceById(e){const r=this.experiences.getById(e).getState();if(!r){F.logger("warn",`Experience with id '${e}' not found.`);return}U(this,r)}setupPlugins(){this.options.plugins?.forEach(e=>{if(Array.isArray(e)){e.forEach(n=>{this.registerPlugin(n)});return}const r=typeof e=="function"?e():e;if(Array.isArray(r)){r.forEach(n=>this.registerPlugin(n));return}this.registerPlugin(r)})}setupFeatures(){const e=this.options.features;e&&(Object.entries(e).forEach(([r,n])=>{const i=typeof n=="function"?n():n;this.registerFeature(r,i)}),this.searchParams.feature&&this.searchParams.feature.forEach(r=>{try{const[n,i]=r.split(":");if(!n||!i)return;let u=i;u==="true"&&(u=!0),u==="false"&&(u=!1),this.registerFeature(n,{key:`${u}`,name:n,decide:()=>u,storage:"session"})}catch{}}))}setupPredicates(){const e=this.options.predicates;e&&Object.entries(e).forEach(([r,n])=>{if(typeof n!="function"){F.logger("warn",`Predicate "${r}" is not a function.`);return}this.registerPredicate(r,n)})}setupActions(){const e=this.options.actions;e&&Object.entries(e).forEach(([r,n])=>{if(typeof n!="function"){F.logger("warn",`Action "${r}" is not a function.`);return}this.registerAction(r,n)})}getPluginConfig(e){return this.plugins[e]??{}}renderString=(e,r)=>{const n=this.responses.listStore.getState().reduce((i,u)=>(i[u.fieldId]=u.value,i),{});return We(e,{...r,responses:n})}}function N(t){return t.options?.some(e=>"condition"in e)??!1}function He(t){return t.some(e=>e.condition||N(e))}async function Ge(t,e){return e.length===0||!He(e)?e:(await Promise.all(e.map(async n=>{if(!(n.condition?await I.evaluateRuleLogic(t,n.condition):!0))return null;if(!n.options||!N(n))return n;const o=(await Promise.all(n.options.map(async a=>a.condition?await I.evaluateRuleLogic(t,a.condition)?a:null:a))).filter(a=>a!==null);return o.length===n.options.length?n:o.length===0?null:{...n,options:o}}))).filter(n=>n!==null)}const Ye=t=>{const e=new M(t);return S.bindClient(e),e};exports.evaluateRuleLogic=I.evaluateRuleLogic;exports.isPickedRoot=I.isPickedRoot;exports.createStorageKey=v.createStorageKey;exports.localStore=v.localStore;exports.sessionStore=v.sessionStore;exports.subscribe=v.subscribe;exports.supportsCookies=S.supportsCookies;exports.supportsCryptoRandomUUID=S.supportsCryptoRandomUUID;exports.supportsDocument=S.supportsDocument;exports.supportsHistory=S.supportsHistory;exports.supportsIntersectionObserver=S.supportsIntersectionObserver;exports.supportsLocalStorage=S.supportsLocalStorage;exports.supportsLocation=S.supportsLocation;exports.supportsSessionStorage=S.supportsSessionStorage;exports.supportsShadowRoot=S.supportsShadowRoot;exports.supportsWebComponents=S.supportsWebComponents;exports.supportsWindow=S.supportsWindow;exports.Picked=M;exports.createClient=Ye;exports.getPickedConfig=V;exports.getStepFields=Ge;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("effector"),n=require("../../../storage-YlR83AWP.cjs"),g=require("../../../logger-BsmHUUw1.cjs"),S=({storage:i="local"}={})=>({name:"experience-browser-storage-plugin",setup:s=>{const c=i==="local"?n.localStore:n.sessionStore,a=r.createEffect(async e=>{if(!e){g.logger("warn","No experience instance provided to loadExperienceVisiblityFx.");return}const t=n.createStorageKey("open-close","experience",e),o=c.get(t).boolean();e.setOpen(o??e.isOpenStore.getState())});r.sample({source:s.eventBus,filter:e=>e.type==="experience_initialize"&&"experienceInstance"in e,fn:e=>e.experienceInstance,target:a});const l=r.createEffect(async e=>{const t=n.createStorageKey("open-close","experience",e),o=e.isOpenStore.getState();c.set(t,o)}),p=e=>r.sample({source:e.isOpenStore,fn:()=>e,target:l});s.experienceInstances.listStore.watch(e=>{e.forEach(t=>p(t))})}});exports.experienceBrowserStoragePlugin=S;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("effector"),n=require("../../../storage-Be5xWNPC.cjs"),g=require("../../../logger-BsmHUUw1.cjs"),S=({storage:i="local"}={})=>({name:"experience-browser-storage-plugin",setup:s=>{const c=i==="local"?n.localStore:n.sessionStore,a=r.createEffect(async e=>{if(!e){g.logger("warn","No experience instance provided to loadExperienceVisiblityFx.");return}const t=n.createStorageKey("open-close","experience",e),o=c.get(t).boolean();e.setOpen(o??e.isOpenStore.getState())});r.sample({source:s.eventBus,filter:e=>e.type==="experience_initialize"&&"experienceInstance"in e,fn:e=>e.experienceInstance,target:a});const l=r.createEffect(async e=>{const t=n.createStorageKey("open-close","experience",e),o=e.isOpenStore.getState();c.set(t,o)}),p=e=>r.sample({source:e.isOpenStore,fn:()=>e,target:l});s.experienceInstances.listStore.watch(e=>{e.forEach(t=>p(t))})}});exports.experienceBrowserStoragePlugin=S;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("effector"),o=require("../../../storage-YlR83AWP.cjs"),a=o.createStorageKey("history","global"),l=({storage:i="local"}={})=>({name:"history-browser-storage-plugin",setup:r=>{const s=i==="local"?o.localStore:o.sessionStore,n=t.createEffect(async()=>{const e=s.get(a).json();e&&r.history.restore({entries:e})}),c=t.createEffect(async e=>{s.set(a,e)});t.sample({source:r.eventBus,filter:e=>e.type==="load",target:n}),t.sample({source:r.history.entriesStore,target:c})}});exports.historyBrowserStoragePlugin=l;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("effector"),o=require("../../../storage-Be5xWNPC.cjs"),a=o.createStorageKey("history","global"),l=({storage:i="local"}={})=>({name:"history-browser-storage-plugin",setup:r=>{const s=i==="local"?o.localStore:o.sessionStore,n=t.createEffect(async()=>{const e=s.get(a).json();e&&r.history.restore({entries:e})}),c=t.createEffect(async e=>{s.set(a,e)});t.sample({source:r.eventBus,filter:e=>e.type==="load",target:n}),t.sample({source:r.history.entriesStore,target:c})}});exports.historyBrowserStoragePlugin=l;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("effector"),c=require("../../../storage-YlR83AWP.cjs"),p=c.createStorageKey("responses","global"),u=(n,e)=>{const o={};return Object.entries(n).forEach(([r,l])=>{!e.find(a=>a.id===r)?.policies?.doNotStoreValue&&(o[r]=l)}),o},g=({storage:n="local"}={})=>({name:"responses-browser-storage-plugin",setup:e=>{const o=n==="local"?c.localStore:c.sessionStore,r=t.createEffect(async()=>{const s=o.get(p).json();if(!s)return null;e.responses.register(s)}),l=t.attach({source:{responses:e.responses.getAllStore,fields:e.fields.listStore},effect:({responses:s,fields:i})=>{const a=u(s,i);o.set(p,a)}});t.sample({source:e.eventBus,filter:s=>s.type==="load",target:r}),t.sample({source:e.responses.getAllStore,target:l})}});exports.responsesBrowserStoragePlugin=g;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("effector"),c=require("../../../storage-Be5xWNPC.cjs"),p=c.createStorageKey("responses","global"),u=(n,e)=>{const o={};return Object.entries(n).forEach(([r,l])=>{!e.find(a=>a.id===r)?.policies?.doNotStoreValue&&(o[r]=l)}),o},g=({storage:n="local"}={})=>({name:"responses-browser-storage-plugin",setup:e=>{const o=n==="local"?c.localStore:c.sessionStore,r=t.createEffect(async()=>{const s=o.get(p).json();if(!s)return null;e.responses.register(s)}),l=t.attach({source:{responses:e.responses.getAllStore,fields:e.fields.listStore},effect:({responses:s,fields:i})=>{const a=u(s,i);o.set(p,a)}});t.sample({source:e.eventBus,filter:s=>s.type==="load",target:r}),t.sample({source:e.responses.getAllStore,target:l})}});exports.responsesBrowserStoragePlugin=g;
package/dist/esm/index.js CHANGED
@@ -3,8 +3,8 @@ import { createFactory as w, invoke as v } from "@withease/factories";
3
3
  import { g as q, t as Z, c as ee, i as te, e as j, a as re, b as ne, d as se } from "../experience-instance-CwXYJkRx.js";
4
4
  import { f as jt } from "../experience-instance-CwXYJkRx.js";
5
5
  import { l as k } from "../logger-C9a75KZn.js";
6
- import { c as A, l as C, s as z } from "../storage-BLmAhfhl.js";
7
- import { a as At } from "../storage-BLmAhfhl.js";
6
+ import { c as A, l as C, s as z } from "../storage-Co_LbKr_.js";
7
+ import { a as At } from "../storage-Co_LbKr_.js";
8
8
  import { g as ie } from "../id-BW-g3y32.js";
9
9
  import { i as oe } from "../object-JwZ58NOH.js";
10
10
  import { s as U, a as V, b as ae, c as ce, d as ue } from "../supports-COb-sl36.js";
@@ -699,7 +699,7 @@ const We = b("response"), Ye = w(({ client: t }) => {
699
699
  function Je(t) {
700
700
  return v(Ye, t);
701
701
  }
702
- const Qe = () => "0.0.37";
702
+ const Qe = () => "0.0.38-next.2";
703
703
  function Xe() {
704
704
  if (U()) {
705
705
  const t = [
@@ -1,5 +1,5 @@
1
1
  import { createEffect as r, sample as i } from "effector";
2
- import { c, l as g, s as S } from "../../../storage-BLmAhfhl.js";
2
+ import { c, l as g, s as S } from "../../../storage-Co_LbKr_.js";
3
3
  import { l as f } from "../../../logger-C9a75KZn.js";
4
4
  const y = ({
5
5
  storage: a = "local"
@@ -1,5 +1,5 @@
1
1
  import { createEffect as s, sample as r } from "effector";
2
- import { c as l, l as y, s as g } from "../../../storage-BLmAhfhl.js";
2
+ import { c as l, l as y, s as g } from "../../../storage-Co_LbKr_.js";
3
3
  const a = l("history", "global"), f = ({
4
4
  storage: i = "local"
5
5
  } = {}) => ({
@@ -1,5 +1,5 @@
1
1
  import { createEffect as i, attach as f, sample as c } from "effector";
2
- import { c as u, l as g, s as d } from "../../../storage-BLmAhfhl.js";
2
+ import { c as u, l as g, s as d } from "../../../storage-Co_LbKr_.js";
3
3
  const p = u("responses", "global"), S = (r, s) => {
4
4
  const o = {};
5
5
  return Object.entries(r).forEach(([t, n]) => {
@@ -0,0 +1 @@
1
+ "use strict";const p=e=>btoa([...e].map(t=>String.fromCharCode(t.charCodeAt(0)^7)).join("")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"");function w(e,t="global",o){let r="pckd";if(t==="experience"){if(!o)throw new Error("Experience instance is required to scope storage to an experience");r=`${r}:${o.experienceId}`}return{_:`${r}:${p(e)}`,scope:t}}const a=new Map;function m(e,t){const o=a.get(e._);o&&o.forEach(r=>r(e,t))}function S(e,t,o,r){const i=o==="local"?localStorage:sessionStorage,c=typeof t!="string"?JSON.stringify(t):t;if(i.setItem(e._,c),typeof r=="number"){const s=new Date(Date.now()+r).toISOString();i.setItem(`${e._}:expires-at`,s)}m(e,o)}function b(e,t){const o=t==="local"?localStorage:sessionStorage;o.removeItem(e._),o.removeItem(`${e._}:expires-at`),m(e,t)}function f(e,t,o,r){const i=t==="local"?localStorage:sessionStorage;function c(s){s.storageArea===i&&s.key===e._&&r(o(e))}function l(s,n){n===t&&r(o(s))}return window.addEventListener("storage",c),a.has(e._)||a.set(e._,new Set),a.get(e._).add(l),function(){window.removeEventListener("storage",c);const n=a.get(e._);n&&(n.delete(l),n.size===0&&a.delete(e._))}}function g(e,t){const o=t==="local"?localStorage:sessionStorage,r=o.getItem(e._),i=o.getItem(`${e._}:expires-at`),c=(n,u)=>S(e,n,t,u),l=()=>b(e,t),s=n=>f(e,t,u=>g(u,t),n);if(i){const n=new Date,u=new Date(i);if(n>u)return b(e,t),{isSet:()=>!1,text:()=>null,json:()=>null,boolean:()=>null,set:c,remove:l,subscribe:s}}return{isSet(){return r!==null},text(){return r},json(){return r?JSON.parse(r):null},boolean(){return r?r==="true":null},set:c,remove:l,subscribe:s}}const d={get(e){return g(e,"session")},set(e,t,o){S(e,t,"session",o)},remove(e){b(e,"session")},subscribe(e,t){return f(e,"session",this.get,t)}},_={get(e){return g(e,"local")},set(e,t,o){S(e,t,"local",o)},remove(e){b(e,"local")},subscribe(e,t){return f(e,"local",this.get,t)}};exports.createStorageKey=w;exports.localStore=_;exports.sessionStore=d;exports.subscribe=f;
@@ -0,0 +1,239 @@
1
+ const m = (e) => btoa([...e].map((t) => String.fromCharCode(t.charCodeAt(0) ^ 7)).join("")).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2
+ function w(e, t = "global", o) {
3
+ let r = "pckd";
4
+ if (t === "experience") {
5
+ if (!o)
6
+ throw new Error("Experience instance is required to scope storage to an experience");
7
+ r = `${r}:${o.experienceId}`;
8
+ }
9
+ return { _: `${r}:${m(e)}`, scope: t };
10
+ }
11
+ const l = /* @__PURE__ */ new Map();
12
+ function p(e, t) {
13
+ const o = l.get(e._);
14
+ o && o.forEach((r) => r(e, t));
15
+ }
16
+ function b(e, t, o, r) {
17
+ const i = o === "local" ? localStorage : sessionStorage, c = typeof t != "string" ? JSON.stringify(t) : t;
18
+ if (i.setItem(e._, c), typeof r == "number") {
19
+ const s = new Date(Date.now() + r).toISOString();
20
+ i.setItem(`${e._}:expires-at`, s);
21
+ }
22
+ p(e, o);
23
+ }
24
+ function f(e, t) {
25
+ const o = t === "local" ? localStorage : sessionStorage;
26
+ o.removeItem(e._), o.removeItem(`${e._}:expires-at`), p(e, t);
27
+ }
28
+ function S(e, t, o, r) {
29
+ const i = t === "local" ? localStorage : sessionStorage;
30
+ function c(s) {
31
+ s.storageArea === i && s.key === e._ && r(o(e));
32
+ }
33
+ function a(s, n) {
34
+ n === t && r(o(s));
35
+ }
36
+ return window.addEventListener("storage", c), l.has(e._) || l.set(e._, /* @__PURE__ */ new Set()), l.get(e._).add(a), function() {
37
+ window.removeEventListener("storage", c);
38
+ const n = l.get(e._);
39
+ n && (n.delete(a), n.size === 0 && l.delete(e._));
40
+ };
41
+ }
42
+ function g(e, t) {
43
+ const o = t === "local" ? localStorage : sessionStorage, r = o.getItem(e._), i = o.getItem(`${e._}:expires-at`), c = (n, u) => b(e, n, t, u), a = () => f(e, t), s = (n) => S(e, t, (u) => g(u, t), n);
44
+ if (i) {
45
+ const n = /* @__PURE__ */ new Date(), u = new Date(i);
46
+ if (n > u)
47
+ return f(e, t), {
48
+ isSet: () => !1,
49
+ text: () => null,
50
+ json: () => null,
51
+ boolean: () => null,
52
+ set: c,
53
+ remove: a,
54
+ subscribe: s
55
+ };
56
+ }
57
+ return {
58
+ isSet() {
59
+ return r !== null;
60
+ },
61
+ text() {
62
+ return r;
63
+ },
64
+ json() {
65
+ return r ? JSON.parse(r) : null;
66
+ },
67
+ boolean() {
68
+ return r ? r === "true" : null;
69
+ },
70
+ set: c,
71
+ remove: a,
72
+ subscribe: s
73
+ };
74
+ }
75
+ const d = {
76
+ /**
77
+ * Retrieves a storage item from sessionStorage.
78
+ *
79
+ * @template T - The type of the stored value
80
+ * @param key - The storage key
81
+ * @returns A StorageItem with methods to interact with the value
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * const key = createStorageKey('user')
86
+ * const item = sessionStore.get<User>(key)
87
+ * const user = item.json() // User | null
88
+ * ```
89
+ */
90
+ get(e) {
91
+ return g(e, "session");
92
+ },
93
+ /**
94
+ * Sets a value in sessionStorage with optional expiry.
95
+ *
96
+ * @param key - The storage key
97
+ * @param value - The value to store
98
+ * @param expiresIn - Optional expiry time in milliseconds from now
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * const key = createStorageKey('theme')
103
+ * // Set without expiry
104
+ * sessionStore.set(key, 'dark')
105
+ * // Set with 1 hour expiry
106
+ * sessionStore.set(key, 'dark', 60 * 60 * 1000)
107
+ * ```
108
+ */
109
+ set(e, t, o) {
110
+ b(e, t, "session", o);
111
+ },
112
+ /**
113
+ * Removes a value from sessionStorage, including expiry metadata.
114
+ *
115
+ * @param key - The storage key
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * const key = createStorageKey('temp-data')
120
+ * sessionStore.remove(key)
121
+ * ```
122
+ */
123
+ remove(e) {
124
+ f(e, "session");
125
+ },
126
+ /**
127
+ * Subscribes to storage changes for a key, both in the same tab and across browser tabs/windows.
128
+ * Callbacks are invoked when changes occur via sessionStore.set() or sessionStore.remove() in the same tab,
129
+ * and also when changes are made in other tabs/windows.
130
+ *
131
+ * @template T - The type of the stored value
132
+ * @param key - The storage key to watch
133
+ * @param callback - Function called when storage changes
134
+ * @returns Unsubscribe function to stop listening
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * const key = createStorageKey('notifications')
139
+ * const unsubscribe = sessionStore.subscribe<Notification[]>(key, (item) => {
140
+ * const notifications = item.json()
141
+ * console.log('Notifications updated:', notifications)
142
+ * })
143
+ *
144
+ * // Changes in same tab trigger callback
145
+ * sessionStore.set(key, [{ id: 1, message: 'New notification' }])
146
+ *
147
+ * // Later, stop listening
148
+ * unsubscribe()
149
+ * ```
150
+ */
151
+ subscribe(e, t) {
152
+ return S(e, "session", this.get, t);
153
+ }
154
+ }, _ = {
155
+ /**
156
+ * Retrieves a storage item from localStorage.
157
+ *
158
+ * @template T - The type of the stored value
159
+ * @param key - The storage key
160
+ * @returns A StorageItem with methods to interact with the value
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * const key = createStorageKey('settings')
165
+ * const item = localStore.get<Settings>(key)
166
+ * const settings = item.json() // Settings | null
167
+ * ```
168
+ */
169
+ get(e) {
170
+ return g(e, "local");
171
+ },
172
+ /**
173
+ * Sets a value in localStorage with optional expiry.
174
+ *
175
+ * @param key - The storage key
176
+ * @param value - The value to store
177
+ * @param expiresIn - Optional expiry time in milliseconds from now
178
+ *
179
+ * @example
180
+ * ```typescript
181
+ * const key = createStorageKey('auth-token')
182
+ * // Set without expiry
183
+ * localStore.set(key, 'token123')
184
+ * // Set with 24 hour expiry
185
+ * localStore.set(key, 'token123', 24 * 60 * 60 * 1000)
186
+ * ```
187
+ */
188
+ set(e, t, o) {
189
+ b(e, t, "local", o);
190
+ },
191
+ /**
192
+ * Removes a value from localStorage, including expiry metadata.
193
+ *
194
+ * @param key - The storage key
195
+ *
196
+ * @example
197
+ * ```typescript
198
+ * const key = createStorageKey('cached-data')
199
+ * localStore.remove(key)
200
+ * ```
201
+ */
202
+ remove(e) {
203
+ f(e, "local");
204
+ },
205
+ /**
206
+ * Subscribes to storage changes for a key, both in the same tab and across browser tabs/windows.
207
+ * Callbacks are invoked when changes occur via localStore.set() or localStore.remove() in the same tab,
208
+ * and also when changes are made in other tabs/windows.
209
+ *
210
+ * @template T - The type of the stored value
211
+ * @param key - The storage key to watch
212
+ * @param callback - Function called when storage changes
213
+ * @returns Unsubscribe function to stop listening
214
+ *
215
+ * @example
216
+ * ```typescript
217
+ * const key = createStorageKey('user-status')
218
+ * const unsubscribe = localStore.subscribe<UserStatus>(key, (item) => {
219
+ * const status = item.json()
220
+ * console.log('User status changed:', status)
221
+ * })
222
+ *
223
+ * // Changes in same tab trigger callback
224
+ * localStore.set(key, { online: true })
225
+ *
226
+ * // Later, stop listening
227
+ * unsubscribe()
228
+ * ```
229
+ */
230
+ subscribe(e, t) {
231
+ return S(e, "local", this.get, t);
232
+ }
233
+ };
234
+ export {
235
+ S as a,
236
+ w as c,
237
+ _ as l,
238
+ d as s
239
+ };
@@ -1,29 +1,385 @@
1
1
  import { ExperienceInstance } from '../entities/experience-instance/experience-instance';
2
+ /**
3
+ * Defines the scope of storage items.
4
+ * - 'global': Storage is shared across all experiences
5
+ * - 'experience': Storage is scoped to a specific experience instance
6
+ */
2
7
  export type StorageScope = 'global' | 'experience';
8
+ /**
9
+ * Represents a storage item with methods to read, write, and subscribe to changes.
10
+ * Provides type-safe access to browser storage (localStorage or sessionStorage).
11
+ *
12
+ * @template T - The type of the stored value
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const key = createStorageKey('user-preferences')
17
+ * const item = sessionStore.get<UserPrefs>(key)
18
+ *
19
+ * // Check if value exists
20
+ * if (item.isSet()) {
21
+ * const prefs = item.json() // UserPrefs | null
22
+ * }
23
+ *
24
+ * // Set value with expiry
25
+ * item.set({ theme: 'dark' }, 3600000) // Expires in 1 hour
26
+ *
27
+ * // Subscribe to changes
28
+ * const unsubscribe = item.subscribe((updatedItem) => {
29
+ * console.log('Updated:', updatedItem.json())
30
+ * })
31
+ * ```
32
+ */
3
33
  export interface StorageItem<T = unknown> {
34
+ /**
35
+ * Checks if a value is stored for this item.
36
+ *
37
+ * @returns `true` if a value exists, `false` otherwise
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * if (item.isSet()) {
42
+ * console.log('Value exists')
43
+ * }
44
+ * ```
45
+ */
4
46
  isSet: () => boolean;
47
+ /**
48
+ * Gets the stored value as a string.
49
+ *
50
+ * @returns The stored string value, or `null` if not set
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const name = item.text() // "John" or null
55
+ * ```
56
+ */
5
57
  text: () => string | null;
58
+ /**
59
+ * Gets the stored value as a parsed JSON object.
60
+ *
61
+ * @returns The parsed value of type T, or `null` if not set
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * const user = item.json<User>() // { name: "John", age: 30 } or null
66
+ * ```
67
+ */
6
68
  json: () => T | null;
69
+ /**
70
+ * Gets the stored value as a boolean.
71
+ *
72
+ * @returns `true` if value is "true", `false` if value is any other string, or `null` if not set
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * const isEnabled = item.boolean() // true, false, or null
77
+ * ```
78
+ */
7
79
  boolean: () => boolean | null;
8
- set: (value: T) => void;
80
+ /**
81
+ * Sets a value in storage with optional expiry time.
82
+ *
83
+ * @param value - The value to store (will be JSON stringified if not a string)
84
+ * @param expiresIn - Optional expiry time in milliseconds from now
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * // Set without expiry
89
+ * item.set({ theme: 'dark' })
90
+ *
91
+ * // Set with 1 hour expiry
92
+ * item.set({ theme: 'dark' }, 60 * 60 * 1000)
93
+ * ```
94
+ */
95
+ set: (value: T, expiresIn?: number) => void;
96
+ /**
97
+ * Removes the item from storage, including any expiry metadata.
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * item.remove()
102
+ * console.log(item.isSet()) // false
103
+ * ```
104
+ */
9
105
  remove: () => void;
106
+ /**
107
+ * Subscribes to storage changes for this item, both in the same tab and across browser tabs/windows.
108
+ * Callbacks are invoked immediately when changes occur via set() or remove() in the same tab,
109
+ * and also when changes are made in other tabs/windows.
110
+ *
111
+ * @param callback - Function called when the storage value changes, receives the updated StorageItem
112
+ * @returns Unsubscribe function to stop listening to changes
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * const unsubscribe = item.subscribe((updatedItem) => {
117
+ * console.log('Value changed:', updatedItem.json())
118
+ * })
119
+ *
120
+ * // Changes in same tab will trigger the callback
121
+ * item.set({ theme: 'dark' }) // callback fires immediately
122
+ *
123
+ * // Changes in other tabs also trigger the callback
124
+ * // (when another tab calls item.set())
125
+ *
126
+ * // Later, stop listening
127
+ * unsubscribe()
128
+ * ```
129
+ */
130
+ subscribe: (callback: (value: StorageItem<T>) => void) => () => void;
10
131
  }
132
+ /**
133
+ * Represents a storage key with encoded identifier and scope metadata.
134
+ */
11
135
  export interface StorageKey {
136
+ /**
137
+ * The encoded storage key string used in browser storage
138
+ */
12
139
  _: string;
140
+ /**
141
+ * The scope of the storage key ('global' or 'experience')
142
+ */
13
143
  scope: StorageScope;
14
144
  }
145
+ /**
146
+ * Creates a storage key with proper prefixing and encoding.
147
+ * Keys are prefixed with 'pckd' and optionally scoped to an experience instance.
148
+ *
149
+ * @param key - The raw key name (e.g., 'user-preferences')
150
+ * @param scope - The storage scope, defaults to 'global'
151
+ * @param experienceInstance - Required when scope is 'experience'
152
+ * @returns A StorageKey object with encoded identifier and scope
153
+ * @throws Error if scope is 'experience' but experienceInstance is not provided
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * // Global scope
158
+ * const globalKey = createStorageKey('theme')
159
+ * // Result: { _: 'pckd:encodedTheme', scope: 'global' }
160
+ *
161
+ * // Experience scope
162
+ * const expKey = createStorageKey('step', 'experience', experienceInstance)
163
+ * // Result: { _: 'pckd:exp123:encodedStep', scope: 'experience' }
164
+ * ```
165
+ */
15
166
  export declare function createStorageKey(key: string, scope?: StorageScope, experienceInstance?: ExperienceInstance): StorageKey;
167
+ /**
168
+ * Subscribes to storage changes for a specific key in both the same tab and across browser tabs/windows.
169
+ * Uses a local subscription registry for same-tab changes and the browser's storage event for cross-tab changes.
170
+ *
171
+ * @template T - The type of the stored value
172
+ * @param key - The storage key to watch
173
+ * @param storage - The storage type ('local' or 'session')
174
+ * @param get - Function to retrieve the current StorageItem
175
+ * @param callback - Function called when storage changes, receives updated StorageItem
176
+ * @returns Unsubscribe function to stop listening to changes
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * const key = createStorageKey('theme')
181
+ * const unsubscribe = subscribe(
182
+ * key,
183
+ * 'local',
184
+ * (k) => localStore.get(k),
185
+ * (item) => console.log('Theme changed:', item.json())
186
+ * )
187
+ *
188
+ * // Later, stop listening
189
+ * unsubscribe()
190
+ * ```
191
+ */
16
192
  export declare function subscribe<T = unknown>(key: StorageKey, storage: 'local' | 'session', get: (key: StorageKey) => StorageItem<T>, callback: (value: StorageItem<T>) => void): () => void;
193
+ /**
194
+ * Session storage wrapper with type-safe access and expiry support.
195
+ * Data persists only for the browser session and is cleared when the tab/window is closed.
196
+ *
197
+ * @example
198
+ * ```typescript
199
+ * // Create a key
200
+ * const key = createStorageKey('cart-items')
201
+ *
202
+ * // Get a storage item
203
+ * const cart = sessionStore.get<CartItem[]>(key)
204
+ *
205
+ * // Set value with 30-minute expiry
206
+ * sessionStore.set(key, [{ id: 1, name: 'Product' }], 30 * 60 * 1000)
207
+ *
208
+ * // Subscribe to changes
209
+ * const unsubscribe = sessionStore.subscribe(key, (item) => {
210
+ * console.log('Cart updated:', item.json())
211
+ * })
212
+ *
213
+ * // Remove value
214
+ * sessionStore.remove(key)
215
+ * ```
216
+ */
17
217
  export declare const sessionStore: {
218
+ /**
219
+ * Retrieves a storage item from sessionStorage.
220
+ *
221
+ * @template T - The type of the stored value
222
+ * @param key - The storage key
223
+ * @returns A StorageItem with methods to interact with the value
224
+ *
225
+ * @example
226
+ * ```typescript
227
+ * const key = createStorageKey('user')
228
+ * const item = sessionStore.get<User>(key)
229
+ * const user = item.json() // User | null
230
+ * ```
231
+ */
18
232
  get<T = unknown>(key: StorageKey): StorageItem<T>;
233
+ /**
234
+ * Sets a value in sessionStorage with optional expiry.
235
+ *
236
+ * @param key - The storage key
237
+ * @param value - The value to store
238
+ * @param expiresIn - Optional expiry time in milliseconds from now
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * const key = createStorageKey('theme')
243
+ * // Set without expiry
244
+ * sessionStore.set(key, 'dark')
245
+ * // Set with 1 hour expiry
246
+ * sessionStore.set(key, 'dark', 60 * 60 * 1000)
247
+ * ```
248
+ */
19
249
  set(key: StorageKey, value: unknown, expiresIn?: number): void;
250
+ /**
251
+ * Removes a value from sessionStorage, including expiry metadata.
252
+ *
253
+ * @param key - The storage key
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * const key = createStorageKey('temp-data')
258
+ * sessionStore.remove(key)
259
+ * ```
260
+ */
20
261
  remove(key: StorageKey): void;
262
+ /**
263
+ * Subscribes to storage changes for a key, both in the same tab and across browser tabs/windows.
264
+ * Callbacks are invoked when changes occur via sessionStore.set() or sessionStore.remove() in the same tab,
265
+ * and also when changes are made in other tabs/windows.
266
+ *
267
+ * @template T - The type of the stored value
268
+ * @param key - The storage key to watch
269
+ * @param callback - Function called when storage changes
270
+ * @returns Unsubscribe function to stop listening
271
+ *
272
+ * @example
273
+ * ```typescript
274
+ * const key = createStorageKey('notifications')
275
+ * const unsubscribe = sessionStore.subscribe<Notification[]>(key, (item) => {
276
+ * const notifications = item.json()
277
+ * console.log('Notifications updated:', notifications)
278
+ * })
279
+ *
280
+ * // Changes in same tab trigger callback
281
+ * sessionStore.set(key, [{ id: 1, message: 'New notification' }])
282
+ *
283
+ * // Later, stop listening
284
+ * unsubscribe()
285
+ * ```
286
+ */
21
287
  subscribe<T = unknown>(key: StorageKey, callback: (value: StorageItem<T>) => void): () => void;
22
288
  };
289
+ /**
290
+ * Local storage wrapper with type-safe access and expiry support.
291
+ * Data persists across browser sessions until explicitly removed or expired.
292
+ *
293
+ * @example
294
+ * ```typescript
295
+ * // Create a key
296
+ * const key = createStorageKey('user-preferences')
297
+ *
298
+ * // Get a storage item
299
+ * const prefs = localStore.get<UserPrefs>(key)
300
+ *
301
+ * // Set value with 7-day expiry
302
+ * localStore.set(key, { theme: 'dark' }, 7 * 24 * 60 * 60 * 1000)
303
+ *
304
+ * // Subscribe to changes
305
+ * const unsubscribe = localStore.subscribe(key, (item) => {
306
+ * console.log('Preferences updated:', item.json())
307
+ * })
308
+ *
309
+ * // Remove value
310
+ * localStore.remove(key)
311
+ * ```
312
+ */
23
313
  export declare const localStore: {
314
+ /**
315
+ * Retrieves a storage item from localStorage.
316
+ *
317
+ * @template T - The type of the stored value
318
+ * @param key - The storage key
319
+ * @returns A StorageItem with methods to interact with the value
320
+ *
321
+ * @example
322
+ * ```typescript
323
+ * const key = createStorageKey('settings')
324
+ * const item = localStore.get<Settings>(key)
325
+ * const settings = item.json() // Settings | null
326
+ * ```
327
+ */
24
328
  get<T = unknown>(key: StorageKey): StorageItem<T>;
329
+ /**
330
+ * Sets a value in localStorage with optional expiry.
331
+ *
332
+ * @param key - The storage key
333
+ * @param value - The value to store
334
+ * @param expiresIn - Optional expiry time in milliseconds from now
335
+ *
336
+ * @example
337
+ * ```typescript
338
+ * const key = createStorageKey('auth-token')
339
+ * // Set without expiry
340
+ * localStore.set(key, 'token123')
341
+ * // Set with 24 hour expiry
342
+ * localStore.set(key, 'token123', 24 * 60 * 60 * 1000)
343
+ * ```
344
+ */
25
345
  set(key: StorageKey, value: unknown, expiresIn?: number): void;
346
+ /**
347
+ * Removes a value from localStorage, including expiry metadata.
348
+ *
349
+ * @param key - The storage key
350
+ *
351
+ * @example
352
+ * ```typescript
353
+ * const key = createStorageKey('cached-data')
354
+ * localStore.remove(key)
355
+ * ```
356
+ */
26
357
  remove(key: StorageKey): void;
358
+ /**
359
+ * Subscribes to storage changes for a key, both in the same tab and across browser tabs/windows.
360
+ * Callbacks are invoked when changes occur via localStore.set() or localStore.remove() in the same tab,
361
+ * and also when changes are made in other tabs/windows.
362
+ *
363
+ * @template T - The type of the stored value
364
+ * @param key - The storage key to watch
365
+ * @param callback - Function called when storage changes
366
+ * @returns Unsubscribe function to stop listening
367
+ *
368
+ * @example
369
+ * ```typescript
370
+ * const key = createStorageKey('user-status')
371
+ * const unsubscribe = localStore.subscribe<UserStatus>(key, (item) => {
372
+ * const status = item.json()
373
+ * console.log('User status changed:', status)
374
+ * })
375
+ *
376
+ * // Changes in same tab trigger callback
377
+ * localStore.set(key, { online: true })
378
+ *
379
+ * // Later, stop listening
380
+ * unsubscribe()
381
+ * ```
382
+ */
27
383
  subscribe<T = unknown>(key: StorageKey, callback: (value: StorageItem<T>) => void): () => void;
28
384
  };
29
385
  //# sourceMappingURL=storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/utils/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qDAAqD,CAAA;AAE7F,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,YAAY,CAAA;AAElD,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,KAAK,EAAE,MAAM,OAAO,CAAA;IACpB,IAAI,EAAE,MAAM,MAAM,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,CAAA;IAC7B,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAA;IACvB,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB;AAQD,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,YAAY,CAAA;CACpB;AAED,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,KAAK,GAAE,YAAuB,EAC9B,kBAAkB,CAAC,EAAE,kBAAkB,GACtC,UAAU,CAaZ;AAyBD,wBAAgB,SAAS,CAAC,CAAC,GAAG,OAAO,EACnC,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,GAAG,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,WAAW,CAAC,CAAC,CAAC,EACxC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,cAc1C;AAmDD,eAAO,MAAM,YAAY;QACnB,CAAC,iBAAiB,UAAU;aAGvB,UAAU,SAAS,OAAO,cAAc,MAAM;gBAG3C,UAAU;cAGZ,CAAC,iBAAiB,UAAU,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI;CAGlF,CAAA;AAED,eAAO,MAAM,UAAU;QACjB,CAAC,iBAAiB,UAAU;aAGvB,UAAU,SAAS,OAAO,cAAc,MAAM;gBAG3C,UAAU;cAGZ,CAAC,iBAAiB,UAAU,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI;CAGlF,CAAA"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/utils/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qDAAqD,CAAA;AAE7F;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,YAAY,CAAA;AAElD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC;;;;;;;;;;;OAWG;IACH,KAAK,EAAE,MAAM,OAAO,CAAA;IAEpB;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,MAAM,GAAG,IAAI,CAAA;IAEzB;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;IAEpB;;;;;;;;;OASG;IACH,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,CAAA;IAE7B;;;;;;;;;;;;;;OAcG;IACH,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAE3C;;;;;;;;OAQG;IACH,MAAM,EAAE,MAAM,IAAI,CAAA;IAElB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;CACrE;AAgBD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,CAAC,EAAE,MAAM,CAAA;IACT;;OAEG;IACH,KAAK,EAAE,YAAY,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,KAAK,GAAE,YAAuB,EAC9B,kBAAkB,CAAC,EAAE,kBAAkB,GACtC,UAAU,CAaZ;AAuFD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,SAAS,CAAC,CAAC,GAAG,OAAO,EACnC,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,GAAG,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,WAAW,CAAC,CAAC,CAAC,EACxC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,cAwC1C;AA6ED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,YAAY;IACvB;;;;;;;;;;;;;OAaG;QACC,CAAC,iBAAiB,UAAU;IAIhC;;;;;;;;;;;;;;;OAeG;aACM,UAAU,SAAS,OAAO,cAAc,MAAM;IAIvD;;;;;;;;;;OAUG;gBACS,UAAU;IAItB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;cACO,CAAC,iBAAiB,UAAU,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI;CAGlF,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,UAAU;IACrB;;;;;;;;;;;;;OAaG;QACC,CAAC,iBAAiB,UAAU;IAIhC;;;;;;;;;;;;;;;OAeG;aACM,UAAU,SAAS,OAAO,cAAc,MAAM;IAIvD;;;;;;;;;;OAUG;gBACS,UAAU;IAItB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;cACO,CAAC,iBAAiB,UAAU,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI;CAGlF,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picked/client",
3
- "version": "0.0.37",
3
+ "version": "0.0.38-next.2",
4
4
  "dependencies": {
5
5
  "@withease/factories": "^1.0.5"
6
6
  },
@@ -1,94 +0,0 @@
1
- const f = (e) => btoa([...e].map((t) => String.fromCharCode(t.charCodeAt(0) ^ 7)).join("")).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
2
- function m(e, t = "global", r) {
3
- let o = "pckd";
4
- if (t === "experience") {
5
- if (!r)
6
- throw new Error("Experience instance is required to scope storage to an experience");
7
- o = `${o}:${r.experienceId}`;
8
- }
9
- return { _: `${o}:${f(e)}`, scope: t };
10
- }
11
- function l(e, t, r, o) {
12
- const n = r === "local" ? localStorage : sessionStorage, s = typeof t != "string" ? JSON.stringify(t) : t;
13
- if (n.setItem(e._, s), typeof o == "number") {
14
- const a = new Date(Date.now() + o).toISOString();
15
- n.setItem(`${e._}:expires-at`, a);
16
- }
17
- }
18
- function c(e, t) {
19
- const r = t === "local" ? localStorage : sessionStorage;
20
- r.removeItem(e._), r.removeItem(`${e._}:expires-at`);
21
- }
22
- function u(e, t, r, o) {
23
- const n = t === "local" ? localStorage : sessionStorage;
24
- function s(i) {
25
- i.storageArea === n && i.key === e._ && o(r(e));
26
- }
27
- return window.addEventListener("storage", s), function() {
28
- window.removeEventListener("storage", s);
29
- };
30
- }
31
- function g(e, t) {
32
- const r = t === "local" ? localStorage : sessionStorage, o = r.getItem(e._), n = r.getItem(`${e._}:expires-at`), s = (a) => l(e, a, t), i = () => c(e, t);
33
- if (n) {
34
- const a = /* @__PURE__ */ new Date(), S = new Date(n);
35
- if (a > S)
36
- return c(e, t), {
37
- isSet: () => !1,
38
- text: () => null,
39
- json: () => null,
40
- boolean: () => null,
41
- set: s,
42
- remove: i
43
- };
44
- }
45
- return {
46
- isSet() {
47
- return o !== null;
48
- },
49
- text() {
50
- return o;
51
- },
52
- json() {
53
- return o ? JSON.parse(o) : null;
54
- },
55
- boolean() {
56
- return o ? o === "true" : null;
57
- },
58
- set: s,
59
- remove: i
60
- };
61
- }
62
- const p = {
63
- get(e) {
64
- return g(e, "session");
65
- },
66
- set(e, t, r) {
67
- l(e, t, "session", r);
68
- },
69
- remove(e) {
70
- c(e, "session");
71
- },
72
- subscribe(e, t) {
73
- return u(e, "session", this.get, t);
74
- }
75
- }, b = {
76
- get(e) {
77
- return g(e, "local");
78
- },
79
- set(e, t, r) {
80
- l(e, t, "local", r);
81
- },
82
- remove(e) {
83
- c(e, "local");
84
- },
85
- subscribe(e, t) {
86
- return u(e, "local", this.get, t);
87
- }
88
- };
89
- export {
90
- u as a,
91
- m as c,
92
- b as l,
93
- p as s
94
- };
@@ -1 +0,0 @@
1
- "use strict";const f=e=>btoa([...e].map(t=>String.fromCharCode(t.charCodeAt(0)^7)).join("")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"");function m(e,t="global",r){let o="pckd";if(t==="experience"){if(!r)throw new Error("Experience instance is required to scope storage to an experience");o=`${o}:${r.experienceId}`}return{_:`${o}:${f(e)}`,scope:t}}function l(e,t,r,o){const n=r==="local"?localStorage:sessionStorage,s=typeof t!="string"?JSON.stringify(t):t;if(n.setItem(e._,s),typeof o=="number"){const c=new Date(Date.now()+o).toISOString();n.setItem(`${e._}:expires-at`,c)}}function a(e,t){const r=t==="local"?localStorage:sessionStorage;r.removeItem(e._),r.removeItem(`${e._}:expires-at`)}function u(e,t,r,o){const n=t==="local"?localStorage:sessionStorage;function s(i){i.storageArea===n&&i.key===e._&&o(r(e))}return window.addEventListener("storage",s),function(){window.removeEventListener("storage",s)}}function g(e,t){const r=t==="local"?localStorage:sessionStorage,o=r.getItem(e._),n=r.getItem(`${e._}:expires-at`),s=c=>l(e,c,t),i=()=>a(e,t);if(n){const c=new Date,S=new Date(n);if(c>S)return a(e,t),{isSet:()=>!1,text:()=>null,json:()=>null,boolean:()=>null,set:s,remove:i}}return{isSet(){return o!==null},text(){return o},json(){return o?JSON.parse(o):null},boolean(){return o?o==="true":null},set:s,remove:i}}const b={get(e){return g(e,"session")},set(e,t,r){l(e,t,"session",r)},remove(e){a(e,"session")},subscribe(e,t){return u(e,"session",this.get,t)}},p={get(e){return g(e,"local")},set(e,t,r){l(e,t,"local",r)},remove(e){a(e,"local")},subscribe(e,t){return u(e,"local",this.get,t)}};exports.createStorageKey=m;exports.localStore=p;exports.sessionStore=b;exports.subscribe=u;