api-core-lib 12.0.88 → 12.0.91

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.
@@ -1,5 +1,5 @@
1
1
  import { AxiosRequestConfig, AxiosProgressEvent, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
2
- import React__default from 'react';
2
+ import react__default from 'react';
3
3
 
4
4
  /**
5
5
  * يمثل معلومات الترقيم (Pagination) التي قد تعود من ה-API.
@@ -156,7 +156,7 @@ interface UseApiQuery {
156
156
  /** The current query options state. */
157
157
  options: QueryOptions;
158
158
  /** A function to set the entire query options object at once. */
159
- setOptions: React__default.Dispatch<React__default.SetStateAction<QueryOptions>>;
159
+ setOptions: react__default.Dispatch<react__default.SetStateAction<QueryOptions>>;
160
160
  /** Sets the current page number. */
161
161
  setPage: (page: number) => void;
162
162
  /** Sets the number of items per page and resets to the first page. */
@@ -287,4 +287,4 @@ type ActionMethods<TAction extends ActionConfigModule<any, any>> = {
287
287
  }) => void;
288
288
  };
289
289
 
290
- 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, UseApiQuery as e, ApiClientConfig as f, ActionOptions as g, ActionStateModule as h, ApiError as i, TokenManager as j, MiddlewareContext as k, Middleware as l, RefreshTokenConfig as m, ActionConfig as n, UseApiState as o, ActionState as p, ExecuteOptions as q, ActionsWithQuery as r, ActionMethods as s, t };
290
+ 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, UseApiQuery as e, ActionsWithQuery as f, ApiClientConfig as g, ActionOptions as h, ActionStateModule 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, ActionMethods as s, t };
@@ -1,5 +1,5 @@
1
1
  import { AxiosRequestConfig, AxiosProgressEvent, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
2
- import React__default from 'react';
2
+ import react__default from 'react';
3
3
 
4
4
  /**
5
5
  * يمثل معلومات الترقيم (Pagination) التي قد تعود من ה-API.
@@ -156,7 +156,7 @@ interface UseApiQuery {
156
156
  /** The current query options state. */
157
157
  options: QueryOptions;
158
158
  /** A function to set the entire query options object at once. */
159
- setOptions: React__default.Dispatch<React__default.SetStateAction<QueryOptions>>;
159
+ setOptions: react__default.Dispatch<react__default.SetStateAction<QueryOptions>>;
160
160
  /** Sets the current page number. */
161
161
  setPage: (page: number) => void;
162
162
  /** Sets the number of items per page and resets to the first page. */
@@ -287,4 +287,4 @@ type ActionMethods<TAction extends ActionConfigModule<any, any>> = {
287
287
  }) => void;
288
288
  };
289
289
 
290
- 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, UseApiQuery as e, ApiClientConfig as f, ActionOptions as g, ActionStateModule as h, ApiError as i, TokenManager as j, MiddlewareContext as k, Middleware as l, RefreshTokenConfig as m, ActionConfig as n, UseApiState as o, ActionState as p, ExecuteOptions as q, ActionsWithQuery as r, ActionMethods as s, t };
290
+ 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, UseApiQuery as e, ActionsWithQuery as f, ApiClientConfig as g, ActionOptions as h, ActionStateModule 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, ActionMethods as s, t };
package/dist/cli.cjs CHANGED
@@ -328,7 +328,7 @@ async function generateModuleFiles(module2, allSchemas, allEnums, outputDir) {
328
328
  const createdFileExports = ["config"];
329
329
  let configContent = `// This file is auto-generated. Do not edit directly.
330
330
 
331
- import type { ApiModuleConfig, ActionConfigModule } from 'api-core-lib';
331
+ import type { ApiModuleConfig, ActionConfigModule, QueryOptions } from 'api-core-lib';
332
332
  `;
333
333
  if (schemasToImport.length > 0) configContent += `import type { ${schemasToImport.join(", ")} } from './types';
334
334
  `;
@@ -447,15 +447,13 @@ import type { ${schemasToImport.join(", ")} } from './types';
447
447
  }
448
448
  const indexFilePath = import_path.default.join(moduleOutputPath, "index.ts");
449
449
  const initialIndexContent = `// This file is auto-generated. Do not edit directly.
450
+ // This file is the main entry point for client-side code.
450
451
 
451
452
  ` + createdFileExports.map((e) => `export * from './${e}';`).join("\n");
452
453
  import_fs.default.writeFileSync(indexFilePath, initialIndexContent);
453
- console.log(import_chalk.default.gray(` \u2713 index.ts (Initial)`));
454
+ console.log(import_chalk.default.gray(` \u2713 index.ts (Initial Client Entry Point)`));
454
455
  const moduleBaseName = module2.moduleName.replace(/Api$/, "");
455
456
  const camelCaseModuleName = toCamelCase(moduleBaseName);
456
- const allPathParams = /* @__PURE__ */ new Set();
457
- Object.values(module2.actions).forEach((action) => action.pathParams.forEach((param) => allPathParams.add(param)));
458
- const pathParamsType = allPathParams.size > 0 ? `{ ${[...allPathParams].map((p) => `${p}?: string | number`).join("; ")} }` : "Record<string, never>";
459
457
  let endpointsContent = `// This file is auto-generated. Do not edit directly.
460
458
 
461
459
  `;
@@ -463,7 +461,7 @@ import type { ${schemasToImport.join(", ")} } from './types';
463
461
  `;
464
462
  const endpointTypesToImport = /* @__PURE__ */ new Set();
465
463
  Object.values(module2.actions).forEach((action) => {
466
- if (action.inputType !== "undefined" && action.inputType !== "QueryOptions") {
464
+ if (action.inputType !== "undefined" && action.inputType !== "QueryOptions" && !BUILT_IN_TYPES.has(action.inputType)) {
467
465
  endpointTypesToImport.add(action.inputType);
468
466
  }
469
467
  });
@@ -498,7 +496,7 @@ import type { ${schemasToImport.join(", ")} } from './types';
498
496
  `;
499
497
  if (action.inputType !== "undefined" && action.inputType !== "QueryOptions") endpointsContent += ` input: body,
500
498
  `;
501
- if (action.hasQuery) endpointsContent += ` input: query,
499
+ else if (action.hasQuery) endpointsContent += ` input: query,
502
500
  `;
503
501
  endpointsContent += ` }),
504
502
 
@@ -506,38 +504,24 @@ import type { ${schemasToImport.join(", ")} } from './types';
506
504
  }
507
505
  endpointsContent += `};
508
506
  `;
509
- import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, `${camelCaseModuleName}.endpoints.ts`), endpointsContent);
507
+ import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, `${camelCaseModuleName}.endpoints.ts`), endpointsContent.trim());
510
508
  console.log(import_chalk.default.gray(` \u2713 ${camelCaseModuleName}.endpoints.ts (Type-Safe Endpoints)`));
511
- const hookContent = `// This file is auto-generated. Do not edit directly.
509
+ const contextFileContent = `// This file is auto-generated. Do not edit directly.
510
+ 'use client';
512
511
 
