api-core-lib 12.0.12 → 12.0.14

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.
@@ -228,6 +228,7 @@ interface ExecuteOptions<TInput, TOutput, TContext = unknown> {
228
228
  onMutate?: (variables: TInput) => TContext | Promise<TContext>;
229
229
  onSuccess?: (data: TOutput, context?: TContext) => void;
230
230
  onError?: (error: ApiError, context?: TContext) => void;
231
+ onSettled?: (data?: TOutput, error?: ApiError, context?: TContext) => void;
231
232
  }
232
233
  /** @description A fully-typed object representing the callable actions for a module. */
233
234
  type ModuleActions<TActions extends Record<string, ActionConfigModule<any, any>>> = {
@@ -254,4 +255,4 @@ interface UseApiModuleReturn<TActions extends Record<string, ActionConfigModule<
254
255
  dehydrate: () => string;
255
256
  }
256
257
 
257
- export type { ActionConfigModule as A, ExecutableAction as E, InputOf as I, LogLevel as L, MiddlewareContext as M, OutputOf as O, PaginationMeta as P, QueryOptions as Q, RequestConfig as R, StandardResponse as S, Tokens as T, UseApiConfig as U, ValidationError as V, ApiModuleConfig as a, UseApiModuleOptions as b, UseApiModuleReturn as c, ApiClientConfig as d, ActionOptions as e, ActionStateModule as f, UseApiQuery as g, ApiError as h, TokenManager as i, Middleware as j, RefreshTokenConfig as k, ActionConfig as l, UseApiState as m, ActionState as n, ExecuteOptions as o, ModuleActions as p, ModuleStates as q };
258
+ export type { ActionConfigModule as A, ExecutableAction as E, InputOf as I, LogLevel as L, MiddlewareContext as M, OutputOf as O, PaginationMeta as P, QueryOptions as Q, RequestConfig as R, StandardResponse as S, Tokens as T, UseApiConfig as U, ValidationError as V, ApiModuleConfig as a, UseApiModuleOptions as b, UseApiModuleReturn as c, ApiClientConfig as d, ActionOptions as e, UseApiQuery as f, ApiError as g, TokenManager as h, Middleware as i, RefreshTokenConfig as j, ActionConfig as k, ActionStateModule as l, UseApiState as m, ActionState as n, ExecuteOptions as o, ModuleActions as p, ModuleStates as q };
@@ -228,6 +228,7 @@ interface ExecuteOptions<TInput, TOutput, TContext = unknown> {
228
228
  onMutate?: (variables: TInput) => TContext | Promise<TContext>;
229
229
  onSuccess?: (data: TOutput, context?: TContext) => void;
230
230
  onError?: (error: ApiError, context?: TContext) => void;
231
+ onSettled?: (data?: TOutput, error?: ApiError, context?: TContext) => void;
231
232
  }
232
233
  /** @description A fully-typed object representing the callable actions for a module. */
233
234
  type ModuleActions<TActions extends Record<string, ActionConfigModule<any, any>>> = {
@@ -254,4 +255,4 @@ interface UseApiModuleReturn<TActions extends Record<string, ActionConfigModule<
254
255
  dehydrate: () => string;
255
256
  }
256
257
 
257
- export type { ActionConfigModule as A, ExecutableAction as E, InputOf as I, LogLevel as L, MiddlewareContext as M, OutputOf as O, PaginationMeta as P, QueryOptions as Q, RequestConfig as R, StandardResponse as S, Tokens as T, UseApiConfig as U, ValidationError as V, ApiModuleConfig as a, UseApiModuleOptions as b, UseApiModuleReturn as c, ApiClientConfig as d, ActionOptions as e, ActionStateModule as f, UseApiQuery as g, ApiError as h, TokenManager as i, Middleware as j, RefreshTokenConfig as k, ActionConfig as l, UseApiState as m, ActionState as n, ExecuteOptions as o, ModuleActions as p, ModuleStates as q };
258
+ export type { ActionConfigModule as A, ExecutableAction as E, InputOf as I, LogLevel as L, MiddlewareContext as M, OutputOf as O, PaginationMeta as P, QueryOptions as Q, RequestConfig as R, StandardResponse as S, Tokens as T, UseApiConfig as U, ValidationError as V, ApiModuleConfig as a, UseApiModuleOptions as b, UseApiModuleReturn as c, ApiClientConfig as d, ActionOptions as e, UseApiQuery as f, ApiError as g, TokenManager as h, Middleware as i, RefreshTokenConfig as j, ActionConfig as k, ActionStateModule as l, UseApiState as m, ActionState as n, ExecuteOptions as o, ModuleActions as p, ModuleStates as q };
@@ -1,5 +1,5 @@
1
1
  import { Dispatch, SetStateAction } from 'react';
2
- import { R as RequestConfig, h as ApiError, S as StandardResponse, e as ActionOptions } from './apiModule.types-CpwGDEpG.cjs';
2
+ import { R as RequestConfig, g as ApiError, S as StandardResponse, e as ActionOptions, l as ActionStateModule } from './apiModule.types-Cvp9QdAc.js';
3
3
 
