@nocios/crudify-ui 4.0.96 → 4.1.0

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.
Files changed (36) hide show
  1. package/dist/{LoginComponent-saSn0o5x.d.mts → LoginComponent-CSTVsfeV.d.mts} +1 -1
  2. package/dist/{LoginComponent-saSn0o5x.d.ts → LoginComponent-CSTVsfeV.d.ts} +1 -1
  3. package/dist/chunk-5JKS55SE.mjs +1 -0
  4. package/dist/chunk-AT74WV5W.js +1 -0
  5. package/dist/chunk-CTDQEJAU.mjs +1 -0
  6. package/dist/{chunk-WG3ZXCPF.js → chunk-GFZGBKFG.js} +1 -1
  7. package/dist/{chunk-JYDCSNNQ.mjs → chunk-GLR5HDJC.mjs} +1 -1
  8. package/dist/{chunk-Y72XFXMI.mjs → chunk-KNEHDX2M.mjs} +1 -1
  9. package/dist/chunk-TLGRXZCS.js +1 -0
  10. package/dist/{chunk-LP5NJV2P.js → chunk-X3HSMDZ7.js} +1 -1
  11. package/dist/components.d.mts +1 -1
  12. package/dist/components.d.ts +1 -1
  13. package/dist/components.js +1 -1
  14. package/dist/components.mjs +1 -1
  15. package/dist/{errorTranslation-DqdgLEUy.d.mts → errorTranslation-DEn4aqs6.d.mts} +1 -1
  16. package/dist/{errorTranslation-CBbQYNWR.d.ts → errorTranslation-DdqZg8JD.d.ts} +1 -1
  17. package/dist/hooks.d.mts +1 -1
  18. package/dist/hooks.d.ts +1 -1
  19. package/dist/hooks.js +1 -1
  20. package/dist/hooks.mjs +1 -1
  21. package/dist/{index-CUbUeMMS.d.mts → index-BwF68SOh.d.mts} +13 -2
  22. package/dist/{index-DZdMugLk.d.ts → index-Fkm9ErmY.d.ts} +13 -2
  23. package/dist/index.d.mts +128 -13
  24. package/dist/index.d.ts +128 -13
  25. package/dist/index.js +6 -1
  26. package/dist/index.mjs +6 -1
  27. package/dist/utils.d.mts +77 -3
  28. package/dist/utils.d.ts +77 -3
  29. package/dist/utils.js +1 -1
  30. package/dist/utils.mjs +1 -1
  31. package/package.json +24 -4
  32. package/vitest.config.ts +27 -0
  33. package/dist/chunk-ATAGEVFK.js +0 -1
  34. package/dist/chunk-HMJY3MMZ.mjs +0 -1
  35. package/dist/chunk-MMYGRMGB.mjs +0 -1
  36. package/dist/chunk-RHG74IMW.js +0 -1
