api-core-lib 12.0.10 → 12.0.12
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-2yhaJWN3.d.cts → apiModule.types-CpwGDEpG.d.cts} +2 -2
- package/dist/{apiModule.types-2yhaJWN3.d.ts → apiModule.types-CpwGDEpG.d.ts} +2 -2
- package/dist/client.cjs +869 -0
- package/dist/client.d.cts +28 -0
- package/dist/client.d.ts +28 -0
- package/dist/client.js +829 -0
- package/dist/index.cjs +2 -458
- package/dist/index.d.cts +5 -113
- package/dist/index.d.ts +5 -113
- package/dist/index.js +1 -451
- package/dist/server.d.cts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/useApiRecord.types-B45E0qux.d.cts +90 -0
- package/dist/useApiRecord.types-DlrlXL1t.d.ts +90 -0
- package/package.json +7 -2
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
"use client";
|
|
3
2
|
var __create = Object.create;
|
|
4
3
|
var __defProp = Object.defineProperty;
|
|
5
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -33,7 +32,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
33
32
|
// src/index.ts
|
|
34
33
|
var index_exports = {};
|
|
35
34
|
__export(index_exports, {
|
|
36
|
-
ApiModuleProvider: () => ApiModuleProvider,
|
|
37
35
|
buildPaginateQuery: () => buildPaginateQuery,
|
|
38
36
|
cacheManager: () => cacheManager,
|
|
39
37
|
callDynamicApi: () => callDynamicApi,
|
|
@@ -41,12 +39,7 @@ __export(index_exports, {
|
|
|
41
39
|
createApiClient: () => createApiClient,
|
|
42
40
|
createApiServices: () => createApiServices,
|
|
43
41
|
globalStateManager: () => globalStateManager,
|
|
44
|
-
processResponse: () => processResponse
|
|
45
|
-
useApi: () => useApi,
|
|
46
|
-
useApiModule: () => useApiModule,
|
|
47
|
-
useApiRecord: () => useApiRecord,
|
|
48
|
-
useDeepCompareEffect: () => useDeepCompareEffect,
|
|
49
|
-
useModuleContext: () => useModuleContext
|
|
42
|
+
processResponse: () => processResponse
|
|
50
43
|
});
|
|
51
44
|
module.exports = __toCommonJS(index_exports);
|
|
52
45
|
|
|
@@ -695,452 +688,8 @@ var CacheManager = class {
|
|
|
695
688
|
}
|
|
696
689
|
};
|
|
697
690
|
var cacheManager = new CacheManager();
|
|
698
|
-
|
|
699
|
-
// src/hooks/useApi.ts
|
|
700
|
-
var import_react = require("react");
|
|
701
|
-
function buildDynamicPath(template, params) {
|
|
702
|
-
if (!params) return template;
|
|
703
|
-
let path = template;
|
|
704
|
-
for (const key in params) {
|
|
705
|
-
path = path.replace(new RegExp(`{${key}}`, "g"), String(params[key]));
|
|
706
|
-
}
|
|
707
|
-
return path;
|
|
708
|
-
}
|
|
709
|
-
function useApi(axiosInstance, config) {
|
|
710
|
-
const {
|
|
711
|
-
endpoint,
|
|
712
|
-
pathParams,
|
|
713
|
-
// [REMOVE] لم نعد بحاجة لهذا الخيار
|
|
714
|
-
// encodeQuery = true,
|
|
715
|
-
initialData,
|
|
716
|
-
initialQuery = {},
|
|
717
|
-
enabled = true,
|
|
718
|
-
refetchAfterChange = true,
|
|
719
|
-
requestConfig,
|
|
720
|
-
onSuccess,
|
|
721
|
-
onError
|
|
722
|
-
} = config;
|
|
723
|
-
const finalEndpoint = (0, import_react.useMemo)(
|
|
724
|
-
() => buildDynamicPath(endpoint, pathParams),
|
|
725
|
-
[endpoint, pathParams]
|
|
726
|
-
);
|
|
727
|
-
const [state, setState] = (0, import_react.useState)({
|
|
728
|
-
data: initialData ?? null,
|
|
729
|
-
rawResponse: null,
|
|
730
|
-
loading: enabled,
|
|
731
|
-
error: null,
|
|
732
|
-
success: false,
|
|
733
|
-
message: void 0,
|
|
734
|
-
validationErrors: void 0
|
|
735
|
-
});
|
|
736
|
-
const [queryOptions, setQueryOptions] = (0, import_react.useState)(initialQuery);
|
|
737
|
-
const apiServices = (0, import_react.useMemo)(
|
|
738
|
-
() => createApiServices(axiosInstance, finalEndpoint),
|
|
739
|
-
[axiosInstance, finalEndpoint]
|
|
740
|
-
);
|
|
741
|
-
const savedOnSuccess = (0, import_react.useRef)(onSuccess);
|
|
742
|
-
const savedOnError = (0, import_react.useRef)(onError);
|
|
743
|
-
(0, import_react.useEffect)(() => {
|
|
744
|
-
savedOnSuccess.current = onSuccess;
|
|
745
|
-
savedOnError.current = onError;
|
|
746
|
-
}, [onSuccess, onError]);
|
|
747
|
-
const fetchData = (0, import_react.useCallback)(async (currentQueryOptions) => {
|
|
748
|
-
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
749
|
-
try {
|
|
750
|
-
const finalQuery = currentQueryOptions || queryOptions;
|
|
751
|
-
const hasQueryParams = Object.keys(finalQuery).length > 0;
|
|
752
|
-
const queryString = buildPaginateQuery(finalQuery);
|
|
753
|
-
const result = hasQueryParams ? await apiServices.getWithQuery(queryString, requestConfig) : await apiServices.get(void 0, requestConfig);
|
|
754
|
-
setState(result);
|
|
755
|
-
if (result.success && savedOnSuccess.current) {
|
|
756
|
-
savedOnSuccess.current(result.message || "Fetch successful!", result.data ?? void 0);
|
|
757
|
-
} else if (!result.success && savedOnError.current) {
|
|
758
|
-
savedOnError.current(result.message || "Fetch failed", result.error ?? void 0);
|
|
759
|
-
}
|
|
760
|
-
} catch (e) {
|
|
761
|
-
const apiError = { status: 500, message: e.message || "An unexpected client-side error occurred." };
|
|
762
|
-
setState((prev) => ({ ...prev, loading: false, error: apiError, success: false }));
|
|
763
|
-
if (savedOnError.current) {
|
|
764
|
-
savedOnError.current(apiError.message, apiError);
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
}, [apiServices, queryOptions, requestConfig]);
|
|
768
|
-
(0, import_react.useEffect)(() => {
|
|
769
|
-
if (enabled) {
|
|
770
|
-
fetchData();
|
|
771
|
-
}
|
|
772
|
-
}, [enabled, fetchData]);
|
|
773
|
-
const handleActionResult = (0, import_react.useCallback)(async (actionPromise) => {
|
|
774
|
-
setState((prev) => ({ ...prev, loading: true }));
|
|
775
|
-
try {
|
|
776
|
-
const result = await actionPromise;
|
|
777
|
-
if (result.success) {
|
|
778
|
-
if (savedOnSuccess.current) {
|
|
779
|
-
savedOnSuccess.current(result.message || "Action successful!", result.data ?? void 0);
|
|
780
|
-
}
|
|
781
|
-
if (refetchAfterChange) {
|
|
782
|
-
await fetchData(queryOptions);
|
|
783
|
-
} else {
|
|
784
|
-
setState((prev) => ({ ...prev, ...result, loading: false }));
|
|
785
|
-
}
|
|
786
|
-
} else {
|
|
787
|
-
if (savedOnError.current) {
|
|
788
|
-
savedOnError.current(result.message || "Action failed", result.error ?? void 0);
|
|
789
|
-
}
|
|
790
|
-
setState((prev) => ({ ...prev, loading: false, error: result.error, success: false }));
|
|
791
|
-
}
|
|
792
|
-
return result;
|
|
793
|
-
} catch (e) {
|
|
794
|
-
const apiError = { status: 500, message: e.message || "An unexpected error occurred during action." };
|
|
795
|
-
setState((prev) => ({ ...prev, loading: false, error: apiError, success: false }));
|
|
796
|
-
if (savedOnError.current) {
|
|
797
|
-
savedOnError.current(apiError.message, apiError);
|
|
798
|
-
}
|
|
799
|
-
return { data: null, error: apiError, loading: false, success: false, rawResponse: e };
|
|
800
|
-
}
|
|
801
|
-
}, [refetchAfterChange, fetchData, queryOptions]);
|
|
802
|
-
const actions = {
|
|
803
|
-
fetch: fetchData,
|
|
804
|
-
create: (newItem, options) => handleActionResult(apiServices.post(newItem, options)),
|
|
805
|
-
put: (id, item, options) => handleActionResult(apiServices.put(id, item, options)),
|
|
806
|
-
update: (id, updatedItem, options) => handleActionResult(apiServices.patch(id, updatedItem, options)),
|
|
807
|
-
remove: (id, options) => handleActionResult(apiServices.remove(id, options)),
|
|
808
|
-
bulkRemove: (ids, options) => handleActionResult(apiServices.bulkDelete(ids, options))
|
|
809
|
-
};
|
|
810
|
-
const query = {
|
|
811
|
-
options: queryOptions,
|
|
812
|
-
setOptions: setQueryOptions,
|
|
813
|
-
setPage: (page) => setQueryOptions((prev) => ({ ...prev, page })),
|
|
814
|
-
setLimit: (limit) => setQueryOptions((prev) => ({ ...prev, page: 1, limit })),
|
|
815
|
-
setSearchTerm: (search) => setQueryOptions((prev) => ({ ...prev, page: 1, search })),
|
|
816
|
-
setSorting: (sortBy) => setQueryOptions((prev) => ({ ...prev, sortBy })),
|
|
817
|
-
setFilters: (filter) => setQueryOptions((prev) => ({ ...prev, page: 1, filter })),
|
|
818
|
-
setQueryParam: (key, value) => setQueryOptions((prev) => ({ ...prev, [key]: value, page: key !== "page" ? 1 : value })),
|
|
819
|
-
reset: () => setQueryOptions(initialQuery)
|
|
820
|
-
};
|
|
821
|
-
return { state, setState, actions, query };
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
// src/hooks/useApiRecord/index.ts
|
|
825
|
-
var import_react2 = require("react");
|
|
826
|
-
function buildDynamicPath2(template, params) {
|
|
827
|
-
if (!params) return template;
|
|
828
|
-
let path = template;
|
|
829
|
-
for (const key in params) {
|
|
830
|
-
path = path.replace(new RegExp(`{${key}}`, "g"), String(params[key]));
|
|
831
|
-
}
|
|
832
|
-
return path;
|
|
833
|
-
}
|
|
834
|
-
function useApiRecord(axiosInstance, config) {
|
|
835
|
-
const {
|
|
836
|
-
endpoint,
|
|
837
|
-
pathParams,
|
|
838
|
-
recordId,
|
|
839
|
-
initialData,
|
|
840
|
-
enabled = true,
|
|
841
|
-
refetchAfterChange = true,
|
|
842
|
-
requestConfig,
|
|
843
|
-
onSuccess,
|
|
844
|
-
onError
|
|
845
|
-
} = config;
|
|
846
|
-
const finalEndpoint = (0, import_react2.useMemo)(
|
|
847
|
-
() => buildDynamicPath2(endpoint, pathParams),
|
|
848
|
-
[endpoint, pathParams]
|
|
849
|
-
);
|
|
850
|
-
const initialState = (0, import_react2.useMemo)(() => ({
|
|
851
|
-
data: initialData ?? null,
|
|
852
|
-
rawResponse: null,
|
|
853
|
-
error: null,
|
|
854
|
-
loading: enabled && !!recordId,
|
|
855
|
-
success: false,
|
|
856
|
-
message: void 0,
|
|
857
|
-
validationErrors: void 0
|
|
858
|
-
}), [initialData, enabled, recordId]);
|
|
859
|
-
const [state, setState] = (0, import_react2.useState)(initialState);
|
|
860
|
-
const savedOnSuccess = (0, import_react2.useRef)(onSuccess);
|
|
861
|
-
const savedOnError = (0, import_react2.useRef)(onError);
|
|
862
|
-
(0, import_react2.useEffect)(() => {
|
|
863
|
-
savedOnSuccess.current = onSuccess;
|
|
864
|
-
savedOnError.current = onError;
|
|
865
|
-
}, [onSuccess, onError]);
|
|
866
|
-
const apiServices = (0, import_react2.useMemo)(
|
|
867
|
-
() => createApiServices(axiosInstance, finalEndpoint),
|
|
868
|
-
[axiosInstance, finalEndpoint]
|
|
869
|
-
);
|
|
870
|
-
const fetchRecord = (0, import_react2.useCallback)(async () => {
|
|
871
|
-
if (!recordId) {
|
|
872
|
-
setState(initialState);
|
|
873
|
-
return;
|
|
874
|
-
}
|
|
875
|
-
setState((prev) => ({ ...prev, loading: true, error: null, success: false }));
|
|
876
|
-
try {
|
|
877
|
-
const result = await apiServices.get(recordId, requestConfig);
|
|
878
|
-
setState(result);
|
|
879
|
-
if (result.success && savedOnSuccess.current) {
|
|
880
|
-
savedOnSuccess.current(result.message || "Record fetched successfully!", result.data ?? void 0);
|
|
881
|
-
} else if (!result.success && savedOnError.current) {
|
|
882
|
-
savedOnError.current(result.message || "Fetch failed", result.error ?? void 0);
|
|
883
|
-
}
|
|
884
|
-
} catch (e) {
|
|
885
|
-
console.error("[useApiRecord Fetch Error]", e);
|
|
886
|
-
const apiError = {
|
|
887
|
-
status: e.response?.status || 500,
|
|
888
|
-
message: e.message || "An unexpected client-side error occurred.",
|
|
889
|
-
code: e.code
|
|
890
|
-
};
|
|
891
|
-
setState((prev) => ({ ...prev, loading: false, success: false, error: apiError }));
|
|
892
|
-
if (savedOnError.current) {
|
|
893
|
-
savedOnError.current(apiError.message, apiError);
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
}, [apiServices, recordId, requestConfig, initialState]);
|
|
897
|
-
(0, import_react2.useEffect)(() => {
|
|
898
|
-
if (enabled) {
|
|
899
|
-
fetchRecord();
|
|
900
|
-
}
|
|
901
|
-
}, [enabled, fetchRecord]);
|
|
902
|
-
const handleActionResult = (0, import_react2.useCallback)(
|
|
903
|
-
async (actionPromise, options) => {
|
|
904
|
-
setState((prev) => ({ ...prev, loading: true }));
|
|
905
|
-
try {
|
|
906
|
-
const result = await actionPromise;
|
|
907
|
-
if (result.success) {
|
|
908
|
-
if (savedOnSuccess.current) {
|
|
909
|
-
savedOnSuccess.current(result.message || "Action successful!", result.data);
|
|
910
|
-
}
|
|
911
|
-
const shouldRefetch = options?.refetch ?? refetchAfterChange;
|
|
912
|
-
if (shouldRefetch) {
|
|
913
|
-
await fetchRecord();
|
|
914
|
-
} else {
|
|
915
|
-
setState({ ...result, loading: false, data: result.data });
|
|
916
|
-
}
|
|
917
|
-
} else {
|
|
918
|
-
if (savedOnError.current) {
|
|
919
|
-
savedOnError.current(result.message || "Action failed", result.error ?? void 0);
|
|
920
|
-
}
|
|
921
|
-
setState((prev) => ({ ...prev, ...result, loading: false }));
|
|
922
|
-
}
|
|
923
|
-
return result;
|
|
924
|
-
} catch (e) {
|
|
925
|
-
console.error("[useApiRecord Action Error]", e);
|
|
926
|
-
const apiError = {
|
|
927
|
-
status: e.response?.status || 500,
|
|
928
|
-
message: e.message || "An unexpected error occurred during the action.",
|
|
929
|
-
code: e.code
|
|
930
|
-
};
|
|
931
|
-
const errorResponse = { ...initialState, loading: false, success: false, error: apiError, rawResponse: e, data: null };
|
|
932
|
-
setState(errorResponse);
|
|
933
|
-
if (savedOnError.current) {
|
|
934
|
-
savedOnError.current(apiError.message, apiError);
|
|
935
|
-
}
|
|
936
|
-
return errorResponse;
|
|
937
|
-
}
|
|
938
|
-
},
|
|
939
|
-
[refetchAfterChange, fetchRecord, initialState]
|
|
940
|
-
);
|
|
941
|
-
const actions = {
|
|
942
|
-
fetch: fetchRecord,
|
|
943
|
-
update: (updatedItem, options) => handleActionResult(apiServices.patch(recordId, updatedItem, { ...requestConfig, ...options }), options),
|
|
944
|
-
put: (item, options) => handleActionResult(apiServices.put(recordId, item, { ...requestConfig, ...options }), options),
|
|
945
|
-
remove: (options) => handleActionResult(apiServices.remove(recordId, { ...requestConfig, ...options }), options),
|
|
946
|
-
resetState: () => setState(initialState)
|
|
947
|
-
};
|
|
948
|
-
return { state, setState, actions };
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
// src/hooks/useDeepCompareEffect/index.ts
|
|
952
|
-
var import_react3 = require("react");
|
|
953
|
-
var import_fast_deep_equal = __toESM(require("fast-deep-equal"), 1);
|
|
954
|
-
function useDeepCompareEffect(callback, dependencies) {
|
|
955
|
-
const currentDependenciesRef = (0, import_react3.useRef)();
|
|
956
|
-
if (!(0, import_fast_deep_equal.default)(currentDependenciesRef.current, dependencies)) {
|
|
957
|
-
currentDependenciesRef.current = dependencies;
|
|
958
|
-
}
|
|
959
|
-
(0, import_react3.useEffect)(callback, [currentDependenciesRef.current]);
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
// src/hooks/useApiModule/useApiModule.ts
|
|
963
|
-
var import_react4 = require("react");
|
|
964
|
-
var ApiModuleContext = (0, import_react4.createContext)(null);
|
|
965
|
-
var ApiModuleProvider = ApiModuleContext.Provider;
|
|
966
|
-
function useModuleContext() {
|
|
967
|
-
const context = (0, import_react4.useContext)(ApiModuleContext);
|
|
968
|
-
if (!context) {
|
|
969
|
-
throw new Error("useModuleContext must be used within an ApiModuleProvider");
|
|
970
|
-
}
|
|
971
|
-
return context;
|
|
972
|
-
}
|
|
973
|
-
var generateCacheKey = (moduleName, actionName, input, callOptions = {}) => {
|
|
974
|
-
const params = { path: callOptions.pathParams, body: input };
|
|
975
|
-
try {
|
|
976
|
-
return `${moduleName}/${actionName}::${JSON.stringify(params)}`;
|
|
977
|
-
} catch (error) {
|
|
978
|
-
return `${moduleName}/${actionName}::${Date.now()}`;
|
|
979
|
-
}
|
|
980
|
-
};
|
|
981
|
-
function useApiModule(axiosInstance, moduleConfig, options = {}) {
|
|
982
|
-
const { refetchOnWindowFocus = true, onSuccess, onError, pathParams: modulePathParams, enabled = true, hydratedState } = options;
|
|
983
|
-
const pathParamsString = (0, import_react4.useMemo)(() => JSON.stringify(modulePathParams || {}), [modulePathParams]);
|
|
984
|
-
const [queryOptions, setQueryOptions] = (0, import_react4.useState)({});
|
|
985
|
-
const savedCallbacks = (0, import_react4.useRef)({ onSuccess, onError });
|
|
986
|
-
(0, import_react4.useEffect)(() => {
|
|
987
|
-
savedCallbacks.current = { onSuccess, onError };
|
|
988
|
-
}, [onSuccess, onError]);
|
|
989
|
-
(0, import_react4.useMemo)(() => {
|
|
990
|
-
if (hydratedState) {
|
|
991
|
-
globalStateManager.rehydrate(hydratedState);
|
|
992
|
-
}
|
|
993
|
-
}, [hydratedState]);
|
|
994
|
-
const actions = (0, import_react4.useMemo)(() => {
|
|
995
|
-
return Object.keys(moduleConfig.actions).reduce((acc, actionName) => {
|
|
996
|
-
const actionConfig = moduleConfig.actions[actionName];
|
|
997
|
-
const execute = async (input, options2 = {}) => {
|
|
998
|
-
const finalPathParams = { ...JSON.parse(pathParamsString), ...options2.pathParams };
|
|
999
|
-
const cacheKey = generateCacheKey(moduleConfig.baseEndpoint, actionName, input, { pathParams: finalPathParams });
|
|
1000
|
-
let mutationContext;
|
|
1001
|
-
try {
|
|
1002
|
-
if (options2.onMutate) {
|
|
1003
|
-
mutationContext = await options2.onMutate(input);
|
|
1004
|
-
}
|
|
1005
|
-
globalStateManager.setState(cacheKey, (prev) => ({ ...prev, loading: true, called: true, error: null, isStale: false }));
|
|
1006
|
-
const result = await callDynamicApi(axiosInstance, moduleConfig.baseEndpoint, actionConfig, {
|
|
1007
|
-
pathParams: finalPathParams,
|
|
1008
|
-
body: input,
|
|
1009
|
-
config: options2.config
|
|
1010
|
-
});
|
|
1011
|
-
globalStateManager.setState(cacheKey, (prev) => ({ ...prev, ...result, loading: false }));
|
|
1012
|
-
if (result.success) {
|
|
1013
|
-
savedCallbacks.current.onSuccess?.(actionName, result.message || "Action successful", result.data);
|
|
1014
|
-
options2.onSuccess?.(result.data, mutationContext);
|
|
1015
|
-
actionConfig.invalidates?.forEach((keyToInvalidate) => {
|
|
1016
|
-
const prefix = `${moduleConfig.baseEndpoint}/${keyToInvalidate}::`;
|
|
1017
|
-
globalStateManager.invalidateByPrefix(prefix);
|
|
1018
|
-
});
|
|
1019
|
-
} else {
|
|
1020
|
-
savedCallbacks.current.onError?.(actionName, result.message || "Action failed", result.error ?? void 0);
|
|
1021
|
-
options2.onError?.(result.error, mutationContext);
|
|
1022
|
-
}
|
|
1023
|
-
return result;
|
|
1024
|
-
} catch (error) {
|
|
1025
|
-
const apiError = { status: 500, message: error.message };
|
|
1026
|
-
const errorResult = { data: null, error: apiError, loading: false, success: false, rawResponse: error };
|
|
1027
|
-
globalStateManager.setState(cacheKey, (prev) => ({ ...prev, ...errorResult, loading: false }));
|
|
1028
|
-
savedCallbacks.current.onError?.(actionName, apiError.message, apiError);
|
|
1029
|
-
options2.onError?.(apiError, mutationContext);
|
|
1030
|
-
return errorResult;
|
|
1031
|
-
}
|
|
1032
|
-
};
|
|
1033
|
-
const reset = (input, options2 = {}) => {
|
|
1034
|
-
const finalPathParams = { ...JSON.parse(pathParamsString), ...options2.pathParams };
|
|
1035
|
-
const cacheKey = generateCacheKey(moduleConfig.baseEndpoint, actionName, input, { pathParams: finalPathParams });
|
|
1036
|
-
globalStateManager.setState(cacheKey, () => ({
|
|
1037
|
-
data: null,
|
|
1038
|
-
error: null,
|
|
1039
|
-
loading: false,
|
|
1040
|
-
success: false,
|
|
1041
|
-
called: false,
|
|
1042
|
-
isStale: false,
|
|
1043
|
-
rawResponse: null
|
|
1044
|
-
}));
|
|
1045
|
-
};
|
|
1046
|
-
acc[actionName] = { execute, reset };
|
|
1047
|
-
return acc;
|
|
1048
|
-
}, {});
|
|
1049
|
-
}, [axiosInstance, moduleConfig, pathParamsString]);
|
|
1050
|
-
const queries = (0, import_react4.useMemo)(() => {
|
|
1051
|
-
const builtQueries = {};
|
|
1052
|
-
for (const actionName in moduleConfig.actions) {
|
|
1053
|
-
if (moduleConfig.actions[actionName]?.hasQuery) {
|
|
1054
|
-
const setActionQueryOptions = (updater) => {
|
|
1055
|
-
setQueryOptions((prev) => ({ ...prev, [actionName]: typeof updater === "function" ? updater(prev[actionName] || {}) : updater }));
|
|
1056
|
-
};
|
|
1057
|
-
builtQueries[actionName] = {
|
|
1058
|
-
options: queryOptions[actionName] || {},
|
|
1059
|
-
setOptions: setActionQueryOptions,
|
|
1060
|
-
setPage: (page) => setActionQueryOptions((p) => ({ ...p, page })),
|
|
1061
|
-
setLimit: (limit) => setActionQueryOptions((p) => ({ ...p, limit, page: 1 })),
|
|
1062
|
-
setSearchTerm: (search) => setActionQueryOptions((p) => ({ ...p, search, page: 1 })),
|
|
1063
|
-
setFilters: (filter) => setActionQueryOptions((p) => ({ ...p, filter, page: 1 })),
|
|
1064
|
-
setSorting: (sortBy) => setActionQueryOptions((p) => ({ ...p, sortBy })),
|
|
1065
|
-
setQueryParam: (key, value) => setActionQueryOptions((p) => ({ ...p, [key]: value, page: key !== "page" ? value : p.page })),
|
|
1066
|
-
reset: () => setActionQueryOptions({})
|
|
1067
|
-
};
|
|
1068
|
-
}
|
|
1069
|
-
}
|
|
1070
|
-
return builtQueries;
|
|
1071
|
-
}, [queryOptions, moduleConfig.actions]);
|
|
1072
|
-
const states = (0, import_react4.useMemo)(() => {
|
|
1073
|
-
const finalStates = {};
|
|
1074
|
-
for (const actionName of Object.keys(moduleConfig.actions)) {
|
|
1075
|
-
Object.defineProperty(finalStates, actionName, {
|
|
1076
|
-
get: () => {
|
|
1077
|
-
const actionConfig = moduleConfig.actions[actionName];
|
|
1078
|
-
const query = queries[actionName]?.options;
|
|
1079
|
-
const input = actionConfig.hasQuery ? query : void 0;
|
|
1080
|
-
const pathParams = JSON.parse(pathParamsString);
|
|
1081
|
-
const cacheKey = generateCacheKey(moduleConfig.baseEndpoint, actionName, input, { pathParams });
|
|
1082
|
-
const state = (0, import_react4.useSyncExternalStore)(
|
|
1083
|
-
(callback) => globalStateManager.subscribe(cacheKey, callback),
|
|
1084
|
-
() => globalStateManager.getSnapshot(cacheKey)
|
|
1085
|
-
);
|
|
1086
|
-
(0, import_react4.useEffect)(() => {
|
|
1087
|
-
if (enabled && state.isStale && !state.loading) {
|
|
1088
|
-
actions[actionName].execute(input);
|
|
1089
|
-
}
|
|
1090
|
-
}, [enabled, state.isStale, state.loading, input, actions, actionName]);
|
|
1091
|
-
return state;
|
|
1092
|
-
},
|
|
1093
|
-
enumerable: true
|
|
1094
|
-
});
|
|
1095
|
-
}
|
|
1096
|
-
return finalStates;
|
|
1097
|
-
}, [moduleConfig, pathParamsString, queries, enabled, actions]);
|
|
1098
|
-
(0, import_react4.useEffect)(() => {
|
|
1099
|
-
if (!enabled) return;
|
|
1100
|
-
const actionKeys = Object.keys(moduleConfig.actions);
|
|
1101
|
-
for (const actionName of actionKeys) {
|
|
1102
|
-
const state = states[actionName];
|
|
1103
|
-
const actionConfig = moduleConfig.actions[actionName];
|
|
1104
|
-
if (actionConfig.autoFetch && state && !state.called && !state.loading) {
|
|
1105
|
-
const query = queries[actionName]?.options;
|
|
1106
|
-
const input = actionConfig.hasQuery ? query : void 0;
|
|
1107
|
-
actions[actionName].execute(input);
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
}, [enabled, moduleConfig, actions, states, queries]);
|
|
1111
|
-
const lastBlurTimestamp = (0, import_react4.useRef)(Date.now());
|
|
1112
|
-
(0, import_react4.useEffect)(() => {
|
|
1113
|
-
if (!enabled || !refetchOnWindowFocus) return;
|
|
1114
|
-
const onFocus = () => {
|
|
1115
|
-
if (Date.now() - lastBlurTimestamp.current > 1e4) {
|
|
1116
|
-
const actionKeys = Object.keys(moduleConfig.actions);
|
|
1117
|
-
for (const actionName of actionKeys) {
|
|
1118
|
-
const state = states[actionName];
|
|
1119
|
-
if (state && state.called && !state.loading) {
|
|
1120
|
-
const prefix = `${moduleConfig.baseEndpoint}/${actionName}::`;
|
|
1121
|
-
globalStateManager.invalidateByPrefix(prefix);
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
};
|
|
1126
|
-
const onBlur = () => {
|
|
1127
|
-
lastBlurTimestamp.current = Date.now();
|
|
1128
|
-
};
|
|
1129
|
-
window.addEventListener("focus", onFocus);
|
|
1130
|
-
window.addEventListener("blur", onBlur);
|
|
1131
|
-
return () => {
|
|
1132
|
-
window.removeEventListener("focus", onFocus);
|
|
1133
|
-
window.removeEventListener("blur", onBlur);
|
|
1134
|
-
};
|
|
1135
|
-
}, [enabled, refetchOnWindowFocus, moduleConfig, states]);
|
|
1136
|
-
const dehydrate = (0, import_react4.useMemo)(() => {
|
|
1137
|
-
return () => globalStateManager.dehydrate();
|
|
1138
|
-
}, []);
|
|
1139
|
-
return { actions, states, queries, dehydrate };
|
|
1140
|
-
}
|
|
1141
691
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1142
692
|
0 && (module.exports = {
|
|
1143
|
-
ApiModuleProvider,
|
|
1144
693
|
buildPaginateQuery,
|
|
1145
694
|
cacheManager,
|
|
1146
695
|
callDynamicApi,
|
|
@@ -1148,10 +697,5 @@ function useApiModule(axiosInstance, moduleConfig, options = {}) {
|
|
|
1148
697
|
createApiClient,
|
|
1149
698
|
createApiServices,
|
|
1150
699
|
globalStateManager,
|
|
1151
|
-
processResponse
|
|
1152
|
-
useApi,
|
|
1153
|
-
useApiModule,
|
|
1154
|
-
useApiRecord,
|
|
1155
|
-
useDeepCompareEffect,
|
|
1156
|
-
useModuleContext
|
|
700
|
+
processResponse
|
|
1157
701
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { AxiosInstance, AxiosRequestConfig, Method, AxiosResponse, AxiosError } from 'axios';
|
|
2
|
-
import {
|
|
3
|
-
export { l as ActionConfig, n as ActionState, E as ExecutableAction, o as ExecuteOptions, I as InputOf, j as Middleware, M as MiddlewareContext, p as ModuleActions, q as ModuleStates, O as OutputOf, P as PaginationMeta, k as RefreshTokenConfig, i as TokenManager, T as Tokens, m as UseApiState, V as ValidationError } from './apiModule.types-
|
|
4
|
-
|
|
5
|
-
import
|
|
2
|
+
import { d as ApiClientConfig, A as ActionConfigModule, S as StandardResponse, e as ActionOptions, R as RequestConfig, f as ActionStateModule, Q as QueryOptions, g as UseApiQuery, h as ApiError, L as LogLevel } from './apiModule.types-CpwGDEpG.cjs';
|
|
3
|
+
export { l as ActionConfig, n as ActionState, a as ApiModuleConfig, E as ExecutableAction, o as ExecuteOptions, I as InputOf, j as Middleware, M as MiddlewareContext, p as ModuleActions, q as ModuleStates, O as OutputOf, P as PaginationMeta, k as RefreshTokenConfig, i as TokenManager, T as Tokens, U as UseApiConfig, b as UseApiModuleOptions, c as UseApiModuleReturn, m as UseApiState, V as ValidationError } from './apiModule.types-CpwGDEpG.cjs';
|
|
4
|
+
export { c as UseApiRecordActions, U as UseApiRecordConfig, a as UseApiRecordReturn, b as UseApiRecordState } from './useApiRecord.types-B45E0qux.cjs';
|
|
5
|
+
import 'react';
|
|
6
6
|
|
|
7
7
|
declare function createApiClient(config: ApiClientConfig): AxiosInstance;
|
|
8
8
|
|
|
@@ -147,114 +147,6 @@ declare class CacheManager {
|
|
|
147
147
|
}
|
|
148
148
|
declare const cacheManager: CacheManager;
|
|
149
149
|
|
|
150
|
-
declare function useApi<T>(axiosInstance: AxiosInstance, config: UseApiConfig<T>): any;
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Represents the internal state of the `useApiRecord` hook.
|
|
154
|
-
* It mirrors the `StandardResponse` structure, which is the unified response format
|
|
155
|
-
* used across the library.
|
|
156
|
-
* @template T The data type of the record.
|
|
157
|
-
*/
|
|
158
|
-
type UseApiRecordState<T> = StandardResponse<T>;
|
|
159
|
-
/**
|
|
160
|
-
* Defines the action methods provided by the `useApiRecord` hook to interact with
|
|
161
|
-
* a single API resource.
|
|
162
|
-
* @template T The data type of the record.
|
|
163
|
-
*/
|
|
164
|
-
interface UseApiRecordActions<T> {
|
|
165
|
-
/**
|
|
166
|
-
* Manually fetches or refetches the record from the API.
|
|
167
|
-
*/
|
|
168
|
-
fetch: () => Promise<void>;
|
|
169
|
-
/**
|
|
170
|
-
* Partially updates the record using an HTTP PATCH request.
|
|
171
|
-
* @param updatedItem An object containing the fields to update.
|
|
172
|
-
* @param options Additional request options, allowing overrides for this specific action.
|
|
173
|
-
* @returns A promise that resolves to the standard response object for the updated record.
|
|
174
|
-
*/
|
|
175
|
-
update: (updatedItem: Partial<T>, options?: ActionOptions) => Promise<StandardResponse<T>>;
|
|
176
|
-
/**
|
|
177
|
-
* Replaces the entire record with a new one using an HTTP PUT request.
|
|
178
|
-
* @param item The complete new record object.
|
|
179
|
-
* @param options Additional request options.
|
|
180
|
-
* @returns A promise that resolves to the standard response object for the replaced record.
|
|
181
|
-
*/
|
|
182
|
-
put: (item: T, options?: ActionOptions) => Promise<StandardResponse<T>>;
|
|
183
|
-
/**
|
|
184
|
-
* Deletes the record using an HTTP DELETE request.
|
|
185
|
-
* @param options Additional request options.
|
|
186
|
-
* @returns A promise that resolves to a standard response object with a null data payload.
|
|
187
|
-
*/
|
|
188
|
-
remove: (options?: ActionOptions) => Promise<StandardResponse<null>>;
|
|
189
|
-
/**
|
|
190
|
-
* Resets the hook's state to its initial value.
|
|
191
|
-
*/
|
|
192
|
-
resetState: () => void;
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Defines the configuration options for the `useApiRecord` hook.
|
|
196
|
-
* @template T The data type of the record.
|
|
197
|
-
*/
|
|
198
|
-
interface UseApiRecordConfig<T> {
|
|
199
|
-
/**
|
|
200
|
-
* The base API endpoint template for the resource.
|
|
201
|
-
* Can contain placeholders like `{endpointName}`.
|
|
202
|
-
* @example 'v1/dynamic/{endpointName}'
|
|
203
|
-
*/
|
|
204
|
-
endpoint: string;
|
|
205
|
-
/**
|
|
206
|
-
* An object containing key-value pairs to replace placeholders in the endpoint template.
|
|
207
|
-
* @example { endpointName: 'products' }
|
|
208
|
-
*/
|
|
209
|
-
pathParams?: Record<string, string | number>;
|
|
210
|
-
/** The unique identifier of the record to fetch or modify. */
|
|
211
|
-
recordId?: string | number | null;
|
|
212
|
-
/** Optional initial data to populate the state before the first fetch is complete. */
|
|
213
|
-
initialData?: T | null;
|
|
214
|
-
/** If `false`, the hook will not automatically fetch data on mount. Defaults to `true`. */
|
|
215
|
-
enabled?: boolean;
|
|
216
|
-
/** If `true`, the record will be refetched after a successful `update`, `put`, or `remove` action. Defaults to `true`. */
|
|
217
|
-
refetchAfterChange?: boolean;
|
|
218
|
-
/** Default `RequestConfig` to apply to the initial GET request made by the hook. */
|
|
219
|
-
requestConfig?: RequestConfig;
|
|
220
|
-
/** A callback function executed on a successful API action. */
|
|
221
|
-
onSuccess?: (message: string, data?: any) => void;
|
|
222
|
-
/** A callback function executed on a failed API action. */
|
|
223
|
-
onError?: (message: string, error?: ApiError) => void;
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* The return value of the `useApiRecord` hook.
|
|
227
|
-
* @template T The data type of the record.
|
|
228
|
-
*/
|
|
229
|
-
interface UseApiRecordReturn<T> {
|
|
230
|
-
/** The current state of the API request, including data, loading, and error status. */
|
|
231
|
-
state: UseApiRecordState<T>;
|
|
232
|
-
/** Action methods to manipulate the record. */
|
|
233
|
-
actions: UseApiRecordActions<T>;
|
|
234
|
-
/** A React dispatch function to manually set the hook's state. Use with caution. */
|
|
235
|
-
setState: Dispatch<SetStateAction<UseApiRecordState<T>>>;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* A React hook for managing the lifecycle of a single API resource (a record).
|
|
240
|
-
* It handles fetching, updating, replacing, and deleting a record, while managing
|
|
241
|
-
* loading, error, and data states. It supports dynamic path parameters for flexible API routing.
|
|
242
|
-
*
|
|
243
|
-
* @template T The data type of the record being managed.
|
|
244
|
-
* @param {AxiosInstance} axiosInstance - The configured Axios instance for making API calls.
|
|
245
|
-
* @param {UseApiRecordConfig<T>} config - Configuration options for the hook.
|
|
246
|
-
* @returns {UseApiRecordReturn<T>} An object containing the state, actions, and setState function.
|
|
247
|
-
*/
|
|
248
|
-
declare function useApiRecord<T>(axiosInstance: AxiosInstance, config: UseApiRecordConfig<T>): UseApiRecordReturn<T>;
|
|
249
|
-
|
|
250
|
-
type EffectCallback = () => (void | (() => void));
|
|
251
|
-
type DependencyList = readonly any[];
|
|
252
|
-
declare function useDeepCompareEffect(callback: EffectCallback, dependencies: DependencyList): void;
|
|
253
|
-
|
|
254
|
-
declare const ApiModuleProvider: React$1.Provider<UseApiModuleReturn<any> | null>;
|
|
255
|
-
declare function useModuleContext<TModule extends ApiModuleConfig<any>>(): UseApiModuleReturn<TModule['actions']>;
|
|
256
|
-
declare function useApiModule<TActions extends Record<string, ActionConfigModule<any, any>>>(axiosInstance: AxiosInstance, moduleConfig: ApiModuleConfig<TActions>, options?: UseApiModuleOptions): UseApiModuleReturn<TActions>;
|
|
257
|
-
|
|
258
150
|
/**
|
|
259
151
|
* @file src/hooks/useApi.types.ts
|
|
260
152
|
* @description This file defines the professional, publicly-facing types for the `useApi` hook,
|
|
@@ -336,4 +228,4 @@ interface UseApiResourceReturn<T, TCreate, TUpdate, TPathParams> {
|
|
|
336
228
|
setQuery: React.Dispatch<React.SetStateAction<QueryOptions>>;
|
|
337
229
|
}
|
|
338
230
|
|
|
339
|
-
export { ActionConfigModule, ActionOptions, ActionStateModule, ApiClientConfig, ApiError,
|
|
231
|
+
export { ActionConfigModule, ActionOptions, ActionStateModule, ApiClientConfig, ApiError, type ApiResourceStatus, LogLevel, QueryOptions, RequestConfig, StandardResponse, type UseApiActions, UseApiQuery, type UseApiResourceActions, type UseApiResourceConfig, type UseApiResourceReturn, type UseApiResourceState, type UseApiReturn, buildPaginateQuery, cacheManager, callDynamicApi, createApiActions, createApiClient, createApiServices, globalStateManager, processResponse };
|