4
4
  /**
5
5
  * Represents the internal state of the `useApiRecord` hook.
@@ -87,4 +87,54 @@ interface UseApiRecordReturn<T> {
87
87
  setState: Dispatch<SetStateAction<UseApiRecordState<T>>>;
88
88
  }
89
89
 
90
- export type { UseApiRecordConfig as U, UseApiRecordReturn as a, UseApiRecordState as b, UseApiRecordActions as c };
90
+ declare class GlobalStateManager {
91
+ private store;
92
+ getSnapshot<T>(key: string): ActionStateModule<T>;
93
+ /**
94
+ * يسجل دالة callback للاستماع إلى التغييرات على مفتاح معين.
95
+ * @returns دالة لإلغاء الاشتراك.
96
+ */
97
+ subscribe(key: string, callback: () => void): () => void;
98
+ /**
99
+ * يحدّث الحالة لمفتاح معين ويقوم بإعلام جميع المشتركين.
100
+ */
101
+ setState<T>(key: string, updater: (prevState: ActionStateModule<T>) => ActionStateModule<T>): void;
102
+ /**
103
+ * يجعل البيانات المرتبطة بمفتاح معين "قديمة" (stale).
104
+ */
105
+ invalidate(key: string): void;
106
+ /**
107
+ * [نسخة محدثة وأكثر قوة]
108
+ * يجعل كل البيانات التي تبدأ بمفتاح معين "قديمة" (stale).
109
+ * @example invalidateByPrefix('myModule/list::') سيبطل كل صفحات القائمة.
110
+ */
111
+ invalidateByPrefix(prefix: string): void;
112
+ /**
113
+ * Serializes the current state of the query store into a JSON string.
114
+ * This is used on the server to pass the initial state to the client.
115
+ * @returns A JSON string representing the dehydrated state.
116
+ */
117
+ dehydrate(): string;
118
+ /**
119
+ * Merges a dehydrated state object into the current store.
120
+ * This is used on the client to hydrate the state received from the server.
121
+ * @param hydratedState - A JSON string from the `dehydrate` method.
122
+ */
123
+ rehydrate(hydratedState: string): void;
124
+ }
125
+ declare const globalStateManager: GlobalStateManager;
126
+
127
+ /**
128
+ * يقوم بإنشاء مفتاح تخزين مؤقت فريد وثابت لإجراء معين ومدخلاته.
129
+ * هذا يضمن أن نفس الطلب ينتج دائمًا نفس المفتاح.
130
+ * @param moduleName - عادةً ما يكون `baseEndpoint` للموديول.
131
+ * @param actionName - اسم الإجراء (مثل 'list', 'create').
132
+ * @param input - بيانات الطلب (body/query params).
133
+ * @param callOptions - خيارات إضافية مثل `pathParams`.
134
+ * @returns سلسلة نصية فريدة تمثل مفتاح التخزين المؤقت.
135
+ */
136
+ declare const generateCacheKey: (moduleName: string, actionName: string, input?: unknown, callOptions?: {
137
+ pathParams?: Record<string, any>;
138
+ }) => string;
139
+
140
+ export { type UseApiRecordConfig as U, type UseApiRecordReturn as a, generateCacheKey as b, type UseApiRecordState as c, type UseApiRecordActions as d, globalStateManager as g };
@@ -1,5 +1,5 @@
1
1
  import { Dispatch, SetStateAction } from 'react';
2
- import { R as RequestConfig, h as ApiError, S as StandardResponse, e as ActionOptions } from './apiModule.types-CpwGDEpG.js';
2
+ import { R as RequestConfig, g as ApiError, S as StandardResponse, e as ActionOptions, l as ActionStateModule } from './apiModule.types-Cvp9QdAc.cjs';
3
3
 
4
4
  /**
5
5
  * Represents the internal state of the `useApiRecord` hook.
@@ -87,4 +87,54 @@ interface UseApiRecordReturn<T> {
87
87
  setState: Dispatch<SetStateAction<UseApiRecordState<T>>>;
88
88
  }
89
89
 
90
- export type { UseApiRecordConfig as U, UseApiRecordReturn as a, UseApiRecordState as b, UseApiRecordActions as c };
90
+ declare class GlobalStateManager {
91
+ private store;
92
+ getSnapshot<T>(key: string): ActionStateModule<T>;
93
+ /**
94
+ * يسجل دالة callback للاستماع إلى التغييرات على مفتاح معين.
95
+ * @returns دالة لإلغاء الاشتراك.
96
+ */
97
+ subscribe(key: string, callback: () => void): () => void;
98
+ /**
99
+ * يحدّث الحالة لمفتاح معين ويقوم بإعلام جميع المشتركين.
100
+ */
101
+ setState<T>(key: string, updater: (prevState: ActionStateModule<T>) => ActionStateModule<T>): void;
102
+ /**
103
+ * يجعل البيانات المرتبطة بمفتاح معين "قديمة" (stale).
104
+ */
105
+ invalidate(key: string): void;
106
+ /**
107
+ * [نسخة محدثة وأكثر قوة]
108
+ * يجعل كل البيانات التي تبدأ بمفتاح معين "قديمة" (stale).
109
+ * @example invalidateByPrefix('myModule/list::') سيبطل كل صفحات القائمة.
110
+ */
111
+ invalidateByPrefix(prefix: string): void;
112
+ /**
113
+ * Serializes the current state of the query store into a JSON string.
114
+ * This is used on the server to pass the initial state to the client.
115
+ * @returns A JSON string representing the dehydrated state.
116
+ */
117
+ dehydrate(): string;
118
+ /**
119
+ * Merges a dehydrated state object into the current store.
120
+ * This is used on the client to hydrate the state received from the server.
121
+ * @param hydratedState - A JSON string from the `dehydrate` method.
122
+ */
123
+ rehydrate(hydratedState: string): void;
124
+ }
125
+ declare const globalStateManager: GlobalStateManager;
126
+
127
+ /**
128
+ * يقوم بإنشاء مفتاح تخزين مؤقت فريد وثابت لإجراء معين ومدخلاته.
129
+ * هذا يضمن أن نفس الطلب ينتج دائمًا نفس المفتاح.
130
+ * @param moduleName - عادةً ما يكون `baseEndpoint` للموديول.
131
+ * @param actionName - اسم الإجراء (مثل 'list', 'create').
132
+ * @param input - بيانات الطلب (body/query params).
133
+ * @param callOptions - خيارات إضافية مثل `pathParams`.
134
+ * @returns سلسلة نصية فريدة تمثل مفتاح التخزين المؤقت.
135
+ */
136
+ declare const generateCacheKey: (moduleName: string, actionName: string, input?: unknown, callOptions?: {
137
+ pathParams?: Record<string, any>;
138
+ }) => string;
139
+
140
+ export { type UseApiRecordConfig as U, type UseApiRecordReturn as a, generateCacheKey as b, type UseApiRecordState as c, type UseApiRecordActions as d, globalStateManager as g };
package/dist/client.cjs CHANGED
@@ -34,6 +34,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
34
34
  var client_exports = {};
