@nocios/crudify-ui 1.2.36 → 1.3.1
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/MIGRATION-GUIDE.md +312 -0
- package/dist/index.d.mts +414 -1
- package/dist/index.d.ts +414 -1
- package/dist/index.js +1229 -18
- package/dist/index.mjs +1214 -16
- package/example-app.tsx +197 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1289,9 +1289,16 @@ __export(index_exports, {
|
|
|
1289
1289
|
CrudifyLogin: () => CrudifyLogin_default,
|
|
1290
1290
|
ERROR_CODES: () => ERROR_CODES,
|
|
1291
1291
|
ERROR_SEVERITY_MAP: () => ERROR_SEVERITY_MAP,
|
|
1292
|
+
LoginComponent: () => LoginComponent,
|
|
1293
|
+
ProtectedRoute: () => ProtectedRoute,
|
|
1294
|
+
SessionDebugInfo: () => SessionDebugInfo,
|
|
1295
|
+
SessionManager: () => SessionManager,
|
|
1296
|
+
SessionProvider: () => SessionProvider,
|
|
1297
|
+
SessionStatus: () => SessionStatus,
|
|
1298
|
+
TokenStorage: () => TokenStorage,
|
|
1292
1299
|
UserProfileDisplay: () => UserProfileDisplay_default,
|
|
1293
1300
|
configurationManager: () => configurationManager,
|
|
1294
|
-
crudify: () =>
|
|
1301
|
+
crudify: () => import_crudify_browser11.default,
|
|
1295
1302
|
crudifyInitializer: () => crudifyInitializer,
|
|
1296
1303
|
decodeJwtSafely: () => decodeJwtSafely,
|
|
1297
1304
|
getCookie: () => getCookie,
|
|
@@ -1307,6 +1314,7 @@ __export(index_exports, {
|
|
|
1307
1314
|
secureLocalStorage: () => secureLocalStorage,
|
|
1308
1315
|
secureSessionStorage: () => secureSessionStorage,
|
|
1309
1316
|
tokenManager: () => tokenManager,
|
|
1317
|
+
useAuth: () => useAuth,
|
|
1310
1318
|
useCrudifyAuth: () => useCrudifyAuth,
|
|
1311
1319
|
useCrudifyConfig: () => useCrudifyConfig,
|
|
1312
1320
|
useCrudifyData: () => useCrudifyData,
|
|
@@ -1314,10 +1322,14 @@ __export(index_exports, {
|
|
|
1314
1322
|
useCrudifyInstance: () => useCrudifyInstance,
|
|
1315
1323
|
useCrudifyLogin: () => useCrudifyLogin,
|
|
1316
1324
|
useCrudifyUser: () => useCrudifyUser,
|
|
1325
|
+
useData: () => useData,
|
|
1326
|
+
useSession: () => useSession,
|
|
1327
|
+
useSessionContext: () => useSessionContext,
|
|
1328
|
+
useUserData: () => useUserData,
|
|
1317
1329
|
useUserProfile: () => useUserProfile
|
|
1318
1330
|
});
|
|
1319
1331
|
module.exports = __toCommonJS(index_exports);
|
|
1320
|
-
var
|
|
1332
|
+
var import_crudify_browser11 = __toESM(require("@nocios/crudify-browser"));
|
|
1321
1333
|
__reExport(index_exports, require("@nocios/crudify-browser"), module.exports);
|
|
1322
1334
|
|
|
1323
1335
|
// src/components/CrudifyLogin/index.tsx
|
|
@@ -2009,7 +2021,7 @@ var useCrudifyAuth = () => {
|
|
|
2009
2021
|
// src/components/CrudifyLogin/Forms/LoginForm.tsx
|
|
2010
2022
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2011
2023
|
var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError, redirectUrl = "/" }) => {
|
|
2012
|
-
const { crudify:
|
|
2024
|
+
const { crudify: crudify11 } = useCrudify();
|
|
2013
2025
|
const { state, updateFormData, setFieldError, clearErrors, setLoading } = useLoginState();
|
|
2014
2026
|
const { setToken } = useCrudifyAuth();
|
|
2015
2027
|
const { t } = useTranslation();
|
|
@@ -2061,10 +2073,10 @@ var LoginForm = ({ onScreenChange, onExternalNavigate, onLoginSuccess, onError,
|
|
|
2061
2073
|
clearErrors();
|
|
2062
2074
|
setLoading(true);
|
|
2063
2075
|
try {
|
|
2064
|
-
if (!
|
|
2076
|
+
if (!crudify11) {
|
|
2065
2077
|
throw new Error("Crudify not initialized");
|
|
2066
2078
|
}
|
|
2067
|
-
const response = await
|
|
2079
|
+
const response = await crudify11.login(state.formData.username, state.formData.password);
|
|
2068
2080
|
setLoading(false);
|
|
2069
2081
|
if (response.success) {
|
|
2070
2082
|
console.log("\u{1F510} LoginForm - Login successful, setting tokens");
|
|
@@ -2227,7 +2239,7 @@ var import_react7 = require("react");
|
|
|
2227
2239
|
var import_material2 = require("@mui/material");
|
|
2228
2240
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2229
2241
|
var ForgotPasswordForm = ({ onScreenChange, onError }) => {
|
|
2230
|
-
const { crudify:
|
|
2242
|
+
const { crudify: crudify11 } = useCrudify();
|
|
2231
2243
|
const [email, setEmail] = (0, import_react7.useState)("");
|
|
2232
2244
|
const [loading, setLoading] = (0, import_react7.useState)(false);
|
|
2233
2245
|
const [errors, setErrors] = (0, import_react7.useState)([]);
|
|
@@ -2256,7 +2268,7 @@ var ForgotPasswordForm = ({ onScreenChange, onError }) => {
|
|
|
2256
2268
|
return emailRegex.test(email2);
|
|
2257
2269
|
};
|
|
2258
2270
|
const handleSubmit = async () => {
|
|
2259
|
-
if (loading || !
|
|
2271
|
+
if (loading || !crudify11) return;
|
|
2260
2272
|
setErrors([]);
|
|
2261
2273
|
setHelperTextEmail(null);
|
|
2262
2274
|
if (!email) {
|
|
@@ -2270,7 +2282,7 @@ var ForgotPasswordForm = ({ onScreenChange, onError }) => {
|
|
|
2270
2282
|
setLoading(true);
|
|
2271
2283
|
try {
|
|
2272
2284
|
const data = [{ operation: "requestPasswordReset", data: { email } }];
|
|
2273
|
-
const response = await
|
|
2285
|
+
const response = await crudify11.transaction(data);
|
|
2274
2286
|
if (response.success) {
|
|
2275
2287
|
if (response.data && response.data.existingCodeValid) {
|
|
2276
2288
|
setCodeAlreadyExists(true);
|
|
@@ -2373,7 +2385,7 @@ var import_react8 = require("react");
|
|
|
2373
2385
|
var import_material3 = require("@mui/material");
|
|
2374
2386
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2375
2387
|
var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess }) => {
|
|
2376
|
-
const { crudify:
|
|
2388
|
+
const { crudify: crudify11 } = useCrudify();
|
|
2377
2389
|
const [newPassword, setNewPassword] = (0, import_react8.useState)("");
|
|
2378
2390
|
const [confirmPassword, setConfirmPassword] = (0, import_react8.useState)("");
|
|
2379
2391
|
const [loading, setLoading] = (0, import_react8.useState)(false);
|
|
@@ -2453,9 +2465,9 @@ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess
|
|
|
2453
2465
|
setErrors([t("resetPassword.invalidCode")]);
|
|
2454
2466
|
setValidatingCode(false);
|
|
2455
2467
|
setTimeout(() => onScreenChange?.("forgotPassword"), 3e3);
|
|
2456
|
-
}, [searchParams,
|
|
2468
|
+
}, [searchParams, crudify11, t, onScreenChange]);
|
|
2457
2469
|
(0, import_react8.useEffect)(() => {
|
|
2458
|
-
if (
|
|
2470
|
+
if (crudify11 && pendingValidation && !isValidating) {
|
|
2459
2471
|
setIsValidating(true);
|
|
2460
2472
|
const validateCode = async (emailToValidate, codeToValidate) => {
|
|
2461
2473
|
try {
|
|
@@ -2465,7 +2477,7 @@ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess
|
|
|
2465
2477
|
data: { email: emailToValidate, codePassword: codeToValidate }
|
|
2466
2478
|
}
|
|
2467
2479
|
];
|
|
2468
|
-
const response = await
|
|
2480
|
+
const response = await crudify11.transaction(data);
|
|
2469
2481
|
if (response.data && Array.isArray(response.data)) {
|
|
2470
2482
|
const validationResult = response.data[0];
|
|
2471
2483
|
if (validationResult && validationResult.response && validationResult.response.status === "OK") {
|
|
@@ -2494,7 +2506,7 @@ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess
|
|
|
2494
2506
|
};
|
|
2495
2507
|
validateCode(pendingValidation.email, pendingValidation.code);
|
|
2496
2508
|
}
|
|
2497
|
-
}, [
|
|
2509
|
+
}, [crudify11, pendingValidation, t, onScreenChange]);
|
|
2498
2510
|
const validatePassword = (password) => {
|
|
2499
2511
|
if (password.length < 8) {
|
|
2500
2512
|
return t("resetPassword.passwordTooShort");
|
|
@@ -2502,7 +2514,7 @@ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess
|
|
|
2502
2514
|
return null;
|
|
2503
2515
|
};
|
|
2504
2516
|
const handleSubmit = async () => {
|
|
2505
|
-
if (loading || !
|
|
2517
|
+
if (loading || !crudify11) return;
|
|
2506
2518
|
setErrors([]);
|
|
2507
2519
|
setHelperTextNewPassword(null);
|
|
2508
2520
|
setHelperTextConfirmPassword(null);
|
|
@@ -2533,7 +2545,7 @@ var ResetPasswordForm = ({ onScreenChange, onError, searchParams, onResetSuccess
|
|
|
2533
2545
|
data: { email, codePassword: code, newPassword }
|
|
2534
2546
|
}
|
|
2535
2547
|
];
|
|
2536
|
-
const response = await
|
|
2548
|
+
const response = await crudify11.transaction(data);
|
|
2537
2549
|
if (response.success) {
|
|
2538
2550
|
setErrors([]);
|
|
2539
2551
|
setTimeout(() => {
|
|
@@ -2644,7 +2656,7 @@ var import_react9 = require("react");
|
|
|
2644
2656
|
var import_material4 = require("@mui/material");
|
|
2645
2657
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2646
2658
|
var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
|
|
2647
|
-
const { crudify:
|
|
2659
|
+
const { crudify: crudify11 } = useCrudify();
|
|
2648
2660
|
const [code, setCode] = (0, import_react9.useState)("");
|
|
2649
2661
|
const [loading, setLoading] = (0, import_react9.useState)(false);
|
|
2650
2662
|
const [errors, setErrors] = (0, import_react9.useState)([]);
|
|
@@ -2683,7 +2695,7 @@ var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
|
|
|
2683
2695
|
}
|
|
2684
2696
|
}, [searchParams, onScreenChange]);
|
|
2685
2697
|
const handleSubmit = async () => {
|
|
2686
|
-
if (loading || !
|
|
2698
|
+
if (loading || !crudify11) return;
|
|
2687
2699
|
setErrors([]);
|
|
2688
2700
|
setHelperTextCode(null);
|
|
2689
2701
|
if (!code) {
|
|
@@ -2702,7 +2714,7 @@ var CheckCodeForm = ({ onScreenChange, onError, searchParams }) => {
|
|
|
2702
2714
|
data: { email, codePassword: code }
|
|
2703
2715
|
}
|
|
2704
2716
|
];
|
|
2705
|
-
const response = await
|
|
2717
|
+
const response = await crudify11.transaction(data);
|
|
2706
2718
|
if (response.success) {
|
|
2707
2719
|
onScreenChange?.("resetPassword", { email, code, fromCodeVerification: "true" });
|
|
2708
2720
|
} else {
|
|
@@ -3875,12 +3887,1206 @@ init_CrudifyDataProvider();
|
|
|
3875
3887
|
init_jwtUtils();
|
|
3876
3888
|
init_cookies();
|
|
3877
3889
|
init_secureStorage();
|
|
3890
|
+
|
|
3891
|
+
// src/core/SessionManager.ts
|
|
3892
|
+
var import_crudify_browser8 = __toESM(require("@nocios/crudify-browser"));
|
|
3893
|
+
|
|
3894
|
+
// src/utils/tokenStorage.ts
|
|
3895
|
+
var import_crypto_js2 = __toESM(require("crypto-js"));
|
|
3896
|
+
var _TokenStorage = class _TokenStorage {
|
|
3897
|
+
/**
|
|
3898
|
+
* Configurar tipo de almacenamiento
|
|
3899
|
+
*/
|
|
3900
|
+
static setStorageType(type) {
|
|
3901
|
+
_TokenStorage.storageType = type;
|
|
3902
|
+
}
|
|
3903
|
+
/**
|
|
3904
|
+
* Verificar si el storage está disponible
|
|
3905
|
+
*/
|
|
3906
|
+
static isStorageAvailable(type) {
|
|
3907
|
+
try {
|
|
3908
|
+
const storage = window[type];
|
|
3909
|
+
const testKey = "__storage_test__";
|
|
3910
|
+
storage.setItem(testKey, "test");
|
|
3911
|
+
storage.removeItem(testKey);
|
|
3912
|
+
return true;
|
|
3913
|
+
} catch {
|
|
3914
|
+
return false;
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
/**
|
|
3918
|
+
* Obtener instancia de storage
|
|
3919
|
+
*/
|
|
3920
|
+
static getStorage() {
|
|
3921
|
+
if (_TokenStorage.storageType === "none") return null;
|
|
3922
|
+
if (!_TokenStorage.isStorageAvailable(_TokenStorage.storageType)) {
|
|
3923
|
+
console.warn(`Crudify: ${_TokenStorage.storageType} not available, tokens won't persist`);
|
|
3924
|
+
return null;
|
|
3925
|
+
}
|
|
3926
|
+
return window[_TokenStorage.storageType];
|
|
3927
|
+
}
|
|
3928
|
+
/**
|
|
3929
|
+
* Encriptar datos sensibles
|
|
3930
|
+
*/
|
|
3931
|
+
static encrypt(data) {
|
|
3932
|
+
try {
|
|
3933
|
+
return import_crypto_js2.default.AES.encrypt(data, _TokenStorage.ENCRYPTION_KEY).toString();
|
|
3934
|
+
} catch (error) {
|
|
3935
|
+
console.error("Crudify: Encryption failed", error);
|
|
3936
|
+
return data;
|
|
3937
|
+
}
|
|
3938
|
+
}
|
|
3939
|
+
/**
|
|
3940
|
+
* Desencriptar datos
|
|
3941
|
+
*/
|
|
3942
|
+
static decrypt(encryptedData) {
|
|
3943
|
+
try {
|
|
3944
|
+
const bytes = import_crypto_js2.default.AES.decrypt(encryptedData, _TokenStorage.ENCRYPTION_KEY);
|
|
3945
|
+
const decrypted = bytes.toString(import_crypto_js2.default.enc.Utf8);
|
|
3946
|
+
return decrypted || encryptedData;
|
|
3947
|
+
} catch (error) {
|
|
3948
|
+
console.error("Crudify: Decryption failed", error);
|
|
3949
|
+
return encryptedData;
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
/**
|
|
3953
|
+
* Guardar tokens de forma segura
|
|
3954
|
+
*/
|
|
3955
|
+
static saveTokens(tokens) {
|
|
3956
|
+
const storage = _TokenStorage.getStorage();
|
|
3957
|
+
if (!storage) return;
|
|
3958
|
+
try {
|
|
3959
|
+
const tokenData = {
|
|
3960
|
+
accessToken: tokens.accessToken,
|
|
3961
|
+
refreshToken: tokens.refreshToken,
|
|
3962
|
+
expiresAt: tokens.expiresAt,
|
|
3963
|
+
refreshExpiresAt: tokens.refreshExpiresAt,
|
|
3964
|
+
savedAt: Date.now()
|
|
3965
|
+
};
|
|
3966
|
+
const encrypted = _TokenStorage.encrypt(JSON.stringify(tokenData));
|
|
3967
|
+
storage.setItem(_TokenStorage.TOKEN_KEY, encrypted);
|
|
3968
|
+
console.debug("Crudify: Tokens saved successfully");
|
|
3969
|
+
} catch (error) {
|
|
3970
|
+
console.error("Crudify: Failed to save tokens", error);
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3973
|
+
/**
|
|
3974
|
+
* Obtener tokens guardados
|
|
3975
|
+
*/
|
|
3976
|
+
static getTokens() {
|
|
3977
|
+
const storage = _TokenStorage.getStorage();
|
|
3978
|
+
if (!storage) return null;
|
|
3979
|
+
try {
|
|
3980
|
+
const encrypted = storage.getItem(_TokenStorage.TOKEN_KEY);
|
|
3981
|
+
if (!encrypted) return null;
|
|
3982
|
+
const decrypted = _TokenStorage.decrypt(encrypted);
|
|
3983
|
+
const tokenData = JSON.parse(decrypted);
|
|
3984
|
+
if (!tokenData.accessToken || !tokenData.refreshToken || !tokenData.expiresAt || !tokenData.refreshExpiresAt) {
|
|
3985
|
+
console.warn("Crudify: Incomplete token data found, clearing storage");
|
|
3986
|
+
_TokenStorage.clearTokens();
|
|
3987
|
+
return null;
|
|
3988
|
+
}
|
|
3989
|
+
if (Date.now() >= tokenData.refreshExpiresAt) {
|
|
3990
|
+
console.info("Crudify: Refresh token expired, clearing storage");
|
|
3991
|
+
_TokenStorage.clearTokens();
|
|
3992
|
+
return null;
|
|
3993
|
+
}
|
|
3994
|
+
return {
|
|
3995
|
+
accessToken: tokenData.accessToken,
|
|
3996
|
+
refreshToken: tokenData.refreshToken,
|
|
3997
|
+
expiresAt: tokenData.expiresAt,
|
|
3998
|
+
refreshExpiresAt: tokenData.refreshExpiresAt
|
|
3999
|
+
};
|
|
4000
|
+
} catch (error) {
|
|
4001
|
+
console.error("Crudify: Failed to retrieve tokens", error);
|
|
4002
|
+
_TokenStorage.clearTokens();
|
|
4003
|
+
return null;
|
|
4004
|
+
}
|
|
4005
|
+
}
|
|
4006
|
+
/**
|
|
4007
|
+
* Limpiar tokens almacenados
|
|
4008
|
+
*/
|
|
4009
|
+
static clearTokens() {
|
|
4010
|
+
const storage = _TokenStorage.getStorage();
|
|
4011
|
+
if (!storage) return;
|
|
4012
|
+
try {
|
|
4013
|
+
storage.removeItem(_TokenStorage.TOKEN_KEY);
|
|
4014
|
+
console.debug("Crudify: Tokens cleared from storage");
|
|
4015
|
+
} catch (error) {
|
|
4016
|
+
console.error("Crudify: Failed to clear tokens", error);
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
4019
|
+
/**
|
|
4020
|
+
* Verificar si hay tokens válidos guardados
|
|
4021
|
+
*/
|
|
4022
|
+
static hasValidTokens() {
|
|
4023
|
+
const tokens = _TokenStorage.getTokens();
|
|
4024
|
+
return tokens !== null;
|
|
4025
|
+
}
|
|
4026
|
+
/**
|
|
4027
|
+
* Obtener información de expiración
|
|
4028
|
+
*/
|
|
4029
|
+
static getExpirationInfo() {
|
|
4030
|
+
const tokens = _TokenStorage.getTokens();
|
|
4031
|
+
if (!tokens) return null;
|
|
4032
|
+
const now = Date.now();
|
|
4033
|
+
return {
|
|
4034
|
+
accessExpired: now >= tokens.expiresAt,
|
|
4035
|
+
refreshExpired: now >= tokens.refreshExpiresAt,
|
|
4036
|
+
accessExpiresIn: Math.max(0, tokens.expiresAt - now),
|
|
4037
|
+
refreshExpiresIn: Math.max(0, tokens.refreshExpiresAt - now)
|
|
4038
|
+
};
|
|
4039
|
+
}
|
|
4040
|
+
/**
|
|
4041
|
+
* Actualizar solo el access token (después de refresh)
|
|
4042
|
+
*/
|
|
4043
|
+
static updateAccessToken(newAccessToken, newExpiresAt) {
|
|
4044
|
+
const existingTokens = _TokenStorage.getTokens();
|
|
4045
|
+
if (!existingTokens) {
|
|
4046
|
+
console.warn("Crudify: Cannot update access token, no existing tokens found");
|
|
4047
|
+
return;
|
|
4048
|
+
}
|
|
4049
|
+
_TokenStorage.saveTokens({
|
|
4050
|
+
...existingTokens,
|
|
4051
|
+
accessToken: newAccessToken,
|
|
4052
|
+
expiresAt: newExpiresAt
|
|
4053
|
+
});
|
|
4054
|
+
}
|
|
4055
|
+
};
|
|
4056
|
+
_TokenStorage.TOKEN_KEY = "crudify_tokens";
|
|
4057
|
+
_TokenStorage.ENCRYPTION_KEY = "crudify_secure_key_v1";
|
|
4058
|
+
_TokenStorage.storageType = "localStorage";
|
|
4059
|
+
var TokenStorage = _TokenStorage;
|
|
4060
|
+
|
|
4061
|
+
// src/core/SessionManager.ts
|
|
4062
|
+
var SessionManager = class _SessionManager {
|
|
4063
|
+
constructor() {
|
|
4064
|
+
this.config = {};
|
|
4065
|
+
this.initialized = false;
|
|
4066
|
+
}
|
|
4067
|
+
static getInstance() {
|
|
4068
|
+
if (!_SessionManager.instance) {
|
|
4069
|
+
_SessionManager.instance = new _SessionManager();
|
|
4070
|
+
}
|
|
4071
|
+
return _SessionManager.instance;
|
|
4072
|
+
}
|
|
4073
|
+
/**
|
|
4074
|
+
* Inicializar el SessionManager
|
|
4075
|
+
*/
|
|
4076
|
+
async initialize(config = {}) {
|
|
4077
|
+
if (this.initialized) {
|
|
4078
|
+
console.warn("SessionManager: Already initialized");
|
|
4079
|
+
return;
|
|
4080
|
+
}
|
|
4081
|
+
this.config = {
|
|
4082
|
+
storageType: "localStorage",
|
|
4083
|
+
autoRestore: true,
|
|
4084
|
+
enableLogging: false,
|
|
4085
|
+
...config
|
|
4086
|
+
};
|
|
4087
|
+
TokenStorage.setStorageType(this.config.storageType || "localStorage");
|
|
4088
|
+
if (this.config.enableLogging) {
|
|
4089
|
+
}
|
|
4090
|
+
if (this.config.autoRestore) {
|
|
4091
|
+
await this.restoreSession();
|
|
4092
|
+
}
|
|
4093
|
+
this.initialized = true;
|
|
4094
|
+
this.log("SessionManager initialized successfully");
|
|
4095
|
+
}
|
|
4096
|
+
/**
|
|
4097
|
+
* Login con persistencia automática
|
|
4098
|
+
*/
|
|
4099
|
+
async login(email, password) {
|
|
4100
|
+
try {
|
|
4101
|
+
this.log("Attempting login...");
|
|
4102
|
+
const response = await import_crudify_browser8.default.login(email, password);
|
|
4103
|
+
if (!response.success) {
|
|
4104
|
+
this.log("Login failed:", response.errors);
|
|
4105
|
+
return {
|
|
4106
|
+
success: false,
|
|
4107
|
+
error: this.formatError(response.errors)
|
|
4108
|
+
};
|
|
4109
|
+
}
|
|
4110
|
+
const tokens = {
|
|
4111
|
+
accessToken: response.data.token,
|
|
4112
|
+
refreshToken: response.data.refreshToken,
|
|
4113
|
+
expiresAt: response.data.expiresAt,
|
|
4114
|
+
refreshExpiresAt: response.data.refreshExpiresAt
|
|
4115
|
+
};
|
|
4116
|
+
TokenStorage.saveTokens(tokens);
|
|
4117
|
+
this.log("Login successful, tokens saved");
|
|
4118
|
+
this.config.onLoginSuccess?.(tokens);
|
|
4119
|
+
return {
|
|
4120
|
+
success: true,
|
|
4121
|
+
tokens
|
|
4122
|
+
};
|
|
4123
|
+
} catch (error) {
|
|
4124
|
+
this.log("Login error:", error);
|
|
4125
|
+
return {
|
|
4126
|
+
success: false,
|
|
4127
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
4128
|
+
};
|
|
4129
|
+
}
|
|
4130
|
+
}
|
|
4131
|
+
/**
|
|
4132
|
+
* Logout con limpieza de tokens
|
|
4133
|
+
*/
|
|
4134
|
+
async logout() {
|
|
4135
|
+
try {
|
|
4136
|
+
this.log("Logging out...");
|
|
4137
|
+
await import_crudify_browser8.default.logout();
|
|
4138
|
+
TokenStorage.clearTokens();
|
|
4139
|
+
this.log("Logout successful");
|
|
4140
|
+
this.config.onLogout?.();
|
|
4141
|
+
} catch (error) {
|
|
4142
|
+
this.log("Logout error:", error);
|
|
4143
|
+
TokenStorage.clearTokens();
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
/**
|
|
4147
|
+
* Restaurar sesión desde storage
|
|
4148
|
+
*/
|
|
4149
|
+
async restoreSession() {
|
|
4150
|
+
try {
|
|
4151
|
+
this.log("Attempting to restore session...");
|
|
4152
|
+
const savedTokens = TokenStorage.getTokens();
|
|
4153
|
+
if (!savedTokens) {
|
|
4154
|
+
this.log("No valid tokens found in storage");
|
|
4155
|
+
return false;
|
|
4156
|
+
}
|
|
4157
|
+
import_crudify_browser8.default.setTokens({
|
|
4158
|
+
accessToken: savedTokens.accessToken,
|
|
4159
|
+
refreshToken: savedTokens.refreshToken,
|
|
4160
|
+
expiresAt: savedTokens.expiresAt,
|
|
4161
|
+
refreshExpiresAt: savedTokens.refreshExpiresAt
|
|
4162
|
+
});
|
|
4163
|
+
this.log("Session restored successfully");
|
|
4164
|
+
this.config.onSessionRestored?.(savedTokens);
|
|
4165
|
+
return true;
|
|
4166
|
+
} catch (error) {
|
|
4167
|
+
this.log("Session restore error:", error);
|
|
4168
|
+
TokenStorage.clearTokens();
|
|
4169
|
+
return false;
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
/**
|
|
4173
|
+
* Verificar si el usuario está autenticado
|
|
4174
|
+
*/
|
|
4175
|
+
isAuthenticated() {
|
|
4176
|
+
return import_crudify_browser8.default.isLogin() || TokenStorage.hasValidTokens();
|
|
4177
|
+
}
|
|
4178
|
+
/**
|
|
4179
|
+
* Obtener información de tokens actuales
|
|
4180
|
+
*/
|
|
4181
|
+
getTokenInfo() {
|
|
4182
|
+
const crudifyTokens = import_crudify_browser8.default.getTokenData();
|
|
4183
|
+
const storageInfo = TokenStorage.getExpirationInfo();
|
|
4184
|
+
return {
|
|
4185
|
+
isLoggedIn: this.isAuthenticated(),
|
|
4186
|
+
crudifyTokens,
|
|
4187
|
+
storageInfo,
|
|
4188
|
+
hasValidTokens: TokenStorage.hasValidTokens()
|
|
4189
|
+
};
|
|
4190
|
+
}
|
|
4191
|
+
/**
|
|
4192
|
+
* Refrescar tokens manualmente
|
|
4193
|
+
*/
|
|
4194
|
+
async refreshTokens() {
|
|
4195
|
+
try {
|
|
4196
|
+
this.log("Manually refreshing tokens...");
|
|
4197
|
+
const response = await import_crudify_browser8.default.refreshAccessToken();
|
|
4198
|
+
if (!response.success) {
|
|
4199
|
+
this.log("Token refresh failed:", response.errors);
|
|
4200
|
+
TokenStorage.clearTokens();
|
|
4201
|
+
this.config.onSessionExpired?.();
|
|
4202
|
+
return false;
|
|
4203
|
+
}
|
|
4204
|
+
const newTokens = {
|
|
4205
|
+
accessToken: response.data.token,
|
|
4206
|
+
refreshToken: response.data.refreshToken,
|
|
4207
|
+
expiresAt: response.data.expiresAt,
|
|
4208
|
+
refreshExpiresAt: response.data.refreshExpiresAt
|
|
4209
|
+
};
|
|
4210
|
+
TokenStorage.saveTokens(newTokens);
|
|
4211
|
+
this.log("Tokens refreshed and saved successfully");
|
|
4212
|
+
return true;
|
|
4213
|
+
} catch (error) {
|
|
4214
|
+
this.log("Token refresh error:", error);
|
|
4215
|
+
TokenStorage.clearTokens();
|
|
4216
|
+
this.config.onSessionExpired?.();
|
|
4217
|
+
return false;
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4220
|
+
/**
|
|
4221
|
+
* Configurar interceptor de respuesta para manejo automático de errores
|
|
4222
|
+
*/
|
|
4223
|
+
setupResponseInterceptor() {
|
|
4224
|
+
import_crudify_browser8.default.setResponseInterceptor(async (response) => {
|
|
4225
|
+
if (response.errors) {
|
|
4226
|
+
const hasAuthError = response.errors.some(
|
|
4227
|
+
(error) => error.message?.includes("Unauthorized") || error.message?.includes("Token") || error.extensions?.code === "UNAUTHENTICATED"
|
|
4228
|
+
);
|
|
4229
|
+
if (hasAuthError && TokenStorage.hasValidTokens()) {
|
|
4230
|
+
this.log("Auth error detected, attempting token refresh...");
|
|
4231
|
+
const refreshSuccess = await this.refreshTokens();
|
|
4232
|
+
if (!refreshSuccess) {
|
|
4233
|
+
this.log("Session expired, triggering callback");
|
|
4234
|
+
this.config.onSessionExpired?.();
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4238
|
+
return response;
|
|
4239
|
+
});
|
|
4240
|
+
this.log("Response interceptor configured");
|
|
4241
|
+
}
|
|
4242
|
+
/**
|
|
4243
|
+
* Limpiar sesión completamente
|
|
4244
|
+
*/
|
|
4245
|
+
clearSession() {
|
|
4246
|
+
TokenStorage.clearTokens();
|
|
4247
|
+
import_crudify_browser8.default.logout();
|
|
4248
|
+
this.log("Session cleared completely");
|
|
4249
|
+
}
|
|
4250
|
+
// Métodos privados
|
|
4251
|
+
log(message, ...args) {
|
|
4252
|
+
if (this.config.enableLogging) {
|
|
4253
|
+
console.log(`[SessionManager] ${message}`, ...args);
|
|
4254
|
+
}
|
|
4255
|
+
}
|
|
4256
|
+
formatError(errors) {
|
|
4257
|
+
if (!errors) return "Unknown error";
|
|
4258
|
+
if (typeof errors === "string") return errors;
|
|
4259
|
+
if (typeof errors === "object") {
|
|
4260
|
+
const errorMessages = Object.values(errors).flat();
|
|
4261
|
+
return errorMessages.join(", ");
|
|
4262
|
+
}
|
|
4263
|
+
return "Authentication failed";
|
|
4264
|
+
}
|
|
4265
|
+
};
|
|
4266
|
+
|
|
4267
|
+
// src/hooks/useSession.ts
|
|
4268
|
+
var import_react16 = require("react");
|
|
4269
|
+
function useSession(options = {}) {
|
|
4270
|
+
const [state, setState] = (0, import_react16.useState)({
|
|
4271
|
+
isAuthenticated: false,
|
|
4272
|
+
isLoading: true,
|
|
4273
|
+
isInitialized: false,
|
|
4274
|
+
tokens: null,
|
|
4275
|
+
error: null
|
|
4276
|
+
});
|
|
4277
|
+
const sessionManager = SessionManager.getInstance();
|
|
4278
|
+
const initialize = (0, import_react16.useCallback)(async () => {
|
|
4279
|
+
try {
|
|
4280
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
4281
|
+
const config = {
|
|
4282
|
+
autoRestore: options.autoRestore ?? true,
|
|
4283
|
+
enableLogging: options.enableLogging ?? false,
|
|
4284
|
+
onSessionExpired: () => {
|
|
4285
|
+
setState((prev) => ({
|
|
4286
|
+
...prev,
|
|
4287
|
+
isAuthenticated: false,
|
|
4288
|
+
tokens: null,
|
|
4289
|
+
error: "Session expired"
|
|
4290
|
+
}));
|
|
4291
|
+
options.onSessionExpired?.();
|
|
4292
|
+
},
|
|
4293
|
+
onSessionRestored: (tokens) => {
|
|
4294
|
+
setState((prev) => ({
|
|
4295
|
+
...prev,
|
|
4296
|
+
isAuthenticated: true,
|
|
4297
|
+
tokens,
|
|
4298
|
+
error: null
|
|
4299
|
+
}));
|
|
4300
|
+
options.onSessionRestored?.(tokens);
|
|
4301
|
+
},
|
|
4302
|
+
onLoginSuccess: (tokens) => {
|
|
4303
|
+
setState((prev) => ({
|
|
4304
|
+
...prev,
|
|
4305
|
+
isAuthenticated: true,
|
|
4306
|
+
tokens,
|
|
4307
|
+
error: null
|
|
4308
|
+
}));
|
|
4309
|
+
},
|
|
4310
|
+
onLogout: () => {
|
|
4311
|
+
setState((prev) => ({
|
|
4312
|
+
...prev,
|
|
4313
|
+
isAuthenticated: false,
|
|
4314
|
+
tokens: null,
|
|
4315
|
+
error: null
|
|
4316
|
+
}));
|
|
4317
|
+
}
|
|
4318
|
+
};
|
|
4319
|
+
await sessionManager.initialize(config);
|
|
4320
|
+
sessionManager.setupResponseInterceptor();
|
|
4321
|
+
const isAuth = sessionManager.isAuthenticated();
|
|
4322
|
+
const tokenInfo = sessionManager.getTokenInfo();
|
|
4323
|
+
setState((prev) => ({
|
|
4324
|
+
...prev,
|
|
4325
|
+
isAuthenticated: isAuth,
|
|
4326
|
+
isInitialized: true,
|
|
4327
|
+
isLoading: false,
|
|
4328
|
+
tokens: tokenInfo.crudifyTokens.accessToken ? {
|
|
4329
|
+
accessToken: tokenInfo.crudifyTokens.accessToken,
|
|
4330
|
+
refreshToken: tokenInfo.crudifyTokens.refreshToken,
|
|
4331
|
+
expiresAt: tokenInfo.crudifyTokens.expiresAt,
|
|
4332
|
+
refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
|
|
4333
|
+
} : null
|
|
4334
|
+
}));
|
|
4335
|
+
} catch (error) {
|
|
4336
|
+
setState((prev) => ({
|
|
4337
|
+
...prev,
|
|
4338
|
+
isLoading: false,
|
|
4339
|
+
isInitialized: true,
|
|
4340
|
+
error: error instanceof Error ? error.message : "Initialization failed"
|
|
4341
|
+
}));
|
|
4342
|
+
}
|
|
4343
|
+
}, [options.autoRestore, options.enableLogging, options.onSessionExpired, options.onSessionRestored]);
|
|
4344
|
+
const login = (0, import_react16.useCallback)(async (email, password) => {
|
|
4345
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
4346
|
+
try {
|
|
4347
|
+
const result = await sessionManager.login(email, password);
|
|
4348
|
+
if (result.success && result.tokens) {
|
|
4349
|
+
setState((prev) => ({
|
|
4350
|
+
...prev,
|
|
4351
|
+
isAuthenticated: true,
|
|
4352
|
+
tokens: result.tokens,
|
|
4353
|
+
isLoading: false,
|
|
4354
|
+
error: null
|
|
4355
|
+
}));
|
|
4356
|
+
} else {
|
|
4357
|
+
setState((prev) => ({
|
|
4358
|
+
...prev,
|
|
4359
|
+
isAuthenticated: false,
|
|
4360
|
+
tokens: null,
|
|
4361
|
+
isLoading: false,
|
|
4362
|
+
error: result.error || "Login failed"
|
|
4363
|
+
}));
|
|
4364
|
+
}
|
|
4365
|
+
return result;
|
|
4366
|
+
} catch (error) {
|
|
4367
|
+
const errorMsg = error instanceof Error ? error.message : "Login failed";
|
|
4368
|
+
setState((prev) => ({
|
|
4369
|
+
...prev,
|
|
4370
|
+
isAuthenticated: false,
|
|
4371
|
+
tokens: null,
|
|
4372
|
+
isLoading: false,
|
|
4373
|
+
error: errorMsg
|
|
4374
|
+
}));
|
|
4375
|
+
return {
|
|
4376
|
+
success: false,
|
|
4377
|
+
error: errorMsg
|
|
4378
|
+
};
|
|
4379
|
+
}
|
|
4380
|
+
}, [sessionManager]);
|
|
4381
|
+
const logout = (0, import_react16.useCallback)(async () => {
|
|
4382
|
+
setState((prev) => ({ ...prev, isLoading: true }));
|
|
4383
|
+
try {
|
|
4384
|
+
await sessionManager.logout();
|
|
4385
|
+
setState((prev) => ({
|
|
4386
|
+
...prev,
|
|
4387
|
+
isAuthenticated: false,
|
|
4388
|
+
tokens: null,
|
|
4389
|
+
isLoading: false,
|
|
4390
|
+
error: null
|
|
4391
|
+
}));
|
|
4392
|
+
} catch (error) {
|
|
4393
|
+
setState((prev) => ({
|
|
4394
|
+
...prev,
|
|
4395
|
+
isAuthenticated: false,
|
|
4396
|
+
tokens: null,
|
|
4397
|
+
isLoading: false,
|
|
4398
|
+
error: error instanceof Error ? error.message : "Logout error"
|
|
4399
|
+
}));
|
|
4400
|
+
}
|
|
4401
|
+
}, [sessionManager]);
|
|
4402
|
+
const refreshTokens = (0, import_react16.useCallback)(async () => {
|
|
4403
|
+
try {
|
|
4404
|
+
const success = await sessionManager.refreshTokens();
|
|
4405
|
+
if (success) {
|
|
4406
|
+
const tokenInfo = sessionManager.getTokenInfo();
|
|
4407
|
+
setState((prev) => ({
|
|
4408
|
+
...prev,
|
|
4409
|
+
tokens: tokenInfo.crudifyTokens.accessToken ? {
|
|
4410
|
+
accessToken: tokenInfo.crudifyTokens.accessToken,
|
|
4411
|
+
refreshToken: tokenInfo.crudifyTokens.refreshToken,
|
|
4412
|
+
expiresAt: tokenInfo.crudifyTokens.expiresAt,
|
|
4413
|
+
refreshExpiresAt: tokenInfo.crudifyTokens.refreshExpiresAt
|
|
4414
|
+
} : null,
|
|
4415
|
+
error: null
|
|
4416
|
+
}));
|
|
4417
|
+
} else {
|
|
4418
|
+
setState((prev) => ({
|
|
4419
|
+
...prev,
|
|
4420
|
+
isAuthenticated: false,
|
|
4421
|
+
tokens: null,
|
|
4422
|
+
error: "Token refresh failed"
|
|
4423
|
+
}));
|
|
4424
|
+
}
|
|
4425
|
+
return success;
|
|
4426
|
+
} catch (error) {
|
|
4427
|
+
setState((prev) => ({
|
|
4428
|
+
...prev,
|
|
4429
|
+
isAuthenticated: false,
|
|
4430
|
+
tokens: null,
|
|
4431
|
+
error: error instanceof Error ? error.message : "Token refresh failed"
|
|
4432
|
+
}));
|
|
4433
|
+
return false;
|
|
4434
|
+
}
|
|
4435
|
+
}, [sessionManager]);
|
|
4436
|
+
const clearError = (0, import_react16.useCallback)(() => {
|
|
4437
|
+
setState((prev) => ({ ...prev, error: null }));
|
|
4438
|
+
}, []);
|
|
4439
|
+
const getTokenInfo = (0, import_react16.useCallback)(() => {
|
|
4440
|
+
return sessionManager.getTokenInfo();
|
|
4441
|
+
}, [sessionManager]);
|
|
4442
|
+
(0, import_react16.useEffect)(() => {
|
|
4443
|
+
initialize();
|
|
4444
|
+
}, [initialize]);
|
|
4445
|
+
return {
|
|
4446
|
+
// Estado
|
|
4447
|
+
...state,
|
|
4448
|
+
// Acciones
|
|
4449
|
+
login,
|
|
4450
|
+
logout,
|
|
4451
|
+
refreshTokens,
|
|
4452
|
+
clearError,
|
|
4453
|
+
getTokenInfo,
|
|
4454
|
+
// Utilidades
|
|
4455
|
+
isExpiringSoon: state.tokens ? state.tokens.expiresAt - Date.now() < 5 * 60 * 1e3 : false,
|
|
4456
|
+
// 5 minutos
|
|
4457
|
+
expiresIn: state.tokens ? Math.max(0, state.tokens.expiresAt - Date.now()) : 0,
|
|
4458
|
+
refreshExpiresIn: state.tokens ? Math.max(0, state.tokens.refreshExpiresAt - Date.now()) : 0
|
|
4459
|
+
};
|
|
4460
|
+
}
|
|
4461
|
+
|
|
4462
|
+
// src/providers/SessionProvider.tsx
|
|
4463
|
+
var import_react17 = require("react");
|
|
4464
|
+
init_jwtUtils();
|
|
4465
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
4466
|
+
var SessionContext = (0, import_react17.createContext)(void 0);
|
|
4467
|
+
function SessionProvider({ children, options = {} }) {
|
|
4468
|
+
const sessionHook = useSession(options);
|
|
4469
|
+
const sessionData = (0, import_react17.useMemo)(() => {
|
|
4470
|
+
if (!sessionHook.tokens?.accessToken || !sessionHook.isAuthenticated) {
|
|
4471
|
+
return null;
|
|
4472
|
+
}
|
|
4473
|
+
try {
|
|
4474
|
+
const decoded = decodeJwtSafely(sessionHook.tokens.accessToken);
|
|
4475
|
+
if (decoded && decoded.sub && decoded.email && decoded.subscriber) {
|
|
4476
|
+
const result = {
|
|
4477
|
+
_id: decoded.sub,
|
|
4478
|
+
email: decoded.email,
|
|
4479
|
+
subscriberKey: decoded.subscriber
|
|
4480
|
+
};
|
|
4481
|
+
Object.keys(decoded).forEach((key) => {
|
|
4482
|
+
if (!["sub", "email", "subscriber"].includes(key)) {
|
|
4483
|
+
result[key] = decoded[key];
|
|
4484
|
+
}
|
|
4485
|
+
});
|
|
4486
|
+
return result;
|
|
4487
|
+
}
|
|
4488
|
+
} catch (error) {
|
|
4489
|
+
console.error("Error decoding JWT token for sessionData:", error);
|
|
4490
|
+
}
|
|
4491
|
+
return null;
|
|
4492
|
+
}, [sessionHook.tokens?.accessToken, sessionHook.isAuthenticated]);
|
|
4493
|
+
const contextValue = {
|
|
4494
|
+
...sessionHook,
|
|
4495
|
+
sessionData
|
|
4496
|
+
};
|
|
4497
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SessionContext.Provider, { value: contextValue, children });
|
|
4498
|
+
}
|
|
4499
|
+
function useSessionContext() {
|
|
4500
|
+
const context = (0, import_react17.useContext)(SessionContext);
|
|
4501
|
+
if (context === void 0) {
|
|
4502
|
+
throw new Error("useSessionContext must be used within a SessionProvider");
|
|
4503
|
+
}
|
|
4504
|
+
return context;
|
|
4505
|
+
}
|
|
4506
|
+
function ProtectedRoute({
|
|
4507
|
+
children,
|
|
4508
|
+
fallback = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { children: "Please log in to access this content" }),
|
|
4509
|
+
redirectTo
|
|
4510
|
+
}) {
|
|
4511
|
+
const { isAuthenticated, isLoading, isInitialized } = useSessionContext();
|
|
4512
|
+
if (!isInitialized || isLoading) {
|
|
4513
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { children: "Loading..." });
|
|
4514
|
+
}
|
|
4515
|
+
if (!isAuthenticated) {
|
|
4516
|
+
if (redirectTo) {
|
|
4517
|
+
redirectTo();
|
|
4518
|
+
return null;
|
|
4519
|
+
}
|
|
4520
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: fallback });
|
|
4521
|
+
}
|
|
4522
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children });
|
|
4523
|
+
}
|
|
4524
|
+
function SessionDebugInfo() {
|
|
4525
|
+
const session = useSessionContext();
|
|
4526
|
+
if (!session.isInitialized) {
|
|
4527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { children: "Session not initialized" });
|
|
4528
|
+
}
|
|
4529
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: {
|
|
4530
|
+
padding: "10px",
|
|
4531
|
+
margin: "10px",
|
|
4532
|
+
border: "1px solid #ccc",
|
|
4533
|
+
borderRadius: "4px",
|
|
4534
|
+
fontSize: "12px",
|
|
4535
|
+
fontFamily: "monospace"
|
|
4536
|
+
}, children: [
|
|
4537
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h4", { children: "Session Debug Info" }),
|
|
4538
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4539
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Authenticated:" }),
|
|
4540
|
+
" ",
|
|
4541
|
+
session.isAuthenticated ? "Yes" : "No"
|
|
4542
|
+
] }),
|
|
4543
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4544
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Loading:" }),
|
|
4545
|
+
" ",
|
|
4546
|
+
session.isLoading ? "Yes" : "No"
|
|
4547
|
+
] }),
|
|
4548
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4549
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Error:" }),
|
|
4550
|
+
" ",
|
|
4551
|
+
session.error || "None"
|
|
4552
|
+
] }),
|
|
4553
|
+
session.tokens && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
4554
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4555
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Access Token:" }),
|
|
4556
|
+
" ",
|
|
4557
|
+
session.tokens.accessToken.substring(0, 20),
|
|
4558
|
+
"..."
|
|
4559
|
+
] }),
|
|
4560
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4561
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Refresh Token:" }),
|
|
4562
|
+
" ",
|
|
4563
|
+
session.tokens.refreshToken.substring(0, 20),
|
|
4564
|
+
"..."
|
|
4565
|
+
] }),
|
|
4566
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4567
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Access Expires In:" }),
|
|
4568
|
+
" ",
|
|
4569
|
+
Math.round(session.expiresIn / 1e3 / 60),
|
|
4570
|
+
" minutes"
|
|
4571
|
+
] }),
|
|
4572
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4573
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Refresh Expires In:" }),
|
|
4574
|
+
" ",
|
|
4575
|
+
Math.round(session.refreshExpiresIn / 1e3 / 60 / 60),
|
|
4576
|
+
" hours"
|
|
4577
|
+
] }),
|
|
4578
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
4579
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: "Expiring Soon:" }),
|
|
4580
|
+
" ",
|
|
4581
|
+
session.isExpiringSoon ? "Yes" : "No"
|
|
4582
|
+
] })
|
|
4583
|
+
] })
|
|
4584
|
+
] });
|
|
4585
|
+
}
|
|
4586
|
+
|
|
4587
|
+
// src/components/LoginComponent.tsx
|
|
4588
|
+
var import_react18 = require("react");
|
|
4589
|
+
var import_material8 = require("@mui/material");
|
|
4590
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
4591
|
+
function LoginComponent() {
|
|
4592
|
+
const [email, setEmail] = (0, import_react18.useState)("");
|
|
4593
|
+
const [password, setPassword] = (0, import_react18.useState)("");
|
|
4594
|
+
const [showForm, setShowForm] = (0, import_react18.useState)(false);
|
|
4595
|
+
const {
|
|
4596
|
+
isAuthenticated,
|
|
4597
|
+
isLoading,
|
|
4598
|
+
error,
|
|
4599
|
+
login,
|
|
4600
|
+
logout,
|
|
4601
|
+
refreshTokens,
|
|
4602
|
+
clearError,
|
|
4603
|
+
isExpiringSoon,
|
|
4604
|
+
expiresIn
|
|
4605
|
+
} = useSessionContext();
|
|
4606
|
+
const handleLogin = async (e) => {
|
|
4607
|
+
e.preventDefault();
|
|
4608
|
+
if (!email || !password) {
|
|
4609
|
+
return;
|
|
4610
|
+
}
|
|
4611
|
+
const result = await login(email, password);
|
|
4612
|
+
if (result.success) {
|
|
4613
|
+
setEmail("");
|
|
4614
|
+
setPassword("");
|
|
4615
|
+
setShowForm(false);
|
|
4616
|
+
}
|
|
4617
|
+
};
|
|
4618
|
+
const handleLogout = async () => {
|
|
4619
|
+
await logout();
|
|
4620
|
+
};
|
|
4621
|
+
const handleRefreshTokens = async () => {
|
|
4622
|
+
await refreshTokens();
|
|
4623
|
+
};
|
|
4624
|
+
if (isAuthenticated) {
|
|
4625
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { sx: { maxWidth: 600, mx: "auto", p: 3 }, children: [
|
|
4626
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "h4", gutterBottom: true, children: "Welcome! \u{1F389}" }),
|
|
4627
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Alert, { severity: "success", sx: { mb: 3 }, children: "You are successfully logged in with Refresh Token Pattern enabled" }),
|
|
4628
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { sx: { mb: 3, p: 2, bgcolor: "background.paper", border: 1, borderColor: "divider", borderRadius: 1 }, children: [
|
|
4629
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "h6", gutterBottom: true, children: "Token Status" }),
|
|
4630
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Typography, { variant: "body2", color: "text.secondary", children: [
|
|
4631
|
+
"Access Token expires in: ",
|
|
4632
|
+
Math.round(expiresIn / 1e3 / 60),
|
|
4633
|
+
" minutes"
|
|
4634
|
+
] }),
|
|
4635
|
+
isExpiringSoon && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Alert, { severity: "warning", sx: { mt: 1 }, children: "Token expires soon - automatic refresh will happen" })
|
|
4636
|
+
] }),
|
|
4637
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { sx: { display: "flex", gap: 2, flexWrap: "wrap" }, children: [
|
|
4638
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4639
|
+
import_material8.Button,
|
|
4640
|
+
{
|
|
4641
|
+
variant: "contained",
|
|
4642
|
+
onClick: handleRefreshTokens,
|
|
4643
|
+
disabled: isLoading,
|
|
4644
|
+
startIcon: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.CircularProgress, { size: 16 }) : null,
|
|
4645
|
+
children: "Refresh Tokens"
|
|
4646
|
+
}
|
|
4647
|
+
),
|
|
4648
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4649
|
+
import_material8.Button,
|
|
4650
|
+
{
|
|
4651
|
+
variant: "outlined",
|
|
4652
|
+
color: "error",
|
|
4653
|
+
onClick: handleLogout,
|
|
4654
|
+
disabled: isLoading,
|
|
4655
|
+
children: "Logout"
|
|
4656
|
+
}
|
|
4657
|
+
)
|
|
4658
|
+
] }),
|
|
4659
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Alert, { severity: "error", sx: { mt: 2 }, onClose: clearError, children: error })
|
|
4660
|
+
] });
|
|
4661
|
+
}
|
|
4662
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { sx: { maxWidth: 400, mx: "auto", p: 3 }, children: [
|
|
4663
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "h4", gutterBottom: true, align: "center", children: "Login with Refresh Tokens" }),
|
|
4664
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Alert, { severity: "info", sx: { mb: 3 }, children: "This demo shows the new Refresh Token Pattern with automatic session management" }),
|
|
4665
|
+
!showForm ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4666
|
+
import_material8.Button,
|
|
4667
|
+
{
|
|
4668
|
+
fullWidth: true,
|
|
4669
|
+
variant: "contained",
|
|
4670
|
+
size: "large",
|
|
4671
|
+
onClick: () => setShowForm(true),
|
|
4672
|
+
sx: { mt: 2 },
|
|
4673
|
+
children: "Show Login Form"
|
|
4674
|
+
}
|
|
4675
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("form", { onSubmit: handleLogin, children: [
|
|
4676
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4677
|
+
import_material8.TextField,
|
|
4678
|
+
{
|
|
4679
|
+
fullWidth: true,
|
|
4680
|
+
label: "Email",
|
|
4681
|
+
type: "email",
|
|
4682
|
+
value: email,
|
|
4683
|
+
onChange: (e) => setEmail(e.target.value),
|
|
4684
|
+
margin: "normal",
|
|
4685
|
+
required: true,
|
|
4686
|
+
autoComplete: "email"
|
|
4687
|
+
}
|
|
4688
|
+
),
|
|
4689
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4690
|
+
import_material8.TextField,
|
|
4691
|
+
{
|
|
4692
|
+
fullWidth: true,
|
|
4693
|
+
label: "Password",
|
|
4694
|
+
type: "password",
|
|
4695
|
+
value: password,
|
|
4696
|
+
onChange: (e) => setPassword(e.target.value),
|
|
4697
|
+
margin: "normal",
|
|
4698
|
+
required: true,
|
|
4699
|
+
autoComplete: "current-password"
|
|
4700
|
+
}
|
|
4701
|
+
),
|
|
4702
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
4703
|
+
import_material8.Button,
|
|
4704
|
+
{
|
|
4705
|
+
type: "submit",
|
|
4706
|
+
fullWidth: true,
|
|
4707
|
+
variant: "contained",
|
|
4708
|
+
size: "large",
|
|
4709
|
+
disabled: isLoading,
|
|
4710
|
+
startIcon: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.CircularProgress, { size: 16 }) : null,
|
|
4711
|
+
sx: { mt: 3, mb: 2 },
|
|
4712
|
+
children: isLoading ? "Logging in..." : "Login"
|
|
4713
|
+
}
|
|
4714
|
+
)
|
|
4715
|
+
] }),
|
|
4716
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Alert, { severity: "error", sx: { mt: 2 }, onClose: clearError, children: error })
|
|
4717
|
+
] });
|
|
4718
|
+
}
|
|
4719
|
+
function SessionStatus() {
|
|
4720
|
+
const { isAuthenticated, isLoading, isExpiringSoon, expiresIn } = useSessionContext();
|
|
4721
|
+
if (isLoading) {
|
|
4722
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
|
|
4723
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.CircularProgress, { size: 16 }),
|
|
4724
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "caption", children: "Loading session..." })
|
|
4725
|
+
] });
|
|
4726
|
+
}
|
|
4727
|
+
if (!isAuthenticated) {
|
|
4728
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "caption", color: "text.secondary", children: "Not logged in" });
|
|
4729
|
+
}
|
|
4730
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Box, { children: [
|
|
4731
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material8.Typography, { variant: "caption", color: "success.main", children: "\u2713 Authenticated" }),
|
|
4732
|
+
isExpiringSoon && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_material8.Typography, { variant: "caption", color: "warning.main", display: "block", children: [
|
|
4733
|
+
"\u26A0 Token expires in ",
|
|
4734
|
+
Math.round(expiresIn / 1e3 / 60),
|
|
4735
|
+
" min"
|
|
4736
|
+
] })
|
|
4737
|
+
] });
|
|
4738
|
+
}
|
|
4739
|
+
|
|
4740
|
+
// src/hooks/useUserData.ts
|
|
4741
|
+
var import_react19 = require("react");
|
|
4742
|
+
var import_crudify_browser9 = __toESM(require("@nocios/crudify-browser"));
|
|
4743
|
+
var useUserData = (options = {}) => {
|
|
4744
|
+
const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
|
|
4745
|
+
const { isAuthenticated, isInitialized, sessionData, tokens } = useSessionContext();
|
|
4746
|
+
const [userData, setUserData] = (0, import_react19.useState)(null);
|
|
4747
|
+
const [loading, setLoading] = (0, import_react19.useState)(false);
|
|
4748
|
+
const [error, setError] = (0, import_react19.useState)(null);
|
|
4749
|
+
const abortControllerRef = (0, import_react19.useRef)(null);
|
|
4750
|
+
const mountedRef = (0, import_react19.useRef)(true);
|
|
4751
|
+
const requestIdRef = (0, import_react19.useRef)(0);
|
|
4752
|
+
const retryCountRef = (0, import_react19.useRef)(0);
|
|
4753
|
+
const getUserEmail = (0, import_react19.useCallback)(() => {
|
|
4754
|
+
if (!sessionData) return null;
|
|
4755
|
+
return sessionData.email || sessionData["cognito:username"] || null;
|
|
4756
|
+
}, [sessionData]);
|
|
4757
|
+
const clearProfile = (0, import_react19.useCallback)(() => {
|
|
4758
|
+
setUserData(null);
|
|
4759
|
+
setError(null);
|
|
4760
|
+
setLoading(false);
|
|
4761
|
+
retryCountRef.current = 0;
|
|
4762
|
+
}, []);
|
|
4763
|
+
const refreshProfile = (0, import_react19.useCallback)(async () => {
|
|
4764
|
+
const userEmail = getUserEmail();
|
|
4765
|
+
console.log("\u{1F464} useUserData - Refreshing profile for:", userEmail);
|
|
4766
|
+
if (!userEmail) {
|
|
4767
|
+
if (mountedRef.current) {
|
|
4768
|
+
setError("No user email available from session data");
|
|
4769
|
+
setLoading(false);
|
|
4770
|
+
}
|
|
4771
|
+
return;
|
|
4772
|
+
}
|
|
4773
|
+
if (!isInitialized) {
|
|
4774
|
+
if (mountedRef.current) {
|
|
4775
|
+
setError("Session not initialized");
|
|
4776
|
+
setLoading(false);
|
|
4777
|
+
}
|
|
4778
|
+
return;
|
|
4779
|
+
}
|
|
4780
|
+
if (abortControllerRef.current) {
|
|
4781
|
+
abortControllerRef.current.abort();
|
|
4782
|
+
}
|
|
4783
|
+
const abortController = new AbortController();
|
|
4784
|
+
abortControllerRef.current = abortController;
|
|
4785
|
+
const currentRequestId = ++requestIdRef.current;
|
|
4786
|
+
try {
|
|
4787
|
+
if (mountedRef.current) {
|
|
4788
|
+
setLoading(true);
|
|
4789
|
+
setError(null);
|
|
4790
|
+
}
|
|
4791
|
+
console.log("\u{1F464} useUserData - Fetching profile data from database");
|
|
4792
|
+
const response = await import_crudify_browser9.default.readItems("users", {
|
|
4793
|
+
filter: { email: userEmail },
|
|
4794
|
+
pagination: { limit: 1 }
|
|
4795
|
+
});
|
|
4796
|
+
console.log("\u{1F464} useUserData - Database response:", response);
|
|
4797
|
+
console.log("\u{1F464} useUserData - response.data:", response.data);
|
|
4798
|
+
console.log("\u{1F464} useUserData - response.data type:", typeof response.data);
|
|
4799
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
|
|
4800
|
+
let userData2 = null;
|
|
4801
|
+
if (response.success) {
|
|
4802
|
+
console.log("\u{1F464} useUserData - Processing successful response:", {
|
|
4803
|
+
dataType: typeof response.data,
|
|
4804
|
+
isArray: Array.isArray(response.data),
|
|
4805
|
+
hasResponse: !!response.data?.response,
|
|
4806
|
+
hasResponseData: !!response.data?.response?.data,
|
|
4807
|
+
responseDataType: typeof response.data?.response?.data
|
|
4808
|
+
});
|
|
4809
|
+
if (Array.isArray(response.data) && response.data.length > 0) {
|
|
4810
|
+
console.log("\u{1F464} useUserData - Found direct array format");
|
|
4811
|
+
userData2 = response.data[0];
|
|
4812
|
+
} else if (response.data?.response?.data) {
|
|
4813
|
+
console.log("\u{1F464} useUserData - Found nested response.data format");
|
|
4814
|
+
try {
|
|
4815
|
+
const rawData = response.data.response.data;
|
|
4816
|
+
console.log("\u{1F464} useUserData - Raw nested data:", rawData);
|
|
4817
|
+
console.log("\u{1F464} useUserData - Raw data type:", typeof rawData);
|
|
4818
|
+
const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
4819
|
+
console.log("\u{1F464} useUserData - Parsed nested data:", parsedData);
|
|
4820
|
+
if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
|
|
4821
|
+
userData2 = parsedData.items[0];
|
|
4822
|
+
console.log("\u{1F464} useUserData - Extracted user from nested items:", userData2);
|
|
4823
|
+
} else {
|
|
4824
|
+
console.log("\u{1F464} useUserData - No items found in parsed data or items array is empty");
|
|
4825
|
+
}
|
|
4826
|
+
} catch (parseError) {
|
|
4827
|
+
console.error("\u{1F464} useUserData - Error parsing nested response data:", parseError);
|
|
4828
|
+
}
|
|
4829
|
+
} else if (response.data && typeof response.data === "object") {
|
|
4830
|
+
console.log("\u{1F464} useUserData - Found object format, checking for items");
|
|
4831
|
+
if (response.data.items && Array.isArray(response.data.items) && response.data.items.length > 0) {
|
|
4832
|
+
console.log("\u{1F464} useUserData - Found items in object format");
|
|
4833
|
+
userData2 = response.data.items[0];
|
|
4834
|
+
} else {
|
|
4835
|
+
console.log("\u{1F464} useUserData - No items found in object format");
|
|
4836
|
+
}
|
|
4837
|
+
} else if (response.data?.data?.response?.data) {
|
|
4838
|
+
console.log("\u{1F464} useUserData - Found double-nested data.data.response.data format");
|
|
4839
|
+
try {
|
|
4840
|
+
const rawData = response.data.data.response.data;
|
|
4841
|
+
console.log("\u{1F464} useUserData - Raw double-nested data:", rawData);
|
|
4842
|
+
const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
4843
|
+
console.log("\u{1F464} useUserData - Parsed double-nested data:", parsedData);
|
|
4844
|
+
if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
|
|
4845
|
+
userData2 = parsedData.items[0];
|
|
4846
|
+
console.log("\u{1F464} useUserData - Extracted user from double-nested items:", userData2);
|
|
4847
|
+
}
|
|
4848
|
+
} catch (parseError) {
|
|
4849
|
+
console.error("\u{1F464} useUserData - Error parsing double-nested response data:", parseError);
|
|
4850
|
+
}
|
|
4851
|
+
}
|
|
4852
|
+
}
|
|
4853
|
+
if (userData2) {
|
|
4854
|
+
console.log("\u{1F464} useUserData - User data found:", userData2);
|
|
4855
|
+
setUserData(userData2);
|
|
4856
|
+
setError(null);
|
|
4857
|
+
retryCountRef.current = 0;
|
|
4858
|
+
console.log("\u{1F464} useUserData - Profile loaded successfully:", userData2);
|
|
4859
|
+
} else {
|
|
4860
|
+
setError("User profile not found in database");
|
|
4861
|
+
setUserData(null);
|
|
4862
|
+
console.warn("\u{1F464} useUserData - User not found for email:", userEmail);
|
|
4863
|
+
}
|
|
4864
|
+
}
|
|
4865
|
+
} catch (err) {
|
|
4866
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
4867
|
+
const error2 = err;
|
|
4868
|
+
console.error("\u{1F464} useUserData - Error fetching profile:", error2);
|
|
4869
|
+
if (error2.name === "AbortError") {
|
|
4870
|
+
return;
|
|
4871
|
+
}
|
|
4872
|
+
const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
|
|
4873
|
+
if (shouldRetry) {
|
|
4874
|
+
retryCountRef.current++;
|
|
4875
|
+
console.log(`\u{1F464} useUserData - Retrying profile fetch (${retryCountRef.current}/${maxRetries})`);
|
|
4876
|
+
setTimeout(() => {
|
|
4877
|
+
if (mountedRef.current) {
|
|
4878
|
+
refreshProfile();
|
|
4879
|
+
}
|
|
4880
|
+
}, 1e3 * retryCountRef.current);
|
|
4881
|
+
} else {
|
|
4882
|
+
setError("Failed to load user profile from database");
|
|
4883
|
+
setUserData(null);
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4886
|
+
} finally {
|
|
4887
|
+
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
4888
|
+
setLoading(false);
|
|
4889
|
+
}
|
|
4890
|
+
if (abortControllerRef.current === abortController) {
|
|
4891
|
+
abortControllerRef.current = null;
|
|
4892
|
+
}
|
|
4893
|
+
}
|
|
4894
|
+
}, [isInitialized, getUserEmail, retryOnError, maxRetries]);
|
|
4895
|
+
(0, import_react19.useEffect)(() => {
|
|
4896
|
+
if (autoFetch && isAuthenticated && isInitialized) {
|
|
4897
|
+
refreshProfile();
|
|
4898
|
+
} else if (!isAuthenticated) {
|
|
4899
|
+
clearProfile();
|
|
4900
|
+
}
|
|
4901
|
+
}, [autoFetch, isAuthenticated, isInitialized, refreshProfile, clearProfile]);
|
|
4902
|
+
(0, import_react19.useEffect)(() => {
|
|
4903
|
+
mountedRef.current = true;
|
|
4904
|
+
return () => {
|
|
4905
|
+
mountedRef.current = false;
|
|
4906
|
+
if (abortControllerRef.current) {
|
|
4907
|
+
abortControllerRef.current.abort();
|
|
4908
|
+
abortControllerRef.current = null;
|
|
4909
|
+
}
|
|
4910
|
+
};
|
|
4911
|
+
}, []);
|
|
4912
|
+
const user = {
|
|
4913
|
+
session: sessionData,
|
|
4914
|
+
// Usar sessionData del nuevo sistema
|
|
4915
|
+
data: userData
|
|
4916
|
+
// Mantener userData del database igual que legacy
|
|
4917
|
+
};
|
|
4918
|
+
return {
|
|
4919
|
+
user,
|
|
4920
|
+
loading,
|
|
4921
|
+
error,
|
|
4922
|
+
refreshProfile,
|
|
4923
|
+
clearProfile
|
|
4924
|
+
};
|
|
4925
|
+
};
|
|
4926
|
+
|
|
4927
|
+
// src/hooks/useAuth.ts
|
|
4928
|
+
var import_react20 = require("react");
|
|
4929
|
+
var useAuth = () => {
|
|
4930
|
+
const {
|
|
4931
|
+
isAuthenticated,
|
|
4932
|
+
isLoading,
|
|
4933
|
+
isInitialized,
|
|
4934
|
+
tokens,
|
|
4935
|
+
error,
|
|
4936
|
+
sessionData,
|
|
4937
|
+
login,
|
|
4938
|
+
logout,
|
|
4939
|
+
refreshTokens,
|
|
4940
|
+
clearError,
|
|
4941
|
+
getTokenInfo,
|
|
4942
|
+
isExpiringSoon,
|
|
4943
|
+
expiresIn,
|
|
4944
|
+
refreshExpiresIn
|
|
4945
|
+
} = useSessionContext();
|
|
4946
|
+
const setToken = (0, import_react20.useCallback)((token) => {
|
|
4947
|
+
if (token) {
|
|
4948
|
+
console.warn("useAuth.setToken() is deprecated. Use login() method instead for better security.");
|
|
4949
|
+
} else {
|
|
4950
|
+
logout();
|
|
4951
|
+
}
|
|
4952
|
+
}, [logout]);
|
|
4953
|
+
const tokenExpiration = tokens?.expiresAt ? new Date(tokens.expiresAt) : null;
|
|
4954
|
+
return {
|
|
4955
|
+
// Estado básico (compatible con legacy)
|
|
4956
|
+
isAuthenticated,
|
|
4957
|
+
loading: isLoading,
|
|
4958
|
+
// En el nuevo sistema se llama isLoading
|
|
4959
|
+
error,
|
|
4960
|
+
// Datos del token (compatible con legacy + mejorado)
|
|
4961
|
+
token: tokens?.accessToken || null,
|
|
4962
|
+
user: sessionData,
|
|
4963
|
+
// sessionData del nuevo sistema (más rico que legacy)
|
|
4964
|
+
tokenExpiration,
|
|
4965
|
+
// Acciones (compatible con legacy + mejorado)
|
|
4966
|
+
setToken,
|
|
4967
|
+
logout,
|
|
4968
|
+
refreshToken: refreshTokens,
|
|
4969
|
+
// Funcionalidad real en el nuevo sistema
|
|
4970
|
+
// Nuevas funcionalidades del sistema de refresh tokens
|
|
4971
|
+
login,
|
|
4972
|
+
isExpiringSoon,
|
|
4973
|
+
expiresIn,
|
|
4974
|
+
refreshExpiresIn,
|
|
4975
|
+
getTokenInfo,
|
|
4976
|
+
clearError
|
|
4977
|
+
};
|
|
4978
|
+
};
|
|
4979
|
+
|
|
4980
|
+
// src/hooks/useData.ts
|
|
4981
|
+
var import_react21 = require("react");
|
|
4982
|
+
var import_crudify_browser10 = __toESM(require("@nocios/crudify-browser"));
|
|
4983
|
+
var useData = () => {
|
|
4984
|
+
const {
|
|
4985
|
+
isInitialized,
|
|
4986
|
+
isLoading,
|
|
4987
|
+
error,
|
|
4988
|
+
isAuthenticated,
|
|
4989
|
+
login: sessionLogin
|
|
4990
|
+
} = useSessionContext();
|
|
4991
|
+
const isReady = (0, import_react21.useCallback)(() => {
|
|
4992
|
+
return isInitialized && !isLoading && !error;
|
|
4993
|
+
}, [isInitialized, isLoading, error]);
|
|
4994
|
+
const waitForReady = (0, import_react21.useCallback)(async () => {
|
|
4995
|
+
return new Promise((resolve, reject) => {
|
|
4996
|
+
const checkReady = () => {
|
|
4997
|
+
if (isReady()) {
|
|
4998
|
+
resolve();
|
|
4999
|
+
} else if (error) {
|
|
5000
|
+
reject(new Error(error));
|
|
5001
|
+
} else {
|
|
5002
|
+
setTimeout(checkReady, 100);
|
|
5003
|
+
}
|
|
5004
|
+
};
|
|
5005
|
+
checkReady();
|
|
5006
|
+
});
|
|
5007
|
+
}, [isReady, error]);
|
|
5008
|
+
const ensureReady = (0, import_react21.useCallback)(async () => {
|
|
5009
|
+
if (!isReady()) {
|
|
5010
|
+
throw new Error("System not ready. Check isInitialized, isLoading, and error states.");
|
|
5011
|
+
}
|
|
5012
|
+
}, [isReady]);
|
|
5013
|
+
const readItems = (0, import_react21.useCallback)(async (moduleKey, filter, options) => {
|
|
5014
|
+
await ensureReady();
|
|
5015
|
+
return await import_crudify_browser10.default.readItems(moduleKey, filter || {}, options);
|
|
5016
|
+
}, [ensureReady]);
|
|
5017
|
+
const readItem = (0, import_react21.useCallback)(async (moduleKey, filter, options) => {
|
|
5018
|
+
await ensureReady();
|
|
5019
|
+
return await import_crudify_browser10.default.readItem(moduleKey, filter, options);
|
|
5020
|
+
}, [ensureReady]);
|
|
5021
|
+
const createItem = (0, import_react21.useCallback)(async (moduleKey, data, options) => {
|
|
5022
|
+
await ensureReady();
|
|
5023
|
+
return await import_crudify_browser10.default.createItem(moduleKey, data, options);
|
|
5024
|
+
}, [ensureReady]);
|
|
5025
|
+
const updateItem = (0, import_react21.useCallback)(async (moduleKey, data, options) => {
|
|
5026
|
+
await ensureReady();
|
|
5027
|
+
return await import_crudify_browser10.default.updateItem(moduleKey, data, options);
|
|
5028
|
+
}, [ensureReady]);
|
|
5029
|
+
const deleteItem = (0, import_react21.useCallback)(async (moduleKey, id, options) => {
|
|
5030
|
+
await ensureReady();
|
|
5031
|
+
return await import_crudify_browser10.default.deleteItem(moduleKey, id, options);
|
|
5032
|
+
}, [ensureReady]);
|
|
5033
|
+
const transaction = (0, import_react21.useCallback)(async (operations, options) => {
|
|
5034
|
+
await ensureReady();
|
|
5035
|
+
return await import_crudify_browser10.default.transaction(operations, options);
|
|
5036
|
+
}, [ensureReady]);
|
|
5037
|
+
const login = (0, import_react21.useCallback)(async (email, password) => {
|
|
5038
|
+
try {
|
|
5039
|
+
const result = await sessionLogin(email, password);
|
|
5040
|
+
if (result.success) {
|
|
5041
|
+
return {
|
|
5042
|
+
success: true,
|
|
5043
|
+
data: result.tokens
|
|
5044
|
+
};
|
|
5045
|
+
} else {
|
|
5046
|
+
return {
|
|
5047
|
+
success: false,
|
|
5048
|
+
errors: result.error || "Login failed"
|
|
5049
|
+
};
|
|
5050
|
+
}
|
|
5051
|
+
} catch (error2) {
|
|
5052
|
+
return {
|
|
5053
|
+
success: false,
|
|
5054
|
+
errors: error2 instanceof Error ? error2.message : "Login failed"
|
|
5055
|
+
};
|
|
5056
|
+
}
|
|
5057
|
+
}, [sessionLogin]);
|
|
5058
|
+
return {
|
|
5059
|
+
// CRUD operations
|
|
5060
|
+
readItems,
|
|
5061
|
+
readItem,
|
|
5062
|
+
createItem,
|
|
5063
|
+
updateItem,
|
|
5064
|
+
deleteItem,
|
|
5065
|
+
transaction,
|
|
5066
|
+
login,
|
|
5067
|
+
// Estado
|
|
5068
|
+
isInitialized,
|
|
5069
|
+
isInitializing: isLoading,
|
|
5070
|
+
// El nuevo sistema usa isLoading
|
|
5071
|
+
initializationError: error,
|
|
5072
|
+
// Utilidades
|
|
5073
|
+
isReady,
|
|
5074
|
+
waitForReady
|
|
5075
|
+
};
|
|
5076
|
+
};
|
|
3878
5077
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3879
5078
|
0 && (module.exports = {
|
|
3880
5079
|
CrudifyDataProvider,
|
|
3881
5080
|
CrudifyLogin,
|
|
3882
5081
|
ERROR_CODES,
|
|
3883
5082
|
ERROR_SEVERITY_MAP,
|
|
5083
|
+
LoginComponent,
|
|
5084
|
+
ProtectedRoute,
|
|
5085
|
+
SessionDebugInfo,
|
|
5086
|
+
SessionManager,
|
|
5087
|
+
SessionProvider,
|
|
5088
|
+
SessionStatus,
|
|
5089
|
+
TokenStorage,
|
|
3884
5090
|
UserProfileDisplay,
|
|
3885
5091
|
configurationManager,
|
|
3886
5092
|
crudify,
|
|
@@ -3899,6 +5105,7 @@ init_secureStorage();
|
|
|
3899
5105
|
secureLocalStorage,
|
|
3900
5106
|
secureSessionStorage,
|
|
3901
5107
|
tokenManager,
|
|
5108
|
+
useAuth,
|
|
3902
5109
|
useCrudifyAuth,
|
|
3903
5110
|
useCrudifyConfig,
|
|
3904
5111
|
useCrudifyData,
|
|
@@ -3906,6 +5113,10 @@ init_secureStorage();
|
|
|
3906
5113
|
useCrudifyInstance,
|
|
3907
5114
|
useCrudifyLogin,
|
|
3908
5115
|
useCrudifyUser,
|
|
5116
|
+
useData,
|
|
5117
|
+
useSession,
|
|
5118
|
+
useSessionContext,
|
|
5119
|
+
useUserData,
|
|
3909
5120
|
useUserProfile,
|
|
3910
5121
|
...require("@nocios/crudify-browser")
|
|
3911
5122
|
});
|