@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/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: () => import_crudify_browser8.default,
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 import_crudify_browser8 = __toESM(require("@nocios/crudify-browser"));
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: crudify8 } = useCrudify();
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 (!crudify8) {
2076
+ if (!crudify11) {
2065
2077
  throw new Error("Crudify not initialized");
2066
2078
  }
2067
- const response = await crudify8.login(state.formData.username, state.formData.password);
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: crudify8 } = useCrudify();
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 || !crudify8) return;
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 crudify8.transaction(data);
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: crudify8 } = useCrudify();
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, crudify8, t, onScreenChange]);
2468
+ }, [searchParams, crudify11, t, onScreenChange]);
2457
2469
  (0, import_react8.useEffect)(() => {
2458
- if (crudify8 && pendingValidation && !isValidating) {
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 crudify8.transaction(data);
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
- }, [crudify8, pendingValidation, t, onScreenChange]);
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 || !crudify8) return;
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 crudify8.transaction(data);
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: crudify8 } = useCrudify();
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 || !crudify8) return;
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 crudify8.transaction(data);
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
  });