@biglogic/rgs 3.9.8 → 3.9.10

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/SKILL.md ADDED
@@ -0,0 +1,148 @@
1
+ ---
2
+ name: biglogic-rgs
3
+ description: Reactive global state management library for React - simple, secure, scalable
4
+ ---
5
+
6
+ # @biglogic/rgs - Reactive Global State
7
+
8
+ ## Overview
9
+
10
+ RGS (Argis) is a reactive global state management library for React. Simple, secure, and scalable. It provides typed state management with built-in persistence, security, and sync capabilities.
11
+
12
+ ## Instructions
13
+
14
+ ### Constraints
15
+
16
+ 1. **TypeScript Strict**: Always use strict typing - avoid `any` unless absolutely necessary
17
+ 2. **No console.log**: Use `console.debug` for debugging, or `console.warn`/`console.error` for warnings/errors
18
+ 3. **Build before commit**: Always run `npm run build` successfully before any commit
19
+ 4. **Test TypeScript**: Run `npx tsc --noEmit` to verify no type errors
20
+ 5. **No console.log debugging**: Never leave console.log statements in production code
21
+ 6. **Use arrow functions**: Prefer arrow functions over function declarations
22
+
23
+ ### Workflow
24
+
25
+ 1. **For new features**:
26
+ - Create in `core/` folder
27
+ - Export from `index.ts` if public API
28
+ - Add types to `core/types.ts`
29
+ - Run build and type-check
30
+
31
+ 2. **For bug fixes**:
32
+ - Run `npx tsc --noEmit` to identify issues
33
+ - Fix type errors first
34
+ - Verify build succeeds
35
+
36
+ 3. **For testing**:
37
+ - Run `npm run build` or `npm run test`
38
+ - Config is in `tests/` folder
39
+
40
+ ### Output Format
41
+
42
+ When adding new hooks or functions:
43
+
44
+ ```typescript
45
+ /**
46
+ * Description of what the hook does.
47
+ * @param param - Description of parameter
48
+ * @returns Description of return value
49
+ */
50
+ export const myHook = (param: string): boolean => {
51
+ // Implementation
52
+ }
53
+ ```
54
+
55
+ ## Usage Examples
56
+
57
+ ### Basic Store Creation
58
+
59
+ ```typescript
60
+ import { gstate } from '@biglogic/rgs'
61
+
62
+ // Create store with typed hook
63
+ const store = gstate({ count: 0, name: 'John' })
64
+
65
+ // Use typed hook for specific keys
66
+ const [count, setCount] = store('count')
67
+ const [name, setName] = store('name')
68
+
69
+ // Or use store directly
70
+ store.set('count', 5)
71
+ store.get('count')
72
+ ```
73
+
74
+ ### SSR Support
75
+
76
+ ```typescript
77
+ import { isServerSide, hydrateOnClient } from '@biglogic/rgs'
78
+
79
+ if (isServerSide()) {
80
+ // Server-side logic
81
+ }
82
+
83
+ hydrateOnClient(myStore)
84
+ ```
85
+
86
+ ### Security
87
+
88
+ ```typescript
89
+ import { generateEncryptionKey, validateKey } from '@biglogic/rgs'
90
+
91
+ // Generate encryption key for secure persistence
92
+ const key = generateEncryptionKey()
93
+
94
+ // Validate keys to prevent XSS
95
+ if (validateKey(userInput)) {
96
+ store.set(userInput, value)
97
+ }
98
+ ```
99
+
100
+ ## API Quick Reference
101
+
102
+ ### Core
103
+
104
+ | Function | Description |
105
+ |----------|-------------|
106
+ | `gstate(initialState, config?)` | Creates store + returns typed hook |
107
+ | `useStore(key, store?)` | React hook for state subscription |
108
+ | `createStore(config?)` | Creates store instance |
109
+ | `initState(config?)` | Initializes global store |
110
+ | `getStore()` | Gets current default store |
111
+
112
+ ### SSR
113
+
114
+ | Function | Description |
115
+ |----------|-------------|
116
+ | `isServerSide()` | Check if running on server |
117
+ | `isClientSide()` | Check if running on client |
118
+ | `hydrateOnClient(store)` | Hydrate store on client |
119
+
120
+ ### Security
121
+
122
+ | Function | Description |
123
+ |----------|-------------|
124
+ | `generateEncryptionKey()` | Generate AES-256 key |
125
+ | `validateKey(key)` | Validate key format (XSS prevention) |
126
+ | `sanitizeValue(value)` | Sanitize value |
127
+
128
+ ## Project Structure
129
+
130
+ ```
131
+ core/
132
+ ├── hooks.ts # React hooks (useStore, useSyncedState)
133
+ ├── store.ts # Core store implementation
134
+ ├── types.ts # TypeScript types
135
+ ├── security.ts # Security utilities
136
+ ├── persistence.ts # Storage persistence
137
+ ├── sync.ts # Sync engine
138
+ └── ssr.ts # SSR support
139
+ ```
140
+
141
+ ## Dependencies
142
+
143
+ - **peerDependencies**: `react`, `react-dom` (>=16.8.0)
144
+ - **devDependencies**: `typescript`, `tsup`, `terser`
145
+
146
+ ## License
147
+
148
+ MIT - Copyright Dario Passariello
package/core/hooks.d.ts CHANGED
@@ -15,3 +15,4 @@ export declare function useSyncedState<T = unknown>(key: string, store?: IStore<
15
15
  ];
