@yakocloud/state-vocab 3.0.1 → 3.0.3

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 CHANGED
@@ -188,6 +188,8 @@ Wraps a nested object of `defineState()` nodes and injects dot-separated paths i
188
188
  | Option | Type | Description | Default |
189
189
  |---|---|---|---|
190
190
  | `verbose` | `boolean \| undefined` | Log current state to the browser console on every change | `false` |
191
+ | `verbosePath` | `string \| undefined` | Narrow verbose logging to a specific subtree (dot-separated path). When set, only that subtree is logged instead of the entire state. TypeScript will autocomplete valid paths based on your tree. | `undefined` |
192
+ | `ssr` | `boolean \| undefined` | Defer storage reads until after hydration (Next.js / SSR) | `false` |
191
193
 
192
194
  ```ts
193
195
  const storage = setupStorage({
@@ -207,6 +209,44 @@ Enable verbose logging during development:
207
209
  const storage = setupStorage({ ... }, { verbose: true })
208
210
  ```
209
211
 
212
+ Narrow verbose logging to a specific subtree:
213
+
214
+ ```ts
215
+ const storage = setupStorage({
216
+ user: {
217
+ profile: defineState({ ... }),
218
+ settings: defineState({ ... }),
219
+ },
220
+ cart: {
221
+ items: defineState({ ... }),
222
+ },
223
+ }, {
224
+ verbose: true,
225
+ verbosePath: "user", // only logs changes inside "user.*"
226
+ })
227
+ ```
228
+
229
+ TypeScript will only accept paths that exist in your tree — `"user"`, `"user.profile"`, `"cart.items"`, etc. Invalid paths are caught at compile time.
230
+
231
+ ### SSR / Next.js
232
+
233
+ When using localStorage or sessionStorage in a Next.js app, the server renders with `defaultValue` while the client reads the persisted value — causing a hydration mismatch. Pass `ssr: true` to fix this:
234
+
235
+ ```ts
236
+ // lib/storage.ts
237
+ const storage = setupStorage({
238
+ preference: {
239
+ theme: defineState<Theme>({ storage: localStorage, defaultValue: 'Dark' }),
240
+ },
241
+ }, { ssr: true })
242
+ ```
243
+
244
+ With `ssr: true`:
245
+ - **Server & first client render** — always use `defaultValue`, storage is not read
246
+ - **After hydration** — `useLayoutEffect` fires synchronously before paint, reads storage and updates state
247
+
248
+ This guarantees the server and client produce identical markup, and the value from storage is applied without a visible flash.
249
+
210
250
  ## `useState` Hook
211
251
 
212
252
  Each state node exposes a `.useState()` method that works like React's built-in `useState` but adds persistence and callbacks.
@@ -389,6 +429,8 @@ createRoot(document.getElementById('root')!).render(<Page />)
389
429
  | Option | Type | Default |
390
430
  |---|---|---|
391
431
  | `verbose` | `boolean \| undefined` | `false` |
432
+ | `verbosePath` | `Path<T> \| undefined` | `undefined` |
433
+ | `ssr` | `boolean \| undefined` | `false` |
392
434
 
393
435
  Returns a proxied copy of `tree` with paths injected into all leaf nodes.
394
436
 
@@ -401,4 +443,4 @@ Returns a proxied copy of `tree` with paths injected into all leaf nodes.
401
443
  | `onSet` | `(next: T, prev: T) => void \| undefined` | Callback after state change |
402
444
  | `bidirectional` | `true \| undefined` | Sync state across browser tabs |
403
445
 