513
- import { useApiModule, UseApiModuleOptions } from 'api-core-lib/client';
512
+ import React from 'react';
513
+ import { createApiModuleContext, useApiModule, UseApiModuleOptions } from 'api-core-lib/client';
514
514
  import { apiClient } from '@/lib/api-core/clientApi'; // Assuming a fixed path
515
- import { ${module2.moduleName} as TModuleType } from './config';
516
- import { ${module2.moduleName} } from './config';
515
+ import { ${module2.moduleName}, ${module2.moduleName} as TModuleType } from './config';
517
516
 
518
- type ModulePathParams = ${pathParamsType};
517
+ const {
518
+ Provider,
519
+ useContext: use${moduleBaseName}Context
520
+ } = createApiModuleContext<typeof TModuleType['actions']>();
519
521
 
520
- type ${moduleBaseName}ApiOptions = Omit<UseApiModuleOptions, 'pathParams'> & {
521
- pathParams?: ModulePathParams;
522
- };
522
+ export { use${moduleBaseName}Context };
523
523
 
524
- /**
525
- * Custom hook for interacting with the ${moduleBaseName} API module.
526
- */
527
- export const use${moduleBaseName}Api = (options: ${moduleBaseName}ApiOptions = {}) => {
528
- return useApiModule<typeof TModuleType['actions']>(apiClient, ${module2.moduleName}, options);
529
- };
530
- `;
531
- import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, `use${moduleBaseName}.ts`), hookContent);
532
- console.log(import_chalk.default.gray(` \u2713 use${moduleBaseName}.ts (Custom Hook)`));
533
- const providerContent = `// This file is auto-generated. Do not edit directly.
534
- 'use client';
535
-
536
- import React from 'react';
537
- import { ApiModuleProvider } from 'api-core-lib/client';
538
- import { use${moduleBaseName}Api } from './use${moduleBaseName}';
539
-
540
- type Options = Parameters<typeof use${moduleBaseName}Api>[0];
524
+ type Options = Parameters<typeof useApiModule>[2];
541
525
 
542
526
  interface ${moduleBaseName}ProviderProps {
543
527
  children: React.ReactNode;
@@ -548,14 +532,14 @@ interface ${moduleBaseName}ProviderProps {
548
532
  * A dedicated React Provider that initializes and provides the ${moduleBaseName} API context.
549
533
  */
550
534
  export function ${moduleBaseName}Provider({ children, options = {} }: ${moduleBaseName}ProviderProps) {
551
- const api = use${moduleBaseName}Api(options);
552
- return <ApiModuleProvider value={api}>{children}</ApiModuleProvider>;
535
+ const api = useApiModule(apiClient, ${module2.moduleName}, options);
536
+ return <Provider value={api}>{children}</Provider>;
553
537
  }
554
538
  `;
555
- const providerFileName = `${moduleBaseName}.provider.tsx`;
556
- import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, providerFileName), providerContent);
557
- console.log(import_chalk.default.gray(` \u2713 ${providerFileName} (React Provider)`));
558
- const serverContent = `// This file is auto-generated. For server-side use only.
539
+ const contextFileName = `${camelCaseModuleName}.context.tsx`;
540
+ import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, contextFileName), contextFileContent.trim());
541
+ console.log(import_chalk.default.gray(` \u2713 ${contextFileName} (Strongly-Typed Context & Provider)`));
542
+ const serverHelperContent = `// This file is auto-generated. For server-side use only.
559
543
 
560
544
  import { createServerApi } from 'api-core-lib/server';
561
545
  import { serverApiClient } from '@/lib/api-core/serverApi'; // Assuming a fixed path
@@ -568,18 +552,25 @@ export const create${moduleBaseName}ServerApi = () => {
568
552
  return createServerApi(serverApiClient, ${module2.moduleName});
569
553
  };
570
554
  `;
571
- import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, `${camelCaseModuleName}.server.ts`), serverContent);
555
+ import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, `${camelCaseModuleName}.server.ts`), serverHelperContent.trim());
572
556
  console.log(import_chalk.default.gray(` \u2713 ${camelCaseModuleName}.server.ts (Server-Side Helper)`));
573
- const newExports = [
557
+ const clientExports = [
574
558
  `
575
- // Generated API helpers`,
559
+ // Generated API client helpers`,
576
560
  `export * from './${camelCaseModuleName}.endpoints';`,
577
- `export * from './use${moduleBaseName}';`,
578
- `export * from './${moduleBaseName}.provider';`,
579
- `export * from './${camelCaseModuleName}.server';`
561
+ `export * from './${camelCaseModuleName}.context';`
580
562
  ].join("\n");
581
- import_fs.default.appendFileSync(indexFilePath, newExports);
582
- console.log(import_chalk.default.gray(` \u2713 index.ts (Updated with helpers)`));
563
+ import_fs.default.appendFileSync(indexFilePath, clientExports);
564
+ console.log(import_chalk.default.gray(` \u2713 index.ts (Updated with client helpers)`));
565
+ const serverEntryPointContent = `// This file is auto-generated. For server-side use only.
566
+ // It serves as the entry point for server-specific utilities.
567
+
568
+ export * from './${camelCaseModuleName}.server';
569
+ // Also exporting endpoints, as they are environment-agnostic and useful on the server.
570
+ export * from './${camelCaseModuleName}.endpoints';
571
+ `;
572
+ import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "server.ts"), serverEntryPointContent);
573
+ console.log(import_chalk.default.gray(` \u2713 server.ts (New Server Entry Point)`));
583
574
  }
