@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
|
@@ -172,6 +172,53 @@ store.recordConsent('user123', 'marketing', true)
|
|
|
172
172
|
|
|
173
173
|
---
|
|
174
174
|
|
|
175
|
+
## v2.9.5: The Architecture & Safety Update (2026-02-16)
|
|
176
|
+
|
|
177
|
+
This release focuses on improving developer ergonomics, security visibility, and complex dependency handling.
|
|
178
|
+
|
|
179
|
+
### 1. Nested Computed Dependencies
|
|
180
|
+
**NEW:** Computed values can now re-trigger based on other computed values.
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
store.compute('tax', (get) => (get<number>('subtotal') || 0) * 0.2)
|
|
184
|
+
store.compute('total', (get) => (get<number>('subtotal') || 0) + (get<number>('tax') || 0))
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 2. Direct Store Access: `getStore()`
|
|
188
|
+
**NEW:** A top-level utility to retrieve the default store without React hooks.
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { getStore } from '@biglogic/rgs'
|
|
192
|
+
|
|
193
|
+
export const toggleTheme = () => {
|
|
194
|
+
const store = getStore()
|
|
195
|
+
if (store) store.set('mode', 'dark')
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 3. Exposed Metadata: `namespace` and `userId`
|
|
200
|
+
**NEW:** Store instances now expose their identifying properties as read-only getters.
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
const store = createStore({ namespace: 'auth-vault', userId: 'user-001' })
|
|
204
|
+
console.log(store.namespace) // 'auth-vault'
|
|
205
|
+
console.log(store.userId) // 'user-001'
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 4. High-Volume & Hybrid Sync (Plugins)
|
|
209
|
+
**NEW:** Support for GB-scale storage and Remote Cloud Backups.
|
|
210
|
+
|
|
211
|
+
- **IndexedDB Plugin**: Replaces localStorage for massive browser datasets.
|
|
212
|
+
- **Cloud Sync Plugin**: Differential synchronization to MongoDB, Firebase, or any SQL backend.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
// Example: Manual Cloud Sync
|
|
216
|
+
const result = await store.plugins.cloudSync.sync()
|
|
217
|
+
console.log('Stats:', store.plugins.cloudSync.getStats())
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
175
222
|
## Breaking Changes
|
|
176
223
|
|
|
177
224
|
### 🔒 Security Isolation
|
|
@@ -203,4 +250,4 @@ If you relied on `addAccessRule()` from the global export to affect a `createSto
|
|
|
203
250
|
|
|
204
251
|
---
|
|
205
252
|
|
|
206
|
-
## Last updated: 2026-02-
|
|
253
|
+
## Last updated: 2026-02-16
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Security Architecture & Hardening
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
React Globo State (RGS) is designed with a "Security-First" philosophy. Our architecture ensures that global state is not only reactive but protected against common web vulnerabilities and unauthorized access.
|
|
5
|
+
|
|
6
|
+
## 1. Data Sanitization (XSS Defense)
|
|
7
|
+
The `sanitizeValue` utility provides a robust baseline defense by stripping malicious content from strings and objects before they enter the store.
|
|
8
|
+
|
|
9
|
+
- **Scheme Blocking**: Specifically blocks `javascript:`, `vbscript:`, and `data:text/html` schemes.
|
|
10
|
+
- **Tag Removal**: Automatically removes dangerous HTML tags such as `<script>`, `<iframe>`, `<form>`, and `<meta>`.
|
|
11
|
+
- **Entity Removal**: Strips HTML entities (`&#...;`) to prevent obfuscation-based bypasses.
|
|
12
|
+
|
|
13
|
+
## 2. Advanced Deep Cloning
|
|
14
|
+
To ensure state immutability and prevent unintended side effects, RGS uses an intelligent cloning engine:
|
|
15
|
+
- **Native structuredClone**: Leverages the browser's native API for maximum performance.
|
|
16
|
+
- **Support for Collections**: Extends cloning capabilities to `Map` and `Set` objects.
|
|
17
|
+
- **Circular Reference Protection**: Uses `WeakMap` to handle complex nested structures safely.
|
|
18
|
+
|
|
19
|
+
## 3. Cryptography (AES-256-GCM)
|
|
20
|
+
The security module uses the Web Crypto API to provide high-performance, authenticated encryption:
|
|
21
|
+
- **AES-GCM**: Provides both confidentiality and integrity verification.
|
|
22
|
+
- **GCM (Galois/Counter Mode)**: Ensures that data has not been tampered with during storage.
|
|
23
|
+
|
|
24
|
+
## 4. RBAC (Role-Based Access Control)
|
|
25
|
+
RGS supports fine-grained access rules:
|
|
26
|
+
- **Fail-Closed Design**: Access is denied by default if any rules are defined.
|
|
27
|
+
- **Regex Caching**: Store instances cache compiled regular expressions for ultra-fast permission checks.
|
|
28
|
+
|
|
29
|
+
## 5. Security Best Practices
|
|
30
|
+
For real-world implementations, refer to the `examples/security-best-practices` directory, which covers:
|
|
31
|
+
- **Encryption Key Management**: Using `generateEncryptionKey()` for secure key generation.
|
|
32
|
+
- **Audit Logging**: Tracking all store modifications for compliance.
|
|
33
|
+
- **GDPR Compliance**: Managing user consent and data export/deletion.
|
|
34
|
+
|
|
35
|
+
## Summary of 2.9.5 Enhancements
|
|
36
|
+
- Robust regex patterns for `sanitizeValue`.
|
|
37
|
+
- Recursive sanitization for plain objects.
|
|
38
|
+
- `Map` and `Set` support in `deepClone`.
|
|
39
|
+
- **Exposed Metadata**: Store instances now expose read-only `namespace` and `userId`.
|
|
40
|
+
- **Direct Store Access**: Added `getStore()` utility for non-React contexts.
|
package/package.json
CHANGED
|
@@ -1,79 +1,84 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@biglogic/rgs",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Argis (RGS) - React Globo State: A react state everywhere made easy",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
},
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"@
|
|
58
|
-
"@
|
|
59
|
-
"@
|
|
60
|
-
"@
|
|
61
|
-
"@
|
|
62
|
-
"@
|
|
63
|
-
"@
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"eslint": "^
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"react": "
|
|
73
|
-
"react-
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
|
|
79
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@biglogic/rgs",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Argis (RGS) - React Globo State: A react state everywhere made easy",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"rgs",
|
|
8
|
+
"gstate",
|
|
9
|
+
"state-management",
|
|
10
|
+
"react",
|
|
11
|
+
"enterprise",
|
|
12
|
+
"hooks",
|
|
13
|
+
"global-state",
|
|
14
|
+
"immer",
|
|
15
|
+
"biglogic",
|
|
16
|
+
"persistence",
|
|
17
|
+
"react-globo-state",
|
|
18
|
+
"argis"
|
|
19
|
+
],
|
|
20
|
+
"homepage": "https://https://github.com/BigLogic-ca/rgs",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/BigLogic-ca/rgs/issues"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "Dario Passariello <dariopassariello@gmail.com>",
|
|
26
|
+
"contributors": [
|
|
27
|
+
{
|
|
28
|
+
"name": "Dario Passariello",
|
|
29
|
+
"email": "dariopassariello@gmail.com",
|
|
30
|
+
"url": "https://dario.passariello.ca/"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "Valeria Cala Scaglitta",
|
|
34
|
+
"email": "valeriacalascaglitta@gmail.com"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"main": "./index.js",
|
|
38
|
+
"types": "./index.d.ts",
|
|
39
|
+
"exports": {
|
|
40
|
+
".": "./index.js"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc --emitDeclarationOnly --outDir dist && node ./esbuild.config.mjs && npm run build:extension",
|
|
44
|
+
"build:extension": "cd vscode-extension && vsce package -o ../dist",
|
|
45
|
+
"test": "jest --config tests/jest/jest.config.ts",
|
|
46
|
+
"npm: pack": "npm run build && cd dist && npm pack",
|
|
47
|
+
"npm: publish": "npm run build && cd dist && npm publish --access=public"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"immer": "^11.1.4"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"react": ">=16.8.0",
|
|
54
|
+
"react-dom": ">=16.8.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@eslint/js": "10.0.1",
|
|
58
|
+
"@playwright/test": "1.58.2",
|
|
59
|
+
"@testing-library/dom": "10.4.1",
|
|
60
|
+
"@testing-library/jest-dom": "6.9.1",
|
|
61
|
+
"@testing-library/react": "16.3.2",
|
|
62
|
+
"@types/jest": "30.0.0",
|
|
63
|
+
"@types/node": "25.2.3",
|
|
64
|
+
"@types/react": "19.2.14",
|
|
65
|
+
"@types/react-dom": "19.2.3",
|
|
66
|
+
"@typescript-eslint/eslint-plugin": "^8.56.0",
|
|
67
|
+
"@typescript-eslint/parser": "^8.56.0",
|
|
68
|
+
"dphelper": "2.6.3",
|
|
69
|
+
"esbuild": "0.27.3",
|
|
70
|
+
"esbuild-plugin-copy": "2.1.1",
|
|
71
|
+
"eslint": "^10.0.0",
|
|
72
|
+
"eslint-plugin-react": "7.37.5",
|
|
73
|
+
"eslint-plugin-react-hooks": "7.0.1",
|
|
74
|
+
"globals": "17.3.0",
|
|
75
|
+
"jest": "30.2.0",
|
|
76
|
+
"jest-environment-jsdom": "30.2.0",
|
|
77
|
+
"react": "19.2.4",
|
|
78
|
+
"react-dom": "19.2.4",
|
|
79
|
+
"ts-jest": "29.4.6",
|
|
80
|
+
"tslib": "^2.8.1",
|
|
81
|
+
"typescript": "^5.9.3",
|
|
82
|
+
"typescript-eslint": "8.56.0"
|
|
83
|
+
}
|
|
84
|
+
}
|
package/plugins/index.d.ts
CHANGED
|
@@ -7,7 +7,9 @@ export { guardPlugin } from "./official/guard.plugin";
|
|
|
7
7
|
export { analyticsPlugin } from "./official/analytics.plugin";
|
|
8
8
|
export { syncPlugin } from "./official/sync.plugin";
|
|
9
9
|
export { debugPlugin } from "./official/debug.plugin";
|
|
10
|
+
export { indexedDBPlugin } from "./official/indexeddb.plugin";
|
|
11
|
+
export { cloudSyncPlugin, createMongoAdapter, createFirestoreAdapter, createSqlRestAdapter } from "./official/cloud-sync.plugin";
|
|
10
12
|
import type { IPlugin } from "../core/types";
|
|
11
|
-
export declare const loggerPlugin: (options?: {
|
|
13
|
+
export declare const loggerPlugin: <S extends Record<string, unknown>>(options?: {
|
|
12
14
|
collapsed?: boolean;
|
|
13
|
-
}) => IPlugin
|
|
15
|
+
}) => IPlugin<S>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IPlugin } from '../../core/types';
|
|
2
|
+
export interface SyncStats {
|
|
3
|
+
lastSyncTimestamp: number | null;
|
|
4
|
+
totalKeysSynced: number;
|
|
5
|
+
totalBytesSynced: number;
|
|
6
|
+
syncCount: number;
|
|
7
|
+
lastDuration: number;
|
|
8
|
+
errors: number;
|
|
9
|
+
}
|
|
10
|
+
export interface CloudSyncAdapter {
|
|
11
|
+
name: string;
|
|
12
|
+
save: (data: Record<string, unknown>) => Promise<boolean>;
|
|
13
|
+
}
|
|
14
|
+
export interface CloudSyncOptions {
|
|
15
|
+
adapter: CloudSyncAdapter;
|
|
16
|
+
autoSyncInterval?: number;
|
|
17
|
+
onSync?: (stats: SyncStats) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare const cloudSyncPlugin: <S extends Record<string, unknown>>(options: CloudSyncOptions) => IPlugin<S>;
|
|
20
|
+
export declare const createMongoAdapter: (apiUrl: string, apiKey: string) => CloudSyncAdapter;
|
|
21
|
+
export declare const createFirestoreAdapter: (db: unknown, docPath: string) => CloudSyncAdapter;
|
|
22
|
+
export declare const createSqlRestAdapter: (endpoint: string, authToken: string) => CloudSyncAdapter;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { IPlugin } from '../../core/types';
|
|
2
|
-
export declare const immerPlugin: () => IPlugin
|
|
2
|
+
export declare const immerPlugin: <S extends Record<string, unknown>>() => IPlugin<S>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { IPlugin } from '../../core/types';
|
|
2
|
+
export interface IndexedDBOptions {
|
|
3
|
+
dbName?: string;
|
|
4
|
+
storeName?: string;
|
|
5
|
+
version?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare const indexedDBPlugin: <S extends Record<string, unknown>>(options?: IndexedDBOptions) => IPlugin<S>;
|
|
Binary file
|