@biglogic/rgs 3.1.0 → 3.5.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.
Files changed (83) hide show
  1. package/README.md +24 -6
  2. package/SECURITY.md +1 -1
  3. package/advanced.js +1 -1
  4. package/core/hooks.d.ts +2 -3
  5. package/core/persistence.d.ts +23 -0
  6. package/core/plugins.d.ts +8 -0
  7. package/core/reactivity.d.ts +19 -0
  8. package/core/types.d.ts +1 -1
  9. package/index.js +1 -1
  10. package/package.json +81 -77
  11. package/rgs-extension.vsix +0 -0
  12. package/core/advanced.js +0 -4
  13. package/core/async.js +0 -40
  14. package/core/hooks.js +0 -52
  15. package/core/security.js +0 -124
  16. package/core/store.js +0 -595
  17. package/core/types.js +0 -5
  18. package/core/utils.js +0 -72
  19. package/examples/README.md +0 -41
  20. package/examples/async-data-fetch/UserLoader.d.ts +0 -12
  21. package/examples/async-data-fetch/UserLoader.js +0 -10
  22. package/examples/async-data-fetch/UserLoader.ts +0 -30
  23. package/examples/basic-counter/CounterComponent.d.ts +0 -2
  24. package/examples/basic-counter/CounterComponent.js +0 -7
  25. package/examples/basic-counter/CounterComponent.tsx +0 -22
  26. package/examples/basic-counter/CounterStore.d.ts +0 -7
  27. package/examples/basic-counter/CounterStore.js +0 -13
  28. package/examples/basic-counter/CounterStore.ts +0 -25
  29. package/examples/big-data-indexeddb/BigDataStore.d.ts +0 -10
  30. package/examples/big-data-indexeddb/BigDataStore.js +0 -32
  31. package/examples/big-data-indexeddb/BigDataStore.ts +0 -60
  32. package/examples/global-theme/ThemeManager.d.ts +0 -7
  33. package/examples/global-theme/ThemeManager.js +0 -13
  34. package/examples/global-theme/ThemeManager.ts +0 -32
  35. package/examples/hybrid-cloud-sync/HybridStore.d.ts +0 -19
  36. package/examples/hybrid-cloud-sync/HybridStore.js +0 -44
  37. package/examples/hybrid-cloud-sync/HybridStore.ts +0 -78
  38. package/examples/persistent-cart/CartStore.d.ts +0 -13
  39. package/examples/persistent-cart/CartStore.js +0 -23
  40. package/examples/persistent-cart/CartStore.ts +0 -41
  41. package/examples/rbac-dashboard/DashboardStore.d.ts +0 -47
  42. package/examples/rbac-dashboard/DashboardStore.js +0 -31
  43. package/examples/rbac-dashboard/DashboardStore.ts +0 -46
  44. package/examples/secure-auth/AuthStore.d.ts +0 -14
  45. package/examples/secure-auth/AuthStore.js +0 -20
  46. package/examples/secure-auth/AuthStore.ts +0 -36
  47. package/examples/security-best-practices/SecurityStore.d.ts +0 -22
  48. package/examples/security-best-practices/SecurityStore.js +0 -30
  49. package/examples/security-best-practices/SecurityStore.ts +0 -75
  50. package/examples/stress-tests/StressStore.d.ts +0 -41
  51. package/examples/stress-tests/StressStore.js +0 -41
  52. package/examples/stress-tests/StressStore.ts +0 -61
  53. package/examples/super-easy/EasyStore.d.ts +0 -44
  54. package/examples/super-easy/EasyStore.js +0 -24
  55. package/examples/super-easy/EasyStore.ts +0 -61
  56. package/examples/undo-redo-editor/EditorStore.d.ts +0 -9
  57. package/examples/undo-redo-editor/EditorStore.js +0 -13
  58. package/examples/undo-redo-editor/EditorStore.ts +0 -28
  59. package/markdown/SUMMARY.md +0 -59
  60. package/markdown/api.md +0 -381
  61. package/markdown/chapters/01-philosophy.md +0 -54
  62. package/markdown/chapters/02-getting-started.md +0 -68
  63. package/markdown/chapters/03-the-magnetar-way.md +0 -69
  64. package/markdown/chapters/04-persistence-and-safety.md +0 -125
  65. package/markdown/chapters/05-plugin-sdk.md +0 -290
  66. package/markdown/chapters/05-plugins-and-extensibility.md +0 -190
  67. package/markdown/chapters/06-case-studies.md +0 -69
  68. package/markdown/chapters/07-faq.md +0 -53
  69. package/markdown/chapters/08-migration-guide.md +0 -253
  70. package/markdown/chapters/09-security-architecture.md +0 -40
  71. package/plugins/index.js +0 -34
  72. package/plugins/official/analytics.plugin.js +0 -19
  73. package/plugins/official/cloud-sync.plugin.js +0 -117
  74. package/plugins/official/debug.plugin.js +0 -62
  75. package/plugins/official/devtools.plugin.js +0 -28
  76. package/plugins/official/guard.plugin.js +0 -15
  77. package/plugins/official/immer.plugin.js +0 -10
  78. package/plugins/official/indexeddb.plugin.js +0 -102
  79. package/plugins/official/schema.plugin.js +0 -16
  80. package/plugins/official/snapshot.plugin.js +0 -27
  81. package/plugins/official/sync.plugin.js +0 -37
  82. package/plugins/official/undo-redo.plugin.js +0 -61
  83. package/tsconfig.tsbuildinfo +0 -1
