@asaidimu/react-store 1.0.1 → 1.1.1

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/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var p=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var v=(a,e)=>{for(var t in e)p(a,t,{get:e[t],enumerable:!0})},w=(a,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of b(e))!T.call(a,r)&&r!==t&&p(a,r,{get:()=>e[r],enumerable:!(i=S(e,r))||i.enumerable});return a};var M=a=>w(p({},"__esModule",{value:!0}),a);var $={};v($,{StateManager:()=>l,createStore:()=>x});module.exports=M($);var h=require("react");var y=require("@asaidimu/node"),k="root",g=class{cache=new Map;maxSize;maxAge;constructor(e=100,t=5e3){this.maxSize=e,this.maxAge=t}get(e){let t=this.cache.get(e);if(t){if(Date.now()-t.timestamp>this.maxAge){this.cache.delete(e);return}return t.value}}set(e,t){if(this.cache.size>=this.maxSize){let i=this.cache.keys().next().value;this.cache.delete(i)}this.cache.set(e,{value:t,timestamp:Date.now()})}},l=class{manager;subscribers=new Set;middleware;options;definition;middlewareCache;constructor(e,t={}){this.definition=e,this.options=t,this.middleware=t.middleware||[],this.middlewareCache=new g,this.manager=this.initializeManager()}initializeManager(){let e=(0,y.createNodeManager)();e.add("root",null,{key:"root"});let t=(i="root",r=this.definition.state)=>{for(let[s,n]of Object.entries(r))typeof n=="object"&&!Array.isArray(n)?(e.add(`${i}/${s}`,n,{key:s}),t(`${i}/${s}`,n)):e.add(`${i}/${s}`,n,{key:s})};if(t(),this.definition.sync){let i=this.getState.bind(this),r=this.definition.sync;e.subscribe("node",()=>{r(i())})}return e}getState(){return this.manager.store().map("key").root}getTree(){return this.manager.store().serialize()}setState(e,t){let i=this.getState();if(!i)return;let r=(s,n)=>{if(typeof n=="object"&&!Array.isArray(n))for(let[o,u]of Object.entries(n)){let d=`${s}/${o}`;r(d,u)}else this.manager.update(s,n)};try{for(let[s,n]of Object.entries(e)){let o=t?`${t}/${s}`:`root/${s}`;if(i[s]===n)continue;if(!this.validateState({[s]:n},o))throw new Error(`Validation failed for ${o}`);let u=this.applyMiddleware({[s]:n},o);r(o,u[s])}this.notifySubscribers()}catch(s){this.handleError(s,{action:"setState",state:e})}}validateState(e,t){if(!this.options.validation)return!0;let i=t.split("/").pop(),r=this.options.validation[i];return r?r.every(s=>{try{return s.validate(e[i])}catch(n){return console.error(`Validation error at ${t}:`,n),!1}}):!0}applyMiddleware(e,t){let i=`${t}-${JSON.stringify(e)}`,r=this.middlewareCache.get(i);if(r)return r;let s=this.middleware.reduce((n,o)=>o(n),e);return this.middlewareCache.set(i,s),s}handleError(e,t){this.options.error?.onError&&this.options.error.onError(e,t),this.options.error?.recovery}subscribe(e){return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}notifySubscribers(){this.subscribers.forEach(e=>e())}select(e,t){let i=[],r=this.manager;function s(n){let o={get:(u,d)=>{let c=`${n}/${d}`;return r.exists(c)&&i.push(c),s(c)}};return new Proxy({},o)}return e(s(k)),r.subscribe({event:"node",path:i},t)}};var f=class{metrics={updates:0,subscriptionTriggers:0,middlewareExecutions:0,batchSize:0,lastUpdateDuration:0};enableMetrics;constructor(e=!1){this.enableMetrics=e}track(e,t){if(!this.enableMetrics)return t();let i=performance.now();try{let r=t();return this.recordMetric(e,performance.now()-i),r}catch(r){throw this.recordError(e,r),r}}recordMetric(e,t){switch(e){case"update":this.metrics.updates++,this.metrics.lastUpdateDuration=t;break;case"subscription":this.metrics.subscriptionTriggers++;break;case"middleware":this.metrics.middlewareExecutions++;break}}recordError(e,t){console.error(`Error in ${e}:`,t)}getMetrics(){return{...this.metrics}}reset(){this.metrics={updates:0,subscriptionTriggers:0,middlewareExecutions:0,batchSize:0,lastUpdateDuration:0}}},m=class{selectorCache=new WeakMap;create(e){return t=>{let i=this.selectorCache.get(e);i||(i=new WeakMap,this.selectorCache.set(e,i));let r=i.get(t);if(r)return r.result;let s=e(t);return i.set(t,{result:s,deps:[]}),s}}};function x(a,e={}){let t=new l(a,e),i=new m,r=new f(e.enableMetrics),s=Object.entries(a.actions).reduce((n,[o,u])=>(n[o]=async(...d)=>{try{return await r.track("update",async()=>{let c=await u(t.getState(),...d);return t.setState(c),c})}catch(c){throw console.error(`Error in action ${o}:`,c),c}},n),{});return function(){return{select:(0,h.useCallback)(u=>{let d=i.create(u);return(0,h.useSyncExternalStore)(c=>r.track("subscription",()=>t.select(d,c)),()=>d(t.getState()),()=>d(t.getState()))},[]),actions:s,getState:()=>t.getState(),getTree:()=>t.getTree(),getMetrics:()=>r.getMetrics(),resetMetrics:()=>r.reset()}}}0&&(module.exports={StateManager,createStore});
1
+ "use strict";var m=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var T=Object.prototype.hasOwnProperty;var M=(n,t)=>{for(var e in t)m(n,e,{get:t[e],enumerable:!0})},E=(n,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of b(t))!T.call(n,r)&&r!==e&&m(n,r,{get:()=>t[r],enumerable:!(i=w(t,r))||i.enumerable});return n};var k=n=>E(m({},"__esModule",{value:!0}),n);var R={};M(R,{StateManager:()=>h,createStore:()=>x});module.exports=k(R);var g=require("react");var S=require("@asaidimu/node");var p=class{cache=new Map;maxSize;maxAge;constructor(t=100,e=5e3){this.maxSize=t,this.maxAge=e}get(t){let e=this.cache.get(t);if(e){if(Date.now()-e.timestamp>this.maxAge){this.cache.delete(t);return}return e.value}}set(t,e){if(this.cache.size>=this.maxSize){let i=Array.from(this.cache.entries()).sort(([,r],[,a])=>r.timestamp-a.timestamp)[0][0];this.cache.delete(i)}this.cache.set(t,{value:e,timestamp:Date.now()})}clear(){this.cache.clear()}};var f=class{validation;constructor(t={}){this.validation=t}validate(t,e){let i=[],r=e.split("/").pop(),a=this.validation[r];return a?(a.forEach((o,s)=>{try{o.validate(t[r])||i.push(o.message||`Validation failed for ${String(r)} at rule ${s}`)}catch(c){i.push(`Validation error at ${e}: ${c.message}`)}}),{valid:i.length===0,errors:i}):{valid:!0,errors:[]}}};var u="root",h=class{manager;subscribers=new Set;middleware;options;definition;middlewareCache;validator;lastValidationResult={valid:!0,errors:[]};constructor(t,e={}){this.definition=t,this.options=e,this.middleware=this.sortMiddleware(e.middleware||[]),this.middlewareCache=new p,this.validator=new f(e.validation),this.manager=this.initializeManager()}sortMiddleware(t){let e=new Map;t.forEach(s=>{e.set(s.id,new Set(s.dependencies||[]))});let i=[],r=new Set,a=new Set,o=s=>{if(a.has(s))throw new Error(`Circular dependency found: ${s}`);if(r.has(s))return;a.add(s),(e.get(s)||new Set).forEach(d=>o(d)),a.delete(s),r.add(s),i.push(t.find(d=>d.id===s))};return t.forEach(s=>{r.has(s.id)||o(s.id)}),i.sort((s,c)=>(c.priority||0)-(s.priority||0))}initializeManager(){let t=(0,S.createNodeManager)();t.add(u,null,{key:u});let e=(i=u,r=this.definition.state)=>{for(let[a,o]of Object.entries(r))typeof o=="object"&&!Array.isArray(o)?(t.add(`${i}/${a}`,o,{key:a}),e(`${i}/${a}`,o)):t.add(`${i}/${a}`,o,{key:a})};if(e(),this.definition.sync){let i=this.getState.bind(this);t.subscribe("node",()=>{this.definition.sync(i())})}return t}async applyMiddleware(t,e,i={value:!1}){let r=`${e}-${JSON.stringify(t)}`,a=this.middlewareCache.get(r);if(a)return a;if(this.lastValidationResult=this.validator.validate(t,e),!this.lastValidationResult.valid)throw new Error(`Validation failed: ${this.lastValidationResult.errors.join(", ")}`);let o={fullState:this.getState(),path:e,abortUpdate:()=>{i.value=!0},getValidationResult:()=>this.lastValidationResult};try{let s=t;for(let c of this.middleware){if(i.value)throw new Error("Update aborted by middleware");if(s=await Promise.resolve(c.transform(s,o)),this.lastValidationResult=this.validator.validate(s,e),!this.lastValidationResult.valid)throw new Error(`Validation failed after middleware ${c.id}: ${this.lastValidationResult.errors.join(", ")}`)}return this.middlewareCache.set(r,s),s}catch(s){throw this.handleMiddlewareError(s,t,e),s}}handleMiddlewareError(t,e,i){if(this.options.error?.onError&&this.options.error.onError(t,{action:"applyMiddleware",state:e,path:i,error:t}),this.options.error?.recovery)switch(this.middlewareCache.clear(),this.options.error.recovery.strategy){case"retry":break;case"revert":this.revertState(i);break;case"ignore":break}}revertState(t){let e=this.getState(),i=t.split("/"),r=e;for(let o=1;o<i.length-1;o++)r=r[i[o]];let a=i[i.length-1];this.manager.update(t,r[a],{force:!0})}async setState(t,e){let r=[{path:e||u,state:t}];try{this.options.lifecycleHooks?.beforeAll?.(r);let a={value:!1};for(let o of r){if(a.value)break;let s=await this.applyMiddleware(o.state,o.path,a);a.value||this.updateState(s,o.path)}this.options.lifecycleHooks?.afterAll?.(r),this.notifySubscribers()}catch(a){this.handleError(a,{action:"batchUpdate",state:r})}}updateState(t,e){let i=(r,a)=>{typeof a=="object"&&a!==null&&!Array.isArray(a)?Object.entries(a).forEach(([o,s])=>{i(`${r}/${o}`,s)}):this.manager.update(r,a,{force:!0})};Object.entries(t).forEach(([r,a])=>{let o=e===u?`${u}/${r}`:`${e}/${r}`;i(o,a)})}handleError(t,e){this.options.error?.onError&&this.options.error.onError(t,e)}getState(){return this.manager.store().map("key")[u]}getValidationResult(){return this.lastValidationResult}subscribe(t){return this.subscribers.add(t),()=>{this.subscribers.delete(t)}}notifySubscribers(){this.subscribers.forEach(t=>t())}select(t,e){let i=[],r=this.manager;function a(o){let s={get:(c,d)=>{let l=`${o}/${d}`;return r.exists(l)&&i.push(l),a(l)}};return new Proxy({},s)}return t(a(u)),r.subscribe({event:"node",path:i},()=>{e(t(this.getState()))})}getTree(){return this.manager.store().serialize()}};var v=class{metrics={updates:0,subscriptionTriggers:0,middlewareExecutions:0,batchSize:0,lastUpdateDuration:0};enableMetrics;constructor(t=!1){this.enableMetrics=t}track(t,e){if(!this.enableMetrics)return e();let i=performance.now();try{let r=e();return this.recordMetric(t,performance.now()-i),r}catch(r){throw this.recordError(t,r),r}}recordMetric(t,e){switch(t){case"update":this.metrics.updates++,this.metrics.lastUpdateDuration=e;break;case"subscription":this.metrics.subscriptionTriggers++;break;case"middleware":this.metrics.middlewareExecutions++;break}}recordError(t,e){console.error(`Error in ${t}:`,e)}getMetrics(){return{...this.metrics}}reset(){this.metrics={updates:0,subscriptionTriggers:0,middlewareExecutions:0,batchSize:0,lastUpdateDuration:0}}},y=class{selectorCache=new WeakMap;create(t){return e=>{let i=this.selectorCache.get(t);i||(i=new WeakMap,this.selectorCache.set(t,i));let r=i.get(e);if(r)return r.result;let a=t(e);return i.set(e,{result:a,deps:[]}),a}}};function x(n,t={}){let e=new h(n,t),i=new y,r=new v(t.enableMetrics),a=Object.entries(n.actions).reduce((o,[s,c])=>(o[s]=async(...d)=>{try{return await r.track("update",async()=>{let l=await c(e.getState(),...d);return e.setState(l),l})}catch(l){throw console.error(`Error in action ${s}:`,l),l}},o),{});return function(){return{select:(0,g.useCallback)(c=>{let d=i.create(c);return(0,g.useSyncExternalStore)(l=>r.track("subscription",()=>e.select(d,l)),()=>d(e.getState()),()=>d(e.getState()))},[]),actions:a,getState:()=>e.getState(),getTree:()=>e.getTree(),getMetrics:()=>r.getMetrics(),resetMetrics:()=>r.reset()}}}0&&(module.exports={StateManager,createStore});
package/index.d.cts CHANGED
@@ -1,6 +1,63 @@
1
1
  import * as _asaidimu_node from '@asaidimu/node';
