@biglogic/rgs 3.7.0 β†’ 3.7.2

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.
Files changed (49) hide show
  1. package/README.md +84 -3
  2. package/package.json +105 -85
  3. package/COPYRIGHT.md +0 -4
  4. package/FUNDING.yml +0 -12
  5. package/SECURITY.md +0 -13
  6. package/advanced.d.ts +0 -9
  7. package/core/advanced.d.ts +0 -5
  8. package/core/async.d.ts +0 -8
  9. package/core/hooks.d.ts +0 -17
  10. package/core/persistence.d.ts +0 -23
  11. package/core/plugins.d.ts +0 -8
  12. package/core/reactivity.d.ts +0 -19
  13. package/core/security.d.ts +0 -56
  14. package/core/store.d.ts +0 -7
  15. package/core/sync.d.ts +0 -76
  16. package/core/types.d.ts +0 -163
  17. package/core/utils.d.ts +0 -2
  18. package/docs/README.md +0 -389
  19. package/docs/SUMMARY.md +0 -64
  20. package/docs/_config.yml +0 -1
  21. package/docs/api.md +0 -381
  22. package/docs/chapters/01-philosophy.md +0 -54
  23. package/docs/chapters/02-getting-started.md +0 -68
  24. package/docs/chapters/03-the-magnetar-way.md +0 -69
  25. package/docs/chapters/04-persistence-and-safety.md +0 -125
  26. package/docs/chapters/05-plugin-sdk.md +0 -290
  27. package/docs/chapters/05-plugins-and-extensibility.md +0 -190
  28. package/docs/chapters/06-case-studies.md +0 -69
  29. package/docs/chapters/07-faq.md +0 -53
  30. package/docs/chapters/08-migration-guide.md +0 -284
  31. package/docs/chapters/09-security-architecture.md +0 -50
  32. package/docs/chapters/10-local-first-sync.md +0 -146
  33. package/docs/qa.md +0 -47
  34. package/index.d.ts +0 -41
  35. package/index.js +0 -2
  36. package/index.js.map +0 -7
  37. package/plugins/index.d.ts +0 -15
  38. package/plugins/official/analytics.plugin.d.ts +0 -9
  39. package/plugins/official/cloud-sync.plugin.d.ts +0 -22
  40. package/plugins/official/debug.plugin.d.ts +0 -2
  41. package/plugins/official/devtools.plugin.d.ts +0 -4
  42. package/plugins/official/guard.plugin.d.ts +0 -2
  43. package/plugins/official/immer.plugin.d.ts +0 -2
  44. package/plugins/official/indexeddb.plugin.d.ts +0 -7
  45. package/plugins/official/schema.plugin.d.ts +0 -2
  46. package/plugins/official/snapshot.plugin.d.ts +0 -2
  47. package/plugins/official/sync.plugin.d.ts +0 -4
  48. package/plugins/official/undo-redo.plugin.d.ts +0 -4
  49. package/rgs-extension.vsix +0 -0