35
35
  __export(client_exports, {
36
36
  ApiModuleProvider: () => ApiModuleProvider,
37
+ generateCacheKey: () => generateCacheKey,
38
+ globalStateManager: () => globalStateManager,
37
39
  useApi: () => useApi,
38
40
  useApiModule: () => useApiModule,
39
41
  useApiRecord: () => useApiRecord,
@@ -586,11 +588,13 @@ var GlobalStateManager = class {
586
588
  constructor() {
587
589
  __publicField(this, "store", /* @__PURE__ */ new Map());
588
590
  }
589
- /**
590
- * يحصل على لقطة (snapshot) للحالة الحالية لمفتاح معين.
591
- */
592
591
  getSnapshot(key) {
593
- return this.store.get(key)?.state ?? createInitialState();
592
+ if (!this.store.has(key)) {
593
+ const initialState = createInitialState();
594
+ this.store.set(key, { state: initialState, listeners: /* @__PURE__ */ new Set() });
595
+ return initialState;
596
+ }
597
+ return this.store.get(key).state;
594
598
  }
595
599
  /**
596
600
  * يسجل دالة callback للاستماع إلى التغييرات على مفتاح معين.
@@ -679,9 +683,14 @@ var globalStateManager = new GlobalStateManager();
679
683
  var ApiModuleContext = (0, import_react4.createContext)(null);
680
684
  var ApiModuleProvider = ApiModuleContext.Provider;
681
685
  function useApiActionState(actionConfig, cacheKey, actionExecutor, enabled) {
686
+ const getClientSnapshot = () => globalStateManager.getSnapshot(cacheKey);
687
+ const getServerSnapshot = () => globalStateManager.getSnapshot(cacheKey);
682
688
  const state = (0, import_react4.useSyncExternalStore)(
683
689
  (callback) => globalStateManager.subscribe(cacheKey, callback),
684
- () => globalStateManager.getSnapshot(cacheKey)
690
+ getClientSnapshot,
691
+ // لقطة العميل
692
+ getServerSnapshot
693
+ // لقطة الخادم
685
694
  );
686
695
  const input = actionConfig.hasQuery ? state.options : void 0;
687
696
  (0, import_react4.useEffect)(() => {
@@ -690,7 +699,7 @@ function useApiActionState(actionConfig, cacheKey, actionExecutor, enabled) {
690
699
  } else if (enabled && state.isStale && !state.loading) {
691
700
  actionExecutor(input);
692
701
  }
693
- }, [enabled, state.isStale, state.loading, state.called, actionConfig.autoFetch, actionExecutor, input]);
702
+ }, [enabled, state.isStale, state.loading, state.called, actionConfig.autoFetch, actionExecutor, JSON.stringify(input)]);
694
703
  return state;
695
704
  }
696
705
  function useModuleContext() {
@@ -700,14 +709,6 @@ function useModuleContext() {
700
709
  }
701
710
  return context;
702
711
  }
703
- var generateCacheKey = (moduleName, actionName, input, callOptions = {}) => {
704
- const params = { path: callOptions.pathParams, body: input };
705
- try {
706
- return `${moduleName}/${actionName}::${JSON.stringify(params)}`;
707
- } catch (error) {
708
- return `${moduleName}/${actionName}::${Date.now()}`;
709
- }
710
- };
711
712
  function useApiModule(axiosInstance, moduleConfig, options = {}) {
712
713
  const { refetchOnWindowFocus = true, onSuccess, onError, pathParams: modulePathParams, enabled = true, hydratedState } = options;
713
714
  const pathParamsString = (0, import_react4.useMemo)(() => JSON.stringify(modulePathParams || {}), [modulePathParams]);
@@ -758,6 +759,10 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
758
759
  savedCallbacks.current.onError?.(actionName, apiError.message, apiError);
759
760
  options2.onError?.(apiError, mutationContext);
760
761
  return errorResult;
762
+ } finally {
763
+ if (options2.onSettled) {
764
+ options2.onSettled();
765
+ }
761
766
  }
762
767
  };
763
768
  const reset = (input, options2 = {}) => {
@@ -858,9 +863,83 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
858
863
  }, []);
859
864
  return { actions, states, queries, dehydrate };
860
865
  }
866
+
867
+ // src/core/client.ts
868
+ var import_axios3 = __toESM(require("axios"), 1);
869
+ var import_uuid = require("uuid");
870
+
871
+ // src/core/cache.ts
872
+ var CacheManager = class {
873
+ constructor() {
874
+ __publicField(this, "cache", /* @__PURE__ */ new Map());
875
+ __publicField(this, "defaultDuration", 15 * 60 * 1e3);
876
+ }
877
+ // 15 minutes
878
+ set(key, data, duration) {
879
+ this.cache.set(key, {
880
+ data,
881
+ timestamp: Date.now(),
882
+ duration: duration || this.defaultDuration
883
+ });
884
+ }
885
+ get(key) {
886
+ const item = this.cache.get(key);
887
+ if (!item) return null;
888
+ const isExpired = Date.now() - item.timestamp > item.duration;
889
+ if (isExpired) {
890
+ this.cache.delete(key);
891
+ return null;
892
+ }
893
+ return item.data;
894
+ }
895
+ /**
896
+ * [FIX] تم تحويلها إلى دالة عامة (generic) لتعيد النوع الصحيح.
897
+ * الآن بدلًا من إرجاع CacheItem<unknown>، ستُرجع CacheItem<T>.
898
+ */
899
+ getWithMeta(key) {
900
+ const item = this.cache.get(key);
901
+ if (!item) return null;
902
+ const isExpired = Date.now() - item.timestamp > item.duration;
903
+ if (isExpired) {
904
+ this.cache.delete(key);
905
+ return null;
906
+ }
907
+ return item;
908
+ }
909
+ delete(key) {
910
+ this.cache.delete(key);
911
+ }
912
+ clear() {
913
+ this.cache.clear();
914
+ }
915
+ invalidateByPrefix(prefix) {
916
+ const keysToDelete = [];
917
+ for (const key of this.cache.keys()) {
918
+ if (key.startsWith(prefix)) {
919
+ keysToDelete.push(key);
920
+ }
921
+ }
922
+ keysToDelete.forEach((key) => this.cache.delete(key));
923
+ console.log(`Invalidated ${keysToDelete.length} cache entries with prefix: ${prefix}`);
924
+ }
925
+ };
926
+ var cacheManager = new CacheManager();
927
+
928
+ // src/core/cacheKey.ts
929
+ var generateCacheKey = (moduleName, actionName, input, callOptions = {}) => {
930
+ const params = { path: callOptions.pathParams, body: input };
931
+ try {
932
+ return `${moduleName}/${actionName}::${JSON.stringify(params)}`;
933
+ } catch (error) {
934
+ console.warn("Could not stringify cache key params, falling back to timestamp.", { moduleName, actionName, error });
935
+ return `${moduleName}/${actionName}::${Date.now()}`;
936
+ }
937
+ };
861
938
  // Annotate the CommonJS export names for ESM import in node:
