@storix-js/persist 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});var at=Symbol.for("preact-signals");function G(){if(E>1)E--;else{for(var e,t=!1;A!==void 0;){var o=A;for(A=void 0,Q++;o!==void 0;){var d=o.o;if(o.o=void 0,o.f&=-3,!(8&o.f)&&it(o))try{o.c()}catch(O){t||(e=O,t=!0)}o=d}}if(Q=0,E--,t)throw e}}function L(e){if(E>0)return e();E++;try{return e()}finally{G()}}var l=void 0;function et(e){var t=l;l=void 0;try{return e()}finally{l=t}}var A=void 0,E=0,Q=0,F=0;function nt(e){if(l!==void 0){var t=e.n;if(t===void 0||t.t!==l)return t={i:0,S:e,p:l.s,n:void 0,t:l,e:void 0,x:void 0,r:t},l.s!==void 0&&(l.s.n=t),l.s=t,e.n=t,32&l.f&&e.S(t),t;if(t.i===-1)return t.i=0,t.n!==void 0&&(t.n.p=t.p,t.p!==void 0&&(t.p.n=t.n),t.p=l.s,t.n=void 0,l.s.n=t,l.s=t),t}}function b(e,t){this.v=e,this.i=0,this.n=void 0,this.t=void 0,this.W=t==null?void 0:t.watched,this.Z=t==null?void 0:t.unwatched,this.name=t==null?void 0:t.name}b.prototype.brand=at;b.prototype.h=function(){return!0};b.prototype.S=function(e){var t=this,o=this.t;o!==e&&e.e===void 0&&(e.x=o,this.t=e,o!==void 0?o.e=e:et(function(){var d;(d=t.W)==null||d.call(t)}))};b.prototype.U=function(e){var t=this;if(this.t!==void 0){var o=e.e,d=e.x;o!==void 0&&(o.x=d,e.e=void 0),d!==void 0&&(d.e=o,e.x=void 0),e===this.t&&(this.t=d,d===void 0&&et(function(){var O;(O=t.Z)==null||O.call(t)}))}};b.prototype.subscribe=function(e){var t=this;return ut(function(){var o=t.value,d=l;l=void 0;try{e(o)}finally{l=d}},{name:"sub"})};b.prototype.valueOf=function(){return this.value};b.prototype.toString=function(){return this.value+""};b.prototype.toJSON=function(){return this.value};b.prototype.peek=function(){var e=l;l=void 0;try{return this.value}finally{l=e}};Object.defineProperty(b.prototype,"value",{get:function(){var e=nt(this);return e!==void 0&&(e.i=this.i),this.v},set:function(e){if(e!==this.v){if(Q>100)throw new Error("Cycle detected");this.v=e,this.i++,F++,E++;try{for(var t=this.t;t!==void 0;t=t.x)t.t.N()}finally{G()}}}});function ct(e,t){return new b(e,t)}function it(e){for(var t=e.s;t!==void 0;t=t.n)if(t.S.i!==t.i||!t.S.h()||t.S.i!==t.i)return!0;return!1}function ot(e){for(var t=e.s;t!==void 0;t=t.n){var o=t.S.n;if(o!==void 0&&(t.r=o),t.S.n=t,t.i=-1,t.n===void 0){e.s=t;break}}}function rt(e){for(var t=e.s,o=void 0;t!==void 0;){var d=t.p;t.i===-1?(t.S.U(t),d!==void 0&&(d.n=t.n),t.n!==void 0&&(t.n.p=d)):o=t,t.S.n=t.r,t.r!==void 0&&(t.r=void 0),t=d}e.s=o}function U(e,t){b.call(this,void 0),this.x=e,this.s=void 0,this.g=F-1,this.f=4,this.W=t==null?void 0:t.watched,this.Z=t==null?void 0:t.unwatched,this.name=t==null?void 0:t.name}U.prototype=new b;U.prototype.h=function(){if(this.f&=-3,1&this.f)return!1;if((36&this.f)==32||(this.f&=-5,this.g===F))return!0;if(this.g=F,this.f|=1,this.i>0&&!it(this))return this.f&=-2,!0;var e=l;try{ot(this),l=this;var t=this.x();(16&this.f||this.v!==t||this.i===0)&&(this.v=t,this.f&=-17,this.i++)}catch(o){this.v=o,this.f|=16,this.i++}return l=e,rt(this),this.f&=-2,!0};U.prototype.S=function(e){if(this.t===void 0){this.f|=36;for(var t=this.s;t!==void 0;t=t.n)t.S.S(t)}b.prototype.S.call(this,e)};U.prototype.U=function(e){if(this.t!==void 0&&(b.prototype.U.call(this,e),this.t===void 0)){this.f&=-33;for(var t=this.s;t!==void 0;t=t.n)t.S.U(t)}};U.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var e=this.t;e!==void 0;e=e.x)e.t.N()}};Object.defineProperty(U.prototype,"value",{get:function(){if(1&this.f)throw new Error("Cycle detected");var e=nt(this);if(this.h(),e!==void 0&&(e.i=this.i),16&this.f)throw this.v;return this.v}});function tt(e,t){return new U(e,t)}function st(e){var t=e.u;if(e.u=void 0,typeof t=="function"){E++;var o=l;l=void 0;try{t()}catch(d){throw e.f&=-2,e.f|=8,X(e),d}finally{l=o,G()}}}function X(e){for(var t=e.s;t!==void 0;t=t.n)t.S.U(t);e.x=void 0,e.s=void 0,st(e)}function ft(e){if(l!==this)throw new Error("Out-of-order effect");rt(this),l=e,this.f&=-2,8&this.f&&X(this),G()}function K(e,t){this.x=e,this.u=void 0,this.s=void 0,this.o=void 0,this.f=32,this.name=t==null?void 0:t.name}K.prototype.c=function(){var e=this.S();try{if(8&this.f||this.x===void 0)return;var t=this.x();typeof t=="function"&&(this.u=t)}finally{e()}};K.prototype.S=function(){if(1&this.f)throw new Error("Cycle detected");this.f|=1,this.f&=-9,st(this),ot(this),E++;var e=l;return l=this,ft.bind(this,e)};K.prototype.N=function(){2&this.f||(this.f|=2,this.o=A,A=this)};K.prototype.d=function(){this.f|=8,1&this.f||X(this)};K.prototype.dispose=function(){this.d()};function ut(e,t){var o=new K(e,t);try{o.c()}catch(O){throw o.d(),O}var d=o.d.bind(o);return d[Symbol.dispose]=d,d}function dt(e={}){const t=(e.namespace??"default").trim()||"default",o=e.plugins??[],d=new Map;function O(S,D){return function(){var Z;const j=`${t}:${S}`,R=d.get(S);if(R)return R;const N=D.state(),x=D.modules??{},z={...N};for(const[i,n]of Object.entries(x))z[i]=n.state();const y=ct(z),I=new Map,H=new Map,q=new Map,P=new Map,$=new Map,T=new Set,M=new Set(Object.keys(N)),W=new Set(Object.keys(D.getters??{})),C=new Set(Object.keys(D.actions??{})),r=i=>y.value[i]??{},a=(i,n)=>{y.value={...y.value,[i]:n}},h=new Proxy({},{get(i,n){var c,f;if(I.has(n))return(c=I.get(n))==null?void 0:c.value;if($.has(n))return(f=$.get(n))==null?void 0:f.value;if(M.has(n))return y.value[n];const p=P.get(n);return p?r(p.moduleName)[p.key]:y.value[n]}});for(const[i,n]of Object.entries(D.getters??{}))I.set(i,tt(()=>n(y.value,h)));const w=(i,n)=>{var c;for(const f of T)f(i);for(const f of o)(c=f.onMutation)==null||c.call(f,n,i)},J=(i,n,c,f)=>{const p=y.value[i];Object.is(p,n)||(y.value={...y.value,[i]:n},w({namespace:t,scopeId:j,storeId:S,key:i,oldValue:p,newValue:n,origin:c},f))},B=(i,n,c,f,p)=>{const m=r(i),s=m[n];Object.is(s,c)||(a(i,{...m,[n]:c}),w({namespace:t,scopeId:j,storeId:S,key:`${i}.${n}`,oldValue:s,newValue:c,origin:f},p))},g={$id:S,$namespace:t,$scopeId:j,$subscribe(i){return T.add(i),()=>T.delete(i)},$dispose(){var i;T.clear();for(const n of o)(i=n.onDispose)==null||i.call(n,v);d.delete(S)},$patch(i,n="local"){L(()=>{for(const[c,f]of Object.entries(i)){const p=P.get(c);if(p){B(p.moduleName,p.key,f,n,v);continue}if(c.includes(".")){const[m,s]=c.split(".",2);if(x[m]){B(m,s,f,n,v);continue}}if(x[c]&&f&&typeof f=="object"&&!Array.isArray(f)){for(const[m,s]of Object.entries(f))B(c,m,s,n,v);continue}J(c,f,n,v)}})},$snapshot(){return{...y.value}}};for(const[i,n]of Object.entries(x)){const c=new Map,f=new Map,p=new Proxy({},{get(s,u){var k,V,Y;if(c.has(u))return(k=c.get(u))==null?void 0:k.value;if(I.has(u))return(V=I.get(u))==null?void 0:V.value;if($.has(u))return(Y=$.get(u))==null?void 0:Y.value;const _=r(i);if(u in _)return _[u];if(M.has(u))return y.value[u]}});for(const[s,u]of Object.entries(n.getters??{}))c.set(s,tt(()=>u(r(i),y.value,p)));let m;for(const[s,u]of Object.entries(n.actions??{}))f.set(s,(...k)=>L(()=>u.apply(m,k)));m=new Proxy({},{get(s,u){var k;if(f.has(u))return f.get(u);if(c.has(u))return(k=c.get(u))==null?void 0:k.value;const V=r(i);return u in V?V[u]:v[u]},set(s,u,k){if(f.has(u)||c.has(u))return!1;const V=r(i);return u in V?B(i,u,k,"local",v):v[u]=k,!0}}),q.set(i,m),H.set(i,c);for(const s of Object.keys(r(i)))!(M.has(s)||W.has(s)||C.has(s)||Reflect.has(g,s)||x[s]!==void 0)&&!P.has(s)&&P.set(s,{moduleName:i,key:s});for(const[s,u]of c.entries())!(M.has(s)||W.has(s)||C.has(s)||Reflect.has(g,s)||x[s]!==void 0)&&!$.has(s)&&$.set(s,u);for(const[s,u]of f.entries())!(M.has(s)||W.has(s)||C.has(s)||Reflect.has(g,s)||x[s]!==void 0)&&!Reflect.has(g,s)&&(g[s]=u)}const v=new Proxy(g,{get(i,n,c){var f,p;if(Reflect.has(i,n))return Reflect.get(i,n,c);if(q.has(n))return q.get(n);if(I.has(n))return(f=I.get(n))==null?void 0:f.value;if($.has(n))return(p=$.get(n))==null?void 0:p.value;if(M.has(n))return y.value[n];const m=P.get(n);return m?r(m.moduleName)[m.key]:y.value[n]},set(i,n,c,f){if(Reflect.has(i,n))return Reflect.set(i,n,c,f);const p=P.get(n);return p?(B(p.moduleName,p.key,c,"local",f),!0):(J(n,c,"local",f),!0)}});for(const[i,n]of Object.entries(D.actions??{}))g[i]=(...c)=>L(()=>n.apply(v,c));for(const i of o)(Z=i.onInit)==null||Z.call(i,v);return d.set(S,v),v}}return{defineStore:O,use(S){o.push(S)}}}dt();function lt(e={}){var W,C;const t=e.keyPrefix??"storix",o=new Set(e.include??[]),d=e.storage??"localStorage",O=e.serialize??JSON.stringify,S=e.deserialize??(r=>JSON.parse(r)),D=e.debounce??100,Z=((W=e.indexedDB)==null?void 0:W.dbName)??`${t}-persist`,j=((C=e.indexedDB)==null?void 0:C.storeName)??"stores",R=new Map,N=new Map;let x=null;const z=r=>{const a=[r.$id,r.$scopeId];return!(o.size>0&&!a.some(h=>o.has(h)))},y=r=>`${t}:${r.$namespace}:${r.$id}`,I=()=>x||(x=new Promise((r,a)=>{const h=window.indexedDB.open(Z,1);h.onupgradeneeded=()=>{const w=h.result;w.objectStoreNames.contains(j)||w.createObjectStore(j)},h.onsuccess=()=>r(h.result),h.onerror=()=>a(h.error??new Error("IndexedDB open failed"))}),x),H=async r=>{const a=await I(),h=y(r);return new Promise((w,J)=>{const g=a.transaction(j,"readonly").objectStore(j).get(h);g.onsuccess=()=>{const v=g.result;if(typeof v!="string"){w(null);return}try{w(S(v))}catch{w(null)}},g.onerror=()=>J(g.error??new Error("IndexedDB read failed"))})},q=async(r,a)=>{const h=await I(),w=y(r),J=O(a);return new Promise((B,g)=>{const v=h.transaction(j,"readwrite");v.objectStore(j).put(J,w),v.oncomplete=()=>B(),v.onerror=()=>g(v.error??new Error("IndexedDB write failed")),v.onabort=()=>g(v.error??new Error("IndexedDB write aborted"))})},P=async r=>{if(typeof window>"u")return null;if(d==="indexedDB"&&"indexedDB"in window)try{return await H(r)}catch{return null}try{const a=window.localStorage.getItem(y(r));return a?S(a):null}catch{return null}},$=r=>{if(typeof window>"u")return;const a=R.get(r.$scopeId);if(a){if(d==="indexedDB"&&"indexedDB"in window){q(r,a).catch(()=>{});return}try{window.localStorage.setItem(y(r),O(a))}catch{}}},T=r=>{const a=r.$scopeId,h=N.get(a);if(h&&(clearTimeout(h),N.delete(a)),D<=0){$(r);return}const w=setTimeout(()=>{N.delete(a),$(r)},D);N.set(a,w)},M=r=>{const a=r.$scopeId,h=N.get(a);h&&(clearTimeout(h),N.delete(a)),$(r)};return{name:"persist",onInit(r){const a=r;typeof window>"u"||z(a)&&(async()=>{const h=await P(a);h&&(R.set(a.$scopeId,h),a.$patch(h,"remote"))})()},onMutation(r,a){const h=r;if(typeof window>"u"||!z(h))return;const w=R.get(h.$scopeId)??{};w[a.key]=a.newValue,R.set(h.$scopeId,w),T(h)},onDispose(r){const a=r;z(a)&&M(a)}}}exports.persistPlugin=lt;
@@ -0,0 +1,17 @@
1
+ type PersistStorage = 'localStorage' | 'indexedDB';
2
+ export interface IndexedDBPersistOptions {
3
+ dbName?: string;
4
+ storeName?: string;
5
+ }
6
+ export interface PersistPluginOptions {
7
+ keyPrefix?: string;
8
+ include?: string[];
9
+ storage?: PersistStorage;
10
+ serialize?: (value: Record<string, unknown>) => string;
11
+ deserialize?: (raw: string) => Record<string, unknown>;
12
+ debounce?: number;
13
+ indexedDB?: IndexedDBPersistOptions;
14
+ }
15
+ export declare function persistPlugin(options?: PersistPluginOptions): import("@storix-js/core").StorePlugin;
16
+ export {};
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,KAAK,cAAc,GAAG,cAAc,GAAG,WAAW,CAAC;AAEnD,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;IACvD,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AASD,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,yCAuL/D"}
package/dist/index.js ADDED
@@ -0,0 +1,544 @@
1
+ var at = Symbol.for("preact-signals");
2
+ function G() {
3
+ if (E > 1)
4
+ E--;
5
+ else {
6
+ for (var e, t = !1; A !== void 0; ) {
7
+ var o = A;
8
+ for (A = void 0, Q++; o !== void 0; ) {
9
+ var d = o.o;
10
+ if (o.o = void 0, o.f &= -3, !(8 & o.f) && it(o)) try {
11
+ o.c();
12
+ } catch (O) {
13
+ t || (e = O, t = !0);
14
+ }
15
+ o = d;
16
+ }
17
+ }
18
+ if (Q = 0, E--, t) throw e;
19
+ }
20
+ }
21
+ function L(e) {
22
+ if (E > 0) return e();
23
+ E++;
24
+ try {
25
+ return e();
26
+ } finally {
27
+ G();
28
+ }
29
+ }
30
+ var l = void 0;
31
+ function et(e) {
32
+ var t = l;
33
+ l = void 0;
34
+ try {
35
+ return e();
36
+ } finally {
37
+ l = t;
38
+ }
39
+ }
40
+ var A = void 0, E = 0, Q = 0, F = 0;
41
+ function nt(e) {
42
+ if (l !== void 0) {
43
+ var t = e.n;
44
+ if (t === void 0 || t.t !== l)
45
+ return t = { i: 0, S: e, p: l.s, n: void 0, t: l, e: void 0, x: void 0, r: t }, l.s !== void 0 && (l.s.n = t), l.s = t, e.n = t, 32 & l.f && e.S(t), t;
46
+ if (t.i === -1)
47
+ return t.i = 0, t.n !== void 0 && (t.n.p = t.p, t.p !== void 0 && (t.p.n = t.n), t.p = l.s, t.n = void 0, l.s.n = t, l.s = t), t;
48
+ }
49
+ }
50
+ function b(e, t) {
51
+ this.v = e, this.i = 0, this.n = void 0, this.t = void 0, this.W = t == null ? void 0 : t.watched, this.Z = t == null ? void 0 : t.unwatched, this.name = t == null ? void 0 : t.name;
52
+ }
53
+ b.prototype.brand = at;
54
+ b.prototype.h = function() {
55
+ return !0;
56
+ };
57
+ b.prototype.S = function(e) {
58
+ var t = this, o = this.t;
59
+ o !== e && e.e === void 0 && (e.x = o, this.t = e, o !== void 0 ? o.e = e : et(function() {
60
+ var d;
61
+ (d = t.W) == null || d.call(t);
62
+ }));
63
+ };
64
+ b.prototype.U = function(e) {
65
+ var t = this;
66
+ if (this.t !== void 0) {
67
+ var o = e.e, d = e.x;
68
+ o !== void 0 && (o.x = d, e.e = void 0), d !== void 0 && (d.e = o, e.x = void 0), e === this.t && (this.t = d, d === void 0 && et(function() {
69
+ var O;
70
+ (O = t.Z) == null || O.call(t);
71
+ }));
72
+ }
73
+ };
74
+ b.prototype.subscribe = function(e) {
75
+ var t = this;
76
+ return ut(function() {
77
+ var o = t.value, d = l;
78
+ l = void 0;
79
+ try {
80
+ e(o);
81
+ } finally {
82
+ l = d;
83
+ }
84
+ }, { name: "sub" });
85
+ };
86
+ b.prototype.valueOf = function() {
87
+ return this.value;
88
+ };
89
+ b.prototype.toString = function() {
90
+ return this.value + "";
91
+ };
92
+ b.prototype.toJSON = function() {
93
+ return this.value;
94
+ };
95
+ b.prototype.peek = function() {
96
+ var e = l;
97
+ l = void 0;
98
+ try {
99
+ return this.value;
100
+ } finally {
101
+ l = e;
102
+ }
103
+ };
104
+ Object.defineProperty(b.prototype, "value", { get: function() {
105
+ var e = nt(this);
106
+ return e !== void 0 && (e.i = this.i), this.v;
107
+ }, set: function(e) {
108
+ if (e !== this.v) {
109
+ if (Q > 100) throw new Error("Cycle detected");
110
+ this.v = e, this.i++, F++, E++;
111
+ try {
112
+ for (var t = this.t; t !== void 0; t = t.x) t.t.N();
113
+ } finally {
114
+ G();
115
+ }
116
+ }
117
+ } });
118
+ function ct(e, t) {
119
+ return new b(e, t);
120
+ }
121
+ function it(e) {
122
+ for (var t = e.s; t !== void 0; t = t.n) if (t.S.i !== t.i || !t.S.h() || t.S.i !== t.i) return !0;
123
+ return !1;
124
+ }
125
+ function ot(e) {
126
+ for (var t = e.s; t !== void 0; t = t.n) {
127
+ var o = t.S.n;
128
+ if (o !== void 0 && (t.r = o), t.S.n = t, t.i = -1, t.n === void 0) {
129
+ e.s = t;
130
+ break;
131
+ }
132
+ }
133
+ }
134
+ function rt(e) {
135
+ for (var t = e.s, o = void 0; t !== void 0; ) {
136
+ var d = t.p;
137
+ t.i === -1 ? (t.S.U(t), d !== void 0 && (d.n = t.n), t.n !== void 0 && (t.n.p = d)) : o = t, t.S.n = t.r, t.r !== void 0 && (t.r = void 0), t = d;
138
+ }
139
+ e.s = o;
140
+ }
141
+ function U(e, t) {
142
+ b.call(this, void 0), this.x = e, this.s = void 0, this.g = F - 1, this.f = 4, this.W = t == null ? void 0 : t.watched, this.Z = t == null ? void 0 : t.unwatched, this.name = t == null ? void 0 : t.name;
143
+ }
144
+ U.prototype = new b();
145
+ U.prototype.h = function() {
146
+ if (this.f &= -3, 1 & this.f) return !1;
147
+ if ((36 & this.f) == 32 || (this.f &= -5, this.g === F)) return !0;
148
+ if (this.g = F, this.f |= 1, this.i > 0 && !it(this))
149
+ return this.f &= -2, !0;
150
+ var e = l;
151
+ try {
152
+ ot(this), l = this;
153
+ var t = this.x();
154
+ (16 & this.f || this.v !== t || this.i === 0) && (this.v = t, this.f &= -17, this.i++);
155
+ } catch (o) {
156
+ this.v = o, this.f |= 16, this.i++;
157
+ }
158
+ return l = e, rt(this), this.f &= -2, !0;
159
+ };
160
+ U.prototype.S = function(e) {
161
+ if (this.t === void 0) {
162
+ this.f |= 36;
163
+ for (var t = this.s; t !== void 0; t = t.n) t.S.S(t);
164
+ }
165
+ b.prototype.S.call(this, e);
166
+ };
167
+ U.prototype.U = function(e) {
168
+ if (this.t !== void 0 && (b.prototype.U.call(this, e), this.t === void 0)) {
169
+ this.f &= -33;
170
+ for (var t = this.s; t !== void 0; t = t.n) t.S.U(t);
171
+ }
172
+ };
173
+ U.prototype.N = function() {
174
+ if (!(2 & this.f)) {
175
+ this.f |= 6;
176
+ for (var e = this.t; e !== void 0; e = e.x) e.t.N();
177
+ }
178
+ };
179
+ Object.defineProperty(U.prototype, "value", { get: function() {
180
+ if (1 & this.f) throw new Error("Cycle detected");
181
+ var e = nt(this);
182
+ if (this.h(), e !== void 0 && (e.i = this.i), 16 & this.f) throw this.v;
183
+ return this.v;
184
+ } });
185
+ function tt(e, t) {
186
+ return new U(e, t);
187
+ }
188
+ function st(e) {
189
+ var t = e.u;
190
+ if (e.u = void 0, typeof t == "function") {
191
+ E++;
192
+ var o = l;
193
+ l = void 0;
194
+ try {
195
+ t();
196
+ } catch (d) {
197
+ throw e.f &= -2, e.f |= 8, X(e), d;
198
+ } finally {
199
+ l = o, G();
200
+ }
201
+ }
202
+ }
203
+ function X(e) {
204
+ for (var t = e.s; t !== void 0; t = t.n) t.S.U(t);
205
+ e.x = void 0, e.s = void 0, st(e);
206
+ }
207
+ function ft(e) {
208
+ if (l !== this) throw new Error("Out-of-order effect");
209
+ rt(this), l = e, this.f &= -2, 8 & this.f && X(this), G();
210
+ }
211
+ function K(e, t) {
212
+ this.x = e, this.u = void 0, this.s = void 0, this.o = void 0, this.f = 32, this.name = t == null ? void 0 : t.name;
213
+ }
214
+ K.prototype.c = function() {
215
+ var e = this.S();
216
+ try {
217
+ if (8 & this.f || this.x === void 0) return;
218
+ var t = this.x();
219
+ typeof t == "function" && (this.u = t);
220
+ } finally {
221
+ e();
222
+ }
223
+ };
224
+ K.prototype.S = function() {
225
+ if (1 & this.f) throw new Error("Cycle detected");
226
+ this.f |= 1, this.f &= -9, st(this), ot(this), E++;
227
+ var e = l;
228
+ return l = this, ft.bind(this, e);
229
+ };
230
+ K.prototype.N = function() {
231
+ 2 & this.f || (this.f |= 2, this.o = A, A = this);
232
+ };
233
+ K.prototype.d = function() {
234
+ this.f |= 8, 1 & this.f || X(this);
235
+ };
236
+ K.prototype.dispose = function() {
237
+ this.d();
238
+ };
239
+ function ut(e, t) {
240
+ var o = new K(e, t);
241
+ try {
242
+ o.c();
243
+ } catch (O) {
244
+ throw o.d(), O;
245
+ }
246
+ var d = o.d.bind(o);
247
+ return d[Symbol.dispose] = d, d;
248
+ }
249
+ function dt(e = {}) {
250
+ const t = (e.namespace ?? "default").trim() || "default", o = e.plugins ?? [], d = /* @__PURE__ */ new Map();
251
+ function O(x, D) {
252
+ return function() {
253
+ var Z;
254
+ const j = `${t}:${x}`, R = d.get(x);
255
+ if (R) return R;
256
+ const N = D.state(), S = D.modules ?? {}, z = { ...N };
257
+ for (const [i, n] of Object.entries(S))
258
+ z[i] = n.state();
259
+ const y = ct(z), I = /* @__PURE__ */ new Map(), H = /* @__PURE__ */ new Map(), q = /* @__PURE__ */ new Map(), P = /* @__PURE__ */ new Map(), $ = /* @__PURE__ */ new Map(), T = /* @__PURE__ */ new Set(), M = new Set(Object.keys(N)), W = new Set(Object.keys(D.getters ?? {})), C = new Set(Object.keys(D.actions ?? {})), r = (i) => y.value[i] ?? {}, a = (i, n) => {
260
+ y.value = {
261
+ ...y.value,
262
+ [i]: n
263
+ };
264
+ }, h = new Proxy(
265
+ {},
266
+ {
267
+ get(i, n) {
268
+ var c, f;
269
+ if (I.has(n)) return (c = I.get(n)) == null ? void 0 : c.value;
270
+ if ($.has(n)) return (f = $.get(n)) == null ? void 0 : f.value;
271
+ if (M.has(n)) return y.value[n];
272
+ const p = P.get(n);
273
+ return p ? r(p.moduleName)[p.key] : y.value[n];
274
+ }
275
+ }
276
+ );
277
+ for (const [i, n] of Object.entries(D.getters ?? {}))
278
+ I.set(
279
+ i,
280
+ tt(() => n(y.value, h))
281
+ );
282
+ const w = (i, n) => {
283
+ var c;
284
+ for (const f of T) f(i);
285
+ for (const f of o)
286
+ (c = f.onMutation) == null || c.call(f, n, i);
287
+ }, J = (i, n, c, f) => {
288
+ const p = y.value[i];
289
+ Object.is(p, n) || (y.value = {
290
+ ...y.value,
291
+ [i]: n
292
+ }, w(
293
+ {
294
+ namespace: t,
295
+ scopeId: j,
296
+ storeId: x,
297
+ key: i,
298
+ oldValue: p,
299
+ newValue: n,
300
+ origin: c
301
+ },
302
+ f
303
+ ));
304
+ }, B = (i, n, c, f, p) => {
305
+ const m = r(i), s = m[n];
306
+ Object.is(s, c) || (a(i, {
307
+ ...m,
308
+ [n]: c
309
+ }), w(
310
+ {
311
+ namespace: t,
312
+ scopeId: j,
313
+ storeId: x,
314
+ key: `${i}.${n}`,
315
+ oldValue: s,
316
+ newValue: c,
317
+ origin: f
318
+ },
319
+ p
320
+ ));
321
+ }, g = {
322
+ $id: x,
323
+ $namespace: t,
324
+ $scopeId: j,
325
+ $subscribe(i) {
326
+ return T.add(i), () => T.delete(i);
327
+ },
328
+ $dispose() {
329
+ var i;
330
+ T.clear();
331
+ for (const n of o)
332
+ (i = n.onDispose) == null || i.call(n, v);
333
+ d.delete(x);
334
+ },
335
+ $patch(i, n = "local") {
336
+ L(() => {
337
+ for (const [c, f] of Object.entries(i)) {
338
+ const p = P.get(c);
339
+ if (p) {
340
+ B(p.moduleName, p.key, f, n, v);
341
+ continue;
342
+ }
343
+ if (c.includes(".")) {
344
+ const [m, s] = c.split(".", 2);
345
+ if (S[m]) {
346
+ B(m, s, f, n, v);
347
+ continue;
348
+ }
349
+ }
350
+ if (S[c] && f && typeof f == "object" && !Array.isArray(f)) {
351
+ for (const [m, s] of Object.entries(f))
352
+ B(c, m, s, n, v);
353
+ continue;
354
+ }
355
+ J(c, f, n, v);
356
+ }
357
+ });
358
+ },
359
+ $snapshot() {
360
+ return { ...y.value };
361
+ }
362
+ };
363
+ for (const [i, n] of Object.entries(S)) {
364
+ const c = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map(), p = new Proxy(
365
+ {},
366
+ {
367
+ get(s, u) {
368
+ var k, V, Y;
369
+ if (c.has(u)) return (k = c.get(u)) == null ? void 0 : k.value;
370
+ if (I.has(u)) return (V = I.get(u)) == null ? void 0 : V.value;
371
+ if ($.has(u)) return (Y = $.get(u)) == null ? void 0 : Y.value;
372
+ const _ = r(i);
373
+ if (u in _) return _[u];
374
+ if (M.has(u)) return y.value[u];
375
+ }
376
+ }
377
+ );
378
+ for (const [s, u] of Object.entries(n.getters ?? {}))
379
+ c.set(
380
+ s,
381
+ tt(() => u(r(i), y.value, p))
382
+ );
383
+ let m;
384
+ for (const [s, u] of Object.entries(n.actions ?? {}))
385
+ f.set(s, (...k) => L(() => u.apply(m, k)));
386
+ m = new Proxy(
387
+ {},
388
+ {
389
+ get(s, u) {
390
+ var k;
391
+ if (f.has(u)) return f.get(u);
392
+ if (c.has(u)) return (k = c.get(u)) == null ? void 0 : k.value;
393
+ const V = r(i);
394
+ return u in V ? V[u] : v[u];
395
+ },
396
+ set(s, u, k) {
397
+ if (f.has(u) || c.has(u)) return !1;
398
+ const V = r(i);
399
+ return u in V ? B(i, u, k, "local", v) : v[u] = k, !0;
400
+ }
401
+ }
402
+ ), q.set(i, m), H.set(i, c);
403
+ for (const s of Object.keys(r(i)))
404
+ !(M.has(s) || W.has(s) || C.has(s) || Reflect.has(g, s) || S[s] !== void 0) && !P.has(s) && P.set(s, { moduleName: i, key: s });
405
+ for (const [s, u] of c.entries())
406
+ !(M.has(s) || W.has(s) || C.has(s) || Reflect.has(g, s) || S[s] !== void 0) && !$.has(s) && $.set(s, u);
407
+ for (const [s, u] of f.entries())
408
+ !(M.has(s) || W.has(s) || C.has(s) || Reflect.has(g, s) || S[s] !== void 0) && !Reflect.has(g, s) && (g[s] = u);
409
+ }
410
+ const v = new Proxy(g, {
411
+ get(i, n, c) {
412
+ var f, p;
413
+ if (Reflect.has(i, n)) return Reflect.get(i, n, c);
414
+ if (q.has(n)) return q.get(n);
415
+ if (I.has(n)) return (f = I.get(n)) == null ? void 0 : f.value;
416
+ if ($.has(n)) return (p = $.get(n)) == null ? void 0 : p.value;
417
+ if (M.has(n)) return y.value[n];
418
+ const m = P.get(n);
419
+ return m ? r(m.moduleName)[m.key] : y.value[n];
420
+ },
421
+ set(i, n, c, f) {
422
+ if (Reflect.has(i, n))
423
+ return Reflect.set(i, n, c, f);
424
+ const p = P.get(n);
425
+ return p ? (B(p.moduleName, p.key, c, "local", f), !0) : (J(n, c, "local", f), !0);
426
+ }
427
+ });
428
+ for (const [i, n] of Object.entries(D.actions ?? {}))
429
+ g[i] = (...c) => L(() => n.apply(v, c));
430
+ for (const i of o)
431
+ (Z = i.onInit) == null || Z.call(i, v);
432
+ return d.set(x, v), v;
433
+ };
434
+ }
435
+ return {
436
+ defineStore: O,
437
+ use(x) {
438
+ o.push(x);
439
+ }
440
+ };
441
+ }
442
+ dt();
443
+ function lt(e = {}) {
444
+ var W, C;
445
+ const t = e.keyPrefix ?? "storix", o = new Set(e.include ?? []), d = e.storage ?? "localStorage", O = e.serialize ?? JSON.stringify, x = e.deserialize ?? ((r) => JSON.parse(r)), D = e.debounce ?? 100, Z = ((W = e.indexedDB) == null ? void 0 : W.dbName) ?? `${t}-persist`, j = ((C = e.indexedDB) == null ? void 0 : C.storeName) ?? "stores", R = /* @__PURE__ */ new Map(), N = /* @__PURE__ */ new Map();
446
+ let S = null;
447
+ const z = (r) => {
448
+ const a = [r.$id, r.$scopeId];
449
+ return !(o.size > 0 && !a.some((h) => o.has(h)));
450
+ }, y = (r) => `${t}:${r.$namespace}:${r.$id}`, I = () => S || (S = new Promise((r, a) => {
451
+ const h = window.indexedDB.open(Z, 1);
452
+ h.onupgradeneeded = () => {
453
+ const w = h.result;
454
+ w.objectStoreNames.contains(j) || w.createObjectStore(j);
455
+ }, h.onsuccess = () => r(h.result), h.onerror = () => a(h.error ?? new Error("IndexedDB open failed"));
456
+ }), S), H = async (r) => {
457
+ const a = await I(), h = y(r);
458
+ return new Promise((w, J) => {
459
+ const g = a.transaction(j, "readonly").objectStore(j).get(h);
460
+ g.onsuccess = () => {
461
+ const v = g.result;
462
+ if (typeof v != "string") {
463
+ w(null);
464
+ return;
465
+ }
466
+ try {
467
+ w(x(v));
468
+ } catch {
469
+ w(null);
470
+ }
471
+ }, g.onerror = () => J(g.error ?? new Error("IndexedDB read failed"));
472
+ });
473
+ }, q = async (r, a) => {
474
+ const h = await I(), w = y(r), J = O(a);
475
+ return new Promise((B, g) => {
476
+ const v = h.transaction(j, "readwrite");
477
+ v.objectStore(j).put(J, w), v.oncomplete = () => B(), v.onerror = () => g(v.error ?? new Error("IndexedDB write failed")), v.onabort = () => g(v.error ?? new Error("IndexedDB write aborted"));
478
+ });
479
+ }, P = async (r) => {
480
+ if (typeof window > "u") return null;
481
+ if (d === "indexedDB" && "indexedDB" in window)
482
+ try {
483
+ return await H(r);
484
+ } catch {
485
+ return null;
486
+ }
487
+ try {
488
+ const a = window.localStorage.getItem(y(r));
489
+ return a ? x(a) : null;
490
+ } catch {
491
+ return null;
492
+ }
493
+ }, $ = (r) => {
494
+ if (typeof window > "u") return;
495
+ const a = R.get(r.$scopeId);
496
+ if (a) {
497
+ if (d === "indexedDB" && "indexedDB" in window) {
498
+ q(r, a).catch(() => {
499
+ });
500
+ return;
501
+ }
502
+ try {
503
+ window.localStorage.setItem(y(r), O(a));
504
+ } catch {
505
+ }
506
+ }
507
+ }, T = (r) => {
508
+ const a = r.$scopeId, h = N.get(a);
509
+ if (h && (clearTimeout(h), N.delete(a)), D <= 0) {
510
+ $(r);
511
+ return;
512
+ }
513
+ const w = setTimeout(() => {
514
+ N.delete(a), $(r);
515
+ }, D);
516
+ N.set(a, w);
517
+ }, M = (r) => {
518
+ const a = r.$scopeId, h = N.get(a);
519
+ h && (clearTimeout(h), N.delete(a)), $(r);
520
+ };
521
+ return {
522
+ name: "persist",
523
+ onInit(r) {
524
+ const a = r;
525
+ typeof window > "u" || z(a) && (async () => {
526
+ const h = await P(a);
527
+ h && (R.set(a.$scopeId, h), a.$patch(h, "remote"));
528
+ })();
529
+ },
530
+ onMutation(r, a) {
531
+ const h = r;
532
+ if (typeof window > "u" || !z(h)) return;
533
+ const w = R.get(h.$scopeId) ?? {};
534
+ w[a.key] = a.newValue, R.set(h.$scopeId, w), T(h);
535
+ },
536
+ onDispose(r) {
537
+ const a = r;
538
+ z(a) && M(a);
539
+ }
540
+ };
541
+ }
542
+ export {
543
+ lt as persistPlugin
544
+ };
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@storix-js/persist",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ }
14
+ },
15
+ "scripts": {
16
+ "build": "vite build && tsc -p tsconfig.build.json --emitDeclarationOnly",
17
+ "dev": "vite build --watch",
18
+ "test": "vitest run",
19
+ "typecheck": "tsc -p tsconfig.json --noEmit"
20
+ },
21
+ "dependencies": {
22
+ "@storix-js/core": "workspace:*"
23
+ }
24
+ }
package/src/index.ts ADDED
@@ -0,0 +1,210 @@
1
+ import { definePlugin } from '@storix-js/core';
2
+
3
+ type PersistStorage = 'localStorage' | 'indexedDB';
4
+
5
+ export interface IndexedDBPersistOptions {
6
+ dbName?: string;
7
+ storeName?: string;
8
+ }
9
+
10
+ export interface PersistPluginOptions {
11
+ keyPrefix?: string;
12
+ include?: string[];
13
+ storage?: PersistStorage;
14
+ serialize?: (value: Record<string, unknown>) => string;
15
+ deserialize?: (raw: string) => Record<string, unknown>;
16
+ debounce?: number;
17
+ indexedDB?: IndexedDBPersistOptions;
18
+ }
19
+
20
+ type ScopedStore = {
21
+ $id: string;
22
+ $namespace: string;
23
+ $scopeId: string;
24
+ $patch: (patch: Record<string, unknown>, origin?: 'local' | 'remote') => void;
25
+ };
26
+
27
+ export function persistPlugin(options: PersistPluginOptions = {}) {
28
+ const keyPrefix = options.keyPrefix ?? 'storix';
29
+ const include = new Set(options.include ?? []);
30
+ const storage = options.storage ?? 'localStorage';
31
+ const serialize = options.serialize ?? JSON.stringify;
32
+ const deserialize = options.deserialize ?? ((raw: string) => JSON.parse(raw) as Record<string, unknown>);
33
+ const debounceMs = options.debounce ?? 100;
34
+ const idbDatabaseName = options.indexedDB?.dbName ?? `${keyPrefix}-persist`;
35
+ const idbStoreName = options.indexedDB?.storeName ?? 'stores';
36
+
37
+ const cache = new Map<string, Record<string, unknown>>();
38
+ const timers = new Map<string, ReturnType<typeof setTimeout>>();
39
+
40
+ let dbPromise: Promise<IDBDatabase> | null = null;
41
+
42
+ const shouldPersistStore = (store: ScopedStore) => {
43
+ const ids = [store.$id, store.$scopeId];
44
+ if (include.size > 0 && !ids.some((value) => include.has(value))) return false;
45
+ return true;
46
+ };
47
+
48
+ const getKey = (store: ScopedStore) => `${keyPrefix}:${store.$namespace}:${store.$id}`;
49
+
50
+ const getDb = () => {
51
+ if (dbPromise) return dbPromise;
52
+
53
+ dbPromise = new Promise<IDBDatabase>((resolve, reject) => {
54
+ const request = window.indexedDB.open(idbDatabaseName, 1);
55
+ request.onupgradeneeded = () => {
56
+ const db = request.result;
57
+ if (!db.objectStoreNames.contains(idbStoreName)) {
58
+ db.createObjectStore(idbStoreName);
59
+ }
60
+ };
61
+ request.onsuccess = () => resolve(request.result);
62
+ request.onerror = () => reject(request.error ?? new Error('IndexedDB open failed'));
63
+ });
64
+
65
+ return dbPromise;
66
+ };
67
+
68
+ const readFromIndexedDb = async (store: ScopedStore) => {
69
+ const db = await getDb();
70
+ const key = getKey(store);
71
+
72
+ return new Promise<Record<string, unknown> | null>((resolve, reject) => {
73
+ const tx = db.transaction(idbStoreName, 'readonly');
74
+ const req = tx.objectStore(idbStoreName).get(key);
75
+
76
+ req.onsuccess = () => {
77
+ const result = req.result;
78
+ if (typeof result !== 'string') {
79
+ resolve(null);
80
+ return;
81
+ }
82
+
83
+ try {
84
+ resolve(deserialize(result));
85
+ } catch {
86
+ resolve(null);
87
+ }
88
+ };
89
+
90
+ req.onerror = () => reject(req.error ?? new Error('IndexedDB read failed'));
91
+ });
92
+ };
93
+
94
+ const writeToIndexedDb = async (store: ScopedStore, value: Record<string, unknown>) => {
95
+ const db = await getDb();
96
+ const key = getKey(store);
97
+ const raw = serialize(value);
98
+
99
+ return new Promise<void>((resolve, reject) => {
100
+ const tx = db.transaction(idbStoreName, 'readwrite');
101
+ tx.objectStore(idbStoreName).put(raw, key);
102
+
103
+ tx.oncomplete = () => resolve();
104
+ tx.onerror = () => reject(tx.error ?? new Error('IndexedDB write failed'));
105
+ tx.onabort = () => reject(tx.error ?? new Error('IndexedDB write aborted'));
106
+ });
107
+ };
108
+
109
+ const readSnapshot = async (store: ScopedStore) => {
110
+ if (typeof window === 'undefined') return null;
111
+
112
+ if (storage === 'indexedDB' && 'indexedDB' in window) {
113
+ try {
114
+ return await readFromIndexedDb(store);
115
+ } catch {
116
+ return null;
117
+ }
118
+ }
119
+
120
+ try {
121
+ const raw = window.localStorage.getItem(getKey(store));
122
+ if (!raw) return null;
123
+ return deserialize(raw);
124
+ } catch {
125
+ return null;
126
+ }
127
+ };
128
+
129
+ const writeSnapshot = (store: ScopedStore) => {
130
+ if (typeof window === 'undefined') return;
131
+
132
+ const snapshot = cache.get(store.$scopeId);
133
+ if (!snapshot) return;
134
+
135
+ if (storage === 'indexedDB' && 'indexedDB' in window) {
136
+ void writeToIndexedDb(store, snapshot).catch(() => {
137
+ // noop
138
+ });
139
+ return;
140
+ }
141
+
142
+ try {
143
+ window.localStorage.setItem(getKey(store), serialize(snapshot));
144
+ } catch {
145
+ // noop
146
+ }
147
+ };
148
+
149
+ const scheduleWrite = (store: ScopedStore) => {
150
+ const timerKey = store.$scopeId;
151
+ const existing = timers.get(timerKey);
152
+ if (existing) {
153
+ clearTimeout(existing);
154
+ timers.delete(timerKey);
155
+ }
156
+
157
+ if (debounceMs <= 0) {
158
+ writeSnapshot(store);
159
+ return;
160
+ }
161
+
162
+ const timer = setTimeout(() => {
163
+ timers.delete(timerKey);
164
+ writeSnapshot(store);
165
+ }, debounceMs);
166
+
167
+ timers.set(timerKey, timer);
168
+ };
169
+
170
+ const flush = (store: ScopedStore) => {
171
+ const timerKey = store.$scopeId;
172
+ const timer = timers.get(timerKey);
173
+ if (timer) {
174
+ clearTimeout(timer);
175
+ timers.delete(timerKey);
176
+ }
177
+ writeSnapshot(store);
178
+ };
179
+
180
+ return definePlugin({
181
+ name: 'persist',
182
+ onInit(store) {
183
+ const scopedStore = store as ScopedStore;
184
+ if (typeof window === 'undefined') return;
185
+ if (!shouldPersistStore(scopedStore)) return;
186
+
187
+ void (async () => {
188
+ const snapshot = await readSnapshot(scopedStore);
189
+ if (!snapshot) return;
190
+ cache.set(scopedStore.$scopeId, snapshot);
191
+ scopedStore.$patch(snapshot, 'remote');
192
+ })();
193
+ },
194
+ onMutation(store, mutation) {
195
+ const scopedStore = store as ScopedStore;
196
+ if (typeof window === 'undefined') return;
197
+ if (!shouldPersistStore(scopedStore)) return;
198
+
199
+ const snapshot = cache.get(scopedStore.$scopeId) ?? {};
200
+ snapshot[mutation.key] = mutation.newValue;
201
+ cache.set(scopedStore.$scopeId, snapshot);
202
+ scheduleWrite(scopedStore);
203
+ },
204
+ onDispose(store) {
205
+ const scopedStore = store as ScopedStore;
206
+ if (!shouldPersistStore(scopedStore)) return;
207
+ flush(scopedStore);
208
+ }
209
+ });
210
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist",
6
+ "paths": {}
7
+ }
8
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "include": ["src"]
4
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { defineConfig } from 'vite';
2
+
3
+ export default defineConfig({
4
+ build: {
5
+ lib: {
6
+ entry: 'src/index.ts',
7
+ name: 'StorixPersist',
8
+ fileName: 'index',
9
+ formats: ['es', 'cjs']
10
+ }
11
+ },
12
+ test: {
13
+ environment: 'node'
14
+ }
15
+ });