2
2
 
3
- type Middleware<T> = (state: T) => T;
3
+ type ValidationRule<T> = {
4
+ validate: (value: T) => boolean;
5
+ message?: string;
6
+ };
7
+ type ValidationResult = {
8
+ valid: boolean;
9
+ errors: string[];
10
+ };
11
+ type Validation<T> = {
12
+ [K in keyof T]?: ValidationRule<T[K]>[];
13
+ };
14
+ type ErrorInfo = {
15
+ action: string;
16
+ state: unknown;
17
+ path?: string;
18
+ error?: Error;
19
+ };
20
+ type ErrorHandler = (error: Error, info: ErrorInfo) => void;
21
+ type RecoveryStrategy = 'retry' | 'revert' | 'ignore';
22
+ type ErrorRecovery = {
23
+ strategy: RecoveryStrategy;
24
+ maxAttempts?: number;
25
+ };
26
+ type ErrorOptions = {
27
+ onError?: ErrorHandler;
28
+ recovery?: ErrorRecovery;
29
+ };
30
+ type MiddlewareContext<T> = {
31
+ fullState: T;
32
+ path: string;
33
+ abortUpdate: () => void;
34
+ getValidationResult: () => ValidationResult;
35
+ };
36
+ type MiddleWare<T> = {
37
+ id: string;
38
+ priority?: number;
39
+ dependencies?: string[];
40
+ transform: (state: Partial<T>, context: MiddlewareContext<T>) => Promise<Partial<T>> | Partial<T>;
41
+ };
42
+ type BatchUpdate<T> = {
43
+ path: string;
44
+ state: Partial<T>;
45
+ };
46
+ type MiddlewareLifecycleHooks<T> = {
47
+ beforeAll?: (updates: BatchUpdate<T>[]) => void;
48
+ afterAll?: (updates: BatchUpdate<T>[]) => void;
49
+ };
50
+ interface StoreOptions<T> {
51
+ middleware?: MiddleWare<T>[];
52
+ validation?: Validation<T>;
53
+ error?: ErrorOptions;
54
+ lifecycleHooks?: MiddlewareLifecycleHooks<T>;
55
+ name?: string;
56
+ trace?: boolean;
57
+ maxTraceHistory?: number;
58
+ traceRetentionPeriod?: number;
59
+ migrations?: Migration<T>[];
60
+ }
4
61
  type Actions<T> = {
5
62
  [K: string]: (state: T, ...args: any[]) => Partial<T> | Promise<Partial<T>>;
6
63
  };