862
939
  0 && (module.exports = {
863
940
  ApiModuleProvider,
941
+ generateCacheKey,
942
+ globalStateManager,
864
943
  useApi,
865
944
  useApiModule,
866
945
  useApiRecord,
package/dist/client.d.cts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { AxiosInstance } from 'axios';
2
- import { U as UseApiConfig, A as ActionConfigModule, a as ApiModuleConfig, b as UseApiModuleOptions, c as UseApiModuleReturn } from './apiModule.types-CpwGDEpG.cjs';
3
- import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-B45E0qux.cjs';
2
+ import { U as UseApiConfig, A as ActionConfigModule, a as ApiModuleConfig, b as UseApiModuleOptions, c as UseApiModuleReturn } from './apiModule.types-Cvp9QdAc.cjs';
3
+ import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './cacheKey-BNQ1ii6y.cjs';
4
+ export { b as generateCacheKey, g as globalStateManager } from './cacheKey-BNQ1ii6y.cjs';
4
5
  import * as React from 'react';
5
6
 
6
7
  declare function useApi<T>(axiosInstance: AxiosInstance, config: UseApiConfig<T>): any;
package/dist/client.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { AxiosInstance } from 'axios';
2
- import { U as UseApiConfig, A as ActionConfigModule, a as ApiModuleConfig, b as UseApiModuleOptions, c as UseApiModuleReturn } from './apiModule.types-CpwGDEpG.js';
3
- import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-DlrlXL1t.js';
2
+ import { U as UseApiConfig, A as ActionConfigModule, a as ApiModuleConfig, b as UseApiModuleOptions, c as UseApiModuleReturn } from './apiModule.types-Cvp9QdAc.js';
3
+ import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './cacheKey-BJQaehcQ.js';
4
+ export { b as generateCacheKey, g as globalStateManager } from './cacheKey-BJQaehcQ.js';
4
5
  import * as React from 'react';
5
6
 
6
7
  declare function useApi<T>(axiosInstance: AxiosInstance, config: UseApiConfig<T>): any;
package/dist/client.js CHANGED
@@ -547,11 +547,13 @@ var GlobalStateManager = class {
547
547
  constructor() {
548
548
  __publicField(this, "store", /* @__PURE__ */ new Map());
549
549
  }
550
- /**
551
- * يحصل على لقطة (snapshot) للحالة الحالية لمفتاح معين.
552
- */
553
550
  getSnapshot(key) {
554
- return this.store.get(key)?.state ?? createInitialState();
551
+ if (!this.store.has(key)) {
552
+ const initialState = createInitialState();
553
+ this.store.set(key, { state: initialState, listeners: /* @__PURE__ */ new Set() });
554
+ return initialState;
555
+ }
556
+ return this.store.get(key).state;
555
557
  }
556
558
  /**
557
559
  * يسجل دالة callback للاستماع إلى التغييرات على مفتاح معين.
@@ -640,9 +642,14 @@ var globalStateManager = new GlobalStateManager();
640
642
  var ApiModuleContext = createContext(null);
641
643
  var ApiModuleProvider = ApiModuleContext.Provider;
642
644
  function useApiActionState(actionConfig, cacheKey, actionExecutor, enabled) {
645
+ const getClientSnapshot = () => globalStateManager.getSnapshot(cacheKey);
646
+ const getServerSnapshot = () => globalStateManager.getSnapshot(cacheKey);
643
647
  const state = useSyncExternalStore(
644
648
  (callback) => globalStateManager.subscribe(cacheKey, callback),
645
- () => globalStateManager.getSnapshot(cacheKey)
649
+ getClientSnapshot,
650
+ // لقطة العميل
651
+ getServerSnapshot
652
+ // لقطة الخادم
646
653
  );
647
654
  const input = actionConfig.hasQuery ? state.options : void 0;
648
655
  useEffect4(() => {
@@ -651,7 +658,7 @@ function useApiActionState(actionConfig, cacheKey, actionExecutor, enabled) {
651
658
  } else if (enabled && state.isStale && !state.loading) {
652
659
  actionExecutor(input);
653
660
  }
654
- }, [enabled, state.isStale, state.loading, state.called, actionConfig.autoFetch, actionExecutor, input]);
661
+ }, [enabled, state.isStale, state.loading, state.called, actionConfig.autoFetch, actionExecutor, JSON.stringify(input)]);
655
662
  return state;
656
663
  }
657
664
  function useModuleContext() {
@@ -661,14 +668,6 @@ function useModuleContext() {
661
668
  }
662
669
  return context;
663
670
  }
664
- var generateCacheKey = (moduleName, actionName, input, callOptions = {}) => {
665
- const params = { path: callOptions.pathParams, body: input };
666
- try {
667
- return `${moduleName}/${actionName}::${JSON.stringify(params)}`;
668
- } catch (error) {
669
- return `${moduleName}/${actionName}::${Date.now()}`;
670
- }
671
- };
672
671
  function useApiModule(axiosInstance, moduleConfig, options = {}) {
673
672
  const { refetchOnWindowFocus = true, onSuccess, onError, pathParams: modulePathParams, enabled = true, hydratedState } = options;
674
673
  const pathParamsString = useMemo3(() => JSON.stringify(modulePathParams || {}), [modulePathParams]);
@@ -719,6 +718,10 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
719
718
  savedCallbacks.current.onError?.(actionName, apiError.message, apiError);
720
719
  options2.onError?.(apiError, mutationContext);
721
720
  return errorResult;
721
+ } finally {
722
+ if (options2.onSettled) {
723
+ options2.onSettled();
724
+ }
722
725
  }
723
726
  };
724
727
  const reset = (input, options2 = {}) => {
@@ -819,8 +822,82 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
819
822
  }, []);
820
823
  return { actions, states, queries, dehydrate };
821
824
  }
825
+
826
+ // src/core/client.ts
827
+ import axios3 from "axios";
828
+ import { v4 as uuidv4 } from "uuid";
829
+
830
+ // src/core/cache.ts
831
+ var CacheManager = class {
832
+ constructor() {
833
+ __publicField(this, "cache", /* @__PURE__ */ new Map());
834
+ __publicField(this, "defaultDuration", 15 * 60 * 1e3);
835
+ }
836
+ // 15 minutes
837
+ set(key, data, duration) {
838
+ this.cache.set(key, {
839
+ data,
840
+ timestamp: Date.now(),
841
+ duration: duration || this.defaultDuration
842
+ });
843
+ }
844
+ get(key) {
845
+ const item = this.cache.get(key);
846
+ if (!item) return null;
847
+ const isExpired = Date.now() - item.timestamp > item.duration;
848
+ if (isExpired) {
849
+ this.cache.delete(key);
850
+ return null;
851
+ }
852
+ return item.data;
853
+ }
854
+ /**
855
+ * [FIX] تم تحويلها إلى دالة عامة (generic) لتعيد النوع الصحيح.
856
+ * الآن بدلًا من إرجاع CacheItem<unknown>، ستُرجع CacheItem<T>.
857
+ */
858
+ getWithMeta(key) {
859
+ const item = this.cache.get(key);
860
+ if (!item) return null;
861
+ const isExpired = Date.now() - item.timestamp > item.duration;
862
+ if (isExpired) {
863
+ this.cache.delete(key);
864
+ return null;
865
+ }
866
+ return item;
867
+ }
868
+ delete(key) {
869
+ this.cache.delete(key);
870
+ }
871
+ clear() {
872
+ this.cache.clear();
873
+ }
874
+ invalidateByPrefix(prefix) {
875
+ const keysToDelete = [];
876
+ for (const key of this.cache.keys()) {
877
+ if (key.startsWith(prefix)) {
878
+ keysToDelete.push(key);
879
+ }
880
+ }
881
+ keysToDelete.forEach((key) => this.cache.delete(key));
882
+ console.log(`Invalidated ${keysToDelete.length} cache entries with prefix: ${prefix}`);
883
+ }
884
+ };
885
+ var cacheManager = new CacheManager();
886
+
887
+ // src/core/cacheKey.ts
888
+ var generateCacheKey = (moduleName, actionName, input, callOptions = {}) => {
889
+ const params = { path: callOptions.pathParams, body: input };
890
+ try {
891
+ return `${moduleName}/${actionName}::${JSON.stringify(params)}`;
892
+ } catch (error) {
893
+ console.warn("Could not stringify cache key params, falling back to timestamp.", { moduleName, actionName, error });
894
+ return `${moduleName}/${actionName}::${Date.now()}`;
895
+ }
896
+ };
822
897
  export {
823
898
  ApiModuleProvider,
899
+ generateCacheKey,
900
+ globalStateManager,
824
901
  useApi,
825
902
  useApiModule,
826
903
  useApiRecord,
package/dist/index.cjs CHANGED
@@ -38,6 +38,7 @@ __export(index_exports, {
38
38
  createApiActions: () => createApiActions,
39
39
  createApiClient: () => createApiClient,
40
40
  createApiServices: () => createApiServices,
41
+ generateCacheKey: () => generateCacheKey,
41
42
  globalStateManager: () => globalStateManager,
42
43
  processResponse: () => processResponse
43
44
  });
@@ -543,11 +544,13 @@ var GlobalStateManager = class {
543
544
  constructor() {
544
545
  __publicField(this, "store", /* @__PURE__ */ new Map());
545
546
  }
546
- /**
547
- * يحصل على لقطة (snapshot) للحالة الحالية لمفتاح معين.
548
- */
549
547
  getSnapshot(key) {
550
- return this.store.get(key)?.state ?? createInitialState();
548
+ if (!this.store.has(key)) {
549
+ const initialState = createInitialState();
550
+ this.store.set(key, { state: initialState, listeners: /* @__PURE__ */ new Set() });
551
+ return initialState;
552
+ }
553
+ return this.store.get(key).state;
551
554
  }
552
555
  /**
553
556
  * يسجل دالة callback للاستماع إلى التغييرات على مفتاح معين.
@@ -688,6 +691,17 @@ var CacheManager = class {
688
691
  }
689
692
  };
690
693
  var cacheManager = new CacheManager();
694
+
695
+ // src/core/cacheKey.ts
696
+ var generateCacheKey = (moduleName, actionName, input, callOptions = {}) => {
697
+ const params = { path: callOptions.pathParams, body: input };
698
+ try {
699
+ return `${moduleName}/${actionName}::${JSON.stringify(params)}`;
700
+ } catch (error) {
701
+ console.warn("Could not stringify cache key params, falling back to timestamp.", { moduleName, actionName, error });
702
+ return `${moduleName}/${actionName}::${Date.now()}`;
703
+ }
704
+ };
691
705
  // Annotate the CommonJS export names for ESM import in node:
692
706
  0 && (module.exports = {
693
707
  buildPaginateQuery,
@@ -696,6 +710,7 @@ var cacheManager = new CacheManager();
696
710
  createApiActions,
697
711
  createApiClient,
698
712
  createApiServices,
713
+ generateCacheKey,
699
714
  globalStateManager,
700
715
  processResponse
701
716
  });
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AxiosInstance, AxiosRequestConfig, Method, AxiosResponse, AxiosError } from 'axios';
2
- import { d as ApiClientConfig, A as ActionConfigModule, S as StandardResponse, e as ActionOptions, R as RequestConfig, f as ActionStateModule, Q as QueryOptions, g as UseApiQuery, h as ApiError, L as LogLevel } from './apiModule.types-CpwGDEpG.cjs';
3
- export { l as ActionConfig, n as ActionState, a as ApiModuleConfig, E as ExecutableAction, o as ExecuteOptions, I as InputOf, j as Middleware, M as MiddlewareContext, p as ModuleActions, q as ModuleStates, O as OutputOf, P as PaginationMeta, k as RefreshTokenConfig, i as TokenManager, T as Tokens, U as UseApiConfig, b as UseApiModuleOptions, c as UseApiModuleReturn, m as UseApiState, V as ValidationError } from './apiModule.types-CpwGDEpG.cjs';
4
- export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-B45E0qux.cjs';
2
+ import { d as ApiClientConfig, A as ActionConfigModule, S as StandardResponse, e as ActionOptions, R as RequestConfig, Q as QueryOptions, f as UseApiQuery, g as ApiError, L as LogLevel } from './apiModule.types-Cvp9QdAc.cjs';
3
+ export { k as ActionConfig, n as ActionState, l as ActionStateModule, a as ApiModuleConfig, E as ExecutableAction, o as ExecuteOptions, I as InputOf, i as Middleware, M as MiddlewareContext, p as ModuleActions, q as ModuleStates, O as OutputOf, P as PaginationMeta, j as RefreshTokenConfig, h as TokenManager, T as Tokens, U as UseApiConfig, b as UseApiModuleOptions, c as UseApiModuleReturn, m as UseApiState, V as ValidationError } from './apiModule.types-Cvp9QdAc.cjs';
4
+ export { d as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, c as UseApiRecordState, b as generateCacheKey, g as globalStateManager } from './cacheKey-BNQ1ii6y.cjs';
5
5
  import 'react';
6
6
 
7
7
  declare function createApiClient(config: ApiClientConfig): AxiosInstance;
@@ -72,46 +72,6 @@ declare function createApiActions<TActions extends Record<string, {
72
72
  [K in keyof TActions]: ApiAction<TActions[K]['requestType'], TActions[K]['responseType']>;
73
73
  };
74
74
 
75
- declare class GlobalStateManager {
76
- private store;
77
- /**
78
- * يحصل على لقطة (snapshot) للحالة الحالية لمفتاح معين.
79
- */
80
- getSnapshot<T>(key: string): ActionStateModule<T>;
81
- /**
82
- * يسجل دالة callback للاستماع إلى التغييرات على مفتاح معين.
83
- * @returns دالة لإلغاء الاشتراك.
84
- */
85
- subscribe(key: string, callback: () => void): () => void;
86
- /**
87
- * يحدّث الحالة لمفتاح معين ويقوم بإعلام جميع المشتركين.
88
- */
89
- setState<T>(key: string, updater: (prevState: ActionStateModule<T>) => ActionStateModule<T>): void;
90
- /**
91
- * يجعل البيانات المرتبطة بمفتاح معين "قديمة" (stale).
92
- */
93
- invalidate(key: string): void;
94
- /**
95
- * [نسخة محدثة وأكثر قوة]
96
- * يجعل كل البيانات التي تبدأ بمفتاح معين "قديمة" (stale).
97
- * @example invalidateByPrefix('myModule/list::') سيبطل كل صفحات القائمة.
98
- */
99
- invalidateByPrefix(prefix: string): void;
100
- /**
101
- * Serializes the current state of the query store into a JSON string.
102
- * This is used on the server to pass the initial state to the client.
103
- * @returns A JSON string representing the dehydrated state.
104
- */
105
- dehydrate(): string;
106
- /**
107
- * Merges a dehydrated state object into the current store.
108
- * This is used on the client to hydrate the state received from the server.
109
- * @param hydratedState - A JSON string from the `dehydrate` method.
110
- */
111
- rehydrate(hydratedState: string): void;
112
- }
113
- declare const globalStateManager: GlobalStateManager;
114
-
115
75
  /**
116
76
  * [نسخة مطورة] يبني سلسلة استعلام (query string) من كائن الخيارات.
117
77
  * يدعم الآن الفلاتر المتداخلة (filter[key]=value) والترتيب المتعدد.
@@ -228,4 +188,4 @@ interface UseApiResourceReturn<T, TCreate, TUpdate, TPathParams> {
228
188
  setQuery: React.Dispatch<React.SetStateAction<QueryOptions>>;
229
189
  }
230
190
 
231
- export { ActionConfigModule, ActionOptions, ActionStateModule, ApiClientConfig, ApiError, type ApiResourceStatus, LogLevel, QueryOptions, RequestConfig, StandardResponse, type UseApiActions, UseApiQuery, type UseApiResourceActions, type UseApiResourceConfig, type UseApiResourceReturn, type UseApiResourceState, type UseApiReturn, buildPaginateQuery, cacheManager, callDynamicApi, createApiActions, createApiClient, createApiServices, globalStateManager, processResponse };
191
+ export { ActionConfigModule, ActionOptions, ApiClientConfig, ApiError, type ApiResourceStatus, LogLevel, QueryOptions, RequestConfig, StandardResponse, type UseApiActions, UseApiQuery, type UseApiResourceActions, type UseApiResourceConfig, type UseApiResourceReturn, type UseApiResourceState, type UseApiReturn, buildPaginateQuery, cacheManager, callDynamicApi, createApiActions, createApiClient, createApiServices, processResponse };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AxiosInstance, AxiosRequestConfig, Method, AxiosResponse, AxiosError } from 'axios';
2
- import { d as ApiClientConfig, A as ActionConfigModule, S as StandardResponse, e as ActionOptions, R as RequestConfig, f as ActionStateModule, Q as QueryOptions, g as UseApiQuery, h as ApiError, L as LogLevel } from './apiModule.types-CpwGDEpG.js';
3
- export { l as ActionConfig, n as ActionState, a as ApiModuleConfig, E as ExecutableAction, o as ExecuteOptions, I as InputOf, j as Middleware, M as MiddlewareContext, p as ModuleActions, q as ModuleStates, O as OutputOf, P as PaginationMeta, k as RefreshTokenConfig, i as TokenManager, T as Tokens, U as UseApiConfig, b as UseApiModuleOptions, c as UseApiModuleReturn, m as UseApiState, V as ValidationError } from './apiModule.types-CpwGDEpG.js';
4
- export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-DlrlXL1t.js';
2
+ import { d as ApiClientConfig, A as ActionConfigModule, S as StandardResponse, e as ActionOptions, R as RequestConfig, Q as QueryOptions, f as UseApiQuery, g as ApiError, L as LogLevel } from './apiModule.types-Cvp9QdAc.js';
3
+ export { k as ActionConfig, n as ActionState, l as ActionStateModule, a as ApiModuleConfig, E as ExecutableAction, o as ExecuteOptions, I as InputOf, i as Middleware, M as MiddlewareContext, p as ModuleActions, q as ModuleStates, O as OutputOf, P as PaginationMeta, j as RefreshTokenConfig, h as TokenManager, T as Tokens, U as UseApiConfig, b as UseApiModuleOptions, c as UseApiModuleReturn, m as UseApiState, V as ValidationError } from './apiModule.types-Cvp9QdAc.js';
4
+ export { d as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, c as UseApiRecordState, b as generateCacheKey, g as globalStateManager } from './cacheKey-BJQaehcQ.js';
5
5
  import 'react';
6
6
 
7
7
  declare function createApiClient(config: ApiClientConfig): AxiosInstance;
@@ -72,46 +72,6 @@ declare function createApiActions<TActions extends Record<string, {
72
72
  [K in keyof TActions]: ApiAction<TActions[K]['requestType'], TActions[K]['responseType']>;
73
73
  };
74
74
 
75
- declare class GlobalStateManager {
76
- private store;
77
- /**
78
- * يحصل على لقطة (snapshot) للحالة الحالية لمفتاح معين.
79
- */
80
- getSnapshot<T>(key: string): ActionStateModule<T>;
81
- /**
82
- * يسجل دالة callback للاستماع إلى التغييرات على مفتاح معين.
83
- * @returns دالة لإلغاء الاشتراك.
84
- */
85
- subscribe(key: string, callback: () => void): () => void;
86
- /**
87
- * يحدّث الحالة لمفتاح معين ويقوم بإعلام جميع المشتركين.
88
- */
89
- setState<T>(key: string, updater: (prevState: ActionStateModule<T>) => ActionStateModule<T>): void;
90
- /**
91
- * يجعل البيانات المرتبطة بمفتاح معين "قديمة" (stale).
92
- */
93
- invalidate(key: string): void;
94
- /**
95
- * [نسخة محدثة وأكثر قوة]
96
- * يجعل كل البيانات التي تبدأ بمفتاح معين "قديمة" (stale).
97
- * @example invalidateByPrefix('myModule/list::') سيبطل كل صفحات القائمة.
98
- */
99
- invalidateByPrefix(prefix: string): void;
100
- /**
101
- * Serializes the current state of the query store into a JSON string.
102
- * This is used on the server to pass the initial state to the client.
103
- * @returns A JSON string representing the dehydrated state.
104
- */
105
- dehydrate(): string;
106
- /**
107
- * Merges a dehydrated state object into the current store.
108
- * This is used on the client to hydrate the state received from the server.
109
- * @param hydratedState - A JSON string from the `dehydrate` method.
110
- */
111
- rehydrate(hydratedState: string): void;
112
- }
113
- declare const globalStateManager: GlobalStateManager;
114
-
115
75
  /**
116
76
  * [نسخة مطورة] يبني سلسلة استعلام (query string) من كائن الخيارات.
117
77
  * يدعم الآن الفلاتر المتداخلة (filter[key]=value) والترتيب المتعدد.
@@ -228,4 +188,4 @@ interface UseApiResourceReturn<T, TCreate, TUpdate, TPathParams> {
228
188
  setQuery: React.Dispatch<React.SetStateAction<QueryOptions>>;
229
189
  }
230
190
 
231
- export { ActionConfigModule, ActionOptions, ActionStateModule, ApiClientConfig, ApiError, type ApiResourceStatus, LogLevel, QueryOptions, RequestConfig, StandardResponse, type UseApiActions, UseApiQuery, type UseApiResourceActions, type UseApiResourceConfig, type UseApiResourceReturn, type UseApiResourceState, type UseApiReturn, buildPaginateQuery, cacheManager, callDynamicApi, createApiActions, createApiClient, createApiServices, globalStateManager, processResponse };
191
+ export { ActionConfigModule, ActionOptions, ApiClientConfig, ApiError, type ApiResourceStatus, LogLevel, QueryOptions, RequestConfig, StandardResponse, type UseApiActions, UseApiQuery, type UseApiResourceActions, type UseApiResourceConfig, type UseApiResourceReturn, type UseApiResourceState, type UseApiReturn, buildPaginateQuery, cacheManager, callDynamicApi, createApiActions, createApiClient, createApiServices, processResponse };
package/dist/index.js CHANGED
@@ -502,11 +502,13 @@ var GlobalStateManager = class {
502
502
  constructor() {
503
503
  __publicField(this, "store", /* @__PURE__ */ new Map());