@@ -1,41 +0,0 @@
1
- # 🌌 RGS Examples & Best Practices
2
-
3
- This folder contains functional and reusable examples of **React Globo State (RGS)** implementation.
4
-
5
- ## 🏁 Overview: FE vs BE Recommendations
6
-
7
- | Example | Recommendation | Primary Use Case |
8
- | :--- | :--- | :--- |
9
- | **[Basic Counter](./basic-counter)** | **FE Only** | Local component state, UI toggles. |
10
- | **[Global Theme](./global-theme)** | **FE Only** | Dark mode, Layout settings, Persistence. |
11
- | **[Persistent Cart](./persistent-cart)** | **FE Preferred** | Shopping carts, Drafts, Offline-first apps. |
12
- | **[Secure Auth](./secure-auth)** | **FE / BE** | Session management, Tokens, User metadata. |
13
- | **[Undo/Redo Editor](./undo-redo-editor)** | **FE Only** | Rich text editors, Canvas tools, Form history. |
14
- | **[RBAC Dashboard](./rbac-dashboard)** | **BE / Admin FE** | Permission-based UI, Secure Admin panels. |
15
- | **[Async Data Fetch](./async-data-fetch)** | **FE Only** | API integration, Data hydration. |
16
- | **[Security Practices](./security-best-practices)** | **BE / Core FE** | Encryption, Audit logs, GDPR compliance. |
17
- | **[Big Data (IndexedDB)](./big-data-indexeddb)** | **FE Specific** | High-volume storage (GBs), Large payloads. |
18
- | **[Stress Tests](./stress-tests)** | **Validation** | Performance benchmarking & profiling. |
19
-
20
- ---
21
-
22
- ## 🛡️ Security Guidelines
23
-
24
- ### 1. Sensitive Data Handling
25
- **CRITICAL:** Never hardcode actual sensitive data (Credit Cards, Passwords, API Keys) in your JavaScript/TypeScript files.
26
- - **Frontend:** Collect from secure `<input type="password">` and pass to RGS at runtime.
27
- - **Backend:** Retrieve from environment variables (`process.env`) or Secret Managers.
28
-
29
- ### 2. Encryption
30
- For PII (Personally Identifiable Information), always use the `encryptionKey` option in `StoreConfig`.
31
- RGS will use the Web Crypto API (or Node Crypto) to perform **AES-256-GCM** encryption before writing to storage.
32
-
33
- ### 3. XSS Defense
34
- Enable `validateInput: true` in your store configuration to automatically sanitize strings. This is vital for any user-generated content displayed in the DOM.
35
-
36
- ### 4. High-Volume Storage (IndexedDB)
37
- If your application needs to store more than 10MB (the typical localStorage limit), use the **IndexedDB Plugin**. It allows storing Gigabytes of data asynchronously without blocking the main UI thread.
38
-
39
- ## 🛠️ Testing Environment
40
- All examples are validated using Jest in a `jsdom` environment.
41
- Refer to `tests/jest/tests/examples_v.test.ts` for automated verify suites.
@@ -1,12 +0,0 @@
1
- interface User {
2
- id: number;
3
- name: string;
4
- email: string;
5
- }
6
- export declare const fetchUser: (args: {
7
- id: string;
8
- }) => Promise<User>;
9
- export declare const useUser: import("../../advanced").IStore<Record<string, import("../../core/types").AsyncState<User>>> & {
10
- execute: () => Promise<void>;
11
- };
12
- export {};
@@ -1,10 +0,0 @@
1
- import { createAsyncStore } from '../../index';
2
- export const fetchUser = async (args) => {
3
- const response = await fetch(`https://jsonplaceholder.typicode.com/users/${args.id}`);
4
- if (!response.ok)
5
- throw new Error('User not found');
6
- return response.json();
7
- };
8
- export const useUser = createAsyncStore(() => fetchUser({ id: '1' }), {
9
- key: 'userData'
10
- });
@@ -1,30 +0,0 @@
1
- import { createAsyncStore } from '../../index'
2
-
3
- /**
4
- * Async Data Loader Utility
5
- * RECOMMENDED FOR: Frontend (FE)
6
- */
7
-
8
- interface User {
9
- id: number
10
- name: string
11
- email: string
12
- }
13
-
14
- export const fetchUser = async (args: { id: string }) => {
15
- const response = await fetch(`https://jsonplaceholder.typicode.com/users/${args.id}`)
16
- if (!response.ok) throw new Error('User not found')
17
- return response.json() as Promise<User>
18
- }
19
-
20
- // Basic Async Store for a specific user (Example)
21
- export const useUser = createAsyncStore<User>(() => fetchUser({ id: '1' }), {
22
- key: 'userData'
23
- })
24
-
25
- /**
26
- * Usage in component:
27
- *
28
- * const [state, actions] = useUser()
29
- * useEffect(() => { actions.execute({ id: '1' }) }, [])
30
- */
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare const CounterComponent: React.FC;
@@ -1,7 +0,0 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useCounter, increment, decrement } from './CounterStore';
3
- export const CounterComponent = () => {
4
- const [count] = useCounter('count');
5
- const [lastUpdated] = useCounter('lastUpdated');
6
- return (_jsxs("div", { style: { padding: '20px', border: '1px solid #ccc' }, children: [_jsxs("h2", { children: ["Counter: ", String(count)] }), _jsx("p", { children: _jsxs("small", { children: ["Last updated: ", String(lastUpdated)] }) }), _jsx("button", { onClick: increment, children: "+" }), _jsx("button", { onClick: decrement, children: "-" }), _jsx("button", { onClick: () => useCounter.set('count', 0), children: "Reset" })] }));
7
- };
@@ -1,22 +0,0 @@
1
- import React from 'react'
2
- import { useCounter, increment, decrement } from './CounterStore'
3
-
4
- /**
5
- * Counter Component
6
- * Demonstrates the "Magnetar" pattern where the store IS the hook.
7
- */
8
- export const CounterComponent: React.FC = () => {
9
- // Subscribe to specific keys for fine-grained re-renders
10
- const [count] = useCounter('count')
11
- const [lastUpdated] = useCounter('lastUpdated')
12
-
13
- return (
14
- <div style={{ padding: '20px', border: '1px solid #ccc' }}>
15
- <h2>Counter: {String(count)}</h2>
16
- <p><small>Last updated: {String(lastUpdated)}</small></p>
17
- <button onClick={increment}>+</button>
18
- <button onClick={decrement}>-</button>
19
- <button onClick={() => useCounter.set('count', 0)}>Reset</button>
20
- </div>
21
- )
22
- }
@@ -1,7 +0,0 @@
1
- export interface CounterState extends Record<string, unknown> {
2
- count: number;
3
- lastUpdated: string;
4
- }
5
- export declare const useCounter: import("../../advanced").IStore<CounterState> & (<K extends keyof CounterState>(key: K) => readonly [CounterState[K] | undefined, (val: CounterState[K] | ((draft: CounterState[K]) => CounterState[K]), options?: unknown) => boolean]);
6
- export declare const increment: () => void;
7
- export declare const decrement: () => void;
@@ -1,13 +0,0 @@
1
- import { gstate } from '../../index';
2
- export const useCounter = gstate({
3
- count: 0,
4
- lastUpdated: new Date().toISOString()
5
- });
6
- export const increment = () => {
7
- useCounter.set('count', (d) => d + 1);
8
- useCounter.set('lastUpdated', new Date().toISOString());
9
- };
10
- export const decrement = () => {
11
- useCounter.set('count', (d) => d - 1);
12
- useCounter.set('lastUpdated', new Date().toISOString());
13
- };
@@ -1,25 +0,0 @@
1
- import { gstate } from '../../index'
2
-
3
- export interface CounterState extends Record<string, unknown> {
4
- count: number
5
- lastUpdated: string
6
- }
7
-
8
- /**
9
- * Basic Counter Store
10
- * RECOMMENDED FOR: Frontend (FE)
11
- */
12
- export const useCounter = gstate<CounterState>({
13
- count: 0,
14
- lastUpdated: new Date().toISOString()
15
- })
16
-
17
- export const increment = () => {
18
- useCounter.set('count', (d) => d + 1)
19
- useCounter.set('lastUpdated', new Date().toISOString())
20
- }
21
-
22
- export const decrement = () => {
23
- useCounter.set('count', (d) => d - 1)
24
- useCounter.set('lastUpdated', new Date().toISOString())
25
- }
@@ -1,10 +0,0 @@
1
- export interface BigDataState extends Record<string, unknown> {
2
- largeCollection: any[];
3
- metaInfo: {
4
- totalItems: number;
5
- lastSync: number;
6
- };
7
- }
8
- export declare const useBigData: import("../../advanced").IStore<BigDataState> & (<K extends keyof BigDataState>(key: K) => readonly [BigDataState[K] | undefined, (val: BigDataState[K] | ((draft: BigDataState[K]) => BigDataState[K]), options?: unknown) => boolean]);
9
- export declare const populateData: (count?: number) => void;
10
- export declare const clearBigData: () => Promise<void>;
@@ -1,32 +0,0 @@
1
- import { gstate } from '../../index';
2
- import { indexedDBPlugin } from '../../plugins/official/indexeddb.plugin';
3
- const initialState = {
4
- largeCollection: [],
5
- metaInfo: { totalItems: 0, lastSync: Date.now() }
6
- };
7
- export const useBigData = gstate(initialState, {
8
- namespace: 'big-data-vault',
9
- persist: false
10
- });
11
- useBigData._addPlugin(indexedDBPlugin({
12
- dbName: 'UserLargeStorage',
13
- storeName: 'appStates'
14
- }));
15
- export const populateData = (count = 1000) => {
16
- const data = [];
17
- for (let i = 0; i < count; i++) {
18
- data.push({
19
- id: `item_${i}`,
20
- payload: 'X'.repeat(1024),
21
- timestamp: Date.now()
22
- });
23
- }
24
- useBigData.transaction(() => {
25
- useBigData.set('largeCollection', data);
26
- useBigData.set('metaInfo', { totalItems: count, lastSync: Date.now() });
27
- });
28
- };
29
- export const clearBigData = async () => {
30
- await useBigData.plugins.indexedDB.clear();
31
- useBigData.set('largeCollection', []);
32
- };
@@ -1,60 +0,0 @@
1
- import { gstate } from '../../index'
2
- import { indexedDBPlugin } from '../../plugins/official/indexeddb.plugin'
3
-
4
- /**
5
- * Big Data Store using IndexedDB
6
- * RECOMMENDED FOR: Frontend (FE)
7
- *
8
- * Demonstrates how to handle massive datasets (GBs) that would exceed
9
- * the standard 5MB-10MB limit of localStorage.
10
- */
11
-
12
- export interface BigDataState extends Record<string, unknown> {
13
- largeCollection: any[]
14
- metaInfo: { totalItems: number, lastSync: number }
15
- }
16
-
17
- const initialState: BigDataState = {
18
- largeCollection: [],
19
- metaInfo: { totalItems: 0, lastSync: Date.now() }
20
- }
21
-
22
- // 1. Define the store
23
- export const useBigData = gstate<BigDataState>(initialState, {
24
- namespace: 'big-data-vault',
25
- persist: false // Disable standard persistence to use IndexedDB exclusively
26
- })
27
-
28
- // 2. Add the IndexedDB Plugin
29
- useBigData._addPlugin(indexedDBPlugin({
30
- dbName: 'UserLargeStorage',
31
- storeName: 'appStates'
32
- }))
33
-
34
- /**
35
- * Action to simulate adding a large amount of data.
36
- */
37
- export const populateData = (count: number = 1000) => {
38
- const data: Array<{ id: string, payload: string, timestamp: number }> = []
39
- for (let i = 0; i < count; i++) {
40
- data.push({
41
- id: `item_${i}`,
42
- payload: 'X'.repeat(1024), // 1KB per item
43
- timestamp: Date.now()
44
- })
45
- }
46
-
47
- useBigData.transaction(() => {
48
- useBigData.set('largeCollection', data)
49
- useBigData.set('metaInfo', { totalItems: count, lastSync: Date.now() })
50
- })
51
- }
52
-
53
- /**
54
- * Clear the database
55
- */
56
- export const clearBigData = async () => {
57
- // Access plugin methods registered on the store
58
- await (useBigData as any).plugins.indexedDB.clear()
59
- useBigData.set('largeCollection', [])
60
- }
@@ -1,7 +0,0 @@
1
- export interface ThemeState extends Record<string, unknown> {
2
- mode: 'light' | 'dark';
3
- accent: string;
4
- }
5
- export declare const useTheme: import("../../advanced").IStore<ThemeState> & (<K extends keyof ThemeState>(key: K) => readonly [ThemeState[K] | undefined, (val: ThemeState[K] | ((draft: ThemeState[K]) => ThemeState[K]), options?: unknown) => boolean]);
6
- export declare const initTheme: () => import("../../advanced").IStore<ThemeState> & (<K extends keyof ThemeState>(key: K) => readonly [ThemeState[K] | undefined, (val: ThemeState[K] | ((draft: ThemeState[K]) => ThemeState[K]), options?: unknown) => boolean]);
7
- export declare const toggleTheme: () => void;
@@ -1,13 +0,0 @@
1
- import { gstate } from '../../index';
2
- export const useTheme = gstate({
3
- mode: 'light',
4
- accent: '#007bff'
5
- }, {
6
- namespace: 'theme-store',
7
- persist: true
8
- });
9
- export const initTheme = () => useTheme;
10
- export const toggleTheme = () => {
11
- const current = useTheme.get('mode');
12
- useTheme.set('mode', current === 'light' ? 'dark' : 'light');
13
- };
@@ -1,32 +0,0 @@
1
- import { gstate, getStore } from '../../index'
2
-
3
- // Define the shape of our theme state
4
- export interface ThemeState extends Record<string, unknown> {
5
- mode: 'light' | 'dark'
6
- accent: string
7
- }
8
-
9
- /**
10
- * Global Theme Manager
11
- * RECOMMENDED FOR: Frontend (FE)
12
- *
13
- * Demonstrates global state using a dedicated store instance.
14
- */
15
- export const useTheme = gstate<ThemeState>({
16
- mode: 'light',
17
- accent: '#007bff'
18
- }, {
19
- namespace: 'theme-store',
20
- persist: true
21
- })
22
-
23
- /**
24
- * Helper to initialize the theme (useful for SSR or specific init logic)
25
- */
26
- export const initTheme = () => useTheme
27
-
28
- // Reusable action to toggle theme
29
- export const toggleTheme = () => {
30
- const current = useTheme.get('mode')
31
- useTheme.set('mode', current === 'light' ? 'dark' : 'light')
32
- }
@@ -1,19 +0,0 @@
1
- export interface AppState extends Record<string, unknown> {
2
- userProfile: {
3
- name: string;
4
- preferences: any;
5
- };
6
- projects: Array<{
7
- id: string;
8
- content: string;
9
- }>;
10
- }
11
- export declare const useHybridStore: import("../../advanced").IStore<AppState> & (<K extends keyof AppState>(key: K) => readonly [AppState[K] | undefined, (val: AppState[K] | ((draft: AppState[K]) => AppState[K]), options?: unknown) => boolean]);
12
- export declare const syncNow: () => Promise<void>;
13
- export declare const getSyncReport: () => {
14
- lastSync: string;
15
- count: any;
16
- errors: any;
17
- averageKeysPerSync: number;
18
- };
19
- export declare const updateName: (newName: string) => void;
@@ -1,44 +0,0 @@
1
- import { gstate } from '../../index';
2
- import { indexedDBPlugin } from '../../plugins/official/indexeddb.plugin';
3
- import { cloudSyncPlugin, createMongoAdapter } from '../../plugins/official/cloud-sync.plugin';
4
- const initialState = {
5
- userProfile: { name: 'Dario', preferences: { theme: 'dark' } },
6
- projects: []
7
- };
8
- export const useHybridStore = gstate(initialState, {
9
- namespace: 'hybrid-app-vault',
10
- persist: false
11
- });
12
- useHybridStore._addPlugin(indexedDBPlugin({
13
- dbName: 'LocalCacheDB'
14
- }));
15
- useHybridStore._addPlugin(cloudSyncPlugin({
16
- adapter: createMongoAdapter('https://api.mongodb.com/v1', 'YOUR_SECRET_API_KEY'),
17
- autoSyncInterval: 300000,
18
- onSync: (stats) => {
19
- console.info(`[CloudSync] Success! Keys: ${stats.totalKeysSynced}, Total Bytes: ${stats.totalBytesSynced}`);
20
- }
21
- }));
22
- export const syncNow = async () => {
23
- const result = await useHybridStore.plugins.cloudSync.sync();
24
- if (result.status === 'success') {
25
- alert(`Sync completed! ${result.stats.totalKeysSynced} items pushed to cloud.`);
26
- }
27
- else if (result.status === 'no-change') {
28
- console.log('No new changes to sync.');
29
- }
30
- };
31
- export const getSyncReport = () => {
32
- const stats = useHybridStore.plugins.cloudSync.getStats();
33
- return {
34
- lastSync: stats.lastSyncTimestamp ? new Date(stats.lastSyncTimestamp).toLocaleString() : 'Never',
35
- count: stats.syncCount,
36
- errors: stats.errors,
37
- averageKeysPerSync: stats.syncCount > 0 ? stats.totalKeysSynced / stats.syncCount : 0
38
- };
39
- };
40
- export const updateName = (newName) => {
41
- useHybridStore.set('userProfile', (draft) => {
42
- draft.name = newName;
43
- });
44
- };
@@ -1,78 +0,0 @@
1
- import { gstate } from '../../index'
2
- import { indexedDBPlugin } from '../../plugins/official/indexeddb.plugin'
3
- import { cloudSyncPlugin, createMongoAdapter } from '../../plugins/official/cloud-sync.plugin'
4
-
5
- /**
6
- * Hybrid Cloud Sync Store
7
- * RECOMMENDED FOR: Frontend (FE) with Cloud Backup
8
- *
9
- * Demonstrates a multi-layer storage strategy:
10
- * 1. Cache: Memory (fast)
11
- * 2. Persistent Local: IndexedDB (large capacity)
12
- * 3. remote: MongoDB Cloud (On-demand/Scheduled backup)
13
- */
14
-
15
- export interface AppState extends Record<string, unknown> {
16
- userProfile: { name: string; preferences: any }
17
- projects: Array<{ id: string; content: string }>
18
- }
19
-
20
- const initialState: AppState = {
21
- userProfile: { name: 'Dario', preferences: { theme: 'dark' } },
22
- projects: []
23
- }
24
-
25
- // 1. Initialize the store
26
- export const useHybridStore = gstate<AppState>(initialState, {
27
- namespace: 'hybrid-app-vault',
28
- persist: false // We use plugins for persistence
29
- })
30
-
31
- // 2. Add IndexedDB for local persistence (up to GBs)
32
- useHybridStore._addPlugin(indexedDBPlugin({
33
- dbName: 'LocalCacheDB'
34
- }))
35
-
36
- // 3. Add Cloud Sync for remote backup
37
- // Configured to automatically sync every 5 minutes (300000ms)
38
- useHybridStore._addPlugin(cloudSyncPlugin({
39
- adapter: createMongoAdapter('https://api.mongodb.com/v1', 'YOUR_SECRET_API_KEY'),
40
- autoSyncInterval: 300000,
41
- onSync: (stats) => {
42
- console.info(`[CloudSync] Success! Keys: ${stats.totalKeysSynced}, Total Bytes: ${stats.totalBytesSynced}`)
43
- }
44
- }))
45
-
46
- /**
47
- * Manual Trigger for Cloud Sync
48
- */
49
- export const syncNow = async () => {
50
- const result = await (useHybridStore as any).plugins.cloudSync.sync()
51
- if (result.status === 'success') {
52
- alert(`Sync completed! ${result.stats.totalKeysSynced} items pushed to cloud.`)
53
- } else if (result.status === 'no-change') {
54
- console.log('No new changes to sync.')
55
- }
56
- }
57
-
58
- /**
59
- * Get synchronization diagnostics
60
- */
61
- export const getSyncReport = () => {
62
- const stats = (useHybridStore as any).plugins.cloudSync.getStats()
63
- return {
64
- lastSync: stats.lastSyncTimestamp ? new Date(stats.lastSyncTimestamp).toLocaleString() : 'Never',
65
- count: stats.syncCount,
66
- errors: stats.errors,
67
- averageKeysPerSync: stats.syncCount > 0 ? stats.totalKeysSynced / stats.syncCount : 0
68
- }
69
- }
70
-
71
- /**
72
- * Action to update profile
73
- */
74
- export const updateName = (newName: string) => {
75
- useHybridStore.set('userProfile', (draft) => {
76
- draft.name = newName
77
- })
78
- }
@@ -1,13 +0,0 @@
1
- export interface CartItem {
2
- id: string;
3
- name: string;
4
- price: number;
5
- quantity: number;
6
- }
7
- export interface CartState extends Record<string, unknown> {
8
- items: CartItem[];
9
- coupon: string | null;
10
- }
11
- export declare const useCart: import("../../advanced").IStore<CartState> & (<K extends keyof CartState>(key: K) => readonly [CartState[K] | undefined, (val: CartState[K] | ((draft: CartState[K]) => CartState[K]), options?: unknown) => boolean]);
12
- export declare const addToCart: (product: Omit<CartItem, "quantity">) => void;
13
- export declare const getCartTotal: () => number;
@@ -1,23 +0,0 @@
1
- import { gstate } from '../../index';
2
- export const useCart = gstate({
3
- items: [],
4
- coupon: null
5
- }, {
6
- namespace: 'shopping-cart',
7
- persist: true
8
- });
9
- export const addToCart = (product) => {
10
- useCart.set('items', (items) => {
11
- const existing = items.find(item => item.id === product.id);
12
- if (existing) {
13
- existing.quantity++;
14
- }
15
- else {
16
- items.push({ ...product, quantity: 1 });
17
- }
18
- });
19
- };
20
- export const getCartTotal = () => useCart.compute('totalPrice', (get) => {
21
- const items = get('items') || [];
22
- return items.reduce((total, item) => total + (item.price * item.quantity), 0);
23
- });
@@ -1,41 +0,0 @@
1
- import { gstate } from '../../index'
2
-
3
- export interface CartItem {
4
- id: string
5
- name: string
6
- price: number
7
- quantity: number
8
- }
9
-
10
- export interface CartState extends Record<string, unknown> {
11
- items: CartItem[]
12
- coupon: string | null
13
- }
14
-
15
- /**
16
- * Persistent Cart Store
17
- * RECOMMENDED FOR: Frontend (FE)
18
- */
19
- export const useCart = gstate<CartState>({
20
- items: [],
21
- coupon: null
22
- }, {
23
- namespace: 'shopping-cart',
24
- persist: true
25
- })
26
-
27
- export const addToCart = (product: Omit<CartItem, 'quantity'>) => {
28
- useCart.set('items', (items) => {
29
- const existing = items.find(item => item.id === product.id)
30
- if (existing) {
31
- existing.quantity++
32
- } else {
33
- items.push({ ...product, quantity: 1 })
34
- }
35
- })
36
- }
37
-
38
- export const getCartTotal = () => useCart.compute('totalPrice', (get) => {
39
- const items = get<CartItem[]>('items') || []
40
- return items.reduce((total, item) => total + (item.price * item.quantity), 0)
41
- })
@@ -1,47 +0,0 @@
1
- export declare const useDashboard: import("../../advanced").IStore<{
2
- stats: {
3
- visitors: number;
4
- revenue: number;
5
- };
6
- settings: {
7
- allowPublicSignup: boolean;
8
- };
9
- logs: string[];
10
- }> & (<K extends "stats" | "settings" | "logs">(key: K) => readonly [{
11
- stats: {
12
- visitors: number;
13
- revenue: number;
14
- };
15
- settings: {
16
- allowPublicSignup: boolean;
17
- };
18
- logs: string[];
19
- }[K] | undefined, (val: {
20
- stats: {
21
- visitors: number;
22
- revenue: number;
23
- };
24
- settings: {
25
- allowPublicSignup: boolean;
26
- };
27
- logs: string[];
28
- }[K] | ((draft: {
29
- stats: {
30
- visitors: number;
31
- revenue: number;
32
- };
33
- settings: {
34
- allowPublicSignup: boolean;
35
- };
36
- logs: string[];
37
- }[K]) => {
38
- stats: {
39
- visitors: number;
40
- revenue: number;
41
- };
42
- settings: {
43
- allowPublicSignup: boolean;
44
- };
45
- logs: string[];
46
- }[K]), options?: unknown) => boolean]);
47
- export declare const addLog: (msg: string) => boolean;
@@ -1,31 +0,0 @@
1
- import { gstate } from '../../index';
2
- export const useDashboard = gstate({
3
- stats: { visitors: 100, revenue: 5000 },
4
- settings: { allowPublicSignup: true },
5
- logs: []
6
- }, {
7
- userId: 'manager-101',
8
- accessRules: [
9
- {
10
- pattern: (key, userId) => key === 'stats' && userId === 'manager-101',
11
- permissions: ['read']
12
- },
13
- {
14
- pattern: (key, userId) => key === 'settings' && userId === 'manager-101',
15
- permissions: ['read', 'write']
16
- },
17
- {
18
- pattern: (key, userId) => key === 'logs' && userId === 'admin-user',
19
- permissions: ['admin']
20
- }
21
- ]
22
- });
23
- export const addLog = (msg) => {
24
- const success = useDashboard.set('logs', (draft) => {
25
- draft.push(msg);
26
- });
27
- if (!success) {
28
- console.warn(`[Security] Access Denied for user ${useDashboard.userId}: Insufficient permissions for 'logs'`);
29
- }
30
- return success;
31
- };