@@ -9,38 +66,10 @@ interface StoreDefinition<T, R extends Actions<T>> {
9
66
  actions: R;
10
67
  sync?: (args: T) => void;
11
68
  }
12
- type Schema<T> = {
13
- [K in keyof T]?: {
14
- validate: (value: T[K]) => boolean;
15
- message: string;
16
- }[];
17
- };
18
69
  interface Migration<T> {
19
70
  version: number;
20
71
  migrate: (state: T) => T;
21
72
  }
22
- interface ErrorConfig {
23
- onError?: (error: Error, errorInfo: {
24
- action?: string;
25
- state?: any;
26
- [key: string]: unknown;
27
- }) => void;
28
- recovery?: {
29
- strategy: "rollback" | "retry" | "reset";
30
- maxAttempts: number;
31
- backoffMs: number;
32
- };
33
- }
34
- interface StoreOptions<T> {
35
- name?: string;
36
- trace?: boolean;
37
- maxTraceHistory?: number;
38
- traceRetentionPeriod?: number;
39
- middleware?: Middleware<T>[];
40
- migrations?: Migration<T>[];
41
- validation?: Schema<T>;
42
- error?: ErrorConfig;
43
- }
44
73
  interface StateManagerMetrics {
45
74
  updates: number;
46
75
  subscriptionTriggers: number;
@@ -73,19 +102,25 @@ declare class StateManager<T extends Record<string, unknown>, R extends Actions<
73
102
  private options;
74
103
  private definition;
75
104
  private middlewareCache;
105
+ private validator;
106
+ private lastValidationResult;
76
107
  constructor(definition: StoreDefinition<T, R>, options?: StoreOptions<T>);
108
+ private sortMiddleware;
77
109
  private initializeManager;
78
- getState(): T;
79
- getTree(): _asaidimu_node.Node<any, {
80
- key: string;
81
- }>[];
82
- setState(nextState: Partial<T>, path?: string): void;
83
- private validateState;
84
110
  private applyMiddleware;
111
+ private handleMiddlewareError;
112
+ private revertState;
113
+ setState(nextState: Partial<T>, path?: string): Promise<void>;
114
+ private updateState;
85
115
  private handleError;
116
+ getState(): T;
117
+ getValidationResult(): ValidationResult;
86
118
  subscribe(callback: () => void): () => void;
87
119
  private notifySubscribers;
88
- select<S>(selector: (state: T) => S, callback: (state: any) => void): () => void;
120
+ select<S>(selector: (state: T) => S, callback: (state: S) => void): () => void;
121
+ getTree(): _asaidimu_node.Node<any, {
122
+ key: string;
123
+ }>[];
89
124
  }
