api-core-lib 16.12.134 → 16.12.136

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.
@@ -196,10 +196,12 @@ interface t {
196
196
  payload?: any;
197
197
  }
198
198
 
199
+ /** @description Extends the base ActionState with an `isStale` flag for automatic refetching. */
199
200
  interface ActionState<TOutput> extends ActionStateModule<TOutput> {
200
201
  isStale?: boolean;
201
202
  }
202
- interface ActionConfigModule<TInput extends Record<string, any> | undefined = undefined, TOutput = unknown> {
203
+ /** @description Defines the configuration for a single API action within a module. */
204
+ interface ActionConfigModule<TInput = unknown, TOutput = unknown> {
203
205
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
204
206
  path: string;
205
207
  description?: string;
@@ -213,17 +215,17 @@ interface ActionConfigModule<TInput extends Record<string, any> | undefined = un
213
215
  _input?: TInput;
214
216
  _output?: TOutput;
215
217
  }
218
+ /** @description Defines the complete structure of an API module. */
219
+ /**
220
+ * يصف إعدادات موديول API كامل.
221
+ * @template TActions كائن يصف جميع الإجراءات المتاحة في الموديول.
222
+ */
216
223
  interface ApiModuleConfig<TActions extends Record<string, ActionConfigModule<any, any>>> {
217
224
  baseEndpoint: string;
218
225
  actions: TActions;
219
226
  }
220
- interface UrlSyncOptions<TModule extends ApiModuleConfig<any>> {
221
- searchParams: string;
222
- updateUrl: (newSearchParams: string) => void;
223
- actionsToSync: (keyof TModule['actions'])[];
224
- defaultSyncAction?: keyof TModule['actions'];
225
- }
226
- interface UseApiModuleOptions<TModule extends ApiModuleConfig<any>, TExtra = {}> {
227
+ /** @description Configuration options passed directly to the `useApiModule` hook. */
228
+ interface UseApiModuleOptions<TExtra = {}> {
227
229
  onSuccess?: (actionName: string, message: string, data: unknown) => void;
228
230
  onError?: (actionName: string, message: string, error?: ApiError | null) => void;
229
231
  refetchOnWindowFocus?: boolean;
@@ -231,12 +233,12 @@ interface UseApiModuleOptions<TModule extends ApiModuleConfig<any>, TExtra = {}>
231
233
  enabled?: boolean;
232
234
  hydratedState?: string;
233
235
  extraContextData?: TExtra;
234
- urlSync?: UrlSyncOptions<TModule>;
235
- defaultQueryOptions?: Partial<Record<keyof TModule['actions'], QueryOptions>>;
236
- initialActionsToExecute?: (keyof TModule['actions'])[];
237
236
  }
237
+ /** A utility type to infer the Input type (`TInput`) from an ActionConfigModule. */
238
238
  type InputOf<TActionConfig> = TActionConfig extends ActionConfigModule<infer TInput, any> ? TInput : never;
239
+ /** A utility type to infer the Output type (`TOutput`) from an ActionConfigModule. */
239
240
  type OutputOf<TActionConfig> = TActionConfig extends ActionConfigModule<any, infer TOutput> ? TOutput : never;
241
+ /** @description Defines the options for the `execute` function, enabling optimistic updates. */
240
242
  interface ExecuteOptions<TInput, TOutput, TContext = unknown> {
241
243
  pathParams?: Record<string, any>;
242
244
  config?: AxiosRequestConfig;
@@ -245,6 +247,7 @@ interface ExecuteOptions<TInput, TOutput, TContext = unknown> {
245
247
  onError?: (error: ApiError, context?: TContext) => void;
246
248
  onSettled?: (data?: TOutput, error?: ApiError, context?: TContext) => void;
247
249
  }
250
+ /** @description A fully-typed object representing the callable actions for a module. */
248
251
  type ModuleActions<TActions extends Record<string, ActionConfigModule<any, any>>> = {
249
252
  [K in keyof TActions]: {
250
253
  execute: <TContext = unknown>(input?: InputOf<TActions[K]>, options?: ExecuteOptions<InputOf<TActions[K]>, OutputOf<TActions[K]>, TContext>) => Promise<StandardResponse<OutputOf<TActions[K]>>>;
@@ -253,26 +256,44 @@ type ModuleActions<TActions extends Record<string, ActionConfigModule<any, any>>
253
256
  }) => void;
254
257
  };
255
258
  };
259
+ /** @description A fully-typed object representing the reactive states for each action in a module. */
256
260
  type ModuleStates<TActions extends Record<string, ActionConfigModule<any, any>>> = {
257
261
  [K in keyof TActions]: ActionState<OutputOf<TActions[K]>>;
258
262
  };
259
263
  type ActionsWithQuery<TActions extends Record<string, ActionConfigModule<any, any>>> = {
260
264
  [K in keyof TActions]: TActions[K] extends ActionConfigModule<QueryOptions, any> ? K : never;
261
265
  }[keyof TActions];
266
+ /**
267
+ * يُنشئ نوعًا لكائن `queries` يحتوي فقط على الإجراءات التي تقبل الكويري.
268
+ */
262
269
  type ModuleQueries<TActions extends Record<string, ActionConfigModule<any, any>>> = {
263
270
  [K in ActionsWithQuery<TActions>]: UseApiQuery;
264
271
  };
272
+ /**
273
+ * @description The complete, fully-typed return object of the `useApiModule` hook.
274
+ */
265
275
  type UseApiModuleReturn<TActions extends Record<string, ActionConfigModule<any, any>>, TExtra extends object = {}> = {
266
276
  states: ModuleStates<TActions>;
267
277
  actions: ModuleActions<TActions>;
268
278
  queries: ModuleQueries<TActions>;
269
279
  dehydrate: () => string;
270
280
  } & TExtra;
281
+ /**
282
+ * يصف دوال `execute` و `reset` لإجراء واحد.
283
+ * هذا النوع عام (generic) ليتناسب مع أنواع الإدخال والإخراج المختلفة لكل إجراء.
284
+ * @template TAction يمثل إعدادات الإجراء الواحد.
285
+ */
271
286
  type ActionMethods<TAction extends ActionConfigModule<any, any>> = {
287
+ /**
288
+ * الدالة الأساسية لتنفيذ طلب ה-API.
289
+ */
272
290
  execute: <TContext = unknown>(input?: InputOf<TAction>, options?: ExecuteOptions<InputOf<TAction>, OutputOf<TAction>, TContext>) => Promise<StandardResponse<OutputOf<TAction>>>;
291
+ /**
292
+ * دالة لإعادة تعيين حالة إجراء معين في ذاكرة التخزين المؤقت إلى حالته الأولية.
293
+ */
273
294
  reset: (input?: InputOf<TAction>, options?: {
274
295
  pathParams?: Record<string, any>;
275
296
  }) => void;
276
297
  };
277
298
 
278
- export type { ApiModuleConfig as A, ExecutableAction as E, InputOf as I, LogLevel as L, ModuleStates 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, UseApiModuleOptions as a, UseApiModuleReturn as b, ModuleActions as c, ModuleQueries as d, ApiClientConfig as e, ActionConfigModule as f, ActionOptions as g, ActionStateModule as h, UseApiQuery as i, ApiError as j, TokenManager as k, MiddlewareContext as l, Middleware as m, RefreshTokenConfig as n, ActionConfig as o, UseApiState as p, ActionState as q, UrlSyncOptions as r, ExecuteOptions as s, t, ActionsWithQuery as u, ActionMethods as v };
299
+ export type { ActionConfigModule as A, ExecutableAction as E, InputOf as I, LogLevel as L, ModuleStates 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, ModuleActions as d, ModuleQueries as e, ApiClientConfig as f, ActionOptions as g, ActionStateModule as h, UseApiQuery as i, ApiError as j, TokenManager as k, MiddlewareContext as l, Middleware as m, RefreshTokenConfig as n, ActionConfig as o, UseApiState as p, ActionState as q, ExecuteOptions as r, ActionsWithQuery as s, t, ActionMethods as u };
@@ -196,10 +196,12 @@ interface t {
196
196
  payload?: any;
197
197
  }
198
198
 
199
+ /** @description Extends the base ActionState with an `isStale` flag for automatic refetching. */
199
200
  interface ActionState<TOutput> extends ActionStateModule<TOutput> {
200
201
  isStale?: boolean;
201
202
  }
202
- interface ActionConfigModule<TInput extends Record<string, any> | undefined = undefined, TOutput = unknown> {
203
+ /** @description Defines the configuration for a single API action within a module. */
204
+ interface ActionConfigModule<TInput = unknown, TOutput = unknown> {
203
205
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
204
206
  path: string;
205
207
  description?: string;
@@ -213,17 +215,17 @@ interface ActionConfigModule<TInput extends Record<string, any> | undefined = un
213
215
  _input?: TInput;
214
216
  _output?: TOutput;
215
217
  }
218
+ /** @description Defines the complete structure of an API module. */
219
+ /**
220
+ * يصف إعدادات موديول API كامل.
221
+ * @template TActions كائن يصف جميع الإجراءات المتاحة في الموديول.
222
+ */
216
223
  interface ApiModuleConfig<TActions extends Record<string, ActionConfigModule<any, any>>> {
217
224
  baseEndpoint: string;
218
225
  actions: TActions;
219
226
  }
220
- interface UrlSyncOptions<TModule extends ApiModuleConfig<any>> {
221
- searchParams: string;
222
- updateUrl: (newSearchParams: string) => void;
223
- actionsToSync: (keyof TModule['actions'])[];
224
- defaultSyncAction?: keyof TModule['actions'];
225
- }
226
- interface UseApiModuleOptions<TModule extends ApiModuleConfig<any>, TExtra = {}> {
227
+ /** @description Configuration options passed directly to the `useApiModule` hook. */
228
+ interface UseApiModuleOptions<TExtra = {}> {
227
229
  onSuccess?: (actionName: string, message: string, data: unknown) => void;
228
230
  onError?: (actionName: string, message: string, error?: ApiError | null) => void;
229
231
  refetchOnWindowFocus?: boolean;
@@ -231,12 +233,12 @@ interface UseApiModuleOptions<TModule extends ApiModuleConfig<any>, TExtra = {}>
231
233
  enabled?: boolean;
232
234
  hydratedState?: string;
233
235
  extraContextData?: TExtra;
234
- urlSync?: UrlSyncOptions<TModule>;
235
- defaultQueryOptions?: Partial<Record<keyof TModule['actions'], QueryOptions>>;
236
- initialActionsToExecute?: (keyof TModule['actions'])[];
237
236
  }
237
+ /** A utility type to infer the Input type (`TInput`) from an ActionConfigModule. */
238
238
  type InputOf<TActionConfig> = TActionConfig extends ActionConfigModule<infer TInput, any> ? TInput : never;
239
+ /** A utility type to infer the Output type (`TOutput`) from an ActionConfigModule. */
239
240
  type OutputOf<TActionConfig> = TActionConfig extends ActionConfigModule<any, infer TOutput> ? TOutput : never;
241
+ /** @description Defines the options for the `execute` function, enabling optimistic updates. */
240
242
  interface ExecuteOptions<TInput, TOutput, TContext = unknown> {
241
243
  pathParams?: Record<string, any>;
242
244
  config?: AxiosRequestConfig;
@@ -245,6 +247,7 @@ interface ExecuteOptions<TInput, TOutput, TContext = unknown> {
245
247
  onError?: (error: ApiError, context?: TContext) => void;
246
248
  onSettled?: (data?: TOutput, error?: ApiError, context?: TContext) => void;
247
249
  }
250
+ /** @description A fully-typed object representing the callable actions for a module. */
248
251
  type ModuleActions<TActions extends Record<string, ActionConfigModule<any, any>>> = {
249
252
  [K in keyof TActions]: {
250
253
  execute: <TContext = unknown>(input?: InputOf<TActions[K]>, options?: ExecuteOptions<InputOf<TActions[K]>, OutputOf<TActions[K]>, TContext>) => Promise<StandardResponse<OutputOf<TActions[K]>>>;
@@ -253,26 +256,44 @@ type ModuleActions<TActions extends Record<string, ActionConfigModule<any, any>>
253
256
  }) => void;
254
257
  };
255
258
  };
259
+ /** @description A fully-typed object representing the reactive states for each action in a module. */
256
260
  type ModuleStates<TActions extends Record<string, ActionConfigModule<any, any>>> = {
257
261
  [K in keyof TActions]: ActionState<OutputOf<TActions[K]>>;
258
262
  };
259
263
  type ActionsWithQuery<TActions extends Record<string, ActionConfigModule<any, any>>> = {
260
264
  [K in keyof TActions]: TActions[K] extends ActionConfigModule<QueryOptions, any> ? K : never;
261
265
  }[keyof TActions];
266
+ /**
267
+ * يُنشئ نوعًا لكائن `queries` يحتوي فقط على الإجراءات التي تقبل الكويري.
268
+ */
262
269
  type ModuleQueries<TActions extends Record<string, ActionConfigModule<any, any>>> = {
263
270
  [K in ActionsWithQuery<TActions>]: UseApiQuery;
264
271
  };
272
+ /**
273
+ * @description The complete, fully-typed return object of the `useApiModule` hook.
274
+ */
265
275
  type UseApiModuleReturn<TActions extends Record<string, ActionConfigModule<any, any>>, TExtra extends object = {}> = {
266
276
  states: ModuleStates<TActions>;
267
277
  actions: ModuleActions<TActions>;
268
278
  queries: ModuleQueries<TActions>;
269
279
  dehydrate: () => string;
270
280
  } & TExtra;
281
+ /**
282
+ * يصف دوال `execute` و `reset` لإجراء واحد.
283
+ * هذا النوع عام (generic) ليتناسب مع أنواع الإدخال والإخراج المختلفة لكل إجراء.
284
+ * @template TAction يمثل إعدادات الإجراء الواحد.
285
+ */
271
286
  type ActionMethods<TAction extends ActionConfigModule<any, any>> = {
287
+ /**
288
+ * الدالة الأساسية لتنفيذ طلب ה-API.
289
+ */
272
290
  execute: <TContext = unknown>(input?: InputOf<TAction>, options?: ExecuteOptions<InputOf<TAction>, OutputOf<TAction>, TContext>) => Promise<StandardResponse<OutputOf<TAction>>>;
291
+ /**
292
+ * دالة لإعادة تعيين حالة إجراء معين في ذاكرة التخزين المؤقت إلى حالته الأولية.
293
+ */
273
294
  reset: (input?: InputOf<TAction>, options?: {
274
295
  pathParams?: Record<string, any>;
275
296
  }) => void;
276
297
  };
277
298
 
278
- export type { ApiModuleConfig as A, ExecutableAction as E, InputOf as I, LogLevel as L, ModuleStates 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, UseApiModuleOptions as a, UseApiModuleReturn as b, ModuleActions as c, ModuleQueries as d, ApiClientConfig as e, ActionConfigModule as f, ActionOptions as g, ActionStateModule as h, UseApiQuery as i, ApiError as j, TokenManager as k, MiddlewareContext as l, Middleware as m, RefreshTokenConfig as n, ActionConfig as o, UseApiState as p, ActionState as q, UrlSyncOptions as r, ExecuteOptions as s, t, ActionsWithQuery as u, ActionMethods as v };
299
+ export type { ActionConfigModule as A, ExecutableAction as E, InputOf as I, LogLevel as L, ModuleStates 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, ModuleActions as d, ModuleQueries as e, ApiClientConfig as f, ActionOptions as g, ActionStateModule as h, UseApiQuery as i, ApiError as j, TokenManager as k, MiddlewareContext as l, Middleware as m, RefreshTokenConfig as n, ActionConfig as o, UseApiState as p, ActionState as q, ExecuteOptions as r, ActionsWithQuery as s, t, ActionMethods as u };
package/dist/client.cjs CHANGED
@@ -279,8 +279,7 @@ var ApiModuleProvider = ApiModuleContext.Provider;
279
279
  var createInitialState = () => ({
280
280
  data: null,
281
281
  lastSuccessAt: void 0,
282
- meta: void 0,
283
- links: void 0,
282
+ meta: [],
284
283
  validationErrors: [],
285
284
  error: null,
286
285
  loading: false,
@@ -322,117 +321,40 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
322
321
  refetchOnWindowFocus = true,
323
322
  onSuccess,
324
323
  onError,
325
- pathParams: globalPathParams,
324
+ pathParams: modulePathParams,
326
325
  enabled = true,
327
326
  hydratedState,
328
- extraContextData,
329
- urlSync,
330
- defaultQueryOptions,
331
- initialActionsToExecute
327
+ extraContextData
332
328
  } = options;
333
- const [queryOptions, setQueryOptions] = _react.useState.call(void 0, () => {
334
- const initialOptions = {};
335
- for (const actionName in moduleConfig.actions) {
336
- const actionConfig = moduleConfig.actions[actionName];
337
- if (actionConfig.hasQuery) {
338
- initialOptions[actionName] = { ..._optionalChain([defaultQueryOptions, 'optionalAccess', _6 => _6[actionName]]) || {} };
339
- }
340
- }
341
- return initialOptions;
342
- });
343
- const queryOptionsRef = _react.useRef.call(void 0, queryOptions);
344
- const pathParamsRef = _react.useRef.call(void 0, globalPathParams);
345
- const savedCallbacksRef = _react.useRef.call(void 0, { onSuccess, onError });
346
- _react.useEffect.call(void 0, () => {
347
- queryOptionsRef.current = queryOptions;
348
- }, [queryOptions]);
329
+ const pathParamsString = _react.useMemo.call(void 0, () => JSON.stringify(modulePathParams || {}), [modulePathParams]);
330
+ const [queryOptions, setQueryOptions] = _react.useState.call(void 0, {});
331
+ const savedCallbacks = _react.useRef.call(void 0, { onSuccess, onError });
349
332
  _react.useEffect.call(void 0, () => {
350
- pathParamsRef.current = globalPathParams;
351
- }, [globalPathParams]);
352
- _react.useEffect.call(void 0, () => {
353
- savedCallbacksRef.current = { onSuccess, onError };
333
+ savedCallbacks.current = { onSuccess, onError };
354
334
  }, [onSuccess, onError]);
355
- const stableActionsRef = _react.useRef.call(void 0, {});
356
- _react.useEffect.call(void 0, () => {
335
+ _react.useMemo.call(void 0, () => {
357
336
  if (hydratedState) {
358
337
  _chunkJAMEOM7Tcjs.globalStateManager.rehydrate(hydratedState);
359
338
  }
360
339
  }, [hydratedState]);
361
- _react.useEffect.call(void 0, () => {
362
- if (!urlSync) return;
363
- const { searchParams, actionsToSync, defaultSyncAction } = urlSync;
364
- const params = new URLSearchParams(searchParams);
365
- const queryFromUrl = {};
366
- params.forEach((value, key) => {
367
- const parts = key.split(".");
368
- const hasPrefix = parts.length > 1;
369
- const actionName = hasPrefix ? parts[0] : defaultSyncAction;
370
- const paramKey = hasPrefix ? parts[1] : parts[0];
371
- if (actionName && paramKey && actionsToSync.some((a) => a === actionName)) {
372
- if (!queryFromUrl[actionName]) queryFromUrl[actionName] = {};
373
- const isNum = !isNaN(Number(value)) && value.trim() !== "";
374
- queryFromUrl[actionName][paramKey] = isNum ? Number(value) : value;
375
- }
376
- });
377
- if (Object.keys(queryFromUrl).length > 0) {
378
- setQueryOptions((prev) => {
379
- const newState = { ...prev };
380
- for (const actionName in queryFromUrl) {
381
- newState[actionName] = { ...newState[actionName], ...queryFromUrl[actionName] };
382
- }
383
- return newState;
384
- });
385
- }
386
- }, [_optionalChain([urlSync, 'optionalAccess', _7 => _7.searchParams]), _optionalChain([urlSync, 'optionalAccess', _8 => _8.actionsToSync]), _optionalChain([urlSync, 'optionalAccess', _9 => _9.defaultSyncAction])]);
387
- _react.useEffect.call(void 0, () => {
388
- if (!urlSync) return;
389
- const { searchParams, updateUrl, actionsToSync, defaultSyncAction } = urlSync;
390
- const currentParams = new URLSearchParams(searchParams);
391
- let hasChanged = false;
392
- for (const actionName in queryOptions) {
393
- if (actionsToSync.some((a) => a === actionName)) {
394
- const params = queryOptions[actionName];
395
- const isDefaultAction = actionName === defaultSyncAction;
396
- for (const key in params) {
397
- const fullKey = isDefaultAction ? key : `${actionName}.${key}`;
398
- const value = params[key];
399
- const stringValue = value !== void 0 && value !== null ? String(value) : "";
400
- if (currentParams.get(fullKey) !== stringValue) {
401
- if (stringValue) currentParams.set(fullKey, stringValue);
402
- else currentParams.delete(fullKey);
403
- hasChanged = true;
404
- }
405
- }
406
- }
407
- }
408
- if (hasChanged) {
409
- updateUrl(currentParams.toString());
410
- }
411
- }, [queryOptions, _optionalChain([urlSync, 'optionalAccess', _10 => _10.updateUrl]), _optionalChain([urlSync, 'optionalAccess', _11 => _11.searchParams]), _optionalChain([urlSync, 'optionalAccess', _12 => _12.actionsToSync]), _optionalChain([urlSync, 'optionalAccess', _13 => _13.defaultSyncAction])]);
412
- _react.useMemo.call(void 0, () => {
413
- for (const actionName in moduleConfig.actions) {
340
+ const actions = _react.useMemo.call(void 0, () => {
341
+ return Object.keys(moduleConfig.actions).reduce((acc, actionName) => {
414
342
  const actionConfig = moduleConfig.actions[actionName];
415
343
  const shouldCache = actionConfig.cacheResponse !== false;
416
344
  const execute = async (input, options2 = {}) => {
417
- const finalPathParams = { ...pathParamsRef.current, ...options2.pathParams };
418
- const currentQueryOptions = queryOptionsRef.current[actionName];
419
- let bodyForCall = input;
420
- if (actionConfig.method === "GET" && actionConfig.hasQuery) {
421
- bodyForCall = { ...currentQueryOptions, ..._optionalChain([options2, 'access', _14 => _14.config, 'optionalAccess', _15 => _15.params]), ...input };
422
- } else if (actionConfig.upload && input) {
423
- bodyForCall = new FormData();
424
- for (const key in input) {
425
- bodyForCall.append(key, input[key]);
426
- }
427
- }
428
- const cacheKey = shouldCache ? _chunkJAMEOM7Tcjs.generateCacheKey.call(void 0, moduleConfig.baseEndpoint, actionName, bodyForCall, { pathParams: finalPathParams }) : "";
429
- if (shouldCache) {
430
- _chunkJAMEOM7Tcjs.globalStateManager.setState(cacheKey, (prev) => ({ ...prev, loading: true, called: true, error: null, isStale: false }));
431
- }
345
+ const finalPathParams = { ...JSON.parse(pathParamsString), ...options2.pathParams };
346
+ const cacheKey = shouldCache ? _chunkJAMEOM7Tcjs.generateCacheKey.call(void 0, moduleConfig.baseEndpoint, actionName, input, { pathParams: finalPathParams }) : "";
347
+ let mutationContext;
432
348
  try {
349
+ if (options2.onMutate && shouldCache) {
350
+ mutationContext = await options2.onMutate(input);
351
+ }
352
+ if (shouldCache) {
353
+ _chunkJAMEOM7Tcjs.globalStateManager.setState(cacheKey, (prev) => ({ ...prev, loading: true, called: true, error: null, isStale: false }));
354
+ }
433
355
  const result = await _chunkJAMEOM7Tcjs.callDynamicApi.call(void 0, axiosInstance, moduleConfig.baseEndpoint, actionConfig, {
434
356
  pathParams: finalPathParams,
435
- body: bodyForCall,
357
+ body: input,
436
358
  config: options2.config
437
359
  });
438
360
  if (shouldCache) {
@@ -446,69 +368,57 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
446
368
  links: result.links,
447
369
  message: result.message,
448
370
  validationErrors: result.validationErrors || [],
449
- rawResponse: result.rawResponse,
450
- lastSuccessAt: result.success ? Date.now() : prev.lastSuccessAt
371
+ rawResponse: result.rawResponse
451
372
  }));
452
373
  }
453
374
  if (result.success) {
454
- _optionalChain([savedCallbacksRef, 'access', _16 => _16.current, 'access', _17 => _17.onSuccess, 'optionalCall', _18 => _18(actionName, result.message || "Action successful", result.data)]);
455
- _optionalChain([options2, 'access', _19 => _19.onSuccess, 'optionalCall', _20 => _20(result.data, void 0)]);
456
- _optionalChain([actionConfig, 'access', _21 => _21.invalidates, 'optionalAccess', _22 => _22.forEach, 'call', _23 => _23((keyToInvalidate) => {
375
+ _optionalChain([savedCallbacks, 'access', _6 => _6.current, 'access', _7 => _7.onSuccess, 'optionalCall', _8 => _8(actionName, result.message || "Action successful", result.data)]);
376
+ _optionalChain([options2, 'access', _9 => _9.onSuccess, 'optionalCall', _10 => _10(result.data, mutationContext)]);
377
+ _optionalChain([actionConfig, 'access', _11 => _11.invalidates, 'optionalAccess', _12 => _12.forEach, 'call', _13 => _13((keyToInvalidate) => {
457
378
  const prefix = `${moduleConfig.baseEndpoint}/${keyToInvalidate}::`;
458
379
  _chunkJAMEOM7Tcjs.globalStateManager.invalidateByPrefix(prefix);
459
380
  })]);
460
381
  } else {
461
- _optionalChain([savedCallbacksRef, 'access', _24 => _24.current, 'access', _25 => _25.onError, 'optionalCall', _26 => _26(actionName, result.message || "Action failed", _nullishCoalesce(result.error, () => ( void 0)))]);
462
- _optionalChain([options2, 'access', _27 => _27.onError, 'optionalCall', _28 => _28(result.error, void 0)]);
382
+ _optionalChain([savedCallbacks, 'access', _14 => _14.current, 'access', _15 => _15.onError, 'optionalCall', _16 => _16(actionName, result.message || "Action failed", _nullishCoalesce(result.error, () => ( void 0)))]);
383
+ _optionalChain([options2, 'access', _17 => _17.onError, 'optionalCall', _18 => _18(result.error, mutationContext)]);
463
384
  }
464
385
  return result;
465
386
  } catch (error) {
466
- const apiError = _optionalChain([error, 'access', _29 => _29.response, 'optionalAccess', _30 => _30.data]) || { status: 500, message: error.message };
387
+ const apiError = _optionalChain([error, 'access', _19 => _19.response, 'optionalAccess', _20 => _20.data]) || { status: 500, message: error.message };
467
388
  if (shouldCache) {
468
389
  _chunkJAMEOM7Tcjs.globalStateManager.setState(cacheKey, (prev) => ({ ...prev, error: apiError, loading: false, success: false }));
469
390
  }
470
- _optionalChain([savedCallbacksRef, 'access', _31 => _31.current, 'access', _32 => _32.onError, 'optionalCall', _33 => _33(actionName, apiError.message, apiError)]);
471
- _optionalChain([options2, 'access', _34 => _34.onError, 'optionalCall', _35 => _35(apiError, void 0)]);
391
+ _optionalChain([savedCallbacks, 'access', _21 => _21.current, 'access', _22 => _22.onError, 'optionalCall', _23 => _23(actionName, apiError.message, apiError)]);
392
+ _optionalChain([options2, 'access', _24 => _24.onError, 'optionalCall', _25 => _25(apiError, mutationContext)]);
472
393
  throw error;
394
+ } finally {
395
+ if (options2.onSettled) {
396
+ options2.onSettled();
397
+ }
473
398
  }
474
399
  };
475
400
  const reset = (input, options2 = {}) => {
476
401
  if (shouldCache) {
477
- const finalPathParams = { ...pathParamsRef.current, ...options2.pathParams };
402
+ const finalPathParams = { ...JSON.parse(pathParamsString), ...options2.pathParams };
478
403
  const cacheKey = _chunkJAMEOM7Tcjs.generateCacheKey.call(void 0, moduleConfig.baseEndpoint, actionName, input, { pathParams: finalPathParams });
479
404
  _chunkJAMEOM7Tcjs.globalStateManager.setState(cacheKey, () => createInitialState());
480
405
  }
481
406
  };
482
- stableActionsRef.current[actionName] = { execute, reset };
483
- }
484
- }, [axiosInstance, moduleConfig]);
485
- const actions = _react.useMemo.call(void 0, () => stableActionsRef.current, []);
486
- const initialFetchRef = _react.useRef.call(void 0, false);
487
- _react.useEffect.call(void 0, () => {
488
- if (typeof window === "undefined" || initialFetchRef.current || !enabled) return;
489
- const actionsToRun = initialActionsToExecute ? initialActionsToExecute.map(String) : Object.keys(moduleConfig.actions).filter(
490
- (actionName) => moduleConfig.actions[actionName].autoFetch
491
- );
492
- actionsToRun.forEach((actionName) => {
493
- const key = actionName;
494
- const executeAction = _optionalChain([actions, 'access', _36 => _36[key], 'optionalAccess', _37 => _37.execute]);
495
- if (typeof executeAction === "function") {
496
- executeAction();
497
- }
498
- });
499
- initialFetchRef.current = true;
500
- }, [actions, initialActionsToExecute, moduleConfig.actions, enabled]);
407
+ acc[actionName] = { execute, reset };
408
+ return acc;
409
+ }, {});
410
+ }, [axiosInstance, moduleConfig, pathParamsString]);
501
411
  const queries = _react.useMemo.call(void 0, () => {
502
412
  return Object.keys(moduleConfig.actions).reduce((acc, actionName) => {
503
413
  const actionConfig = moduleConfig.actions[actionName];
504
- if (_optionalChain([actionConfig, 'optionalAccess', _38 => _38.hasQuery])) {
414
+ if (_optionalChain([actionConfig, 'optionalAccess', _26 => _26.hasQuery])) {
505
415
  const setActionQueryOptions = (updater) => {
506
416
  const key = actionName;
507
417
  setQueryOptions((prev) => ({ ...prev, [key]: typeof updater === "function" ? updater(prev[key] || {}) : updater }));
508
418
  };
419
+ const specificActionExecute = actions[actionName].execute;
509
420
  const refetch = () => {
510
- const execute = actions[actionName].execute;
511
- execute(queryOptions[actionName] || {});
421
+ specificActionExecute(queryOptions[actionName] || {});
512
422
  };
513
423
  acc[actionName] = {
514
424
  options: queryOptions[actionName] || {},
@@ -520,29 +430,39 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
520
430
  setFilters: (filter) => setActionQueryOptions((p) => ({ ...p, filter, page: 1 })),
521
431
  setSorting: (sortBy) => setActionQueryOptions((p) => ({ ...p, sortBy })),
522
432
  setQueryParam: (key, value) => setActionQueryOptions((p) => ({ ...p, [key]: value, page: key !== "page" ? value : p.page })),
523
- reset: () => setActionQueryOptions(_optionalChain([defaultQueryOptions, 'optionalAccess', _39 => _39[actionName]]) || {})
433
+ reset: () => setActionQueryOptions({})
524
434
  };
525
435
  }
526
436
  return acc;
527
437
  }, {});
528
- }, [actions, queryOptions, moduleConfig.actions, defaultQueryOptions]);
438
+ }, [actions, queryOptions, moduleConfig.actions]);
529
439
  const states = {};
530
440
  function isActionWithQuery(key, actions2) {
531
- return _optionalChain([actions2, 'access', _40 => _40[key], 'optionalAccess', _41 => _41.hasQuery]) === true;
441
+ return _optionalChain([actions2, 'access', _27 => _27[key], 'optionalAccess', _28 => _28.hasQuery]) === true;
532
442
  }
533
443
  for (const actionName in moduleConfig.actions) {
534
444
  if (Object.prototype.hasOwnProperty.call(moduleConfig.actions, actionName)) {
535
- const key = actionName;
536
- const actionConfig = moduleConfig.actions[key];
445
+ const actionConfig = moduleConfig.actions[actionName];
537
446
  if (actionConfig.cacheResponse !== false) {
538
447
  let currentQueryOptions;
539
- if (isActionWithQuery(key, moduleConfig.actions)) {
540
- currentQueryOptions = _optionalChain([queries, 'access', _42 => _42[key], 'optionalAccess', _43 => _43.options]);
448
+ if (isActionWithQuery(actionName, moduleConfig.actions)) {
449
+ currentQueryOptions = _optionalChain([queries, 'access', _29 => _29[actionName], 'optionalAccess', _30 => _30.options]);
541
450
  }
542
451
  const input = currentQueryOptions;
543
- const pathParams = globalPathParams || {};
544
- const cacheKey = _chunkJAMEOM7Tcjs.generateCacheKey.call(void 0, moduleConfig.baseEndpoint, actionName, input, { pathParams });
545
- states[actionName] = useApiActionState(actionConfig, cacheKey, actions[key].execute, input, enabled);
452
+ const pathParams = JSON.parse(pathParamsString);
453
+ const cacheKey = _chunkJAMEOM7Tcjs.generateCacheKey.call(void 0,
454
+ moduleConfig.baseEndpoint,
455
+ actionName,
456
+ input,
457
+ { pathParams }
458
+ );
459
+ states[actionName] = useApiActionState(
460
+ actionConfig,
461
+ cacheKey,
462
+ actions[actionName].execute,
463
+ input,
464
+ enabled
465
+ );
546
466
  } else {
547
467
  states[actionName] = createInitialState();
548
468
  }
@@ -553,10 +473,12 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
553
473
  if (!enabled || !refetchOnWindowFocus) return;
554
474
  const onFocus = () => {
555
475
  if (Date.now() - lastBlurTimestamp.current > 1e4) {
556
- for (const actionName of Object.keys(moduleConfig.actions)) {
476
+ const actionKeys = Object.keys(moduleConfig.actions);
477
+ for (const actionName of actionKeys) {
557
478
  const state = states[actionName];
558
479
  if (state && state.called && !state.loading) {
559
- _chunkJAMEOM7Tcjs.globalStateManager.invalidateByPrefix(`${moduleConfig.baseEndpoint}/${actionName}::`);
480
+ const prefix = `${moduleConfig.baseEndpoint}/${actionName}::`;
481
+ _chunkJAMEOM7Tcjs.globalStateManager.invalidateByPrefix(prefix);
560
482
  }
561
483
  }
562
484
  }
@@ -571,16 +493,14 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
571
493
  window.removeEventListener("blur", onBlur);
572
494
  };
573
495
  }, [enabled, refetchOnWindowFocus, moduleConfig, states]);
574
- const dehydrate = _react.useCallback.call(void 0, () => _chunkJAMEOM7Tcjs.globalStateManager.dehydrate(), []);
496
+ const dehydrate = _react.useMemo.call(void 0, () => {
497
+ return () => _chunkJAMEOM7Tcjs.globalStateManager.dehydrate();
498
+ }, []);
499
+ const baseApiReturn = { actions, states, queries, dehydrate };
575
500
  const finalApiReturn = _react.useMemo.call(void 0, () => ({
576
- actions,
577
- states,
578
- queries,
579
- dehydrate,
501
+ ...baseApiReturn,
580
502
  ...extraContextData || {}
581
- // [REFACTOR] `states` and `queries` are now dependencies because they are recalculated on re-renders.
582
- // `actions` is stable and doesn't need to be a dependency.
583
- }), [actions, states, queries, dehydrate, extraContextData]);
503
+ }), [baseApiReturn, extraContextData]);
584
504
  return finalApiReturn;
585
505
  }
586
506
 
package/dist/client.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AxiosInstance } from 'axios';
2
- import { U as UseApiConfig, A as ApiModuleConfig, a as UseApiModuleOptions, b as UseApiModuleReturn, M as ModuleStates, c as ModuleActions, d as ModuleQueries } from './apiModule.types-DEskFzOY.cjs';
3
- import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-mpeiDoxm.cjs';
2
+ import { U as UseApiConfig, A as ActionConfigModule, a as ApiModuleConfig, b as UseApiModuleOptions, c as UseApiModuleReturn, M as ModuleStates, d as ModuleActions, e as ModuleQueries } from './apiModule.types-hGWAkTwf.cjs';
3
+ import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-V-4fiB7L.cjs';
4
4
  import * as react from 'react';
5
5
  import { ReactNode } from 'react';
6
6
 
@@ -28,7 +28,7 @@ declare const ApiModuleProvider: react.Provider<{
28
28
  queries: ModuleQueries<any>;
29
29
  dehydrate: () => string;
30
30
  } | null>;
31
- declare function useApiModule<TModule extends ApiModuleConfig<any>, TExtra extends object = {}>(axiosInstance: AxiosInstance, moduleConfig: TModule, options?: UseApiModuleOptions<TModule, TExtra>): UseApiModuleReturn<TModule['actions'], TExtra>;
31
+ declare function useApiModule<TActions extends Record<string, ActionConfigModule<any, any>>, TExtra extends object = {}>(axiosInstance: AxiosInstance, moduleConfig: ApiModuleConfig<TActions>, options?: UseApiModuleOptions<TExtra>): UseApiModuleReturn<TActions, TExtra>;
32
32
 
33
33
  /**
34
34
  * Creates a strongly-typed React Context, Provider, and consumer hook for a specific API module.
package/dist/client.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AxiosInstance } from 'axios';
2
- import { U as UseApiConfig, A as ApiModuleConfig, a as UseApiModuleOptions, b as UseApiModuleReturn, M as ModuleStates, c as ModuleActions, d as ModuleQueries } from './apiModule.types-DEskFzOY.js';
3
- import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-C31nzgeP.js';
2
+ import { U as UseApiConfig, A as ActionConfigModule, a as ApiModuleConfig, b as UseApiModuleOptions, c as UseApiModuleReturn, M as ModuleStates, d as ModuleActions, e as ModuleQueries } from './apiModule.types-hGWAkTwf.js';
3
+ import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-BJop2XPB.js';
4
4
  import * as react from 'react';
5
5
  import { ReactNode } from 'react';
6
6
 
@@ -28,7 +28,7 @@ declare const ApiModuleProvider: react.Provider<{
28
28
  queries: ModuleQueries<any>;
29
29
  dehydrate: () => string;
30
30
  } | null>;
31
- declare function useApiModule<TModule extends ApiModuleConfig<any>, TExtra extends object = {}>(axiosInstance: AxiosInstance, moduleConfig: TModule, options?: UseApiModuleOptions<TModule, TExtra>): UseApiModuleReturn<TModule['actions'], TExtra>;
31
+ declare function useApiModule<TActions extends Record<string, ActionConfigModule<any, any>>, TExtra extends object = {}>(axiosInstance: AxiosInstance, moduleConfig: ApiModuleConfig<TActions>, options?: UseApiModuleOptions<TExtra>): UseApiModuleReturn<TActions, TExtra>;
32
32
 
33
33
  /**
34
34
  * Creates a strongly-typed React Context, Provider, and consumer hook for a specific API module.
package/dist/client.js CHANGED
@@ -279,8 +279,7 @@ var ApiModuleProvider = ApiModuleContext.Provider;
279
279
  var createInitialState = () => ({
280
280
  data: null,
281
281
  lastSuccessAt: void 0,
282
- meta: void 0,
283
- links: void 0,
282
+ meta: [],
284
283
  validationErrors: [],
285
284
  error: null,
286
285
  loading: false,
@@ -322,117 +321,40 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
322
321
  refetchOnWindowFocus = true,
323
322
  onSuccess,
324
323
  onError,
325
- pathParams: globalPathParams,
324
+ pathParams: modulePathParams,
326
325
  enabled = true,
327
326
  hydratedState,
328
- extraContextData,
329
- urlSync,
330
- defaultQueryOptions,
331
- initialActionsToExecute
327
+ extraContextData
332
328
  } = options;
333
- const [queryOptions, setQueryOptions] = useState3(() => {
334
- const initialOptions = {};
335
- for (const actionName in moduleConfig.actions) {
336
- const actionConfig = moduleConfig.actions[actionName];
337
- if (actionConfig.hasQuery) {
338
- initialOptions[actionName] = { ...defaultQueryOptions?.[actionName] || {} };
339
- }
340
- }
341
- return initialOptions;
342
- });
343
- const queryOptionsRef = useRef4(queryOptions);
344
- const pathParamsRef = useRef4(globalPathParams);
345
- const savedCallbacksRef = useRef4({ onSuccess, onError });
346
- useEffect4(() => {
347
- queryOptionsRef.current = queryOptions;
348
- }, [queryOptions]);
329
+ const pathParamsString = useMemo3(() => JSON.stringify(modulePathParams || {}), [modulePathParams]);
330
+ const [queryOptions, setQueryOptions] = useState3({});
331
+ const savedCallbacks = useRef4({ onSuccess, onError });
349
332
  useEffect4(() => {
350
- pathParamsRef.current = globalPathParams;
351
- }, [globalPathParams]);
352
- useEffect4(() => {
353
- savedCallbacksRef.current = { onSuccess, onError };
333
+ savedCallbacks.current = { onSuccess, onError };
354
334
  }, [onSuccess, onError]);
355
- const stableActionsRef = useRef4({});
356
- useEffect4(() => {
335
+ useMemo3(() => {
357
336
  if (hydratedState) {
358
337
  globalStateManager.rehydrate(hydratedState);
359
338
  }
360
339
  }, [hydratedState]);
361
- useEffect4(() => {
362
- if (!urlSync) return;
363
- const { searchParams, actionsToSync, defaultSyncAction } = urlSync;
364
- const params = new URLSearchParams(searchParams);
365
- const queryFromUrl = {};
366
- params.forEach((value, key) => {
367
- const parts = key.split(".");
368
- const hasPrefix = parts.length > 1;
369
- const actionName = hasPrefix ? parts[0] : defaultSyncAction;
370
- const paramKey = hasPrefix ? parts[1] : parts[0];
371
- if (actionName && paramKey && actionsToSync.some((a) => a === actionName)) {
372
- if (!queryFromUrl[actionName]) queryFromUrl[actionName] = {};
373
- const isNum = !isNaN(Number(value)) && value.trim() !== "";
374
- queryFromUrl[actionName][paramKey] = isNum ? Number(value) : value;
375
- }
376
- });
377
- if (Object.keys(queryFromUrl).length > 0) {
378
- setQueryOptions((prev) => {
379
- const newState = { ...prev };
380
- for (const actionName in queryFromUrl) {
381
- newState[actionName] = { ...newState[actionName], ...queryFromUrl[actionName] };
382
- }
383
- return newState;
384
- });
385
- }
386
- }, [urlSync?.searchParams, urlSync?.actionsToSync, urlSync?.defaultSyncAction]);
387
- useEffect4(() => {
388
- if (!urlSync) return;
389
- const { searchParams, updateUrl, actionsToSync, defaultSyncAction } = urlSync;
390
- const currentParams = new URLSearchParams(searchParams);
391
- let hasChanged = false;
392
- for (const actionName in queryOptions) {
393
- if (actionsToSync.some((a) => a === actionName)) {
394
- const params = queryOptions[actionName];
395
- const isDefaultAction = actionName === defaultSyncAction;
396
- for (const key in params) {
397
- const fullKey = isDefaultAction ? key : `${actionName}.${key}`;
398
- const value = params[key];
399
- const stringValue = value !== void 0 && value !== null ? String(value) : "";
400
- if (currentParams.get(fullKey) !== stringValue) {
401
- if (stringValue) currentParams.set(fullKey, stringValue);
402
- else currentParams.delete(fullKey);
403
- hasChanged = true;
404
- }
405
- }
406
- }
407
- }
408
- if (hasChanged) {
409
- updateUrl(currentParams.toString());
410
- }
411
- }, [queryOptions, urlSync?.updateUrl, urlSync?.searchParams, urlSync?.actionsToSync, urlSync?.defaultSyncAction]);
412
- useMemo3(() => {
413
- for (const actionName in moduleConfig.actions) {
340
+ const actions = useMemo3(() => {
341
+ return Object.keys(moduleConfig.actions).reduce((acc, actionName) => {
414
342
  const actionConfig = moduleConfig.actions[actionName];
415
343
  const shouldCache = actionConfig.cacheResponse !== false;
416
344
  const execute = async (input, options2 = {}) => {
417
- const finalPathParams = { ...pathParamsRef.current, ...options2.pathParams };
418
- const currentQueryOptions = queryOptionsRef.current[actionName];
419
- let bodyForCall = input;
420
- if (actionConfig.method === "GET" && actionConfig.hasQuery) {
421
- bodyForCall = { ...currentQueryOptions, ...options2.config?.params, ...input };
422
- } else if (actionConfig.upload && input) {
423
- bodyForCall = new FormData();
424
- for (const key in input) {
425
- bodyForCall.append(key, input[key]);
426
- }
427
- }
428
- const cacheKey = shouldCache ? generateCacheKey(moduleConfig.baseEndpoint, actionName, bodyForCall, { pathParams: finalPathParams }) : "";
429
- if (shouldCache) {
430
- globalStateManager.setState(cacheKey, (prev) => ({ ...prev, loading: true, called: true, error: null, isStale: false }));
431
- }
345
+ const finalPathParams = { ...JSON.parse(pathParamsString), ...options2.pathParams };
346
+ const cacheKey = shouldCache ? generateCacheKey(moduleConfig.baseEndpoint, actionName, input, { pathParams: finalPathParams }) : "";
347
+ let mutationContext;
432
348
  try {
349
+ if (options2.onMutate && shouldCache) {
350
+ mutationContext = await options2.onMutate(input);
351
+ }
352
+ if (shouldCache) {
353
+ globalStateManager.setState(cacheKey, (prev) => ({ ...prev, loading: true, called: true, error: null, isStale: false }));
354
+ }
433
355
  const result = await callDynamicApi(axiosInstance, moduleConfig.baseEndpoint, actionConfig, {
434
356
  pathParams: finalPathParams,
435
- body: bodyForCall,
357
+ body: input,
436
358
  config: options2.config
437
359
  });
438
360
  if (shouldCache) {
@@ -446,20 +368,19 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
446
368
  links: result.links,
447
369
  message: result.message,
448
370
  validationErrors: result.validationErrors || [],
449
- rawResponse: result.rawResponse,
450
- lastSuccessAt: result.success ? Date.now() : prev.lastSuccessAt
371
+ rawResponse: result.rawResponse
451
372
  }));
452
373
  }
453
374
  if (result.success) {
454
- savedCallbacksRef.current.onSuccess?.(actionName, result.message || "Action successful", result.data);
455
- options2.onSuccess?.(result.data, void 0);
375
+ savedCallbacks.current.onSuccess?.(actionName, result.message || "Action successful", result.data);
376
+ options2.onSuccess?.(result.data, mutationContext);
456
377
  actionConfig.invalidates?.forEach((keyToInvalidate) => {
457
378
  const prefix = `${moduleConfig.baseEndpoint}/${keyToInvalidate}::`;
458
379
  globalStateManager.invalidateByPrefix(prefix);
459
380
  });
460
381
  } else {
461
- savedCallbacksRef.current.onError?.(actionName, result.message || "Action failed", result.error ?? void 0);
462
- options2.onError?.(result.error, void 0);
382
+ savedCallbacks.current.onError?.(actionName, result.message || "Action failed", result.error ?? void 0);
383
+ options2.onError?.(result.error, mutationContext);
463
384
  }
464
385
  return result;
465
386
  } catch (error) {
@@ -467,37 +388,26 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
467
388
  if (shouldCache) {
468
389
  globalStateManager.setState(cacheKey, (prev) => ({ ...prev, error: apiError, loading: false, success: false }));
469
390
  }
470
- savedCallbacksRef.current.onError?.(actionName, apiError.message, apiError);
471
- options2.onError?.(apiError, void 0);
391
+ savedCallbacks.current.onError?.(actionName, apiError.message, apiError);
392
+ options2.onError?.(apiError, mutationContext);
472
393
  throw error;
394
+ } finally {
395
+ if (options2.onSettled) {
396
+ options2.onSettled();
397
+ }
473
398
  }
474
399
  };
475
400
  const reset = (input, options2 = {}) => {
476
401
  if (shouldCache) {
477
- const finalPathParams = { ...pathParamsRef.current, ...options2.pathParams };
402
+ const finalPathParams = { ...JSON.parse(pathParamsString), ...options2.pathParams };
478
403
  const cacheKey = generateCacheKey(moduleConfig.baseEndpoint, actionName, input, { pathParams: finalPathParams });
479
404
  globalStateManager.setState(cacheKey, () => createInitialState());
480
405
  }
481
406
  };
482
- stableActionsRef.current[actionName] = { execute, reset };
483
- }
484
- }, [axiosInstance, moduleConfig]);
485
- const actions = useMemo3(() => stableActionsRef.current, []);
486
- const initialFetchRef = useRef4(false);
487
- useEffect4(() => {
488
- if (typeof window === "undefined" || initialFetchRef.current || !enabled) return;
489
- const actionsToRun = initialActionsToExecute ? initialActionsToExecute.map(String) : Object.keys(moduleConfig.actions).filter(
490
- (actionName) => moduleConfig.actions[actionName].autoFetch
491
- );
492
- actionsToRun.forEach((actionName) => {
493
- const key = actionName;
494
- const executeAction = actions[key]?.execute;
495
- if (typeof executeAction === "function") {
496
- executeAction();
497
- }
498
- });
499
- initialFetchRef.current = true;
500
- }, [actions, initialActionsToExecute, moduleConfig.actions, enabled]);
407
+ acc[actionName] = { execute, reset };
408
+ return acc;
409
+ }, {});
410
+ }, [axiosInstance, moduleConfig, pathParamsString]);
501
411
  const queries = useMemo3(() => {
502
412
  return Object.keys(moduleConfig.actions).reduce((acc, actionName) => {
503
413
  const actionConfig = moduleConfig.actions[actionName];
@@ -506,9 +416,9 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
506
416
  const key = actionName;
507
417
  setQueryOptions((prev) => ({ ...prev, [key]: typeof updater === "function" ? updater(prev[key] || {}) : updater }));
508
418
  };
419
+ const specificActionExecute = actions[actionName].execute;
509
420
  const refetch = () => {
510
- const execute = actions[actionName].execute;
511
- execute(queryOptions[actionName] || {});
421
+ specificActionExecute(queryOptions[actionName] || {});
512
422
  };
513
423
  acc[actionName] = {
514
424
  options: queryOptions[actionName] || {},
@@ -520,29 +430,39 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
520
430
  setFilters: (filter) => setActionQueryOptions((p) => ({ ...p, filter, page: 1 })),
521
431
  setSorting: (sortBy) => setActionQueryOptions((p) => ({ ...p, sortBy })),
522
432
  setQueryParam: (key, value) => setActionQueryOptions((p) => ({ ...p, [key]: value, page: key !== "page" ? value : p.page })),
523
- reset: () => setActionQueryOptions(defaultQueryOptions?.[actionName] || {})
433
+ reset: () => setActionQueryOptions({})
524
434
  };
525
435
  }
526
436
  return acc;
527
437
  }, {});
528
- }, [actions, queryOptions, moduleConfig.actions, defaultQueryOptions]);
438
+ }, [actions, queryOptions, moduleConfig.actions]);
529
439
  const states = {};
530
440
  function isActionWithQuery(key, actions2) {
531
441
  return actions2[key]?.hasQuery === true;
532
442
  }
533
443
  for (const actionName in moduleConfig.actions) {
534
444
  if (Object.prototype.hasOwnProperty.call(moduleConfig.actions, actionName)) {
535
- const key = actionName;
536
- const actionConfig = moduleConfig.actions[key];
445
+ const actionConfig = moduleConfig.actions[actionName];
537
446
  if (actionConfig.cacheResponse !== false) {
538
447
  let currentQueryOptions;
539
- if (isActionWithQuery(key, moduleConfig.actions)) {
540
- currentQueryOptions = queries[key]?.options;
448
+ if (isActionWithQuery(actionName, moduleConfig.actions)) {
449
+ currentQueryOptions = queries[actionName]?.options;
541
450
  }
542
451
  const input = currentQueryOptions;
543
- const pathParams = globalPathParams || {};
544
- const cacheKey = generateCacheKey(moduleConfig.baseEndpoint, actionName, input, { pathParams });
545
- states[actionName] = useApiActionState(actionConfig, cacheKey, actions[key].execute, input, enabled);
452
+ const pathParams = JSON.parse(pathParamsString);
453
+ const cacheKey = generateCacheKey(
454
+ moduleConfig.baseEndpoint,
455
+ actionName,
456
+ input,
457
+ { pathParams }
458
+ );
459
+ states[actionName] = useApiActionState(
460
+ actionConfig,
461
+ cacheKey,
462
+ actions[actionName].execute,
463
+ input,
464
+ enabled
465
+ );
546
466
  } else {
547
467
  states[actionName] = createInitialState();
548
468
  }
@@ -553,10 +473,12 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
553
473
  if (!enabled || !refetchOnWindowFocus) return;
554
474
  const onFocus = () => {
555
475
  if (Date.now() - lastBlurTimestamp.current > 1e4) {
556
- for (const actionName of Object.keys(moduleConfig.actions)) {
476
+ const actionKeys = Object.keys(moduleConfig.actions);
477
+ for (const actionName of actionKeys) {
557
478
  const state = states[actionName];
558
479
  if (state && state.called && !state.loading) {
559
- globalStateManager.invalidateByPrefix(`${moduleConfig.baseEndpoint}/${actionName}::`);
480
+ const prefix = `${moduleConfig.baseEndpoint}/${actionName}::`;
481
+ globalStateManager.invalidateByPrefix(prefix);
560
482
  }
561
483
  }
562
484
  }
@@ -571,21 +493,19 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
571
493
  window.removeEventListener("blur", onBlur);
572
494
  };
573
495
  }, [enabled, refetchOnWindowFocus, moduleConfig, states]);
574
- const dehydrate = useCallback3(() => globalStateManager.dehydrate(), []);
496
+ const dehydrate = useMemo3(() => {
497
+ return () => globalStateManager.dehydrate();
498
+ }, []);
499
+ const baseApiReturn = { actions, states, queries, dehydrate };
575
500
  const finalApiReturn = useMemo3(() => ({
576
- actions,
577
- states,
578
- queries,
579
- dehydrate,
501
+ ...baseApiReturn,
580
502
  ...extraContextData || {}
581
- // [REFACTOR] `states` and `queries` are now dependencies because they are recalculated on re-renders.
582
- // `actions` is stable and doesn't need to be a dependency.
583
- }), [actions, states, queries, dehydrate, extraContextData]);
503
+ }), [baseApiReturn, extraContextData]);
584
504
  return finalApiReturn;
585
505
  }
586
506
 
587
507
  // src/hooks/useApiModule/apiModuleContext.ts
588
- import { createContext as createContext2, useContext, createElement } from "react";
508
+ import { createContext as createContext2, useContext as useContext2, createElement } from "react";
589
509
  function createApiModuleContext() {
590
510
  const Context = createContext2(null);
591
511
  Context.displayName = "ApiModuleContext";
@@ -593,7 +513,7 @@ function createApiModuleContext() {
593
513
  return createElement(Context.Provider, { value }, children);
594
514
  };
595
515
  const useConsumer = () => {
596
- const context = useContext(Context);
516
+ const context = useContext2(Context);
597
517
  if (!context) {
598
518
  throw new Error("This component must be used within its corresponding ApiModuleProvider.");
599
519
  }
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AxiosInstance, AxiosRequestConfig, Method, AxiosResponse, AxiosError } from 'axios';
2
- import { e as ApiClientConfig, f as ActionConfigModule, S as StandardResponse, g as ActionOptions, R as RequestConfig, h as ActionStateModule, Q as QueryOptions, i as UseApiQuery, j as ApiError, L as LogLevel } from './apiModule.types-DEskFzOY.cjs';
3
- export { o as ActionConfig, v as ActionMethods, q as ActionState, u as ActionsWithQuery, A as ApiModuleConfig, E as ExecutableAction, s as ExecuteOptions, I as InputOf, m as Middleware, l as MiddlewareContext, c as ModuleActions, d as ModuleQueries, M as ModuleStates, O as OutputOf, P as PaginationMeta, n as RefreshTokenConfig, k as TokenManager, T as Tokens, r as UrlSyncOptions, U as UseApiConfig, a as UseApiModuleOptions, b as UseApiModuleReturn, p as UseApiState, V as ValidationError, t } from './apiModule.types-DEskFzOY.cjs';
4
- export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-mpeiDoxm.cjs';
2
+ import { f as ApiClientConfig, A as ActionConfigModule, S as StandardResponse, g as ActionOptions, R as RequestConfig, h as ActionStateModule, Q as QueryOptions, i as UseApiQuery, j as ApiError, L as LogLevel } from './apiModule.types-hGWAkTwf.cjs';
3
+ export { o as ActionConfig, u as ActionMethods, q as ActionState, s as ActionsWithQuery, a as ApiModuleConfig, E as ExecutableAction, r as ExecuteOptions, I as InputOf, m as Middleware, l as MiddlewareContext, d as ModuleActions, e as ModuleQueries, M as ModuleStates, O as OutputOf, P as PaginationMeta, n as RefreshTokenConfig, k as TokenManager, T as Tokens, U as UseApiConfig, b as UseApiModuleOptions, c as UseApiModuleReturn, p as UseApiState, V as ValidationError, t } from './apiModule.types-hGWAkTwf.cjs';
4
+ export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-V-4fiB7L.cjs';
5
5
  import 'react';
6
6
 
7
7
  declare function createApiClient(config: ApiClientConfig): AxiosInstance;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AxiosInstance, AxiosRequestConfig, Method, AxiosResponse, AxiosError } from 'axios';
2
- import { e as ApiClientConfig, f as ActionConfigModule, S as StandardResponse, g as ActionOptions, R as RequestConfig, h as ActionStateModule, Q as QueryOptions, i as UseApiQuery, j as ApiError, L as LogLevel } from './apiModule.types-DEskFzOY.js';
3
- export { o as ActionConfig, v as ActionMethods, q as ActionState, u as ActionsWithQuery, A as ApiModuleConfig, E as ExecutableAction, s as ExecuteOptions, I as InputOf, m as Middleware, l as MiddlewareContext, c as ModuleActions, d as ModuleQueries, M as ModuleStates, O as OutputOf, P as PaginationMeta, n as RefreshTokenConfig, k as TokenManager, T as Tokens, r as UrlSyncOptions, U as UseApiConfig, a as UseApiModuleOptions, b as UseApiModuleReturn, p as UseApiState, V as ValidationError, t } from './apiModule.types-DEskFzOY.js';
4
- export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-C31nzgeP.js';
2
+ import { f as ApiClientConfig, A as ActionConfigModule, S as StandardResponse, g as ActionOptions, R as RequestConfig, h as ActionStateModule, Q as QueryOptions, i as UseApiQuery, j as ApiError, L as LogLevel } from './apiModule.types-hGWAkTwf.js';
3
+ export { o as ActionConfig, u as ActionMethods, q as ActionState, s as ActionsWithQuery, a as ApiModuleConfig, E as ExecutableAction, r as ExecuteOptions, I as InputOf, m as Middleware, l as MiddlewareContext, d as ModuleActions, e as ModuleQueries, M as ModuleStates, O as OutputOf, P as PaginationMeta, n as RefreshTokenConfig, k as TokenManager, T as Tokens, U as UseApiConfig, b as UseApiModuleOptions, c as UseApiModuleReturn, p as UseApiState, V as ValidationError, t } from './apiModule.types-hGWAkTwf.js';
4
+ export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-BJop2XPB.js';
5
5
  import 'react';
6
6
 
7
7
  declare function createApiClient(config: ApiClientConfig): AxiosInstance;
package/dist/server.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AxiosInstance } from 'axios';
2
- import { f as ActionConfigModule, A as ApiModuleConfig, I as InputOf } from './apiModule.types-DEskFzOY.cjs';
2
+ import { A as ActionConfigModule, a as ApiModuleConfig, I as InputOf } from './apiModule.types-hGWAkTwf.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 { f as ActionConfigModule, A as ApiModuleConfig, I as InputOf } from './apiModule.types-DEskFzOY.js';
2
+ import { A as ActionConfigModule, a as ApiModuleConfig, I as InputOf } from './apiModule.types-hGWAkTwf.js';
3
3
  import 'react';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { Dispatch, SetStateAction } from 'react';
2
- import { R as RequestConfig, j as ApiError, S as StandardResponse, g as ActionOptions } from './apiModule.types-DEskFzOY.js';
2
+ import { R as RequestConfig, j as ApiError, S as StandardResponse, g as ActionOptions } from './apiModule.types-hGWAkTwf.js';
3
3
 
4
4
  /**
5
5
  * Represents the internal state of the `useApiRecord` hook.
@@ -1,5 +1,5 @@
1
1
  import { Dispatch, SetStateAction } from 'react';
2
- import { R as RequestConfig, j as ApiError, S as StandardResponse, g as ActionOptions } from './apiModule.types-DEskFzOY.cjs';
2
+ import { R as RequestConfig, j as ApiError, S as StandardResponse, g as ActionOptions } from './apiModule.types-hGWAkTwf.cjs';
3
3
 
4
4
  /**
5
5
  * Represents the internal state of the `useApiRecord` hook.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-core-lib",
3
- "version": "16.12.134",
3
+ "version": "16.12.136",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "type": "module",
6
6
  "exports": {