504
504
  }
505
- /**
506
- * يحصل على لقطة (snapshot) للحالة الحالية لمفتاح معين.
507
- */
508
505
  getSnapshot(key) {
509
- return this.store.get(key)?.state ?? createInitialState();
506
+ if (!this.store.has(key)) {
507
+ const initialState = createInitialState();
508
+ this.store.set(key, { state: initialState, listeners: /* @__PURE__ */ new Set() });
509
+ return initialState;
510
+ }
511
+ return this.store.get(key).state;
510
512
  }
511
513
  /**
512
514
  * يسجل دالة callback للاستماع إلى التغييرات على مفتاح معين.
@@ -647,6 +649,17 @@ var CacheManager = class {
647
649
  }
648
650
  };
649
651
  var cacheManager = new CacheManager();
652
+
653
+ // src/core/cacheKey.ts
654
+ var generateCacheKey = (moduleName, actionName, input, callOptions = {}) => {
655
+ const params = { path: callOptions.pathParams, body: input };
656
+ try {
657
+ return `${moduleName}/${actionName}::${JSON.stringify(params)}`;
658
+ } catch (error) {
659
+ console.warn("Could not stringify cache key params, falling back to timestamp.", { moduleName, actionName, error });
660
+ return `${moduleName}/${actionName}::${Date.now()}`;
661
+ }
662
+ };
650
663
  export {
651
664
  buildPaginateQuery,
652
665
  cacheManager,
@@ -654,6 +667,7 @@ export {
654
667
  createApiActions,
655
668
  createApiClient,
656
669
  createApiServices,
670
+ generateCacheKey,
657
671
  globalStateManager,
658
672
  processResponse
659
673
  };
package/dist/server.cjs CHANGED
@@ -195,11 +195,13 @@ var GlobalStateManager = class {
195
195
  constructor() {
196
196
  __publicField(this, "store", /* @__PURE__ */ new Map());