90
125
 
91
126
  export { StateManager, createStore };
package/index.d.ts CHANGED
@@ -1,6 +1,63 @@
1
1
  import * as _asaidimu_node from '@asaidimu/node';
2
2
 
3
- type Middleware<T> = (state: T) => T;
3
+ type ValidationRule<T> = {
4
+ validate: (value: T) => boolean;
5
+ message?: string;
6
+ };
7
+ type ValidationResult = {
8
+ valid: boolean;
9
+ errors: string[];
10
+ };
11
+ type Validation<T> = {
12
+ [K in keyof T]?: ValidationRule<T[K]>[];
13
+ };
14
+ type ErrorInfo = {
15
+ action: string;
16
+ state: unknown;
17
+ path?: string;
18
+ error?: Error;
19
+ };
20
+ type ErrorHandler = (error: Error, info: ErrorInfo) => void;
21
+ type RecoveryStrategy = 'retry' | 'revert' | 'ignore';
22
+ type ErrorRecovery = {
23
+ strategy: RecoveryStrategy;
24
+ maxAttempts?: number;
25
+ };
26
+ type ErrorOptions = {
27
+ onError?: ErrorHandler;
28
+ recovery?: ErrorRecovery;
29
+ };
30
+ type MiddlewareContext<T> = {
31
+ fullState: T;
32
+ path: string;
33
+ abortUpdate: () => void;
34
+ getValidationResult: () => ValidationResult;
35
+ };
36
+ type MiddleWare<T> = {
37
+ id: string;
38
+ priority?: number;
39
+ dependencies?: string[];
40
+ transform: (state: Partial<T>, context: MiddlewareContext<T>) => Promise<Partial<T>> | Partial<T>;
41
+ };
42
+ type BatchUpdate<T> = {
43
+ path: string;
44
+ state: Partial<T>;
45
+ };
46
+ type MiddlewareLifecycleHooks<T> = {
47
+ beforeAll?: (updates: BatchUpdate<T>[]) => void;
48
+ afterAll?: (updates: BatchUpdate<T>[]) => void;
49
+ };
50
+ interface StoreOptions<T> {
51
+ middleware?: MiddleWare<T>[];
52
+ validation?: Validation<T>;
53
+ error?: ErrorOptions;
54
+ lifecycleHooks?: MiddlewareLifecycleHooks<T>;
55
+ name?: string;
56
+ trace?: boolean;
57
+ maxTraceHistory?: number;
58
+ traceRetentionPeriod?: number;
59
+ migrations?: Migration<T>[];
60
+ }
4
61
  type Actions<T> = {
5
62
  [K: string]: (state: T, ...args: any[]) => Partial<T> | Promise<Partial<T>>;
6
63
  };