404
- Returns `[value, setValue, resetValue]`.
446
+ Returns `[value, setValue, resetValue]`
@@ -1,3 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("react"),M=Symbol("state-def"),w=Symbol("state-path"),$=Symbol("state-verbose");function z(e,t,s){if(!t)return e;const r=t.split(".");let n=e;for(const o of r)if(n!==null&&typeof n=="object"&&o in n)n=n[o];else return s;return n===void 0?s:n}function N(e,t,s){const r=t.replace(/\[(\d+)\]/g,".$1").split(".");let n=e;for(let o=0;o<r.length-1;o++){const a=r[o],g=r[o+1];(n[a]===void 0||n[a]===null)&&(n[a]=/^\d+$/.test(g)?[]:{}),n=n[a]}return n[r[r.length-1]]=s,e}function j(e,t=0){let s;return function(...r){s!==void 0&&clearTimeout(s),s=setTimeout(()=>{s=void 0,e.apply(this,r)},t)}}function A(e,t,s=[]){return S.useMemo(()=>j(e,t),s)}function D(e){const t=JSON.stringify(e,null,2).split(`
2
- `),s=[],r=[];for(const n of t){const o=n.match(/^(\s*)"([^"]+)"(\s*:\s*)(.+)$/);if(o){const[,a,g,u,l]=o;s.push(`${a}%c"${g}"%c${u}%c${l}`),r.push("color: #9cdcfe; font-weight: bold","color: #cccccc","color: #ce9178")}else s.push(`%c${n}`),r.push("color: #cccccc")}console.log(s.join(`
3
- `),...r,e)}const P=e=>typeof e=="function",O=e=>typeof e=="function",p=e=>typeof e<"u",k=e=>O(e)?e():e;class F{#e;#t;constructor(){this.#e={},this.#t=new Set}subscribe(t){return this.#t.add(t),()=>this.#t.delete(t)}getClientSnapshot(){return this.#e}getServerSnapshot(){return this.#e}set(t,s){const r=z(this.#e,t),n=P(s)?s(r):s,o={...this.#e};N(o,t,n),this.#e=o,this.#t.forEach(a=>a())}}function J(e={}){const t=new F;return{[M]:!0,[w]:"",[$]:!1,useState(s){const r=k(e.storage),n=e.serialize??JSON.stringify,o=e.deserialize??JSON.parse,a=k(e.defaultValue),g=e.bidirectional;s??={};const u=k(s.defaultValue)??a,l=s.bidirectional??g,f=A(s.onSet??(()=>{}),s.delayedSet,[]),c=this[w],y=this[$],h=S.useRef(void 0),m=S.useRef(!1);if(!m.current){m.current=!0;let i=z(t.getServerSnapshot(),c);if(!p(i)){if(i=u,r){const d=r.getItem(c);d===null?p(i)&&r.setItem(c,n(i)):i=o(d)}p(i)&&t.set(c,i)}}const V=S.useSyncExternalStore(t.subscribe.bind(t),()=>t.getClientSnapshot(),()=>t.getServerSnapshot());y&&D(V);const v=z(V,c);h.current=v;const b=S.useEffectEvent(i=>{if(i.key!==c)return;const d=i.newValue,T=(d===null?null:o(d))??u;p(T)&&(t.set(c,T),f(T,h.current))});S.useEffect(()=>{if(l)return window.addEventListener("storage",b),()=>window.removeEventListener("storage",b)},[l]);const E=S.useCallback(i=>{const d=P(i)?i(h.current):i;t.set(c,d),f(d,h.current),r&&r.setItem(c,n(d))},[c,r,n,f]),x=S.useCallback(()=>{const i=u;if(!p(i)){r?.removeItem(c);return}t.set(c,i),f(i,h.current),r&&r.setItem(c,n(i))},[c,u,r,n,f]);return[v,E,x]},toString(){return this[w]}}}const C=new WeakMap,I=new WeakMap;function R(e,t){t??={};const{path:s="",verbose:r}=t;let n=C.get(e);n||(n=new Map,C.set(e,n));const o=n.get(s);if(o)return o;const a=new Proxy(e,{get(g,u){const l=g[u],f=s?`${s}.${String(u)}`:String(u);if(l&&typeof l=="object"&&M in l){const c=l;let y=I.get(c);y||(y=new Map,I.set(c,y));const h=y.get(f);if(h)return h;const m=Reflect.ownKeys(c).filter(b=>typeof c[b]=="function"),V=Object.fromEntries(m.map(b=>[b,(...E)=>c[b].call({...c,[w]:f,[$]:r},...E)])),v={...c,...V};return y.set(f,v),v}return l&&typeof l=="object"?R(l,{path:f,verbose:r}):l}});return n.set(s,a),a}function L(e,t){return R(e,t)}exports.defineState=J;exports.setupStorage=L;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("react"),M=Symbol("state-def"),k=Symbol("state-path"),R=Symbol("state-verbose"),x=Symbol("state-verbose-path"),A=Symbol("state-ssr");function I(t,e,s){if(!e)return t;const i=e.split(".");let c=t;for(const r of i)if(c!==null&&typeof c=="object"&&r in c)c=c[r];else return s;return c===void 0?s:c}function j(t,e,s){const i=e.replace(/\[(\d+)\]/g,".$1").split(".");let c=t;for(let r=0;r<i.length-1;r++){const n=i[r],l=i[r+1];(c[n]===void 0||c[n]===null)&&(c[n]=/^\d+$/.test(l)?[]:{}),c=c[n]}return c[i[i.length-1]]=s,t}function D(t,e=0){let s;return function(...i){s!==void 0&&clearTimeout(s),s=setTimeout(()=>{s=void 0,t.apply(this,i)},e)}}function B(t,e,s=[]){return d.useMemo(()=>D(t,e),s)}function C(t){const e=JSON.stringify(t,null,2).split(`
2
+ `),s=[],i=[];for(const c of e){const r=c.match(/^(\s*)"([^"]+)"(\s*:\s*)(.+)$/);if(r){const[,n,l,h,u]=r;s.push(`${n}%c"${l}"%c${h}%c${u}`),i.push("color: #9cdcfe; font-weight: bold","color: #cccccc","color: #ce9178")}else s.push(`%c${c}`),i.push("color: #cccccc")}console.log(s.join(`
3
+ `),...i,t)}const _=t=>typeof t=="function",F=t=>typeof t=="function",T=t=>typeof t<"u",P=t=>F(t)?t():t,L=typeof window>"u",J=L?d.useEffect:d.useLayoutEffect;class H{#e;#t;constructor(){this.#e={},this.#t=new Set}subscribe(e){return this.#t.add(e),()=>this.#t.delete(e)}getClientSnapshot(){return this.#e}getServerSnapshot(){return this.#e}get(e){return I(this.#e,e)}set(e,s){const i=I(this.#e,e),c=_(s)?s(i):s,r={...this.#e};j(r,e,c),this.#e=r,this.#t.forEach(n=>n())}}function K(t={}){const e=new H,s=t.serialize??JSON.stringify,i=t.deserialize??JSON.parse,c=(r,n,l)=>{const h=n.getItem(r);h===null?T(l)&&n.setItem(r,s(l)):e.set(r,i(h))};return{[M]:!0,[k]:"",[R]:!1,[x]:"",[A]:!1,useState(r){const n=L?void 0:P(t.storage),l=P(t.defaultValue),h=t.bidirectional;r??={};const u=P(r.defaultValue)??l,w=r.bidirectional??h,S=B(r.onSet??(()=>{}),r.delayedSet,[]),o=this[k],v=this[R],f=this[x],y=this[A],b=d.useRef(void 0),V=d.useRef(!1);if(!V.current){V.current=!0;let a=e.get(o);T(a)||(a=u,T(a)&&e.set(o,a)),!y&&n&&c(o,n,a)}const E=d.useSyncExternalStore(e.subscribe.bind(e),e.getClientSnapshot.bind(e),e.getServerSnapshot.bind(e));if(v)if(f){const a=I(E,f);a&&C(a)}else C(E);const p=I(E,o,u);b.current=p,J(()=>{!y||!n||c(o,n,p)},[]);const g=d.useEffectEvent(a=>{if(a.key!==o)return;const m=a.newValue,z=(m===null?null:i(m))??u;T(z)&&(e.set(o,z),S(z,b.current))});d.useEffect(()=>{if(w)return window.addEventListener("storage",g),()=>window.removeEventListener("storage",g)},[w]);const $=d.useCallback(a=>{const m=_(a)?a(b.current):a;e.set(o,m),S(m,b.current),n&&n.setItem(o,s(m))},[o,n,S]),O=d.useCallback(()=>{const a=u;if(!T(a)){n?.removeItem(o);return}e.set(o,a),S(a,b.current),n&&n.setItem(o,s(a))},[o,u,n,S]);return[p,$,O]},toString(){return this[k]}}}function N(t,e){const{path:s="",verbose:i,verbosePath:c,ssr:r,cache:n}=e;let l=n.proxy.get(t);l||(l=new Map,n.proxy.set(t,l));const h=l.get(s);if(h)return h;const u=new Proxy(t,{get(w,S){const o=w[S],v=s?`${s}.${String(S)}`:String(S);if(o&&typeof o=="object"&&M in o){const f=o;let y=n.leaf.get(f);y||(y=new Map,n.leaf.set(f,y));const b=y.get(v);if(b)return b;const V=Reflect.ownKeys(f).filter(g=>typeof f[g]=="function"),E=Object.fromEntries(V.map(g=>[g,(...$)=>f[g].call({...f,[k]:v,[R]:i,[x]:c,[A]:r},...$)])),p={...f,...E};return y.set(v,p),p}return o&&typeof o=="object"?N(o,{...e,path:v}):o}});return l.set(s,u),u}function W(t,e){return N(t,{...e,verbosePath:e?.verbosePath??"",cache:{proxy:new WeakMap,leaf:new WeakMap}})}exports.defineState=K;exports.setupStorage=W;
@@ -1,68 +1,68 @@
1
- import { useMemo as A, useRef as z, useSyncExternalStore as D, useEffectEvent as j, useEffect as F, useCallback as I } from "react";
2
- const M = Symbol("state-def"), V = Symbol("state-path"), $ = Symbol("state-verbose");
3
- function k(e, t, s) {
4
- if (!t)
5
- return e;
6
- const r = t.split(".");
7
- let n = e;
8
- for (const o of r)
9
- if (n !== null && typeof n == "object" && o in n)
10
- n = n[o];
1
+ import { useMemo as B, useRef as R, useSyncExternalStore as F, useEffect as L, useLayoutEffect as J, useEffectEvent as H, useCallback as C } from "react";
2
+ const M = Symbol("state-def"), V = Symbol("state-path"), x = Symbol("state-verbose"), P = Symbol("state-verbose-path"), A = Symbol("state-ssr");
3
+ function I(t, e, s) {
4
+ if (!e)
5
+ return t;
6
+ const i = e.split(".");
7
+ let o = t;
8
+ for (const r of i)
9
+ if (o !== null && typeof o == "object" && r in o)
10
+ o = o[r];
11
11
  else
12
12
  return s;
13
- return n === void 0 ? s : n;
13
+ return o === void 0 ? s : o;
14
14
  }
15
- function J(e, t, s) {
16
- const r = t.replace(/\[(\d+)\]/g, ".$1").split(".");
17
- let n = e;
18
- for (let o = 0; o < r.length - 1; o++) {
19
- const l = r[o], S = r[o + 1];
20
- (n[l] === void 0 || n[l] === null) && (n[l] = /^\d+$/.test(S) ? [] : {}), n = n[l];
15
+ function K(t, e, s) {
16
+ const i = e.replace(/\[(\d+)\]/g, ".$1").split(".");
17
+ let o = t;
18
+ for (let r = 0; r < i.length - 1; r++) {
19
+ const n = i[r], a = i[r + 1];
20
+ (o[n] === void 0 || o[n] === null) && (o[n] = /^\d+$/.test(a) ? [] : {}), o = o[n];
21
21
  }
22
- return n[r[r.length - 1]] = s, e;
22
+ return o[i[i.length - 1]] = s, t;
23
23
  }
24
- function L(e, t = 0) {
24
+ function W(t, e = 0) {
25
25
  let s;
26
- return function(...r) {
26
+ return function(...i) {
27
27
  s !== void 0 && clearTimeout(s), s = setTimeout(() => {
28
- s = void 0, e.apply(this, r);
29
- }, t);
28
+ s = void 0, t.apply(this, i);
29
+ }, e);
30
30
  };
31
31
  }
32
- function O(e, t, s = []) {
33
- return A(
34
- () => L(e, t),
32
+ function q(t, e, s = []) {
33
+ return B(
34
+ () => W(t, e),
35
35
  // eslint-disable-next-line react-hooks/exhaustive-deps
36
36
  s
37
37
  );
38
38
  }
39
- function _(e) {
40
- const t = JSON.stringify(e, null, 2).split(`
41
- `), s = [], r = [];
42
- for (const n of t) {
43
- const o = n.match(/^(\s*)"([^"]+)"(\s*:\s*)(.+)$/);
44
- if (o) {
45
- const [, l, S, u, a] = o;
46
- s.push(`${l}%c"${S}"%c${u}%c${a}`), r.push(
39
+ function _(t) {
40
+ const e = JSON.stringify(t, null, 2).split(`
41
+ `), s = [], i = [];
42
+ for (const o of e) {
43
+ const r = o.match(/^(\s*)"([^"]+)"(\s*:\s*)(.+)$/);
44
+ if (r) {
45
+ const [, n, a, d, u] = r;
46
+ s.push(`${n}%c"${a}"%c${d}%c${u}`), i.push(
47
47
  "color: #9cdcfe; font-weight: bold",
48
48
  "color: #cccccc",
49
49
  "color: #ce9178"
50
50
  );
51
51
  } else
52
- s.push(`%c${n}`), r.push("color: #cccccc");
52
+ s.push(`%c${o}`), i.push("color: #cccccc");
53
53
  }
54
54
  console.log(s.join(`
55
- `), ...r, e);
55
+ `), ...i, t);
56
56
  }
