@nocios/crudify-ui 3.0.48 → 3.0.50
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/index.d.mts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +194 -159
- package/dist/index.mjs +194 -159
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -227,6 +227,8 @@ type SessionConfig = {
|
|
|
227
227
|
onSessionRestored?: (tokens: TokenData) => void;
|
|
228
228
|
onLoginSuccess?: (tokens: TokenData) => void;
|
|
229
229
|
onLogout?: () => void;
|
|
230
|
+
showNotification?: (message: string, severity?: "error" | "info" | "success" | "warning") => void;
|
|
231
|
+
translateFn?: (key: string) => string;
|
|
230
232
|
};
|
|
231
233
|
type LoginResult = {
|
|
232
234
|
success: boolean;
|
|
@@ -298,6 +300,10 @@ declare class SessionManager {
|
|
|
298
300
|
* Limpiar sesión completamente
|
|
299
301
|
*/
|
|
300
302
|
clearSession(): void;
|
|
303
|
+
/**
|
|
304
|
+
* Obtener mensaje de sesión expirada traducido
|
|
305
|
+
*/
|
|
306
|
+
private getSessionExpiredMessage;
|
|
301
307
|
private log;
|
|
302
308
|
private formatError;
|
|
303
309
|
}
|
|
@@ -314,6 +320,8 @@ type UseSessionOptions = {
|
|
|
314
320
|
enableLogging?: boolean;
|
|
315
321
|
onSessionExpired?: () => void;
|
|
316
322
|
onSessionRestored?: (tokens: TokenData) => void;
|
|
323
|
+
showNotification?: (message: string, severity?: "error" | "info" | "success" | "warning") => void;
|
|
324
|
+
translateFn?: (key: string) => string;
|
|
317
325
|
};
|
|
318
326
|
declare function useSession(options?: UseSessionOptions): {
|
|
319
327
|
login: (email: string, password: string) => Promise<LoginResult>;
|
|
@@ -400,10 +408,9 @@ type SessionProviderProps = {
|
|
|
400
408
|
notificationOptions?: NotificationOptions;
|
|
401
409
|
};
|
|
402
410
|
/**
|
|
403
|
-
* Provider de sesión para envolver la aplicación
|
|
411
|
+
* Provider de sesión principal para envolver la aplicación
|
|
404
412
|
*/
|
|
405
|
-
declare function SessionProvider(
|
|
406
|
-
notificationOptions, }: SessionProviderProps): react_jsx_runtime.JSX.Element;
|
|
413
|
+
declare function SessionProvider(props: SessionProviderProps): react_jsx_runtime.JSX.Element;
|
|
407
414
|
/**
|
|
408
415
|
* Hook para usar el contexto de sesión
|
|
409
416
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -227,6 +227,8 @@ type SessionConfig = {
|
|
|
227
227
|
onSessionRestored?: (tokens: TokenData) => void;
|
|
228
228
|
onLoginSuccess?: (tokens: TokenData) => void;
|
|
229
229
|
onLogout?: () => void;
|
|
230
|
+
showNotification?: (message: string, severity?: "error" | "info" | "success" | "warning") => void;
|
|
231
|
+
translateFn?: (key: string) => string;
|
|
230
232
|
};
|
|
231
233
|
type LoginResult = {
|
|
232
234
|
success: boolean;
|
|
@@ -298,6 +300,10 @@ declare class SessionManager {
|
|
|
298
300
|
* Limpiar sesión completamente
|
|
299
301
|
*/
|
|
300
302
|
clearSession(): void;
|
|
303
|
+
/**
|
|
304
|
+
* Obtener mensaje de sesión expirada traducido
|
|
305
|
+
*/
|
|
306
|
+
private getSessionExpiredMessage;
|
|
301
307
|
private log;
|
|
302
308
|
private formatError;
|
|
303
309
|
}
|
|
@@ -314,6 +320,8 @@ type UseSessionOptions = {
|
|
|
314
320
|
enableLogging?: boolean;
|
|
315
321
|
onSessionExpired?: () => void;
|
|
316
322
|
onSessionRestored?: (tokens: TokenData) => void;
|
|
323
|
+
showNotification?: (message: string, severity?: "error" | "info" | "success" | "warning") => void;
|
|
324
|
+
translateFn?: (key: string) => string;
|
|
317
325
|
};
|
|
318
326
|
declare function useSession(options?: UseSessionOptions): {
|
|
319
327
|
login: (email: string, password: string) => Promise<LoginResult>;
|
|
@@ -400,10 +408,9 @@ type SessionProviderProps = {
|
|
|
400
408
|
notificationOptions?: NotificationOptions;
|
|
401
409
|
};
|
|
402
410
|
/**
|
|
403
|
-
* Provider de sesión para envolver la aplicación
|
|
411
|
+
* Provider de sesión principal para envolver la aplicación
|
|
404
412
|
*/
|
|
405
|
-
declare function SessionProvider(
|
|
406
|
-
notificationOptions, }: SessionProviderProps): react_jsx_runtime.JSX.Element;
|
|
413
|
+
declare function SessionProvider(props: SessionProviderProps): react_jsx_runtime.JSX.Element;
|
|
407
414
|
/**
|
|
408
415
|
* Hook para usar el contexto de sesión
|
|
409
416
|
*/
|
package/dist/index.js
CHANGED
|
@@ -662,6 +662,162 @@ _TokenStorage.ENCRYPTION_KEY = "crudify_secure_key_v1";
|
|
|
662
662
|
_TokenStorage.storageType = "localStorage";
|
|
663
663
|
var TokenStorage = _TokenStorage;
|
|
664
664
|
|
|
665
|
+
// src/utils/errorTranslation.ts
|
|
666
|
+
var ERROR_TRANSLATION_HIERARCHY = [
|
|
667
|
+
"errors.{category}.{code}",
|
|
668
|
+
// errors.auth.INVALID_CREDENTIALS
|
|
669
|
+
"errors.{code}",
|
|
670
|
+
// errors.INVALID_CREDENTIALS
|
|
671
|
+
"login.{code}",
|
|
672
|
+
// login.INVALID_CREDENTIALS (legacy)
|
|
673
|
+
"error.{code}",
|
|
674
|
+
// error.INVALID_CREDENTIALS (singular)
|
|
675
|
+
"messages.{code}",
|
|
676
|
+
// messages.INVALID_CREDENTIALS
|
|
677
|
+
"{code}"
|
|
678
|
+
// INVALID_CREDENTIALS (direct)
|
|
679
|
+
];
|
|
680
|
+
var ERROR_CATEGORY_MAP = {
|
|
681
|
+
// Authentication errors
|
|
682
|
+
"INVALID_CREDENTIALS": "auth",
|
|
683
|
+
"UNAUTHORIZED": "auth",
|
|
684
|
+
"INVALID_API_KEY": "auth",
|
|
685
|
+
"USER_NOT_FOUND": "auth",
|
|
686
|
+
"USER_NOT_ACTIVE": "auth",
|
|
687
|
+
"NO_PERMISSION": "auth",
|
|
688
|
+
"SESSION_EXPIRED": "auth",
|
|
689
|
+
// Data errors
|
|
690
|
+
"ITEM_NOT_FOUND": "data",
|
|
691
|
+
"NOT_FOUND": "data",
|
|
692
|
+
"IN_USE": "data",
|
|
693
|
+
"DUPLICATE_ENTRY": "data",
|
|
694
|
+
// Validation errors
|
|
695
|
+
"FIELD_ERROR": "validation",
|
|
696
|
+
"BAD_REQUEST": "validation",
|
|
697
|
+
"INVALID_EMAIL": "validation",
|
|
698
|
+
"INVALID_CODE": "validation",
|
|
699
|
+
"REQUIRED_FIELD": "validation",
|
|
700
|
+
// System errors
|
|
701
|
+
"INTERNAL_SERVER_ERROR": "system",
|
|
702
|
+
"DATABASE_CONNECTION_ERROR": "system",
|
|
703
|
+
"INVALID_CONFIGURATION": "system",
|
|
704
|
+
"UNKNOWN_OPERATION": "system",
|
|
705
|
+
"TIMEOUT_ERROR": "system",
|
|
706
|
+
"NETWORK_ERROR": "system",
|
|
707
|
+
// Rate limiting
|
|
708
|
+
"TOO_MANY_REQUESTS": "rate_limit"
|
|
709
|
+
};
|
|
710
|
+
var DEFAULT_ERROR_MESSAGES = {
|
|
711
|
+
"INVALID_CREDENTIALS": "Invalid username or password",
|
|
712
|
+
"UNAUTHORIZED": "You are not authorized to perform this action",
|
|
713
|
+
"SESSION_EXPIRED": "Your session has expired. Please log in again.",
|
|
714
|
+
"USER_NOT_FOUND": "User not found",
|
|
715
|
+
"ITEM_NOT_FOUND": "Item not found",
|
|
716
|
+
"FIELD_ERROR": "Invalid field value",
|
|
717
|
+
"INTERNAL_SERVER_ERROR": "An internal error occurred",
|
|
718
|
+
"NETWORK_ERROR": "Network connection error",
|
|
719
|
+
"TIMEOUT_ERROR": "Request timeout",
|
|
720
|
+
"UNKNOWN_OPERATION": "Unknown operation",
|
|
721
|
+
"INVALID_EMAIL": "Invalid email format",
|
|
722
|
+
"INVALID_CODE": "Invalid code",
|
|
723
|
+
"TOO_MANY_REQUESTS": "Too many requests, please try again later"
|
|
724
|
+
};
|
|
725
|
+
function translateErrorCode(errorCode, config) {
|
|
726
|
+
const { translateFn, currentLanguage, enableDebug } = config;
|
|
727
|
+
if (enableDebug) {
|
|
728
|
+
console.log(`\u{1F50D} [ErrorTranslation] Translating error code: ${errorCode} (lang: ${currentLanguage || "unknown"})`);
|
|
729
|
+
}
|
|
730
|
+
const normalizedCode = errorCode.toUpperCase();
|
|
731
|
+
const category = ERROR_CATEGORY_MAP[normalizedCode];
|
|
732
|
+
const translationKeys = ERROR_TRANSLATION_HIERARCHY.map((pattern) => {
|
|
733
|
+
return pattern.replace("{category}", category || "general").replace("{code}", normalizedCode);
|
|
734
|
+
});
|
|
735
|
+
if (enableDebug) {
|
|
736
|
+
console.log(`\u{1F511} [ErrorTranslation] Searching keys:`, translationKeys);
|
|
737
|
+
}
|
|
738
|
+
for (const key of translationKeys) {
|
|
739
|
+
const translated = translateFn(key);
|
|
740
|
+
if (enableDebug) {
|
|
741
|
+
console.log(`\u{1F50D} [ErrorTranslation] Checking key: "${key}" -> result: "${translated}" (same as key: ${translated === key})`);
|
|
742
|
+
}
|
|
743
|
+
if (translated && translated !== key) {
|
|
744
|
+
if (enableDebug) {
|
|
745
|
+
console.log(`\u2705 [ErrorTranslation] Found translation at key: ${key} = "${translated}"`);
|
|
746
|
+
}
|
|
747
|
+
return translated;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
const defaultMessage = DEFAULT_ERROR_MESSAGES[normalizedCode];
|
|
751
|
+
if (defaultMessage) {
|
|
752
|
+
if (enableDebug) {
|
|
753
|
+
console.log(`\u{1F504} [ErrorTranslation] Using default message: "${defaultMessage}"`);
|
|
754
|
+
}
|
|
755
|
+
return defaultMessage;
|
|
756
|
+
}
|
|
757
|
+
const friendlyCode = normalizedCode.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (l) => l.toUpperCase());
|
|
758
|
+
if (enableDebug) {
|
|
759
|
+
console.log(`\u26A0\uFE0F [ErrorTranslation] No translation found, using friendly code: "${friendlyCode}"`);
|
|
760
|
+
}
|
|
761
|
+
return friendlyCode;
|
|
762
|
+
}
|
|
763
|
+
function translateErrorCodes(errorCodes, config) {
|
|
764
|
+
return errorCodes.map((code) => translateErrorCode(code, config));
|
|
765
|
+
}
|
|
766
|
+
function translateError(error, config) {
|
|
767
|
+
const { enableDebug } = config;
|
|
768
|
+
if (enableDebug) {
|
|
769
|
+
console.log(`\u{1F50D} [ErrorTranslation] Translating error:`, error);
|
|
770
|
+
}
|
|
771
|
+
const translatedCode = translateErrorCode(error.code, config);
|
|
772
|
+
if (translatedCode !== error.code.toUpperCase() && translatedCode !== error.code) {
|
|
773
|
+
if (enableDebug) {
|
|
774
|
+
console.log(`\u2705 [ErrorTranslation] Using hierarchical translation: "${translatedCode}"`);
|
|
775
|
+
}
|
|
776
|
+
if (error.field) {
|
|
777
|
+
return `${error.field}: ${translatedCode}`;
|
|
778
|
+
}
|
|
779
|
+
return translatedCode;
|
|
780
|
+
}
|
|
781
|
+
if (error.message && !error.message.includes("Error:") && error.message.length > 0 && error.message !== error.code) {
|
|
782
|
+
if (enableDebug) {
|
|
783
|
+
console.log(`\u{1F504} [ErrorTranslation] No hierarchical translation found, using API message: "${error.message}"`);
|
|
784
|
+
}
|
|
785
|
+
return error.message;
|
|
786
|
+
}
|
|
787
|
+
if (enableDebug) {
|
|
788
|
+
console.log(`\u26A0\uFE0F [ErrorTranslation] Using final fallback: "${translatedCode}"`);
|
|
789
|
+
}
|
|
790
|
+
if (error.field) {
|
|
791
|
+
return `${error.field}: ${translatedCode}`;
|
|
792
|
+
}
|
|
793
|
+
return translatedCode;
|
|
794
|
+
}
|
|
795
|
+
function createErrorTranslator(translateFn, options = {}) {
|
|
796
|
+
const config = {
|
|
797
|
+
translateFn,
|
|
798
|
+
currentLanguage: options.currentLanguage,
|
|
799
|
+
enableDebug: options.enableDebug || false
|
|
800
|
+
};
|
|
801
|
+
return {
|
|
802
|
+
translateErrorCode: (code) => translateErrorCode(code, config),
|
|
803
|
+
translateErrorCodes: (codes) => translateErrorCodes(codes, config),
|
|
804
|
+
translateError: (error) => translateError(error, config),
|
|
805
|
+
// Método de conveniencia para errores de API
|
|
806
|
+
translateApiError: (apiResponse) => {
|
|
807
|
+
if (apiResponse?.data?.response?.status) {
|
|
808
|
+
return translateErrorCode(apiResponse.data.response.status, config);
|
|
809
|
+
}
|
|
810
|
+
if (apiResponse?.status) {
|
|
811
|
+
return translateErrorCode(apiResponse.status, config);
|
|
812
|
+
}
|
|
813
|
+
if (apiResponse?.code) {
|
|
814
|
+
return translateErrorCode(apiResponse.code, config);
|
|
815
|
+
}
|
|
816
|
+
return "Unknown error";
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
|
|
665
821
|
// src/core/SessionManager.ts
|
|
666
822
|
var SessionManager = class _SessionManager {
|
|
667
823
|
constructor() {
|
|
@@ -818,6 +974,7 @@ var SessionManager = class _SessionManager {
|
|
|
818
974
|
if (!response.success) {
|
|
819
975
|
this.log("Token refresh failed:", response.errors);
|
|
820
976
|
TokenStorage.clearTokens();
|
|
977
|
+
this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
|
|
821
978
|
this.config.onSessionExpired?.();
|
|
822
979
|
return false;
|
|
823
980
|
}
|
|
@@ -833,6 +990,7 @@ var SessionManager = class _SessionManager {
|
|
|
833
990
|
} catch (error) {
|
|
834
991
|
this.log("Token refresh error:", error);
|
|
835
992
|
TokenStorage.clearTokens();
|
|
993
|
+
this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
|
|
836
994
|
this.config.onSessionExpired?.();
|
|
837
995
|
return false;
|
|
838
996
|
}
|
|
@@ -852,6 +1010,7 @@ var SessionManager = class _SessionManager {
|
|
|
852
1010
|
if (authError.isRefreshTokenInvalid || authError.isTokenRefreshFailed) {
|
|
853
1011
|
this.log("Refresh token invalid or refresh already failed, clearing session");
|
|
854
1012
|
TokenStorage.clearTokens();
|
|
1013
|
+
this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
|
|
855
1014
|
this.config.onSessionExpired?.();
|
|
856
1015
|
return response;
|
|
857
1016
|
}
|
|
@@ -865,6 +1024,7 @@ var SessionManager = class _SessionManager {
|
|
|
865
1024
|
} else {
|
|
866
1025
|
this.log("Auth error with no valid tokens or irrecoverable error, triggering session expired");
|
|
867
1026
|
TokenStorage.clearTokens();
|
|
1027
|
+
this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
|
|
868
1028
|
this.config.onSessionExpired?.();
|
|
869
1029
|
}
|
|
870
1030
|
}
|
|
@@ -947,6 +1107,18 @@ var SessionManager = class _SessionManager {
|
|
|
947
1107
|
import_crudify_browser2.default.logout();
|
|
948
1108
|
this.log("Session cleared completely");
|
|
949
1109
|
}
|
|
1110
|
+
/**
|
|
1111
|
+
* Obtener mensaje de sesión expirada traducido
|
|
1112
|
+
*/
|
|
1113
|
+
getSessionExpiredMessage() {
|
|
1114
|
+
if (this.config.translateFn) {
|
|
1115
|
+
return translateErrorCode("SESSION_EXPIRED", {
|
|
1116
|
+
translateFn: this.config.translateFn,
|
|
1117
|
+
enableDebug: this.config.enableLogging
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
return "Tu sesi\xF3n ha expirado. Por favor, inicia sesi\xF3n nuevamente.";
|
|
1121
|
+
}
|
|
950
1122
|
// Métodos privados
|
|
951
1123
|
log(message, ...args) {
|
|
952
1124
|
if (this.config.enableLogging) {
|
|
@@ -980,6 +1152,8 @@ function useSession(options = {}) {
|
|
|
980
1152
|
const config = {
|
|
981
1153
|
autoRestore: options.autoRestore ?? true,
|
|
982
1154
|
enableLogging: options.enableLogging ?? false,
|
|
1155
|
+
showNotification: options.showNotification,
|
|
1156
|
+
translateFn: options.translateFn,
|
|
983
1157
|
onSessionExpired: () => {
|
|
984
1158
|
setState((prev) => ({
|
|
985
1159
|
...prev,
|
|
@@ -1356,21 +1530,28 @@ var useGlobalNotification = () => {
|
|
|
1356
1530
|
// src/providers/SessionProvider.tsx
|
|
1357
1531
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1358
1532
|
var SessionContext = (0, import_react7.createContext)(void 0);
|
|
1359
|
-
function
|
|
1533
|
+
function InnerSessionProvider({
|
|
1360
1534
|
children,
|
|
1361
1535
|
options = {},
|
|
1362
1536
|
config: propConfig,
|
|
1363
1537
|
showNotifications = false,
|
|
1364
|
-
// ✅ Por defecto DESACTIVADO
|
|
1365
1538
|
notificationOptions = {}
|
|
1366
1539
|
}) {
|
|
1540
|
+
let showNotificationFn;
|
|
1541
|
+
try {
|
|
1542
|
+
const { showNotification } = useGlobalNotification();
|
|
1543
|
+
showNotificationFn = showNotification;
|
|
1544
|
+
} catch {
|
|
1545
|
+
}
|
|
1367
1546
|
const enhancedOptions = import_react7.default.useMemo(() => ({
|
|
1368
1547
|
...options,
|
|
1548
|
+
showNotification: showNotificationFn,
|
|
1549
|
+
// TODO: Agregar translateFn cuando esté disponible
|
|
1369
1550
|
onSessionExpired: () => {
|
|
1370
1551
|
console.log("\u{1F6A8} SessionProvider - Session expired callback triggered");
|
|
1371
1552
|
options.onSessionExpired?.();
|
|
1372
1553
|
}
|
|
1373
|
-
}), [options]);
|
|
1554
|
+
}), [options, showNotificationFn]);
|
|
1374
1555
|
const sessionHook = useSession(enhancedOptions);
|
|
1375
1556
|
const resolvedConfig = (0, import_react7.useMemo)(() => {
|
|
1376
1557
|
let publicApiKey;
|
|
@@ -1469,7 +1650,16 @@ function SessionProvider({
|
|
|
1469
1650
|
defaultAutoHideDuration: notificationOptions.defaultAutoHideDuration || 6e3,
|
|
1470
1651
|
position: notificationOptions.position || { vertical: "top", horizontal: "right" }
|
|
1471
1652
|
};
|
|
1472
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1653
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SessionContext.Provider, { value: contextValue, children });
|
|
1654
|
+
}
|
|
1655
|
+
function SessionProvider(props) {
|
|
1656
|
+
const notificationConfig = {
|
|
1657
|
+
enabled: props.showNotifications,
|
|
1658
|
+
maxNotifications: props.notificationOptions?.maxNotifications || 5,
|
|
1659
|
+
defaultAutoHideDuration: props.notificationOptions?.defaultAutoHideDuration || 6e3,
|
|
1660
|
+
position: props.notificationOptions?.position || { vertical: "top", horizontal: "right" }
|
|
1661
|
+
};
|
|
1662
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(GlobalNotificationProvider, { ...notificationConfig, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InnerSessionProvider, { ...props }) });
|
|
1473
1663
|
}
|
|
1474
1664
|
function useSessionContext() {
|
|
1475
1665
|
const context = (0, import_react7.useContext)(SessionContext);
|
|
@@ -1835,161 +2025,6 @@ function handleCrudifyError(error) {
|
|
|
1835
2025
|
];
|
|
1836
2026
|
}
|
|
1837
2027
|
|
|
1838
|
-
// src/utils/errorTranslation.ts
|
|
1839
|
-
var ERROR_TRANSLATION_HIERARCHY = [
|
|
1840
|
-
"errors.{category}.{code}",
|
|
1841
|
-
// errors.auth.INVALID_CREDENTIALS
|
|
1842
|
-
"errors.{code}",
|
|
1843
|
-
// errors.INVALID_CREDENTIALS
|
|
1844
|
-
"login.{code}",
|
|
1845
|
-
// login.INVALID_CREDENTIALS (legacy)
|
|
1846
|
-
"error.{code}",
|
|
1847
|
-
// error.INVALID_CREDENTIALS (singular)
|
|
1848
|
-
"messages.{code}",
|
|
1849
|
-
// messages.INVALID_CREDENTIALS
|
|
1850
|
-
"{code}"
|
|
1851
|
-
// INVALID_CREDENTIALS (direct)
|
|
1852
|
-
];
|
|
1853
|
-
var ERROR_CATEGORY_MAP = {
|
|
1854
|
-
// Authentication errors
|
|
1855
|
-
"INVALID_CREDENTIALS": "auth",
|
|
1856
|
-
"UNAUTHORIZED": "auth",
|
|
1857
|
-
"INVALID_API_KEY": "auth",
|
|
1858
|
-
"USER_NOT_FOUND": "auth",
|
|
1859
|
-
"USER_NOT_ACTIVE": "auth",
|
|
1860
|
-
"NO_PERMISSION": "auth",
|
|
1861
|
-
"SESSION_EXPIRED": "auth",
|
|
1862
|
-
// Data errors
|
|
1863
|
-
"ITEM_NOT_FOUND": "data",
|
|
1864
|
-
"NOT_FOUND": "data",
|
|
1865
|
-
"IN_USE": "data",
|
|
1866
|
-
"DUPLICATE_ENTRY": "data",
|
|
1867
|
-
// Validation errors
|
|
1868
|
-
"FIELD_ERROR": "validation",
|
|
1869
|
-
"BAD_REQUEST": "validation",
|
|
1870
|
-
"INVALID_EMAIL": "validation",
|
|
1871
|
-
"INVALID_CODE": "validation",
|
|
1872
|
-
"REQUIRED_FIELD": "validation",
|
|
1873
|
-
// System errors
|
|
1874
|
-
"INTERNAL_SERVER_ERROR": "system",
|
|
1875
|
-
"DATABASE_CONNECTION_ERROR": "system",
|
|
1876
|
-
"INVALID_CONFIGURATION": "system",
|
|
1877
|
-
"UNKNOWN_OPERATION": "system",
|
|
1878
|
-
"TIMEOUT_ERROR": "system",
|
|
1879
|
-
"NETWORK_ERROR": "system",
|
|
1880
|
-
// Rate limiting
|
|
1881
|
-
"TOO_MANY_REQUESTS": "rate_limit"
|
|
1882
|
-
};
|
|
1883
|
-
var DEFAULT_ERROR_MESSAGES = {
|
|
1884
|
-
"INVALID_CREDENTIALS": "Invalid username or password",
|
|
1885
|
-
"UNAUTHORIZED": "You are not authorized to perform this action",
|
|
1886
|
-
"USER_NOT_FOUND": "User not found",
|
|
1887
|
-
"ITEM_NOT_FOUND": "Item not found",
|
|
1888
|
-
"FIELD_ERROR": "Invalid field value",
|
|
1889
|
-
"INTERNAL_SERVER_ERROR": "An internal error occurred",
|
|
1890
|
-
"NETWORK_ERROR": "Network connection error",
|
|
1891
|
-
"TIMEOUT_ERROR": "Request timeout",
|
|
1892
|
-
"UNKNOWN_OPERATION": "Unknown operation",
|
|
1893
|
-
"INVALID_EMAIL": "Invalid email format",
|
|
1894
|
-
"INVALID_CODE": "Invalid code",
|
|
1895
|
-
"TOO_MANY_REQUESTS": "Too many requests, please try again later"
|
|
1896
|
-
};
|
|
1897
|
-
function translateErrorCode(errorCode, config) {
|
|
1898
|
-
const { translateFn, currentLanguage, enableDebug } = config;
|
|
1899
|
-
if (enableDebug) {
|
|
1900
|
-
console.log(`\u{1F50D} [ErrorTranslation] Translating error code: ${errorCode} (lang: ${currentLanguage || "unknown"})`);
|
|
1901
|
-
}
|
|
1902
|
-
const normalizedCode = errorCode.toUpperCase();
|
|
1903
|
-
const category = ERROR_CATEGORY_MAP[normalizedCode];
|
|
1904
|
-
const translationKeys = ERROR_TRANSLATION_HIERARCHY.map((pattern) => {
|
|
1905
|
-
return pattern.replace("{category}", category || "general").replace("{code}", normalizedCode);
|
|
1906
|
-
});
|
|
1907
|
-
if (enableDebug) {
|
|
1908
|
-
console.log(`\u{1F511} [ErrorTranslation] Searching keys:`, translationKeys);
|
|
1909
|
-
}
|
|
1910
|
-
for (const key of translationKeys) {
|
|
1911
|
-
const translated = translateFn(key);
|
|
1912
|
-
if (enableDebug) {
|
|
1913
|
-
console.log(`\u{1F50D} [ErrorTranslation] Checking key: "${key}" -> result: "${translated}" (same as key: ${translated === key})`);
|
|
1914
|
-
}
|
|
1915
|
-
if (translated && translated !== key) {
|
|
1916
|
-
if (enableDebug) {
|
|
1917
|
-
console.log(`\u2705 [ErrorTranslation] Found translation at key: ${key} = "${translated}"`);
|
|
1918
|
-
}
|
|
1919
|
-
return translated;
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
const defaultMessage = DEFAULT_ERROR_MESSAGES[normalizedCode];
|
|
1923
|
-
if (defaultMessage) {
|
|
1924
|
-
if (enableDebug) {
|
|
1925
|
-
console.log(`\u{1F504} [ErrorTranslation] Using default message: "${defaultMessage}"`);
|
|
1926
|
-
}
|
|
1927
|
-
return defaultMessage;
|
|
1928
|
-
}
|
|
1929
|
-
const friendlyCode = normalizedCode.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (l) => l.toUpperCase());
|
|
1930
|
-
if (enableDebug) {
|
|
1931
|
-
console.log(`\u26A0\uFE0F [ErrorTranslation] No translation found, using friendly code: "${friendlyCode}"`);
|
|
1932
|
-
}
|
|
1933
|
-
return friendlyCode;
|
|
1934
|
-
}
|
|
1935
|
-
function translateErrorCodes(errorCodes, config) {
|
|
1936
|
-
return errorCodes.map((code) => translateErrorCode(code, config));
|
|
1937
|
-
}
|
|
1938
|
-
function translateError(error, config) {
|
|
1939
|
-
const { enableDebug } = config;
|
|
1940
|
-
if (enableDebug) {
|
|
1941
|
-
console.log(`\u{1F50D} [ErrorTranslation] Translating error:`, error);
|
|
1942
|
-
}
|
|
1943
|
-
const translatedCode = translateErrorCode(error.code, config);
|
|
1944
|
-
if (translatedCode !== error.code.toUpperCase() && translatedCode !== error.code) {
|
|
1945
|
-
if (enableDebug) {
|
|
1946
|
-
console.log(`\u2705 [ErrorTranslation] Using hierarchical translation: "${translatedCode}"`);
|
|
1947
|
-
}
|
|
1948
|
-
if (error.field) {
|
|
1949
|
-
return `${error.field}: ${translatedCode}`;
|
|
1950
|
-
}
|
|
1951
|
-
return translatedCode;
|
|
1952
|
-
}
|
|
1953
|
-
if (error.message && !error.message.includes("Error:") && error.message.length > 0 && error.message !== error.code) {
|
|
1954
|
-
if (enableDebug) {
|
|
1955
|
-
console.log(`\u{1F504} [ErrorTranslation] No hierarchical translation found, using API message: "${error.message}"`);
|
|
1956
|
-
}
|
|
1957
|
-
return error.message;
|
|
1958
|
-
}
|
|
1959
|
-
if (enableDebug) {
|
|
1960
|
-
console.log(`\u26A0\uFE0F [ErrorTranslation] Using final fallback: "${translatedCode}"`);
|
|
1961
|
-
}
|
|
1962
|
-
if (error.field) {
|
|
1963
|
-
return `${error.field}: ${translatedCode}`;
|
|
1964
|
-
}
|
|
1965
|
-
return translatedCode;
|
|
1966
|
-
}
|
|
1967
|
-
function createErrorTranslator(translateFn, options = {}) {
|
|
1968
|
-
const config = {
|
|
1969
|
-
translateFn,
|
|
1970
|
-
currentLanguage: options.currentLanguage,
|
|
1971
|
-
enableDebug: options.enableDebug || false
|
|
1972
|
-
};
|
|
1973
|
-
return {
|
|
1974
|
-
translateErrorCode: (code) => translateErrorCode(code, config),
|
|
1975
|
-
translateErrorCodes: (codes) => translateErrorCodes(codes, config),
|
|
1976
|
-
translateError: (error) => translateError(error, config),
|
|
1977
|
-
// Método de conveniencia para errores de API
|
|
1978
|
-
translateApiError: (apiResponse) => {
|
|
1979
|
-
if (apiResponse?.data?.response?.status) {
|
|
1980
|
-
return translateErrorCode(apiResponse.data.response.status, config);
|
|
1981
|
-
}
|
|
1982
|
-
if (apiResponse?.status) {
|
|
1983
|
-
return translateErrorCode(apiResponse.status, config);
|
|
1984
|
-
}
|
|
1985
|
-
if (apiResponse?.code) {
|
|
1986
|
-
return translateErrorCode(apiResponse.code, config);
|
|
1987
|
-
}
|
|
1988
|
-
return "Unknown error";
|
|
1989
|
-
}
|
|
1990
|
-
};
|
|
1991
|
-
}
|
|
1992
|
-
|
|
1993
2028
|
// src/components/CrudifyLogin/Forms/LoginForm.tsx
|
|
1994
2029
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1995
2030
|
var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError, redirectUrl = "/" }) => {
|
package/dist/index.mjs
CHANGED
|
@@ -589,6 +589,162 @@ _TokenStorage.ENCRYPTION_KEY = "crudify_secure_key_v1";
|
|
|
589
589
|
_TokenStorage.storageType = "localStorage";
|
|
590
590
|
var TokenStorage = _TokenStorage;
|
|
591
591
|
|
|
592
|
+
// src/utils/errorTranslation.ts
|
|
593
|
+
var ERROR_TRANSLATION_HIERARCHY = [
|
|
594
|
+
"errors.{category}.{code}",
|
|
595
|
+
// errors.auth.INVALID_CREDENTIALS
|
|
596
|
+
"errors.{code}",
|
|
597
|
+
// errors.INVALID_CREDENTIALS
|
|
598
|
+
"login.{code}",
|
|
599
|
+
// login.INVALID_CREDENTIALS (legacy)
|
|
600
|
+
"error.{code}",
|
|
601
|
+
// error.INVALID_CREDENTIALS (singular)
|
|
602
|
+
"messages.{code}",
|
|
603
|
+
// messages.INVALID_CREDENTIALS
|
|
604
|
+
"{code}"
|
|
605
|
+
// INVALID_CREDENTIALS (direct)
|
|
606
|
+
];
|
|
607
|
+
var ERROR_CATEGORY_MAP = {
|
|
608
|
+
// Authentication errors
|
|
609
|
+
"INVALID_CREDENTIALS": "auth",
|
|
610
|
+
"UNAUTHORIZED": "auth",
|
|
611
|
+
"INVALID_API_KEY": "auth",
|
|
612
|
+
"USER_NOT_FOUND": "auth",
|
|
613
|
+
"USER_NOT_ACTIVE": "auth",
|
|
614
|
+
"NO_PERMISSION": "auth",
|
|
615
|
+
"SESSION_EXPIRED": "auth",
|
|
616
|
+
// Data errors
|
|
617
|
+
"ITEM_NOT_FOUND": "data",
|
|
618
|
+
"NOT_FOUND": "data",
|
|
619
|
+
"IN_USE": "data",
|
|
620
|
+
"DUPLICATE_ENTRY": "data",
|
|
621
|
+
// Validation errors
|
|
622
|
+
"FIELD_ERROR": "validation",
|
|
623
|
+
"BAD_REQUEST": "validation",
|
|
624
|
+
"INVALID_EMAIL": "validation",
|
|
625
|
+
"INVALID_CODE": "validation",
|
|
626
|
+
"REQUIRED_FIELD": "validation",
|
|
627
|
+
// System errors
|
|
628
|
+
"INTERNAL_SERVER_ERROR": "system",
|
|
629
|
+
"DATABASE_CONNECTION_ERROR": "system",
|
|
630
|
+
"INVALID_CONFIGURATION": "system",
|
|
631
|
+
"UNKNOWN_OPERATION": "system",
|
|
632
|
+
"TIMEOUT_ERROR": "system",
|
|
633
|
+
"NETWORK_ERROR": "system",
|
|
634
|
+
// Rate limiting
|
|
635
|
+
"TOO_MANY_REQUESTS": "rate_limit"
|
|
636
|
+
};
|
|
637
|
+
var DEFAULT_ERROR_MESSAGES = {
|
|
638
|
+
"INVALID_CREDENTIALS": "Invalid username or password",
|
|
639
|
+
"UNAUTHORIZED": "You are not authorized to perform this action",
|
|
640
|
+
"SESSION_EXPIRED": "Your session has expired. Please log in again.",
|
|
641
|
+
"USER_NOT_FOUND": "User not found",
|
|
642
|
+
"ITEM_NOT_FOUND": "Item not found",
|
|
643
|
+
"FIELD_ERROR": "Invalid field value",
|
|
644
|
+
"INTERNAL_SERVER_ERROR": "An internal error occurred",
|
|
645
|
+
"NETWORK_ERROR": "Network connection error",
|
|
646
|
+
"TIMEOUT_ERROR": "Request timeout",
|
|
647
|
+
"UNKNOWN_OPERATION": "Unknown operation",
|
|
648
|
+
"INVALID_EMAIL": "Invalid email format",
|
|
649
|
+
"INVALID_CODE": "Invalid code",
|
|
650
|
+
"TOO_MANY_REQUESTS": "Too many requests, please try again later"
|
|
651
|
+
};
|
|
652
|
+
function translateErrorCode(errorCode, config) {
|
|
653
|
+
const { translateFn, currentLanguage, enableDebug } = config;
|
|
654
|
+
if (enableDebug) {
|
|
655
|
+
console.log(`\u{1F50D} [ErrorTranslation] Translating error code: ${errorCode} (lang: ${currentLanguage || "unknown"})`);
|
|
656
|
+
}
|
|
657
|
+
const normalizedCode = errorCode.toUpperCase();
|
|
658
|
+
const category = ERROR_CATEGORY_MAP[normalizedCode];
|
|
659
|
+
const translationKeys = ERROR_TRANSLATION_HIERARCHY.map((pattern) => {
|
|
660
|
+
return pattern.replace("{category}", category || "general").replace("{code}", normalizedCode);
|
|
661
|
+
});
|
|
662
|
+
if (enableDebug) {
|
|
663
|
+
console.log(`\u{1F511} [ErrorTranslation] Searching keys:`, translationKeys);
|
|
664
|
+
}
|
|
665
|
+
for (const key of translationKeys) {
|
|
666
|
+
const translated = translateFn(key);
|
|
667
|
+
if (enableDebug) {
|
|
668
|
+
console.log(`\u{1F50D} [ErrorTranslation] Checking key: "${key}" -> result: "${translated}" (same as key: ${translated === key})`);
|
|
669
|
+
}
|
|
670
|
+
if (translated && translated !== key) {
|
|
671
|
+
if (enableDebug) {
|
|
672
|
+
console.log(`\u2705 [ErrorTranslation] Found translation at key: ${key} = "${translated}"`);
|
|
673
|
+
}
|
|
674
|
+
return translated;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
const defaultMessage = DEFAULT_ERROR_MESSAGES[normalizedCode];
|
|
678
|
+
if (defaultMessage) {
|
|
679
|
+
if (enableDebug) {
|
|
680
|
+
console.log(`\u{1F504} [ErrorTranslation] Using default message: "${defaultMessage}"`);
|
|
681
|
+
}
|
|
682
|
+
return defaultMessage;
|
|
683
|
+
}
|
|
684
|
+
const friendlyCode = normalizedCode.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (l) => l.toUpperCase());
|
|
685
|
+
if (enableDebug) {
|
|
686
|
+
console.log(`\u26A0\uFE0F [ErrorTranslation] No translation found, using friendly code: "${friendlyCode}"`);
|
|
687
|
+
}
|
|
688
|
+
return friendlyCode;
|
|
689
|
+
}
|
|
690
|
+
function translateErrorCodes(errorCodes, config) {
|
|
691
|
+
return errorCodes.map((code) => translateErrorCode(code, config));
|
|
692
|
+
}
|
|
693
|
+
function translateError(error, config) {
|
|
694
|
+
const { enableDebug } = config;
|
|
695
|
+
if (enableDebug) {
|
|
696
|
+
console.log(`\u{1F50D} [ErrorTranslation] Translating error:`, error);
|
|
697
|
+
}
|
|
698
|
+
const translatedCode = translateErrorCode(error.code, config);
|
|
699
|
+
if (translatedCode !== error.code.toUpperCase() && translatedCode !== error.code) {
|
|
700
|
+
if (enableDebug) {
|
|
701
|
+
console.log(`\u2705 [ErrorTranslation] Using hierarchical translation: "${translatedCode}"`);
|
|
702
|
+
}
|
|
703
|
+
if (error.field) {
|
|
704
|
+
return `${error.field}: ${translatedCode}`;
|
|
705
|
+
}
|
|
706
|
+
return translatedCode;
|
|
707
|
+
}
|
|
708
|
+
if (error.message && !error.message.includes("Error:") && error.message.length > 0 && error.message !== error.code) {
|
|
709
|
+
if (enableDebug) {
|
|
710
|
+
console.log(`\u{1F504} [ErrorTranslation] No hierarchical translation found, using API message: "${error.message}"`);
|
|
711
|
+
}
|
|
712
|
+
return error.message;
|
|
713
|
+
}
|
|
714
|
+
if (enableDebug) {
|
|
715
|
+
console.log(`\u26A0\uFE0F [ErrorTranslation] Using final fallback: "${translatedCode}"`);
|
|
716
|
+
}
|
|
717
|
+
if (error.field) {
|
|
718
|
+
return `${error.field}: ${translatedCode}`;
|
|
719
|
+
}
|
|
720
|
+
return translatedCode;
|
|
721
|
+
}
|
|
722
|
+
function createErrorTranslator(translateFn, options = {}) {
|
|
723
|
+
const config = {
|
|
724
|
+
translateFn,
|
|
725
|
+
currentLanguage: options.currentLanguage,
|
|
726
|
+
enableDebug: options.enableDebug || false
|
|
727
|
+
};
|
|
728
|
+
return {
|
|
729
|
+
translateErrorCode: (code) => translateErrorCode(code, config),
|
|
730
|
+
translateErrorCodes: (codes) => translateErrorCodes(codes, config),
|
|
731
|
+
translateError: (error) => translateError(error, config),
|
|
732
|
+
// Método de conveniencia para errores de API
|
|
733
|
+
translateApiError: (apiResponse) => {
|
|
734
|
+
if (apiResponse?.data?.response?.status) {
|
|
735
|
+
return translateErrorCode(apiResponse.data.response.status, config);
|
|
736
|
+
}
|
|
737
|
+
if (apiResponse?.status) {
|
|
738
|
+
return translateErrorCode(apiResponse.status, config);
|
|
739
|
+
}
|
|
740
|
+
if (apiResponse?.code) {
|
|
741
|
+
return translateErrorCode(apiResponse.code, config);
|
|
742
|
+
}
|
|
743
|
+
return "Unknown error";
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
|
|
592
748
|
// src/core/SessionManager.ts
|
|
593
749
|
var SessionManager = class _SessionManager {
|
|
594
750
|
constructor() {
|
|
@@ -745,6 +901,7 @@ var SessionManager = class _SessionManager {
|
|
|
745
901
|
if (!response.success) {
|
|
746
902
|
this.log("Token refresh failed:", response.errors);
|
|
747
903
|
TokenStorage.clearTokens();
|
|
904
|
+
this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
|
|
748
905
|
this.config.onSessionExpired?.();
|
|
749
906
|
return false;
|
|
750
907
|
}
|
|
@@ -760,6 +917,7 @@ var SessionManager = class _SessionManager {
|
|
|
760
917
|
} catch (error) {
|
|
761
918
|
this.log("Token refresh error:", error);
|
|
762
919
|
TokenStorage.clearTokens();
|
|
920
|
+
this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
|
|
763
921
|
this.config.onSessionExpired?.();
|
|
764
922
|
return false;
|
|
765
923
|
}
|
|
@@ -779,6 +937,7 @@ var SessionManager = class _SessionManager {
|
|
|
779
937
|
if (authError.isRefreshTokenInvalid || authError.isTokenRefreshFailed) {
|
|
780
938
|
this.log("Refresh token invalid or refresh already failed, clearing session");
|
|
781
939
|
TokenStorage.clearTokens();
|
|
940
|
+
this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
|
|
782
941
|
this.config.onSessionExpired?.();
|
|
783
942
|
return response;
|
|
784
943
|
}
|
|
@@ -792,6 +951,7 @@ var SessionManager = class _SessionManager {
|
|
|
792
951
|
} else {
|
|
793
952
|
this.log("Auth error with no valid tokens or irrecoverable error, triggering session expired");
|
|
794
953
|
TokenStorage.clearTokens();
|
|
954
|
+
this.config.showNotification?.(this.getSessionExpiredMessage(), "warning");
|
|
795
955
|
this.config.onSessionExpired?.();
|
|
796
956
|
}
|
|
797
957
|
}
|
|
@@ -874,6 +1034,18 @@ var SessionManager = class _SessionManager {
|
|
|
874
1034
|
crudify2.logout();
|
|
875
1035
|
this.log("Session cleared completely");
|
|
876
1036
|
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Obtener mensaje de sesión expirada traducido
|
|
1039
|
+
*/
|
|
1040
|
+
getSessionExpiredMessage() {
|
|
1041
|
+
if (this.config.translateFn) {
|
|
1042
|
+
return translateErrorCode("SESSION_EXPIRED", {
|
|
1043
|
+
translateFn: this.config.translateFn,
|
|
1044
|
+
enableDebug: this.config.enableLogging
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
return "Tu sesi\xF3n ha expirado. Por favor, inicia sesi\xF3n nuevamente.";
|
|
1048
|
+
}
|
|
877
1049
|
// Métodos privados
|
|
878
1050
|
log(message, ...args) {
|
|
879
1051
|
if (this.config.enableLogging) {
|
|
@@ -907,6 +1079,8 @@ function useSession(options = {}) {
|
|
|
907
1079
|
const config = {
|
|
908
1080
|
autoRestore: options.autoRestore ?? true,
|
|
909
1081
|
enableLogging: options.enableLogging ?? false,
|
|
1082
|
+
showNotification: options.showNotification,
|
|
1083
|
+
translateFn: options.translateFn,
|
|
910
1084
|
onSessionExpired: () => {
|
|
911
1085
|
setState((prev) => ({
|
|
912
1086
|
...prev,
|
|
@@ -1283,21 +1457,28 @@ var useGlobalNotification = () => {
|
|
|
1283
1457
|
// src/providers/SessionProvider.tsx
|
|
1284
1458
|
import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1285
1459
|
var SessionContext = createContext5(void 0);
|
|
1286
|
-
function
|
|
1460
|
+
function InnerSessionProvider({
|
|
1287
1461
|
children,
|
|
1288
1462
|
options = {},
|
|
1289
1463
|
config: propConfig,
|
|
1290
1464
|
showNotifications = false,
|
|
1291
|
-
// ✅ Por defecto DESACTIVADO
|
|
1292
1465
|
notificationOptions = {}
|
|
1293
1466
|
}) {
|
|
1467
|
+
let showNotificationFn;
|
|
1468
|
+
try {
|
|
1469
|
+
const { showNotification } = useGlobalNotification();
|
|
1470
|
+
showNotificationFn = showNotification;
|
|
1471
|
+
} catch {
|
|
1472
|
+
}
|
|
1294
1473
|
const enhancedOptions = React5.useMemo(() => ({
|
|
1295
1474
|
...options,
|
|
1475
|
+
showNotification: showNotificationFn,
|
|
1476
|
+
// TODO: Agregar translateFn cuando esté disponible
|
|
1296
1477
|
onSessionExpired: () => {
|
|
1297
1478
|
console.log("\u{1F6A8} SessionProvider - Session expired callback triggered");
|
|
1298
1479
|
options.onSessionExpired?.();
|
|
1299
1480
|
}
|
|
1300
|
-
}), [options]);
|
|
1481
|
+
}), [options, showNotificationFn]);
|
|
1301
1482
|
const sessionHook = useSession(enhancedOptions);
|
|
1302
1483
|
const resolvedConfig = useMemo2(() => {
|
|
1303
1484
|
let publicApiKey;
|
|
@@ -1396,7 +1577,16 @@ function SessionProvider({
|
|
|
1396
1577
|
defaultAutoHideDuration: notificationOptions.defaultAutoHideDuration || 6e3,
|
|
1397
1578
|
position: notificationOptions.position || { vertical: "top", horizontal: "right" }
|
|
1398
1579
|
};
|
|
1399
|
-
return /* @__PURE__ */ jsx5(
|
|
1580
|
+
return /* @__PURE__ */ jsx5(SessionContext.Provider, { value: contextValue, children });
|
|
1581
|
+
}
|
|
1582
|
+
function SessionProvider(props) {
|
|
1583
|
+
const notificationConfig = {
|
|
1584
|
+
enabled: props.showNotifications,
|
|
1585
|
+
maxNotifications: props.notificationOptions?.maxNotifications || 5,
|
|
1586
|
+
defaultAutoHideDuration: props.notificationOptions?.defaultAutoHideDuration || 6e3,
|
|
1587
|
+
position: props.notificationOptions?.position || { vertical: "top", horizontal: "right" }
|
|
1588
|
+
};
|
|
1589
|
+
return /* @__PURE__ */ jsx5(GlobalNotificationProvider, { ...notificationConfig, children: /* @__PURE__ */ jsx5(InnerSessionProvider, { ...props }) });
|
|
1400
1590
|
}
|
|
1401
1591
|
function useSessionContext() {
|
|
1402
1592
|
const context = useContext5(SessionContext);
|
|
@@ -1762,161 +1952,6 @@ function handleCrudifyError(error) {
|
|
|
1762
1952
|
];
|
|
1763
1953
|
}
|
|
1764
1954
|
|
|
1765
|
-
// src/utils/errorTranslation.ts
|
|
1766
|
-
var ERROR_TRANSLATION_HIERARCHY = [
|
|
1767
|
-
"errors.{category}.{code}",
|
|
1768
|
-
// errors.auth.INVALID_CREDENTIALS
|
|
1769
|
-
"errors.{code}",
|
|
1770
|
-
// errors.INVALID_CREDENTIALS
|
|
1771
|
-
"login.{code}",
|
|
1772
|
-
// login.INVALID_CREDENTIALS (legacy)
|
|
1773
|
-
"error.{code}",
|
|
1774
|
-
// error.INVALID_CREDENTIALS (singular)
|
|
1775
|
-
"messages.{code}",
|
|
1776
|
-
// messages.INVALID_CREDENTIALS
|
|
1777
|
-
"{code}"
|
|
1778
|
-
// INVALID_CREDENTIALS (direct)
|
|
1779
|
-
];
|
|
1780
|
-
var ERROR_CATEGORY_MAP = {
|
|
1781
|
-
// Authentication errors
|
|
1782
|
-
"INVALID_CREDENTIALS": "auth",
|
|
1783
|
-
"UNAUTHORIZED": "auth",
|
|
1784
|
-
"INVALID_API_KEY": "auth",
|
|
1785
|
-
"USER_NOT_FOUND": "auth",
|
|
1786
|
-
"USER_NOT_ACTIVE": "auth",
|
|
1787
|
-
"NO_PERMISSION": "auth",
|
|
1788
|
-
"SESSION_EXPIRED": "auth",
|
|
1789
|
-
// Data errors
|
|
1790
|
-
"ITEM_NOT_FOUND": "data",
|
|
1791
|
-
"NOT_FOUND": "data",
|
|
1792
|
-
"IN_USE": "data",
|
|
1793
|
-
"DUPLICATE_ENTRY": "data",
|
|
1794
|
-
// Validation errors
|
|
1795
|
-
"FIELD_ERROR": "validation",
|
|
1796
|
-
"BAD_REQUEST": "validation",
|
|
1797
|
-
"INVALID_EMAIL": "validation",
|
|
1798
|
-
"INVALID_CODE": "validation",
|
|
1799
|
-
"REQUIRED_FIELD": "validation",
|
|
1800
|
-
// System errors
|
|
1801
|
-
"INTERNAL_SERVER_ERROR": "system",
|
|
1802
|
-
"DATABASE_CONNECTION_ERROR": "system",
|
|
1803
|
-
"INVALID_CONFIGURATION": "system",
|
|
1804
|
-
"UNKNOWN_OPERATION": "system",
|
|
1805
|
-
"TIMEOUT_ERROR": "system",
|
|
1806
|
-
"NETWORK_ERROR": "system",
|
|
1807
|
-
// Rate limiting
|
|
1808
|
-
"TOO_MANY_REQUESTS": "rate_limit"
|
|
1809
|
-
};
|
|
1810
|
-
var DEFAULT_ERROR_MESSAGES = {
|
|
1811
|
-
"INVALID_CREDENTIALS": "Invalid username or password",
|
|
1812
|
-
"UNAUTHORIZED": "You are not authorized to perform this action",
|
|
1813
|
-
"USER_NOT_FOUND": "User not found",
|
|
1814
|
-
"ITEM_NOT_FOUND": "Item not found",
|
|
1815
|
-
"FIELD_ERROR": "Invalid field value",
|
|
1816
|
-
"INTERNAL_SERVER_ERROR": "An internal error occurred",
|
|
1817
|
-
"NETWORK_ERROR": "Network connection error",
|
|
1818
|
-
"TIMEOUT_ERROR": "Request timeout",
|
|
1819
|
-
"UNKNOWN_OPERATION": "Unknown operation",
|
|
1820
|
-
"INVALID_EMAIL": "Invalid email format",
|
|
1821
|
-
"INVALID_CODE": "Invalid code",
|
|
1822
|
-
"TOO_MANY_REQUESTS": "Too many requests, please try again later"
|
|
1823
|
-
};
|
|
1824
|
-
function translateErrorCode(errorCode, config) {
|
|
1825
|
-
const { translateFn, currentLanguage, enableDebug } = config;
|
|
1826
|
-
if (enableDebug) {
|
|
1827
|
-
console.log(`\u{1F50D} [ErrorTranslation] Translating error code: ${errorCode} (lang: ${currentLanguage || "unknown"})`);
|
|
1828
|
-
}
|
|
1829
|
-
const normalizedCode = errorCode.toUpperCase();
|
|
1830
|
-
const category = ERROR_CATEGORY_MAP[normalizedCode];
|
|
1831
|
-
const translationKeys = ERROR_TRANSLATION_HIERARCHY.map((pattern) => {
|
|
1832
|
-
return pattern.replace("{category}", category || "general").replace("{code}", normalizedCode);
|
|
1833
|
-
});
|
|
1834
|
-
if (enableDebug) {
|
|
1835
|
-
console.log(`\u{1F511} [ErrorTranslation] Searching keys:`, translationKeys);
|
|
1836
|
-
}
|
|
1837
|
-
for (const key of translationKeys) {
|
|
1838
|
-
const translated = translateFn(key);
|
|
1839
|
-
if (enableDebug) {
|
|
1840
|
-
console.log(`\u{1F50D} [ErrorTranslation] Checking key: "${key}" -> result: "${translated}" (same as key: ${translated === key})`);
|
|
1841
|
-
}
|
|
1842
|
-
if (translated && translated !== key) {
|
|
1843
|
-
if (enableDebug) {
|
|
1844
|
-
console.log(`\u2705 [ErrorTranslation] Found translation at key: ${key} = "${translated}"`);
|
|
1845
|
-
}
|
|
1846
|
-
return translated;
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
|
-
const defaultMessage = DEFAULT_ERROR_MESSAGES[normalizedCode];
|
|
1850
|
-
if (defaultMessage) {
|
|
1851
|
-
if (enableDebug) {
|
|
1852
|
-
console.log(`\u{1F504} [ErrorTranslation] Using default message: "${defaultMessage}"`);
|
|
1853
|
-
}
|
|
1854
|
-
return defaultMessage;
|
|
1855
|
-
}
|
|
1856
|
-
const friendlyCode = normalizedCode.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (l) => l.toUpperCase());
|
|
1857
|
-
if (enableDebug) {
|
|
1858
|
-
console.log(`\u26A0\uFE0F [ErrorTranslation] No translation found, using friendly code: "${friendlyCode}"`);
|
|
1859
|
-
}
|
|
1860
|
-
return friendlyCode;
|
|
1861
|
-
}
|
|
1862
|
-
function translateErrorCodes(errorCodes, config) {
|
|
1863
|
-
return errorCodes.map((code) => translateErrorCode(code, config));
|
|
1864
|
-
}
|
|
1865
|
-
function translateError(error, config) {
|
|
1866
|
-
const { enableDebug } = config;
|
|
1867
|
-
if (enableDebug) {
|
|
1868
|
-
console.log(`\u{1F50D} [ErrorTranslation] Translating error:`, error);
|
|
1869
|
-
}
|
|
1870
|
-
const translatedCode = translateErrorCode(error.code, config);
|
|
1871
|
-
if (translatedCode !== error.code.toUpperCase() && translatedCode !== error.code) {
|
|
1872
|
-
if (enableDebug) {
|
|
1873
|
-
console.log(`\u2705 [ErrorTranslation] Using hierarchical translation: "${translatedCode}"`);
|
|
1874
|
-
}
|
|
1875
|
-
if (error.field) {
|
|
1876
|
-
return `${error.field}: ${translatedCode}`;
|
|
1877
|
-
}
|
|
1878
|
-
return translatedCode;
|
|
1879
|
-
}
|
|
1880
|
-
if (error.message && !error.message.includes("Error:") && error.message.length > 0 && error.message !== error.code) {
|
|
1881
|
-
if (enableDebug) {
|
|
1882
|
-
console.log(`\u{1F504} [ErrorTranslation] No hierarchical translation found, using API message: "${error.message}"`);
|
|
1883
|
-
}
|
|
1884
|
-
return error.message;
|
|
1885
|
-
}
|
|
1886
|
-
if (enableDebug) {
|
|
1887
|
-
console.log(`\u26A0\uFE0F [ErrorTranslation] Using final fallback: "${translatedCode}"`);
|
|
1888
|
-
}
|
|
1889
|
-
if (error.field) {
|
|
1890
|
-
return `${error.field}: ${translatedCode}`;
|
|
1891
|
-
}
|
|
1892
|
-
return translatedCode;
|
|
1893
|
-
}
|
|
1894
|
-
function createErrorTranslator(translateFn, options = {}) {
|
|
1895
|
-
const config = {
|
|
1896
|
-
translateFn,
|
|
1897
|
-
currentLanguage: options.currentLanguage,
|
|
1898
|
-
enableDebug: options.enableDebug || false
|
|
1899
|
-
};
|
|
1900
|
-
return {
|
|
1901
|
-
translateErrorCode: (code) => translateErrorCode(code, config),
|
|
1902
|
-
translateErrorCodes: (codes) => translateErrorCodes(codes, config),
|
|
1903
|
-
translateError: (error) => translateError(error, config),
|
|
1904
|
-
// Método de conveniencia para errores de API
|
|
1905
|
-
translateApiError: (apiResponse) => {
|
|
1906
|
-
if (apiResponse?.data?.response?.status) {
|
|
1907
|
-
return translateErrorCode(apiResponse.data.response.status, config);
|
|
1908
|
-
}
|
|
1909
|
-
if (apiResponse?.status) {
|
|
1910
|
-
return translateErrorCode(apiResponse.status, config);
|
|
1911
|
-
}
|
|
1912
|
-
if (apiResponse?.code) {
|
|
1913
|
-
return translateErrorCode(apiResponse.code, config);
|
|
1914
|
-
}
|
|
1915
|
-
return "Unknown error";
|
|
1916
|
-
}
|
|
1917
|
-
};
|
|
1918
|
-
}
|
|
1919
|
-
|
|
1920
1955
|
// src/components/CrudifyLogin/Forms/LoginForm.tsx
|
|
1921
1956
|
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1922
1957
|
var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError, redirectUrl = "/" }) => {
|