@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 +148 -0
- package/core/hooks.d.ts +1 -0
- package/extension/rgs.vsix +0 -0
- package/index.cjs +29 -23
- package/index.d.ts +2 -2
- package/index.js +85 -75
- package/{docs/markdown → markdown}/api.md +32 -0
- package/markdown/getting-started.md +62 -0
- package/package.json +1 -1
- package/docs/README.md +0 -479
- package/docs/markdown/getting-started.md +0 -68
- package/tsup.setup.d.ts +0 -9
- /package/{docs/SUMMARY.md → SUMMARY.md} +0 -0
- /package/{docs/_config.yml → _config.yml} +0 -0
- /package/{docs/markdown → markdown}/case-studies.md +0 -0
- /package/{docs/markdown → markdown}/faq.md +0 -0
- /package/{docs/markdown → markdown}/local-first-sync.md +0 -0
- /package/{docs/markdown → markdown}/migration-guide.md +0 -0
- /package/{docs/markdown → markdown}/persistence-and-safety.md +0 -0
- /package/{docs/markdown → markdown}/philosophy.md +0 -0
- /package/{docs/markdown → markdown}/plugin-sdk.md +0 -0
- /package/{docs/markdown → markdown}/plugins-and-extensibility.md +0 -0
- /package/{docs/markdown → markdown}/security-architecture.md +0 -0
- /package/{docs/markdown → markdown}/the-magnetar-way.md +0 -0
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 && (
|
|
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(),
|
|
321
|
+
var x = g[S][m].toString(), C = new WeakMap;
|
|
322
322
|
|
|
323
|
-
function
|
|
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 =
|
|
331
|
-
return void 0 === r && (r = Function.toString.call(n),
|
|
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 =
|
|
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
|
-
},
|
|
795
|
-
|
|
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),
|
|
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,
|
|
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:
|
|
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 !==
|
|
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 ||
|
|
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 ||
|
|
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 (
|
|
1069
|
+
if (C > 0) {
|
|
1070
1070
|
const t = V - y + e;
|
|
1071
|
-
if (t >
|
|
1072
|
-
const e = new Error(`Total store size (${t} bytes) exceeds limit (${
|
|
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 ||
|
|
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
|
-
|
|
1875
|
-
window.
|
|
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 =
|
|
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
|
-
|
|
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.
|
|
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>) =>
|
|
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;
|