57
- const N = (e) => typeof e == "function", B = (e) => typeof e == "function", v = (e) => typeof e < "u", T = (e) => B(e) ? e() : e;
58
- class K {
57
+ const N = (t) => typeof t == "function", G = (t) => typeof t == "function", E = (t) => typeof t < "u", z = (t) => G(t) ? t() : t, D = typeof window > "u", Q = D ? L : J;
58
+ class U {
59
59
  #e;
60
60
  #t;
61
61
  constructor() {
62
62
  this.#e = {}, this.#t = /* @__PURE__ */ new Set();
63
63
  }
64
- subscribe(t) {
65
- return this.#t.add(t), () => this.#t.delete(t);
64
+ subscribe(e) {
65
+ return this.#t.add(e), () => this.#t.delete(e);
66
66
  }
67
67
  getClientSnapshot() {
68
68
  return this.#e;
@@ -70,84 +70,84 @@ class K {
70
70
  getServerSnapshot() {
71
71
  return this.#e;
72
72
  }
73
- set(t, s) {
74
- const r = k(this.#e, t), n = N(s) ? s(r) : s, o = { ...this.#e };
75
- J(o, t, n), this.#e = o, this.#t.forEach((l) => l());
73
+ get(e) {
74
+ return I(this.#e, e);
75
+ }
76
+ set(e, s) {
77
+ const i = I(this.#e, e), o = N(s) ? s(i) : s, r = { ...this.#e };
78
+ K(r, e, o), this.#e = r, this.#t.forEach((n) => n());
76
79
  }
77
80
  }
78
- function q(e = {}) {
79
- const t = new K();
81
+ function Z(t = {}) {
82
+ const e = new U(), s = t.serialize ?? JSON.stringify, i = t.deserialize ?? JSON.parse, o = (r, n, a) => {
83
+ const d = n.getItem(r);
84
+ d === null ? E(a) && n.setItem(r, s(a)) : e.set(r, i(d));
85
+ };
80
86
  return {
81
87
  [M]: !0,
82
88
  // marks this object as a leaf in the router tree
83
89
  [V]: "",
84
90
  // placeholder; injected at runtime by injectPaths()
85
- [$]: !1,
91
+ [x]: !1,
92
+ // placeholder
93
+ [P]: "",
94
+ // placeholder
95
+ [A]: !1,
86
96
  // placeholder
87
- useState(s) {
88
- const r = T(e.storage), n = e.serialize ?? JSON.stringify, o = e.deserialize ?? JSON.parse, l = T(e.defaultValue), S = e.bidirectional;
89
- s ??= {};
90
- const u = T(s.defaultValue) ?? l, a = s.bidirectional ?? S, f = O(
91
- s.onSet ?? (() => {
97
+ useState(r) {
98
+ const n = D ? void 0 : z(t.storage), a = z(t.defaultValue), d = t.bidirectional;
99
+ r ??= {};
100
+ const u = z(r.defaultValue) ?? a, w = r.bidirectional ?? d, h = q(
101
+ r.onSet ?? (() => {
92
102
  }),
93
- s.delayedSet,
103
+ r.delayedSet,
94
104
  []
95
- ), c = this[V], g = this[$], h = z(void 0), b = z(!1);
96
- if (!b.current) {
97
- b.current = !0;
98
- let i = k(t.getServerSnapshot(), c);
99
- if (!v(i)) {
100
- if (i = u, r) {
101
- const d = r.getItem(c);
102
- d === null ? v(i) && r.setItem(c, n(i)) : i = o(d);
103
- }
104
- v(i) && t.set(c, i);
105
- }
105
+ ), c = this[V], g = this[x], f = this[P], S = this[A], y = R(void 0), T = R(!1);
106
+ if (!T.current) {
107
+ T.current = !0;
108
+ let l = e.get(c);
109
+ E(l) || (l = u, E(l) && e.set(c, l)), !S && n && o(c, n, l);
106
110
  }
107
- const m = D(
108
- t.subscribe.bind(t),
109
- () => t.getClientSnapshot(),
110
- () => t.getServerSnapshot()
111
+ const m = F(
112
+ e.subscribe.bind(e),
113
+ e.getClientSnapshot.bind(e),
114
+ e.getServerSnapshot.bind(e)
111
115
  );
112
- g && _(m);
113
- const p = k(m, c);
114
- h.current = p;
115
- const y = j((i) => {
116
- if (i.key !== c)
116
+ if (g)
117
+ if (f) {
118
+ const l = I(m, f);
119
+ l && _(l);
120
+ } else
121
+ _(m);
122
+ const v = I(m, c, u);
123
+ y.current = v, Q(() => {
124
+ !S || !n || o(c, n, v);
125
+ }, []);
126
+ const b = H((l) => {
127
+ if (l.key !== c)
117
128
  return;
118
- const d = i.newValue, E = (d === null ? null : o(d)) ?? u;
119
- v(E) && (t.set(c, E), f(E, h.current));
129
+ const p = l.newValue, k = (p === null ? null : i(p)) ?? u;
130
+ E(k) && (e.set(c, k), h(k, y.current));
120
131
  });
121
- F(() => {
122
- if (a)
123
- return window.addEventListener("storage", y), () => window.removeEventListener("storage", y);
124
- }, [a]);
125
- const w = I((i) => {
126
- const d = N(i) ? i(h.current) : i;
127
- t.set(c, d), f(d, h.current), r && r.setItem(c, n(d));
128
- }, [
129
- c,
130
- r,
131
- n,
132
- f
133
- ]), R = I(() => {
134
- const i = u;
135
- if (!v(i)) {
136
- r?.removeItem(c);
132
+ L(() => {
133
+ if (w)
134
+ return window.addEventListener("storage", b), () => window.removeEventListener("storage", b);
135
+ }, [w]);
136
+ const $ = C((l) => {
137
+ const p = N(l) ? l(y.current) : l;
138
+ e.set(c, p), h(p, y.current), n && n.setItem(c, s(p));
139
+ }, [c, n, h]), j = C(() => {
140
+ const l = u;
141
+ if (!E(l)) {
142
+ n?.removeItem(c);
137
143
  return;
138
144
  }
139
- t.set(c, i), f(i, h.current), r && r.setItem(c, n(i));
140
- }, [
141
- c,
142
- u,
143
- r,
144
- n,
145
- f
146
- ]);
145
+ e.set(c, l), h(l, y.current), n && n.setItem(c, s(l));
146
+ }, [c, u, n, h]);
147
147
  return [
148
- p,
149
- w,
150
- R
148
+ v,
149
+ $,
150
+ j
151
151
  ];
152
152
  },
153
153
  /** Returns the fully qualified job name (dot-separated path). */
@@ -156,57 +156,67 @@ function q(e = {}) {
156
156
  }
157
157
  };
158
158
  }
159
- const C = /* @__PURE__ */ new WeakMap(), x = /* @__PURE__ */ new WeakMap();
160
- function P(e, t) {
161
- t ??= {};
159
+ function O(t, e) {
162
160
  const {
163
161
  path: s = "",
164
- verbose: r
165
- } = t;
166
- let n = C.get(e);
167
- n || (n = /* @__PURE__ */ new Map(), C.set(e, n));
168
- const o = n.get(s);
169
- if (o)
170
- return o;
171
- const l = new Proxy(e, {
172
- get(S, u) {
173
- const a = S[u], f = s ? `${s}.${String(u)}` : String(u);
174
- if (a && typeof a == "object" && M in a) {
175
- const c = a;
176
- let g = x.get(c);
177
- g || (g = /* @__PURE__ */ new Map(), x.set(c, g));
178
- const h = g.get(f);
179
- if (h)
180
- return h;
181
- const b = Reflect.ownKeys(c).filter(
182
- (y) => typeof c[y] == "function"
162
+ verbose: i,
163
+ verbosePath: o,
164
+ ssr: r,
165
+ cache: n
166
+ } = e;
167
+ let a = n.proxy.get(t);
168
+ a || (a = /* @__PURE__ */ new Map(), n.proxy.set(t, a));
169
+ const d = a.get(s);
170
+ if (d)
171
+ return d;
172
+ const u = new Proxy(t, {
173
+ get(w, h) {
174
+ const c = w[h], g = s ? `${s}.${String(h)}` : String(h);
175
+ if (c && typeof c == "object" && M in c) {
176
+ const f = c;
177
+ let S = n.leaf.get(f);
178
+ S || (S = /* @__PURE__ */ new Map(), n.leaf.set(f, S));
179
+ const y = S.get(g);
180
+ if (y)
181
+ return y;
182
+ const T = Reflect.ownKeys(f).filter(
183
+ (b) => typeof f[b] == "function"
183
184
  ), m = Object.fromEntries(
184
- b.map((y) => [
185
- y,
186
- (...w) => c[y].call(
185
+ T.map((b) => [
186
+ b,
187
+ (...$) => f[b].call(
187
188
  {
188
- ...c,
189
- [V]: f,
190
- [$]: r
189
+ ...f,
190
+ [V]: g,
191
+ [x]: i,
192
+ [P]: o,
193
+ [A]: r
191
194
  },
192
- ...w
195
+ ...$
193
196
  )
194
197
  ])
195
- ), p = { ...c, ...m };
196
- return g.set(f, p), p;
198
+ ), v = { ...f, ...m };
199
+ return S.set(g, v), v;
197
200
  }
198
- return a && typeof a == "object" ? P(a, {
199
- path: f,
200
- verbose: r
201
- }) : a;
201
+ return c && typeof c == "object" ? O(c, {
202
+ ...e,
203
+ path: g
204
+ }) : c;
202
205
  }
203
206
  });
204
- return n.set(s, l), l;
207
+ return a.set(s, u), u;
205
208
  }
206
- function G(e, t) {
207
- return P(e, t);
209
+ function ee(t, e) {
210
+ return O(t, {
211
+ ...e,
212
+ verbosePath: e?.verbosePath ?? "",
213
+ cache: {
214
+ proxy: /* @__PURE__ */ new WeakMap(),
215
+ leaf: /* @__PURE__ */ new WeakMap()
216
+ }
217
+ });
208
218
  }
209
219
  export {
210
- q as defineState,
211
- G as setupStorage
220
+ Z as defineState,
221
+ ee as setupStorage
212
222
  };
@@ -1,3 +1,5 @@
1
1
  export declare const STATE_DEFINITION: unique symbol;
2
2
  export declare const STATE_PATH: unique symbol;
3
3
  export declare const STATE_VERBOSE: unique symbol;
4
+ export declare const STATE_VERBOSE_PATH: unique symbol;
5
+ export declare const STATE_SSR: unique symbol;
@@ -1,2 +1,2 @@
1
1
  export declare const toLocalDatetimeString: (date: Date | null) => string;
2
- export declare const toDateString: (date: Date | null) => string | undefined;
2
+ export declare const toDateString: (date: Date | null) => string;
@@ -1,6 +1,14 @@
1
- type InjectPathsOptions = {
1
+ import { STATE_DEFINITION } from "./constants";
2
+ type Path<T, Prefix extends string = ""> = {
3
+ [K in keyof T & string]: T[K] extends object ? T[K] extends {
4
+ [STATE_DEFINITION]: unknown;
5
+ } ? `${Prefix}${K}` : `${Prefix}${K}` | Path<T[K], `${Prefix}${K}.`> : `${Prefix}${K}`;
6
+ }[keyof T & string];
7
+ type InjectPathsOptions<T extends object> = {
2
8
  path: string;
3
9
  verbose: boolean;
10
+ verbosePath: Path<T>;
11
+ ssr: boolean;
4
12
  };
5
- export declare function setupStorage<T extends object>(native: T, options?: Partial<Omit<InjectPathsOptions, "path">>): T;
13
+ export declare function setupStorage<T extends object>(native: T, options?: Partial<Omit<InjectPathsOptions<T>, "path">>): T;
6
14
  export {};
@@ -1,4 +1,4 @@
1
- import { STATE_DEFINITION, STATE_PATH, STATE_VERBOSE } from "./constants";
1
+ import { STATE_DEFINITION, STATE_PATH, STATE_SSR, STATE_VERBOSE, STATE_VERBOSE_PATH } from "./constants";
2
2
  import type { Deserialize, Serialize, ValueOrFactory, ValueOrTransformer } from "./state.types";
3
3
  export declare function defineState<D>(definitionOptions?: {
4
4
  storage?: ValueOrFactory<Storage>;
@@ -10,9 +10,13 @@ export declare function defineState<D>(definitionOptions?: {
10
10
  [STATE_DEFINITION]: boolean;
11
11
  [STATE_PATH]: string;
12
12
  [STATE_VERBOSE]: boolean;
13
+ [STATE_VERBOSE_PATH]: string;
14
+ [STATE_SSR]: boolean;
13
15
  useState(this: {
14
16
  [STATE_PATH]: string;
15
17
  [STATE_VERBOSE]: boolean;
18
+ [STATE_VERBOSE_PATH]: string;
19
+ [STATE_SSR]: boolean;
16
20
  }, options?: {
17
21
  defaultValue?: ValueOrFactory<D>;
18
22
  delayedSet?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yakocloud/state-vocab",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "main": "dist/state-vocab.cjs.js",
5
5
  "module": "dist/state-vocab.es.js",
6
6
  "types": "dist/types/index.d.ts",