@@ -105,6 +105,8 @@ declare class SessionManager {
105
105
  private config;
106
106
  private initialized;
107
107
  private lastActivityTime;
108
+ private isRefreshingLocally;
109
+ private refreshPromise;
108
110
  private constructor();
109
111
  static getInstance(): SessionManager;
110
112
  /**
@@ -152,11 +154,20 @@ declare class SessionManager {
152
154
  hasValidTokens: boolean;
153
155
  };
154
156
  /**
155
- * Refrescar tokens manualmente
157
+ * ✅ FASE 4: Refrescar tokens con protección contra concurrencia
156
158
  */
157
159
  refreshTokens(): Promise<boolean>;
158
160
  /**
159
- * ✅ FASE 3.3: Configurar interceptor de respuesta con Event Bus
161
+ * ✅ FASE 4: Método privado que realiza el refresh real
162
+ */
163
+ private _performRefresh;
164
+ /**
165
+ * ✅ FASE 4: Verificar si hay un refresh en progreso
166
+ */
167
+ isRefreshing(): boolean;
168
+ /**
169
+ * ✅ MEJORADO FASE 3: Configurar interceptor de respuesta NON-BLOCKING
170
+ * El interceptor NO debe hacer await, solo detectar y emitir eventos
160
171
  */
161
172
  setupResponseInterceptor(): void;
162
173
  /**
@@ -105,6 +105,8 @@ declare class SessionManager {
105
105
  private config;
106
106
  private initialized;
107
107
  private lastActivityTime;
108
+ private isRefreshingLocally;
109
+ private refreshPromise;
108
110
  private constructor();
109
111
  static getInstance(): SessionManager;
110
112
  /**
@@ -152,11 +154,20 @@ declare class SessionManager {
152
154
  hasValidTokens: boolean;
153
155
  };
154
156
  /**
155
- * Refrescar tokens manualmente
157
+ * ✅ FASE 4: Refrescar tokens con protección contra concurrencia
156
158
  */
157
159
  refreshTokens(): Promise<boolean>;
158
160
  /**
159
- * ✅ FASE 3.3: Configurar interceptor de respuesta con Event Bus
161
+ * ✅ FASE 4: Método privado que realiza el refresh real
162
+ */
163
+ private _performRefresh;
164
+ /**
165
+ * ✅ FASE 4: Verificar si hay un refresh en progreso
166
+ */
167
+ isRefreshing(): boolean;
168
+ /**
169
+ * ✅ MEJORADO FASE 3: Configurar interceptor de respuesta NON-BLOCKING
170
+ * El interceptor NO debe hacer await, solo detectar y emitir eventos
160
171
  */
161
172
  setupResponseInterceptor(): void;
162
173
  /**
package/dist/index.d.mts CHANGED
@@ -1,12 +1,12 @@
1
1
  export * from '@nocios/crudify-browser';
2
2
  export { default as crudify } from '@nocios/crudify-browser';
3
- export { B as BoxScreenType, C as CrudifyLogin, d as CrudifyLoginConfig, e as CrudifyLoginProps, f as CrudifyLoginTranslations, L as LoginComponent, a as POLICY_ACTIONS, b as PREFERRED_POLICY_ORDER, P as Policies, c as PolicyAction, S as SessionStatus, g as UserLoginData, U as UserProfileDisplay } from './LoginComponent-saSn0o5x.mjs';
3
+ export { B as BoxScreenType, C as CrudifyLogin, a as CrudifyLoginConfig, b as CrudifyLoginProps, c as CrudifyLoginTranslations, L as LoginComponent, f as POLICY_ACTIONS, g as PREFERRED_POLICY_ORDER, P as Policies, e as PolicyAction, S as SessionStatus, d as UserLoginData, U as UserProfileDisplay } from './LoginComponent-CSTVsfeV.mjs';
4
4
  export { A as ApiError, C as CrudifyApiResponse, a as CrudifyTransactionResponse, F as ForgotPasswordRequest, J as JwtPayload, b as LoginRequest, L as LoginResponse, R as ResetPasswordRequest, T as TransactionResponseData, U as UserProfile, V as ValidateCodeRequest, c as ValidationError } from './api-Djqihi4n.mjs';
5
- import { U as UseSessionOptions, T as TokenData, L as LoginResult } from './index-CUbUeMMS.mjs';
6
- export { a as SessionConfig, S as SessionManager, d as SessionState, c as StorageType, b as TokenStorage, j as UseAuthReturn, l as UseDataReturn, g as UseUserDataOptions, f as UseUserDataReturn, h as UserData, i as useAuth, n as useCrudifyWithNotifications, k as useData, u as useSession, e as useUserData, m as useUserProfile } from './index-CUbUeMMS.mjs';
5
+ import { U as UseSessionOptions, T as TokenData, L as LoginResult } from './index-BwF68SOh.mjs';
6
+ export { a as SessionConfig, S as SessionManager, d as SessionState, c as StorageType, b as TokenStorage, j as UseAuthReturn, l as UseDataReturn, g as UseUserDataOptions, f as UseUserDataReturn, h as UserData, i as useAuth, n as useCrudifyWithNotifications, k as useData, u as useSession, e as useUserData, m as useUserProfile } from './index-BwF68SOh.mjs';
7
7
  import * as react_jsx_runtime from 'react/jsx-runtime';
8
8
  import { ReactNode } from 'react';
9
- export { E as ERROR_CODES, j as ERROR_SEVERITY_MAP, k as ErrorCode, l as ErrorSeverity, q as ErrorTranslationConfig, P as ParsedError, o as createErrorTranslator, d as decodeJwtSafely, a as getCookie, g as getCurrentUserEmail, f as getErrorMessage, h as handleCrudifyError, i as isTokenExpired, p as parseApiError, e as parseJavaScriptError, c as parseTransactionError, b as secureLocalStorage, s as secureSessionStorage, n as translateError, t as translateErrorCode, m as translateErrorCodes } from './errorTranslation-DqdgLEUy.mjs';
9
+ export { E as ERROR_CODES, j as ERROR_SEVERITY_MAP, n as ErrorCode, o as ErrorSeverity, q as ErrorTranslationConfig, P as ParsedError, m as createErrorTranslator, d as decodeJwtSafely, a as getCookie, g as getCurrentUserEmail, f as getErrorMessage, h as handleCrudifyError, i as isTokenExpired, p as parseApiError, e as parseJavaScriptError, c as parseTransactionError, b as secureLocalStorage, s as secureSessionStorage, l as translateError, t as translateErrorCode, k as translateErrorCodes } from './errorTranslation-DEn4aqs6.mjs';
10
10
  export { G as GlobalNotificationProvider, a as GlobalNotificationProviderProps, N as Notification, b as NotificationSeverity, u as useGlobalNotification } from './GlobalNotificationProvider-C3iWgM1z.mjs';
11
11
 
12
12
  type SessionData = {
@@ -65,17 +65,132 @@ declare function SessionProvider(props: SessionProviderProps): react_jsx_runtime
65
65
  */
66
66
  declare function useSessionContext(): SessionContextType;
67
67
  /**
68
- * HOC para proteger rutas que requieren autenticación
68
+ * Componente para mostrar información de la sesión (debug)
69
69
  */
70
- type ProtectedRouteProps = {
70
+ declare function SessionDebugInfo(): react_jsx_runtime.JSX.Element;
71
+
72
+ interface ProtectedRouteProps {
71
73
  children: ReactNode;
72
- fallback?: ReactNode;
73
- redirectTo?: () => void;
74
- };
75
- declare function ProtectedRoute({ children, fallback, redirectTo }: ProtectedRouteProps): react_jsx_runtime.JSX.Element | null;
74
+ /**
75
+ * Componente a mostrar mientras se valida la sesión
76
+ * @default <SessionLoadingScreen stage="validating-session" />
77
+ */
78
+ loadingComponent?: ReactNode;
79
+ /**
80
+ * Ruta a la que redirigir si no está autenticado
81
+ * @default "/login"
82
+ */
83
+ loginPath?: string;
84
+ }
76
85
  /**
77
- * Componente para mostrar información de la sesión (debug)
86
+ * Componente para proteger rutas que requieren autenticación
87
+ *
88
+ * Características:
89
+ * - Valida sesión de forma estricta (isAuthenticated + tokens válidos)
90
+ * - Guarda URL actual para redirect post-login
91
+ * - Previene open redirect attacks
92
+ * - Limpia storage corrupto automáticamente
93
+ *
94
+ * @example
95
+ * ```tsx
96
+ * <Route
97
+ * path="/dashboard"
98
+ * element={
99
+ * <ProtectedRoute>
100
+ * <Dashboard />
101
+ * </ProtectedRoute>
102
+ * }
103
+ * />
104
+ * ```
78
105
  */
79
- declare function SessionDebugInfo(): react_jsx_runtime.JSX.Element;
106
+ declare function ProtectedRoute({ children, loadingComponent, loginPath, }: ProtectedRouteProps): react_jsx_runtime.JSX.Element;
107
+
108
+ interface AuthRouteProps {
109
+ children: ReactNode;
110
+ /**
111
+ * Ruta a la que redirigir si ya está autenticado
112
+ * Si hay parámetro ?redirect= en la URL, se usará ese en su lugar
113
+ * @default "/"
114
+ */
115
+ redirectTo?: string;
116
+ }
117
+ /**
118
+ * Componente para proteger rutas de autenticación (login, register, etc.)
119
+ * Redirige a home si el usuario ya está autenticado
120
+ *
121
+ * Características:
122
+ * - Si usuario autenticado → redirige a home (o ?redirect= si existe)
123
+ * - Si no autenticado → muestra el componente (login, etc.)
124
+ * - Valida parámetro redirect para prevenir open redirect
125
+ *
126
+ * @example
127
+ * ```tsx
128
+ * <Route
129
+ * path="/login"
130
+ * element={
131
+ * <AuthRoute>
132
+ * <LoginPage />
133
+ * </AuthRoute>
134
+ * }
135
+ * />
136
+ * ```
137
+ */
138
+ declare function AuthRoute({ children, redirectTo }: AuthRouteProps): react_jsx_runtime.JSX.Element;
139
+
140
+ interface SessionLoadingScreenProps {
141
+ /**
142
+ * Stage of loading to display appropriate message
143
+ * @default "loading"
144
+ */
145
+ stage?: "initializing" | "validating-session" | "loading";
146
+ /**
147
+ * Custom message to display (overrides default stage message)
148
+ */
149
+ message?: string;
150
+ }
151
+ /**
152
+ * Loading screen component for session-related loading states
153
+ *
154
+ * Features:
155
+ * - Clean, minimal design
156
+ * - Customizable message
157
+ * - Stage-based default messages
158
+ * - No external dependencies (works without i18n)
159
+ *
160
+ * @example
161
+ * ```tsx
162
+ * // Basic usage
163
+ * <SessionLoadingScreen stage="validating-session" />
164
+ *
165
+ * // With custom message
166
+ * <SessionLoadingScreen
167
+ * stage="validating-session"
168
+ * message={t("loading.validatingSession")}
169
+ * />
170
+ * ```
171
+ */
172
+ declare function SessionLoadingScreen({ stage, message, }: SessionLoadingScreenProps): react_jsx_runtime.JSX.Element;
173
+
174
+ /**
175
+ * Utilidades de seguridad para validar redirecciones
176
+ * Previene ataques de open redirect permitiendo rutas dinámicas
177
+ */
178
+ /**
179
+ * Valida que una ruta de redirección sea segura (solo rutas internas)
180
+ * Permite rutas dinámicas pero bloquea ataques de open redirect
181
+ *
182
+ * @param path - La ruta a validar
183
+ * @param defaultPath - Ruta por defecto si la validación falla
184
+ * @returns Ruta validada y segura
185
+ */
186
+ declare const validateInternalRedirect: (path: string, defaultPath?: string) => string;
187
+ /**
188
+ * Extrae y valida parámetro redirect de URL search params
189
+ *
190
+ * @param searchParams - URLSearchParams o string de query params
191
+ * @param defaultPath - Ruta por defecto
192
+ * @returns Ruta validada
193
+ */
194
+ declare const extractSafeRedirectFromUrl: (searchParams: URLSearchParams | string, defaultPath?: string) => string;
80
195
 
81
- export { LoginResult, type NotificationOptions, ProtectedRoute, type ProtectedRouteProps, SessionDebugInfo, SessionProvider, type SessionProviderProps, TokenData, UseSessionOptions, useSessionContext };
196
+ export { AuthRoute, type AuthRouteProps, LoginResult, type NotificationOptions, ProtectedRoute, type ProtectedRouteProps, SessionDebugInfo, SessionLoadingScreen, type SessionLoadingScreenProps, SessionProvider, type SessionProviderProps, TokenData, UseSessionOptions, extractSafeRedirectFromUrl, useSessionContext, validateInternalRedirect };
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  export * from '@nocios/crudify-browser';
2
2
  export { default as crudify } from '@nocios/crudify-browser';
3
- export { B as BoxScreenType, C as CrudifyLogin, d as CrudifyLoginConfig, e as CrudifyLoginProps, f as CrudifyLoginTranslations, L as LoginComponent, a as POLICY_ACTIONS, b as PREFERRED_POLICY_ORDER, P as Policies, c as PolicyAction, S as SessionStatus, g as UserLoginData, U as UserProfileDisplay } from './LoginComponent-saSn0o5x.js';
3
+ export { B as BoxScreenType, C as CrudifyLogin, a as CrudifyLoginConfig, b as CrudifyLoginProps, c as CrudifyLoginTranslations, L as LoginComponent, f as POLICY_ACTIONS, g as PREFERRED_POLICY_ORDER, P as Policies, e as PolicyAction, S as SessionStatus, d as UserLoginData, U as UserProfileDisplay } from './LoginComponent-CSTVsfeV.js';
4
4
  export { A as ApiError, C as CrudifyApiResponse, a as CrudifyTransactionResponse, F as ForgotPasswordRequest, J as JwtPayload, b as LoginRequest, L as LoginResponse, R as ResetPasswordRequest, T as TransactionResponseData, U as UserProfile, V as ValidateCodeRequest, c as ValidationError } from './api-Djqihi4n.js';
5
- import { U as UseSessionOptions, T as TokenData, L as LoginResult } from './index-DZdMugLk.js';
6
- export { a as SessionConfig, S as SessionManager, d as SessionState, c as StorageType, b as TokenStorage, j as UseAuthReturn, l as UseDataReturn, g as UseUserDataOptions, f as UseUserDataReturn, h as UserData, i as useAuth, n as useCrudifyWithNotifications, k as useData, u as useSession, e as useUserData, m as useUserProfile } from './index-DZdMugLk.js';
5
+ import { U as UseSessionOptions, T as TokenData, L as LoginResult } from './index-Fkm9ErmY.js';
6
+ export { a as SessionConfig, S as SessionManager, d as SessionState, c as StorageType, b as TokenStorage, j as UseAuthReturn, l as UseDataReturn, g as UseUserDataOptions, f as UseUserDataReturn, h as UserData, i as useAuth, n as useCrudifyWithNotifications, k as useData, u as useSession, e as useUserData, m as useUserProfile } from './index-Fkm9ErmY.js';
7
7
  import * as react_jsx_runtime from 'react/jsx-runtime';
8
8
  import { ReactNode } from 'react';
9
- export { E as ERROR_CODES, j as ERROR_SEVERITY_MAP, k as ErrorCode, l as ErrorSeverity, q as ErrorTranslationConfig, P as ParsedError, o as createErrorTranslator, d as decodeJwtSafely, a as getCookie, g as getCurrentUserEmail, f as getErrorMessage, h as handleCrudifyError, i as isTokenExpired, p as parseApiError, e as parseJavaScriptError, c as parseTransactionError, b as secureLocalStorage, s as secureSessionStorage, n as translateError, t as translateErrorCode, m as translateErrorCodes } from './errorTranslation-CBbQYNWR.js';
9
+ export { E as ERROR_CODES, j as ERROR_SEVERITY_MAP, n as ErrorCode, o as ErrorSeverity, q as ErrorTranslationConfig, P as ParsedError, m as createErrorTranslator, d as decodeJwtSafely, a as getCookie, g as getCurrentUserEmail, f as getErrorMessage, h as handleCrudifyError, i as isTokenExpired, p as parseApiError, e as parseJavaScriptError, c as parseTransactionError, b as secureLocalStorage, s as secureSessionStorage, l as translateError, t as translateErrorCode, k as translateErrorCodes } from './errorTranslation-DdqZg8JD.js';
10
10
  export { G as GlobalNotificationProvider, a as GlobalNotificationProviderProps, N as Notification, b as NotificationSeverity, u as useGlobalNotification } from './GlobalNotificationProvider-C3iWgM1z.js';
11
11
 
12
12
  type SessionData = {
@@ -65,17 +65,132 @@ declare function SessionProvider(props: SessionProviderProps): react_jsx_runtime
65
65
  */
66
66
  declare function useSessionContext(): SessionContextType;
67
67
  /**
68
- * HOC para proteger rutas que requieren autenticación
68
+ * Componente para mostrar información de la sesión (debug)
69
69
  */
70
- type ProtectedRouteProps = {
70
+ declare function SessionDebugInfo(): react_jsx_runtime.JSX.Element;
71
+
72
+ interface ProtectedRouteProps {
71
73
  children: ReactNode;
72
- fallback?: ReactNode;
73
- redirectTo?: () => void;
74
- };
75
- declare function ProtectedRoute({ children, fallback, redirectTo }: ProtectedRouteProps): react_jsx_runtime.JSX.Element | null;
74
+ /**
75
+ * Componente a mostrar mientras se valida la sesión
76
+ * @default <SessionLoadingScreen stage="validating-session" />
77
+ */
78
+ loadingComponent?: ReactNode;
79
+ /**
80
+ * Ruta a la que redirigir si no está autenticado
81
+ * @default "/login"
82
+ */
83
+ loginPath?: string;
84
+ }
76
85
  /**
77
- * Componente para mostrar información de la sesión (debug)
86
+ * Componente para proteger rutas que requieren autenticación
87
+ *
88
+ * Características:
89
+ * - Valida sesión de forma estricta (isAuthenticated + tokens válidos)
90
+ * - Guarda URL actual para redirect post-login
91
+ * - Previene open redirect attacks
92
+ * - Limpia storage corrupto automáticamente
93
+ *
94
+ * @example
95
+ * ```tsx
96
+ * <Route
97
+ * path="/dashboard"
98
+ * element={
99
+ * <ProtectedRoute>
100
+ * <Dashboard />
101
+ * </ProtectedRoute>
102
+ * }
103
+ * />
104
+ * ```
78
105
  */
79
- declare function SessionDebugInfo(): react_jsx_runtime.JSX.Element;
106
+ declare function ProtectedRoute({ children, loadingComponent, loginPath, }: ProtectedRouteProps): react_jsx_runtime.JSX.Element;
107
+
108
+ interface AuthRouteProps {
109
+ children: ReactNode;
110
+ /**
111
+ * Ruta a la que redirigir si ya está autenticado
112
+ * Si hay parámetro ?redirect= en la URL, se usará ese en su lugar
113
+ * @default "/"
114
+ */
115
+ redirectTo?: string;
116
+ }
117
+ /**
118
+ * Componente para proteger rutas de autenticación (login, register, etc.)
119
+ * Redirige a home si el usuario ya está autenticado
120
+ *
121
+ * Características:
122
+ * - Si usuario autenticado → redirige a home (o ?redirect= si existe)
123
+ * - Si no autenticado → muestra el componente (login, etc.)
124
+ * - Valida parámetro redirect para prevenir open redirect
125
+ *
126
+ * @example
127
+ * ```tsx
128
+ * <Route
129
+ * path="/login"
130
+ * element={
131
+ * <AuthRoute>
132
+ * <LoginPage />
133
+ * </AuthRoute>
134
+ * }
135
+ * />
136
+ * ```
137
+ */
138
+ declare function AuthRoute({ children, redirectTo }: AuthRouteProps): react_jsx_runtime.JSX.Element;
139
+
140
+ interface SessionLoadingScreenProps {
141
+ /**
142
+ * Stage of loading to display appropriate message
143
+ * @default "loading"
144
+ */
145
+ stage?: "initializing" | "validating-session" | "loading";
146
+ /**
147
+ * Custom message to display (overrides default stage message)
148
+ */
149
+ message?: string;
150
+ }
151
+ /**
152
+ * Loading screen component for session-related loading states
153
+ *
154
+ * Features:
155
+ * - Clean, minimal design
156
+ * - Customizable message
157
+ * - Stage-based default messages
158
+ * - No external dependencies (works without i18n)
159
+ *
160
+ * @example
161
+ * ```tsx
162
+ * // Basic usage
163
+ * <SessionLoadingScreen stage="validating-session" />
164
+ *
165
+ * // With custom message
166
+ * <SessionLoadingScreen
167
+ * stage="validating-session"
168
+ * message={t("loading.validatingSession")}
169
+ * />
170
+ * ```
171
+ */
172
+ declare function SessionLoadingScreen({ stage, message, }: SessionLoadingScreenProps): react_jsx_runtime.JSX.Element;
173
+
174
+ /**
175
+ * Utilidades de seguridad para validar redirecciones
176
+ * Previene ataques de open redirect permitiendo rutas dinámicas
177
+ */
178
+ /**
179
+ * Valida que una ruta de redirección sea segura (solo rutas internas)
180
+ * Permite rutas dinámicas pero bloquea ataques de open redirect
181
+ *
182
+ * @param path - La ruta a validar
183
+ * @param defaultPath - Ruta por defecto si la validación falla
184
+ * @returns Ruta validada y segura
185
+ */
186
+ declare const validateInternalRedirect: (path: string, defaultPath?: string) => string;
187
+ /**
188
+ * Extrae y valida parámetro redirect de URL search params
189
+ *
190
+ * @param searchParams - URLSearchParams o string de query params
191
+ * @param defaultPath - Ruta por defecto
192
+ * @returns Ruta validada
193
+ */
194
+ declare const extractSafeRedirectFromUrl: (searchParams: URLSearchParams | string, defaultPath?: string) => string;
80
195
 
81
- export { LoginResult, type NotificationOptions, ProtectedRoute, type ProtectedRouteProps, SessionDebugInfo, SessionProvider, type SessionProviderProps, TokenData, UseSessionOptions, useSessionContext };
196
+ export { AuthRoute, type AuthRouteProps, LoginResult, type NotificationOptions, ProtectedRoute, type ProtectedRouteProps, SessionDebugInfo, SessionLoadingScreen, type SessionLoadingScreenProps, SessionProvider, type SessionProviderProps, TokenData, UseSessionOptions, extractSafeRedirectFromUrl, useSessionContext, validateInternalRedirect };
package/dist/index.js CHANGED
@@ -1 +1,6 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _createStarExport(obj) { Object.keys(obj) .filter((key) => key !== "default" && key !== "__esModule") .forEach((key) => { if (exports.hasOwnProperty(key)) { return; } Object.defineProperty(exports, key, {enumerable: true, configurable: true, get: () => obj[key]}); }); }var _chunkWG3ZXCPFjs = require('./chunk-WG3ZXCPF.js');var _chunkLP5NJV2Pjs = require('./chunk-LP5NJV2P.js');var _chunkRHG74IMWjs = require('./chunk-RHG74IMW.js');var _chunkNNY4A73Vjs = require('./chunk-NNY4A73V.js');var _chunkYIIUEOXCjs = require('./chunk-YIIUEOXC.js');var _chunkATAGEVFKjs = require('./chunk-ATAGEVFK.js');var _crudifybrowser = require('@nocios/crudify-browser'); var _crudifybrowser2 = _interopRequireDefault(_crudifybrowser); _createStarExport(_crudifybrowser);exports.CrudifyLogin = _chunkWG3ZXCPFjs.a; exports.ERROR_CODES = _chunkYIIUEOXCjs.a; exports.ERROR_SEVERITY_MAP = _chunkYIIUEOXCjs.b; exports.GlobalNotificationProvider = _chunkRHG74IMWjs.d; exports.LoginComponent = _chunkWG3ZXCPFjs.f; exports.POLICY_ACTIONS = _chunkWG3ZXCPFjs.c; exports.PREFERRED_POLICY_ORDER = _chunkWG3ZXCPFjs.d; exports.Policies = _chunkWG3ZXCPFjs.e; exports.ProtectedRoute = _chunkRHG74IMWjs.h; exports.SessionDebugInfo = _chunkRHG74IMWjs.i; exports.SessionManager = _chunkRHG74IMWjs.b; exports.SessionProvider = _chunkRHG74IMWjs.f; exports.SessionStatus = _chunkWG3ZXCPFjs.g; exports.TokenStorage = _chunkRHG74IMWjs.a; exports.UserProfileDisplay = _chunkWG3ZXCPFjs.b; exports.createErrorTranslator = _chunkATAGEVFKjs.e; exports.crudify = _crudifybrowser2.default; exports.decodeJwtSafely = _chunkATAGEVFKjs.g; exports.getCookie = _chunkATAGEVFKjs.a; exports.getCurrentUserEmail = _chunkATAGEVFKjs.h; exports.getErrorMessage = _chunkYIIUEOXCjs.e; exports.handleCrudifyError = _chunkYIIUEOXCjs.g; exports.isTokenExpired = _chunkATAGEVFKjs.i; exports.parseApiError = _chunkYIIUEOXCjs.c; exports.parseJavaScriptError = _chunkYIIUEOXCjs.f; exports.parseTransactionError = _chunkYIIUEOXCjs.d; exports.secureLocalStorage = _chunkNNY4A73Vjs.b; exports.secureSessionStorage = _chunkNNY4A73Vjs.a; exports.translateError = _chunkATAGEVFKjs.d; exports.translateErrorCode = _chunkATAGEVFKjs.b; exports.translateErrorCodes = _chunkATAGEVFKjs.c; exports.useAuth = _chunkLP5NJV2Pjs.b; exports.useCrudifyWithNotifications = _chunkLP5NJV2Pjs.d; exports.useData = _chunkLP5NJV2Pjs.c; exports.useGlobalNotification = _chunkRHG74IMWjs.e; exports.useSession = _chunkRHG74IMWjs.c; exports.useSessionContext = _chunkRHG74IMWjs.g; exports.useUserData = _chunkLP5NJV2Pjs.a; exports.useUserProfile = _chunkRHG74IMWjs.j;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _createStarExport(obj) { Object.keys(obj) .filter((key) => key !== "default" && key !== "__esModule") .forEach((key) => { if (exports.hasOwnProperty(key)) { return; } Object.defineProperty(exports, key, {enumerable: true, configurable: true, get: () => obj[key]}); }); } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _chunkGFZGBKFGjs = require('./chunk-GFZGBKFG.js');var _chunkX3HSMDZ7js = require('./chunk-X3HSMDZ7.js');var _chunkTLGRXZCSjs = require('./chunk-TLGRXZCS.js');var _chunkNNY4A73Vjs = require('./chunk-NNY4A73V.js');var _chunkYIIUEOXCjs = require('./chunk-YIIUEOXC.js');var _chunkAT74WV5Wjs = require('./chunk-AT74WV5W.js');var _crudifybrowser = require('@nocios/crudify-browser'); var _crudifybrowser2 = _interopRequireDefault(_crudifybrowser); _createStarExport(_crudifybrowser);var _reactrouterdom = require('react-router-dom');var _jsxruntime = require('react/jsx-runtime');var ne={border:"5px solid rgba(0, 0, 0, 0.1)",borderTopColor:"#3B82F6",borderRadius:"50%",width:"50px",height:"50px",animation:"spin 1s linear infinite"},ae=()=>_jsxruntime.jsx.call(void 0, "style",{children:`
2
+ @keyframes spin {
3
+ 0% { transform: rotate(0deg); }
4
+ 100% { transform: rotate(360deg); }
5
+ }
6
+ `});function d({stage:e="loading",message:o}){let t=o||{initializing:"Initializing application...","validating-session":"Validating session...",loading:"Loading..."}[e];return _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment,{children:[_jsxruntime.jsx.call(void 0, ae,{}),_jsxruntime.jsxs.call(void 0, "div",{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",height:"100vh",width:"100vw",backgroundColor:"#f0f2f5",fontFamily:'"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',color:"#333",textAlign:"center",boxSizing:"border-box",padding:"20px",background:"#fff"},children:[_jsxruntime.jsx.call(void 0, "div",{style:ne}),_jsxruntime.jsx.call(void 0, "p",{style:{fontSize:"1.25em",fontWeight:"500",marginTop:"24px",color:"#1f2937"},children:t})]})]})}var pe=/^[a-zA-Z0-9\-_./\?=&%#]+$/,fe=[/^https?:\/\//i,/^ftp:\/\//i,/^\/\//,/javascript:/i,/data:/i,/vbscript:/i,/about:/i,/\.\.\//,/\.\.\\/,/%2e%2e%2f/i,/%2e%2e%5c/i,/%2f%2f/i,/%5c%5c/i,/[\x00-\x1f\x7f-\x9f]/,/\\/],p= exports.validateInternalRedirect =(e,o="/")=>{if(!e||typeof e!="string")return o;let r=e.trim();if(!r)return o;if(!r.startsWith("/"))return console.warn("\u{1F6A8} Open redirect blocked (relative path):",e),o;if(!pe.test(r))return console.warn("\u{1F6A8} Open redirect blocked (invalid characters):",e),o;let t=r.toLowerCase();for(let i of fe)if(i.test(t))return console.warn("\u{1F6A8} Open redirect blocked (dangerous pattern):",e),o;let s=r.split("?")[0].split("/").filter(Boolean);if(s.length===0)return r;for(let i of s)if(i===".."||i.includes(":")||i.length>100)return console.warn("\u{1F6A8} Open redirect blocked (suspicious path part):",i),o;return r},l= exports.extractSafeRedirectFromUrl =(e,o="/")=>{try{let t=(typeof e=="string"?new URLSearchParams(e):e).get("redirect");if(!t)return o;let s=decodeURIComponent(t);return p(s,o)}catch(r){return console.warn("\u{1F6A8} Error parsing redirect parameter:",r),o}};function x({children:e,loadingComponent:o,loginPath:r="/login"}){let{isAuthenticated:t,isLoading:s,isInitialized:i,tokens:n,error:y}=_chunkTLGRXZCSjs.g.call(void 0, ),u=_reactrouterdom.useLocation.call(void 0, );if(!i||s)return _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment,{children:o||_jsxruntime.jsx.call(void 0, d,{stage:"validating-session"})});let P=t&&_optionalChain([n, 'optionalAccess', _2 => _2.accessToken])&&n.accessToken.length>0;if(y||!t||!P){n&&(!n.accessToken||n.accessToken.length===0)&&localStorage.removeItem("crudify_tokens");let h=u.pathname+u.search,C=p(h),L=encodeURIComponent(C);return _jsxruntime.jsx.call(void 0, _reactrouterdom.Navigate,{to:`${r}?redirect=${L}`,replace:!0})}return _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment,{children:e})}function S({children:e,redirectTo:o="/"}){let{isAuthenticated:r}=_chunkTLGRXZCSjs.g.call(void 0, ),t=_reactrouterdom.useLocation.call(void 0, );if(r){let s=new URLSearchParams(t.search),i=l(s,o);return _jsxruntime.jsx.call(void 0, _reactrouterdom.Navigate,{to:i,replace:!0})}return _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment,{children:e})}exports.AuthRoute = S; exports.CrudifyLogin = _chunkGFZGBKFGjs.a; exports.ERROR_CODES = _chunkYIIUEOXCjs.a; exports.ERROR_SEVERITY_MAP = _chunkYIIUEOXCjs.b; exports.GlobalNotificationProvider = _chunkTLGRXZCSjs.d; exports.LoginComponent = _chunkGFZGBKFGjs.f; exports.POLICY_ACTIONS = _chunkGFZGBKFGjs.c; exports.PREFERRED_POLICY_ORDER = _chunkGFZGBKFGjs.d; exports.Policies = _chunkGFZGBKFGjs.e; exports.ProtectedRoute = x; exports.SessionDebugInfo = _chunkTLGRXZCSjs.h; exports.SessionLoadingScreen = d; exports.SessionManager = _chunkTLGRXZCSjs.b; exports.SessionProvider = _chunkTLGRXZCSjs.f; exports.SessionStatus = _chunkGFZGBKFGjs.g; exports.TokenStorage = _chunkTLGRXZCSjs.a; exports.UserProfileDisplay = _chunkGFZGBKFGjs.b; exports.createErrorTranslator = _chunkAT74WV5Wjs.e; exports.crudify = _crudifybrowser2.default; exports.decodeJwtSafely = _chunkAT74WV5Wjs.h; exports.extractSafeRedirectFromUrl = l; exports.getCookie = _chunkAT74WV5Wjs.a; exports.getCurrentUserEmail = _chunkAT74WV5Wjs.i; exports.getErrorMessage = _chunkYIIUEOXCjs.e; exports.handleCrudifyError = _chunkYIIUEOXCjs.g; exports.isTokenExpired = _chunkAT74WV5Wjs.j; exports.parseApiError = _chunkYIIUEOXCjs.c; exports.parseJavaScriptError = _chunkYIIUEOXCjs.f; exports.parseTransactionError = _chunkYIIUEOXCjs.d; exports.secureLocalStorage = _chunkNNY4A73Vjs.b; exports.secureSessionStorage = _chunkNNY4A73Vjs.a; exports.translateError = _chunkAT74WV5Wjs.d; exports.translateErrorCode = _chunkAT74WV5Wjs.b; exports.translateErrorCodes = _chunkAT74WV5Wjs.c; exports.useAuth = _chunkX3HSMDZ7js.b; exports.useCrudifyWithNotifications = _chunkX3HSMDZ7js.d; exports.useData = _chunkX3HSMDZ7js.c; exports.useGlobalNotification = _chunkTLGRXZCSjs.e; exports.useSession = _chunkTLGRXZCSjs.c; exports.useSessionContext = _chunkTLGRXZCSjs.g; exports.useUserData = _chunkX3HSMDZ7js.a; exports.useUserProfile = _chunkTLGRXZCSjs.i; exports.validateInternalRedirect = p;
package/dist/index.mjs CHANGED
@@ -1 +1,6 @@
1
- import{a as U,b as L,c as v,d as O,e as h,f as k,g as A}from"./chunk-JYDCSNNQ.mjs";import{a as N,b,c as _,d as w}from"./chunk-Y72XFXMI.mjs";import{a as r,b as a,c as n,d as m,e as l,f as x,g as d,h as y,i as c,j as T}from"./chunk-MMYGRMGB.mjs";import{a as I,b as q}from"./chunk-T2CPA46I.mjs";import{a as S,b as P,c as R,d as g,e as E,f as C,g as D}from"./chunk-BJ6PIVZR.mjs";import{a as o,b as e,c as t,d as s,e as i,g as p,h as f,i as u}from"./chunk-HMJY3MMZ.mjs";import{default as J}from"@nocios/crudify-browser";export*from"@nocios/crudify-browser";export{U as CrudifyLogin,S as ERROR_CODES,P as ERROR_SEVERITY_MAP,m as GlobalNotificationProvider,k as LoginComponent,v as POLICY_ACTIONS,O as PREFERRED_POLICY_ORDER,h as Policies,y as ProtectedRoute,c as SessionDebugInfo,a as SessionManager,x as SessionProvider,A as SessionStatus,r as TokenStorage,L as UserProfileDisplay,i as createErrorTranslator,J as crudify,p as decodeJwtSafely,o as getCookie,f as getCurrentUserEmail,E as getErrorMessage,D as handleCrudifyError,u as isTokenExpired,R as parseApiError,C as parseJavaScriptError,g as parseTransactionError,q as secureLocalStorage,I as secureSessionStorage,s as translateError,e as translateErrorCode,t as translateErrorCodes,b as useAuth,w as useCrudifyWithNotifications,_ as useData,l as useGlobalNotification,n as useSession,d as useSessionContext,N as useUserData,T as useUserProfile};
1
+ import{a as J,b as $,c as K,d as Z,e as Q,f as X,g as j}from"./chunk-GLR5HDJC.mjs";import{a as ee,b as oe,c as re,d as se}from"./chunk-KNEHDX2M.mjs";import{a as E,b as k,c as D,d as I,e as _,f as z,g as a,h as F,i as Y}from"./chunk-CTDQEJAU.mjs";import{a as te,b as ie}from"./chunk-T2CPA46I.mjs";import{a as M,b as G,c as V,d as q,e as H,f as W,g as B}from"./chunk-BJ6PIVZR.mjs";import{a as v,b as A,c as U,d as T,e as b,h as N,i as w,j as O}from"./chunk-5JKS55SE.mjs";import{default as Ie}from"@nocios/crudify-browser";export*from"@nocios/crudify-browser";import{Navigate as de,useLocation as le}from"react-router-dom";import{Fragment as ce,jsx as c,jsxs as m}from"react/jsx-runtime";var ne={border:"5px solid rgba(0, 0, 0, 0.1)",borderTopColor:"#3B82F6",borderRadius:"50%",width:"50px",height:"50px",animation:"spin 1s linear infinite"},ae=()=>c("style",{children:`
2
+ @keyframes spin {
3
+ 0% { transform: rotate(0deg); }
4
+ 100% { transform: rotate(360deg); }
5
+ }
6
+ `});function d({stage:e="loading",message:o}){let t=o||{initializing:"Initializing application...","validating-session":"Validating session...",loading:"Loading..."}[e];return m(ce,{children:[c(ae,{}),m("div",{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",height:"100vh",width:"100vw",backgroundColor:"#f0f2f5",fontFamily:'"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',color:"#333",textAlign:"center",boxSizing:"border-box",padding:"20px",background:"#fff"},children:[c("div",{style:ne}),c("p",{style:{fontSize:"1.25em",fontWeight:"500",marginTop:"24px",color:"#1f2937"},children:t})]})]})}var pe=/^[a-zA-Z0-9\-_./\?=&%#]+$/,fe=[/^https?:\/\//i,/^ftp:\/\//i,/^\/\//,/javascript:/i,/data:/i,/vbscript:/i,/about:/i,/\.\.\//,/\.\.\\/,/%2e%2e%2f/i,/%2e%2e%5c/i,/%2f%2f/i,/%5c%5c/i,/[\x00-\x1f\x7f-\x9f]/,/\\/],p=(e,o="/")=>{if(!e||typeof e!="string")return o;let r=e.trim();if(!r)return o;if(!r.startsWith("/"))return console.warn("\u{1F6A8} Open redirect blocked (relative path):",e),o;if(!pe.test(r))return console.warn("\u{1F6A8} Open redirect blocked (invalid characters):",e),o;let t=r.toLowerCase();for(let i of fe)if(i.test(t))return console.warn("\u{1F6A8} Open redirect blocked (dangerous pattern):",e),o;let s=r.split("?")[0].split("/").filter(Boolean);if(s.length===0)return r;for(let i of s)if(i===".."||i.includes(":")||i.length>100)return console.warn("\u{1F6A8} Open redirect blocked (suspicious path part):",i),o;return r},l=(e,o="/")=>{try{let t=(typeof e=="string"?new URLSearchParams(e):e).get("redirect");if(!t)return o;let s=decodeURIComponent(t);return p(s,o)}catch(r){return console.warn("\u{1F6A8} Error parsing redirect parameter:",r),o}};import{Fragment as g,jsx as f}from"react/jsx-runtime";function x({children:e,loadingComponent:o,loginPath:r="/login"}){let{isAuthenticated:t,isLoading:s,isInitialized:i,tokens:n,error:y}=a(),u=le();if(!i||s)return f(g,{children:o||f(d,{stage:"validating-session"})});let P=t&&n?.accessToken&&n.accessToken.length>0;if(y||!t||!P){n&&(!n.accessToken||n.accessToken.length===0)&&localStorage.removeItem("crudify_tokens");let h=u.pathname+u.search,C=p(h),L=encodeURIComponent(C);return f(de,{to:`${r}?redirect=${L}`,replace:!0})}return f(g,{children:e})}import{Navigate as ue,useLocation as me}from"react-router-dom";import{Fragment as ge,jsx as R}from"react/jsx-runtime";function S({children:e,redirectTo:o="/"}){let{isAuthenticated:r}=a(),t=me();if(r){let s=new URLSearchParams(t.search),i=l(s,o);return R(ue,{to:i,replace:!0})}return R(ge,{children:e})}export{S as AuthRoute,J as CrudifyLogin,M as ERROR_CODES,G as ERROR_SEVERITY_MAP,I as GlobalNotificationProvider,X as LoginComponent,K as POLICY_ACTIONS,Z as PREFERRED_POLICY_ORDER,Q as Policies,x as ProtectedRoute,F as SessionDebugInfo,d as SessionLoadingScreen,k as SessionManager,z as SessionProvider,j as SessionStatus,E as TokenStorage,$ as UserProfileDisplay,b as createErrorTranslator,Ie as crudify,N as decodeJwtSafely,l as extractSafeRedirectFromUrl,v as getCookie,w as getCurrentUserEmail,H as getErrorMessage,B as handleCrudifyError,O as isTokenExpired,V as parseApiError,W as parseJavaScriptError,q as parseTransactionError,ie as secureLocalStorage,te as secureSessionStorage,T as translateError,A as translateErrorCode,U as translateErrorCodes,oe as useAuth,se as useCrudifyWithNotifications,re as useData,_ as useGlobalNotification,D as useSession,a as useSessionContext,ee as useUserData,Y as useUserProfile,p as validateInternalRedirect};
package/dist/utils.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- export { E as ERROR_CODES, j as ERROR_SEVERITY_MAP, k as ErrorCode, l as ErrorSeverity, q as ErrorTranslationConfig, P as ParsedError, o as createErrorTranslator, d as decodeJwtSafely, a as getCookie, g as getCurrentUserEmail, f as getErrorMessage, h as handleCrudifyError, i as isTokenExpired, p as parseApiError, e as parseJavaScriptError, c as parseTransactionError, b as secureLocalStorage, s as secureSessionStorage, n as translateError, t as translateErrorCode, m as translateErrorCodes } from './errorTranslation-DqdgLEUy.mjs';
1
+ export { E as ERROR_CODES, j as ERROR_SEVERITY_MAP, n as ErrorCode, o as ErrorSeverity, q as ErrorTranslationConfig, P as ParsedError, m as createErrorTranslator, d as decodeJwtSafely, a as getCookie, g as getCurrentUserEmail, f as getErrorMessage, h as handleCrudifyError, i as isTokenExpired, p as parseApiError, e as parseJavaScriptError, c as parseTransactionError, b as secureLocalStorage, s as secureSessionStorage, l as translateError, t as translateErrorCode, k as translateErrorCodes } from './errorTranslation-DEn4aqs6.mjs';
2
2
  import './api-Djqihi4n.mjs';
3
3
 
4
4
  /**
@@ -10,7 +10,7 @@ import './api-Djqihi4n.mjs';
10
10
  * - Suscribirse para recibir notificaciones de eventos
11
11
  * - Debounce automático para evitar múltiples disparos
12
12
  */
13
- type AuthEventType = "SESSION_EXPIRED" | "TOKEN_REFRESH_FAILED" | "UNAUTHORIZED";
13
+ type AuthEventType = "SESSION_EXPIRED" | "TOKEN_REFRESH_FAILED" | "UNAUTHORIZED" | "TOKEN_EXPIRED";
14
14
  type AuthEventDetails = {
15
15
  message?: string;
16
16
  error?: any;
@@ -52,4 +52,78 @@ declare class AuthEventBus {
52
52
  }
53
53
  declare const authEventBus: AuthEventBus;
54
54
 
55
- export { type AuthEvent, type AuthEventDetails, type AuthEventType, authEventBus };
55
+ /**
56
+ * Sistema global de tracking de navegación para evitar monkey-patching anidado
57
+ * Usa patrón singleton con reference counting
58
+ *
59
+ * Problema que resuelve:
60
+ * - Si múltiples componentes usan useSession, cada uno crearía su propio monkey-patch
61
+ * - Esto causa anidamiento infinito de patches
62
+ * - NavigationTracker centraliza el patching con reference counting
63
+ *
64
+ * Uso:
65
+ * ```typescript
66
+ * const tracker = NavigationTracker.getInstance();
67
+ * const unsubscribe = tracker.subscribe(() => {
68
+ * console.log("Navigation detected!");
69
+ * });
70
+ *
71
+ * // Cleanup
72
+ * unsubscribe();
73
+ * ```
74
+ */
75
+ type NavigationCallback = () => void;
76
+ declare class NavigationTracker {
77
+ private static instance;
78
+ private isPatched;
79
+ private refCount;
80
+ private listeners;
81
+ private originalPushState;
82
+ private originalReplaceState;
83
+ private constructor();
84
+ /**
85
+ * Obtener instancia singleton
86
+ */
87
+ static getInstance(): NavigationTracker;
88
+ /**
89
+ * Suscribirse a eventos de navegación
90
+ * @param callback - Función a llamar cuando hay navegación
91
+ * @returns Función de cleanup para desuscribirse
92
+ */
93
+ subscribe(callback: NavigationCallback): () => void;
94
+ /**
95
+ * Desuscribirse de eventos de navegación
96
+ * @private
97
+ */
98
+ private unsubscribe;
99
+ /**
100
+ * Aplicar monkey-patches a history API
101
+ * @private
102
+ */
103
+ private applyPatches;
104
+ /**
105
+ * Remover monkey-patches y restaurar métodos originales
106
+ * @private
107
+ */
108
+ private removePatches;
109
+ /**
110
+ * Notificar a todos los listeners
111
+ * @private
112
+ */
113
+ private notifyListeners;
114
+ /**
115
+ * Para testing: limpiar completamente el tracker
116
+ * ⚠️ SOLO USAR EN TESTS
117
+ */
118
+ static reset(): void;
119
+ /**
120
+ * Obtener número de suscriptores activos (útil para debugging)
121
+ */
122
+ getSubscriberCount(): number;
123
+ /**
124
+ * Verificar si los patches están activos
125
+ */
126
+ isActive(): boolean;
127
+ }
128
+
129
+ export { type AuthEvent, type AuthEventDetails, type AuthEventType, NavigationTracker, authEventBus };
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { E as ERROR_CODES, j as ERROR_SEVERITY_MAP, k as ErrorCode, l as ErrorSeverity, q as ErrorTranslationConfig, P as ParsedError, o as createErrorTranslator, d as decodeJwtSafely, a as getCookie, g as getCurrentUserEmail, f as getErrorMessage, h as handleCrudifyError, i as isTokenExpired, p as parseApiError, e as parseJavaScriptError, c as parseTransactionError, b as secureLocalStorage, s as secureSessionStorage, n as translateError, t as translateErrorCode, m as translateErrorCodes } from './errorTranslation-CBbQYNWR.js';
1
+ export { E as ERROR_CODES, j as ERROR_SEVERITY_MAP, n as ErrorCode, o as ErrorSeverity, q as ErrorTranslationConfig, P as ParsedError, m as createErrorTranslator, d as decodeJwtSafely, a as getCookie, g as getCurrentUserEmail, f as getErrorMessage, h as handleCrudifyError, i as isTokenExpired, p as parseApiError, e as parseJavaScriptError, c as parseTransactionError, b as secureLocalStorage, s as secureSessionStorage, l as translateError, t as translateErrorCode, k as translateErrorCodes } from './errorTranslation-DdqZg8JD.js';
2
2
  import './api-Djqihi4n.js';
3
3
 
4
4
  /**
@@ -10,7 +10,7 @@ import './api-Djqihi4n.js';
10
10
  * - Suscribirse para recibir notificaciones de eventos
11
11
  * - Debounce automático para evitar múltiples disparos
12
12
  */
13
- type AuthEventType = "SESSION_EXPIRED" | "TOKEN_REFRESH_FAILED" | "UNAUTHORIZED";
13
+ type AuthEventType = "SESSION_EXPIRED" | "TOKEN_REFRESH_FAILED" | "UNAUTHORIZED" | "TOKEN_EXPIRED";
14
14
  type AuthEventDetails = {
15
15
  message?: string;
16
16
  error?: any;
@@ -52,4 +52,78 @@ declare class AuthEventBus {
52
52
  }
53
53
  declare const authEventBus: AuthEventBus;
54
54
 
55
- export { type AuthEvent, type AuthEventDetails, type AuthEventType, authEventBus };
55
+ /**
56
+ * Sistema global de tracking de navegación para evitar monkey-patching anidado
57
+ * Usa patrón singleton con reference counting
58
+ *
59
+ * Problema que resuelve:
60
+ * - Si múltiples componentes usan useSession, cada uno crearía su propio monkey-patch
61
+ * - Esto causa anidamiento infinito de patches
62
+ * - NavigationTracker centraliza el patching con reference counting
63
+ *
64
+ * Uso:
65
+ * ```typescript
66
+ * const tracker = NavigationTracker.getInstance();
67
+ * const unsubscribe = tracker.subscribe(() => {
68
+ * console.log("Navigation detected!");
69
+ * });
70
+ *
71
+ * // Cleanup
72
+ * unsubscribe();
73
+ * ```
74
+ */
75
+ type NavigationCallback = () => void;
76
+ declare class NavigationTracker {
77
+ private static instance;
78
+ private isPatched;
79
+ private refCount;
80
+ private listeners;
81
+ private originalPushState;
82
+ private originalReplaceState;
83
+ private constructor();
84
+ /**
85
+ * Obtener instancia singleton
86
+ */
87
+ static getInstance(): NavigationTracker;
88
+ /**
89
+ * Suscribirse a eventos de navegación
90
+ * @param callback - Función a llamar cuando hay navegación
91
+ * @returns Función de cleanup para desuscribirse
92
+ */
93
+ subscribe(callback: NavigationCallback): () => void;
94
+ /**
95
+ * Desuscribirse de eventos de navegación
96
+ * @private
97
+ */
98
+ private unsubscribe;
99
+ /**
100
+ * Aplicar monkey-patches a history API
101
+ * @private
102
+ */
103
+ private applyPatches;
104
+ /**
105
+ * Remover monkey-patches y restaurar métodos originales
106
+ * @private
107
+ */
108
+ private removePatches;
109
+ /**
110
+ * Notificar a todos los listeners
111
+ * @private
112
+ */
113
+ private notifyListeners;
114
+ /**
115
+ * Para testing: limpiar completamente el tracker
116
+ * ⚠️ SOLO USAR EN TESTS
117
+ */
118
+ static reset(): void;
119
+ /**
120
+ * Obtener número de suscriptores activos (útil para debugging)
121
+ */
122
+ getSubscriberCount(): number;
123
+ /**
124
+ * Verificar si los patches están activos
125
+ */
126
+ isActive(): boolean;
127
+ }
128
+
129
+ export { type AuthEvent, type AuthEventDetails, type AuthEventType, NavigationTracker, authEventBus };
package/dist/utils.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkNNY4A73Vjs = require('./chunk-NNY4A73V.js');var _chunkYIIUEOXCjs = require('./chunk-YIIUEOXC.js');var _chunkATAGEVFKjs = require('./chunk-ATAGEVFK.js');exports.ERROR_CODES = _chunkYIIUEOXCjs.a; exports.ERROR_SEVERITY_MAP = _chunkYIIUEOXCjs.b; exports.authEventBus = _chunkATAGEVFKjs.f; exports.createErrorTranslator = _chunkATAGEVFKjs.e; exports.decodeJwtSafely = _chunkATAGEVFKjs.g; exports.getCookie = _chunkATAGEVFKjs.a; exports.getCurrentUserEmail = _chunkATAGEVFKjs.h; exports.getErrorMessage = _chunkYIIUEOXCjs.e; exports.handleCrudifyError = _chunkYIIUEOXCjs.g; exports.isTokenExpired = _chunkATAGEVFKjs.i; exports.parseApiError = _chunkYIIUEOXCjs.c; exports.parseJavaScriptError = _chunkYIIUEOXCjs.f; exports.parseTransactionError = _chunkYIIUEOXCjs.d; exports.secureLocalStorage = _chunkNNY4A73Vjs.b; exports.secureSessionStorage = _chunkNNY4A73Vjs.a; exports.translateError = _chunkATAGEVFKjs.d; exports.translateErrorCode = _chunkATAGEVFKjs.b; exports.translateErrorCodes = _chunkATAGEVFKjs.c;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var _chunkNNY4A73Vjs = require('./chunk-NNY4A73V.js');var _chunkYIIUEOXCjs = require('./chunk-YIIUEOXC.js');var _chunkAT74WV5Wjs = require('./chunk-AT74WV5W.js');exports.ERROR_CODES = _chunkYIIUEOXCjs.a; exports.ERROR_SEVERITY_MAP = _chunkYIIUEOXCjs.b; exports.NavigationTracker = _chunkAT74WV5Wjs.g; exports.authEventBus = _chunkAT74WV5Wjs.f; exports.createErrorTranslator = _chunkAT74WV5Wjs.e; exports.decodeJwtSafely = _chunkAT74WV5Wjs.h; exports.getCookie = _chunkAT74WV5Wjs.a; exports.getCurrentUserEmail = _chunkAT74WV5Wjs.i; exports.getErrorMessage = _chunkYIIUEOXCjs.e; exports.handleCrudifyError = _chunkYIIUEOXCjs.g; exports.isTokenExpired = _chunkAT74WV5Wjs.j; exports.parseApiError = _chunkYIIUEOXCjs.c; exports.parseJavaScriptError = _chunkYIIUEOXCjs.f; exports.parseTransactionError = _chunkYIIUEOXCjs.d; exports.secureLocalStorage = _chunkNNY4A73Vjs.b; exports.secureSessionStorage = _chunkNNY4A73Vjs.a; exports.translateError = _chunkAT74WV5Wjs.d; exports.translateErrorCode = _chunkAT74WV5Wjs.b; exports.translateErrorCodes = _chunkAT74WV5Wjs.c;
package/dist/utils.mjs CHANGED
@@ -1 +1 @@
1
- import{a as C,b as S}from"./chunk-T2CPA46I.mjs";import{a as i,b as f,c as l,d as u,e as d,f as m,g as x}from"./chunk-BJ6PIVZR.mjs";import{a as r,b as e,c as o,d as t,e as a,f as E,g as s,h as n,i as p}from"./chunk-HMJY3MMZ.mjs";export{i as ERROR_CODES,f as ERROR_SEVERITY_MAP,E as authEventBus,a as createErrorTranslator,s as decodeJwtSafely,r as getCookie,n as getCurrentUserEmail,d as getErrorMessage,x as handleCrudifyError,p as isTokenExpired,l as parseApiError,m as parseJavaScriptError,u as parseTransactionError,S as secureLocalStorage,C as secureSessionStorage,t as translateError,e as translateErrorCode,o as translateErrorCodes};
1
+ import{a as g,b as v}from"./chunk-T2CPA46I.mjs";import{a as f,b as l,c as m,d as u,e as x,f as d,g as c}from"./chunk-BJ6PIVZR.mjs";import{a as r,b as e,c as o,d as t,e as a,f as E,g as s,h as n,i as p,j as i}from"./chunk-5JKS55SE.mjs";export{f as ERROR_CODES,l as ERROR_SEVERITY_MAP,s as NavigationTracker,E as authEventBus,a as createErrorTranslator,n as decodeJwtSafely,r as getCookie,p as getCurrentUserEmail,x as getErrorMessage,c as handleCrudifyError,i as isTokenExpired,m as parseApiError,d as parseJavaScriptError,u as parseTransactionError,v as secureLocalStorage,g as secureSessionStorage,t as translateError,e as translateErrorCode,o as translateErrorCodes};