@dashadmin/dash-axios-hook 1.3.25 → 1.3.26

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 +1,51 @@
1
- const E=(s,t,n="update")=>{t||(t="");const c={update:"Actualizar",create:"Crear",delete:"Eliminar"},a=s.response?.data?.message||s.message||"Error al "+(c[n]||n)+" el recurso",i=s.response?.status||500;let e={errors:{}};if(s.response?.data?.errors){const o=s.response.data.errors;Object.keys(o).forEach(r=>{typeof o[r]=="string"?e.errors[r]=o[r]:Array.isArray(o[r])?e.errors[r]=o[r].join(", "):typeof o[r]=="object"&&(e.errors[r]=o[r])}),a&&(e.errors.root={serverError:a})}const u={message:a,status:i,body:e,resource:t,originalError:s,name:"Error"};return console.error("Update error:",{resource:t,errorMessage:a,status:i,validationErrors:e.errors,originalError:s}),u};var l=E;export{l as default};
1
+ const processAxiosError = (error, resource, method = "update") => {
2
+ var _a, _b, _c, _d, _e;
3
+ if (!resource) resource = "";
4
+ const methodMap = {
5
+ "update": "Actualizar",
6
+ "create": "Crear",
7
+ "delete": "Eliminar"
8
+ };
9
+ const errorMessage = ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message) || error.message || "Error al " + (methodMap[method] || method) + " el recurso";
10
+ const status = ((_c = error.response) == null ? void 0 : _c.status) || 500;
11
+ let body = {
12
+ errors: {}
13
+ };
14
+ if ((_e = (_d = error.response) == null ? void 0 : _d.data) == null ? void 0 : _e.errors) {
15
+ const validationErrors = error.response.data.errors;
16
+ Object.keys(validationErrors).forEach((field) => {
17
+ if (typeof validationErrors[field] === "string") {
18
+ body.errors[field] = validationErrors[field];
19
+ } else if (Array.isArray(validationErrors[field])) {
20
+ body.errors[field] = validationErrors[field].join(", ");
21
+ } else if (typeof validationErrors[field] === "object") {
22
+ body.errors[field] = validationErrors[field];
23
+ }
24
+ });
25
+ if (errorMessage) {
26
+ body.errors["root"] = {
27
+ serverError: errorMessage
28
+ };
29
+ }
30
+ }
31
+ const enhancedError = {
32
+ message: errorMessage,
33
+ status,
34
+ body,
35
+ resource,
36
+ originalError: error,
37
+ name: "Error"
38
+ };
39
+ console.error("Update error:", {
40
+ resource,
41
+ errorMessage,
42
+ status,
43
+ validationErrors: body.errors,
44
+ originalError: error
45
+ });
46
+ return enhancedError;
47
+ };
48
+ var processAxiosErrorFunction_default = processAxiosError;
49
+ export {
50
+ processAxiosErrorFunction_default as default
51
+ };
@@ -1 +1,199 @@
1
- import A from"axios";import{DASHAdminSystemConstants as l}from"@dashadmin/dash-constants";import{dashStorage as u}from"@dashadmin/dash-utils";import y from"./processAxiosErrorFunction";let f=!1,h=[];const d=(s,r=null)=>{h.forEach(a=>{s?a.reject(s):a.resolve(r)}),h=[]},k=async s=>{const r=u.getItem("refreshToken");if(!r)return console.log("[Axios] No refresh token available"),null;try{console.log("[Axios] Attempting to refresh access token...");const i=await A.create({baseURL:l.system.ADMIN_API_URL,headers:{"Content-Type":"application/json",Accept:"application/json"}}).post("/auth/refresh",{refresh_token:r});if(i.status===200&&i.data.token){const o=i.data.token,e=i.data.refresh_token;return u.setItem("token",o),e&&u.setItem("refreshToken",e),console.log("[Axios] Token refresh successful"),o}return null}catch(a){return console.error("[Axios] Token refresh failed:",a),null}},g=()=>{console.log("[Axios] Logging out due to authentication failure");debugger;u.clear(),localStorage.clear(),window.dispatchEvent(new CustomEvent("auth:logout",{detail:{reason:"token_refresh_failed"}}))},p=(s,r)=>{const a=typeof navigator<"u"&&navigator.language?navigator.language.split("-")[0]:"es",i={headers:{"Content-Type":"application/json","Accept-Language":"es",Accept:"application/json"},...s},o=A.create(i);return r&&(o.defaults.withCredentials=!0,o.get("/csrf-cookie").then(e=>{console.log("sanctum",e)})),o.interceptors.request.use(function(e){const t=u.getItem("token");t!==void 0&&t!=="undefined"&&(e.headers.Authorization="Bearer "+t);const c=u.getItem("active_tenant_id");return c&&(e.headers["X-Tenant-Id"]=c),e}),o.interceptors.response.use(e=>e,async e=>{const t=e.config;if(e.response?.status===401&&!t._retry){if(t.url?.includes("/login")||t.url?.includes("/auth/refresh")||t.url?.includes("/logout"))return Promise.reject(e);if(f)return new Promise((n,x)=>{h.push({resolve:n,reject:x})}).then(n=>(n&&t.headers&&(t.headers.Authorization=`Bearer ${n}`),o(t))).catch(n=>Promise.reject(n));t._retry=!0,f=!0;try{const n=await k(o);return n?(t.headers&&(t.headers.Authorization=`Bearer ${n}`),d(null,n),o(t)):(d(e,null),g(),Promise.reject(e))}catch(n){return d(n,null),g(),Promise.reject(n)}finally{f=!1}}return window.dispatchEvent(new MessageEvent("DASHGlobalError",{data:y(e,null,"list"),origin:"AxiosInterceptor"})),Promise.reject(e)}),o},m=s=>p({baseURL:l.system.ADMIN_API_URL,...s&&{...s}}),b=s=>p({baseURL:l.system.ADMIN_API_URL,...s&&{...s}});var D=m;export{b as createAxiosInstance,D as default,p as initAxios,m as useAxios};
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __spreadValues = (a, b) => {
7
+ for (var prop in b || (b = {}))
8
+ if (__hasOwnProp.call(b, prop))
9
+ __defNormalProp(a, prop, b[prop]);
10
+ if (__getOwnPropSymbols)
11
+ for (var prop of __getOwnPropSymbols(b)) {
12
+ if (__propIsEnum.call(b, prop))
13
+ __defNormalProp(a, prop, b[prop]);
14
+ }
15
+ return a;
16
+ };
17
+ var __async = (__this, __arguments, generator) => {
18
+ return new Promise((resolve, reject) => {
19
+ var fulfilled = (value) => {
20
+ try {
21
+ step(generator.next(value));
22
+ } catch (e) {
23
+ reject(e);
24
+ }
25
+ };
26
+ var rejected = (value) => {
27
+ try {
28
+ step(generator.throw(value));
29
+ } catch (e) {
30
+ reject(e);
31
+ }
32
+ };
33
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
34
+ step((generator = generator.apply(__this, __arguments)).next());
35
+ });
36
+ };
37
+ import axios from "axios";
38
+ import { DASHAdminSystemConstants } from "dash-constants";
39
+ import { dashStorage } from "dash-utils";
40
+ import processAxiosError from "./processAxiosErrorFunction";
41
+ let isRefreshing = false;
42
+ let failedQueue = [];
43
+ const processQueue = (error, token = null) => {
44
+ failedQueue.forEach((prom) => {
45
+ if (error) {
46
+ prom.reject(error);
47
+ } else {
48
+ prom.resolve(token);
49
+ }
50
+ });
51
+ failedQueue = [];
52
+ };
53
+ const refreshAccessToken = (axiosInstance) => __async(null, null, function* () {
54
+ const refreshToken = dashStorage.getItem("refreshToken");
55
+ if (!refreshToken) {
56
+ console.log("[Axios] No refresh token available");
57
+ return null;
58
+ }
59
+ try {
60
+ console.log("[Axios] Attempting to refresh access token...");
61
+ const refreshAxios = axios.create({
62
+ baseURL: DASHAdminSystemConstants.system.ADMIN_API_URL,
63
+ headers: {
64
+ "Content-Type": "application/json",
65
+ "Accept": "application/json"
66
+ }
67
+ });
68
+ const response = yield refreshAxios.post("/auth/refresh", {
69
+ refresh_token: refreshToken
70
+ });
71
+ if (response.status === 200 && response.data.token) {
72
+ const newToken = response.data.token;
73
+ const newRefreshToken = response.data.refresh_token;
74
+ dashStorage.setItem("token", newToken);
75
+ if (newRefreshToken) {
76
+ dashStorage.setItem("refreshToken", newRefreshToken);
77
+ }
78
+ console.log("[Axios] Token refresh successful");
79
+ return newToken;
80
+ }
81
+ return null;
82
+ } catch (error) {
83
+ console.error("[Axios] Token refresh failed:", error);
84
+ return null;
85
+ }
86
+ });
87
+ const handleLogout = () => {
88
+ console.log("[Axios] Logging out due to authentication failure");
89
+ debugger;
90
+ dashStorage.clear();
91
+ localStorage.clear();
92
+ window.dispatchEvent(new CustomEvent("auth:logout", {
93
+ detail: { reason: "token_refresh_failed" }
94
+ }));
95
+ };
96
+ const initAxios = (options, CSRFAuth) => {
97
+ const browserLanguage = typeof navigator !== "undefined" && navigator.language ? navigator.language.split("-")[0] : "es";
98
+ const _options = __spreadValues({
99
+ headers: {
100
+ "Content-Type": "application/json",
101
+ //'Accept-Language': browserLanguage || 'es', // fallback to 'es' if not available
102
+ "Accept-Language": "es",
103
+ Accept: "application/json"
104
+ }
105
+ }, options);
106
+ const instance = axios.create(_options);
107
+ if (CSRFAuth) {
108
+ instance.defaults.withCredentials = true;
109
+ instance.get("/csrf-cookie").then((response) => {
110
+ console.log("sanctum", response);
111
+ });
112
+ }
113
+ instance.interceptors.request.use(function(config) {
114
+ const token = dashStorage.getItem("token");
115
+ if (token !== void 0 && token !== "undefined") {
116
+ config.headers.Authorization = "Bearer " + token;
117
+ }
118
+ const activeTenantId = dashStorage.getItem("active_tenant_id");
119
+ if (activeTenantId) {
120
+ config.headers["X-Tenant-Id"] = activeTenantId;
121
+ }
122
+ return config;
123
+ });
124
+ instance.interceptors.response.use(
125
+ (response) => {
126
+ return response;
127
+ },
128
+ (error) => __async(null, null, function* () {
129
+ var _a, _b, _c, _d;
130
+ const originalRequest = error.config;
131
+ if (((_a = error.response) == null ? void 0 : _a.status) === 401 && !originalRequest._retry) {
132
+ const isAuthEndpoint = ((_b = originalRequest.url) == null ? void 0 : _b.includes("/login")) || ((_c = originalRequest.url) == null ? void 0 : _c.includes("/auth/refresh")) || ((_d = originalRequest.url) == null ? void 0 : _d.includes("/logout"));
133
+ if (isAuthEndpoint) {
134
+ return Promise.reject(error);
135
+ }
136
+ if (isRefreshing) {
137
+ return new Promise((resolve, reject) => {
138
+ failedQueue.push({ resolve, reject });
139
+ }).then((token) => {
140
+ if (token && originalRequest.headers) {
141
+ originalRequest.headers.Authorization = `Bearer ${token}`;
142
+ }
143
+ return instance(originalRequest);
144
+ }).catch((err) => {
145
+ return Promise.reject(err);
146
+ });
147
+ }
148
+ originalRequest._retry = true;
149
+ isRefreshing = true;
150
+ try {
151
+ const newToken = yield refreshAccessToken(instance);
152
+ if (newToken) {
153
+ if (originalRequest.headers) {
154
+ originalRequest.headers.Authorization = `Bearer ${newToken}`;
155
+ }
156
+ processQueue(null, newToken);
157
+ return instance(originalRequest);
158
+ } else {
159
+ processQueue(error, null);
160
+ handleLogout();
161
+ return Promise.reject(error);
162
+ }
163
+ } catch (refreshError) {
164
+ processQueue(refreshError, null);
165
+ handleLogout();
166
+ return Promise.reject(refreshError);
167
+ } finally {
168
+ isRefreshing = false;
169
+ }
170
+ }
171
+ window.dispatchEvent(
172
+ new MessageEvent("DASHGlobalError", {
173
+ data: processAxiosError(error, null, "list"),
174
+ origin: "AxiosInterceptor"
175
+ })
176
+ );
177
+ return Promise.reject(error);
178
+ })
179
+ );
180
+ return instance;
181
+ };
182
+ const useAxios = (options) => {
183
+ const a = initAxios(__spreadValues({
184
+ baseURL: DASHAdminSystemConstants.system.ADMIN_API_URL
185
+ }, options && __spreadValues({}, options)));
186
+ return a;
187
+ };
188
+ const createAxiosInstance = (options) => {
189
+ return initAxios(__spreadValues({
190
+ baseURL: DASHAdminSystemConstants.system.ADMIN_API_URL
191
+ }, options && __spreadValues({}, options)));
192
+ };
193
+ var useAxios_default = useAxios;
194
+ export {
195
+ createAxiosInstance,
196
+ useAxios_default as default,
197
+ initAxios,
198
+ useAxios
199
+ };
@@ -1 +1,63 @@
1
- import{useEffect as y,useState as u}from"react";import{useStore as m}from"react-admin";import x from"./useAxios";const p=(e,o,a)=>o.split(".").reduce((s,i)=>s?s[i]:a,e),S=e=>{const{storeKey:o,dataPath:a="data"}=e,s=x(),[i,c]=u(null),[d,f]=u(!1),[l,h]=m(o,null),n=async r=>{try{const t=await s({method:r.method,url:`${r.url}${r.payload?"?"+r.payload:""}`});(t.status>=200||t.status<300)&&h(p(t,a,null))}catch(t){c(t)}finally{f(!0)}};return y(()=>{l||n(e)},[]),{request:n,results:l,error:i,loaded:d}};var W=S;export{W as default};
1
+ var __async = (__this, __arguments, generator) => {
2
+ return new Promise((resolve, reject) => {
3
+ var fulfilled = (value) => {
4
+ try {
5
+ step(generator.next(value));
6
+ } catch (e) {
7
+ reject(e);
8
+ }
9
+ };
10
+ var rejected = (value) => {
11
+ try {
12
+ step(generator.throw(value));
13
+ } catch (e) {
14
+ reject(e);
15
+ }
16
+ };
17
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
18
+ step((generator = generator.apply(__this, __arguments)).next());
19
+ });
20
+ };
21
+ import { useEffect, useState } from "react";
22
+ import { useStore } from "react-admin";
23
+ import useAxios from "./useAxios";
24
+ const resolveObjectPath = (object, path, defaultValue) => path.split(".").reduce((o, p) => o ? o[p] : defaultValue, object);
25
+ const useAxiosGetWithStore = (options) => {
26
+ const {
27
+ /*method = 'GET',
28
+ url,
29
+ payload = null,*/
30
+ storeKey,
31
+ dataPath = "data"
32
+ } = options;
33
+ const axios = useAxios();
34
+ const [error, setError] = useState(null);
35
+ const [loaded, setLoaded] = useState(false);
36
+ const [results, setResults] = useStore(storeKey, null);
37
+ const request = (ops) => __async(null, null, function* () {
38
+ try {
39
+ const response = yield axios({
40
+ method: ops.method,
41
+ url: `${ops.url}${ops.payload ? "?" + ops.payload : ""}`
42
+ });
43
+ if (response.status >= 200 || response.status < 300) {
44
+ setResults(resolveObjectPath(response, dataPath, null));
45
+ }
46
+ } catch (e) {
47
+ setError(e);
48
+ } finally {
49
+ setLoaded(true);
50
+ }
51
+ });
52
+ useEffect(() => {
53
+ if (!results) {
54
+ request(options);
55
+ } else {
56
+ }
57
+ }, []);
58
+ return { request, results, error, loaded };
59
+ };
60
+ var useAxiosWithStore_default = useAxiosGetWithStore;
61
+ export {
62
+ useAxiosWithStore_default as default
63
+ };
package/dist/index.js CHANGED
@@ -1,154 +1,9 @@
1
- import k from "axios";
2
- import { DASHAdminSystemConstants as A } from "@dashadmin/dash-constants";
3
- import { dashStorage as l } from "@dashadmin/dash-utils";
4
- import { useState as y, useEffect as v } from "react";
5
- import { useStore as I } from "react-admin";
6
- const _ = (t, n, a = "update") => {
7
- n || (n = "");
8
- const s = {
9
- update: "Actualizar",
10
- create: "Crear",
11
- delete: "Eliminar"
12
- }, e = t.response?.data?.message || t.message || "Error al " + (s[a] || a) + " el recurso", r = t.response?.status || 500;
13
- let i = {
14
- errors: {}
15
- };
16
- if (t.response?.data?.errors) {
17
- const c = t.response.data.errors;
18
- Object.keys(c).forEach((u) => {
19
- typeof c[u] == "string" ? i.errors[u] = c[u] : Array.isArray(c[u]) ? i.errors[u] = c[u].join(", ") : typeof c[u] == "object" && (i.errors[u] = c[u]);
20
- }), e && (i.errors.root = {
21
- serverError: e
22
- });
23
- }
24
- const o = {
25
- message: e,
26
- status: r,
27
- body: i,
28
- resource: n,
29
- originalError: t,
30
- name: "Error"
31
- };
32
- return console.error("Update error:", {
33
- resource: n,
34
- errorMessage: e,
35
- status: r,
36
- validationErrors: i.errors,
37
- originalError: t
38
- }), o;
39
- };
40
- let d = !1, g = [];
41
- const p = (t, n = null) => {
42
- g.forEach((a) => {
43
- t ? a.reject(t) : a.resolve(n);
44
- }), g = [];
45
- }, j = async (t) => {
46
- const n = l.getItem("refreshToken");
47
- if (!n)
48
- return console.log("[Axios] No refresh token available"), null;
49
- try {
50
- console.log("[Axios] Attempting to refresh access token...");
51
- const s = await k.create({
52
- baseURL: A.system.ADMIN_API_URL,
53
- headers: {
54
- "Content-Type": "application/json",
55
- Accept: "application/json"
56
- }
57
- }).post("/auth/refresh", {
58
- refresh_token: n
59
- });
60
- if (s.status === 200 && s.data.token) {
61
- const e = s.data.token, r = s.data.refresh_token;
62
- return l.setItem("token", e), r && l.setItem("refreshToken", r), console.log("[Axios] Token refresh successful"), e;
63
- }
64
- return null;
65
- } catch (a) {
66
- return console.error("[Axios] Token refresh failed:", a), null;
67
- }
68
- }, E = () => {
69
- console.log("[Axios] Logging out due to authentication failure");
70
- debugger;
71
- l.clear(), localStorage.clear(), window.dispatchEvent(new CustomEvent("auth:logout", {
72
- detail: { reason: "token_refresh_failed" }
73
- }));
74
- }, x = (t, n) => {
75
- typeof navigator < "u" && navigator.language && navigator.language.split("-")[0];
76
- const a = {
77
- headers: {
78
- "Content-Type": "application/json",
79
- //'Accept-Language': browserLanguage || 'es', // fallback to 'es' if not available
80
- "Accept-Language": "es",
81
- Accept: "application/json"
82
- },
83
- ...t
84
- }, s = k.create(a);
85
- return s.interceptors.request.use(function(e) {
86
- const r = l.getItem("token");
87
- r !== void 0 && r !== "undefined" && (e.headers.Authorization = "Bearer " + r);
88
- const i = l.getItem("active_tenant_id");
89
- return i && (e.headers["X-Tenant-Id"] = i), e;
90
- }), s.interceptors.response.use(
91
- (e) => e,
92
- async (e) => {
93
- const r = e.config;
94
- if (e.response?.status === 401 && !r._retry) {
95
- if (r.url?.includes("/login") || r.url?.includes("/auth/refresh") || r.url?.includes("/logout"))
96
- return Promise.reject(e);
97
- if (d)
98
- return new Promise((o, c) => {
99
- g.push({ resolve: o, reject: c });
100
- }).then((o) => (o && r.headers && (r.headers.Authorization = `Bearer ${o}`), s(r))).catch((o) => Promise.reject(o));
101
- r._retry = !0, d = !0;
102
- try {
103
- const o = await j(s);
104
- return o ? (r.headers && (r.headers.Authorization = `Bearer ${o}`), p(null, o), s(r)) : (p(e, null), E(), Promise.reject(e));
105
- } catch (o) {
106
- return p(o, null), E(), Promise.reject(o);
107
- } finally {
108
- d = !1;
109
- }
110
- }
111
- return window.dispatchEvent(
112
- new MessageEvent("DASHGlobalError", {
113
- data: _(e, null, "list"),
114
- origin: "AxiosInterceptor"
115
- })
116
- ), Promise.reject(e);
117
- }
118
- ), s;
119
- }, w = (t) => x({
120
- baseURL: A.system.ADMIN_API_URL,
121
- ...t && { ...t }
122
- }), U = (t) => x({
123
- baseURL: A.system.ADMIN_API_URL,
124
- ...t && { ...t }
125
- }), T = (t, n, a) => n.split(".").reduce((s, e) => s ? s[e] : a, t), C = (t) => {
126
- const {
127
- /*method = 'GET',
128
- url,
129
- payload = null,*/
130
- storeKey: n,
131
- dataPath: a = "data"
132
- } = t, s = w(), [e, r] = y(null), [i, o] = y(!1), [c, u] = I(n, null), m = async (h) => {
133
- try {
134
- const f = await s({
135
- method: h.method,
136
- url: `${h.url}${h.payload ? "?" + h.payload : ""}`
137
- });
138
- (f.status >= 200 || f.status < 300) && u(T(f, a, null));
139
- } catch (f) {
140
- r(f);
141
- } finally {
142
- o(!0);
143
- }
144
- };
145
- return v(() => {
146
- c || m(t);
147
- }, []), { request: m, results: c, error: e, loaded: i };
148
- };
1
+ import { default as default2, createAxiosInstance } from "./hooks/useAxios";
2
+ import { default as default3 } from "./hooks/useAxiosWithStore";
3
+ import { default as default4 } from "./hooks/processAxiosErrorFunction";
149
4
  export {
150
- U as createAxiosInstance,
151
- _ as processAxiosError,
152
- w as useAxios,
153
- C as useAxiosGetWithStore
5
+ createAxiosInstance,
6
+ default4 as processAxiosError,
7
+ default2 as useAxios,
8
+ default3 as useAxiosGetWithStore
154
9
  };
