@biglogic/rgs 3.8.0 → 3.8.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biglogic/rgs",
3
- "version": "3.8.0",
3
+ "version": "3.8.4",
4
4
  "license": "MIT",
5
5
  "description": "Argis (RGS) - Reactive Global State: A react state everywhere made easy",
6
6
  "type": "module",
@@ -86,4 +86,4 @@
86
86
  "tslib": "^2.8.1",
87
87
  "typescript": "^5.9.3"
88
88
  }
89
- }
89
+ }
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,290 +0,0 @@
1
- # 🔧 Plugin SDK: Build Your Own Extensions
2
-
3
- This guide shows you how to create custom plugins for RGS (Argis) - Reactive Global State. Plugins are the way to extend the store with custom functionality.
4
-
5
- ---
6
-
7
- ## 📦 What is a Plugin?
8
-
9
- A plugin is a module that:
10
-
11
- 1. Adds **lifecycle hooks** to react to store events
12
- 2. Exposes **custom methods** via `store.plugins.yourPlugin.method()`
13
- 3. Can **validate**, **transform**, or **track** data
14
-
15
- ---
16
-
17
- ## 🏗️ Plugin Structure
18
-
19
- Every plugin implements the `IPlugin` interface:
20
-
21
- ```typescript
22
- import type { IPlugin, PluginContext } from '@biglogic/rgs'
23
-
24
- interface IPlugin {
25
- name: string
26
- hooks: {
27
- onInit?: (ctx: PluginContext) => void | Promise<void>
28
- onInstall?: (ctx: PluginContext) => void | Promise<void>
29
- onSet?: (ctx: PluginContext) => void | Promise<void>
30
- onGet?: (ctx: PluginContext) => void | Promise<void>
31
- onRemove?: (ctx: PluginContext) => void | Promise<void>
32
- onDestroy?: (ctx: PluginContext) => void | Promise<void>
33
- onTransaction?: (ctx: PluginContext) => void | Promise<void>
34
- onBeforeSet?: (ctx: PluginContext) => void | Promise<void>
35
- onAfterSet?: (ctx: PluginContext) => void | Promise<void>
36
- }
37
- }
38
- ```
39
-
40
- ---
41
-
42
- ## 🎯 Creating Your First Plugin
43
-
44
- ### Example: A Simple Logger Plugin
45
-
46
- ```typescript
47
- import type { IPlugin, PluginContext } from '@biglogic/rgs'
48
-
49
- export const loggerPlugin = (): IPlugin => {
50
- return {
51
- name: 'my-logger',
52
- hooks: {
53
- onSet: ({ key, value }: PluginContext) => {
54
- console.log(`[Logger] Set "${key}" to:`, value)
55
- },
56
- onGet: ({ key, value }: PluginContext) => {
57
- console.log(`[Logger] Got "${key}":`, value)
58
- },
59
- onRemove: ({ key }: PluginContext) => {
60
- console.log(`[Logger] Removed "${key}"`)
61
- }
62
- }
63
- }
64
- }
65
-
66
- // Usage
67
- store._addPlugin(loggerPlugin())
68
- ```
69
-
70
- ---
71
-
72
- ## 🔌 Registering Custom Methods
73
-
74
- Plugins can expose methods accessible via `store.plugins.pluginName.methodName()`:
75
-
76
- ```typescript
77
- import type { IPlugin, PluginContext } from '@biglogic/rgs'
78
-
79
- export const counterPlugin = (): IPlugin => {
80
- let _count = 0
81
-
82
- return {
83
- name: 'counter',
84
- hooks: {
85
- onInstall: ({ store }) => {
86
- // Register methods with explicit plugin namespace
87
- store._registerMethod('counter', 'increment', () => {
88
- _count++
89
- return _count
90
- })
91
-
92
- store._registerMethod('counter', 'decrement', () => {
93
- _count--
94
- return _count
95
- })
96
-
97
- store._registerMethod('counter', 'getCount', () => _count)
98
-
99
- store._registerMethod('counter', 'reset', () => {
100
- _count = 0
101
- return _count
102
- })
103
- }
104
- }
105
- }
106
- }
107
-
108
- // Usage
109
- store._addPlugin(counterPlugin())
110
-
111
- store.plugins.counter.increment() // returns 1
112
- store.plugins.counter.increment() // returns 2
113
- store.plugins.counter.getCount() // returns 2
114
- store.plugins.counter.decrement() // returns 1
115
- store.plugins.counter.reset() // returns 0
116
- ```
117
-
118
- ---
119
-
120
- ## ⚙️ Plugin Configuration
121
-
122
- Plugins can accept configuration options:
123
-
124
- ```typescript
125
- interface ValidationConfig {
126
- email?: (value: string) => boolean | string
127
- username?: (value: string) => boolean | string
128
- maxLength?: number
129
- }
130
-
131
- export const validationPlugin = (config: ValidationConfig): IPlugin => {
132
- return {
133
- name: 'validation',
134
- hooks: {
135
- onBeforeSet: ({ key, value }) => {
136
- const validator = config[key as keyof ValidationConfig]
137
- if (validator && typeof value === 'string') {
138
- const result = validator(value)
139
- if (result !== true) {
140
- throw new Error(`Validation failed for "${key}": ${result}`)
141
- }
142
- }
143
-
144
- // Check maxLength
145
- if (config.maxLength && typeof value === 'string' && value.length > config.maxLength) {
146
- throw new Error(`"${key}" exceeds max length of ${config.maxLength}`)
147
- }
148
- }
149
- }
150
- }
151
- }
152
-
153
- // Usage
154
- store._addPlugin(validationPlugin({
155
- email: (v) => v.includes('@') ? true : 'Invalid email',
156
- username: (v) => v.length >= 3 ? true : 'Too short',
157
- maxLength: 100
158
- }))
159
- ```
160
-
161
- ---
162
-
163
- ## 🔄 Using Store Internals
164
-
165
- Plugins have access to internal store methods:
166
-
167
- ```typescript
168
- export const auditPlugin = (): IPlugin => {
169
- return {
170
- name: 'audit',
171
- hooks: {
172
- onSet: ({ store, key, value, version }) => {
173
- // Read other keys
174
- const currentUser = store.get('currentUser')
175
-
176
- // Set silently (without triggering hooks)
177
- store._setSilently('_auditLog', [
178
- ...(store.get('_auditLog') || []),
179
- { action: 'set', key, timestamp: Date.now() }
180
- ])
181
-
182
- // Get version
183
- const ver = store._getVersion(key)
184
- }
185
- }
186
- }
187
- }
188
- ```
189
-
190
- ### Available Internal Methods
191
-
192
- | Method | Description |
193
- |--------|-------------|
194
- | `store.get(key)` | Get a value |
195
- | `store.set(key, value)` | Set a value |
196
- | `store._setSilently(key, value)` | Set without triggering hooks |
197
- | `store.list()` | Get all key-value pairs |
198
- | `store._getVersion(key)` | Get version number |
199
- | `store._subscribe(callback)` | Subscribe to changes |
200
-
201
- ---
202
-
203
- ## 🧪 Full Example: Persistence Plugin
204
-
205
- Here's a complete plugin that auto-saves to a custom backend:
206
-
207
- ```typescript
208
- import type { IPlugin, PluginContext } from '@biglogic/rgs'
209
-
210
- interface AutoSaveConfig {
211
- endpoint: string
212
- debounceMs?: number
213
- keys?: string[] // Which keys to save
214
- }
215
-
216
- export const autoSavePlugin = (config: AutoSaveConfig): IPlugin => {
217
- const { endpoint, debounceMs = 1000, keys } = config
218
- let _saveTimeout: ReturnType<typeof setTimeout> | null = null
219
-
220
- const save = async (store: any) => {
221
- const data = keys
222
- ? Object.fromEntries(keys.map(k => [k, store.get(k)]))
223
- : store.list()
224
-
225
- try {
226
- await fetch(endpoint, {
227
- method: 'POST',
228
- headers: { 'Content-Type': 'application/json' },
229
- body: JSON.stringify(data)
230
- })
231
- console.log('[AutoSave] Saved to', endpoint)
232
- } catch (err) {
233
- console.error('[AutoSave] Failed:', err)
234
- }
235
- }
236
-
237
- return {
238
- name: 'auto-save',
239
- hooks: {
240
- onInstall: async ({ store }) => {
241
- // Load initial data
242
- try {
243
- const res = await fetch(endpoint)
244
- const data = await res.json()
245
- Object.entries(data).forEach(([k, v]) => {
246
- store._setSilently(k, v)
247
- })
248
- } catch {
249
- // Ignore load errors
250
- }
251
- },
252
- onSet: ({ store }) => {
253
- // Debounced save
254
- if (_saveTimeout) clearTimeout(_saveTimeout)
255
- _saveTimeout = setTimeout(() => save(store), debounceMs)
256
- },
257
- onDestroy: ({ store }) => {
258
- // Save immediately on destroy
259
- if (_saveTimeout) clearTimeout(_saveTimeout)
260
- save(store)
261
- }
262
- }
263
- }
264
- }
265
-
266
- // Usage
267
- store._addPlugin(autoSavePlugin({
268
- endpoint: '/api/save',
269
- debounceMs: 2000,
270
- keys: ['user', 'settings', 'preferences']
271
- }))
272
- ```
273
-
274
- ---
275
-
276
- ## 📋 Plugin Best Practices
277
-
278
- 1. **Use Namespaced Methods** - Always use `store._registerMethod('pluginName', 'methodName', fn)`
279
- 2. **Clean Up Resources** - Use `onDestroy` to clean up timers, listeners, etc.
280
- 3. **Handle Errors** - Wrap async operations in try/catch
281
- 4. **Document Configuration** - Provide clear TypeScript interfaces
282
- 5. **Test Hooks** - Test each hook independently
283
-
284
- ---
285
-
286
- ## 📚 Related
287
-
288
- - [Plugin API Reference](../api/plugins.md)
289
- - [Chapter 5: Ecosystem and Plugins](05-plugins-and-extensibility.md)
290
- - [Case Studies](06-case-studies.md)