package/docs/api.md DELETED
@@ -1,381 +0,0 @@
1
- # πŸ“š API Reference
2
-
3
- Complete API reference for RGS (Argis) - Reactive Global State.
4
-
5
- ---
6
-
7
- ## Core Functions
8
-
9
- ### `initState`
10
-
11
- Initializes a global store instance.
12
-
13
- ```typescript
14
- function initState<S extends Record<string, unknown>>(
15
- config?: StoreConfig<S>
16
- ): IStore<S>
17
- ```
18
-
19
- **Parameters:**
20
- - `config` - Optional store configuration
21
-
22
- **Returns:** `IStore<S>`
23
-
24
- **Example:**
25
- ```typescript
26
- const store = initState({
27
- namespace: 'myApp',
28
- version: 1,
29
- persistByDefault: true,
30
- onError: (error, context) => {
31
- console.error(`Error in ${context.operation}:`, error.message)
32
- }
33
- })
34
- ```
35
-
36
- ---
37
-
38
- ### `useStore`
39
-
40
- React hook for reactive state.
41
-
42
- ```typescript
43
- function useStore<T = unknown, S extends Record<string, unknown> = Record<string, unknown>>(
44
- key: string,
45
- store?: IStore<S>
46
- ): readonly [T | undefined, (val: T | StateUpdater<T>, options?: PersistOptions) => boolean]
47
- ```
48
-
49
- **Parameters:**
50
- - `key` - State key to subscribe to
51
- - `store` - Optional store instance
52
-
53
- **Returns:** Tuple of `[value, setter]`
54
-
55
- ---
56
-
57
- ### `createStore`
58
-
59
- Creates a new store instance.
60
-
61
- ```typescript
62
- function createStore<S extends Record<string, unknown>>(
63
- config?: StoreConfig<S>
64
- ): IStore<S>
65
- ```
66
-
67
- ---
68
-
69
- ### `getStore`
70
-
71
- Retrieves the currently active default store instance. Useful for accessing the store outside of React components or in utility functions.
72
-
73
- ```typescript
74
- function getStore(): IStore<Record<string, unknown>> | null
75
- ```
76
-
77
- **Returns:** The active `IStore` or `null` if no store was initialized via `initState`.
78
-
79
- ---
80
-
81
- ## Store Interface (`IStore`)
82
-
83
- ### State Operations
84
-
85
- #### `set`
86
-
87
- Sets a value in the store.
88
-
89
- ```typescript
90
- store.set<T>(key: string, value: T | StateUpdater<T>, options?: PersistOptions): boolean
91
- ```
92
-
93
- #### `get`
94
-
95
- Gets a value from the store.
96
-
97
- ```typescript
98
- store.get<T>(key: string): T | null
99
- ```
100
-
101
- #### `remove` / `delete`
102
-
103
- Removes a value from the store.
104
-
105
- ```typescript
106
- store.remove(key: string): boolean
107
- store.delete(key: string): boolean
108
- ```
109
-
110
- #### `deleteAll`
111
-
112
- Removes all values from the store.
113
-
114
- ```typescript
115
- store.deleteAll(): void
116
- ```
117
-
118
- #### `list`
119
-
120
- Returns all key-value pairs.
121
-
122
- ```typescript
123
- store.list(): Record<string, unknown>
124
- ```
125
-
126
- ---
127
-
128
- ### Metadata Properties
129
-
130
- #### `namespace`
131
-
132
- The unique namespace of the store (read-only).
133
-
134
- ```typescript
135
- store.namespace: string
136
- ```
137
-
138
- #### `userId`
139
-
140
- The current user ID associated with the store for RBAC and audit logs (read-only).
141
-
142
- ```typescript
143
- store.userId?: string
144
- ```
145
-
146
- ---
147
-
148
- ### Computed Values
149
-
150
- #### `compute`
151
-
152
- Creates or retrieves a computed (derived) value.
153
-
154
- ```typescript
155
- store.compute<T>(key: string, selector: ComputedSelector<T>): T
156
- ```
157
-
158
- **Example:**
159
- ```typescript
160
- const fullName = store.compute('fullName', (get) => {
161
- const first = get<string>('firstName')
162
- const last = get<string>('lastName')
163
- return `${first} ${last}`
164
- })
165
- ```
166
-
167
- > **Note:** RGS supports **nested computed dependencies**. A computed value can reactively depend on other computed values in the same store.
168
-
169
- ---
170
-
171
- ### Watching Changes
172
-
173
- #### `watch`
174
-
175
- Watches for changes on a specific key.
176
-
177
- ```typescript
178
- store.watch<T>(key: string, callback: WatcherCallback<T>): () => void
179
- ```
180
-
181
- **Returns:** Unsubscribe function
182
-
183
- ---
184
-
185
- ### Transactions
186
-
187
- #### `transaction`
188
-
189
- Groups multiple operations into a single transaction.
190
-
191
- ```typescript
192
- store.transaction(fn: () => void): void
193
- ```
194
-
195
- ---
196
-
197
- ### Middleware
198
-
199
- #### `use`
200
-
201
- Adds a middleware function.
202
-
203
- ```typescript
204
- store.use(middleware: Middleware): void
205
- ```
206
-
207
- ---
208
-
209
- ### Lifecycle
210
-
211
- #### `destroy`
212
-
213
- Destroys the store and cleans up resources.
214
-
215
- ```typescript
216
- store.destroy(): void
217
- ```
218
-
219
- ---
220
-
221
- ## Plugin API
222
-
223
- ### `_addPlugin`
224
-
225
- Adds a plugin to the store.
226
-
227
- ```typescript
228
- store._addPlugin(plugin: IPlugin): void
229
- ```
230
-
231
- ### `_removePlugin`
232
-
233
- Removes a plugin from the store.
234
-
235
- ```typescript
236
- store._removePlugin(name: string): void
237
- ```
238
-
239
- ### `_registerMethod`
240
-
241
- Registers a custom method on the store.
242
-
243
- ```typescript
244
- // New signature (recommended)
245
- store._registerMethod(pluginName: string, methodName: string, fn: (...args) => unknown): void
246
- ```
247
-
248
- ---
249
-
250
- ## Plugins Property
251
-
252
- Access plugin methods via `store.plugins`:
253
-
254
- ```typescript
255
- store.plugins.undoRedo.undo()
256
- store.plugins.undoRedo.redo()
257
- store.plugins.counter.increment()
258
- store.plugins.cloudSync.sync()
259
- store.plugins.cloudSync.getStats()
260
- ```
261
-
262
- ---
263
-
264
- ## Configuration (`StoreConfig`)
265
-
266
- ```typescript
267
- interface StoreConfig<S> {
268
- /** Unique namespace for this store */
269
- namespace?: string
270
- /** Schema version */
271
- version?: number
272
- /** Suppress console warnings */
273
- silent?: boolean
274
- /** Debounce time for disk flush (default: 150ms) */
275
- debounceTime?: number
276
- /** Custom storage adapter */
277
- storage?: CustomStorage | Storage
278
- /** Migration function */
279
- migrate?: (oldState: Record<string, unknown>, oldVersion: number) => S
280
- /** Error handler */
281
- onError?: (error: Error, context: { operation: string; key?: string }) => void
282
- /** Max object size in bytes (default: 5MB) */
283
- maxObjectSize?: number
284
- /** Max total store size in bytes (default: 50MB) */
285
- maxTotalSize?: number
286
- /** AES-256-GCM encryption key */
287
- encryptionKey?: EncryptionKey
288
- /** Enable audit logging */
289
- auditEnabled?: boolean
290
- /** Current user ID for audit */
291
- userId?: string
292
- /** Enable input validation */
293
- validateInput?: boolean
294
- /** Access control rules */
295
- accessRules?: Array<{
296
- pattern: string | ((key: string, userId?: string) => boolean)
297
- permissions: Permission[]
298
- }>
299
- /** Enable Immer (default: true) */
300
- immer?: boolean
301
- }
302
- ```
303
-
304
- ---
305
-
306
- ## Persistence Options (`PersistOptions`)
307
-
308
- ```typescript
309
- interface PersistOptions {
310
- /** Persist to storage (default: localStorage) */
311
- persist?: boolean
312
- /** Base64 encode the value */
313
- encoded?: boolean
314
- /** AES-256-GCM encryption */
315
- encrypted?: boolean
316
- /** Time-to-live in milliseconds */
317
- ttl?: number
318
- }
319
- ```
320
-
321
- ---
322
-
323
- ## Types
324
-
325
- ### `StateUpdater`
326
-
327
- ```typescript
328
- type StateUpdater<T> = (draft: T) => void | T
329
- ```
330
-
331
- ### `ComputedSelector`
332
-
333
- ```typescript
334
- type ComputedSelector<T> = (get: <V>(key: string) => V | null) => T
335
- ```
336
-
337
- ### `WatcherCallback`
338
-
339
- ```typescript
340
- type WatcherCallback<T> = (value: T | null) => void
341
- ```
342
-
343
- ### `Middleware`
344
-
345
- ```typescript
346
- type Middleware<T = unknown> = (key: string, value: T, meta: StoreMetadata) => void
347
- ```
348
-
349
- ---
350
-
351
- ## Security Types
352
-
353
- ### `Permission`
354
-
355
- ```typescript
356
- type Permission = 'read' | 'write' | 'delete' | 'admin'
357
- ```
358
-
359
- ### `AccessRule`
360
-
361
- ```typescript
362
- interface AccessRule {
363
- pattern: string | ((key: string, userId?: string) => boolean)
364
- permissions: Permission[]
365
- }
366
- ```
367
-
368
- ---
369
-
370
- ## Plugin Hooks
371
-
372
- | Hook | Description |
373
- |------|-------------|
374
- | `onInit` | Called when plugin is first initialized |
375
- | `onInstall` | Called when plugin is added to store |
376
- | `onBeforeSet` | Called before a value is set |
377
- | `onSet` | Called after a value is set |
378
- | `onGet` | Called when a value is retrieved |
379
- | `onRemove` | Called when a value is removed |
380
- | `onDestroy` | Called when store is destroyed |
381
- | `onTransaction` | Called during a transaction |
@@ -1,54 +0,0 @@
1
- # 🧠 Chapter 1: The Philosophy - Panzer vs. Bicycle
2
-
3
- You are a developer. You have deadlines. You have bugs. But more importantly, you have a reputation to protect.
4
-
5
- ## 🚜 Choose Your Vehicle
6
-
7
- Most state managers focus on being "lightweight" or "easy." **RGS (Argis)** has evolved beyond that. It is a framework designed for high-stakes applications where data leakage is a disaster and production uptime is non-negotiable.
8
-
9
- ### The Bicycle (Standard Hooks/Context)
10
-
11
- If you just need a counter for a simple todo list, use a basic hook or `useState`. You don't need a Panzer to go to the grocery store. It's light, it's fast to set up, but it offers zero protection when the road gets rough.
12
-
13
- ### The Panzer (RGS)
14
-
15
- If you are building an Enterprise platform where:
16
-
17
- - **Isolation is King**: User A's data must never collide with User B's state.
18
- - **Fail-Safe Security**: RBAC (Role-Based Access Control) is built into the state layer.
19
- - **Resilience**: The app must survive uninitialized states without crashing (`Ghost Stores`).
20
-
21
- ...then you need a Panzer. **You need RGS.**
22
-
23
- ---
24
-
25
- ## πŸš€ Surgical Performance: Atomic Access
26
-
27
- RGS was born from a "crazy" idea: **State should be global by nature, but atomic by access.**
28
-
29
- ### πŸ”΄ Camp A: Context API (The Re-render Rain)
30
-
31
- In React Context, any change in the provider forces a global re-render of the entire tree consuming it. Change a theme brand color? The whole product list re-renders.
32
-
33
- ### 🟒 Camp B: RGS (The Sniper)
34
-
35
- In RGS, only the component observing a specific key wakes up. Change the 'cart'? Only the cart icon updates. Total silence for the rest of the application.
36
-
37
- ---
38
-
39
- ## πŸ›‘οΈ Defensive Engineering
40
-
41
- We don't just manage state; we protect it:
42
-
43
- - **Zero Boilerplate**: No actions, no reducers. Just `.set()` and Move on.
44
- - **Fail-Closed Security**: If a pattern is defined but doesn't explicitly match the action, access is denied. No exceptions.
45
- - **Ghost Stores**: If a component accesses an uninitialized store, we return a Proxy that warns you but **keeps the UI alive**. No more `ReferenceError: store is not defined`.
46
-
47
- ## πŸ’‘ Case Study: "No-Stress" E-commerce
48
-
49
- Imagine a shopping cart.
50
-
51
- - **Standard Approach**: The user adds a sock, and the entire product list (2000 items) re-renders because they share a Context.
52
- - **RGS Approach**: Adds the item with `set('cart', [...])`. Only the tiny cart badge updates. 3ms execution time. Happy client, happy developer.
53
-
54
- **Next step:** [Quick Start: 30-Second Setup](02-getting-started.md)
@@ -1,68 +0,0 @@
1
- # ⚑ Chapter 2: Quick Start - From Zero to State in 30 Seconds
2
-
3
- Stop wasting time on boilerplate. Here is how you deploy the RGS Panzer in your React project.
4
-
5
- ## 1. Installation
6
-
7
- The engine is lightweight but armored.
8
-
9
- ```bash
10
- npm install rgs
11
- ```
12
-
13
- ## 2. Initialization: The "Big Bang"
14
-
15
- In your main entry file (e.g., `main.tsx` or `App.tsx`), wake up the engine once.
16
-
17
- ```typescript
18
- import { initState, useStore } from '@biglogic/rgs';
19
-
20
- // Initialize with optional settings
21
- initState({
22
- namespace: 'my-awesome-app',
23
- persistence: true // Optional: Saves everything to localStorage automatically
24
- });
25
- ```
26
-
27
- ## 3. Usage: Instant Reactions
28
-
29
- Use the `useStore` hook. No providers, no wrappers. Just raw, atomic power.
30
-
31
- ```tsx
32
- import { useStore } from '@biglogic/rgs';
33
-
34
- function Counter() {
35
- // If 'count' doesn't exist yet, it defaults to undefined. Easy.
36
- const [count, setCount] = useStore<number>('count');
37
-
38
- return (
39
- <div className="card">
40
- <h1>Power Level: {count ?? 0}</h1>
41
- <button onClick={() => setCount((prev) => (prev || 0) + 1)}>
42
- Boost Power πŸ’₯
43
- </button>
44
- </div>
45
- );
46
- }
47
- ```
48
-
49
- ## 🧐 What just happened?
50
-
51
- - **Reactive Subscription**: `useStore('count')` tells React to watch the 'count' key. Surgical updates only.
52
- - **Global Scope**: `setCount` updates the value everywhere in the app, instantly.
53
- - **Resilient Nature**: If you access a key that hasn't been set yet, RGS returns `undefined` gracefully instead of throwing a tantrum.
54
-
55
- ## 🚨 Pro Tip: Direct Store Access
56
-
57
- Need to access state outside of React components? Simple.
58
-
59
- ```typescript
60
- import { getStore } from '@biglogic/rgs';
61
-
62
- const value = getStore()?.get('count');
63
- getStore()?.set('count', 9001);
64
- ```
65
-
66
- ---
67
-
68
- **Next step:** [The Magnetar Way: One-Liner Power](03-the-magnetar-way.md)
@@ -1,69 +0,0 @@
1
- # 🌌 Chapter 3: The Magnetar Way - Peak Simplicity
2
-
3
- If you are a fan of "Clean Code" or just hate writing imports, the **Magnetar** method is your new best friend.
4
-
5
- It's a single function that creates the store and the hook simultaneously. **Zero config, 100% typed.**
6
-
7
- ## πŸ› οΈ The "Master" Example
8
-
9
- Let's create a User Profile module.
10
-
11
- ```typescript
12
- import { gstate } from '@biglogic/rgs';
13
-
14
- // 1. Define the state and create everything in ONE shot
15
- // Pass a string namespace to enable automatic persistence to localStorage
16
- export const useUser = gstate({
17
- name: 'Guest',
18
- isLogged: false,
19
- preferences: { theme: 'dark', lang: 'en' }
20
- }, 'user_module'); // Auto-persists to localStorage (excludes sensitive fields)
21
-
22
- // Or use an object config for more control:
23
- export const useUserNoPersist = gstate({
24
- name: 'Guest',
25
- isLogged: false
26
- }, { namespace: 'user_module', autoPersist: false }); // No persistence
27
-
28
- // 2. Use it anywhere
29
- function ProfileHeader() {
30
- const [name, setName] = useUser('name');
31
- // Note: 'setName' is already typed! It only accepts strings.
32
-
33
- return <h1>Hello, {name}!</h1>;
34
- }
35
- ```
36
-
37
- ## πŸ’Ž Why Magnetar Rocks
38
-
39
- 1. **Inferred Types**: No need to define `<string>`. TypeScript looks at the initial value you passed to `gstate` and figures it out.
40
- 2. **Auto-Persistence**: When you pass a string namespace, RGS automatically persists to localStorage (excluding sensitive fields like tokens, passwords, secrets).
41
- 3. **Security**: Sensitive fields (containing 'token', 'password', 'secret', 'key') are automatically excluded from persistence.
42
-
43
- ```typescript
44
- // You can access the store OUTSIDE components!
45
- const currentUser = useUser.get('name');
46
- useUser.set('isLogged', true);
47
-
48
- // You can even compute data on the fly (Computed State)
49
- useUser.compute('fullName', ['firstName', 'lastName'], (s) => `${s.firstName} ${s.lastName}`);
50
- ```
51
-
52
- ## 🚜 Production Strategy: "The Store Folder"
53
-
54
- Don't scatter stores everywhere. Create a `src/stores` folder and put your Magnetar files there:
55
-
56
- - `auth.ts`
57
- - `cart.ts`
58
- - `settings.ts`
59
-
60
- Then import them whenever needed. It’s clean, fast, and professional.
61
-
62
- ## 🧠 Reflection for the Senior Dev
63
-
64
- *"Wait, does Magnetar create a new store every time?"*
65
- Yes, and that's the point! You can have isolated micro-stores for every domain of your app, while still keeping the ability to make them talk to each other. It’s the evolution of the "Atomic State" concept.
66
-
67
- ---
68
-
69
- **Next step:** [Persistence and Safety: Data Never Dies](04-persistence-and-safety.md)
@@ -1,125 +0,0 @@
1
- # πŸ—οΈ Chapter 4: Persistence and Safety - Built like a Tank
2
-
3
- In a real-world application, state that vanishes on page refresh is a developer failure. RGS handles data saving **intelligently**.
4
-
5
- ## πŸ’Ύ Persistence: "Set and Forget"
6
-
7
- When you initialize RGS or a Magnetar, you can enable persistence. But it's not a simple `localStorage.set`.
8
-
9
- ```typescript
10
- initState({
11
- persist: true,
12
- storage: 'local' // or 'session', or a custom adapter
13
- });
14
- ```
15
-
16
- ### Advanced Storage: Beyond 5MB
17
-
18
- For applications that need to store massive amounts of data (Gigabytes), standard `localStorage` is not enough. RGS provides official plugins for advanced scenarios:
19
-
20
- | Technology | Capacity | Purpose | Plugin |
21
- | :--- | :--- | :--- | :--- |
22
- | **LocalStorage** | ~5MB | Basic UI settings, small profiles. | Core (Native) |
23
- | **IndexedDB** | GBs | Offline-first apps, large datasets, logs. | `indexedDBPlugin` |
24
- | **Cloud Sync** | Unlimited | Remote backup, cross-device sync. | `cloudSyncPlugin` |
25
-
26
- ---
27
-
28
- ## ☁️ Hybrid Persistence: The "Cloud-Cloud" Strategy
29
-
30
- RGS allows you to combine local power with cloud safety. You can store your active data in **IndexedDB** for speed and capacity, while automatically backing it up to a remote database (MongoDB, Firebase, SQL) using the **Cloud Sync Plugin**.
31
-
32
- ### Why use Cloud Sync?
33
- - **Differential Updates**: Safely sends only what was changed since the last sync.
34
- - **Scheduled or On-Demand**: Sync every 5 minutes automatically, or triggered by a "Save to Cloud" button.
35
- - **Diagnostics**: Track how much data you are syncing and detect errors before they reach the user.
36
-
37
- ---
38
-
39
- ### What happens under the hood?
40
-
41
- ```mermaid
42
- sequenceDiagram
43
- participant C as Component
44
- participant RGS as Globo State
45
- participant S as LocalStorage
46
-
47
- Note over C,RGS: User clicks a button
48
- C->>RGS: set('count', 10)
49
- RGS-->>C: Update UI (Instant)
50
-
51
- Note over RGS: Waiting 300ms (Debounce)
52
-
53
- RGS->>S: Write to Disk
54
- Note right of S: Data saved successfully
55
- ```
56
-
57
- - **Debouncing**: If you update the state 100 times in one second, RGS writes to the disk only once at the end. This saves battery life and browser performance.
58
- - **Selective Persistence**: Don't want to save everything? You can tell RGS which keys to ignore or which ones to save only temporarily.
59
-
60
- ## πŸ›‘οΈ Immutability: The Immer Shield
61
-
62
- Have you ever had bugs where state changed "mysteriously" because you mutated an array directly? RGS uses **Immer** at its core (the Stellar Engine).
63
-
64
- **Dangerous Code (Standard JS):**
65
-
66
- ```javascript
67
- const user = store.get('user');
68
- user.permissions.push('admin'); // BOOM! You mutated the original without triggering a re-render.
69
- ```
70
-
71
- **The RGS Way:**
72
-
73
- ```javascript
74
- store.set('user', (draft) => {
75
- draft.permissions.push('admin'); // SAFE! RGS creates an immutable copy for you.
76
- });
77
- ```
78
-
79
- ## πŸ•΅οΈ Validation: Schema Plugin
80
-
81
- Never trust data coming back from the server or saved in the browser 6 months ago. Use the **schemaPlugin**.
82
-
83
- ```typescript
84
- import { schemaPlugin } from '@biglogic/rgs';
85
- import { z } from 'zod'; // Recommended!
86
-
87
- const store = initState();
88
- store._addPlugin(schemaPlugin({
89
- price: (val) => typeof val === 'number' && val > 0,
90
- email: (val) => val.includes('@')
91
- }));
92
- ```
93
-
94
- If anyone tries to `set('price', -50)`, RGS will block the operation and warn you. **Clean State = Happy App.**
95
-
96
- ---
97
-
98
- ## ⚠️ Size Limits: maxObjectSize & maxTotalSize
99
-
100
- Protect your app from memory issues with automatic size warnings:
101
-
102
- ```typescript
103
- const store = initState({
104
- // Warn if single value exceeds 5MB (default: 5MB)
105
- maxObjectSize: 5 * 1024 * 1024,
106
- // Warn if total store exceeds 50MB (default: 50MB)
107
- maxTotalSize: 50 * 1024 * 1024
108
- });
109
-
110
- // Setting a value that exceeds the limit will trigger a warning
111
- store.set('largeData', bigObject); // Warns if > maxObjectSize
112
- ```
113
-
114
- ---
115
-
116
- ## πŸ’‘ Case Study: The Cart that Never Lost an Item
117
-
118
- **Challenge**: User adds products, closes the browser, comes back after two days. The cart must still be there, and synced with their account on other devices.
119
- **RGS Solution**:
120
-
121
- 1. Enable `indexedDBPlugin` for robust local storage (handles thousands of items).
122
- 2. Use `cloudSyncPlugin` to bridge the local state with your company's MongoDB Atlas or Firebase.
123
- 3. Result? 5-star UX with full data durability and cross-device sync.
124
-
125
- **Next step:** [Ecosystem and Plugins: Extending the Power](05-plugins-and-extensibility.md)