@biglogic/rgs 2.9.3 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -8
- package/SECURITY.md +10 -0
- package/advanced.js +1 -1
- package/core/types.d.ts +22 -1
- package/core/utils.d.ts +2 -0
- package/examples/README.md +41 -0
- package/examples/async-data-fetch/UserLoader.d.ts +12 -0
- package/examples/async-data-fetch/UserLoader.ts +30 -0
- package/examples/basic-counter/CounterComponent.d.ts +2 -0
- package/examples/basic-counter/CounterComponent.tsx +22 -0
- package/examples/basic-counter/CounterStore.d.ts +7 -0
- package/examples/basic-counter/CounterStore.ts +25 -0
- package/examples/big-data-indexeddb/BigDataStore.d.ts +10 -0
- package/examples/big-data-indexeddb/BigDataStore.ts +60 -0
- package/examples/global-theme/ThemeManager.d.ts +7 -0
- package/examples/global-theme/ThemeManager.ts +32 -0
- package/examples/hybrid-cloud-sync/HybridStore.d.ts +19 -0
- package/examples/hybrid-cloud-sync/HybridStore.ts +78 -0
- package/examples/persistent-cart/CartStore.d.ts +13 -0
- package/examples/persistent-cart/CartStore.ts +41 -0
- package/examples/rbac-dashboard/DashboardStore.d.ts +47 -0
- package/examples/rbac-dashboard/DashboardStore.ts +46 -0
- package/examples/secure-auth/AuthStore.d.ts +14 -0
- package/examples/secure-auth/AuthStore.ts +36 -0
- package/examples/security-best-practices/SecurityStore.d.ts +22 -0
- package/examples/security-best-practices/SecurityStore.ts +75 -0
- package/examples/stress-tests/StressStore.d.ts +41 -0
- package/examples/stress-tests/StressStore.ts +61 -0
- package/examples/super-easy/EasyStore.d.ts +44 -0
- package/examples/super-easy/EasyStore.ts +61 -0
- package/examples/undo-redo-editor/EditorStore.d.ts +9 -0
- package/examples/undo-redo-editor/EditorStore.ts +28 -0
- package/index.d.ts +3 -2
- package/index.js +1 -1
- package/markdown/SUMMARY.md +4 -0
- package/markdown/api.md +40 -1
- package/markdown/chapters/03-the-magnetar-way.md +10 -3
- package/markdown/chapters/04-persistence-and-safety.md +46 -5
- package/markdown/chapters/05-plugins-and-extensibility.md +24 -8
- package/markdown/chapters/06-case-studies.md +69 -69
- package/markdown/chapters/08-migration-guide.md +48 -1
- package/markdown/chapters/09-security-architecture.md +40 -0
- package/package.json +84 -79
- package/plugins/index.d.ts +4 -2
- package/plugins/official/cloud-sync.plugin.d.ts +22 -0
- package/plugins/official/immer.plugin.d.ts +1 -1
- package/plugins/official/indexeddb.plugin.d.ts +7 -0
- package/plugins/official/undo-redo.plugin.d.ts +2 -2
- package/rgs-highlighter-2.9.5.vsix +0 -0
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ Best for modern applications. Clean imports, zero global pollution.
|
|
|
101
101
|
```tsx
|
|
102
102
|
import { gstate } from '@biglogic/rgs'
|
|
103
103
|
|
|
104
|
-
// gstate
|
|
104
|
+
// gstate CREATES a custom hook - it is NOT imported!
|
|
105
105
|
const useCounter = gstate({ count: 0 })
|
|
106
106
|
|
|
107
107
|
// In your component
|
|
@@ -125,10 +125,8 @@ const [user, setUser] = useStore('user')
|
|
|
125
125
|
|
|
126
126
|
## 📚 Quick Examples
|
|
127
127
|
|
|
128
|
-
### Persistence
|
|
129
|
-
|
|
130
128
|
```tsx
|
|
131
|
-
const store = gstate({ theme: 'dark' },
|
|
129
|
+
const store = gstate({ theme: 'dark' }, "my-app")
|
|
132
130
|
```
|
|
133
131
|
|
|
134
132
|
### Encryption
|
|
@@ -154,16 +152,39 @@ const store = gstate({ theme: 'light' })
|
|
|
154
152
|
store._addPlugin(syncPlugin({ channelName: 'my-app' }))
|
|
155
153
|
```
|
|
156
154
|
|
|
157
|
-
### Computed Values
|
|
158
|
-
|
|
159
155
|
```tsx
|
|
160
156
|
const store = gstate({ firstName: 'John', lastName: 'Doe' })
|
|
161
|
-
store.compute('fullName',
|
|
162
|
-
(s) => `${s.firstName} ${s.lastName}`)
|
|
157
|
+
store.compute('fullName', (get) => `${get('firstName')} ${get('lastName')}`)
|
|
163
158
|
|
|
164
159
|
const [fullName] = store('fullName') // "John Doe"
|
|
165
160
|
```
|
|
166
161
|
|
|
162
|
+
### Error Handling with onError
|
|
163
|
+
|
|
164
|
+
Handle errors gracefully with the `onError` callback - perfect for production apps:
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
const store = gstate({ data: null }, {
|
|
168
|
+
onError: (error, context) => {
|
|
169
|
+
console.error(`Error in ${context.operation}:`, error.message)
|
|
170
|
+
// Send to error tracking service (Sentry, etc.)
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Size Limits (maxObjectSize & maxTotalSize)
|
|
176
|
+
|
|
177
|
+
Protect your app from memory issues with automatic size warnings:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
const store = gstate({ data: {} }, {
|
|
181
|
+
// Warn if single value exceeds 5MB (default)
|
|
182
|
+
maxObjectSize: 5 * 1024 * 1024,
|
|
183
|
+
// Warn if total store exceeds 50MB (default)
|
|
184
|
+
maxTotalSize: 50 * 1024 * 1024
|
|
185
|
+
})
|
|
186
|
+
```
|
|
187
|
+
|
|
167
188
|
---
|
|
168
189
|
|
|
169
190
|
## Multiple Stores
|
package/SECURITY.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
1
|
# Security
|
|
2
2
|
|
|
3
|
+
React Globo State (RGS) implements enterprise-grade security including AES-256-GCM encryption, RBAC, and internal XSS sanitization as a secondary defense layer.
|
|
4
|
+
|
|
5
|
+
## Reporting a Vulnerability
|
|
6
|
+
|
|
3
7
|
Please email [@passariello](https://github.com/passariello) or see <https://dario.passariello.ca/contact/> if you have a potential security vulnerability to report.
|
|
8
|
+
|
|
9
|
+
## Recent Hardening (v2.9.5)
|
|
10
|
+
|
|
11
|
+
- Improved XSS sanitization patterns to block `data:`, `vbscript:`, and complex HTML tag combinations.
|
|
12
|
+
- Implemented removal of HTML entity obfuscation.
|
|
13
|
+
- Enhanced deep cloning to support `Map`/`Set` and circular references.
|
package/advanced.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var Lt=Object.defineProperty;var At=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),Jt=(e,t)=>{for(var r in t)Lt(e,r,{get:t[r],enumerable:!0})};var Wt=At((Or,Nt)=>{"use strict";var ht=Object.defineProperty,Xt=Object.getOwnPropertyDescriptor,Zt=Object.getOwnPropertyNames,Yt=Object.prototype.hasOwnProperty,er=(e,t)=>{for(var r in t)ht(e,r,{get:t[r],enumerable:!0})},tr=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Zt(t))!Yt.call(e,s)&&s!==r&&ht(e,s,{get:()=>t[s],enumerable:!(n=Xt(t,s))||n.enumerable});return e},rr=e=>tr(ht({},"__esModule",{value:!0}),e),Rt={};er(Rt,{Immer:()=>Vt,applyPatches:()=>Cr,castDraft:()=>_r,castImmutable:()=>Pr,createDraft:()=>Er,current:()=>Ut,enableArrayMethods:()=>Sr,enableMapSet:()=>mr,enablePatches:()=>yr,finishDraft:()=>Mr,freeze:()=>Ke,immerable:()=>se,isDraft:()=>L,isDraftable:()=>K,nothing:()=>Fe,original:()=>or,produce:()=>wr,produceWithPatches:()=>br,setAutoFreeze:()=>vr,setUseStrictIteration:()=>xr,setUseStrictShallowCopy:()=>Ar});Nt.exports=rr(Rt);var Fe=Symbol.for("immer-nothing"),se=Symbol.for("immer-draftable"),E=Symbol.for("immer-state");function T(e,...t){throw new Error(`[Immer] minified error nr: ${e}. Full error at: https://bit.ly/3cXEKWf`)}var F=Object,re=F.getPrototypeOf,ge="constructor",be="prototype",ut="configurable",ze="enumerable",De="writable",he="value",L=e=>!!e&&!!e[E];function K(e){return e?It(e)||ve(e)||!!e[se]||!!e[ge]?.[se]||Ae(e)||xe(e):!1}var nr=F[be][ge].toString(),Ct=new WeakMap;function It(e){if(!e||!ie(e))return!1;let t=re(e);if(t===null||t===F[be])return!0;let r=F.hasOwnProperty.call(t,ge)&&t[ge];if(r===Object)return!0;if(!te(r))return!1;let n=Ct.get(r);return n===void 0&&(n=Function.toString.call(r),Ct.set(r,n)),n===nr}function or(e){return L(e)||T(15,e),e[E].t}function ae(e,t,r=!0){ne(e)===0?(r?Reflect.ownKeys(e):F.keys(e)).forEach(n=>{t(n,e[n],e)}):e.forEach((n,s)=>t(s,n,e))}function ne(e){let t=e[E];return t?t.r:ve(e)?1:Ae(e)?2:xe(e)?3:0}var pe=(e,t,r=ne(e))=>r===2?e.has(t):F[be].hasOwnProperty.call(e,t),X=(e,t,r=ne(e))=>r===2?e.get(t):e[t],je=(e,t,r,n=ne(e))=>{n===2?e.set(t,r):n===3?e.add(r):e[t]=r};function sr(e,t){return e===t?e!==0||1/e===1/t:e!==e&&t!==t}var ve=Array.isArray,Ae=e=>e instanceof Map,xe=e=>e instanceof Set,ie=e=>typeof e=="object",te=e=>typeof e=="function",lt=e=>typeof e=="boolean";function ir(e){let t=+e;return Number.isInteger(t)&&String(t)===e}var Ot=e=>ie(e)?e?.[E]:null,z=e=>e.e||e.t,ar=e=>{let t=Ot(e);return t?t.e??t.t:e},yt=e=>e.s?e.e:e.t;function ft(e,t){if(Ae(e))return new Map(e);if(xe(e))return new Set(e);if(ve(e))return Array[be].slice.call(e);let r=It(e);if(t===!0||t==="class_only"&&!r){let n=F.getOwnPropertyDescriptors(e);delete n[E];let s=Reflect.ownKeys(n);for(let l=0;l<s.length;l++){let g=s[l],x=n[g];x[De]===!1&&(x[De]=!0,x[ut]=!0),(x.get||x.set)&&(n[g]={[ut]:!0,[De]:!0,[ze]:x[ze],[he]:e[g]})}return F.create(re(e),n)}else{let n=re(e);if(n!==null&&r)return{...e};let s=F.create(n);return F.assign(s,e)}}function Ke(e,t=!1){return Be(e)||L(e)||!K(e)||(ne(e)>1&&F.defineProperties(e,{set:Oe,add:Oe,clear:Oe,delete:Oe}),F.freeze(e),t&&ae(e,(r,n)=>{Ke(n,!0)},!1)),e}function lr(){T(2)}var Oe={[he]:lr};function Be(e){return e===null||!ie(e)?!0:F.isFrozen(e)}var ye="MapSet",Te="Patches",pt="ArrayMethods",Ve={};function oe(e){let t=Ve[e];return t||T(0,e),t}var Et=e=>!!Ve[e];function mt(e,t){Ve[e]||(Ve[e]=t)}var me,Ue=()=>me,cr=(e,t)=>({o:[],i:e,l:t,F:!0,m:0,P:new Set,T:new Set,I:Et(ye)?oe(ye):void 0,E:Et(pt)?oe(pt):void 0});function Mt(e,t){t&&(e.x=oe(Te),e.y=[],e.d=[],e.C=t)}function dt(e){gt(e),e.o.forEach(ur),e.o=null}function gt(e){e===me&&(me=e.i)}var _t=e=>me=cr(me,e);function ur(e){let t=e[E];t.r===0||t.r===1?t.b():t.g=!0}function Pt(e,t){t.m=t.o.length;let r=t.o[0];if(e!==void 0&&e!==r){r[E].s&&(dt(t),T(4)),K(e)&&(e=kt(t,e));let{x:n}=t;n&&n.M(r[E].t,e,t)}else e=kt(t,r);return fr(t,e,!0),dt(t),t.y&&t.C(t.y,t.d),e!==Fe?e:void 0}function kt(e,t){if(Be(t))return t;let r=t[E];if(!r)return Ne(t,e.P,e);if(!Le(r,e))return t;if(!r.s)return r.t;if(!r.u){let{f:n}=r;if(n)for(;n.length>0;)n.pop()(e);jt(r,e)}return r.e}function fr(e,t,r=!1){!e.i&&e.l.h&&e.F&&Ke(t,r)}function Dt(e){e.u=!0,e.a.m--}var Le=(e,t)=>e.a===t,pr=[];function zt(e,t,r,n){let s=z(e),l=e.r;if(n!==void 0&&X(s,n,l)===t){je(s,n,r,l);return}if(!e.D){let x=e.D=new Map;ae(s,(v,a)=>{if(L(a)){let u=x.get(a)||[];u.push(v),x.set(a,u)}})}let g=e.D.get(t)??pr;for(let x of g)je(s,x,r,l)}function dr(e,t,r){e.f.push(function(n){let s=t;if(!s||!Le(s,n))return;n.I?.fixSetContents(s);let l=yt(s);zt(e,s.c??s,l,r),jt(s,n)})}function jt(e,t){if(e.s&&!e.u&&(e.r===3||e.r===1&&e.R||(e.n?.size??0)>0)){let{x:r}=t;if(r){let n=r.getPath(e);n&&r.O(e,n,t)}Dt(e)}}function $e(e,t,r){let{a:n}=e;if(L(r)){let s=r[E];Le(s,n)&&s.f.push(function(){de(e);let l=yt(s);zt(e,r,l,t)})}else K(r)&&e.f.push(function(){let s=z(e);e.r===3?s.has(r)&&Ne(r,n.P,n):X(s,t,e.r)===r&&n.o.length>1&&(e.n.get(t)??!1)===!0&&e.e&&Ne(X(e.e,t,e.r),n.P,n)})}function Ne(e,t,r){return!r.l.h&&r.m<1||L(e)||t.has(e)||!K(e)||Be(e)||(t.add(e),ae(e,(n,s)=>{if(L(s)){let l=s[E];if(Le(l,r)){let g=yt(l);je(e,n,g,e.r),Dt(l)}}else K(s)&&Ne(s,t,r)})),e}function gr(e,t){let r=ve(e),n={r:r?1:0,a:t?t.a:Ue(),s:!1,u:!1,n:void 0,i:t,t:e,c:null,e:null,b:null,S:!1,f:void 0},s=n,l=We;r&&(s=[n],l=Se);let{revoke:g,proxy:x}=Proxy.revocable(s,l);return n.c=x,n.b=g,[x,n]}var We={get(e,t){if(t===E)return e;let r=e.a.E,n=e.r===1&&typeof t=="string";if(n&&r?.isArrayOperationMethod(t))return r.createMethodInterceptor(e,t);let s=z(e);if(!pe(s,t,e.r))return hr(e,s,t);let l=s[t];if(e.u||!K(l)||n&&e.operationMethod&&r?.isMutatingArrayMethod(e.operationMethod)&&ir(t))return l;if(l===ct(e.t,t)){de(e);let g=e.r===1?+t:t,x=we(e.a,l,e,g);return e.e[g]=x}return l},has(e,t){return t in z(e)},ownKeys(e){return Reflect.ownKeys(z(e))},set(e,t,r){let n=Tt(z(e),t);if(n?.set)return n.set.call(e.c,r),!0;if(!e.s){let s=ct(z(e),t),l=s?.[E];if(l&&l.t===r)return e.e[t]=r,e.n.set(t,!1),!0;if(sr(r,s)&&(r!==void 0||pe(e.t,t,e.r)))return!0;de(e),H(e)}return e.e[t]===r&&(r!==void 0||t in e.e)||Number.isNaN(r)&&Number.isNaN(e.e[t])||(e.e[t]=r,e.n.set(t,!0),$e(e,t,r)),!0},deleteProperty(e,t){return de(e),ct(e.t,t)!==void 0||t in e.t?(e.n.set(t,!1),H(e)):e.n.delete(t),e.e&&delete e.e[t],!0},getOwnPropertyDescriptor(e,t){let r=z(e),n=Reflect.getOwnPropertyDescriptor(r,t);return n&&{[De]:!0,[ut]:e.r!==1||t!=="length",[ze]:n[ze],[he]:r[t]}},defineProperty(){T(11)},getPrototypeOf(e){return re(e.t)},setPrototypeOf(){T(12)}},Se={};for(let e in We){let t=We[e];Se[e]=function(){let r=arguments;return r[0]=r[0][0],t.apply(this,r)}}Se.deleteProperty=function(e,t){return Se.set.call(this,e,t,void 0)};Se.set=function(e,t,r){return We.set.call(this,e[0],t,r,e[0])};function ct(e,t){let r=e[E];return(r?z(r):e)[t]}function hr(e,t,r){let n=Tt(t,r);return n?he in n?n[he]:n.get?.call(e.c):void 0}function Tt(e,t){if(!(t in e))return;let r=re(e);for(;r;){let n=Object.getOwnPropertyDescriptor(r,t);if(n)return n;r=re(r)}}function H(e){e.s||(e.s=!0,e.i&&H(e.i))}function de(e){e.e||(e.n=new Map,e.e=ft(e.t,e.a.l.A))}var Vt=class{constructor(e){this.h=!0,this.A=!1,this._=!1,this.produce=(t,r,n)=>{if(te(t)&&!te(r)){let l=r;r=t;let g=this;return function(x=l,...v){return g.produce(x,a=>r.call(this,a,...v))}}te(r)||T(6),n!==void 0&&!te(n)&&T(7);let s;if(K(t)){let l=_t(this),g=we(l,t,void 0),x=!0;try{s=r(g),x=!1}finally{x?dt(l):gt(l)}return Mt(l,n),Pt(s,l)}else if(!t||!ie(t)){if(s=r(t),s===void 0&&(s=t),s===Fe&&(s=void 0),this.h&&Ke(s,!0),n){let l=[],g=[];oe(Te).M(t,s,{y:l,d:g}),n(l,g)}return s}else T(1,t)},this.produceWithPatches=(t,r)=>{if(te(t))return(l,...g)=>this.produceWithPatches(l,x=>t(x,...g));let n,s;return[this.produce(t,r,(l,g)=>{n=l,s=g}),n,s]},lt(e?.autoFreeze)&&this.setAutoFreeze(e.autoFreeze),lt(e?.useStrictShallowCopy)&&this.setUseStrictShallowCopy(e.useStrictShallowCopy),lt(e?.useStrictIteration)&&this.setUseStrictIteration(e.useStrictIteration)}createDraft(e){K(e)||T(8),L(e)&&(e=Ut(e));let t=_t(this),r=we(t,e,void 0);return r[E].S=!0,gt(t),r}finishDraft(e,t){let r=e&&e[E];(!r||!r.S)&&T(9);let{a:n}=r;return Mt(n,t),Pt(void 0,n)}setAutoFreeze(e){this.h=e}setUseStrictShallowCopy(e){this.A=e}setUseStrictIteration(e){this._=e}shouldUseStrictIteration(){return this._}applyPatches(e,t){let r;for(r=t.length-1;r>=0;r--){let s=t[r];if(s.path.length===0&&s.op==="replace"){e=s.value;break}}r>-1&&(t=t.slice(r+1));let n=oe(Te).N;return L(e)?n(e,t):this.produce(e,s=>n(s,t))}};function we(e,t,r,n){let[s,l]=Ae(t)?oe(ye).w(t,r):xe(t)?oe(ye).V(t,r):gr(t,r);return(r?.a??Ue()).o.push(s),l.f=r?.f??[],l.p=n,r&&n!==void 0?dr(r,l,n):l.f.push(function(g){g.I?.fixSetContents(l);let{x}=g;l.s&&x&&x.O(l,[],g)}),s}function Ut(e){return L(e)||T(10,e),$t(e)}function $t(e){if(!K(e)||Be(e))return e;let t=e[E],r,n=!0;if(t){if(!t.s)return t.t;t.u=!0,r=ft(e,t.a.l.A),n=t.a.l.shouldUseStrictIteration()}else r=ft(e,!0);return ae(r,(s,l)=>{je(r,s,$t(l))},n),t&&(t.u=!1),r}function yr(){function e(p,S=[]){if(p.p!==void 0){let C=p.i.e??p.i.t,m=Ot(X(C,p.p)),R=X(C,p.p);if(R===void 0||R!==p.c&&R!==p.t&&R!==p.e||m!=null&&m.t!==p.t)return null;let I=p.i.r===3,A;if(I){let i=p.i;A=Array.from(i.o.keys()).indexOf(p.p)}else A=p.p;if(!(I&&C.size>A||pe(C,A)))return null;S.push(A)}if(p.i)return e(p.i,S);S.reverse();try{t(p.e,S)}catch{return null}return S}function t(p,S){let C=p;for(let m=0;m<S.length-1;m++){let R=S[m];if(C=X(C,R),!ie(C)||C===null)throw new Error(`Cannot resolve path at '${S.join("/")}'`)}return C}let r="replace",n="add",s="remove";function l(p,S,C){if(p.a.T.has(p))return;p.a.T.add(p);let{y:m,d:R}=C;switch(p.r){case 0:case 2:return x(p,S,m,R);case 1:return g(p,S,m,R);case 3:return v(p,S,m,R)}}function g(p,S,C,m){let{t:R,n:I}=p,A=p.e;A.length<R.length&&([R,A]=[A,R],[C,m]=[m,C]);let i=p.R===!0;for(let d=0;d<R.length;d++){let h=A[d],w=R[d];if((i||I?.get(d.toString()))&&h!==w){let _=h?.[E];if(_&&_.s)continue;let j=S.concat([d]);C.push({op:r,path:j,value:D(h)}),m.push({op:r,path:j,value:D(w)})}}for(let d=R.length;d<A.length;d++){let h=S.concat([d]);C.push({op:n,path:h,value:D(A[d])})}for(let d=A.length-1;R.length<=d;--d){let h=S.concat([d]);m.push({op:s,path:h})}}function x(p,S,C,m){let{t:R,e:I,r:A}=p;ae(p.n,(i,d)=>{let h=X(R,i,A),w=X(I,i,A),_=d?pe(R,i)?r:n:s;if(h===w&&_===r)return;let j=S.concat(i);C.push(_===s?{op:_,path:j}:{op:_,path:j,value:D(w)}),m.push(_===n?{op:s,path:j}:_===s?{op:n,path:j,value:D(h)}:{op:r,path:j,value:D(h)})})}function v(p,S,C,m){let{t:R,e:I}=p,A=0;R.forEach(i=>{if(!I.has(i)){let d=S.concat([A]);C.push({op:s,path:d,value:i}),m.unshift({op:n,path:d,value:i})}A++}),A=0,I.forEach(i=>{if(!R.has(i)){let d=S.concat([A]);C.push({op:n,path:d,value:i}),m.unshift({op:s,path:d,value:i})}A++})}function a(p,S,C){let{y:m,d:R}=C;m.push({op:r,path:[],value:S===Fe?void 0:S}),R.push({op:r,path:[],value:p})}function u(p,S){return S.forEach(C=>{let{path:m,op:R}=C,I=p;for(let h=0;h<m.length-1;h++){let w=ne(I),_=m[h];typeof _!="string"&&typeof _!="number"&&(_=""+_),(w===0||w===1)&&(_==="__proto__"||_===ge)&&T(19),te(I)&&_===be&&T(19),I=X(I,_),ie(I)||T(18,m.join("/"))}let A=ne(I),i=M(C.value),d=m[m.length-1];switch(R){case r:switch(A){case 2:return I.set(d,i);case 3:T(16);default:return I[d]=i}case n:switch(A){case 1:return d==="-"?I.push(i):I.splice(d,0,i);case 2:return I.set(d,i);case 3:return I.add(i);default:return I[d]=i}case s:switch(A){case 1:return I.splice(d,1);case 2:return I.delete(d);case 3:return I.delete(C.value);default:return delete I[d]}default:T(17,R)}}),p}function M(p){if(!K(p))return p;if(ve(p))return p.map(M);if(Ae(p))return new Map(Array.from(p.entries()).map(([C,m])=>[C,M(m)]));if(xe(p))return new Set(Array.from(p).map(M));let S=Object.create(re(p));for(let C in p)S[C]=M(p[C]);return pe(p,se)&&(S[se]=p[se]),S}function D(p){return L(p)?M(p):p}mt(Te,{N:u,O:l,M:a,getPath:e})}function mr(){class e extends Map{constructor(a,u){super(),this[E]={r:2,i:u,a:u?u.a:Ue(),s:!1,u:!1,e:void 0,n:void 0,t:a,c:this,S:!1,g:!1,f:[]}}get size(){return z(this[E]).size}has(a){return z(this[E]).has(a)}set(a,u){let M=this[E];return g(M),(!z(M).has(a)||z(M).get(a)!==u)&&(r(M),H(M),M.n.set(a,!0),M.e.set(a,u),M.n.set(a,!0),$e(M,a,u)),this}delete(a){if(!this.has(a))return!1;let u=this[E];return g(u),r(u),H(u),u.t.has(a)?u.n.set(a,!1):u.n.delete(a),u.e.delete(a),!0}clear(){let a=this[E];g(a),z(a).size&&(r(a),H(a),a.n=new Map,ae(a.t,u=>{a.n.set(u,!1)}),a.e.clear())}forEach(a,u){let M=this[E];z(M).forEach((D,p,S)=>{a.call(u,this.get(p),p,this)})}get(a){let u=this[E];g(u);let M=z(u).get(a);if(u.u||!K(M)||M!==u.t.get(a))return M;let D=we(u.a,M,u,a);return r(u),u.e.set(a,D),D}keys(){return z(this[E]).keys()}values(){let a=this.keys();return{[Symbol.iterator]:()=>this.values(),next:()=>{let u=a.next();return u.done?u:{done:!1,value:this.get(u.value)}}}}entries(){let a=this.keys();return{[Symbol.iterator]:()=>this.entries(),next:()=>{let u=a.next();if(u.done)return u;let M=this.get(u.value);return{done:!1,value:[u.value,M]}}}}[Symbol.iterator](){return this.entries()}}function t(v,a){let u=new e(v,a);return[u,u[E]]}function r(v){v.e||(v.n=new Map,v.e=new Map(v.t))}class n extends Set{constructor(a,u){super(),this[E]={r:3,i:u,a:u?u.a:Ue(),s:!1,u:!1,e:void 0,t:a,c:this,o:new Map,g:!1,S:!1,n:void 0,f:[]}}get size(){return z(this[E]).size}has(a){let u=this[E];return g(u),u.e?!!(u.e.has(a)||u.o.has(a)&&u.e.has(u.o.get(a))):u.t.has(a)}add(a){let u=this[E];return g(u),this.has(a)||(l(u),H(u),u.e.add(a),$e(u,a,a)),this}delete(a){if(!this.has(a))return!1;let u=this[E];return g(u),l(u),H(u),u.e.delete(a)||(u.o.has(a)?u.e.delete(u.o.get(a)):!1)}clear(){let a=this[E];g(a),z(a).size&&(l(a),H(a),a.e.clear())}values(){let a=this[E];return g(a),l(a),a.e.values()}entries(){let a=this[E];return g(a),l(a),a.e.entries()}keys(){return this.values()}[Symbol.iterator](){return this.values()}forEach(a,u){let M=this.values(),D=M.next();for(;!D.done;)a.call(u,D.value,D.value,this),D=M.next()}}function s(v,a){let u=new n(v,a);return[u,u[E]]}function l(v){v.e||(v.e=new Set,v.t.forEach(a=>{if(K(a)){let u=we(v.a,a,v,a);v.o.set(a,u),v.e.add(u)}else v.e.add(a)}))}function g(v){v.g&&T(3,JSON.stringify(z(v)))}function x(v){if(v.r===3&&v.e){let a=new Set(v.e);v.e.clear(),a.forEach(u=>{v.e.add(ar(u))})}}mt(ye,{w:t,V:s,fixSetContents:x})}function Sr(){let e=new Set(["shift","unshift"]),t=new Set(["push","pop"]),r=new Set([...t,...e]),n=new Set(["reverse","sort"]),s=new Set([...r,...n,"splice"]),l=new Set(["find","findLast"]),g=new Set(["filter","slice","concat","flat",...l,"findIndex","findLastIndex","some","every","indexOf","lastIndexOf","includes","join","toString","toLocaleString"]);function x(i){return s.has(i)}function v(i){return g.has(i)}function a(i){return x(i)||v(i)}function u(i,d){i.operationMethod=d}function M(i){i.operationMethod=void 0}function D(i,d,h=!0){de(i);let w=d();return H(i),h&&i.n.set("length",!0),w}function p(i){i.R=!0}function S(i,d){return i<0?Math.max(d+i,0):Math.min(i,d)}function C(i,d,h){for(let w=0;w<h.length;w++){let _=d+w;i.n.set(_,!0),$e(i,_,h[w])}}function m(i,d,h){return D(i,()=>{let w=i.e.length,_=i.e[d](...h);return e.has(d)&&p(i),d==="push"&&h.length>0?C(i,w,h):d==="unshift"&&h.length>0&&C(i,0,h),r.has(d)?_:i.c})}function R(i,d,h){return D(i,()=>(i.e[d](...h),p(i),i.c),!1)}function I(i,d){return function(...h){let w=d;u(i,w);try{if(x(w)){if(r.has(w))return m(i,w,h);if(n.has(w))return R(i,w,h);if(w==="splice"){let _=D(i,()=>i.e.splice(...h));if(p(i),h.length>2){let j=S(h[0]??0,i.e.length);C(i,j,h.slice(2))}return _}}else return A(i,w,h)}finally{M(i)}}}function A(i,d,h){let w=z(i);if(d==="filter"){let _=h[0],j=[];for(let N=0;N<w.length;N++)_(w[N],N,w)&&j.push(i.c[N]);return j}if(l.has(d)){let _=h[0],j=d==="find",N=j?1:-1,J=j?0:w.length-1;for(let W=J;W>=0&&W<w.length;W+=N)if(_(w[W],W,w))return i.c[W];return}if(d==="slice"){let _=h[0]??0,j=h[1]??w.length,N=S(_,w.length),J=S(j,w.length),W=[];for(let Z=N;Z<J;Z++)W.push(i.c[Z]);return W}return w[d](...h)}mt(pt,{createMethodInterceptor:I,isArrayOperationMethod:a,isMutatingArrayMethod:x})}var $=new Vt,wr=$.produce,br=$.produceWithPatches.bind($),vr=$.setAutoFreeze.bind($),Ar=$.setUseStrictShallowCopy.bind($),xr=$.setUseStrictIteration.bind($),Cr=$.applyPatches.bind($),Er=$.createDraft.bind($),Mr=$.finishDraft.bind($),_r=e=>e,Pr=e=>e});var Kt=At((zr,Ft)=>{"use strict";Ft.exports=Wt()});var at={};Jt(at,{addAccessRule:()=>Re,decrypt:()=>Ye,deleteUserData:()=>it,encrypt:()=>Ze,exportKey:()=>Ht,exportUserData:()=>st,generateEncryptionKey:()=>Gt,getConsents:()=>ot,hasConsent:()=>rt,hasPermission:()=>fe,importKey:()=>qt,isAuditActive:()=>et,isCryptoAvailable:()=>xt,logAudit:()=>ue,recordConsent:()=>Ie,revokeConsent:()=>nt,sanitizeValue:()=>ce,setAuditLogger:()=>Qt,validateKey:()=>tt});var xt=typeof crypto<"u"&&typeof crypto.subtle<"u"&&typeof crypto.subtle.generateKey=="function",Gt=async()=>{if(!xt)throw new Error("Web Crypto API not available");let e=await crypto.subtle.generateKey({name:"AES-GCM",length:256},!0,["encrypt","decrypt"]),t=crypto.getRandomValues(new Uint8Array(12));return{key:e,iv:t}},Ht=async e=>{let t=await crypto.subtle.exportKey("raw",e.key);return{key:btoa(String.fromCharCode(...new Uint8Array(t))),iv:btoa(String.fromCharCode(...e.iv))}},qt=async(e,t)=>{let r=Uint8Array.from(atob(e),l=>l.charCodeAt(0)),n=Uint8Array.from(atob(t),l=>l.charCodeAt(0));return{key:await crypto.subtle.importKey("raw",r,{name:"AES-GCM",length:256},!0,["encrypt","decrypt"]),iv:n}},Ze=async(e,t)=>{let r=new TextEncoder,n=r.encode(JSON.stringify(e)),s=await crypto.subtle.encrypt({name:"AES-GCM",iv:t.iv},t.key,n),l=new Uint8Array(t.iv.length+s.byteLength);return l.set(t.iv),l.set(new Uint8Array(s),t.iv.length),btoa(String.fromCharCode(...l))},Ye=async(e,t)=>{let r=Uint8Array.from(atob(e),g=>g.charCodeAt(0)),n=r.slice(0,12),s=r.slice(12),l=await crypto.subtle.decrypt({name:"AES-GCM",iv:n},t.key,s);return JSON.parse(new TextDecoder().decode(l))},ke=null,Qt=e=>{ke=e},et=()=>ke!==null,ue=e=>{ke&&ke(e)},Re=(e,t,r)=>{e.set(t instanceof RegExp?t.source:t,r)},fe=(e,t,r,n)=>{if(e.size===0)return!0;for(let[s,l]of e){let g;if(typeof s=="function")g=s(t,n);else try{g=new RegExp(s).test(t)}catch{continue}if(g)return l.includes(r)||l.includes("admin")}return!1},ce=e=>{if(typeof e=="string")return e.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"").replace(/javascript:/gi,"[REMOVED]").replace(/on\w+\s*=/gi,"[REMOVED]=").replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,"").replace(/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi,"").replace(/<embed\b[^<]*(?:(?!<\/embed>)<[^<]*)*<\/embed>/gi,"").replace(/<svg\b[^<]*(?:(?!<\/svg>)<[^<]*)*<\/svg>/gi,"").replace(/<foreignObject\b[^<]*(?:(?!<\/foreignObject>)<[^<]*)*<\/foreignObject>/gi,"").replace(/<math\b[^<]*(?:(?!<\/math>)<[^<]*)*<\/math>/gi,"").replace(/<\?php\b[^<]*(?:(?!<\?php>)<[^<]*)*<\?php>/gi,"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/`/g,"`");if(e&&typeof e=="object"&&!Array.isArray(e)){let t={};for(let[r,n]of Object.entries(e))t[r]=ce(n);return t}return Array.isArray(e)?e.map(t=>ce(t)):e},tt=e=>/^[a-zA-Z0-9_.-]+$/.test(e)&&e.length<=256,Ie=(e,t,r,n)=>{let s={id:crypto.randomUUID(),purpose:r,granted:n,timestamp:Date.now()},l=e.get(t)||[];return l.push(s),e.set(t,l),ue({timestamp:Date.now(),action:"set",key:`consent:${r}`,userId:t,success:!0}),s},rt=(e,t,r)=>{let n=e.get(t);if(!n)return!1;for(let s=n.length-1;s>=0;s--){let l=n[s];if(l&&l.purpose===r)return l.granted}return!1},nt=(e,t,r)=>Ie(e,t,r,!1),ot=(e,t)=>e.get(t)||[],st=(e,t)=>({userId:t,exportedAt:Date.now(),consents:e.get(t)||[]}),it=(e,t)=>{let r=e.get(t)?.length||0;return e.delete(t),{success:!0,deletedConsents:r}};var St=null,Ce=null,kr=()=>{if(!St)try{let e=Kt();St=e.produce,Ce=e.freeze}catch(e){throw console.error("[gState] Immer not installed. Run: npm install immer"),e}},He={local:()=>typeof window<"u"?window.localStorage:null,session:()=>typeof window<"u"?window.sessionStorage:null,memory:()=>{let e=new Map;return{getItem:t=>e.get(t)||null,setItem:(t,r)=>e.set(t,r),removeItem:t=>e.delete(t),key:t=>Array.from(e.keys())[t]||null,get length(){return e.size}}}},Je=e=>{if(e===null||typeof e!="object")return e;if(typeof structuredClone=="function")try{return structuredClone(e)}catch{}let t=new WeakMap,r=n=>{if(n===null||typeof n!="object")return n;if(t.has(n))return t.get(n);if(n instanceof Date)return new Date(n.getTime());if(n instanceof RegExp)return new RegExp(n.source,n.flags);let s=Array.isArray(n)?[]:Object.create(Object.getPrototypeOf(n));if(t.set(n,s),Array.isArray(n))for(let l=0;l<n.length;l++)s[l]=r(n[l]);else for(let l of Object.keys(n))s[l]=r(n[l]);return s};return r(e)},Ge=(e,t)=>{if(e===t)return!0;if(e===null||t===null||typeof e!="object"||typeof t!="object")return e===t;if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return!1;for(let s=0;s<e.length;s++)if(!Ge(e[s],t[s]))return!1;return!0}let r=Object.keys(e),n=Object.keys(t);if(r.length!==n.length)return!1;for(let s of r)if(!n.includes(s)||!Ge(e[s],t[s]))return!1;return!0},qe=e=>{let t=new Map,r=new Map,n=new Map,s=new Set,l=new Map,g=new Set,x=new Map,v=new Map,a=new Map,u=new Map,M=new Map,D=new Map,p=new Map,S=new Map,C=e?.namespace||"gstate",m=e?.silent??!1,R=e?.debounceTime??150,I=e?.version??0,A=e?.storage||He.local(),i=e?.onError,d=e?.maxObjectSize??5*1024*1024,h=e?.maxTotalSize??50*1024*1024,w=e?.encryptionKey??null,_=e?.validateInput??!0,j=e?.auditEnabled??!0,N=e?.userId,J=e?.immer??!0;J&&kr(),e?.accessRules&&e.accessRules.forEach(o=>Re(p,o.pattern,o.permissions));let W=!1,Z=!1,Ee=!1,G=0,Qe=null,Me,Bt=new Promise(o=>{Me=o}),Xe=o=>{if(o==null)return 0;let c=0,f=[o],y=new WeakSet;for(;f.length>0;){let P=f.pop();if(typeof P=="boolean")c+=4;else if(typeof P=="number")c+=8;else if(typeof P=="string")c+=P.length*2;else if(typeof P=="object"&&P!==null){let b=P;if(y.has(b))continue;if(y.add(b),Array.isArray(b))for(let k=0;k<b.length;k++)f.push(b[k]);else for(let k of Object.keys(b))c+=k.length*2,f.push(b[k])}}return c},_e=()=>`${C}_`,Y=(o,c)=>{u.forEach(f=>{if(f.hooks?.[o])try{f.hooks[o](c)}catch(y){let P=y instanceof Error?y:new Error(String(y));i?i(P,{operation:`plugin:${f.name}:${o}`,key:c.key}):m||console.error(`[gState] Plugin "${f.name}" error:`,y)}})},q=(o,c,f,y)=>{j&&et()&&ue&&ue({timestamp:Date.now(),action:o,key:c,userId:N,success:f,error:y})},le=o=>{if(o&&(a.get(o)?.forEach(c=>wt(c)),x.get(o)?.forEach(c=>{try{c(U.get(o))}catch(f){let y=f instanceof Error?f:new Error(String(f));i?i(y,{operation:"watcher",key:o}):m||console.error(`[gState] Watcher error for "${o}":`,f)}}),l.get(o)?.forEach(c=>{try{c()}catch(f){let y=f instanceof Error?f:new Error(String(f));i?i(y,{operation:"keyListener",key:o}):m||console.error(`[gState] Listener error for "${o}":`,f)}})),W){Z=!0;return}s.forEach(c=>{try{c()}catch(f){let y=f instanceof Error?f:new Error(String(f));i?i(y,{operation:"listener"}):m||console.error("[gState] Global listener error:",f)}})},wt=o=>{let c=v.get(o),f=new Set;if(!c)return;let y=b=>(f.add(b),U.get(b)),P=c.selector(y);c.deps.forEach(b=>{if(!f.has(b)){let k=a.get(b);k&&(k.delete(o),k.size===0&&a.delete(b))}}),f.forEach(b=>{c.deps.has(b)||(a.has(b)||a.set(b,new Set),a.get(b).add(o))}),c.deps=f,Ge(c.lastValue,P)||(c.lastValue=J&&P!==null&&typeof P=="object"?Ce(Je(P),!0):P,r.set(o,(r.get(o)||0)+1),le(o))},bt=async()=>{if(!A)return;let o=Array.from(M.entries());M.clear();for(let[c,f]of o)try{let y=f.value,P=f.options.encoded||f.options.secure;if(f.options.encrypted){if(!w)throw new Error(`Encryption key missing for "${c}"`);y=await Ze(f.value,w)}else P?y=btoa(JSON.stringify(f.value)):typeof f.value=="object"&&f.value!==null&&(y=JSON.stringify(f.value));A.setItem(`${_e()}${c}`,JSON.stringify({v:r.get(c)||1,t:Date.now(),e:f.options.ttl?Date.now()+f.options.ttl:null,d:y,_sys_v:I,_enc:f.options.encrypted?!0:void 0,_b64:P?!0:void 0})),q("set",c,!0)}catch(y){let P=y instanceof Error?y:new Error(String(y));i?i(P,{operation:"persist",key:c}):m||console.error("[gState] Persist failed:",P)}},ee={},U={_setSilently:(o,c)=>{let f=n.get(o)||0,y=J&&c!==null&&typeof c=="object"?Ce(Je(c),!0):c,P=Xe(y);G=G-f+P,n.set(o,P),t.set(o,y),r.set(o,(r.get(o)||0)+1)},_registerMethod:(o,c,f)=>{if(f!==void 0){let b=o,k=c;ee[b]||(ee[b]={}),ee[b][k]=f;return}console.warn("[gState] _registerMethod(name, fn) is deprecated. Use _registerMethod(pluginName, methodName, fn) instead.");let y=o,P=c;ee.core||(ee.core={}),ee.core[y]=P},set:(o,c,f={})=>{let y=t.get(o),P=J&&typeof c=="function"?St(y,c):c;if(_&&!tt(o))return m||console.warn(`[gState] Invalid key: ${o}`),!1;if(!fe(p,o,"write",N))return q("set",o,!1,"RBAC Denied"),m||console.error(`[gState] RBAC Denied for "${o}"`),!1;let b=_?ce(P):P,k=n.get(o)||0;Y("onBeforeSet",{key:o,value:b,store:U,version:r.get(o)||0});let B=J&&b!==null&&typeof b=="object"?Ce(Je(b),!0):b;if(!Ge(y,B)){let O=d>0||h>0?Xe(B):0;if(d>0&&O>d){let V=new Error(`Object size (${O} bytes) exceeds maxObjectSize (${d} bytes)`);i?i(V,{operation:"set",key:o}):m||console.warn(`[gState] ${V.message} for "${o}"`)}if(h>0){let V=G-k+O;if(V>h){let Pe=new Error(`Total store size (${V} bytes) exceeds limit (${h} bytes)`);i?i(Pe,{operation:"set"}):m||console.warn(`[gState] ${Pe.message}`)}}G=G-k+O,n.set(o,O),t.set(o,B),r.set(o,(r.get(o)||0)+1);let Q=!!(f.persist||e?.persistByDefault||e?.persistence||f.encrypted||f.encoded||f.secure||f.ttl);return Q&&(M.set(o,{value:B,options:{...f,persist:Q}}),Qe&&clearTimeout(Qe),Qe=setTimeout(bt,R)),Y("onSet",{key:o,value:B,store:U,version:r.get(o)}),q("set",o,!0),le(o),!0}return!1},get:o=>{if(!fe(p,o,"read",N))return q("get",o,!1,"RBAC Denied"),null;let c=t.get(o);return Y("onGet",{store:U,key:o,value:c}),q("get",o,!0),c},compute:(o,c)=>{try{return v.has(o)||(v.set(o,{selector:c,lastValue:null,deps:new Set}),wt(o)),v.get(o).lastValue}catch(f){let y=f instanceof Error?f:new Error(String(f));return i?i(y,{operation:"compute",key:o}):m||console.error(`[gState] Compute error for "${o}":`,f),null}},watch:(o,c)=>{x.has(o)||x.set(o,new Set);let f=x.get(o);return f.add(c),()=>{f.delete(c),f.size===0&&x.delete(o)}},remove:o=>{if(!fe(p,o,"delete",N))return q("delete",o,!1,"RBAC Denied"),!1;let c=t.get(o),f=t.delete(o);return f&&(G-=n.get(o)||0,n.delete(o),Y("onRemove",{store:U,key:o,value:c})),r.set(o,(r.get(o)||0)+1),A&&A.removeItem(`${_e()}${o}`),q("delete",o,!0),le(o),f},delete:o=>U.remove(o),deleteAll:()=>{if(Array.from(t.keys()).forEach(o=>U.remove(o)),A){let o=_e();for(let c=0;c<(A.length||0);c++){let f=A.key(c);f?.startsWith(o)&&(A.removeItem(f),c--)}}return G=0,n.clear(),!0},list:()=>Object.fromEntries(t.entries()),use:o=>{g.add(o)},transaction:o=>{W=!0,Y("onTransaction",{store:U,key:"START"});try{o()}finally{W=!1,Y("onTransaction",{store:U,key:"END"}),Z&&(Z=!1,le())}},destroy:()=>{typeof window<"u"&&window.removeEventListener("beforeunload",vt),Y("onDestroy",{store:U}),s.clear(),l.clear(),x.clear(),v.clear(),a.clear(),u.clear(),t.clear(),n.clear(),G=0,p.clear(),S.clear()},_addPlugin:o=>{try{u.set(o.name,o),o.hooks?.onInstall?.({store:U})}catch(c){let f=c instanceof Error?c:new Error(String(c));i?i(f,{operation:"plugin:install",key:o.name}):m||console.error(`[gState] Failed to install plugin "${o.name}":`,c)}},_removePlugin:o=>{u.delete(o)},_subscribe:(o,c)=>{if(c){l.has(c)||l.set(c,new Set);let f=l.get(c);return f.add(o),()=>{f.delete(o),f.size===0&&l.delete(c)}}return s.add(o),()=>s.delete(o)},_getVersion:o=>r.get(o)??0,addAccessRule:(o,c)=>Re(p,o,c),hasPermission:(o,c,f)=>{if(p.size===0)return!0;for(let[y,P]of p){let b;if(typeof y=="function")b=y(o,f);else try{let k=D.get(y);k||(k=new RegExp(y),D.set(y,k)),b=k.test(o)}catch{continue}if(b)return P.includes(c)||P.includes("admin")}return!1},recordConsent:(o,c,f)=>Ie(S,o,c,f),hasConsent:(o,c)=>rt(S,o,c),getConsents:o=>ot(S,o),revokeConsent:(o,c)=>nt(S,o,c),exportUserData:o=>st(S,o),deleteUserData:o=>it(S,o),get plugins(){return ee},get isReady(){return Ee},whenReady:()=>Bt};["addAccessRule","recordConsent","hasConsent","getConsents","revokeConsent","exportUserData","deleteUserData"].forEach(o=>{let c=U[o];c&&U._registerMethod("security",o,c)});let vt=()=>{M.size>0&&bt()};return typeof window<"u"&&window.addEventListener("beforeunload",vt),A?(async()=>{try{let c={},f=_e(),y=0;for(let b=0;b<(A.length||0);b++){let k=A.key(b);if(!k||!k.startsWith(f))continue;let B=A.getItem(k);if(B)try{let O=JSON.parse(B),Q=k.substring(f.length);if(y=Math.max(y,O._sys_v!==void 0?O._sys_v:O.v||0),O.e&&Date.now()>O.e){A.removeItem(k),b--;continue}let V=O.d;if(O._enc&&w)V=await Ye(V,w);else if(typeof V=="string"){if(O._b64)try{V=JSON.parse(atob(V))}catch{}else if(V.startsWith("{")||V.startsWith("["))try{V=JSON.parse(V)}catch{}}c[Q]=V,q("hydrate",Q,!0)}catch(O){q("hydrate",k,!1,String(O));let Q=O instanceof Error?O:new Error(String(O));i?i(Q,{operation:"hydration",key:k}):m||console.error(`[gState] Hydration failed for "${k}":`,O)}}let P=y<I&&e?.migrate?e.migrate(c,y):c;Object.entries(P).forEach(([b,k])=>{let B=J&&k!==null&&typeof k=="object"?Ce(Je(k),!0):k,O=Xe(B),Q=n.get(b)||0;G=G-Q+O,n.set(b,O),t.set(b,B),r.set(b,1)}),Ee=!0,Me(),le()}catch(c){Ee=!0,Me();let f=c instanceof Error?c:new Error(String(c));i?i(f,{operation:"hydration"}):m||console.error("[gState] Hydration failed:",f)}})():(Ee=!0,Me()),U};var Vr=(e,t)=>qe({...t,storage:e}),Ur=e=>qe({...e,storage:He.memory()}),$r=e=>{let t=He.session();return t?qe({...e,storage:t}):null};export{at as Security,He as StorageAdapters,Ur as createMemoryStore,$r as createSessionStore,qe as createStore,Vr as createStoreWithStorage};
|
|
1
|
+
var It=Object.defineProperty;var zt=(e,t)=>{for(var r in t)It(e,r,{get:t[r],enumerable:!0})};var mt=Symbol.for("immer-nothing"),ut=Symbol.for("immer-draftable"),b=Symbol.for("immer-state");function v(e,...t){throw new Error(`[Immer] minified error nr: ${e}. Full error at: https://bit.ly/3cXEKWf`)}var M=Object,W=M.getPrototypeOf,de="constructor",me="prototype",Ne="configurable",pe="enumerable",le="writable",q="value",z=e=>!!e&&!!e[b];function D(e){return e?St(e)||we(e)||!!e[ut]||!!e[de]?.[ut]||be(e)||Ee(e):!1}var Tt=M[me][de].toString(),lt=new WeakMap;function St(e){if(!e||!Ge(e))return!1;let t=W(e);if(t===null||t===M[me])return!0;let r=M.hasOwnProperty.call(t,de)&&t[de];if(r===Object)return!0;if(!L(r))return!1;let n=lt.get(r);return n===void 0&&(n=Function.toString.call(r),lt.set(r,n)),n===Tt}function Se(e,t,r=!0){Y(e)===0?(r?Reflect.ownKeys(e):M.keys(e)).forEach(s=>{t(s,e[s],e)}):e.forEach((n,s)=>t(s,n,e))}function Y(e){let t=e[b];return t?t.type_:we(e)?1:be(e)?2:Ee(e)?3:0}var ft=(e,t,r=Y(e))=>r===2?e.has(t):M[me].hasOwnProperty.call(e,t),Fe=(e,t,r=Y(e))=>r===2?e.get(t):e[t],_e=(e,t,r,n=Y(e))=>{n===2?e.set(t,r):n===3?e.add(r):e[t]=r};function Vt(e,t){return e===t?e!==0||1/e===1/t:e!==e&&t!==t}var we=Array.isArray,be=e=>e instanceof Map,Ee=e=>e instanceof Set,Ge=e=>typeof e=="object",L=e=>typeof e=="function",Te=e=>typeof e=="boolean";function Nt(e){let t=+e;return Number.isInteger(t)&&String(t)===e}var k=e=>e.copy_||e.base_;var He=e=>e.modified_?e.copy_:e.base_;function Ue(e,t){if(be(e))return new Map(e);if(Ee(e))return new Set(e);if(we(e))return Array[me].slice.call(e);let r=St(e);if(t===!0||t==="class_only"&&!r){let n=M.getOwnPropertyDescriptors(e);delete n[b];let s=Reflect.ownKeys(n);for(let a=0;a<s.length;a++){let f=s[a],_=n[f];_[le]===!1&&(_[le]=!0,_[Ne]=!0),(_.get||_.set)&&(n[f]={[Ne]:!0,[le]:!0,[pe]:_[pe],[q]:e[f]})}return M.create(W(e),n)}else{let n=W(e);if(n!==null&&r)return{...e};let s=M.create(n);return M.assign(s,e)}}function T(e,t=!1){return Ce(e)||z(e)||!D(e)||(Y(e)>1&&M.defineProperties(e,{set:ue,add:ue,clear:ue,delete:ue}),M.freeze(e),t&&Se(e,(r,n)=>{T(n,!0)},!1)),e}function Ft(){v(2)}var ue={[q]:Ft};function Ce(e){return e===null||!Ge(e)?!0:M.isFrozen(e)}var ge="MapSet",je="Patches",dt="ArrayMethods",wt={};function j(e){let t=wt[e];return t||v(0,e),t}var pt=e=>!!wt[e];var Q,bt=()=>Q,Ut=(e,t)=>({drafts_:[],parent_:e,immer_:t,canAutoFreeze_:!0,unfinalizedDrafts_:0,handledSet_:new Set,processedForPatches_:new Set,mapSetPlugin_:pt(ge)?j(ge):void 0,arrayMethodsPlugin_:pt(dt)?j(dt):void 0});function _t(e,t){t&&(e.patchPlugin_=j(je),e.patches_=[],e.inversePatches_=[],e.patchListener_=t)}function $e(e){Le(e),e.drafts_.forEach(jt),e.drafts_=null}function Le(e){e===Q&&(Q=e.parent_)}var gt=e=>Q=Ut(Q,e);function jt(e){let t=e[b];t.type_===0||t.type_===1?t.revoke_():t.revoked_=!0}function ht(e,t){t.unfinalizedDrafts_=t.drafts_.length;let r=t.drafts_[0];if(e!==void 0&&e!==r){r[b].modified_&&($e(t),v(4)),D(e)&&(e=yt(t,e));let{patchPlugin_:s}=t;s&&s.generateReplacementPatches_(r[b].base_,e,t)}else e=yt(t,r);return $t(t,e,!0),$e(t),t.patches_&&t.patchListener_(t.patches_,t.inversePatches_),e!==mt?e:void 0}function yt(e,t){if(Ce(t))return t;let r=t[b];if(!r)return he(t,e.handledSet_,e);if(!Pe(r,e))return t;if(!r.modified_)return r.base_;if(!r.finalized_){let{callbacks_:n}=r;if(n)for(;n.length>0;)n.pop()(e);Pt(r,e)}return r.copy_}function $t(e,t,r=!1){!e.parent_&&e.immer_.autoFreeze_&&e.canAutoFreeze_&&T(t,r)}function Et(e){e.finalized_=!0,e.scope_.unfinalizedDrafts_--}var Pe=(e,t)=>e.scope_===t,Lt=[];function Ct(e,t,r,n){let s=k(e),a=e.type_;if(n!==void 0&&Fe(s,n,a)===t){_e(s,n,r,a);return}if(!e.draftLocations_){let _=e.draftLocations_=new Map;Se(s,(y,S)=>{if(z(S)){let x=_.get(S)||[];x.push(y),_.set(S,x)}})}let f=e.draftLocations_.get(t)??Lt;for(let _ of f)_e(s,_,r,a)}function Wt(e,t,r){e.callbacks_.push(function(s){let a=t;if(!a||!Pe(a,s))return;s.mapSetPlugin_?.fixSetContents(a);let f=He(a);Ct(e,a.draft_??a,f,r),Pt(a,s)})}function Pt(e,t){if(e.modified_&&!e.finalized_&&(e.type_===3||e.type_===1&&e.allIndicesReassigned_||(e.assigned_?.size??0)>0)){let{patchPlugin_:n}=t;if(n){let s=n.getPath(e);s&&n.generatePatches_(e,s,t)}Et(e)}}function Bt(e,t,r){let{scope_:n}=e;if(z(r)){let s=r[b];Pe(s,n)&&s.callbacks_.push(function(){fe(e);let f=He(s);Ct(e,r,f,t)})}else D(r)&&e.callbacks_.push(function(){let a=k(e);e.type_===3?a.has(r)&&he(r,n.handledSet_,n):Fe(a,t,e.type_)===r&&n.drafts_.length>1&&(e.assigned_.get(t)??!1)===!0&&e.copy_&&he(Fe(e.copy_,t,e.type_),n.handledSet_,n)})}function he(e,t,r){return!r.immer_.autoFreeze_&&r.unfinalizedDrafts_<1||z(e)||t.has(e)||!D(e)||Ce(e)||(t.add(e),Se(e,(n,s)=>{if(z(s)){let a=s[b];if(Pe(a,r)){let f=He(a);_e(e,n,f,e.type_),Et(a)}}else D(s)&&he(s,t,r)})),e}function Gt(e,t){let r=we(e),n={type_:r?1:0,scope_:t?t.scope_:bt(),modified_:!1,finalized_:!1,assigned_:void 0,parent_:t,base_:e,draft_:null,copy_:null,revoke_:null,isManual_:!1,callbacks_:void 0},s=n,a=ye;r&&(s=[n],a=X);let{revoke:f,proxy:_}=Proxy.revocable(s,a);return n.draft_=_,n.revoke_=f,[_,n]}var ye={get(e,t){if(t===b)return e;let r=e.scope_.arrayMethodsPlugin_,n=e.type_===1&&typeof t=="string";if(n&&r?.isArrayOperationMethod(t))return r.createMethodInterceptor(e,t);let s=k(e);if(!ft(s,t,e.type_))return Ht(e,s,t);let a=s[t];if(e.finalized_||!D(a)||n&&e.operationMethod&&r?.isMutatingArrayMethod(e.operationMethod)&&Nt(t))return a;if(a===Ve(e.base_,t)){fe(e);let f=e.type_===1?+t:t,_=Be(e.scope_,a,e,f);return e.copy_[f]=_}return a},has(e,t){return t in k(e)},ownKeys(e){return Reflect.ownKeys(k(e))},set(e,t,r){let n=Mt(k(e),t);if(n?.set)return n.set.call(e.draft_,r),!0;if(!e.modified_){let s=Ve(k(e),t),a=s?.[b];if(a&&a.base_===r)return e.copy_[t]=r,e.assigned_.set(t,!1),!0;if(Vt(r,s)&&(r!==void 0||ft(e.base_,t,e.type_)))return!0;fe(e),We(e)}return e.copy_[t]===r&&(r!==void 0||t in e.copy_)||Number.isNaN(r)&&Number.isNaN(e.copy_[t])||(e.copy_[t]=r,e.assigned_.set(t,!0),Bt(e,t,r)),!0},deleteProperty(e,t){return fe(e),Ve(e.base_,t)!==void 0||t in e.base_?(e.assigned_.set(t,!1),We(e)):e.assigned_.delete(t),e.copy_&&delete e.copy_[t],!0},getOwnPropertyDescriptor(e,t){let r=k(e),n=Reflect.getOwnPropertyDescriptor(r,t);return n&&{[le]:!0,[Ne]:e.type_!==1||t!=="length",[pe]:n[pe],[q]:r[t]}},defineProperty(){v(11)},getPrototypeOf(e){return W(e.base_)},setPrototypeOf(){v(12)}},X={};for(let e in ye){let t=ye[e];X[e]=function(){let r=arguments;return r[0]=r[0][0],t.apply(this,r)}}X.deleteProperty=function(e,t){return X.set.call(this,e,t,void 0)};X.set=function(e,t,r){return ye.set.call(this,e[0],t,r,e[0])};function Ve(e,t){let r=e[b];return(r?k(r):e)[t]}function Ht(e,t,r){let n=Mt(t,r);return n?q in n?n[q]:n.get?.call(e.draft_):void 0}function Mt(e,t){if(!(t in e))return;let r=W(e);for(;r;){let n=Object.getOwnPropertyDescriptor(r,t);if(n)return n;r=W(r)}}function We(e){e.modified_||(e.modified_=!0,e.parent_&&We(e.parent_))}function fe(e){e.copy_||(e.assigned_=new Map,e.copy_=Ue(e.base_,e.scope_.immer_.useStrictShallowCopy_))}var Jt=class{constructor(e){this.autoFreeze_=!0,this.useStrictShallowCopy_=!1,this.useStrictIteration_=!1,this.produce=(t,r,n)=>{if(L(t)&&!L(r)){let a=r;r=t;let f=this;return function(y=a,...S){return f.produce(y,x=>r.call(this,x,...S))}}L(r)||v(6),n!==void 0&&!L(n)&&v(7);let s;if(D(t)){let a=gt(this),f=Be(a,t,void 0),_=!0;try{s=r(f),_=!1}finally{_?$e(a):Le(a)}return _t(a,n),ht(s,a)}else if(!t||!Ge(t)){if(s=r(t),s===void 0&&(s=t),s===mt&&(s=void 0),this.autoFreeze_&&T(s,!0),n){let a=[],f=[];j(je).generateReplacementPatches_(t,s,{patches_:a,inversePatches_:f}),n(a,f)}return s}else v(1,t)},this.produceWithPatches=(t,r)=>{if(L(t))return(f,..._)=>this.produceWithPatches(f,y=>t(y,..._));let n,s;return[this.produce(t,r,(f,_)=>{n=f,s=_}),n,s]},Te(e?.autoFreeze)&&this.setAutoFreeze(e.autoFreeze),Te(e?.useStrictShallowCopy)&&this.setUseStrictShallowCopy(e.useStrictShallowCopy),Te(e?.useStrictIteration)&&this.setUseStrictIteration(e.useStrictIteration)}createDraft(e){D(e)||v(8),z(e)&&(e=Kt(e));let t=gt(this),r=Be(t,e,void 0);return r[b].isManual_=!0,Le(t),r}finishDraft(e,t){let r=e&&e[b];(!r||!r.isManual_)&&v(9);let{scope_:n}=r;return _t(n,t),ht(void 0,n)}setAutoFreeze(e){this.autoFreeze_=e}setUseStrictShallowCopy(e){this.useStrictShallowCopy_=e}setUseStrictIteration(e){this.useStrictIteration_=e}shouldUseStrictIteration(){return this.useStrictIteration_}applyPatches(e,t){let r;for(r=t.length-1;r>=0;r--){let s=t[r];if(s.path.length===0&&s.op==="replace"){e=s.value;break}}r>-1&&(t=t.slice(r+1));let n=j(je).applyPatches_;return z(e)?n(e,t):this.produce(e,s=>n(s,t))}};function Be(e,t,r,n){let[s,a]=be(t)?j(ge).proxyMap_(t,r):Ee(t)?j(ge).proxySet_(t,r):Gt(t,r);return(r?.scope_??bt()).drafts_.push(s),a.callbacks_=r?.callbacks_??[],a.key_=n,r&&n!==void 0?Wt(r,a,n):a.callbacks_.push(function(y){y.mapSetPlugin_?.fixSetContents(a);let{patchPlugin_:S}=y;a.modified_&&S&&S.generatePatches_(a,[],y)}),s}function Kt(e){return z(e)||v(10,e),At(e)}function At(e){if(!D(e)||Ce(e))return e;let t=e[b],r,n=!0;if(t){if(!t.modified_)return t.base_;t.finalized_=!0,r=Ue(e,t.scope_.immer_.useStrictShallowCopy_),n=t.scope_.immer_.shouldUseStrictIteration()}else r=Ue(e,!0);return Se(r,(s,a)=>{_e(r,s,At(a))},n),t&&(t.finalized_=!1),r}var qt=new Jt,vt=qt.produce;var rt={};zt(rt,{addAccessRule:()=>Ae,decrypt:()=>Ke,deleteUserData:()=>tt,encrypt:()=>Je,exportKey:()=>Xt,exportUserData:()=>et,generateEncryptionKey:()=>Qt,getConsents:()=>Ze,hasConsent:()=>Xe,hasPermission:()=>te,importKey:()=>Yt,isAuditActive:()=>qe,isCryptoAvailable:()=>xt,logAudit:()=>ee,recordConsent:()=>ve,revokeConsent:()=>Ye,sanitizeValue:()=>Z,setAuditLogger:()=>Zt,validateKey:()=>Qe});var xt=typeof crypto<"u"&&typeof crypto.subtle<"u"&&typeof crypto.subtle.generateKey=="function",Qt=async()=>{if(!xt)throw new Error("Web Crypto API not available");let e=await crypto.subtle.generateKey({name:"AES-GCM",length:256},!0,["encrypt","decrypt"]),t=crypto.getRandomValues(new Uint8Array(12));return{key:e,iv:t}},Xt=async e=>{let t=await crypto.subtle.exportKey("raw",e.key);return{key:btoa(String.fromCharCode(...new Uint8Array(t))),iv:btoa(String.fromCharCode(...e.iv))}},Yt=async(e,t)=>{let r=Uint8Array.from(atob(e),a=>a.charCodeAt(0)),n=Uint8Array.from(atob(t),a=>a.charCodeAt(0));return{key:await crypto.subtle.importKey("raw",r,{name:"AES-GCM",length:256},!0,["encrypt","decrypt"]),iv:n}},Je=async(e,t)=>{let r=new TextEncoder,n=r.encode(JSON.stringify(e)),s=await crypto.subtle.encrypt({name:"AES-GCM",iv:t.iv},t.key,n),a=new Uint8Array(t.iv.length+s.byteLength);return a.set(t.iv),a.set(new Uint8Array(s),t.iv.length),btoa(String.fromCharCode(...a))},Ke=async(e,t)=>{let r=Uint8Array.from(atob(e),f=>f.charCodeAt(0)),n=r.slice(0,12),s=r.slice(12),a=await crypto.subtle.decrypt({name:"AES-GCM",iv:n},t.key,s);return JSON.parse(new TextDecoder().decode(a))},Me=null,Zt=e=>{Me=e},qe=()=>Me!==null,ee=e=>{Me&&Me(e)},Ae=(e,t,r)=>{e.set(t instanceof RegExp?t.source:t,r)},te=(e,t,r,n)=>{if(e.size===0)return!0;for(let[s,a]of e){let f;if(typeof s=="function")f=s(t,n);else try{f=new RegExp(s).test(t)}catch{continue}if(f)return a.includes(r)||a.includes("admin")}return!1},Z=e=>{if(typeof e=="string")return e.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"[SEC-REMOVED]").replace(/javascript:/gi,"[SEC-REMOVED]").replace(/data:text\/html/gi,"[SEC-REMOVED]").replace(/vbscript:/gi,"[SEC-REMOVED]").replace(/on\w+\s*=/gi,"[SEC-REMOVED]=").replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,"[SEC-REMOVED]").replace(/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi,"[SEC-REMOVED]").replace(/<embed\b[^<]*(?:(?!<\/embed>)<[^<]*)*<\/embed>/gi,"[SEC-REMOVED]").replace(/<svg\b[^<]*(?:(?!<\/svg>)<[^<]*)*<\/svg>/gi,"[SEC-REMOVED]").replace(/<form\b[^<]*(?:(?!<\/form>)<[^<]*)*<\/form>/gi,"[SEC-REMOVED]").replace(/<base\b[^<]*(?:(?!<\/base>)<[^<]*)*<\/base>/gi,"[SEC-REMOVED]").replace(/<link\b[^<]*(?:(?!<\/link>)<[^<]*)*<\/link>/gi,"[SEC-REMOVED]").replace(/<meta\b[^<]*(?:(?!<\/meta>)<[^<]*)*<\/meta>/gi,"[SEC-REMOVED]").replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi,"[SEC-REMOVED]").replace(/&#[xX]?[0-9a-fA-F]+;?/g,"");if(e&&typeof e=="object"&&!Array.isArray(e)){if(Object.getPrototypeOf(e)===Object.prototype){let t={};for(let[r,n]of Object.entries(e))t[r]=Z(n);return t}return e}return Array.isArray(e)?e.map(t=>Z(t)):e},Qe=e=>/^[a-zA-Z0-9_.-]+$/.test(e)&&e.length<=256,ve=(e,t,r,n)=>{let s={id:crypto.randomUUID(),purpose:r,granted:n,timestamp:Date.now()},a=e.get(t)||[];return a.push(s),e.set(t,a),ee({timestamp:Date.now(),action:"set",key:`consent:${r}`,userId:t,success:!0}),s},Xe=(e,t,r)=>{let n=e.get(t);if(!n)return!1;for(let s=n.length-1;s>=0;s--){let a=n[s];if(a&&a.purpose===r)return a.granted}return!1},Ye=(e,t,r)=>ve(e,t,r,!1),Ze=(e,t)=>e.get(t)||[],et=(e,t)=>({userId:t,exportedAt:Date.now(),consents:e.get(t)||[]}),tt=(e,t)=>{let r=e.get(t)?.length||0;return e.delete(t),{success:!0,deletedConsents:r}};var ne=e=>{if(e===null||typeof e!="object")return e;if(typeof structuredClone=="function")try{return structuredClone(e)}catch{}let t=new WeakMap,r=n=>{if(n===null||typeof n!="object"||typeof n=="function")return n;if(t.has(n))return t.get(n);if(n instanceof Date)return new Date(n.getTime());if(n instanceof RegExp)return new RegExp(n.source,n.flags);if(n instanceof Map){let f=new Map;return t.set(n,f),n.forEach((_,y)=>f.set(r(y),r(_))),f}if(n instanceof Set){let f=new Set;return t.set(n,f),n.forEach(_=>f.add(r(_))),f}let s=Array.isArray(n)?[]:Object.create(Object.getPrototypeOf(n));t.set(n,s);let a=[...Object.keys(n),...Object.getOwnPropertySymbols(n)];for(let f of a)s[f]=r(n[f]);return s};return r(e)},re=(e,t)=>{if(e===t)return!0;if(e===null||t===null||typeof e!="object"||typeof t!="object")return e===t;if(Array.isArray(e)&&Array.isArray(t)){if(e.length!==t.length)return!1;for(let s=0;s<e.length;s++)if(!re(e[s],t[s]))return!1;return!0}let r=Object.keys(e),n=Object.keys(t);if(r.length!==n.length)return!1;for(let s=0;s<r.length;s++){let a=r[s];if(!(a in t)||!re(e[a],t[a]))return!1}return!0};var xe={local:()=>typeof window<"u"?window.localStorage:null,session:()=>typeof window<"u"?window.sessionStorage:null,memory:()=>{let e=new Map;return{getItem:t=>e.get(t)||null,setItem:(t,r)=>e.set(t,r),removeItem:t=>e.delete(t),key:t=>Array.from(e.keys())[t]||null,get length(){return e.size}}}},Oe=e=>{let t=new Map,r=new Map,n=new Map,s=new Set,a=new Map,f=new Set,_=new Map,y=new Map,S=new Map,x=new Map,B=new Map,Re=new Map,I=new Map,V=new Map,nt=e?.namespace||"gstate",E=e?.silent??!1,Ot=e?.debounceTime??150,ke=e?.version??0,C=e?.storage||xe.local(),g=e?.onError,oe=e?.maxObjectSize??5*1024*1024,se=e?.maxTotalSize??50*1024*1024,ie=e?.encryptionKey??null,ot=e?.validateInput??!0,Rt=e?.auditEnabled??!0,G=e?.userId,H=e?.immer??!0,kt=e?.persistByDefault??e?.persistence??e?.persist??!1;e?.accessRules&&e.accessRules.forEach(o=>Ae(I,o.pattern,o.permissions));let De=!1,Ie=!1,ae=!1,O=0,$=null,ce,Dt=new Promise(o=>{ce=o}),ze=o=>{if(o==null)return 0;let i=typeof o;if(i==="boolean")return 4;if(i==="number")return 8;if(i==="string")return o.length*2;if(i!=="object")return 0;let c=0,l=[o],p=new WeakSet;for(;l.length>0;){let u=l.pop();if(typeof u=="boolean")c+=4;else if(typeof u=="number")c+=8;else if(typeof u=="string")c+=u.length*2;else if(typeof u=="object"&&u!==null){let d=u;if(p.has(d))continue;if(p.add(d),Array.isArray(d))for(let h=0;h<d.length;h++)l.push(d[h]);else for(let h of Object.keys(d))c+=h.length*2,l.push(d[h])}}return c},J=()=>`${nt}_`,N=(o,i)=>{if(x.size!==0)for(let c of x.values()){let l=c.hooks?.[o];if(l)try{l(i)}catch(p){let u=p instanceof Error?p:new Error(String(p));g?g(u,{operation:`plugin:${c.name}:${o}`,key:i.key}):E||console.error(`[gState] Plugin "${c.name}" error:`,p)}}},R=(o,i,c,l)=>{Rt&&qe()&&ee&&ee({timestamp:Date.now(),action:o,key:i,userId:G,success:c,error:l})},K=o=>{if(o){let i=S.get(o);if(i)for(let p of i)st(p);let c=_.get(o);if(c){let p=w.get(o);for(let u of c)try{u(p)}catch(d){let h=d instanceof Error?d:new Error(String(d));g?g(h,{operation:"watcher",key:o}):E||console.error(`[gState] Watcher error for "${o}":`,d)}}let l=a.get(o);if(l)for(let p of l)try{p()}catch(u){let d=u instanceof Error?u:new Error(String(u));g?g(d,{operation:"keyListener",key:o}):E||console.error(`[gState] Listener error for "${o}":`,u)}}if(De){Ie=!0;return}for(let i of s)try{i()}catch(c){let l=c instanceof Error?c:new Error(String(c));g?g(l,{operation:"listener"}):E||console.error("[gState] Global listener error: ",c)}},st=o=>{let i=y.get(o),c=new Set;if(!i)return;let l=u=>(c.add(u),y.has(u)?y.get(u).lastValue:w.get(u)),p=i.selector(l);i.deps.forEach(u=>{if(!c.has(u)){let d=S.get(u);d&&(d.delete(o),d.size===0&&S.delete(u))}}),c.forEach(u=>{i.deps.has(u)||(S.has(u)||S.set(u,new Set),S.get(u).add(o))}),i.deps=c,re(i.lastValue,p)||(i.lastValue=H&&p!==null&&typeof p=="object"?T(ne(p),!0):p,r.set(o,(r.get(o)||0)+1),K(o))},it=async()=>{if(!C)return;try{let i={};t.forEach((p,u)=>{i[u]=p});let c,l=e?.encoded;l?c=btoa(JSON.stringify(i)):c=JSON.stringify(i),C.setItem(J().replace("_",""),JSON.stringify({v:1,t:Date.now(),e:null,d:c,_sys_v:ke,_b64:l?!0:void 0})),R("set","FULL_STATE",!0)}catch(i){let c=i instanceof Error?i:new Error(String(i));g?g(c,{operation:"persist",key:"FULL_STATE"}):E||console.error("[gState] Persist failed: ",c)}let o=Array.from(B.entries());B.clear();for(let[i,c]of o)try{let l=c.value,p=c.options.encoded||c.options.secure;if(c.options.encrypted){if(!ie)throw new Error(`Encryption key missing for "${i}"`);l=await Je(c.value,ie)}else p?l=btoa(JSON.stringify(c.value)):typeof c.value=="object"&&c.value!==null&&(l=JSON.stringify(c.value));C.setItem(`${J()}${i} `,JSON.stringify({v:r.get(i)||1,t:Date.now(),e:c.options.ttl?Date.now()+c.options.ttl:null,d:l,_sys_v:ke,_enc:c.options.encrypted?!0:void 0,_b64:p?!0:void 0})),R("set",i,!0)}catch(l){let p=l instanceof Error?l:new Error(String(l));g?g(p,{operation:"persist",key:i}):E||console.error("[gState] Persist failed: ",p)}},F={},w={_setSilently:(o,i)=>{let c=n.get(o)||0,l=H&&i!==null&&typeof i=="object"?T(ne(i),!0):i,p=ze(l);O=O-c+p,n.set(o,p),t.set(o,l),r.set(o,(r.get(o)||0)+1)},_registerMethod:(o,i,c)=>{if(c!==void 0){let u=o,d=i;F[u]||(F[u]={}),F[u][d]=c;return}console.warn("[gState] _registerMethod(name, fn) is deprecated. Use _registerMethod(pluginName, methodName, fn) instead.");let l=o,p=i;F.core||(F.core={}),F.core[l]=p},set:(o,i,c={})=>{let l=t.get(o),p=H&&typeof i=="function"?vt(l,i):i;if(ot&&!Qe(o))return E||console.warn(`[gState] Invalid key: ${o}`),!1;if(!te(I,o,"write",G))return R("set",o,!1,"RBAC Denied"),E||console.error(`[gState] RBAC Denied for "${o}"`),!1;let u=ot?Z(p):p,d=n.get(o)||0;N("onBeforeSet",{key:o,value:u,store:w,version:r.get(o)||0});let h=H&&u!==null&&typeof u=="object"?T(ne(u),!0):u;if(!re(l,h)){let A=oe>0||se>0?ze(h):0;if(oe>0&&A>oe){let U=new Error(`Object size (${A} bytes) exceeds maxObjectSize (${oe} bytes)`);g?g(U,{operation:"set",key:o}):E||console.warn(`[gState] ${U.message} for "${o}"`)}if(se>0){let U=O-d+A;if(U>se){let ct=new Error(`Total store size (${U} bytes) exceeds limit (${se} bytes)`);g?g(ct,{operation:"set"}):E||console.warn(`[gState] ${ct.message}`)}}O=O-d+A,n.set(o,A),t.set(o,h),r.set(o,(r.get(o)||0)+1);let P=c.persist??kt;return P&&(B.set(o,{value:h,options:{...c,persist:P,encoded:c.encoded||e?.encoded}}),$&&clearTimeout($),$=setTimeout(it,Ot)),N("onSet",{key:o,value:h,store:w,version:r.get(o)}),R("set",o,!0),K(o),!0}return!1},get:o=>{if(!te(I,o,"read",G))return R("get",o,!1,"RBAC Denied"),null;let i=t.get(o);return N("onGet",{store:w,key:o,value:i}),R("get",o,!0),i},compute:(o,i)=>{try{return y.has(o)||(y.set(o,{selector:i,lastValue:null,deps:new Set}),st(o)),y.get(o).lastValue}catch(c){let l=c instanceof Error?c:new Error(String(c));return g?g(l,{operation:"compute",key:o}):E||console.error(`[gState] Compute error for "${o}": `,c),null}},watch:(o,i)=>{_.has(o)||_.set(o,new Set);let c=_.get(o);return c.add(i),()=>{c.delete(i),c.size===0&&_.delete(o)}},remove:o=>{if(!te(I,o,"delete",G))return R("delete",o,!1,"RBAC Denied"),!1;let i=t.get(o),c=t.delete(o);return c&&(O-=n.get(o)||0,n.delete(o),N("onRemove",{store:w,key:o,value:i})),r.set(o,(r.get(o)||0)+1),C&&C.removeItem(`${J()}${o} `),R("delete",o,!0),K(o),c},delete:o=>w.remove(o),deleteAll:()=>{if(Array.from(t.keys()).forEach(o=>w.remove(o)),C){let o=J();for(let i=0;i<(C.length||0);i++){let c=C.key(i);c?.startsWith(o)&&(C.removeItem(c),i--)}}return O=0,n.clear(),!0},list:()=>Object.fromEntries(t.entries()),use:o=>{f.add(o)},transaction:o=>{De=!0,N("onTransaction",{store:w,key:"START"});try{o()}finally{De=!1,N("onTransaction",{store:w,key:"END"}),Ie&&(Ie=!1,K())}},destroy:()=>{$&&(clearTimeout($),$=null),B.clear(),typeof window<"u"&&window.removeEventListener("beforeunload",at),N("onDestroy",{store:w}),s.clear(),a.clear(),_.clear(),y.clear(),S.clear(),x.clear(),t.clear(),n.clear(),O=0,I.clear(),V.clear(),r.clear(),Re.clear(),f.clear()},_addPlugin:o=>{try{x.set(o.name,o),o.hooks?.onInstall?.({store:w})}catch(i){let c=i instanceof Error?i:new Error(String(i));g?g(c,{operation:"plugin:install",key:o.name}):E||console.error(`[gState] Failed to install plugin "${o.name}": `,i)}},_removePlugin:o=>{x.delete(o)},_subscribe:(o,i)=>{if(i){a.has(i)||a.set(i,new Set);let c=a.get(i);return c.add(o),()=>{c.delete(o),c.size===0&&a.delete(i)}}return s.add(o),()=>s.delete(o)},_getVersion:o=>r.get(o)??0,addAccessRule:(o,i)=>Ae(I,o,i),hasPermission:(o,i,c)=>{if(I.size===0)return!0;for(let[l,p]of I){let u;if(typeof l=="function")u=l(o,c);else try{let d=Re.get(l);d||(d=new RegExp(l),Re.set(l,d)),u=d.test(o)}catch{continue}if(u)return p.includes(i)||p.includes("admin")}return!1},recordConsent:(o,i,c)=>ve(V,o,i,c),hasConsent:(o,i)=>Xe(V,o,i),getConsents:o=>Ze(V,o),revokeConsent:(o,i)=>Ye(V,o,i),exportUserData:o=>et(V,o),deleteUserData:o=>tt(V,o),get plugins(){return F},get isReady(){return ae},get namespace(){return nt},get userId(){return G},whenReady:()=>Dt};["addAccessRule","recordConsent","hasConsent","getConsents","revokeConsent","exportUserData","deleteUserData"].forEach(o=>{let i=w[o];i&&w._registerMethod("security",o,i)});let at=()=>{B.size>0&&it()};return typeof window<"u"&&window.addEventListener("beforeunload",at),C?(async()=>{try{let i={},c=J(),l=0;for(let u=0;u<(C.length||0);u++){let d=C.key(u);if(!d||!d.startsWith(c))continue;let h=C.getItem(d);if(h)try{let m=JSON.parse(h),A=d.substring(c.length);if(l=Math.max(l,m._sys_v!==void 0?m._sys_v:m.v||0),m.e&&Date.now()>m.e){C.removeItem(d),u--;continue}let P=m.d;if(m._enc&&ie)P=await Ke(P,ie);else if(typeof P=="string"){if(m._b64)try{P=JSON.parse(atob(P))}catch{}else if(P.startsWith("{")||P.startsWith("["))try{P=JSON.parse(P)}catch{}}i[A]=P,R("hydrate",A,!0)}catch(m){R("hydrate",d,!1,String(m));let A=m instanceof Error?m:new Error(String(m));g?g(A,{operation:"hydration",key:d}):E||console.error(`[gState] Hydration failed for "${d}": `,m)}}let p=l<ke&&e?.migrate?e.migrate(i,l):i;Object.entries(p).forEach(([u,d])=>{let h=H&&d!==null&&typeof d=="object"?T(ne(d),!0):d,m=ze(h),A=n.get(u)||0;O=O-A+m,n.set(u,m),t.set(u,h),r.set(u,1)}),ae=!0,ce(),K()}catch(i){ae=!0,ce();let c=i instanceof Error?i:new Error(String(i));g?g(c,{operation:"hydration"}):E||console.error("[gState] Hydration failed: ",c)}})():(ae=!0,ce()),w};var ur=(e,t)=>Oe({...t,storage:e}),lr=e=>Oe({...e,storage:xe.memory()}),fr=e=>{let t=xe.session();return t?Oe({...e,storage:t}):null};export{rt as Security,xe as StorageAdapters,lr as createMemoryStore,fr as createSessionStore,Oe as createStore,ur as createStoreWithStorage};
|
package/core/types.d.ts
CHANGED
|
@@ -73,6 +73,8 @@ export interface IStore<S extends Record<string, unknown> = Record<string, unkno
|
|
|
73
73
|
deletedConsents: number;
|
|
74
74
|
};
|
|
75
75
|
readonly isReady: boolean;
|
|
76
|
+
readonly namespace: string;
|
|
77
|
+
readonly userId?: string;
|
|
76
78
|
whenReady(): Promise<void>;
|
|
77
79
|
readonly plugins: GStatePlugins;
|
|
78
80
|
}
|
|
@@ -93,7 +95,24 @@ export interface GStatePlugins {
|
|
|
93
95
|
deletedConsents: number;
|
|
94
96
|
};
|
|
95
97
|
};
|
|
96
|
-
|
|
98
|
+
undoRedo: {
|
|
99
|
+
undo: () => boolean;
|
|
100
|
+
redo: () => boolean;
|
|
101
|
+
canUndo: () => boolean;
|
|
102
|
+
canRedo: () => boolean;
|
|
103
|
+
};
|
|
104
|
+
immer: {
|
|
105
|
+
setWithProduce: <T>(key: string, updater: (draft: T) => void) => boolean;
|
|
106
|
+
};
|
|
107
|
+
cloudSync: {
|
|
108
|
+
sync: () => Promise<{
|
|
109
|
+
status: string;
|
|
110
|
+
stats: import('../plugins/official/cloud-sync.plugin').SyncStats;
|
|
111
|
+
}>;
|
|
112
|
+
getStats: () => import('../plugins/official/cloud-sync.plugin').SyncStats;
|
|
113
|
+
};
|
|
114
|
+
logger: Record<string, never>;
|
|
115
|
+
[key: string]: unknown;
|
|
97
116
|
}
|
|
98
117
|
export interface StoreConfig<S extends Record<string, unknown> = Record<string, unknown>> {
|
|
99
118
|
namespace?: string;
|
|
@@ -104,6 +123,7 @@ export interface StoreConfig<S extends Record<string, unknown> = Record<string,
|
|
|
104
123
|
migrate?: (oldState: Record<string, unknown>, oldVersion: number) => S;
|
|
105
124
|
persistByDefault?: boolean;
|
|
106
125
|
persistence?: boolean;
|
|
126
|
+
persist?: boolean;
|
|
107
127
|
onError?: (error: Error, context: {
|
|
108
128
|
operation: string;
|
|
109
129
|
key?: string;
|
|
@@ -114,6 +134,7 @@ export interface StoreConfig<S extends Record<string, unknown> = Record<string,
|
|
|
114
134
|
auditEnabled?: boolean;
|
|
115
135
|
userId?: string;
|
|
116
136
|
validateInput?: boolean;
|
|
137
|
+
encoded?: boolean;
|
|
117
138
|
accessRules?: Array<{
|
|
118
139
|
pattern: string | ((key: string, userId?: string) => boolean);
|
|
119
140
|
permissions: Permission[];
|
package/core/utils.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 🌌 RGS Examples & Best Practices
|
|
2
|
+
|
|
3
|
+
This folder contains functional and reusable examples of **React Globo State (RGS)** implementation.
|
|
4
|
+
|
|
5
|
+
## 🏁 Overview: FE vs BE Recommendations
|
|
6
|
+
|
|
7
|
+
| Example | Recommendation | Primary Use Case |
|
|
8
|
+
| :--- | :--- | :--- |
|
|
9
|
+
| **[Basic Counter](./basic-counter)** | **FE Only** | Local component state, UI toggles. |
|
|
10
|
+
| **[Global Theme](./global-theme)** | **FE Only** | Dark mode, Layout settings, Persistence. |
|
|
11
|
+
| **[Persistent Cart](./persistent-cart)** | **FE Preferred** | Shopping carts, Drafts, Offline-first apps. |
|
|
12
|
+
| **[Secure Auth](./secure-auth)** | **FE / BE** | Session management, Tokens, User metadata. |
|
|
13
|
+
| **[Undo/Redo Editor](./undo-redo-editor)** | **FE Only** | Rich text editors, Canvas tools, Form history. |
|
|
14
|
+
| **[RBAC Dashboard](./rbac-dashboard)** | **BE / Admin FE** | Permission-based UI, Secure Admin panels. |
|
|
15
|
+
| **[Async Data Fetch](./async-data-fetch)** | **FE Only** | API integration, Data hydration. |
|
|
16
|
+
| **[Security Practices](./security-best-practices)** | **BE / Core FE** | Encryption, Audit logs, GDPR compliance. |
|
|
17
|
+
| **[Big Data (IndexedDB)](./big-data-indexeddb)** | **FE Specific** | High-volume storage (GBs), Large payloads. |
|
|
18
|
+
| **[Stress Tests](./stress-tests)** | **Validation** | Performance benchmarking & profiling. |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 🛡️ Security Guidelines
|
|
23
|
+
|
|
24
|
+
### 1. Sensitive Data Handling
|
|
25
|
+
**CRITICAL:** Never hardcode actual sensitive data (Credit Cards, Passwords, API Keys) in your JavaScript/TypeScript files.
|
|
26
|
+
- **Frontend:** Collect from secure `<input type="password">` and pass to RGS at runtime.
|
|
27
|
+
- **Backend:** Retrieve from environment variables (`process.env`) or Secret Managers.
|
|
28
|
+
|
|
29
|
+
### 2. Encryption
|
|
30
|
+
For PII (Personally Identifiable Information), always use the `encryptionKey` option in `StoreConfig`.
|
|
31
|
+
RGS will use the Web Crypto API (or Node Crypto) to perform **AES-256-GCM** encryption before writing to storage.
|
|
32
|
+
|
|
33
|
+
### 3. XSS Defense
|
|
34
|
+
Enable `validateInput: true` in your store configuration to automatically sanitize strings. This is vital for any user-generated content displayed in the DOM.
|
|
35
|
+
|
|
36
|
+
### 4. High-Volume Storage (IndexedDB)
|
|
37
|
+
If your application needs to store more than 10MB (the typical localStorage limit), use the **IndexedDB Plugin**. It allows storing Gigabytes of data asynchronously without blocking the main UI thread.
|
|
38
|
+
|
|
39
|
+
## 🛠️ Testing Environment
|
|
40
|
+
All examples are validated using Jest in a `jsdom` environment.
|
|
41
|
+
Refer to `tests/jest/tests/examples_v.test.ts` for automated verify suites.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface User {
|
|
2
|
+
id: number;
|
|
3
|
+
name: string;
|
|
4
|
+
email: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const fetchUser: (args: {
|
|
7
|
+
id: string;
|
|
8
|
+
}) => Promise<User>;
|
|
9
|
+
export declare const useUser: import("../../advanced").IStore<Record<string, import("../../core/types").AsyncState<User>>> & {
|
|
10
|
+
execute: () => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createAsyncStore } from '../../index'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Async Data Loader Utility
|
|
5
|
+
* RECOMMENDED FOR: Frontend (FE)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
interface User {
|
|
9
|
+
id: number
|
|
10
|
+
name: string
|
|
11
|
+
email: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const fetchUser = async (args: { id: string }) => {
|
|
15
|
+
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${args.id}`)
|
|
16
|
+
if (!response.ok) throw new Error('User not found')
|
|
17
|
+
return response.json() as Promise<User>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Basic Async Store for a specific user (Example)
|
|
21
|
+
export const useUser = createAsyncStore<User>(() => fetchUser({ id: '1' }), {
|
|
22
|
+
key: 'userData'
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Usage in component:
|
|
27
|
+
*
|
|
28
|
+
* const [state, actions] = useUser()
|
|
29
|
+
* useEffect(() => { actions.execute({ id: '1' }) }, [])
|
|
30
|
+
*/
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { useCounter, increment, decrement } from './CounterStore'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Counter Component
|
|
6
|
+
* Demonstrates the "Magnetar" pattern where the store IS the hook.
|
|
7
|
+
*/
|
|
8
|
+
export const CounterComponent: React.FC = () => {
|
|
9
|
+
// Subscribe to specific keys for fine-grained re-renders
|
|
10
|
+
const [count] = useCounter('count')
|
|
11
|
+
const [lastUpdated] = useCounter('lastUpdated')
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div style={{ padding: '20px', border: '1px solid #ccc' }}>
|
|
15
|
+
<h2>Counter: {String(count)}</h2>
|
|
16
|
+
<p><small>Last updated: {String(lastUpdated)}</small></p>
|
|
17
|
+
<button onClick={increment}>+</button>
|
|
18
|
+
<button onClick={decrement}>-</button>
|
|
19
|
+
<button onClick={() => useCounter.set('count', 0)}>Reset</button>
|
|
20
|
+
</div>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface CounterState extends Record<string, unknown> {
|
|
2
|
+
count: number;
|
|
3
|
+
lastUpdated: string;
|
|
4
|
+
}
|
|
5
|
+
export declare const useCounter: import("../../advanced").IStore<CounterState> & (<K extends keyof CounterState>(key: K) => readonly [CounterState[K] | undefined, (val: CounterState[K] | ((draft: CounterState[K]) => CounterState[K]), options?: unknown) => boolean]);
|
|
6
|
+
export declare const increment: () => void;
|
|
7
|
+
export declare const decrement: () => void;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { gstate } from '../../index'
|
|
2
|
+
|
|
3
|
+
export interface CounterState extends Record<string, unknown> {
|
|
4
|
+
count: number
|
|
5
|
+
lastUpdated: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Basic Counter Store
|
|
10
|
+
* RECOMMENDED FOR: Frontend (FE)
|
|
11
|
+
*/
|
|
12
|
+
export const useCounter = gstate<CounterState>({
|
|
13
|
+
count: 0,
|
|
14
|
+
lastUpdated: new Date().toISOString()
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
export const increment = () => {
|
|
18
|
+
useCounter.set('count', (d) => d + 1)
|
|
19
|
+
useCounter.set('lastUpdated', new Date().toISOString())
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const decrement = () => {
|
|
23
|
+
useCounter.set('count', (d) => d - 1)
|
|
24
|
+
useCounter.set('lastUpdated', new Date().toISOString())
|
|
25
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface BigDataState extends Record<string, unknown> {
|
|
2
|
+
largeCollection: any[];
|
|
3
|
+
metaInfo: {
|
|
4
|
+
totalItems: number;
|
|
5
|
+
lastSync: number;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export declare const useBigData: import("../../advanced").IStore<BigDataState> & (<K extends keyof BigDataState>(key: K) => readonly [BigDataState[K] | undefined, (val: BigDataState[K] | ((draft: BigDataState[K]) => BigDataState[K]), options?: unknown) => boolean]);
|
|
9
|
+
export declare const populateData: (count?: number) => void;
|
|
10
|
+
export declare const clearBigData: () => Promise<void>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { gstate } from '../../index'
|
|
2
|
+
import { indexedDBPlugin } from '../../plugins/official/indexeddb.plugin'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Big Data Store using IndexedDB
|
|
6
|
+
* RECOMMENDED FOR: Frontend (FE)
|
|
7
|
+
*
|
|
8
|
+
* Demonstrates how to handle massive datasets (GBs) that would exceed
|
|
9
|
+
* the standard 5MB-10MB limit of localStorage.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export interface BigDataState extends Record<string, unknown> {
|
|
13
|
+
largeCollection: any[]
|
|
14
|
+
metaInfo: { totalItems: number, lastSync: number }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const initialState: BigDataState = {
|
|
18
|
+
largeCollection: [],
|
|
19
|
+
metaInfo: { totalItems: 0, lastSync: Date.now() }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 1. Define the store
|
|
23
|
+
export const useBigData = gstate<BigDataState>(initialState, {
|
|
24
|
+
namespace: 'big-data-vault',
|
|
25
|
+
persist: false // Disable standard persistence to use IndexedDB exclusively
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// 2. Add the IndexedDB Plugin
|
|
29
|
+
useBigData._addPlugin(indexedDBPlugin({
|
|
30
|
+
dbName: 'UserLargeStorage',
|
|
31
|
+
storeName: 'appStates'
|
|
32
|
+
}))
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Action to simulate adding a large amount of data.
|
|
36
|
+
*/
|
|
37
|
+
export const populateData = (count: number = 1000) => {
|
|
38
|
+
const data: Array<{ id: string, payload: string, timestamp: number }> = []
|
|
39
|
+
for (let i = 0; i < count; i++) {
|
|
40
|
+
data.push({
|
|
41
|
+
id: `item_${i}`,
|
|
42
|
+
payload: 'X'.repeat(1024), // 1KB per item
|
|
43
|
+
timestamp: Date.now()
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
useBigData.transaction(() => {
|
|
48
|
+
useBigData.set('largeCollection', data)
|
|
49
|
+
useBigData.set('metaInfo', { totalItems: count, lastSync: Date.now() })
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Clear the database
|
|
55
|
+
*/
|
|
56
|
+
export const clearBigData = async () => {
|
|
57
|
+
// Access plugin methods registered on the store
|
|
58
|
+
await (useBigData as any).plugins.indexedDB.clear()
|
|
59
|
+
useBigData.set('largeCollection', [])
|
|
60
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface ThemeState extends Record<string, unknown> {
|
|
2
|
+
mode: 'light' | 'dark';
|
|
3
|
+
accent: string;
|
|
4
|
+
}
|
|
5
|
+
export declare const useTheme: import("../../advanced").IStore<ThemeState> & (<K extends keyof ThemeState>(key: K) => readonly [ThemeState[K] | undefined, (val: ThemeState[K] | ((draft: ThemeState[K]) => ThemeState[K]), options?: unknown) => boolean]);
|
|
6
|
+
export declare const initTheme: () => import("../../advanced").IStore<ThemeState> & (<K extends keyof ThemeState>(key: K) => readonly [ThemeState[K] | undefined, (val: ThemeState[K] | ((draft: ThemeState[K]) => ThemeState[K]), options?: unknown) => boolean]);
|
|
7
|
+
export declare const toggleTheme: () => void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { gstate, getStore } from '../../index'
|
|
2
|
+
|
|
3
|
+
// Define the shape of our theme state
|
|
4
|
+
export interface ThemeState extends Record<string, unknown> {
|
|
5
|
+
mode: 'light' | 'dark'
|
|
6
|
+
accent: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Global Theme Manager
|
|
11
|
+
* RECOMMENDED FOR: Frontend (FE)
|
|
12
|
+
*
|
|
13
|
+
* Demonstrates global state using a dedicated store instance.
|
|
14
|
+
*/
|
|
15
|
+
export const useTheme = gstate<ThemeState>({
|
|
16
|
+
mode: 'light',
|
|
17
|
+
accent: '#007bff'
|
|
18
|
+
}, {
|
|
19
|
+
namespace: 'theme-store',
|
|
20
|
+
persist: true
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Helper to initialize the theme (useful for SSR or specific init logic)
|
|
25
|
+
*/
|
|
26
|
+
export const initTheme = () => useTheme
|
|
27
|
+
|
|
28
|
+
// Reusable action to toggle theme
|
|
29
|
+
export const toggleTheme = () => {
|
|
30
|
+
const current = useTheme.get('mode')
|
|
31
|
+
useTheme.set('mode', current === 'light' ? 'dark' : 'light')
|
|
32
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface AppState extends Record<string, unknown> {
|
|
2
|
+
userProfile: {
|
|
3
|
+
name: string;
|
|
4
|
+
preferences: any;
|
|
5
|
+
};
|
|
6
|
+
projects: Array<{
|
|
7
|
+
id: string;
|
|
8
|
+
content: string;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
export declare const useHybridStore: import("../../advanced").IStore<AppState> & (<K extends keyof AppState>(key: K) => readonly [AppState[K] | undefined, (val: AppState[K] | ((draft: AppState[K]) => AppState[K]), options?: unknown) => boolean]);
|
|
12
|
+
export declare const syncNow: () => Promise<void>;
|
|
13
|
+
export declare const getSyncReport: () => {
|
|
14
|
+
lastSync: string;
|
|
15
|
+
count: any;
|
|
16
|
+
errors: any;
|
|
17
|
+
averageKeysPerSync: number;
|
|
18
|
+
};
|
|
19
|
+
export declare const updateName: (newName: string) => void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { gstate } from '../../index'
|
|
2
|
+
import { indexedDBPlugin } from '../../plugins/official/indexeddb.plugin'
|
|
3
|
+
import { cloudSyncPlugin, createMongoAdapter } from '../../plugins/official/cloud-sync.plugin'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hybrid Cloud Sync Store
|
|
7
|
+
* RECOMMENDED FOR: Frontend (FE) with Cloud Backup
|
|
8
|
+
*
|
|
9
|
+
* Demonstrates a multi-layer storage strategy:
|
|
10
|
+
* 1. Cache: Memory (fast)
|
|
11
|
+
* 2. Persistent Local: IndexedDB (large capacity)
|
|
12
|
+
* 3. remote: MongoDB Cloud (On-demand/Scheduled backup)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export interface AppState extends Record<string, unknown> {
|
|
16
|
+
userProfile: { name: string; preferences: any }
|
|
17
|
+
projects: Array<{ id: string; content: string }>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const initialState: AppState = {
|
|
21
|
+
userProfile: { name: 'Dario', preferences: { theme: 'dark' } },
|
|
22
|
+
projects: []
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 1. Initialize the store
|
|
26
|
+
export const useHybridStore = gstate<AppState>(initialState, {
|
|
27
|
+
namespace: 'hybrid-app-vault',
|
|
28
|
+
persist: false // We use plugins for persistence
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
// 2. Add IndexedDB for local persistence (up to GBs)
|
|
32
|
+
useHybridStore._addPlugin(indexedDBPlugin({
|
|
33
|
+
dbName: 'LocalCacheDB'
|
|
34
|
+
}))
|
|
35
|
+
|
|
36
|
+
// 3. Add Cloud Sync for remote backup
|
|
37
|
+
// Configured to automatically sync every 5 minutes (300000ms)
|
|
38
|
+
useHybridStore._addPlugin(cloudSyncPlugin({
|
|
39
|
+
adapter: createMongoAdapter('https://api.mongodb.com/v1', 'YOUR_SECRET_API_KEY'),
|
|
40
|
+
autoSyncInterval: 300000,
|
|
41
|
+
onSync: (stats) => {
|
|
42
|
+
console.info(`[CloudSync] Success! Keys: ${stats.totalKeysSynced}, Total Bytes: ${stats.totalBytesSynced}`)
|
|
43
|
+
}
|
|
44
|
+
}))
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Manual Trigger for Cloud Sync
|
|
48
|
+
*/
|
|
49
|
+
export const syncNow = async () => {
|
|
50
|
+
const result = await (useHybridStore as any).plugins.cloudSync.sync()
|
|
51
|
+
if (result.status === 'success') {
|
|
52
|
+
alert(`Sync completed! ${result.stats.totalKeysSynced} items pushed to cloud.`)
|
|
53
|
+
} else if (result.status === 'no-change') {
|
|
54
|
+
console.log('No new changes to sync.')
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get synchronization diagnostics
|
|
60
|
+
*/
|
|
61
|
+
export const getSyncReport = () => {
|
|
62
|
+
const stats = (useHybridStore as any).plugins.cloudSync.getStats()
|
|
63
|
+
return {
|
|
64
|
+
lastSync: stats.lastSyncTimestamp ? new Date(stats.lastSyncTimestamp).toLocaleString() : 'Never',
|
|
65
|
+
count: stats.syncCount,
|
|
66
|
+
errors: stats.errors,
|
|
67
|
+
averageKeysPerSync: stats.syncCount > 0 ? stats.totalKeysSynced / stats.syncCount : 0
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Action to update profile
|
|
73
|
+
*/
|
|
74
|
+
export const updateName = (newName: string) => {
|
|
75
|
+
useHybridStore.set('userProfile', (draft) => {
|
|
76
|
+
draft.name = newName
|
|
77
|
+
})
|
|
78
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface CartItem {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
price: number;
|
|
5
|
+
quantity: number;
|
|
6
|
+
}
|
|
7
|
+
export interface CartState extends Record<string, unknown> {
|
|
8
|
+
items: CartItem[];
|
|
9
|
+
coupon: string | null;
|
|
10
|
+
}
|
|
11
|
+
export declare const useCart: import("../../advanced").IStore<CartState> & (<K extends keyof CartState>(key: K) => readonly [CartState[K] | undefined, (val: CartState[K] | ((draft: CartState[K]) => CartState[K]), options?: unknown) => boolean]);
|
|
12
|
+
export declare const addToCart: (product: Omit<CartItem, "quantity">) => void;
|
|
13
|
+
export declare const getCartTotal: () => number;
|