@@ -9,38 +66,10 @@ interface StoreDefinition<T, R extends Actions<T>> {
9
66
  actions: R;
10
67
  sync?: (args: T) => void;
11
68
  }
12
- type Schema<T> = {
13
- [K in keyof T]?: {
14
- validate: (value: T[K]) => boolean;
15
- message: string;
16
- }[];
17
- };
18
69
  interface Migration<T> {
19
70
  version: number;
20
71
  migrate: (state: T) => T;
21
72
  }
22
- interface ErrorConfig {
23
- onError?: (error: Error, errorInfo: {
24
- action?: string;
25
- state?: any;
26
- [key: string]: unknown;
27
- }) => void;
28
- recovery?: {
29
- strategy: "rollback" | "retry" | "reset";
30
- maxAttempts: number;
31
- backoffMs: number;
32
- };
33
- }
34
- interface StoreOptions<T> {
35
- name?: string;
36
- trace?: boolean;
37
- maxTraceHistory?: number;
38
- traceRetentionPeriod?: number;
39
- middleware?: Middleware<T>[];
40
- migrations?: Migration<T>[];
41
- validation?: Schema<T>;
42
- error?: ErrorConfig;
43
- }
44
73
  interface StateManagerMetrics {
45
74
  updates: number;
46
75
  subscriptionTriggers: number;
@@ -73,19 +102,25 @@ declare class StateManager<T extends Record<string, unknown>, R extends Actions<
73
102
  private options;
74
103
  private definition;
75
104
  private middlewareCache;
105
+ private validator;
106
+ private lastValidationResult;
76
107
  constructor(definition: StoreDefinition<T, R>, options?: StoreOptions<T>);
108
+ private sortMiddleware;
77
109
  private initializeManager;
78
- getState(): T;
79
- getTree(): _asaidimu_node.Node<any, {
80
- key: string;
81
- }>[];
82
- setState(nextState: Partial<T>, path?: string): void;
83
- private validateState;
84
110
  private applyMiddleware;
111
+ private handleMiddlewareError;
112
+ private revertState;
113
+ setState(nextState: Partial<T>, path?: string): Promise<void>;
114
+ private updateState;
85
115
  private handleError;
116
+ getState(): T;
117
+ getValidationResult(): ValidationResult;
86
118
  subscribe(callback: () => void): () => void;
87
119
  private notifySubscribers;
88
- select<S>(selector: (state: T) => S, callback: (state: any) => void): () => void;
120
+ select<S>(selector: (state: T) => S, callback: (state: S) => void): () => void;
121
+ getTree(): _asaidimu_node.Node<any, {
122
+ key: string;
123
+ }>[];
89
124
  }
