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.
- package/dist/{apiModule.types-Bn0tJF7b.d.cts → apiModule.types-CZX-M2Ub.d.cts} +3 -3
- package/dist/{apiModule.types-Bn0tJF7b.d.ts → apiModule.types-CZX-M2Ub.d.ts} +3 -3
- package/dist/cli.cjs +38 -47
- package/dist/client.cjs +90 -91
- package/dist/client.d.cts +32 -5
- package/dist/client.d.ts +32 -5
- package/dist/client.js +80 -81
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/server.d.cts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/{useApiRecord.types-NZtPRga3.d.cts → useApiRecord.types-Cq9AlZX2.d.cts} +1 -1
- package/dist/{useApiRecord.types-CWhwCAB6.d.ts → useApiRecord.types-Cye9a7zh.d.ts} +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AxiosRequestConfig, AxiosProgressEvent, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
|
|
2
|
-
import
|
|
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:
|
|
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,
|
|
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
|
|
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:
|
|
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,
|
|
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
|
|
509
|
+
const contextFileContent = `// This file is auto-generated. Do not edit directly.
|
|
510
|
+
'use client';
|
|
512
511
|
|
|
513
|
-
import
|
|
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
|
-
|
|
517
|
+
const {
|
|
518
|
+
Provider,
|
|
519
|
+
useContext: use${moduleBaseName}Context
|
|
520
|
+
} = createApiModuleContext<typeof TModuleType['actions']>();
|
|
519
521
|
|
|
520
|
-
|
|
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 =
|
|
552
|
-
return <
|
|
535
|
+
const api = useApiModule(apiClient, ${module2.moduleName}, options);
|
|
536
|
+
return <Provider value={api}>{children}</Provider>;
|
|
553
537
|
}
|
|
554
538
|
`;
|
|
555
|
-
const
|
|
556
|
-
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath,
|
|
557
|
-
console.log(import_chalk.default.gray(` \u2713 ${
|
|
558
|
-
const
|
|
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`),
|
|
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
|
|
557
|
+
const clientExports = [
|
|
574
558
|
`
|
|
575
|
-
// Generated API helpers`,
|
|
559
|
+
// Generated API client helpers`,
|
|
576
560
|
`export * from './${camelCaseModuleName}.endpoints';`,
|
|
577
|
-
`export * from '
|
|
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,
|
|
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
|
-
|
|
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(
|
|
303
|
-
}, [execute]);
|
|
304
|
-
const
|
|
302
|
+
execute(input);
|
|
303
|
+
}, [execute, input]);
|
|
304
|
+
const prevStateRef = _react.useRef.call(void 0, );
|
|
305
305
|
_react.useEffect.call(void 0, () => {
|
|
306
|
-
|
|
307
|
-
|
|
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 &&
|
|
310
|
-
console.log(`[Auto Fetch] for ${cacheKey}. Fetching...`);
|
|
310
|
+
} else if (enabled && currentState.isStale && !currentState.loading) {
|
|
311
311
|
refetch();
|
|
312
|
-
} else if (enabled &&
|
|
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
|
-
|
|
317
|
-
}, [cacheKey, enabled, state
|
|
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 = { ...
|
|
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
|
-
|
|
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
|
-
|
|
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',
|
|
400
|
-
_optionalChain([options2, 'access',
|
|
401
|
-
_optionalChain([actionConfig, 'access',
|
|
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',
|
|
408
|
-
_optionalChain([options2, 'access',
|
|
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',
|
|
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',
|
|
417
|
-
_optionalChain([options2, 'access',
|
|
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 = { ...
|
|
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,
|
|
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',
|
|
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" ?
|
|
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
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
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 >
|
|
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.
|
|
516
|
-
return
|
|
491
|
+
const dehydrate = _react.useCallback.call(void 0, () => {
|
|
492
|
+
return _chunk25UFVV4Fcjs.globalStateManager.dehydrate();
|
|
517
493
|
}, []);
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
494
|
+
return _react.useMemo.call(void 0, () => ({
|
|
495
|
+
actions,
|
|
496
|
+
states,
|
|
497
|
+
queries,
|
|
498
|
+
dehydrate,
|
|
521
499
|
...extraContextData || {}
|
|
522
|
-
}), [
|
|
523
|
-
|
|
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
|
-
|
|
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-
|
|
3
|
-
import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-
|
|
4
|
-
import * as
|
|
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:
|
|
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
|
-
|
|
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-
|
|
3
|
-
import { U as UseApiRecordConfig, a as UseApiRecordReturn } from './useApiRecord.types-
|
|
4
|
-
import * as
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
303
|
-
}, [execute]);
|
|
304
|
-
const
|
|
302
|
+
execute(input);
|
|
303
|
+
}, [execute, input]);
|
|
304
|
+
const prevStateRef = useRef4();
|
|
305
305
|
useEffect4(() => {
|
|
306
|
-
|
|
307
|
-
|
|
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 &&
|
|
310
|
-
console.log(`[Auto Fetch] for ${cacheKey}. Fetching...`);
|
|
310
|
+
} else if (enabled && currentState.isStale && !currentState.loading) {
|
|
311
311
|
refetch();
|
|
312
|
-
} else if (enabled &&
|
|
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
|
-
|
|
317
|
-
}, [cacheKey, enabled, state
|
|
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 = { ...
|
|
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
|
-
|
|
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
|
-
|
|
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 = { ...
|
|
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,
|
|
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" ?
|
|
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
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
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 >
|
|
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 =
|
|
516
|
-
return
|
|
491
|
+
const dehydrate = useCallback3(() => {
|
|
492
|
+
return globalStateManager.dehydrate();
|
|
517
493
|
}, []);
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
494
|
+
return useMemo3(() => ({
|
|
495
|
+
actions,
|
|
496
|
+
states,
|
|
497
|
+
queries,
|
|
498
|
+
dehydrate,
|
|
521
499
|
...extraContextData || {}
|
|
522
|
-
}), [
|
|
523
|
-
|
|
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 {
|
|
3
|
-
export {
|
|
4
|
-
export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-
|
|
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 {
|
|
3
|
-
export {
|
|
4
|
-
export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-
|
|
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-
|
|
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-
|
|
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,
|
|
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,
|
|
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.
|