197
197
  }
198
- /**
199
- * يحصل على لقطة (snapshot) للحالة الحالية لمفتاح معين.
200
- */
201
198
  getSnapshot(key) {
202
- return this.store.get(key)?.state ?? createInitialState();
199
+ if (!this.store.has(key)) {
200
+ const initialState = createInitialState();
201
+ this.store.set(key, { state: initialState, listeners: /* @__PURE__ */ new Set() });
202
+ return initialState;
203
+ }
204
+ return this.store.get(key).state;
203
205
  }
204
206
  /**
205
207
  * يسجل دالة callback للاستماع إلى التغييرات على مفتاح معين.
@@ -284,15 +286,94 @@ var GlobalStateManager = class {
284
286
  };
285
287
  var globalStateManager = new GlobalStateManager();
286
288
 
287
- // src/server.ts
289
+ // src/hooks/useApi.ts
290
+ var import_react = require("react");
291
+
292
+ // src/hooks/useApiRecord/index.ts
293
+ var import_react2 = require("react");
294
+
295
+ // src/hooks/useDeepCompareEffect/index.ts
296
+ var import_react3 = require("react");
297
+ var import_fast_deep_equal = __toESM(require("fast-deep-equal"), 1);
298
+
299
+ // src/hooks/useApiModule/useApiModule.ts
300
+ var import_react4 = require("react");
301
+ var ApiModuleContext = (0, import_react4.createContext)(null);
302
+ var ApiModuleProvider = ApiModuleContext.Provider;
303
+
304
+ // src/core/client.ts
305
+ var import_axios3 = __toESM(require("axios"), 1);
306
+ var import_uuid = require("uuid");
307
+
308
+ // src/core/cache.ts
309
+ var CacheManager = class {
310
+ constructor() {
311
+ __publicField(this, "cache", /* @__PURE__ */ new Map());
312
+ __publicField(this, "defaultDuration", 15 * 60 * 1e3);
313
+ }
314
+ // 15 minutes
315
+ set(key, data, duration) {
316
+ this.cache.set(key, {
317
+ data,
318
+ timestamp: Date.now(),
319
+ duration: duration || this.defaultDuration
320
+ });
321
+ }
322
+ get(key) {
323
+ const item = this.cache.get(key);
324
+ if (!item) return null;
325
+ const isExpired = Date.now() - item.timestamp > item.duration;
326
+ if (isExpired) {
327
+ this.cache.delete(key);
328
+ return null;
329
+ }
330
+ return item.data;
331
+ }
332
+ /**
333
+ * [FIX] تم تحويلها إلى دالة عامة (generic) لتعيد النوع الصحيح.
334
+ * الآن بدلًا من إرجاع CacheItem<unknown>، ستُرجع CacheItem<T>.
335
+ */
336
+ getWithMeta(key) {
337
+ const item = this.cache.get(key);
338
+ if (!item) return null;
339
+ const isExpired = Date.now() - item.timestamp > item.duration;
340
+ if (isExpired) {
341
+ this.cache.delete(key);
342
+ return null;
343
+ }
344
+ return item;
345
+ }
346
+ delete(key) {
347
+ this.cache.delete(key);
348
+ }
349
+ clear() {
350
+ this.cache.clear();
351
+ }
352
+ invalidateByPrefix(prefix) {
353
+ const keysToDelete = [];
354
+ for (const key of this.cache.keys()) {
355
+ if (key.startsWith(prefix)) {
356
+ keysToDelete.push(key);
357
+ }
358
+ }
359
+ keysToDelete.forEach((key) => this.cache.delete(key));
360
+ console.log(`Invalidated ${keysToDelete.length} cache entries with prefix: ${prefix}`);
361
+ }
362
+ };
363
+ var cacheManager = new CacheManager();
364
+
365
+ // src/core/cacheKey.ts
288
366
  var generateCacheKey = (moduleName, actionName, input, callOptions = {}) => {
289
367
  const params = { path: callOptions.pathParams, body: input };
290
368
  try {
291
369
  return `${moduleName}/${actionName}::${JSON.stringify(params)}`;
292
370
  } catch (error) {
371
+ console.warn("Could not stringify cache key params, falling back to timestamp.", { moduleName, actionName, error });
293
372
  return `${moduleName}/${actionName}::${Date.now()}`;
294
373
  }
295
374
  };