90
125
 
91
126
  export { StateManager, createStore };
package/index.js CHANGED
@@ -1 +1 @@
1
- import{useCallback as y,useSyncExternalStore as S}from"react";import{createNodeManager as f}from"@asaidimu/node";var m="root",h=class{cache=new Map;maxSize;maxAge;constructor(e=100,t=5e3){this.maxSize=e,this.maxAge=t}get(e){let t=this.cache.get(e);if(t){if(Date.now()-t.timestamp>this.maxAge){this.cache.delete(e);return}return t.value}}set(e,t){if(this.cache.size>=this.maxSize){let i=this.cache.keys().next().value;this.cache.delete(i)}this.cache.set(e,{value:t,timestamp:Date.now()})}},l=class{manager;subscribers=new Set;middleware;options;definition;middlewareCache;constructor(e,t={}){this.definition=e,this.options=t,this.middleware=t.middleware||[],this.middlewareCache=new h,this.manager=this.initializeManager()}initializeManager(){let e=f();e.add("root",null,{key:"root"});let t=(i="root",s=this.definition.state)=>{for(let[r,n]of Object.entries(s))typeof n=="object"&&!Array.isArray(n)?(e.add(`${i}/${r}`,n,{key:r}),t(`${i}/${r}`,n)):e.add(`${i}/${r}`,n,{key:r})};if(t(),this.definition.sync){let i=this.getState.bind(this),s=this.definition.sync;e.subscribe("node",()=>{s(i())})}return e}getState(){return this.manager.store().map("key").root}getTree(){return this.manager.store().serialize()}setState(e,t){let i=this.getState();if(!i)return;let s=(r,n)=>{if(typeof n=="object"&&!Array.isArray(n))for(let[a,d]of Object.entries(n)){let c=`${r}/${a}`;s(c,d)}else this.manager.update(r,n)};try{for(let[r,n]of Object.entries(e)){let a=t?`${t}/${r}`:`root/${r}`;if(i[r]===n)continue;if(!this.validateState({[r]:n},a))throw new Error(`Validation failed for ${a}`);let d=this.applyMiddleware({[r]:n},a);s(a,d[r])}this.notifySubscribers()}catch(r){this.handleError(r,{action:"setState",state:e})}}validateState(e,t){if(!this.options.validation)return!0;let i=t.split("/").pop(),s=this.options.validation[i];return s?s.every(r=>{try{return r.validate(e[i])}catch(n){return console.error(`Validation error at ${t}:`,n),!1}}):!0}applyMiddleware(e,t){let i=`${t}-${JSON.stringify(e)}`,s=this.middlewareCache.get(i);if(s)return s;let r=this.middleware.reduce((n,a)=>a(n),e);return this.middlewareCache.set(i,r),r}handleError(e,t){this.options.error?.onError&&this.options.error.onError(e,t),this.options.error?.recovery}subscribe(e){return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}notifySubscribers(){this.subscribers.forEach(e=>e())}select(e,t){let i=[],s=this.manager;function r(n){let a={get:(d,c)=>{let o=`${n}/${c}`;return s.exists(o)&&i.push(o),r(o)}};return new Proxy({},a)}return e(r(m)),s.subscribe({event:"node",path:i},t)}};var p=class{metrics={updates:0,subscriptionTriggers:0,middlewareExecutions:0,batchSize:0,lastUpdateDuration:0};enableMetrics;constructor(e=!1){this.enableMetrics=e}track(e,t){if(!this.enableMetrics)return t();let i=performance.now();try{let s=t();return this.recordMetric(e,performance.now()-i),s}catch(s){throw this.recordError(e,s),s}}recordMetric(e,t){switch(e){case"update":this.metrics.updates++,this.metrics.lastUpdateDuration=t;break;case"subscription":this.metrics.subscriptionTriggers++;break;case"middleware":this.metrics.middlewareExecutions++;break}}recordError(e,t){console.error(`Error in ${e}:`,t)}getMetrics(){return{...this.metrics}}reset(){this.metrics={updates:0,subscriptionTriggers:0,middlewareExecutions:0,batchSize:0,lastUpdateDuration:0}}},g=class{selectorCache=new WeakMap;create(e){return t=>{let i=this.selectorCache.get(e);i||(i=new WeakMap,this.selectorCache.set(e,i));let s=i.get(t);if(s)return s.result;let r=e(t);return i.set(t,{result:r,deps:[]}),r}}};function M(u,e={}){let t=new l(u,e),i=new g,s=new p(e.enableMetrics),r=Object.entries(u.actions).reduce((n,[a,d])=>(n[a]=async(...c)=>{try{return await s.track("update",async()=>{let o=await d(t.getState(),...c);return t.setState(o),o})}catch(o){throw console.error(`Error in action ${a}:`,o),o}},n),{});return function(){return{select:y(d=>{let c=i.create(d);return S(o=>s.track("subscription",()=>t.select(c,o)),()=>c(t.getState()),()=>c(t.getState()))},[]),actions:r,getState:()=>t.getState(),getTree:()=>t.getTree(),getMetrics:()=>s.getMetrics(),resetMetrics:()=>s.reset()}}}export{l as StateManager,M as createStore};
1
+ import{useCallback as y,useSyncExternalStore as S}from"react";import{createNodeManager as v}from"@asaidimu/node";var h=class{cache=new Map;maxSize;maxAge;constructor(t=100,e=5e3){this.maxSize=t,this.maxAge=e}get(t){let e=this.cache.get(t);if(e){if(Date.now()-e.timestamp>this.maxAge){this.cache.delete(t);return}return e.value}}set(t,e){if(this.cache.size>=this.maxSize){let i=Array.from(this.cache.entries()).sort(([,r],[,a])=>r.timestamp-a.timestamp)[0][0];this.cache.delete(i)}this.cache.set(t,{value:e,timestamp:Date.now()})}clear(){this.cache.clear()}};var p=class{validation;constructor(t={}){this.validation=t}validate(t,e){let i=[],r=e.split("/").pop(),a=this.validation[r];return a?(a.forEach((o,s)=>{try{o.validate(t[r])||i.push(o.message||`Validation failed for ${String(r)} at rule ${s}`)}catch(n){i.push(`Validation error at ${e}: ${n.message}`)}}),{valid:i.length===0,errors:i}):{valid:!0,errors:[]}}};var l="root",f=class{manager;subscribers=new Set;middleware;options;definition;middlewareCache;validator;lastValidationResult={valid:!0,errors:[]};constructor(t,e={}){this.definition=t,this.options=e,this.middleware=this.sortMiddleware(e.middleware||[]),this.middlewareCache=new h,this.validator=new p(e.validation),this.manager=this.initializeManager()}sortMiddleware(t){let e=new Map;t.forEach(s=>{e.set(s.id,new Set(s.dependencies||[]))});let i=[],r=new Set,a=new Set,o=s=>{if(a.has(s))throw new Error(`Circular dependency found: ${s}`);if(r.has(s))return;a.add(s),(e.get(s)||new Set).forEach(c=>o(c)),a.delete(s),r.add(s),i.push(t.find(c=>c.id===s))};return t.forEach(s=>{r.has(s.id)||o(s.id)}),i.sort((s,n)=>(n.priority||0)-(s.priority||0))}initializeManager(){let t=v();t.add(l,null,{key:l});let e=(i=l,r=this.definition.state)=>{for(let[a,o]of Object.entries(r))typeof o=="object"&&!Array.isArray(o)?(t.add(`${i}/${a}`,o,{key:a}),e(`${i}/${a}`,o)):t.add(`${i}/${a}`,o,{key:a})};if(e(),this.definition.sync){let i=this.getState.bind(this);t.subscribe("node",()=>{this.definition.sync(i())})}return t}async applyMiddleware(t,e,i={value:!1}){let r=`${e}-${JSON.stringify(t)}`,a=this.middlewareCache.get(r);if(a)return a;if(this.lastValidationResult=this.validator.validate(t,e),!this.lastValidationResult.valid)throw new Error(`Validation failed: ${this.lastValidationResult.errors.join(", ")}`);let o={fullState:this.getState(),path:e,abortUpdate:()=>{i.value=!0},getValidationResult:()=>this.lastValidationResult};try{let s=t;for(let n of this.middleware){if(i.value)throw new Error("Update aborted by middleware");if(s=await Promise.resolve(n.transform(s,o)),this.lastValidationResult=this.validator.validate(s,e),!this.lastValidationResult.valid)throw new Error(`Validation failed after middleware ${n.id}: ${this.lastValidationResult.errors.join(", ")}`)}return this.middlewareCache.set(r,s),s}catch(s){throw this.handleMiddlewareError(s,t,e),s}}handleMiddlewareError(t,e,i){if(this.options.error?.onError&&this.options.error.onError(t,{action:"applyMiddleware",state:e,path:i,error:t}),this.options.error?.recovery)switch(this.middlewareCache.clear(),this.options.error.recovery.strategy){case"retry":break;case"revert":this.revertState(i);break;case"ignore":break}}revertState(t){let e=this.getState(),i=t.split("/"),r=e;for(let o=1;o<i.length-1;o++)r=r[i[o]];let a=i[i.length-1];this.manager.update(t,r[a],{force:!0})}async setState(t,e){let r=[{path:e||l,state:t}];try{this.options.lifecycleHooks?.beforeAll?.(r);let a={value:!1};for(let o of r){if(a.value)break;let s=await this.applyMiddleware(o.state,o.path,a);a.value||this.updateState(s,o.path)}this.options.lifecycleHooks?.afterAll?.(r),this.notifySubscribers()}catch(a){this.handleError(a,{action:"batchUpdate",state:r})}}updateState(t,e){let i=(r,a)=>{typeof a=="object"&&a!==null&&!Array.isArray(a)?Object.entries(a).forEach(([o,s])=>{i(`${r}/${o}`,s)}):this.manager.update(r,a,{force:!0})};Object.entries(t).forEach(([r,a])=>{let o=e===l?`${l}/${r}`:`${e}/${r}`;i(o,a)})}handleError(t,e){this.options.error?.onError&&this.options.error.onError(t,e)}getState(){return this.manager.store().map("key")[l]}getValidationResult(){return this.lastValidationResult}subscribe(t){return this.subscribers.add(t),()=>{this.subscribers.delete(t)}}notifySubscribers(){this.subscribers.forEach(t=>t())}select(t,e){let i=[],r=this.manager;function a(o){let s={get:(n,c)=>{let d=`${o}/${c}`;return r.exists(d)&&i.push(d),a(d)}};return new Proxy({},s)}return t(a(l)),r.subscribe({event:"node",path:i},()=>{e(t(this.getState()))})}getTree(){return this.manager.store().serialize()}};var g=class{metrics={updates:0,subscriptionTriggers:0,middlewareExecutions:0,batchSize:0,lastUpdateDuration:0};enableMetrics;constructor(t=!1){this.enableMetrics=t}track(t,e){if(!this.enableMetrics)return e();let i=performance.now();try{let r=e();return this.recordMetric(t,performance.now()-i),r}catch(r){throw this.recordError(t,r),r}}recordMetric(t,e){switch(t){case"update":this.metrics.updates++,this.metrics.lastUpdateDuration=e;break;case"subscription":this.metrics.subscriptionTriggers++;break;case"middleware":this.metrics.middlewareExecutions++;break}}recordError(t,e){console.error(`Error in ${t}:`,e)}getMetrics(){return{...this.metrics}}reset(){this.metrics={updates:0,subscriptionTriggers:0,middlewareExecutions:0,batchSize:0,lastUpdateDuration:0}}},m=class{selectorCache=new WeakMap;create(t){return e=>{let i=this.selectorCache.get(t);i||(i=new WeakMap,this.selectorCache.set(t,i));let r=i.get(e);if(r)return r.result;let a=t(e);return i.set(e,{result:a,deps:[]}),a}}};function V(u,t={}){let e=new f(u,t),i=new m,r=new g(t.enableMetrics),a=Object.entries(u.actions).reduce((o,[s,n])=>(o[s]=async(...c)=>{try{return await r.track("update",async()=>{let d=await n(e.getState(),...c);return e.setState(d),d})}catch(d){throw console.error(`Error in action ${s}:`,d),d}},o),{});return function(){return{select:y(n=>{let c=i.create(n);return S(d=>r.track("subscription",()=>e.select(c,d)),()=>c(e.getState()),()=>c(e.getState()))},[]),actions:a,getState:()=>e.getState(),getTree:()=>e.getTree(),getMetrics:()=>r.getMetrics(),resetMetrics:()=>r.reset()}}}export{f as StateManager,V as createStore};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asaidimu/react-store",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "Efficient react state manager.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@asaidimu/events": "^1.0.0",
30
- "@asaidimu/node": "^1.0.4",
30
+ "@asaidimu/node": "^1.0.5",
31
31
  "react": "^19.0.0"
32
32
  }
33
33
  }