16
16
  export declare const useSyncStatus: () => SyncState;
17
17
  export declare const triggerSync: (namespace?: string) => Promise<void>;
18
+ export declare function useStoreSubscribe<S extends Record<string, unknown> = Record<string, unknown>>(store?: IStore<S>): readonly [boolean, () => void];
Binary file
package/index.cjs CHANGED
@@ -315,20 +315,20 @@ function f(e, ...t) {
315
315
  var g = Object, h = g.getPrototypeOf, m = "constructor", S = "prototype", _ = "configurable", w = "enumerable", b = "writable", v = "value", E = e => !!e && !!e[y];
316
316
 
317
317
  function k(e) {
318
- return !!e && (C(e) || j(e) || !!e[d] || !!e[m]?.[d] || T(e) || I(e));
318
+ return !!e && (O(e) || j(e) || !!e[d] || !!e[m]?.[d] || T(e) || I(e));
319
319
  }
320
320
 
321
- var x = g[S][m].toString(), O = new WeakMap;
321
+ var x = g[S][m].toString(), C = new WeakMap;
322
322
 
323
- function C(e) {
323
+ function O(e) {
324
324
  if (!e || !z(e)) return !1;
325
325
  const t = h(e);
326
326
  if (null === t || t === g[S]) return !0;
327
327
  const n = g.hasOwnProperty.call(t, m) && t[m];
328
328
  if (n === Object) return !0;
329
329
  if (!V(n)) return !1;
330
- let r = O.get(n);
331
- return void 0 === r && (r = Function.toString.call(n), O.set(n, r)), r === x;
330
+ let r = C.get(n);
331
+ return void 0 === r && (r = Function.toString.call(n), C.set(n, r)), r === x;
332
332
  }
333
333
 
334
334
  function A(e, t, n = !0) {
@@ -356,7 +356,7 @@ function L(e, t) {
356
356
  if (T(e)) return new Map(e);
357
357
  if (I(e)) return new Set(e);
358
358
  if (j(e)) return Array[S].slice.call(e);
359
- const n = C(e);
359
+ const n = O(e);
360
360
  if (!0 === t || "class_only" === t && !n) {
361
361
  const t = g.getOwnPropertyDescriptors(e);
362
362
  delete t[y];
@@ -791,8 +791,8 @@ var we = (new class {
791
791
  iv: r
792
792
  }, t.key, s);
793
793
  return JSON.parse((new TextDecoder).decode(o));
794
- }, Oe = null, Ce = e => {
795
- Oe && Oe(e);
794
+ }, Ce = null, Oe = e => {
795
+ Ce && Ce(e);
796
796
  }, Ae = (e, t, n) => {
797
797
  e.set(t instanceof RegExp ? t.source : t, n);
798
798
  }, De = (e, t, n, r) => {
@@ -831,7 +831,7 @@ var we = (new class {
831
831
  granted: r,
832
832
  timestamp: Date.now()
833
833
  }, o = e.get(t) || [];
834
- return o.push(s), e.set(t, o), Ce({
834
+ return o.push(s), e.set(t, o), Oe({
835
835
  timestamp: Date.now(),
836
836
  action: "set",
837
837
  key: `consent:${n}`,
@@ -866,7 +866,7 @@ var Te = () => {
866
866
  }
867
867
  };
868
868
  }, Ve = n => {
869
- const r = new Map, s = new Map, o = new Map, a = new Set, i = new Map, u = new Set, d = new Map, y = new Map, p = new Map, f = new Map, g = new Map, h = new Map, m = new Map, S = new Map, _ = n?.namespace || "gstate", w = n?.silent ?? !1, b = n?.debounceTime ?? 150, v = n?.version ?? 0, E = n?.storage || Ie(), k = n?.onError, x = n?.maxObjectSize ?? 0, O = n?.maxTotalSize ?? 0, C = n?.encryptionKey ?? null, A = n?.validateInput ?? !0, D = n?.auditEnabled ?? !0, M = n?.userId, P = n?.immer ?? !0, R = n?.persistByDefault ?? n?.persistence ?? n?.persist ?? !1;
869
+ const r = new Map, s = new Map, o = new Map, a = new Set, i = new Map, u = new Set, d = new Map, y = new Map, p = new Map, f = new Map, g = new Map, h = new Map, m = new Map, S = new Map, _ = n?.namespace || "gstate", w = n?.silent ?? !1, b = n?.debounceTime ?? 150, v = n?.version ?? 0, E = n?.storage || Ie(), k = n?.onError, x = n?.maxObjectSize ?? 0, C = n?.maxTotalSize ?? 0, O = n?.encryptionKey ?? null, A = n?.validateInput ?? !0, D = n?.auditEnabled ?? !0, M = n?.userId, P = n?.immer ?? !0, R = n?.persistByDefault ?? n?.persistence ?? n?.persist ?? !1;
870
870
  n?.accessRules && n.accessRules.forEach(e => Ae(m, e.pattern, e.permissions));
871
871
  let j, T = !1, I = !1, z = !1, V = 0, $ = null, N = null;
872
872
  const U = new Promise(e => {
@@ -879,7 +879,7 @@ var Te = () => {
879
879
  storage: E,
880
880
  config: n || {},
881
881
  diskQueue: g,
882
- encryptionKey: C,
882
+ encryptionKey: O,
883
883
  audit: q,
884
884
  onError: k,
885
885
  silent: w,
@@ -924,7 +924,7 @@ var Te = () => {
924
924
  }
925
925
  })(B(), e, t);
926
926
  }, q = (e, t, n, r) => {
927
- D && null !== Oe && Ce && Ce({
927
+ D && null !== Ce && Oe && Oe({
928
928
  timestamp: Date.now(),
929
929
  action: e,
930
930
  key: t,
@@ -1038,7 +1038,7 @@ var Te = () => {
1038
1038
  })(K());
1039
1039
  }, X = {}, Z = {
1040
1040
  _setSilently: (t, n) => {
1041
- const a = o.get(t) || 0, i = P && null !== n && "object" == typeof n ? F(e(n), !0) : n, c = (x > 0 || O > 0) && !Te() ? J(i) : 0;
1041
+ const a = o.get(t) || 0, i = P && null !== n && "object" == typeof n ? F(e(n), !0) : n, c = (x > 0 || C > 0) && !Te() ? J(i) : 0;
1042
1042
  V = V - a + c, o.set(t, c), r.set(t, i), s.set(t, (s.get(t) || 0) + 1), N = null;
1043
1043
  },
1044
1044
  _registerMethod: (e, t, n) => {
@@ -1058,7 +1058,7 @@ var Te = () => {
1058
1058
  });
1059
1059
  const p = P && null !== d && "object" == typeof d ? F(e(d), !0) : d;
1060
1060
  if (!t(l, p)) {
1061
- const e = (x > 0 || O > 0) && !Te() ? J(p) : 0;
1061
+ const e = (x > 0 || C > 0) && !Te() ? J(p) : 0;
1062
1062
  if (x > 0 && e > x) {
1063
1063
  const t = new Error(`Object size (${e} bytes) exceeds maxObjectSize (${x} bytes)`);
1064
1064
  return k && k(t, {
@@ -1066,10 +1066,10 @@ var Te = () => {
1066
1066
  key: a
1067
1067
  }), !1;
1068
1068
  }
1069
- if (O > 0) {
1069
+ if (C > 0) {
1070
1070
  const t = V - y + e;
1071
- if (t > O) {
1072
- const e = new Error(`Total store size (${t} bytes) exceeds limit (${O} bytes)`);
1071
+ if (t > C) {
1072
+ const e = new Error(`Total store size (${t} bytes) exceeds limit (${C} bytes)`);
1073
1073
  return k && k(e, {
1074
1074
  operation: "set"
1075
1075
  }), !1;
@@ -1291,7 +1291,7 @@ var Te = () => {
1291
1291
  operation: "hydration"
1292
1292
  });
1293
1293
  }
1294
- })(K(), e => (x > 0 || O > 0) && !Te() ? J(e) : 0, () => {
1294
+ })(K(), e => (x > 0 || C > 0) && !Te() ? J(e) : 0, () => {
1295
1295
  z = !0, N = null, j(), Q();
1296
1296
  }).then(() => {}) : (z = !0, j()), n?.sync) {
1297
1297
  const e = n.sync, t = async () => {
@@ -1871,8 +1871,9 @@ exports.getStore = Ne, exports.gstate = (e, t) => {
1871
1871
  e && Object.entries(e).forEach(([e, t]) => {
1872
1872
  null === n.get(e) && n._setSilently(e, t);
1873
1873
  });
1874
- return "undefined" == typeof window || Te() || (window.gstate = n, window.gState = n,
1875
- window.rgs = n), Object.assign(e => Ue(e, n), n);
1874
+ const r = e => Ue(e, n);
1875
+ return "undefined" == typeof window || Te() || (window.gstate = r, window.gState = n,
1876
+ window.rgs = n), Object.assign(r, n);
1876
1877
  }, exports.guardPlugin = e => ({
1877
1878
  name: "gstate-guard",
1878
1879
  hooks: {
@@ -1982,7 +1983,7 @@ exports.hydrateOnClient = async e => {
1982
1983
  e._setSilently(t, n);
1983
1984
  });
1984
1985
  }, exports.isClientSide = Qe, exports.isCryptoAvailable = Ee, exports.isServerSide = He,
1985
- exports.logAudit = Ce, exports.loggerPlugin = e => ({
1986
+ exports.logAudit = Oe, exports.loggerPlugin = e => ({
1986
1987
  name: "gstate-logger",
1987
1988
  hooks: {
1988
1989
  onSet: ({key: e, value: t, version: n}) => {
@@ -2025,7 +2026,7 @@ exports.logAudit = Ce, exports.loggerPlugin = e => ({
2025
2026
  type: "select",
2026
2027
  selector: e
2027
2028
  }), exports.setAuditLogger = e => {
2028
- Oe = e;
2029
+ Ce = e;
2029
2030
  }, exports.snapshotPlugin = () => {
2030
2031
  const e = new Map;
2031
2032
  return {
@@ -2120,7 +2121,12 @@ exports.logAudit = Ce, exports.loggerPlugin = e => ({
2120
2121
  exports.useHydrationStatus = Ye, exports.useIsStoreReady = e => {
2121
2122
  const t = e || $e, r = n.useMemo(() => e => t ? t._subscribe(e) : () => {}, [ t ]);
2122
2123
  return n.useSyncExternalStore(r, () => !!t && t.isReady, () => !0);
2123
- }, exports.useSimpleState = Ue, exports.useStore = Ue, exports.useSyncStatus = () => {
2124
+ }, exports.useSimpleState = Ue, exports.useStore = Ue, exports.useStoreSubscribe = function(e) {
2125
+ const t = n.useMemo(() => e || $e, [ e ]), r = n.useCallback(e => t ? t._subscribe(e) : () => {}, [ t ]), s = n.useCallback(() => !0, []), o = n.useCallback(() => !0, []);
2126
+ n.useSyncExternalStore(r, s, o);
2127
+ const [, a] = n.useState(0);
2128
+ return [ !0, n.useCallback(() => a(e => e + 1), []) ];
2129
+ }, exports.useSyncStatus = () => {
2124
2130
  const [e, t] = n.useState({
2125
2131
  isOnline: !0,
2126
2132
  isSyncing: !1,
package/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { createStore as baseCreateStore } from "./core/store";
2
2
  import { useStore as baseUseStore } from "./core/hooks";
3
3
  import * as Security from "./core/security";
4
4
  import type { IStore, StoreConfig } from "./core/types";
5
- export declare const gstate: <S extends Record<string, unknown>>(initialState: S, configOrNamespace?: string | StoreConfig<S>) => IStore<S> & (<K extends keyof S>(key: K) => readonly [S[K] | undefined, (val: S[K] | ((draft: S[K]) => S[K]), options?: unknown) => boolean]);
5
+ export declare const gstate: <S extends Record<string, unknown>>(initialState: S, configOrNamespace?: string | StoreConfig<S>) => (<K extends keyof S>(key: K) => readonly [S[K] | undefined, (val: S[K] | import(".").StateUpdater<S[K]>, options?: import("./advanced").PersistOptions) => boolean]) & IStore<S>;
6
6
  export { baseCreateStore as createStore };
7
7
  export { useStore, useIsStoreReady, initState, getStore, destroyState, useStore as useGState, useStore as useSimpleState } from "./core/hooks";
8
8
  export { createAsyncStore } from "./core/async";
@@ -12,7 +12,7 @@ export { createThunkStore, createActions, createAsyncAction, createAsyncActions,
12
12
  export type { ThunkAction, ThunkDispatch, ThunkActionPayload, Effect } from "./core/thunk";
13
13
  export { SyncEngine, createSyncEngine } from "./core/sync";
14
14
  export type { SyncConfig, SyncState, SyncResult, SyncStrategy, ConflictInfo, ConflictResolution } from "./core/sync";
15
- export { initSync, destroySync, useSyncedState, useSyncStatus, triggerSync } from "./core/hooks";
15
+ export { initSync, destroySync, useSyncedState, useSyncStatus, triggerSync, useStoreSubscribe } from "./core/hooks";
16
16
  export * from "./plugins/index";
17
17
  export { generateEncryptionKey, exportKey, importKey, isCryptoAvailable, setAuditLogger, logAudit, validateKey, sanitizeValue, deriveKeyFromPassword, generateSalt } from "./core/security";
18
18
  export declare const addAccessRule: (pattern: string | ((key: string, userId?: string) => boolean), perms: Security.Permission[]) => void | undefined;