375
+
376
+ // src/server.ts
296
377
  function createServerApi(apiClient, moduleConfig) {
297
378
  return {
298
379
  /**
package/dist/server.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AxiosInstance } from 'axios';
2
- import { A as ActionConfigModule, a as ApiModuleConfig, I as InputOf } from './apiModule.types-CpwGDEpG.cjs';
2
+ import { A as ActionConfigModule, a as ApiModuleConfig, I as InputOf } from './apiModule.types-Cvp9QdAc.cjs';
3
3
  import 'react';
4
4
 
5
5
  /**
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AxiosInstance } from 'axios';
2
- import { A as ActionConfigModule, a as ApiModuleConfig, I as InputOf } from './apiModule.types-CpwGDEpG.js';
2
+ import { A as ActionConfigModule, a as ApiModuleConfig, I as InputOf } from './apiModule.types-Cvp9QdAc.js';
3
3
  import 'react';
4
4
 
5
5
  /**
package/dist/server.js CHANGED
@@ -161,11 +161,13 @@ var GlobalStateManager = class {
161
161
  constructor() {
162
162
  __publicField(this, "store", /* @__PURE__ */ new Map());
163
163
  }
164
- /**
165
- * يحصل على لقطة (snapshot) للحالة الحالية لمفتاح معين.
166
- */
167
164
  getSnapshot(key) {
168
- return this.store.get(key)?.state ?? createInitialState();
165
+ if (!this.store.has(key)) {
166
+ const initialState = createInitialState();
167
+ this.store.set(key, { state: initialState, listeners: /* @__PURE__ */ new Set() });
168
+ return initialState;
169
+ }
170
+ return this.store.get(key).state;
169
171
  }