584
575
  function _propToMock(prop) {
585
576
  if (prop.example) return prop.example;
package/dist/client.cjs CHANGED
@@ -270,15 +270,19 @@ function useDeepCompareEffect(callback, dependencies) {
270
270
  _react.useEffect.call(void 0, callback, [currentDependenciesRef.current]);
271
271
  }
272
272
 
273
- // src/hooks/useApiModule/useApiModule.ts
273
+ // src/hooks/useApiModule/useApiModule.v1.ts
274
274
 
275
275
  var ApiModuleContext = _react.createContext.call(void 0, null);
276
276
  var ApiModuleProvider = ApiModuleContext.Provider;
277
277
  var createInitialState = () => ({
278
278
  data: null,
279
279
  lastSuccessAt: void 0,
280
- meta: [],
281
- validationErrors: [],
280
+ meta: void 0,
281
+ // meta هو كائن، وليس مصفوفة
282
+ links: void 0,
283
+ // links هو كائن، وليس مصفوفة
284
+ validationErrors: void 0,
285
+ // validationErrors هو مصفوفة، ولكن يمكن أن يكون غير موجود
282
286
  error: null,
283
287
  loading: false,
284
288
  success: false,
@@ -287,34 +291,29 @@ var createInitialState = () => ({
287
291
  rawResponse: null
288
292
  });
289
293
  function useApiActionState(actionConfig, cacheKey, execute, input, enabled) {
290
- const getClientSnapshot = () => _chunk25UFVV4Fcjs.globalStateManager.getSnapshot(cacheKey);
291
- const getServerSnapshot = () => _chunk25UFVV4Fcjs.globalStateManager.getSnapshot(cacheKey);
294
+ const getClientSnapshot = _react.useCallback.call(void 0, () => _chunk25UFVV4Fcjs.globalStateManager.getSnapshot(cacheKey), [cacheKey]);
295
+ const getServerSnapshot = _react.useCallback.call(void 0, () => _chunk25UFVV4Fcjs.globalStateManager.getSnapshot(cacheKey), [cacheKey]);
292
296
  const state = _react.useSyncExternalStore.call(void 0,
293
297
  (callback) => _chunk25UFVV4Fcjs.globalStateManager.subscribe(cacheKey, callback),
294
298
  getClientSnapshot,
295
299
  getServerSnapshot
296
300
  );
297
- const inputRef = _react.useRef.call(void 0, input);
298
- _react.useEffect.call(void 0, () => {
299
- inputRef.current = input;
300
- }, [input]);
301
301
  const refetch = _react.useCallback.call(void 0, () => {
302
- execute(inputRef.current);
303
- }, [execute]);
304
- const prevCacheKeyRef = _react.useRef.call(void 0, cacheKey);
302
+ execute(input);
303
+ }, [execute, input]);
304
+ const prevStateRef = _react.useRef.call(void 0, );
305
305
  _react.useEffect.call(void 0, () => {
306
- if (prevCacheKeyRef.current !== cacheKey && enabled && state.called) {
307
- console.log(`[Cache Key Changed] from ${prevCacheKeyRef.current} to ${cacheKey}. Refetching...`);
306
+ const currentState = state || createInitialState();
307
+ const previousState = prevStateRef.current;
308
+ if (enabled && actionConfig.autoFetch && !currentState.called && !currentState.loading) {
308
309
  refetch();
309
- } else if (enabled && actionConfig.autoFetch && !state.called && !state.loading) {
310
- console.log(`[Auto Fetch] for ${cacheKey}. Fetching...`);
310
+ } else if (enabled && currentState.isStale && !currentState.loading) {
311
311
  refetch();
312
- } else if (enabled && state.isStale && !state.loading) {
313
- console.log(`[Stale State] for ${cacheKey}. Refetching...`);
312
+ } else if (enabled && _optionalChain([previousState, 'optionalAccess', _6 => _6.called]) && !currentState.loading && cacheKey !== _optionalChain([prevStateRef, 'access', _7 => _7.current, 'optionalAccess', _8 => _8.cacheKey])) {
314
313
  refetch();
315
314
  }
316
- prevCacheKeyRef.current = cacheKey;
317
- }, [cacheKey, enabled, state.isStale, state.loading, state.called, actionConfig.autoFetch, refetch]);
315
+ prevStateRef.current = { ...currentState, cacheKey };
316
+ }, [cacheKey, enabled, state, actionConfig.autoFetch, refetch]);
318
317
  return state;
319
318
  }