package/package.json CHANGED
@@ -1,53 +1,63 @@
1
1
  {
2
- "name": "@dashadmin/dash-axios-hook",
3
- "version": "1.3.25",
4
- "private": false,
5
- "license": "MIT",
6
- "main": "dist/index.js",
7
- "devDependencies": {
8
- "@commitlint/cli": "latest",
9
- "@commitlint/config-conventional": "latest",
10
- "@types/jest": "latest",
11
- "@types/node": "latest",
12
- "@types/react": "latest",
13
- "@types/react-dom": "latest",
14
- "@typescript-eslint/eslint-plugin": "latest",
15
- "@typescript-eslint/parser": "latest",
16
- "eslint-config-airbnb-typescript": "latest",
17
- "eslint-config-prettier": "latest",
18
- "eslint-plugin-html": "latest",
19
- "eslint-plugin-import": "latest",
20
- "eslint-plugin-jsdoc": "latest",
21
- "eslint-plugin-json": "latest",
22
- "eslint-plugin-prettier": "latest",
23
- "ts-jest": "latest",
24
- "ts-loader": "latest",
25
- "tsconfig-paths": "latest",
26
- "typescript": "latest",
27
- "vite": "^5.2.0",
28
- "rollup": "^4.0.0"
29
- },
30
- "dependencies": {
31
- "@mui/material": "^7.3.10",
32
- "@dashadmin/dash-constants": "1.3.25",
33
- "@dashadmin/dash-utils": "1.3.25"
34
- },
35
- "publishConfig": {
36
- "name": "@dashadmin/dash-axios-hook",
37
- "access": "public"
38
- },
39
- "files": [
40
- "dist"
41
- ],
42
- "exports": {
43
- ".": {
44
- "import": "./dist/index.js"
45
- },
46
- "./src/*": {
47
- "import": "./dist/*.js"
48
- }
49
- },
50
- "scripts": {
51
- "build": "rm -rf dist && node ../dash-build/compile.mjs && vite build"
52
- }
53
- }
2
+ "name": "@dashadmin/dash-axios-hook",
3
+ "version": "1.3.26",
4
+ "license": "MIT",
5
+ "main": "dist/index.js",
6
+ "devDependencies": {
7
+ "@commitlint/cli": "latest",
8
+ "@commitlint/config-conventional": "latest",
9
+ "@types/jest": "latest",
10
+ "@types/node": "latest",
11
+ "@types/react": "latest",
12
+ "@types/react-dom": "latest",
13
+ "@typescript-eslint/eslint-plugin": "latest",
14
+ "@typescript-eslint/parser": "latest",
15
+ "eslint-config-airbnb-typescript": "latest",
16
+ "eslint-config-prettier": "latest",
17
+ "eslint-plugin-html": "latest",
18
+ "eslint-plugin-import": "latest",
19
+ "eslint-plugin-jsdoc": "latest",
20
+ "eslint-plugin-json": "latest",
21
+ "eslint-plugin-prettier": "latest",
22
+ "ts-jest": "latest",
23
+ "ts-loader": "latest",
24
+ "tsconfig-paths": "latest",
25
+ "typescript": "latest"
26
+ },
27
+ "dependencies": {
28
+ "@mui/material": "^7.3.10",
29
+ "@dashadmin/dash-constants": "workspace:*",
30
+ "@dashadmin/dash-utils": "workspace:*"
31
+ },
32
+ "module": "dist/index.js",
33
+ "types": "./src/index.tsx",
34
+ "exports": {
35
+ ".": "./dist/index.js",
36
+ "./*": "./dist/*.js",
37
+ "./src/*": "./dist/*.js"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public",
41
+ "registry": "https://registry.npmjs.org"
42
+ },
43
+ "scripts": {
44
+ "build": "tsup"
45
+ },
46
+ "type": "module",
47
+ "files": [
48
+ "dist",
49
+ "src"
50
+ ],
51
+ "typesVersions": {
52
+ "*": {
53
+ "src/*": [
54
+ "src/*",
55
+ "src/*/index"
56
+ ],
57
+ "*": [
58
+ "src/*",
59
+ "src/*/index"
60
+ ]
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,73 @@
1
+ import { AxiosError } from 'axios';
2
+ import { IDashAutoAdminBackendError,IDashAutoAdminDefaultBackendStructure } from '../interfaces/IDashAutoAdminBackendError';
3
+
4
+
5
+ const processAxiosError = (error:AxiosError<IDashAutoAdminDefaultBackendStructure>,resource?:string,method:string='update') => {
6
+
7
+ if(!resource) resource = ""
8
+ // Map method to Spanish action words
9
+ const methodMap = {
10
+ 'update': 'Actualizar',
11
+ 'create': 'Crear',
12
+ 'delete': 'Eliminar'
13
+ };
14
+
15
+ // Extract error details
16
+ const errorMessage = error.response?.data?.message || error.message || 'Error al '+ (methodMap[method] || method) +' el recurso';
17
+ // Get HTTP status or fallback to 500
18
+ const status = error.response?.status || 500;
19
+
20
+ // If validation errors exist, format them for React Admin
21
+ let body = {
22
+ errors: {}
23
+ };
24
+
25
+ if (error.response?.data?.errors) {
26
+
27
+
28
+ // Format Laravel validation errors for React Admin
29
+ const validationErrors = error.response.data.errors;
30
+ Object.keys(validationErrors).forEach(field => {
31
+ if (typeof validationErrors[field] === 'string') {
32
+ body.errors[field] = validationErrors[field];
33
+ } else if (Array.isArray(validationErrors[field])) {
34
+ body.errors[field] = validationErrors[field].join(', ');
35
+ } else if (typeof validationErrors[field] === 'object') {
36
+ body.errors[field] = validationErrors[field];
37
+ }
38
+ });
39
+
40
+ // Add global validation error if exists
41
+ if (errorMessage) {
42
+ body.errors["root"] = {
43
+ serverError: errorMessage
44
+ };
45
+ }
46
+ }
47
+
48
+ // Create an enhanced error object that React Admin can understand
49
+ const enhancedError = {
50
+ message: errorMessage,
51
+ status: status,
52
+ body: body,
53
+ resource: resource,
54
+ originalError: error,
55
+ name: 'Error'
56
+ } as IDashAutoAdminBackendError;
57
+
58
+ // Log for debugging
59
+ console.error('Update error:', {
60
+ resource,
61
+ errorMessage,
62
+ status,
63
+ validationErrors: body.errors,
64
+ originalError: error
65
+ });
66
+
67
+
68
+
69
+ return enhancedError;
70
+
71
+ }
72
+
73
+ export default processAxiosError;
@@ -0,0 +1,236 @@
1
+ import axios, { Axios, AxiosError, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
2
+
3
+ import {DASHAdminSystemConstants} from 'dash-constants'
4
+
5
+ import { dashStorage } from 'dash-utils';
6
+
7
+ import processAxiosError from './processAxiosErrorFunction';
8
+ import { IDashAutoAdminDefaultBackendStructure } from '../interfaces/IDashAutoAdminBackendError';
9
+
10
+ //import { getCookie } from '../utils/cookies';
11
+
12
+ // Flag to prevent multiple simultaneous refresh requests
13
+ let isRefreshing = false;
14
+ // Queue of requests waiting for token refresh
15
+ let failedQueue: Array<{
16
+ resolve: (value?: unknown) => void;
17
+ reject: (reason?: any) => void;
18
+ }> = [];
19
+
20
+ const processQueue = (error: any, token: string | null = null) => {
21
+ failedQueue.forEach(prom => {
22
+ if (error) {
23
+ prom.reject(error);
24
+ } else {
25
+ prom.resolve(token);
26
+ }
27
+ });
28
+ failedQueue = [];
29
+ };
30
+
31
+ // Function to refresh the token
32
+ const refreshAccessToken = async (axiosInstance: any): Promise<string | null> => {
33
+ const refreshToken = dashStorage.getItem('refreshToken');
34
+
35
+ if (!refreshToken) {
36
+ console.log('[Axios] No refresh token available');
37
+ return null;
38
+ }
39
+
40
+ try {
41
+ console.log('[Axios] Attempting to refresh access token...');
42
+
43
+ // Create a new axios instance without interceptors to avoid infinite loops
44
+ const refreshAxios = axios.create({
45
+ baseURL: DASHAdminSystemConstants.system.ADMIN_API_URL,
46
+ headers: {
47
+ 'Content-Type': 'application/json',
48
+ 'Accept': 'application/json',
49
+ },
50
+ });
51
+
52
+ const response = await refreshAxios.post('/auth/refresh', {
53
+ refresh_token: refreshToken,
54
+ });
55
+
56
+ if (response.status === 200 && response.data.token) {
57
+ const newToken = response.data.token;
58
+ const newRefreshToken = response.data.refresh_token;
59
+
60
+ // Store new tokens
61
+ dashStorage.setItem('token', newToken);
62
+ if (newRefreshToken) {
63
+ dashStorage.setItem('refreshToken', newRefreshToken);
64
+ }
65
+
66
+ console.log('[Axios] Token refresh successful');
67
+ return newToken;
68
+ }
69
+
70
+ return null;
71
+ } catch (error) {
72
+ console.error('[Axios] Token refresh failed:', error);
73
+ return null;
74
+ }
75
+ };
76
+
77
+ // Function to handle logout
78
+ const handleLogout = () => {
79
+ console.log('[Axios] Logging out due to authentication failure');
80
+ debugger;
81
+ // Clear all auth data
82
+ //dashStorage.removeItem('token');
83
+ //dashStorage.removeItem('refreshToken');
84
+ //dashStorage.removeItem('authenticated');
85
+ //dashStorage.removeItem('user');
86
+ //dashStorage.removeItem('roles');
87
+ dashStorage.clear();
88
+ localStorage.clear();
89
+ // Dispatch logout event for the app to handle
90
+ window.dispatchEvent(new CustomEvent('auth:logout', {
91
+ detail: { reason: 'token_refresh_failed' }
92
+ }));
93
+ };
94
+
95
+ export const initAxios = (
96
+ options: Partial<AxiosRequestConfig<any>>,
97
+ CSRFAuth?: boolean,
98
+ ) => {
99
+ const browserLanguage = typeof navigator !== 'undefined' && navigator.language ? navigator.language.split('-')[0] : 'es';
100
+ const _options = {
101
+ headers: {
102
+ 'Content-Type': 'application/json',
103
+ //'Accept-Language': browserLanguage || 'es', // fallback to 'es' if not available
104
+ 'Accept-Language':'es',
105
+ Accept: 'application/json',
106
+ },
107
+ ...options,
108
+ };
109
+
110
+ const instance = axios.create(_options);
111
+
112
+ if (CSRFAuth) {
113
+ instance.defaults.withCredentials = true;
114
+ instance.get('/csrf-cookie').then((response) => {
115
+ console.log('sanctum', response);
116
+ });
117
+ }
118
+
119
+ instance.interceptors.request.use(function (config) {
120
+ const token = dashStorage.getItem('token');
121
+ //console.log("axios Hook", axios, token);
122
+ if (token !== undefined && token !== 'undefined') {
123
+ config.headers.Authorization = 'Bearer ' + token;
124
+ }
125
+
126
+ // Inject X-Tenant-Id header when tenant impersonation is active
127
+ const activeTenantId = dashStorage.getItem('active_tenant_id');
128
+ if (activeTenantId) {
129
+ config.headers['X-Tenant-Id'] = activeTenantId;
130
+ }
131
+
132
+ return config;
133
+ });
134
+
135
+ instance.interceptors.response.use(
136
+ (response) => {
137
+ //console.log("Axios Success", response);
138
+ return response;
139
+ },
140
+ async (error: AxiosError<IDashAutoAdminDefaultBackendStructure, any>) => {
141
+ const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };
142
+
143
+ // Handle 401 Unauthorized errors
144
+ if (error.response?.status === 401 && !originalRequest._retry) {
145
+ // Skip refresh for auth endpoints to prevent infinite loops
146
+ const isAuthEndpoint = originalRequest.url?.includes('/login') ||
147
+ originalRequest.url?.includes('/auth/refresh') ||
148
+ originalRequest.url?.includes('/logout');
149
+
150
+ if (isAuthEndpoint) {
151
+ return Promise.reject(error);
152
+ }
153
+
154
+ if (isRefreshing) {
155
+ // If already refreshing, queue this request
156
+ return new Promise((resolve, reject) => {
157
+ failedQueue.push({ resolve, reject });
158
+ }).then(token => {
159
+ if (token && originalRequest.headers) {
160
+ originalRequest.headers.Authorization = `Bearer ${token}`;
161
+ }
162
+ return instance(originalRequest);
163
+ }).catch(err => {
164
+ return Promise.reject(err);
165
+ });
166
+ }
167
+
168
+ originalRequest._retry = true;
169
+ isRefreshing = true;
170
+
171
+ try {
172
+ const newToken = await refreshAccessToken(instance);
173
+
174
+ if (newToken) {
175
+ // Update the authorization header
176
+ if (originalRequest.headers) {
177
+ originalRequest.headers.Authorization = `Bearer ${newToken}`;
178
+ }
179
+
180
+ // Process queued requests
181
+ processQueue(null, newToken);
182
+
183
+ // Retry the original request
184
+ return instance(originalRequest);
185
+ } else {
186
+ // Refresh failed - logout user
187
+ processQueue(error, null);
188
+ handleLogout();
189
+ return Promise.reject(error);
190
+ }
191
+ } catch (refreshError) {
192
+ processQueue(refreshError, null);
193
+ handleLogout();
194
+ return Promise.reject(refreshError);
195
+ } finally {
196
+ isRefreshing = false;
197
+ }
198
+ }
199
+
200
+ // Dispatch global error event for non-401 errors
201
+ window.dispatchEvent(
202
+ new MessageEvent('DASHGlobalError', {
203
+ data: processAxiosError(error, null, "list"),
204
+ origin: "AxiosInterceptor"
205
+ }),
206
+ );
207
+
208
+ return Promise.reject(error);
209
+ },
210
+ );
211
+
212
+ return instance;
213
+ };
214
+
215
+ // Hook version (for use in React components)
216
+ const useAxios = (options?: Partial<AxiosRequestConfig<any>>) => {
217
+ const a = initAxios({
218
+ baseURL: DASHAdminSystemConstants.system.ADMIN_API_URL,
219
+ ...(options) && {...options}
220
+ });
221
+ return a;
222
+ };
223
+
224
+ // Non-hook version (for use in classes and regular functions)
225
+ export const createAxiosInstance = (options?: Partial<AxiosRequestConfig<any>>) => {
226
+ return initAxios({
227
+ baseURL: DASHAdminSystemConstants.system.ADMIN_API_URL,
228
+ ...(options) && {...options}
229
+ });
230
+ };
231
+
232
+ // Default export is the hook
233
+ export default useAxios;
234
+
235
+ // Named export for non-hook usage
236
+ export { useAxios };
@@ -0,0 +1,66 @@
1
+
2
+ import { useEffect, useState } from 'react';
3
+ //import queryString from 'query-string';
4
+ import { useStore } from 'react-admin';
5
+ import useAxios from './useAxios';
6
+
7
+ export interface IUseAxiosGetWithStore {
8
+ method?: string;
9
+ url: string;
10
+ payload?: any;
11
+ storeKey: string;
12
+ dataPath?: string;
13
+ }
14
+
15
+ const resolveObjectPath = (object, path, defaultValue) =>
16
+ path.split('.').reduce((o, p) => (o ? o[p] : defaultValue), object);
17
+
18
+ const useAxiosGetWithStore = (options: IUseAxiosGetWithStore) => {
19
+ const {
20
+ /*method = 'GET',
21
+ url,
22
+ payload = null,*/
23
+ storeKey,
24
+ dataPath = 'data',
25
+ } = options;
26
+ const axios = useAxios();
27
+
28
+ const [error, setError] = useState(null);
29
+ const [loaded, setLoaded] = useState(false);
30
+
31
+ const [results, setResults] = useStore(storeKey, null);
32
+
33
+ const request = async (ops: IUseAxiosGetWithStore) => {
34
+ //const payload = queryString.stringify(ops.payload, { arrayFormat: 'bracket' });
35
+
36
+ try {
37
+ //console.log('useAxiosGetWithStore performing query:', ops);
38
+ const response = await axios({
39
+ method: ops.method,
40
+ url: `${ops.url}${ops.payload ? '?' + ops.payload : ''}`,
41
+ });
42
+
43
+ if (response.status >= 200 || response.status < 300) {
44
+ setResults(resolveObjectPath(response, dataPath, null));
45
+ }
46
+ } catch (e:any) {
47
+ setError(e);
48
+ } finally {
49
+ setLoaded(true);
50
+ }
51
+ };
52
+
53
+ useEffect(() => {
54
+ //console.log('useAxiosGetWithStore results:', results);
55
+ if (!results) {
56
+ //console.log('Therefore, performing request');
57
+ request(options);
58
+ } else {
59
+ //console.log('returning stored results');
60
+ }
61
+ }, []);
62
+
63
+ return { request, results, error, loaded };
64
+ };
65
+
66
+ export default useAxiosGetWithStore;
package/src/index.tsx ADDED
@@ -0,0 +1,4 @@
1
+ export { default as useAxios, createAxiosInstance } from "./hooks/useAxios";
2
+ export { default as useAxiosGetWithStore } from "./hooks/useAxiosWithStore";
3
+ export type { IDashAutoAdminBackendError,IDashAutoAdminDefaultBackendStructure } from "./interfaces/IDashAutoAdminBackendError";
4
+ export { default as processAxiosError } from "./hooks/processAxiosErrorFunction";
@@ -0,0 +1,21 @@
1
+ import { AxiosError } from 'axios';
2
+
3
+ export interface IDashAutoAdminBackendError {
4
+ status: number;
5
+ body: Body;
6
+ resource: string;
7
+ originalError: AxiosError<IDashAutoAdminDefaultBackendStructure>;
8
+ message?: string;
9
+ }
10
+
11
+ export interface IDashAutoAdminDefaultBackendStructure {
12
+ message: string;
13
+ errors: {
14
+ [key: string]: string[];
15
+ };
16
+ }
17
+
18
+ interface Body {
19
+ [x:string]: any
20
+ }
21
+