170
172
  /**
171
173
  * يسجل دالة callback للاستماع إلى التغييرات على مفتاح معين.
@@ -250,15 +252,94 @@ var GlobalStateManager = class {
250
252
  };
251
253
  var globalStateManager = new GlobalStateManager();
252
254
 
253
- // src/server.ts
255
+ // src/hooks/useApi.ts
256
+ import { useState, useEffect, useCallback, useRef, useMemo } from "react";
257
+
258
+ // src/hooks/useApiRecord/index.ts
259
+ import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2, useRef as useRef2, useMemo as useMemo2 } from "react";
260
+
261
+ // src/hooks/useDeepCompareEffect/index.ts
262
+ import { useEffect as useEffect3, useRef as useRef3 } from "react";
263
+ import isEqual from "fast-deep-equal";
264
+
265
+ // src/hooks/useApiModule/useApiModule.ts
266
+ import { createContext, useContext, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef4, useState as useState3, useSyncExternalStore } from "react";
267
+ var ApiModuleContext = createContext(null);
268
+ var ApiModuleProvider = ApiModuleContext.Provider;
269
+
270
+ // src/core/client.ts
271
+ import axios3 from "axios";
272
+ import { v4 as uuidv4 } from "uuid";
273
+
274
+ // src/core/cache.ts
275
+ var CacheManager = class {
276
+ constructor() {
277
+ __publicField(this, "cache", /* @__PURE__ */ new Map());
278
+ __publicField(this, "defaultDuration", 15 * 60 * 1e3);
279
+ }
280
+ // 15 minutes
281
+ set(key, data, duration) {
282
+ this.cache.set(key, {
283
+ data,
284
+ timestamp: Date.now(),
285
+ duration: duration || this.defaultDuration
286
+ });
287
+ }
288
+ get(key) {
289
+ const item = this.cache.get(key);
290
+ if (!item) return null;
291
+ const isExpired = Date.now() - item.timestamp > item.duration;
292
+ if (isExpired) {
293
+ this.cache.delete(key);
294
+ return null;
295
+ }
296
+ return item.data;
297
+ }
298
+ /**
299
+ * [FIX] تم تحويلها إلى دالة عامة (generic) لتعيد النوع الصحيح.
300
+ * الآن بدلًا من إرجاع CacheItem<unknown>، ستُرجع CacheItem<T>.
301
+ */
302
+ getWithMeta(key) {
303
+ const item = this.cache.get(key);
304
+ if (!item) return null;
305
+ const isExpired = Date.now() - item.timestamp > item.duration;
306
+ if (isExpired) {
307
+ this.cache.delete(key);
308
+ return null;
309
+ }
310
+ return item;
311
+ }
312
+ delete(key) {
313
+ this.cache.delete(key);
314
+ }
315
+ clear() {
316
+ this.cache.clear();
317
+ }
318
+ invalidateByPrefix(prefix) {
319
+ const keysToDelete = [];
320
+ for (const key of this.cache.keys()) {
321
+ if (key.startsWith(prefix)) {
322
+ keysToDelete.push(key);
323
+ }
324
+ }
325
+ keysToDelete.forEach((key) => this.cache.delete(key));
326
+ console.log(`Invalidated ${keysToDelete.length} cache entries with prefix: ${prefix}`);
327
+ }
328
+ };
329
+ var cacheManager = new CacheManager();
330
+
331
+ // src/core/cacheKey.ts
254
332
  var generateCacheKey = (moduleName, actionName, input, callOptions = {}) => {
255
333
  const params = { path: callOptions.pathParams, body: input };
256
334
  try {
257
335
  return `${moduleName}/${actionName}::${JSON.stringify(params)}`;
258
336
  } catch (error) {
337
+ console.warn("Could not stringify cache key params, falling back to timestamp.", { moduleName, actionName, error });
259
338
  return `${moduleName}/${actionName}::${Date.now()}`;
260
339
  }
261
340
  };
341
+
342
+ // src/server.ts
262
343
  function createServerApi(apiClient, moduleConfig) {
263
344
  return {
264
345
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-core-lib",
3
- "version": "12.0.12",
3
+ "version": "12.0.14",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "type": "module",
6
6