320
319
  function useModuleContext() {
@@ -340,15 +339,7 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
340
339
  _react.useEffect.call(void 0, () => {
341
340
  savedCallbacks.current = { onSuccess, onError };
342
341
  }, [onSuccess, onError]);
343
- _react.useMemo.call(void 0, () => {
344
- if (hydratedState) {
345
- _chunk25UFVV4Fcjs.globalStateManager.rehydrate(hydratedState);
346
- }
347
- }, [hydratedState]);
348
342
  _react.useEffect.call(void 0, () => {
349
- savedCallbacks.current = { onSuccess, onError };
350
- }, [onSuccess, onError]);
351
- _react.useMemo.call(void 0, () => {
352
343
  if (hydratedState) {
353
344
  _chunk25UFVV4Fcjs.globalStateManager.rehydrate(hydratedState);
354
345
  }
@@ -358,7 +349,7 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
358
349
  const actionConfig = moduleConfig.actions[actionName];
359
350
  const shouldCache = actionConfig.cacheResponse !== false;
360
351
  const execute = async (input, options2 = {}) => {
361
- const finalPathParams = { ...JSON.parse(pathParamsString), ...options2.pathParams };
352
+ const finalPathParams = { ...modulePathParams || {}, ...options2.pathParams };
362
353
  const cacheKey = shouldCache ? _chunk25UFVV4Fcjs.generateCacheKey.call(void 0, moduleConfig.baseEndpoint, actionName, input, { pathParams: finalPathParams }) : "";
363
354
  let mutationContext;
364
355
  try {
@@ -373,48 +364,41 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
373
364
  body: input,
374
365
  config: options2.config
375
366
  });
376
- console.log("[API Result execute]", result);
377
367
  if (shouldCache) {
378
368
  _chunk25UFVV4Fcjs.globalStateManager.setState(cacheKey, (prev) => ({
379
369
  ...prev,
380
- // احتفظ بالخصائص القديمة مثل 'called'
381
370
  loading: false,
382
371
  success: result.success,
383
- // تحديث صريح
384
372
  error: result.success ? null : result.error || prev.error,
385
- // تحديث صريح
386
- data: result.data,
387
- // تحديث صريح للبيانات
373
+ data: result.success ? result.data : prev.data,
374
+ // ✅ [تحسين] لا تمسح البيانات القديمة عند حدوث خطأ
388
375
  meta: result.meta,
389
- // تحديث صريح
390
376
  links: result.links,
391
- // تحديث صريح
392
377
  message: result.message,
393
- validationErrors: result.validationErrors || [],
394
- rawResponse: result.rawResponse
395
- // isStale تم تعيينه إلى false في بداية execute، وسيظل كذلك
378
+ validationErrors: result.validationErrors,
379
+ rawResponse: result.rawResponse,
380
+ lastSuccessAt: result.success ? Date.now() : prev.lastSuccessAt
396
381
  }));
397
382
  }
398
383
  if (result.success) {
399
- _optionalChain([savedCallbacks, 'access', _6 => _6.current, 'access', _7 => _7.onSuccess, 'optionalCall', _8 => _8(actionName, result.message || "Action successful", result.data)]);
400
- _optionalChain([options2, 'access', _9 => _9.onSuccess, 'optionalCall', _10 => _10(result.data, mutationContext)]);
401
- _optionalChain([actionConfig, 'access', _11 => _11.invalidates, 'optionalAccess', _12 => _12.forEach, 'call', _13 => _13((keyToInvalidate) => {
384
+ _optionalChain([savedCallbacks, 'access', _9 => _9.current, 'access', _10 => _10.onSuccess, 'optionalCall', _11 => _11(actionName, result.message || "Action successful", result.data)]);
385
+ _optionalChain([options2, 'access', _12 => _12.onSuccess, 'optionalCall', _13 => _13(result.data, mutationContext)]);
386
+ _optionalChain([actionConfig, 'access', _14 => _14.invalidates, 'optionalAccess', _15 => _15.forEach, 'call', _16 => _16((keyToInvalidate) => {
402
387
  const prefix = `${moduleConfig.baseEndpoint}/${keyToInvalidate}::`;
403
- console.log(`[Invalidating] by prefix: ${prefix}`);
404
388
  _chunk25UFVV4Fcjs.globalStateManager.invalidateByPrefix(prefix);
405
389
  })]);
406
390
  } else {
407
- _optionalChain([savedCallbacks, 'access', _14 => _14.current, 'access', _15 => _15.onError, 'optionalCall', _16 => _16(actionName, result.message || "Action failed", _nullishCoalesce(result.error, () => ( void 0)))]);
408
- _optionalChain([options2, 'access', _17 => _17.onError, 'optionalCall', _18 => _18(result.error, mutationContext)]);
391
+ _optionalChain([savedCallbacks, 'access', _17 => _17.current, 'access', _18 => _18.onError, 'optionalCall', _19 => _19(actionName, result.message || "Action failed", _nullishCoalesce(result.error, () => ( void 0)))]);
392
+ _optionalChain([options2, 'access', _20 => _20.onError, 'optionalCall', _21 => _21(result.error, mutationContext)]);
409
393
  }
410
394
  return result;
411
395
  } catch (error) {
412
- const apiError = _optionalChain([error, 'access', _19 => _19.response, 'optionalAccess', _20 => _20.data]) || { status: 500, message: error.message };
396
+ const apiError = _optionalChain([error, 'access', _22 => _22.response, 'optionalAccess', _23 => _23.data]) || { status: 500, message: error.message };
413
397
  if (shouldCache) {
414
398
  _chunk25UFVV4Fcjs.globalStateManager.setState(cacheKey, (prev) => ({ ...prev, error: apiError, loading: false, success: false }));
415
399
  }
416
- _optionalChain([savedCallbacks, 'access', _21 => _21.current, 'access', _22 => _22.onError, 'optionalCall', _23 => _23(actionName, apiError.message, apiError)]);
417
- _optionalChain([options2, 'access', _24 => _24.onError, 'optionalCall', _25 => _25(apiError, mutationContext)]);
400
+ _optionalChain([savedCallbacks, 'access', _24 => _24.current, 'access', _25 => _25.onError, 'optionalCall', _26 => _26(actionName, apiError.message, apiError)]);
401
+ _optionalChain([options2, 'access', _27 => _27.onError, 'optionalCall', _28 => _28(apiError, mutationContext)]);
418
402
  throw error;
419
403
  } finally {
420
404
  if (options2.onSettled) {
@@ -424,7 +408,7 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
424
408
  };
425
409
  const reset = (input, options2 = {}) => {
426
410
  if (shouldCache) {
427
- const finalPathParams = { ...JSON.parse(pathParamsString), ...options2.pathParams };
411
+ const finalPathParams = { ...modulePathParams || {}, ...options2.pathParams };
428
412
  const cacheKey = _chunk25UFVV4Fcjs.generateCacheKey.call(void 0, moduleConfig.baseEndpoint, actionName, input, { pathParams: finalPathParams });
429
413
  _chunk25UFVV4Fcjs.globalStateManager.setState(cacheKey, () => createInitialState());
430
414
  }
@@ -432,11 +416,11 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
432
416
  acc[actionName] = { execute, reset };
433
417
  return acc;
434
418
  }, {});
435
- }, [axiosInstance, moduleConfig, pathParamsString]);
419
+ }, [axiosInstance, moduleConfig, modulePathParams]);
436
420
  const queries = _react.useMemo.call(void 0, () => {
437
421
  const builtQueries = {};
438
422
  for (const actionName in moduleConfig.actions) {
439
- if (_optionalChain([moduleConfig, 'access', _26 => _26.actions, 'access', _27 => _27[actionName], 'optionalAccess', _28 => _28.hasQuery])) {
423
+ if (_optionalChain([moduleConfig, 'access', _29 => _29.actions, 'access', _30 => _30[actionName], 'optionalAccess', _31 => _31.hasQuery])) {
440
424
  const setActionQueryOptions = (updater) => {
441
425
  setQueryOptions((prev) => ({ ...prev, [actionName]: typeof updater === "function" ? updater(prev[actionName] || {}) : updater }));
442
426
  };
@@ -448,50 +432,42 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
448
432
  setSearchTerm: (search) => setActionQueryOptions((p) => ({ ...p, search, page: 1 })),
449
433
  setFilters: (filter) => setActionQueryOptions((p) => ({ ...p, filter, page: 1 })),
450
434
  setSorting: (sortBy) => setActionQueryOptions((p) => ({ ...p, sortBy })),
451
- setQueryParam: (key, value) => setActionQueryOptions((p) => ({ ...p, [key]: value, page: key !== "page" ? value : p.page })),
435
+ setQueryParam: (key, value) => setActionQueryOptions((p) => ({ ...p, [key]: value, page: key !== "page" ? 1 : value })),
452
436
  reset: () => setActionQueryOptions({})
453
437
  };
454
438
  }
455
439
  }
456
440
  return builtQueries;
457
441
  }, [queryOptions, moduleConfig.actions]);
458
- const states = {};
459
- function isActionWithQuery(key, actions2) {
460
- return _optionalChain([actions2, 'access', _29 => _29[key], 'optionalAccess', _30 => _30.hasQuery]) === true;
461
- }
462
- for (const actionName in moduleConfig.actions) {
463
- if (Object.prototype.hasOwnProperty.call(moduleConfig.actions, actionName)) {
464
- const actionConfig = moduleConfig.actions[actionName];
465
- if (actionConfig.cacheResponse !== false) {
466
- let queryOptions2;
467
- if (isActionWithQuery(actionName, moduleConfig.actions)) {
468
- queryOptions2 = _optionalChain([queries, 'access', _31 => _31[actionName], 'optionalAccess', _32 => _32.options]);
442
+ const states = _react.useMemo.call(void 0, () => {
443
+ const builtStates = {};
444
+ for (const actionName in moduleConfig.actions) {
445
+ if (Object.prototype.hasOwnProperty.call(moduleConfig.actions, actionName)) {
446
+ const actionConfig = moduleConfig.actions[actionName];
447
+ if (actionConfig.cacheResponse !== false) {
448
+ const query = _optionalChain([queries, 'access', _32 => _32[actionName], 'optionalAccess', _33 => _33.options]);
449
+ const input = actionConfig.hasQuery ? query : void 0;
450
+ const cacheKey = _chunk25UFVV4Fcjs.generateCacheKey.call(void 0, moduleConfig.baseEndpoint, actionName, input, { pathParams: modulePathParams });
451
+ builtStates[actionName] = useApiActionState(
452
+ actionConfig,
453
+ cacheKey,
454
+ actions[actionName].execute,
455
+ input,
456
+ enabled
457
+ );
458
+ } else {
459
+ builtStates[actionName] = createInitialState();
469
460
  }
470
- const input = queryOptions2;
471
- const pathParams = JSON.parse(pathParamsString);
472
- const cacheKey = _chunk25UFVV4Fcjs.generateCacheKey.call(void 0,
473
- moduleConfig.baseEndpoint,
474
- actionName,
475
- input,
476
- { pathParams }
477
- );
478
- states[actionName] = useApiActionState(
479
- actionConfig,
480
- cacheKey,
481
- actions[actionName].execute,
482
- input,
483
- enabled
484
- );
485
- } else {
486
- states[actionName] = createInitialState();
487
461
  }
488
462
  }
489
- }
463
+ return builtStates;
464
+ }, [moduleConfig, queries, actions, modulePathParams, enabled]);
490
465
  const lastBlurTimestamp = _react.useRef.call(void 0, Date.now());
491
466
  _react.useEffect.call(void 0, () => {
492
467
  if (!enabled || !refetchOnWindowFocus) return;
493
468
  const onFocus = () => {
494
- if (Date.now() - lastBlurTimestamp.current > 1e4) {
469
+ if (Date.now() - lastBlurTimestamp.current > 3e4) {
470
+ console.log("[Refetch on Focus] Invalidating all called queries for this module.");
495
471
  const actionKeys = Object.keys(moduleConfig.actions);
496
472
  for (const actionName of actionKeys) {
497
473
  const state = states[actionName];
@@ -512,15 +488,37 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
512
488
  window.removeEventListener("blur", onBlur);
513
489
  };
514
490
  }, [enabled, refetchOnWindowFocus, moduleConfig, states]);
515
- const dehydrate = _react.useMemo.call(void 0, () => {
516
- return () => _chunk25UFVV4Fcjs.globalStateManager.dehydrate();
491
+ const dehydrate = _react.useCallback.call(void 0, () => {
492
+ return _chunk25UFVV4Fcjs.globalStateManager.dehydrate();
517
493
  }, []);
518
- const baseApiReturn = { actions, states, queries, dehydrate };
519
- const finalApiReturn = _react.useMemo.call(void 0, () => ({
520
- ...baseApiReturn,
494
+ return _react.useMemo.call(void 0, () => ({
495
+ actions,
496
+ states,
497
+ queries,
498
+ dehydrate,
521
499
  ...extraContextData || {}
522
- }), [baseApiReturn, extraContextData]);
523
- return finalApiReturn;
500
+ }), [actions, states, queries, dehydrate, extraContextData]);
501
+ }
502
+
503
+ // src/hooks/useApiModule/apiModuleContext.ts
504
+
505
+ function createApiModuleContext() {
506
+ const Context = _react.createContext.call(void 0, null);
507
+ const Provider = ({ value, children }) => {
508
+ return _react.createElement.call(void 0, Context.Provider, { value }, children);
509
+ };
510
+ const useConsumer = () => {
511
+ const context = _react.useContext.call(void 0, Context);
512
+ if (!context) {
513
+ throw new Error("This component must be used within its corresponding ApiModuleProvider.");
514
+ }
515
+ return context;
516
+ };
517
+ return {
518
+ Context,
519
+ Provider,
520
+ useContext: useConsumer
521
+ };
524
522
  }
525
523
 
526
524
 
@@ -529,4 +527,5 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
529
527
 
530
528
 
531
529
 
532
- exports.ApiModuleProvider = ApiModuleProvider; exports.useApi = useApi; exports.useApiModule = useApiModule; exports.useApiRecord = useApiRecord; exports.useDeepCompareEffect = useDeepCompareEffect; exports.useModuleContext = useModuleContext;
530
+
531
+ exports.ApiModuleProvider = ApiModuleProvider; exports.createApiModuleContext = createApiModuleContext; exports.useApi = useApi; exports.useApiModule = useApiModule; exports.useApiRecord = useApiRecord; exports.useDeepCompareEffect = useDeepCompareEffect; exports.useModuleContext = useModuleContext;
package/dist/client.d.cts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { AxiosInstance } from 'axios';
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 UseApiQuery } from './apiModule.types-Bn0tJF7b.cjs';
3
- import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-NZtPRga3.cjs';
4
- import * as React from 'react';
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 UseApiQuery, f as ActionsWithQuery } from './apiModule.types-CZX-M2Ub.cjs';
3
+ import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-Cq9AlZX2.cjs';
4
+ import * as react from 'react';
5
+ import { ReactNode } from 'react';
5
6
 
6
7
  declare function useApi<T>(axiosInstance: AxiosInstance, config: UseApiConfig<T>): any;
7
8
 
@@ -21,7 +22,7 @@ type EffectCallback = () => (void | (() => void));
21
22
  type DependencyList = readonly any[];
22
23
  declare function useDeepCompareEffect(callback: EffectCallback, dependencies: DependencyList): void;
23
24
 
24
- declare const ApiModuleProvider: React.Provider<{
25
+ declare const ApiModuleProvider: react.Provider<{
25
26
  states: ModuleStates<any>;
26
27
  actions: ModuleActions<any>;
27
28
  queries: {
@@ -32,4 +33,30 @@ declare const ApiModuleProvider: React.Provider<{
32
33
  declare function useModuleContext<TModule extends ApiModuleConfig<any>, TExtra = {}>(): UseApiModuleReturn<TModule['actions'], TExtra>;
33
34
  declare function useApiModule<TActions extends Record<string, ActionConfigModule<any, any>>, TExtra extends object = {}>(axiosInstance: AxiosInstance, moduleConfig: ApiModuleConfig<TActions>, options?: UseApiModuleOptions<TExtra>): UseApiModuleReturn<TActions, TExtra>;
34
35
 
35
- export { ApiModuleProvider, useApi, useApiModule, useApiRecord, useDeepCompareEffect, useModuleContext };
36
+ /**
37
+ * Creates a strongly-typed React Context, Provider, and consumer hook for a specific API module.
38
+ * This pattern avoids the need for manual type assertions in consuming components.
39
+ *
40
+ * @template TActions - The shape of the actions in the API module.
41
+ * @returns An object containing the typed Context, Provider, and a `useContext` hook.
42
+ */
43
+ declare function createApiModuleContext<TActions extends Record<string, any>>(): {
44
+ Context: react.Context<{
45
+ states: ModuleStates<TActions>;
46
+ actions: ModuleActions<TActions>;
47
+ queries: { [K in ActionsWithQuery<TActions>]: UseApiQuery; };
48
+ dehydrate: () => string;
49
+ } | null>;
50
+ Provider: ({ value, children }: {
51
+ value: UseApiModuleReturn<TActions>;
52
+ children: ReactNode;
53
+ }) => react.FunctionComponentElement<react.ProviderProps<{
54
+ states: ModuleStates<TActions>;
55
+ actions: ModuleActions<TActions>;
56
+ queries: { [K in ActionsWithQuery<TActions>]: UseApiQuery; };
57
+ dehydrate: () => string;
58
+ } | null>>;
59
+ useContext: () => UseApiModuleReturn<TActions>;
60
+ };
61
+
62
+ export { ApiModuleProvider, createApiModuleContext, useApi, useApiModule, useApiRecord, useDeepCompareEffect, useModuleContext };
package/dist/client.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { AxiosInstance } from 'axios';
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 UseApiQuery } from './apiModule.types-Bn0tJF7b.js';
3
- import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-CWhwCAB6.js';
4
- import * as React from 'react';
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 UseApiQuery, f as ActionsWithQuery } from './apiModule.types-CZX-M2Ub.js';
3
+ import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-Cye9a7zh.js';
4
+ import * as react from 'react';
5
+ import { ReactNode } from 'react';
5
6
 
6
7
  declare function useApi<T>(axiosInstance: AxiosInstance, config: UseApiConfig<T>): any;
7
8
 
@@ -21,7 +22,7 @@ type EffectCallback = () => (void | (() => void));
21
22
  type DependencyList = readonly any[];
22
23
  declare function useDeepCompareEffect(callback: EffectCallback, dependencies: DependencyList): void;
23
24
 
24
- declare const ApiModuleProvider: React.Provider<{
25
+ declare const ApiModuleProvider: react.Provider<{
25
26
  states: ModuleStates<any>;
26
27
  actions: ModuleActions<any>;
27
28
  queries: {
@@ -32,4 +33,30 @@ declare const ApiModuleProvider: React.Provider<{
32
33
  declare function useModuleContext<TModule extends ApiModuleConfig<any>, TExtra = {}>(): UseApiModuleReturn<TModule['actions'], TExtra>;
33
34
  declare function useApiModule<TActions extends Record<string, ActionConfigModule<any, any>>, TExtra extends object = {}>(axiosInstance: AxiosInstance, moduleConfig: ApiModuleConfig<TActions>, options?: UseApiModuleOptions<TExtra>): UseApiModuleReturn<TActions, TExtra>;
34
35
 
35
- export { ApiModuleProvider, useApi, useApiModule, useApiRecord, useDeepCompareEffect, useModuleContext };
36
+ /**
37
+ * Creates a strongly-typed React Context, Provider, and consumer hook for a specific API module.
38
+ * This pattern avoids the need for manual type assertions in consuming components.
39
+ *
40
+ * @template TActions - The shape of the actions in the API module.
41
+ * @returns An object containing the typed Context, Provider, and a `useContext` hook.
42
+ */
43
+ declare function createApiModuleContext<TActions extends Record<string, any>>(): {
44
+ Context: react.Context<{
45
+ states: ModuleStates<TActions>;
46
+ actions: ModuleActions<TActions>;
47
+ queries: { [K in ActionsWithQuery<TActions>]: UseApiQuery; };
48
+ dehydrate: () => string;
49
+ } | null>;
50
+ Provider: ({ value, children }: {
51
+ value: UseApiModuleReturn<TActions>;
52
+ children: ReactNode;
53
+ }) => react.FunctionComponentElement<react.ProviderProps<{
54
+ states: ModuleStates<TActions>;
55
+ actions: ModuleActions<TActions>;
56
+ queries: { [K in ActionsWithQuery<TActions>]: UseApiQuery; };
57
+ dehydrate: () => string;
58
+ } | null>>;
59
+ useContext: () => UseApiModuleReturn<TActions>;
60
+ };
61
+
62
+ export { ApiModuleProvider, createApiModuleContext, useApi, useApiModule, useApiRecord, useDeepCompareEffect, useModuleContext };
package/dist/client.js CHANGED
@@ -270,15 +270,19 @@ function useDeepCompareEffect(callback, dependencies) {
270
270
  useEffect3(callback, [currentDependenciesRef.current]);
271
271
  }
272
272
 
273
- // src/hooks/useApiModule/useApiModule.ts
273
+ // src/hooks/useApiModule/useApiModule.v1.ts
274
274
  import { createContext, useCallback as useCallback3, useContext, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef4, useState as useState3, useSyncExternalStore } from "react";
275
275
  var ApiModuleContext = createContext(null);
276
276
  var ApiModuleProvider = ApiModuleContext.Provider;
277
277
  var createInitialState = () => ({
278
278
  data: null,
279
279
  lastSuccessAt: void 0,
280
- meta: [],
281
- validationErrors: [],
280
+ meta: void 0,
281
+ // meta هو كائن، وليس مصفوفة
282
+ links: void 0,
283
+ // links هو كائن، وليس مصفوفة
284
+ validationErrors: void 0,
285
+ // validationErrors هو مصفوفة، ولكن يمكن أن يكون غير موجود
282
286
  error: null,
283
287
  loading: false,
284
288
  success: false,
@@ -287,34 +291,29 @@ var createInitialState = () => ({
287
291
  rawResponse: null
288
292
  });
289
293
  function useApiActionState(actionConfig, cacheKey, execute, input, enabled) {
290
- const getClientSnapshot = () => globalStateManager.getSnapshot(cacheKey);
291
- const getServerSnapshot = () => globalStateManager.getSnapshot(cacheKey);
294
+ const getClientSnapshot = useCallback3(() => globalStateManager.getSnapshot(cacheKey), [cacheKey]);
295
+ const getServerSnapshot = useCallback3(() => globalStateManager.getSnapshot(cacheKey), [cacheKey]);
292
296
  const state = useSyncExternalStore(
293
297
  (callback) => globalStateManager.subscribe(cacheKey, callback),
294
298
  getClientSnapshot,
295
299
  getServerSnapshot
296
300
  );
297
- const inputRef = useRef4(input);
298
- useEffect4(() => {
299
- inputRef.current = input;
300
- }, [input]);
301
301
  const refetch = useCallback3(() => {
302
- execute(inputRef.current);
303
- }, [execute]);
304
- const prevCacheKeyRef = useRef4(cacheKey);
302
+ execute(input);
303
+ }, [execute, input]);
304
+ const prevStateRef = useRef4();
305
305
  useEffect4(() => {
306
- if (prevCacheKeyRef.current !== cacheKey && enabled && state.called) {
307
- console.log(`[Cache Key Changed] from ${prevCacheKeyRef.current} to ${cacheKey}. Refetching...`);
306
+ const currentState = state || createInitialState();
307
+ const previousState = prevStateRef.current;
308
+ if (enabled && actionConfig.autoFetch && !currentState.called && !currentState.loading) {
308
309
  refetch();
309
- } else if (enabled && actionConfig.autoFetch && !state.called && !state.loading) {
310
- console.log(`[Auto Fetch] for ${cacheKey}. Fetching...`);
310
+ } else if (enabled && currentState.isStale && !currentState.loading) {
311
311
  refetch();
312
- } else if (enabled && state.isStale && !state.loading) {
313
- console.log(`[Stale State] for ${cacheKey}. Refetching...`);
312
+ } else if (enabled && previousState?.called && !currentState.loading && cacheKey !== prevStateRef.current?.cacheKey) {
314
313
  refetch();
315
314
  }
316
- prevCacheKeyRef.current = cacheKey;
317
- }, [cacheKey, enabled, state.isStale, state.loading, state.called, actionConfig.autoFetch, refetch]);
315
+ prevStateRef.current = { ...currentState, cacheKey };
316
+ }, [cacheKey, enabled, state, actionConfig.autoFetch, refetch]);
318
317
  return state;
319
318
  }
320
319
  function useModuleContext() {
@@ -340,15 +339,7 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
340
339
  useEffect4(() => {
341
340
  savedCallbacks.current = { onSuccess, onError };
342
341
  }, [onSuccess, onError]);
343
- useMemo3(() => {
344
- if (hydratedState) {
345
- globalStateManager.rehydrate(hydratedState);
346
- }
347
- }, [hydratedState]);
348
342
  useEffect4(() => {
349
- savedCallbacks.current = { onSuccess, onError };
350
- }, [onSuccess, onError]);
351
- useMemo3(() => {
352
343
  if (hydratedState) {
353
344
  globalStateManager.rehydrate(hydratedState);
354
345
  }
@@ -358,7 +349,7 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
358
349
  const actionConfig = moduleConfig.actions[actionName];
359
350
  const shouldCache = actionConfig.cacheResponse !== false;
360
351
  const execute = async (input, options2 = {}) => {
361
- const finalPathParams = { ...JSON.parse(pathParamsString), ...options2.pathParams };
352
+ const finalPathParams = { ...modulePathParams || {}, ...options2.pathParams };
362
353
  const cacheKey = shouldCache ? generateCacheKey(moduleConfig.baseEndpoint, actionName, input, { pathParams: finalPathParams }) : "";
363
354
  let mutationContext;
364
355
  try {
@@ -373,26 +364,20 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
373
364
  body: input,
374
365
  config: options2.config
375
366
  });
376
- console.log("[API Result execute]", result);
377
367
  if (shouldCache) {
378
368
  globalStateManager.setState(cacheKey, (prev) => ({
379
369
  ...prev,
380
- // احتفظ بالخصائص القديمة مثل 'called'
381
370
  loading: false,
382
371
  success: result.success,
383
- // تحديث صريح
384
372
  error: result.success ? null : result.error || prev.error,
385
- // تحديث صريح
386
- data: result.data,
387
- // تحديث صريح للبيانات
373
+ data: result.success ? result.data : prev.data,
374
+ // ✅ [تحسين] لا تمسح البيانات القديمة عند حدوث خطأ
388
375
  meta: result.meta,
389
- // تحديث صريح
390
376
  links: result.links,
391
- // تحديث صريح
392
377
  message: result.message,
393
- validationErrors: result.validationErrors || [],
394
- rawResponse: result.rawResponse
395
- // isStale تم تعيينه إلى false في بداية execute، وسيظل كذلك
378
+ validationErrors: result.validationErrors,
379
+ rawResponse: result.rawResponse,
380
+ lastSuccessAt: result.success ? Date.now() : prev.lastSuccessAt
396
381
  }));
397
382
  }
398
383
  if (result.success) {
@@ -400,7 +385,6 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
400
385
  options2.onSuccess?.(result.data, mutationContext);
401
386
  actionConfig.invalidates?.forEach((keyToInvalidate) => {
402
387
  const prefix = `${moduleConfig.baseEndpoint}/${keyToInvalidate}::`;
403
- console.log(`[Invalidating] by prefix: ${prefix}`);
404
388
  globalStateManager.invalidateByPrefix(prefix);
405
389
  });
406
390
  } else {
@@ -424,7 +408,7 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
424
408
  };
425
409
  const reset = (input, options2 = {}) => {
426
410
  if (shouldCache) {
427
- const finalPathParams = { ...JSON.parse(pathParamsString), ...options2.pathParams };
411
+ const finalPathParams = { ...modulePathParams || {}, ...options2.pathParams };
428
412
  const cacheKey = generateCacheKey(moduleConfig.baseEndpoint, actionName, input, { pathParams: finalPathParams });
429
413
  globalStateManager.setState(cacheKey, () => createInitialState());
430
414
  }
@@ -432,7 +416,7 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
432
416
  acc[actionName] = { execute, reset };
433
417
  return acc;
434
418
  }, {});
435
- }, [axiosInstance, moduleConfig, pathParamsString]);
419
+ }, [axiosInstance, moduleConfig, modulePathParams]);
436
420
  const queries = useMemo3(() => {
437
421
  const builtQueries = {};
438
422
  for (const actionName in moduleConfig.actions) {
@@ -448,50 +432,42 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
448
432
  setSearchTerm: (search) => setActionQueryOptions((p) => ({ ...p, search, page: 1 })),
449
433
  setFilters: (filter) => setActionQueryOptions((p) => ({ ...p, filter, page: 1 })),
450
434
  setSorting: (sortBy) => setActionQueryOptions((p) => ({ ...p, sortBy })),
451
- setQueryParam: (key, value) => setActionQueryOptions((p) => ({ ...p, [key]: value, page: key !== "page" ? value : p.page })),
435
+ setQueryParam: (key, value) => setActionQueryOptions((p) => ({ ...p, [key]: value, page: key !== "page" ? 1 : value })),
452
436
  reset: () => setActionQueryOptions({})
453
437
  };
454
438
  }
455
439
  }
456
440
  return builtQueries;
457
441
  }, [queryOptions, moduleConfig.actions]);
458
- const states = {};
459
- function isActionWithQuery(key, actions2) {
460
- return actions2[key]?.hasQuery === true;
461
- }
462
- for (const actionName in moduleConfig.actions) {
463
- if (Object.prototype.hasOwnProperty.call(moduleConfig.actions, actionName)) {
464
- const actionConfig = moduleConfig.actions[actionName];
465
- if (actionConfig.cacheResponse !== false) {
466
- let queryOptions2;
467
- if (isActionWithQuery(actionName, moduleConfig.actions)) {
468
- queryOptions2 = queries[actionName]?.options;
442
+ const states = useMemo3(() => {
443
+ const builtStates = {};
444
+ for (const actionName in moduleConfig.actions) {
445
+ if (Object.prototype.hasOwnProperty.call(moduleConfig.actions, actionName)) {
446
+ const actionConfig = moduleConfig.actions[actionName];
447
+ if (actionConfig.cacheResponse !== false) {
448
+ const query = queries[actionName]?.options;
449
+ const input = actionConfig.hasQuery ? query : void 0;
450
+ const cacheKey = generateCacheKey(moduleConfig.baseEndpoint, actionName, input, { pathParams: modulePathParams });
451
+ builtStates[actionName] = useApiActionState(
452
+ actionConfig,
453
+ cacheKey,
454
+ actions[actionName].execute,
455
+ input,
456
+ enabled
457
+ );
458
+ } else {
459
+ builtStates[actionName] = createInitialState();
469
460
  }
470
- const input = queryOptions2;
471
- const pathParams = JSON.parse(pathParamsString);
472
- const cacheKey = generateCacheKey(
473
- moduleConfig.baseEndpoint,
474
- actionName,
475
- input,
476
- { pathParams }
477
- );
478
- states[actionName] = useApiActionState(
479
- actionConfig,
480
- cacheKey,
481
- actions[actionName].execute,
482
- input,
483
- enabled
484
- );
485
- } else {
486
- states[actionName] = createInitialState();
487
461
  }
488
462
  }
489
- }
463
+ return builtStates;
464
+ }, [moduleConfig, queries, actions, modulePathParams, enabled]);
490
465
  const lastBlurTimestamp = useRef4(Date.now());
491
466
  useEffect4(() => {
492
467
  if (!enabled || !refetchOnWindowFocus) return;
493
468
  const onFocus = () => {
494
- if (Date.now() - lastBlurTimestamp.current > 1e4) {
469
+ if (Date.now() - lastBlurTimestamp.current > 3e4) {
470
+ console.log("[Refetch on Focus] Invalidating all called queries for this module.");
495
471
  const actionKeys = Object.keys(moduleConfig.actions);
496
472
  for (const actionName of actionKeys) {
497
473
  const state = states[actionName];
@@ -512,18 +488,41 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
512
488
  window.removeEventListener("blur", onBlur);
513
489
  };
514
490
  }, [enabled, refetchOnWindowFocus, moduleConfig, states]);
515
- const dehydrate = useMemo3(() => {
516
- return () => globalStateManager.dehydrate();
491
+ const dehydrate = useCallback3(() => {
492
+ return globalStateManager.dehydrate();
517
493
  }, []);
518
- const baseApiReturn = { actions, states, queries, dehydrate };
519
- const finalApiReturn = useMemo3(() => ({
520
- ...baseApiReturn,
494
+ return useMemo3(() => ({
495
+ actions,
496
+ states,
497
+ queries,
498
+ dehydrate,
521
499
  ...extraContextData || {}
522
- }), [baseApiReturn, extraContextData]);
523
- return finalApiReturn;
500
+ }), [actions, states, queries, dehydrate, extraContextData]);
501
+ }
502
+
503
+ // src/hooks/useApiModule/apiModuleContext.ts
504
+ import { createContext as createContext2, useContext as useContext2, createElement } from "react";
505
+ function createApiModuleContext() {
506
+ const Context = createContext2(null);
507
+ const Provider = ({ value, children }) => {
508
+ return createElement(Context.Provider, { value }, children);
509
+ };
510
+ const useConsumer = () => {
511
+ const context = useContext2(Context);
512
+ if (!context) {
513
+ throw new Error("This component must be used within its corresponding ApiModuleProvider.");
514
+ }
515
+ return context;
516
+ };
517
+ return {
518
+ Context,
519
+ Provider,
520
+ useContext: useConsumer
521
+ };
524
522
  }
525
523
  export {
526
524
  ApiModuleProvider,
525
+ createApiModuleContext,
527
526
  useApi,
528
527
  useApiModule,
529
528
  useApiRecord,
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { AxiosInstance, AxiosRequestConfig, Method, AxiosResponse, AxiosError } from 'axios';
2
- import { f as ApiClientConfig, A as ActionConfigModule, S as StandardResponse, g as ActionOptions, R as RequestConfig, h as ActionStateModule, Q as QueryOptions, e as UseApiQuery, i as ApiError, L as LogLevel } from './apiModule.types-Bn0tJF7b.cjs';
3
- export { n as ActionConfig, s as ActionMethods, p as ActionState, r as ActionsWithQuery, a as ApiModuleConfig, E as ExecutableAction, q as ExecuteOptions, I as InputOf, l as Middleware, k as MiddlewareContext, d as ModuleActions, M as ModuleStates, O as OutputOf, P as PaginationMeta, m as RefreshTokenConfig, j as TokenManager, T as Tokens, U as UseApiConfig, b as UseApiModuleOptions, c as UseApiModuleReturn, o as UseApiState, V as ValidationError, t } from './apiModule.types-Bn0tJF7b.cjs';
4
- export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-NZtPRga3.cjs';
2
+ import { g as ApiClientConfig, A as ActionConfigModule, S as StandardResponse, h as ActionOptions, R as RequestConfig, i as ActionStateModule, Q as QueryOptions, e as UseApiQuery, j as ApiError, L as LogLevel } from './apiModule.types-CZX-M2Ub.cjs';
3
+ export { o as ActionConfig, s as ActionMethods, q as ActionState, f as ActionsWithQuery, a as ApiModuleConfig, E as ExecutableAction, r as ExecuteOptions, I as InputOf, m as Middleware, l as MiddlewareContext, d as ModuleActions, 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-CZX-M2Ub.cjs';
4
+ export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-Cq9AlZX2.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 { f as ApiClientConfig, A as ActionConfigModule, S as StandardResponse, g as ActionOptions, R as RequestConfig, h as ActionStateModule, Q as QueryOptions, e as UseApiQuery, i as ApiError, L as LogLevel } from './apiModule.types-Bn0tJF7b.js';
3
- export { n as ActionConfig, s as ActionMethods, p as ActionState, r as ActionsWithQuery, a as ApiModuleConfig, E as ExecutableAction, q as ExecuteOptions, I as InputOf, l as Middleware, k as MiddlewareContext, d as ModuleActions, M as ModuleStates, O as OutputOf, P as PaginationMeta, m as RefreshTokenConfig, j as TokenManager, T as Tokens, U as UseApiConfig, b as UseApiModuleOptions, c as UseApiModuleReturn, o as UseApiState, V as ValidationError, t } from './apiModule.types-Bn0tJF7b.js';
4
- export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-CWhwCAB6.js';
2
+ import { g as ApiClientConfig, A as ActionConfigModule, S as StandardResponse, h as ActionOptions, R as RequestConfig, i as ActionStateModule, Q as QueryOptions, e as UseApiQuery, j as ApiError, L as LogLevel } from './apiModule.types-CZX-M2Ub.js';
3
+ export { o as ActionConfig, s as ActionMethods, q as ActionState, f as ActionsWithQuery, a as ApiModuleConfig, E as ExecutableAction, r as ExecuteOptions, I as InputOf, m as Middleware, l as MiddlewareContext, d as ModuleActions, 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-CZX-M2Ub.js';
4
+ export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-Cye9a7zh.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 { A as ActionConfigModule, a as ApiModuleConfig, I as InputOf } from './apiModule.types-Bn0tJF7b.cjs';
2
+ import { A as ActionConfigModule, a as ApiModuleConfig, I as InputOf } from './apiModule.types-CZX-M2Ub.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-Bn0tJF7b.js';
2
+ import { A as ActionConfigModule, a as ApiModuleConfig, I as InputOf } from './apiModule.types-CZX-M2Ub.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, i as ApiError, S as StandardResponse, g as ActionOptions } from './apiModule.types-Bn0tJF7b.cjs';
2
+ import { R as RequestConfig, j as ApiError, S as StandardResponse, h as ActionOptions } from './apiModule.types-CZX-M2Ub.cjs';
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, i as ApiError, S as StandardResponse, g as ActionOptions } from './apiModule.types-Bn0tJF7b.js';
2
+ import { R as RequestConfig, j as ApiError, S as StandardResponse, h as ActionOptions } from './apiModule.types-CZX-M2Ub.js';
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": "12.0.88",
3
+ "version": "12.0.91",
4
4
  "description": "A flexible and powerful API client library for modern web applications.",
5
5
  "type": "module",
6
6
  "exports": {