@nocios/crudify-components 1.0.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.
- package/.github/workflows/test.yml +59 -0
- package/.nvmrc +1 -0
- package/README.md +398 -0
- package/README_DEPTH.md +1230 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/coverage-final.json +85 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +506 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/CrudiaMarkdownField-C54-A_J3.d.mts +328 -0
- package/dist/CrudiaMarkdownField-C8HQh7s5.d.ts +328 -0
- package/dist/GlobalNotificationProvider-Zq18OkpI.d.mts +96 -0
- package/dist/GlobalNotificationProvider-Zq18OkpI.d.ts +96 -0
- package/dist/api-B4uXiHF0.d.mts +118 -0
- package/dist/api-B4uXiHF0.d.ts +118 -0
- package/dist/chunk-2XOTIEKS.js +1 -0
- package/dist/chunk-5HFI5CZ5.js +1 -0
- package/dist/chunk-CHDM7KGH.js +1 -0
- package/dist/chunk-HVTRRU4W.mjs +1 -0
- package/dist/chunk-JAPL7EZJ.mjs +1 -0
- package/dist/chunk-JNEWPO2J.mjs +1 -0
- package/dist/chunk-MFYHD6S5.js +1 -0
- package/dist/chunk-MGJZTOEM.mjs +1 -0
- package/dist/chunk-NBQH6QOU.mjs +1 -0
- package/dist/chunk-NSV6ECYO.js +1 -0
- package/dist/chunk-PNI3ZBZV.js +1 -0
- package/dist/chunk-U4RS66TB.mjs +1 -0
- package/dist/components.d.mts +24 -0
- package/dist/components.d.ts +24 -0
- package/dist/components.js +1 -0
- package/dist/components.mjs +1 -0
- package/dist/errorTranslation-DGdrMidg.d.ts +143 -0
- package/dist/errorTranslation-qwwQTvCO.d.mts +143 -0
- package/dist/hooks.d.mts +6 -0
- package/dist/hooks.d.ts +6 -0
- package/dist/hooks.js +1 -0
- package/dist/hooks.mjs +1 -0
- package/dist/index-BUKX3duW.d.ts +854 -0
- package/dist/index-Y9tTsinC.d.mts +854 -0
- package/dist/index.d.mts +1274 -0
- package/dist/index.d.ts +1274 -0
- package/dist/index.js +6 -0
- package/dist/index.mjs +6 -0
- package/dist/utils.d.mts +175 -0
- package/dist/utils.d.ts +175 -0
- package/dist/utils.js +1 -0
- package/dist/utils.mjs +1 -0
- package/package.json +88 -0
- package/vitest.config.ts +28 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,1274 @@
|
|
|
1
|
+
import crudify__default from '@nocios/crudify-sdk';
|
|
2
|
+
export * from '@nocios/crudify-sdk';
|
|
3
|
+
export { default as crudify } from '@nocios/crudify-sdk';
|
|
4
|
+
import { d as CrudifyLoginConfig, l as PasswordRule, E as EvaluatedPasswordRule } from './CrudiaMarkdownField-C54-A_J3.mjs';
|
|
5
|
+
export { B as BoxScreenType, a as CrudiaAutoGenerate, i as CrudiaAutoGenerateProps, b as CrudiaFileField, o as CrudiaFileFieldDeletionHandlers, j as CrudiaFileFieldProps, c as CrudiaMarkdownField, k as CrudiaMarkdownFieldProps, C as CrudifyLogin, e as CrudifyLoginProps, f as CrudifyLoginTranslations, D as DEFAULT_PASSWORD_RULES, L as LoginComponent, m as POLICY_ACTIONS, n as PREFERRED_POLICY_ORDER, p as PasswordRuleType, P as Policies, h as PolicyAction, S as SessionStatus, g as UserLoginData, U as UserProfileDisplay } from './CrudiaMarkdownField-C54-A_J3.mjs';
|
|
6
|
+
import React, { ReactNode } from 'react';
|
|
7
|
+
export { A as ApiError, C as CrudifyApiResponse, d as CrudifyOperationOptions, e as CrudifyRequestOptions, a as CrudifyTransactionResponse, F as ForgotPasswordRequest, J as JwtPayload, b as LoginRequest, L as LoginResponse, R as ResetPasswordRequest, g as TransactionInput, f as TransactionOperation, T as TransactionResponseData, U as UserProfile, V as ValidateCodeRequest, c as ValidationError } from './api-B4uXiHF0.mjs';
|
|
8
|
+
export { F as FileItem, v as FileStatus, L as LoginResult, N as NotificationOptions, a as SessionConfig, g as SessionDebugInfo, S as SessionManager, e as SessionProvider, h as SessionProviderProps, d as SessionState, c as StorageType, b as TokenData, T as TokenStorage, n as UseAuthReturn, p as UseDataReturn, s as UseFileUploadOptions, t as UseFileUploadReturn, U as UseSessionOptions, k as UseUserDataOptions, j as UseUserDataReturn, l as UserData, m as useAuth, w as useCrudifyWithNotifications, o as useData, r as useFileUpload, u as useSession, f as useSessionContext, i as useUserData, q as useUserProfile } from './index-Y9tTsinC.mjs';
|
|
9
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
10
|
+
import { ThemeOptions } from '@mui/material';
|
|
11
|
+
export { A as AutoGenerateConfig, G as GlobalNotificationProvider, a as GlobalNotificationProviderProps, N as Notification, b as NotificationSeverity, d as UseAutoGenerateOptions, U as UseAutoGenerateReturn, c as useAutoGenerate, u as useGlobalNotification } from './GlobalNotificationProvider-Zq18OkpI.mjs';
|
|
12
|
+
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-qwwQTvCO.mjs';
|
|
13
|
+
import { ApiResponse, IModule, ModuleCreateInput, ModuleEditInput, ActionListFilters, IAction, ActionCreateInput, ActionEditInput, UpdateActionsProfilesInput, UpdateActionsProfilesResponse, CalculatePermissionsInput, CalculatePermissionsResponse } from '@nocios/crudify-admin';
|
|
14
|
+
export { ActionCreateInput, ActionEditInput, ActionListFilters, ApiResponse, IAction, IModule, ModuleCreateInput, ModuleEditInput, UpdateActionsProfilesInput, UpdateActionsProfilesResponse } from '@nocios/crudify-admin';
|
|
15
|
+
|
|
16
|
+
interface CrudifyContextValue {
|
|
17
|
+
crudify: typeof crudify__default | null;
|
|
18
|
+
isLoading: boolean;
|
|
19
|
+
error: string | null;
|
|
20
|
+
isInitialized: boolean;
|
|
21
|
+
adminCredentials?: {
|
|
22
|
+
apiEndpointAdmin?: string;
|
|
23
|
+
apiKeyEndpointAdmin?: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
interface CrudifyProviderProps {
|
|
27
|
+
config: CrudifyLoginConfig;
|
|
28
|
+
children: ReactNode;
|
|
29
|
+
}
|
|
30
|
+
declare const CrudifyProvider: React.FC<CrudifyProviderProps>;
|
|
31
|
+
declare const useCrudify: () => CrudifyContextValue;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Tipos de mensajes que se pueden enviar entre tabs
|
|
35
|
+
*/
|
|
36
|
+
type CrossTabMessageType = "SESSION_STARTED" | "SESSION_ENDED" | "TOKEN_REFRESHED" | "SESSION_PING" | "SESSION_PONG";
|
|
37
|
+
/**
|
|
38
|
+
* Estructura del mensaje cross-tab
|
|
39
|
+
*/
|
|
40
|
+
interface CrossTabMessage {
|
|
41
|
+
type: CrossTabMessageType;
|
|
42
|
+
tabId: string;
|
|
43
|
+
timestamp: number;
|
|
44
|
+
payload?: Record<string, unknown>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Tipo de callback para suscriptores
|
|
48
|
+
*/
|
|
49
|
+
type CrossTabListener = (message: CrossTabMessage) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Manager singleton para sincronización cross-tab
|
|
52
|
+
*/
|
|
53
|
+
declare class CrossTabSyncManager {
|
|
54
|
+
private static instance;
|
|
55
|
+
private broadcastChannel;
|
|
56
|
+
private readonly CHANNEL_NAME;
|
|
57
|
+
private tabId;
|
|
58
|
+
private listeners;
|
|
59
|
+
private isInitialized;
|
|
60
|
+
/**
|
|
61
|
+
* Constructor privado - usar getInstance()
|
|
62
|
+
*/
|
|
63
|
+
private constructor();
|
|
64
|
+
/**
|
|
65
|
+
* Genera un ID único para esta pestaña
|
|
66
|
+
*/
|
|
67
|
+
private static generateTabId;
|
|
68
|
+
/**
|
|
69
|
+
* Obtener la instancia singleton
|
|
70
|
+
*/
|
|
71
|
+
static getInstance(): CrossTabSyncManager;
|
|
72
|
+
/**
|
|
73
|
+
* Resetear la instancia (útil para tests)
|
|
74
|
+
*/
|
|
75
|
+
static resetInstance(): void;
|
|
76
|
+
/**
|
|
77
|
+
* Inicializar el canal de comunicación
|
|
78
|
+
*/
|
|
79
|
+
private initialize;
|
|
80
|
+
/**
|
|
81
|
+
* Destruir el manager y limpiar recursos
|
|
82
|
+
*/
|
|
83
|
+
destroy(): void;
|
|
84
|
+
/**
|
|
85
|
+
* Obtener el ID de esta pestaña
|
|
86
|
+
*/
|
|
87
|
+
getTabId(): string;
|
|
88
|
+
/**
|
|
89
|
+
* Suscribirse a mensajes de otras pestañas
|
|
90
|
+
* @returns Función para desuscribirse
|
|
91
|
+
*/
|
|
92
|
+
subscribe(listener: CrossTabListener): () => void;
|
|
93
|
+
/**
|
|
94
|
+
* Notificar que se inició sesión en esta pestaña
|
|
95
|
+
*/
|
|
96
|
+
notifyLogin(): void;
|
|
97
|
+
/**
|
|
98
|
+
* Notificar que se cerró sesión en esta pestaña
|
|
99
|
+
*/
|
|
100
|
+
notifyLogout(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Notificar que se refrescaron los tokens
|
|
103
|
+
*/
|
|
104
|
+
notifyTokenRefreshed(): void;
|
|
105
|
+
/**
|
|
106
|
+
* Enviar un ping para verificar otras pestañas activas
|
|
107
|
+
*/
|
|
108
|
+
ping(): void;
|
|
109
|
+
/**
|
|
110
|
+
* Enviar mensaje a todas las demás pestañas
|
|
111
|
+
*/
|
|
112
|
+
private broadcast;
|
|
113
|
+
/**
|
|
114
|
+
* Procesar mensaje recibido de otra pestaña
|
|
115
|
+
*/
|
|
116
|
+
private handleMessage;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Instancia singleton exportada para uso directo
|
|
120
|
+
*/
|
|
121
|
+
declare const crossTabSync: CrossTabSyncManager;
|
|
122
|
+
|
|
123
|
+
type CrudifyThemeProviderProps = {
|
|
124
|
+
children: ReactNode;
|
|
125
|
+
defaultTheme?: ThemeOptions;
|
|
126
|
+
disableCssBaseline?: boolean;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Provider de tema para aplicaciones Crudify
|
|
130
|
+
* Lee automáticamente la cookie "theme" y aplica el tema a Material-UI
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```tsx
|
|
134
|
+
* <CrudifyThemeProvider>
|
|
135
|
+
* <App />
|
|
136
|
+
* </CrudifyThemeProvider>
|
|
137
|
+
* ```
|
|
138
|
+
*
|
|
139
|
+
* @example Con tema por defecto personalizado
|
|
140
|
+
* ```tsx
|
|
141
|
+
* <CrudifyThemeProvider defaultTheme={{ palette: { mode: 'dark' } }}>
|
|
142
|
+
* <App />
|
|
143
|
+
* </CrudifyThemeProvider>
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
declare function CrudifyThemeProvider({ children, defaultTheme, disableCssBaseline }: CrudifyThemeProviderProps): react_jsx_runtime.JSX.Element;
|
|
147
|
+
|
|
148
|
+
interface PasswordRequirementsProps {
|
|
149
|
+
requirements: Array<{
|
|
150
|
+
message: string;
|
|
151
|
+
valid: boolean;
|
|
152
|
+
}>;
|
|
153
|
+
show?: boolean;
|
|
154
|
+
}
|
|
155
|
+
declare const PasswordRequirements: React.FC<PasswordRequirementsProps>;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Password validation utilities
|
|
159
|
+
* Evaluates password against a set of configurable rules
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Evaluates a password against a set of rules
|
|
164
|
+
* @param password - The password to validate
|
|
165
|
+
* @param rules - Array of password rules to check against
|
|
166
|
+
* @returns Array of evaluated rules with validation status
|
|
167
|
+
*/
|
|
168
|
+
declare function evaluatePasswordRules(password: string, rules: PasswordRule[]): EvaluatedPasswordRule[];
|
|
169
|
+
/**
|
|
170
|
+
* Checks if all enforced password rules are satisfied
|
|
171
|
+
* @param evaluated - Array of evaluated password rules
|
|
172
|
+
* @returns true if all enforced rules pass, false otherwise
|
|
173
|
+
*/
|
|
174
|
+
declare function allPasswordRulesPassed(evaluated: EvaluatedPasswordRule[]): boolean;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Unified Logger for Crudify Projects
|
|
178
|
+
*
|
|
179
|
+
* Environment-based logging:
|
|
180
|
+
* - dev/stg: All logs (error, warn, info, debug)
|
|
181
|
+
* - prod: Only errors (default)
|
|
182
|
+
*
|
|
183
|
+
* AUTO-DETECTION:
|
|
184
|
+
* The logger will automatically detect the environment from:
|
|
185
|
+
* 1. Explicit setEnvironment() call (highest priority)
|
|
186
|
+
* 2. Cookie named 'environment' (for production with Lambda@Edge)
|
|
187
|
+
* 3. window.__CRUDIFY_ENV__ global variable
|
|
188
|
+
* 4. Default to "prod" for safety
|
|
189
|
+
*
|
|
190
|
+
* Usage:
|
|
191
|
+
* import { logger } from './logger';
|
|
192
|
+
*
|
|
193
|
+
* // Option 1: Explicit configuration (recommended for apps)
|
|
194
|
+
* logger.setEnvironment('dev'); // or 'stg', 'prod'
|
|
195
|
+
*
|
|
196
|
+
* // Option 2: Auto-detection (reads cookie or global)
|
|
197
|
+
* // Just use the logger - it will auto-detect
|
|
198
|
+
*
|
|
199
|
+
* logger.error('Something failed', { userId: '123' });
|
|
200
|
+
* logger.warn('Deprecated feature used');
|
|
201
|
+
* logger.info('User logged in', { email: 'user@example.com' });
|
|
202
|
+
* logger.debug('Processing request', { payload: data });
|
|
203
|
+
*/
|
|
204
|
+
type LogLevel = "error" | "warn" | "info" | "debug";
|
|
205
|
+
interface LogContext {
|
|
206
|
+
[key: string]: unknown;
|
|
207
|
+
}
|
|
208
|
+
declare class Logger {
|
|
209
|
+
private explicitEnv;
|
|
210
|
+
private prefix;
|
|
211
|
+
constructor();
|
|
212
|
+
/**
|
|
213
|
+
* Get current effective environment
|
|
214
|
+
* Priority: explicit setEnvironment() > auto-detection
|
|
215
|
+
*/
|
|
216
|
+
private getEffectiveEnv;
|
|
217
|
+
/**
|
|
218
|
+
* Sanitize sensitive data from strings
|
|
219
|
+
*/
|
|
220
|
+
private sanitize;
|
|
221
|
+
/**
|
|
222
|
+
* Sanitize context object
|
|
223
|
+
*/
|
|
224
|
+
private sanitizeContext;
|
|
225
|
+
/**
|
|
226
|
+
* Check if a log level should be displayed based on environment
|
|
227
|
+
* - dev/stg: show all logs
|
|
228
|
+
* - prod: show only errors (unless CRUDIFY_DEBUG_MODE is enabled)
|
|
229
|
+
*/
|
|
230
|
+
private shouldLog;
|
|
231
|
+
/**
|
|
232
|
+
* Format and output log entry
|
|
233
|
+
*/
|
|
234
|
+
private log;
|
|
235
|
+
/**
|
|
236
|
+
* Log an error - Always logged in all environments
|
|
237
|
+
*/
|
|
238
|
+
error(message: string, context?: LogContext | Error): void;
|
|
239
|
+
/**
|
|
240
|
+
* Log a warning - Only in dev/stg
|
|
241
|
+
*/
|
|
242
|
+
warn(message: string, context?: LogContext): void;
|
|
243
|
+
/**
|
|
244
|
+
* Log info - Only in dev/stg
|
|
245
|
+
*/
|
|
246
|
+
info(message: string, context?: LogContext): void;
|
|
247
|
+
/**
|
|
248
|
+
* Log debug information - Only in dev/stg
|
|
249
|
+
*/
|
|
250
|
+
debug(message: string, context?: LogContext): void;
|
|
251
|
+
/**
|
|
252
|
+
* Get current effective environment
|
|
253
|
+
*/
|
|
254
|
+
getEnvironment(): string;
|
|
255
|
+
/**
|
|
256
|
+
* Manually set environment (useful for libraries that receive env from parent app)
|
|
257
|
+
* This takes priority over auto-detection
|
|
258
|
+
*/
|
|
259
|
+
setEnvironment(env: string): void;
|
|
260
|
+
/**
|
|
261
|
+
* Check if environment was explicitly set or auto-detected
|
|
262
|
+
*/
|
|
263
|
+
isExplicitlyConfigured(): boolean;
|
|
264
|
+
}
|
|
265
|
+
declare const logger: Logger;
|
|
266
|
+
|
|
267
|
+
interface ProtectedRouteProps {
|
|
268
|
+
children: ReactNode;
|
|
269
|
+
/**
|
|
270
|
+
* Componente a mostrar mientras se valida la sesión
|
|
271
|
+
* @default <SessionLoadingScreen stage="validating-session" />
|
|
272
|
+
*/
|
|
273
|
+
loadingComponent?: ReactNode;
|
|
274
|
+
/**
|
|
275
|
+
* Ruta a la que redirigir si no está autenticado
|
|
276
|
+
* @default "/login"
|
|
277
|
+
*/
|
|
278
|
+
loginPath?: string;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Componente para proteger rutas que requieren autenticación
|
|
282
|
+
*
|
|
283
|
+
* Características:
|
|
284
|
+
* - Valida sesión de forma estricta (isAuthenticated + tokens válidos)
|
|
285
|
+
* - Guarda URL actual para redirect post-login
|
|
286
|
+
* - Previene open redirect attacks
|
|
287
|
+
* - Limpia storage corrupto automáticamente
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```tsx
|
|
291
|
+
* <Route
|
|
292
|
+
* path="/dashboard"
|
|
293
|
+
* element={
|
|
294
|
+
* <ProtectedRoute>
|
|
295
|
+
* <Dashboard />
|
|
296
|
+
* </ProtectedRoute>
|
|
297
|
+
* }
|
|
298
|
+
* />
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
declare function ProtectedRoute({ children, loadingComponent, loginPath }: ProtectedRouteProps): react_jsx_runtime.JSX.Element;
|
|
302
|
+
|
|
303
|
+
interface AuthRouteProps {
|
|
304
|
+
children: ReactNode;
|
|
305
|
+
/**
|
|
306
|
+
* Ruta a la que redirigir si ya está autenticado
|
|
307
|
+
* Si hay parámetro ?redirect= en la URL, se usará ese en su lugar
|
|
308
|
+
* @default "/"
|
|
309
|
+
*/
|
|
310
|
+
redirectTo?: string;
|
|
311
|
+
/**
|
|
312
|
+
* Componente a mostrar mientras se valida la sesión
|
|
313
|
+
* @default <SessionLoadingScreen stage="validating-session" />
|
|
314
|
+
*/
|
|
315
|
+
loadingComponent?: ReactNode;
|
|
316
|
+
/**
|
|
317
|
+
* Tiempo máximo de espera (ms) para la inicialización antes de mostrar el form
|
|
318
|
+
* @default 3000
|
|
319
|
+
*/
|
|
320
|
+
initTimeout?: number;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Componente para proteger rutas de autenticación (login, register, etc.)
|
|
324
|
+
* Redirige a home si el usuario ya está autenticado
|
|
325
|
+
*
|
|
326
|
+
* Características:
|
|
327
|
+
* - Si usuario autenticado → redirige a home (o ?redirect= si existe)
|
|
328
|
+
* - Si no autenticado → muestra el componente (login, etc.)
|
|
329
|
+
* - Pre-check: Si hay tokens en localStorage, espera inicialización antes de mostrar form
|
|
330
|
+
* - Timeout: Si la inicialización tarda mucho, muestra el form de todos modos
|
|
331
|
+
* - Valida parámetro redirect para prevenir open redirect
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```tsx
|
|
335
|
+
* <Route
|
|
336
|
+
* path="/login"
|
|
337
|
+
* element={
|
|
338
|
+
* <AuthRoute>
|
|
339
|
+
* <LoginPage />
|
|
340
|
+
* </AuthRoute>
|
|
341
|
+
* }
|
|
342
|
+
* />
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
declare function AuthRoute({ children, redirectTo, loadingComponent, initTimeout }: AuthRouteProps): react_jsx_runtime.JSX.Element;
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Comportamiento de GuestRoute cuando el usuario está autenticado
|
|
349
|
+
*/
|
|
350
|
+
type GuestRouteBehavior = "redirect-if-authenticated" | "allow-all";
|
|
351
|
+
interface GuestRouteProps {
|
|
352
|
+
children: ReactNode;
|
|
353
|
+
/**
|
|
354
|
+
* Comportamiento cuando el usuario está autenticado
|
|
355
|
+
* - 'redirect-if-authenticated': Redirige al usuario a redirectTo (default)
|
|
356
|
+
* - 'allow-all': Permite acceso tanto a usuarios autenticados como no autenticados
|
|
357
|
+
* @default 'redirect-if-authenticated'
|
|
358
|
+
*/
|
|
359
|
+
behavior?: GuestRouteBehavior;
|
|
360
|
+
/**
|
|
361
|
+
* Ruta a la que redirigir si está autenticado y behavior es 'redirect-if-authenticated'
|
|
362
|
+
* @default "/"
|
|
363
|
+
*/
|
|
364
|
+
redirectTo?: string;
|
|
365
|
+
/**
|
|
366
|
+
* Componente a mostrar mientras se valida la sesión
|
|
367
|
+
* @default <SessionLoadingScreen stage="validating-session" />
|
|
368
|
+
*/
|
|
369
|
+
loadingComponent?: ReactNode;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Componente para rutas de invitados con comportamiento configurable
|
|
373
|
+
*
|
|
374
|
+
* Casos de uso:
|
|
375
|
+
* - Login page: behavior='redirect-if-authenticated' → redirige si ya está logueado
|
|
376
|
+
* - Forgot password: behavior='allow-all' → permite acceso aunque esté logueado
|
|
377
|
+
* - Reset password: behavior='allow-all' → permite acceso aunque esté logueado
|
|
378
|
+
*
|
|
379
|
+
* @example
|
|
380
|
+
* ```tsx
|
|
381
|
+
* // Login - redirige si ya está autenticado
|
|
382
|
+
* <Route
|
|
383
|
+
* path="/login"
|
|
384
|
+
* element={
|
|
385
|
+
* <GuestRoute behavior="redirect-if-authenticated">
|
|
386
|
+
* <LoginPage />
|
|
387
|
+
* </GuestRoute>
|
|
388
|
+
* }
|
|
389
|
+
* />
|
|
390
|
+
*
|
|
391
|
+
* // Forgot password - permite acceso aunque esté autenticado
|
|
392
|
+
* <Route
|
|
393
|
+
* path="/login/forgotPassword"
|
|
394
|
+
* element={
|
|
395
|
+
* <GuestRoute behavior="allow-all">
|
|
396
|
+
* <ForgotPasswordPage />
|
|
397
|
+
* </GuestRoute>
|
|
398
|
+
* }
|
|
399
|
+
* />
|
|
400
|
+
* ```
|
|
401
|
+
*/
|
|
402
|
+
declare function GuestRoute({ children, behavior, redirectTo, loadingComponent }: GuestRouteProps): react_jsx_runtime.JSX.Element;
|
|
403
|
+
|
|
404
|
+
interface SessionLoadingScreenProps {
|
|
405
|
+
/**
|
|
406
|
+
* Stage of loading to display appropriate message
|
|
407
|
+
* @default "loading"
|
|
408
|
+
*/
|
|
409
|
+
stage?: "initializing" | "validating-session" | "loading";
|
|
410
|
+
/**
|
|
411
|
+
* Custom message to display (overrides default stage message)
|
|
412
|
+
*/
|
|
413
|
+
message?: string;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Loading screen component for session-related loading states
|
|
417
|
+
*
|
|
418
|
+
* Features:
|
|
419
|
+
* - Clean, minimal design
|
|
420
|
+
* - Customizable message
|
|
421
|
+
* - Stage-based default messages
|
|
422
|
+
* - No external dependencies (works without i18n)
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* ```tsx
|
|
426
|
+
* // Basic usage
|
|
427
|
+
* <SessionLoadingScreen stage="validating-session" />
|
|
428
|
+
*
|
|
429
|
+
* // With custom message
|
|
430
|
+
* <SessionLoadingScreen
|
|
431
|
+
* stage="validating-session"
|
|
432
|
+
* message={t("loading.validatingSession")}
|
|
433
|
+
* />
|
|
434
|
+
* ```
|
|
435
|
+
*/
|
|
436
|
+
declare function SessionLoadingScreen({ stage, message, }: SessionLoadingScreenProps): react_jsx_runtime.JSX.Element;
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Utilidades de seguridad para validar redirecciones
|
|
440
|
+
* Previene ataques de open redirect permitiendo rutas dinámicas
|
|
441
|
+
*/
|
|
442
|
+
/**
|
|
443
|
+
* Valida que una ruta de redirección sea segura (solo rutas internas)
|
|
444
|
+
* Permite rutas dinámicas pero bloquea ataques de open redirect
|
|
445
|
+
*
|
|
446
|
+
* @param path - La ruta a validar
|
|
447
|
+
* @param defaultPath - Ruta por defecto si la validación falla
|
|
448
|
+
* @returns Ruta validada y segura
|
|
449
|
+
*/
|
|
450
|
+
declare const validateInternalRedirect: (path: string, defaultPath?: string) => string;
|
|
451
|
+
/**
|
|
452
|
+
* Extrae y valida parámetro redirect de URL search params
|
|
453
|
+
*
|
|
454
|
+
* @param searchParams - URLSearchParams o string de query params
|
|
455
|
+
* @param defaultPath - Ruta por defecto
|
|
456
|
+
* @returns Ruta validada
|
|
457
|
+
*/
|
|
458
|
+
declare const extractSafeRedirectFromUrl: (searchParams: URLSearchParams | string, defaultPath?: string) => string;
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Verifica si hay tokens encriptados en localStorage
|
|
462
|
+
* Hace un check rápido sin desencriptar
|
|
463
|
+
*
|
|
464
|
+
* @returns true si parece haber tokens guardados en formato v2
|
|
465
|
+
*/
|
|
466
|
+
declare function hasStoredTokens(): boolean;
|
|
467
|
+
/**
|
|
468
|
+
* Verifica si existe el hash de la clave de encriptación
|
|
469
|
+
* Si existe, indica que TokenStorage puede desencriptar los tokens
|
|
470
|
+
*
|
|
471
|
+
* @returns true si hay un hash de clave válido guardado
|
|
472
|
+
*/
|
|
473
|
+
declare function hasEncryptionKeyHash(): boolean;
|
|
474
|
+
/**
|
|
475
|
+
* Determina si debemos esperar a la inicialización de la sesión
|
|
476
|
+
* antes de mostrar el formulario de login
|
|
477
|
+
*
|
|
478
|
+
* Retorna true si:
|
|
479
|
+
* - Hay tokens encriptados guardados
|
|
480
|
+
* - Hay un hash de clave de encriptación (para poder desencriptarlos)
|
|
481
|
+
*
|
|
482
|
+
* Esto indica alta probabilidad de sesión válida, por lo que
|
|
483
|
+
* deberíamos mostrar loading mientras se inicializa SessionManager
|
|
484
|
+
*
|
|
485
|
+
* @returns true si probablemente hay una sesión válida
|
|
486
|
+
*/
|
|
487
|
+
declare function shouldWaitForInitialization(): boolean;
|
|
488
|
+
/**
|
|
489
|
+
* Verifica si los tokens parecen estar corruptos o incompletos
|
|
490
|
+
* Útil para decidir si limpiar el storage
|
|
491
|
+
*
|
|
492
|
+
* @returns true si hay datos pero parecen corruptos
|
|
493
|
+
*/
|
|
494
|
+
declare function hasCorruptedTokens(): boolean;
|
|
495
|
+
/**
|
|
496
|
+
* Limpia tokens que parecen corruptos
|
|
497
|
+
* Solo debe llamarse si hasCorruptedTokens() retorna true
|
|
498
|
+
*/
|
|
499
|
+
declare function clearCorruptedTokens(): void;
|
|
500
|
+
|
|
501
|
+
type InitializationPriority = "HIGH" | "LOW";
|
|
502
|
+
type InitializationStatus = "UNINITIALIZED" | "INITIALIZING" | "INITIALIZED" | "ERROR";
|
|
503
|
+
interface InitializationState {
|
|
504
|
+
status: InitializationStatus;
|
|
505
|
+
priority: InitializationPriority | null;
|
|
506
|
+
publicApiKey: string | null;
|
|
507
|
+
env: string | null;
|
|
508
|
+
error: Error | null;
|
|
509
|
+
initializedBy: string | null;
|
|
510
|
+
}
|
|
511
|
+
interface InitializationRequest {
|
|
512
|
+
priority: InitializationPriority;
|
|
513
|
+
publicApiKey: string;
|
|
514
|
+
env: "dev" | "stg" | "api" | "prod";
|
|
515
|
+
enableLogging?: boolean;
|
|
516
|
+
requestedBy: string;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* CrudifyInitializationManager
|
|
520
|
+
*
|
|
521
|
+
* Singleton manager for controlling Crudify SDK initialization with priority system.
|
|
522
|
+
*
|
|
523
|
+
* **Priority System:**
|
|
524
|
+
* - HIGH: Explicit initialization via `<CrudifyInitializer>` component
|
|
525
|
+
* - LOW: Automatic fallback initialization in providers
|
|
526
|
+
*
|
|
527
|
+
* **Thread-Safe:**
|
|
528
|
+
* - Prevents duplicate initializations
|
|
529
|
+
* - Handles concurrent initialization requests
|
|
530
|
+
* - Shared promise ensures single initialization
|
|
531
|
+
*
|
|
532
|
+
* @example
|
|
533
|
+
* ```typescript
|
|
534
|
+
* // HIGH priority (CrudifyInitializer)
|
|
535
|
+
* await crudifyInitManager.initialize({
|
|
536
|
+
* priority: "HIGH",
|
|
537
|
+
* publicApiKey: "key",
|
|
538
|
+
* env: "stg",
|
|
539
|
+
* requestedBy: "CrudifyInitializer"
|
|
540
|
+
* });
|
|
541
|
+
*
|
|
542
|
+
* // LOW priority (provider auto-init)
|
|
543
|
+
* await crudifyInitManager.initialize({
|
|
544
|
+
* priority: "LOW",
|
|
545
|
+
* publicApiKey: "key",
|
|
546
|
+
* env: "stg",
|
|
547
|
+
* requestedBy: "SessionProvider"
|
|
548
|
+
* });
|
|
549
|
+
* ```
|
|
550
|
+
*/
|
|
551
|
+
declare class CrudifyInitializationManager {
|
|
552
|
+
private static instance;
|
|
553
|
+
private state;
|
|
554
|
+
private initializationPromise;
|
|
555
|
+
private highPriorityInitializerPresent;
|
|
556
|
+
private waitingForHighPriority;
|
|
557
|
+
private readonly HIGH_PRIORITY_WAIT_TIMEOUT;
|
|
558
|
+
private constructor();
|
|
559
|
+
/**
|
|
560
|
+
* Get singleton instance
|
|
561
|
+
*/
|
|
562
|
+
static getInstance(): CrudifyInitializationManager;
|
|
563
|
+
/**
|
|
564
|
+
* Register that a HIGH priority initializer is present
|
|
565
|
+
* This must be called SYNCHRONOUSLY during component mount
|
|
566
|
+
*/
|
|
567
|
+
registerHighPriorityInitializer(): void;
|
|
568
|
+
/**
|
|
569
|
+
* Check if a HIGH priority initializer is present
|
|
570
|
+
*/
|
|
571
|
+
isHighPriorityInitializerPresent(): boolean;
|
|
572
|
+
/**
|
|
573
|
+
* Get current initialization state (read-only)
|
|
574
|
+
*/
|
|
575
|
+
getState(): Readonly<InitializationState>;
|
|
576
|
+
/**
|
|
577
|
+
* Main initialization method - handles priority and concurrency
|
|
578
|
+
*
|
|
579
|
+
* @param request Initialization request with priority and config
|
|
580
|
+
* @returns Promise that resolves when initialization completes
|
|
581
|
+
* @throws Error if initialization fails
|
|
582
|
+
*/
|
|
583
|
+
initialize(request: InitializationRequest): Promise<void>;
|
|
584
|
+
/**
|
|
585
|
+
* Wait for HIGH priority initializer with timeout
|
|
586
|
+
*/
|
|
587
|
+
private waitForHighPriorityOrTimeout;
|
|
588
|
+
/**
|
|
589
|
+
* Actual SDK initialization
|
|
590
|
+
*/
|
|
591
|
+
private performInitialization;
|
|
592
|
+
/**
|
|
593
|
+
* Reset initialization state (for testing)
|
|
594
|
+
*/
|
|
595
|
+
reset(): void;
|
|
596
|
+
/**
|
|
597
|
+
* Check if initialized (without triggering initialization)
|
|
598
|
+
*/
|
|
599
|
+
isInitialized(): boolean;
|
|
600
|
+
/**
|
|
601
|
+
* Get diagnostic info (for debugging)
|
|
602
|
+
*/
|
|
603
|
+
getDiagnostics(): {
|
|
604
|
+
waitingCount: number;
|
|
605
|
+
waitingComponents: string[];
|
|
606
|
+
hasActivePromise: boolean;
|
|
607
|
+
status: InitializationStatus;
|
|
608
|
+
priority: InitializationPriority | null;
|
|
609
|
+
publicApiKey: string | null;
|
|
610
|
+
env: string | null;
|
|
611
|
+
error: Error | null;
|
|
612
|
+
initializedBy: string | null;
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Export singleton instance
|
|
617
|
+
*
|
|
618
|
+
* @example
|
|
619
|
+
* ```typescript
|
|
620
|
+
* import { crudifyInitManager } from "@nocios/crudify-components";
|
|
621
|
+
*
|
|
622
|
+
* // Initialize with HIGH priority
|
|
623
|
+
* await crudifyInitManager.initialize({
|
|
624
|
+
* priority: "HIGH",
|
|
625
|
+
* publicApiKey: "your-key",
|
|
626
|
+
* env: "stg",
|
|
627
|
+
* requestedBy: "CrudifyInitializer"
|
|
628
|
+
* });
|
|
629
|
+
*
|
|
630
|
+
* // Check if initialized
|
|
631
|
+
* if (crudifyInitManager.isInitialized()) {
|
|
632
|
+
* // Ready to use crudify SDK
|
|
633
|
+
* }
|
|
634
|
+
*
|
|
635
|
+
* // Get diagnostics
|
|
636
|
+
* console.log(crudifyInitManager.getDiagnostics());
|
|
637
|
+
* ```
|
|
638
|
+
*/
|
|
639
|
+
declare const crudifyInitManager: CrudifyInitializationManager;
|
|
640
|
+
|
|
641
|
+
interface CrudifyInitializerConfig {
|
|
642
|
+
publicApiKey?: string;
|
|
643
|
+
env?: "dev" | "stg" | "api" | "prod";
|
|
644
|
+
enableLogging?: boolean;
|
|
645
|
+
}
|
|
646
|
+
interface CrudifyInitializerContextValue {
|
|
647
|
+
isInitialized: boolean;
|
|
648
|
+
isInitializing: boolean;
|
|
649
|
+
error: Error | null;
|
|
650
|
+
}
|
|
651
|
+
interface CrudifyInitializerProps {
|
|
652
|
+
config?: CrudifyInitializerConfig;
|
|
653
|
+
children: React.ReactNode;
|
|
654
|
+
fallback?: React.ReactNode;
|
|
655
|
+
onInitialized?: () => void;
|
|
656
|
+
onError?: (error: Error) => void;
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* CrudifyInitializer Component
|
|
660
|
+
*
|
|
661
|
+
* HIGH priority Crudify SDK initializer component.
|
|
662
|
+
* Use this at the root of your app to explicitly control initialization.
|
|
663
|
+
*
|
|
664
|
+
* **Features:**
|
|
665
|
+
* - HIGH priority initialization (takes precedence over auto-init)
|
|
666
|
+
* - Provides initialization status via context
|
|
667
|
+
* - Optional loading fallback while initializing
|
|
668
|
+
* - Callbacks for initialization complete/error
|
|
669
|
+
* - React 18 StrictMode compatible
|
|
670
|
+
*
|
|
671
|
+
* **Usage:**
|
|
672
|
+
* ```tsx
|
|
673
|
+
* // App.tsx
|
|
674
|
+
* import { CrudifyInitializer } from "@nocios/crudify-components";
|
|
675
|
+
*
|
|
676
|
+
* function App() {
|
|
677
|
+
* return (
|
|
678
|
+
* <CrudifyInitializer
|
|
679
|
+
* config={{
|
|
680
|
+
* publicApiKey: import.meta.env.VITE_CRUDIFY_PUBLIC_API_KEY,
|
|
681
|
+
* env: "stg",
|
|
682
|
+
* enableLogging: true,
|
|
683
|
+
* }}
|
|
684
|
+
* fallback={<div>Loading Crudify...</div>}
|
|
685
|
+
* onInitialized={() => console.log("Crudify ready!")}
|
|
686
|
+
* onError={(err) => console.error("Init failed:", err)}
|
|
687
|
+
* >
|
|
688
|
+
* <SessionProvider>
|
|
689
|
+
* <TranslationsProvider>
|
|
690
|
+
* <App />
|
|
691
|
+
* </TranslationsProvider>
|
|
692
|
+
* </SessionProvider>
|
|
693
|
+
* </CrudifyInitializer>
|
|
694
|
+
* );
|
|
695
|
+
* }
|
|
696
|
+
* ```
|
|
697
|
+
*
|
|
698
|
+
* **Context Access:**
|
|
699
|
+
* ```tsx
|
|
700
|
+
* import { useCrudifyInitializer } from "@nocios/crudify-components";
|
|
701
|
+
*
|
|
702
|
+
* function MyComponent() {
|
|
703
|
+
* const { isInitialized, isInitializing, error } = useCrudifyInitializer();
|
|
704
|
+
*
|
|
705
|
+
* if (isInitializing) return <div>Loading...</div>;
|
|
706
|
+
* if (error) return <div>Error: {error.message}</div>;
|
|
707
|
+
* if (!isInitialized) return null;
|
|
708
|
+
*
|
|
709
|
+
* return <div>Crudify is ready!</div>;
|
|
710
|
+
* }
|
|
711
|
+
* ```
|
|
712
|
+
*/
|
|
713
|
+
declare const CrudifyInitializer: React.FC<CrudifyInitializerProps>;
|
|
714
|
+
/**
|
|
715
|
+
* Hook to access CrudifyInitializer context
|
|
716
|
+
*
|
|
717
|
+
* @returns Initialization status (isInitialized, isInitializing, error)
|
|
718
|
+
* @throws Error if used outside CrudifyInitializer
|
|
719
|
+
*
|
|
720
|
+
* @example
|
|
721
|
+
* ```tsx
|
|
722
|
+
* function MyComponent() {
|
|
723
|
+
* const { isInitialized, isInitializing, error } = useCrudifyInitializer();
|
|
724
|
+
*
|
|
725
|
+
* if (isInitializing) return <Spinner />;
|
|
726
|
+
* if (error) return <ErrorDisplay error={error} />;
|
|
727
|
+
*
|
|
728
|
+
* return <div>Ready!</div>;
|
|
729
|
+
* }
|
|
730
|
+
* ```
|
|
731
|
+
*/
|
|
732
|
+
declare const useCrudifyInitializer: () => CrudifyInitializerContextValue;
|
|
733
|
+
|
|
734
|
+
/** i18next instance interface for auto-syncing translations */
|
|
735
|
+
interface I18nInstance {
|
|
736
|
+
addResourceBundle: (lang: string, ns: string, resources: Record<string, string>, deep?: boolean, overwrite?: boolean) => void;
|
|
737
|
+
language?: string;
|
|
738
|
+
changeLanguage?: (lang: string) => void;
|
|
739
|
+
}
|
|
740
|
+
interface TranslationsProviderProps {
|
|
741
|
+
children: React.ReactNode;
|
|
742
|
+
apiKey?: string;
|
|
743
|
+
crudifyEnv?: "dev" | "stg" | "api" | "prod";
|
|
744
|
+
featureKeys?: string[];
|
|
745
|
+
language?: string;
|
|
746
|
+
devTranslations?: Record<string, string>;
|
|
747
|
+
translationUrl?: string;
|
|
748
|
+
enableDebug?: boolean;
|
|
749
|
+
skipAutoInit?: boolean;
|
|
750
|
+
autoSyncI18n?: boolean;
|
|
751
|
+
i18nInstance?: I18nInstance;
|
|
752
|
+
loadingFallback?: React.ReactNode;
|
|
753
|
+
waitForInitialLoad?: boolean;
|
|
754
|
+
}
|
|
755
|
+
interface TranslationsContextValue {
|
|
756
|
+
t: (key: string, variables?: Record<string, string | number>) => string;
|
|
757
|
+
language: string;
|
|
758
|
+
availableLanguages: string[];
|
|
759
|
+
translations: Record<string, Record<string, string>>;
|
|
760
|
+
isLoading: boolean;
|
|
761
|
+
error: string | null;
|
|
762
|
+
refreshTranslations: () => Promise<void>;
|
|
763
|
+
}
|
|
764
|
+
/**
|
|
765
|
+
* TranslationsProvider
|
|
766
|
+
*
|
|
767
|
+
* Provides translation functionality to the application
|
|
768
|
+
* Handles fetching, caching, and fallback strategies
|
|
769
|
+
*
|
|
770
|
+
* Note: The app MUST initialize crudify before mounting TranslationsProvider
|
|
771
|
+
*
|
|
772
|
+
* @example Basic usage
|
|
773
|
+
* ```tsx
|
|
774
|
+
* // App must initialize crudify first
|
|
775
|
+
* await crudify.init(publicApiKey, 'debug')
|
|
776
|
+
*
|
|
777
|
+
* <TranslationsProvider
|
|
778
|
+
* apiKey="xxx"
|
|
779
|
+
* language="es"
|
|
780
|
+
* translationUrl="https://example.com/locales/es/translation.json"
|
|
781
|
+
* skipAutoInit={true}
|
|
782
|
+
* >
|
|
783
|
+
* <App />
|
|
784
|
+
* </TranslationsProvider>
|
|
785
|
+
* ```
|
|
786
|
+
*
|
|
787
|
+
* @example With custom loading fallback (recommended for better UX)
|
|
788
|
+
* ```tsx
|
|
789
|
+
* <TranslationsProvider
|
|
790
|
+
* apiKey="xxx"
|
|
791
|
+
* crudifyEnv="prod"
|
|
792
|
+
* language={i18n.language}
|
|
793
|
+
* autoSyncI18n={true}
|
|
794
|
+
* i18nInstance={i18n}
|
|
795
|
+
* waitForInitialLoad={true} // Default - waits on first visit
|
|
796
|
+
* loadingFallback={<LoadingSpinner />} // Custom loading component
|
|
797
|
+
* >
|
|
798
|
+
* <App />
|
|
799
|
+
* </TranslationsProvider>
|
|
800
|
+
* ```
|
|
801
|
+
*
|
|
802
|
+
* @example Disable waiting (legacy behavior - may show keys briefly)
|
|
803
|
+
* ```tsx
|
|
804
|
+
* <TranslationsProvider
|
|
805
|
+
* apiKey="xxx"
|
|
806
|
+
* language="es"
|
|
807
|
+
* waitForInitialLoad={false} // Don't wait - render immediately
|
|
808
|
+
* >
|
|
809
|
+
* <App />
|
|
810
|
+
* </TranslationsProvider>
|
|
811
|
+
* ```
|
|
812
|
+
*/
|
|
813
|
+
declare const TranslationsProvider: React.FC<TranslationsProviderProps>;
|
|
814
|
+
/**
|
|
815
|
+
* Hook to use translations
|
|
816
|
+
*
|
|
817
|
+
* @example
|
|
818
|
+
* ```tsx
|
|
819
|
+
* const MyComponent = () => {
|
|
820
|
+
* const { t } = useTranslations();
|
|
821
|
+
* return <h1>{t('welcome.title')}</h1>;
|
|
822
|
+
* };
|
|
823
|
+
* ```
|
|
824
|
+
*/
|
|
825
|
+
declare const useTranslations: () => TranslationsContextValue;
|
|
826
|
+
|
|
827
|
+
interface FetchTranslationsOptions {
|
|
828
|
+
apiKey: string;
|
|
829
|
+
crudifyEnv?: "dev" | "stg" | "api" | "prod";
|
|
830
|
+
featureKeys?: string[];
|
|
831
|
+
urlTranslations?: Record<string, string>;
|
|
832
|
+
}
|
|
833
|
+
interface TranslationResponse {
|
|
834
|
+
languages: string[];
|
|
835
|
+
translations: Record<string, Record<string, string>>;
|
|
836
|
+
timestamp: string;
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Translation Service
|
|
840
|
+
* Handles fetching, caching, and fallback strategies for translations
|
|
841
|
+
* Uses Crudify SDK for API calls
|
|
842
|
+
*
|
|
843
|
+
* Priority order (lowest to highest):
|
|
844
|
+
* 1. Critical bundle (fallback)
|
|
845
|
+
* 2. API translations (system + subscriber merged by backend)
|
|
846
|
+
* 3. URL translations (buildTranslations from config.json or translationUrl)
|
|
847
|
+
* 4. Dev translations (props override - handled by provider)
|
|
848
|
+
*/
|
|
849
|
+
declare class TranslationService {
|
|
850
|
+
private static instance;
|
|
851
|
+
private enableDebug;
|
|
852
|
+
private initializationPromise;
|
|
853
|
+
private isInitialized;
|
|
854
|
+
private constructor();
|
|
855
|
+
static getInstance(): TranslationService;
|
|
856
|
+
/**
|
|
857
|
+
* Set debug mode
|
|
858
|
+
*/
|
|
859
|
+
setDebug(enable: boolean): void;
|
|
860
|
+
/**
|
|
861
|
+
* Ensure crudify is initialized before making API calls
|
|
862
|
+
* Thread-safe: multiple calls will wait for the same initialization
|
|
863
|
+
*/
|
|
864
|
+
private ensureCrudifyInitialized;
|
|
865
|
+
/**
|
|
866
|
+
* Fetch translations with cache strategy
|
|
867
|
+
* 1. Try cache (if valid and not changed)
|
|
868
|
+
* 2. Ensure crudify is initialized
|
|
869
|
+
* 3. Try API fetch via crudify SDK
|
|
870
|
+
* 4. Try expired cache
|
|
871
|
+
* 5. Fall back to critical bundle
|
|
872
|
+
*/
|
|
873
|
+
fetchTranslations(options: FetchTranslationsOptions): Promise<Record<string, Record<string, string>>>;
|
|
874
|
+
/**
|
|
875
|
+
* Fetch from API via crudify SDK
|
|
876
|
+
*/
|
|
877
|
+
private fetchFromAPI;
|
|
878
|
+
/**
|
|
879
|
+
* Merge API translations with URL translations
|
|
880
|
+
* URL translations have higher priority
|
|
881
|
+
*/
|
|
882
|
+
private mergeWithUrlTranslations;
|
|
883
|
+
/**
|
|
884
|
+
* Check if data has changed (compare timestamps or hash)
|
|
885
|
+
*/
|
|
886
|
+
private hasDataChanged;
|
|
887
|
+
/**
|
|
888
|
+
* Simple hash function for data comparison
|
|
889
|
+
*/
|
|
890
|
+
private hashData;
|
|
891
|
+
/**
|
|
892
|
+
* Save to localStorage
|
|
893
|
+
*/
|
|
894
|
+
private saveToCache;
|
|
895
|
+
/**
|
|
896
|
+
* Read from localStorage
|
|
897
|
+
*/
|
|
898
|
+
private getFromCache;
|
|
899
|
+
/**
|
|
900
|
+
* Refresh cache timestamp without changing data
|
|
901
|
+
*/
|
|
902
|
+
private refreshCacheTimestamp;
|
|
903
|
+
/**
|
|
904
|
+
* Check if cache is expired
|
|
905
|
+
*/
|
|
906
|
+
private isCacheExpired;
|
|
907
|
+
/**
|
|
908
|
+
* Check if there is valid (non-expired) cache available
|
|
909
|
+
* Public method for TranslationsProvider to check before rendering
|
|
910
|
+
*/
|
|
911
|
+
hasValidCache(apiKey: string): boolean;
|
|
912
|
+
/**
|
|
913
|
+
* Generate cache key from apiKey
|
|
914
|
+
* Uses a hash to ensure privacy and consistent length
|
|
915
|
+
*/
|
|
916
|
+
private getCacheKey;
|
|
917
|
+
/**
|
|
918
|
+
* Get only critical translations from bundle
|
|
919
|
+
*/
|
|
920
|
+
private getCriticalTranslationsOnly;
|
|
921
|
+
/**
|
|
922
|
+
* Invalidate cache (useful for testing/debugging)
|
|
923
|
+
*/
|
|
924
|
+
invalidateCache(apiKey: string): void;
|
|
925
|
+
/**
|
|
926
|
+
* Prefetch translations in background
|
|
927
|
+
*/
|
|
928
|
+
prefetchTranslations(options: FetchTranslationsOptions): Promise<void>;
|
|
929
|
+
/**
|
|
930
|
+
* Clear all translation caches
|
|
931
|
+
*/
|
|
932
|
+
clearAllCaches(): void;
|
|
933
|
+
}
|
|
934
|
+
declare const translationService: TranslationService;
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* Critical translations bundle
|
|
938
|
+
* These translations are bundled with the application to ensure
|
|
939
|
+
* basic functionality (login, errors, loading) works even if the API is unavailable
|
|
940
|
+
*
|
|
941
|
+
* Total keys: 108
|
|
942
|
+
* - login.*: 15 keys
|
|
943
|
+
* - forgotPassword.*: 11 keys
|
|
944
|
+
* - checkCode.*: 11 keys
|
|
945
|
+
* - resetPassword.*: 19 keys
|
|
946
|
+
* - errors.*: 39 keys
|
|
947
|
+
* - loading.*: 5 keys
|
|
948
|
+
* - common (basic): 2 keys
|
|
949
|
+
* - footer.*: 2 keys
|
|
950
|
+
* - error.app.*: 4 keys
|
|
951
|
+
*/
|
|
952
|
+
declare const CRITICAL_TRANSLATIONS: {
|
|
953
|
+
readonly es: {
|
|
954
|
+
readonly "checkCode.codeLabel": "Código de Verificación";
|
|
955
|
+
readonly "checkCode.codePlaceholder": "Ingresa el código de 6 dígitos";
|
|
956
|
+
readonly "checkCode.codeRequired": "El código es obligatorio";
|
|
957
|
+
readonly "checkCode.emailLabel": "Correo Electrónico";
|
|
958
|
+
readonly "checkCode.emailPlaceholder": "Ingresa tu correo electrónico";
|
|
959
|
+
readonly "checkCode.emailRequired": "El correo electrónico es obligatorio";
|
|
960
|
+
readonly "checkCode.instructions": "Ingresa el código de 6 dígitos que enviamos a tu correo electrónico.";
|
|
961
|
+
readonly "checkCode.invalidEmail": "Ingresa un correo electrónico válido";
|
|
962
|
+
readonly "checkCode.resendCodeLink": "Reenviar código";
|
|
963
|
+
readonly "checkCode.title": "Verificar Código";
|
|
964
|
+
readonly "checkCode.verifyButton": "Verificar Código";
|
|
965
|
+
readonly "base.btn.back": "Volver";
|
|
966
|
+
readonly "base.btn.cancel": "Cancelar";
|
|
967
|
+
readonly "error.app.config": "Error de Configuración: {{message}}";
|
|
968
|
+
readonly "error.app.initialization": "Error durante la inicialización final de la aplicación.";
|
|
969
|
+
readonly "error.transaction": "Error en la operación";
|
|
970
|
+
readonly "base.errors.errorUnknown": "Ocurrió un error desconocido.";
|
|
971
|
+
readonly "errors.DUPLICATE": "El campo <b>{{field}}</b> debe ser único.";
|
|
972
|
+
readonly "errors.FOREIGN_KEY_NOT_FOUND": "El campo <b>{{field}}</b> debe referenciar un ítem existente.";
|
|
973
|
+
readonly "errors.INVALID_EMAIL": "El campo <b>{{field}}</b> debe ser un correo electrónico válido.";
|
|
974
|
+
readonly "errors.INVALID_OBJECT_ID": "El campo <b>{{field}}</b> debe ser un valor válido.";
|
|
975
|
+
readonly "errors.IN_USE": "El ítem está en uso y no puede ser eliminado.";
|
|
976
|
+
readonly "errors.MAX_LENGTH": "El campo <b>{{field}}</b> no debe exceder los <b>{{length}}</b> caracteres.";
|
|
977
|
+
readonly "errors.MIN_LENGTH": "El campo <b>{{field}}</b> debe tener al menos <b>{{length}}</b> caracteres.";
|
|
978
|
+
readonly "errors.MUST_NOT_BE_EMAIL": "El campo <b>{{field}}</b> no debe ser un correo electrónico.";
|
|
979
|
+
readonly "errors.NO_PERMISSION": "No tienes permiso para realizar esta acción.";
|
|
980
|
+
readonly "errors.NO_SPACES": "El campo <b>{{field}}</b> no debe contener espacios.";
|
|
981
|
+
readonly "errors.ONE_OR_MORE_OPERATIONS_FAILED": "Error en la operación";
|
|
982
|
+
readonly "errors.REQUIRED": "El campo <b>{{field}}</b> es obligatorio.";
|
|
983
|
+
readonly "errors.TOKEN_HAS_EXPIRED": "La sesión ha expirado. Por favor, inicia sesión nuevamente.";
|
|
984
|
+
readonly "errors.TOO_MANY_REQUESTS": "Límite de solicitudes alcanzado. Por favor intenta más tarde.";
|
|
985
|
+
readonly "errors.UNAUTHORIZED": "No estás autorizado para realizar esta acción.";
|
|
986
|
+
readonly "errors.all_password_fields_required": "Todos los campos de contraseña son obligatorios";
|
|
987
|
+
readonly "errors.auth.INVALID_API_KEY": "Clave de API inválida";
|
|
988
|
+
readonly "errors.auth.INVALID_CREDENTIALS": "Usuario y/o contraseña incorrectos";
|
|
989
|
+
readonly "errors.auth.NO_PERMISSION": "No tienes permisos suficientes";
|
|
990
|
+
readonly "errors.auth.SESSION_EXPIRED": "Tu sesión ha expirado. Por favor, inicia sesión nuevamente.";
|
|
991
|
+
readonly "errors.auth.TOO_MANY_REQUESTS": "Demasiados intentos. Por favor espera 15 minutos e intenta nuevamente";
|
|
992
|
+
readonly "errors.auth.UNAUTHORIZED": "No tienes permisos para realizar esta acción";
|
|
993
|
+
readonly "errors.auth.USER_NOT_ACTIVE": "Usuario no activo";
|
|
994
|
+
readonly "errors.auth.USER_NOT_FOUND": "Usuario no encontrado";
|
|
995
|
+
readonly "errors.data.BAD_REQUEST": "Solicitud inválida";
|
|
996
|
+
readonly "errors.data.FIELD_ERROR": "Error en los datos ingresados";
|
|
997
|
+
readonly "errors.data.IN_USE": "El elemento está en uso y no puede ser eliminado";
|
|
998
|
+
readonly "errors.data.ITEM_NOT_FOUND": "El elemento solicitado no fue encontrado";
|
|
999
|
+
readonly "errors.data.NOT_FOUND": "No se encontró lo solicitado";
|
|
1000
|
+
readonly "errors.internal_error_changing_password": "Error interno al cambiar la contraseña. Intenta nuevamente";
|
|
1001
|
+
readonly "errors.password_min_length": "La contraseña debe tener al menos 8 caracteres";
|
|
1002
|
+
readonly "errors.password_mismatch": "Las contraseñas no coinciden";
|
|
1003
|
+
readonly "errors.password_must_be_different": "La nueva contraseña debe ser diferente a la actual";
|
|
1004
|
+
readonly "errors.system.DATABASE_CONNECTION_ERROR": "Error de conexión. Verifica tu conexión a internet.";
|
|
1005
|
+
readonly "errors.system.INTERNAL_SERVER_ERROR": "Error interno del servidor. Intenta nuevamente.";
|
|
1006
|
+
readonly "errors.system.INVALID_CONFIGURATION": "Error de configuración del sistema";
|
|
1007
|
+
readonly "errors.system.TOO_MANY_REQUESTS": "Demasiadas solicitudes. Por favor espera un momento e intenta nuevamente";
|
|
1008
|
+
readonly "errors.system.UNKNOWN_OPERATION": "Operación no reconocida";
|
|
1009
|
+
readonly "errors.users_module_not_configured": "Módulo de usuarios no configurado";
|
|
1010
|
+
readonly "footer.copyright": "Nocios S.R.L. Todos los derechos reservados.";
|
|
1011
|
+
readonly "footer.version": "Versión";
|
|
1012
|
+
readonly "forgotPassword.checkEmailInstructions": "Revisa tu bandeja de entrada para el código de verificación";
|
|
1013
|
+
readonly "forgotPassword.codeAlreadyExistsMessage": "Ya se envió un código y aún es válido";
|
|
1014
|
+
readonly "forgotPassword.emailLabel": "Correo Electrónico";
|
|
1015
|
+
readonly "forgotPassword.emailPlaceholder": "Ingresa tu correo electrónico";
|
|
1016
|
+
readonly "forgotPassword.emailRequired": "El correo electrónico es obligatorio";
|
|
1017
|
+
readonly "forgotPassword.emailSentMessage": "Código enviado exitosamente";
|
|
1018
|
+
readonly "forgotPassword.enterCodeLink": "Ingresar Código";
|
|
1019
|
+
readonly "forgotPassword.instructions": "Ingresa tu correo electrónico y te enviaremos un código para restablecer tu contraseña.";
|
|
1020
|
+
readonly "forgotPassword.invalidEmail": "Ingresa un correo electrónico válido";
|
|
1021
|
+
readonly "forgotPassword.sendCodeButton": "Enviar Código";
|
|
1022
|
+
readonly "forgotPassword.title": "Recuperar Contraseña";
|
|
1023
|
+
readonly "base.loading.configInitial": "Cargando configuración inicial...";
|
|
1024
|
+
readonly "base.loading.pleaseWait": "Cargando, por favor espera...";
|
|
1025
|
+
readonly "base.loading.starting": "Iniciando aplicación...";
|
|
1026
|
+
readonly "base.loading.themeSetup": "Generando tema...";
|
|
1027
|
+
readonly "base.loading.validatingSession": "Validando sesión...";
|
|
1028
|
+
readonly "login.alreadyHaveCodeLink": "¿Ya tienes un código?";
|
|
1029
|
+
readonly "login.forgotPasswordLink": "¿Olvidaste tu contraseña?";
|
|
1030
|
+
readonly "login.initializationError": "Error de inicialización";
|
|
1031
|
+
readonly "login.initializing": "Inicializando...";
|
|
1032
|
+
readonly "login.loginButton": "Iniciar Sesión";
|
|
1033
|
+
readonly "login.logoAlt": "Logotipo";
|
|
1034
|
+
readonly "login.noAccountPrompt": "¿No tienes una cuenta?";
|
|
1035
|
+
readonly "login.notInitialized": "Sistema no inicializado";
|
|
1036
|
+
readonly "login.passwordLabel": "Contraseña";
|
|
1037
|
+
readonly "login.passwordPlaceholder": "Ingresa tu contraseña";
|
|
1038
|
+
readonly "login.passwordRequired": "Contraseña es obligatoria";
|
|
1039
|
+
readonly "login.signUpLink": "Regístrate";
|
|
1040
|
+
readonly "login.usernameOrEmailLabel": "Correo Electrónico";
|
|
1041
|
+
readonly "login.usernameOrEmailPlaceholder": "Ingresa tu correo electrónico";
|
|
1042
|
+
readonly "login.usernameRequired": "Correo electrónico es obligatorio";
|
|
1043
|
+
readonly "resetPassword.codeExpiredOrInvalid": "El código ha expirado o es inválido";
|
|
1044
|
+
readonly "resetPassword.confirmPasswordLabel": "Confirmar Contraseña";
|
|
1045
|
+
readonly "resetPassword.confirmPasswordPlaceholder": "Confirma tu nueva contraseña";
|
|
1046
|
+
readonly "resetPassword.confirmPasswordRequired": "Confirma tu contraseña";
|
|
1047
|
+
readonly "resetPassword.goToLoginButton": "Ir al Login";
|
|
1048
|
+
readonly "resetPassword.instructions": "Ingresa tu nueva contraseña.";
|
|
1049
|
+
readonly "resetPassword.invalidCode": "El código de verificación es inválido. Por favor, verifica el enlace o solicita uno nuevo.";
|
|
1050
|
+
readonly "resetPassword.missingParameters": "Faltan parámetros obligatorios";
|
|
1051
|
+
readonly "resetPassword.newPasswordLabel": "Nueva Contraseña";
|
|
1052
|
+
readonly "resetPassword.newPasswordPlaceholder": "Ingresa tu nueva contraseña";
|
|
1053
|
+
readonly "resetPassword.newPasswordRequired": "La nueva contraseña es obligatoria";
|
|
1054
|
+
readonly "resetPassword.passwordTooShort": "La contraseña debe tener al menos 8 caracteres";
|
|
1055
|
+
readonly "resetPassword.passwordsDoNotMatch": "Las contraseñas no coinciden";
|
|
1056
|
+
readonly "resetPassword.requestNewCodeButton": "Solicitar Nuevo Código";
|
|
1057
|
+
readonly "resetPassword.resetPasswordButton": "Restablecer Contraseña";
|
|
1058
|
+
readonly "resetPassword.successInstructions": "Ahora puedes iniciar sesión con tu nueva contraseña";
|
|
1059
|
+
readonly "resetPassword.successMessage": "Contraseña restablecida exitosamente";
|
|
1060
|
+
readonly "resetPassword.title": "Nueva Contraseña";
|
|
1061
|
+
readonly "resetPassword.validatingCode": "Validando código...";
|
|
1062
|
+
readonly "resetPassword.passwordRequirementsNotMet": "La contraseña no cumple con todos los requisitos";
|
|
1063
|
+
readonly "passwordRequirements.minLength": "Mínimo 8 caracteres";
|
|
1064
|
+
readonly "passwordRequirements.uppercase": "Una letra mayúscula";
|
|
1065
|
+
readonly "passwordRequirements.lowercase": "Una letra minúscula";
|
|
1066
|
+
readonly "passwordRequirements.number": "Un número";
|
|
1067
|
+
readonly "passwordRequirements.special": "Un carácter especial (!@#$%...)";
|
|
1068
|
+
readonly "base.btn.showPassword": "Mostrar contraseña";
|
|
1069
|
+
readonly "base.btn.hidePassword": "Ocultar contraseña";
|
|
1070
|
+
readonly "publicPolicies.fields.conditions.customEdit": "Edición personalizada";
|
|
1071
|
+
readonly "base.file.clickToPreview": "Clic para ver imagen";
|
|
1072
|
+
readonly "base.file.clickToDownload": "Clic para descargar";
|
|
1073
|
+
readonly "base.file.privateFile": "Archivo privado";
|
|
1074
|
+
readonly "base.file.noPreview": "Sin vista previa";
|
|
1075
|
+
readonly "base.file.dropHere": "Suelta el archivo aquí";
|
|
1076
|
+
readonly "base.file.dragOrClick": "Arrastra archivos aquí o haz clic para seleccionar";
|
|
1077
|
+
readonly "base.file.uploading": "Subiendo archivos...";
|
|
1078
|
+
readonly "base.file.restore": "Restaurar";
|
|
1079
|
+
readonly "base.file.delete": "Eliminar";
|
|
1080
|
+
readonly "base.file.pendingDeletion": "Pendiente de eliminación";
|
|
1081
|
+
readonly "base.file.allowedTypes": "Tipos permitidos: {{types}}";
|
|
1082
|
+
readonly "base.file.maxSize": "Máximo {{size}} por archivo";
|
|
1083
|
+
readonly "base.file.maxFiles": "Máximo {{count}} archivos";
|
|
1084
|
+
readonly "base.file.validation.minFilesRequired": "Se requiere al menos un archivo";
|
|
1085
|
+
readonly "base.file.validation.minFilesRequiredPlural": "Se requieren al menos {{count}} archivos";
|
|
1086
|
+
readonly "base.file.validation.maxFilesExceeded": "Máximo {{count}} archivos permitidos";
|
|
1087
|
+
readonly "base.file.validation.filesWithErrors": "Algunos archivos tienen errores";
|
|
1088
|
+
readonly "base.file.confirmDelete.title": "Eliminar archivo";
|
|
1089
|
+
readonly "base.file.confirmDelete.message": "¿Estás seguro de que deseas eliminar este archivo? Esta acción no se puede deshacer.";
|
|
1090
|
+
readonly "base.file.confirmDelete.confirm": "Eliminar";
|
|
1091
|
+
readonly "base.file.confirmDelete.cancel": "Cancelar";
|
|
1092
|
+
readonly "base.file.deleting": "Eliminando...";
|
|
1093
|
+
};
|
|
1094
|
+
readonly en: {
|
|
1095
|
+
readonly "checkCode.codeLabel": "Verification Code";
|
|
1096
|
+
readonly "checkCode.codePlaceholder": "Enter 6-digit code";
|
|
1097
|
+
readonly "checkCode.codeRequired": "Code is required";
|
|
1098
|
+
readonly "checkCode.emailLabel": "Email Address";
|
|
1099
|
+
readonly "checkCode.emailPlaceholder": "Enter your email address";
|
|
1100
|
+
readonly "checkCode.emailRequired": "Email address is required";
|
|
1101
|
+
readonly "checkCode.instructions": "Enter the 6-digit code we sent to your email address.";
|
|
1102
|
+
readonly "checkCode.invalidEmail": "Enter a valid email address";
|
|
1103
|
+
readonly "checkCode.resendCodeLink": "Resend code";
|
|
1104
|
+
readonly "checkCode.title": "Verify Code";
|
|
1105
|
+
readonly "checkCode.verifyButton": "Verify Code";
|
|
1106
|
+
readonly "base.btn.back": "Back";
|
|
1107
|
+
readonly "base.btn.cancel": "Cancel";
|
|
1108
|
+
readonly "error.app.config": "Configuration Error: {{message}}";
|
|
1109
|
+
readonly "error.app.initialization": "Error during final application initialization.";
|
|
1110
|
+
readonly "error.transaction": "Operation error";
|
|
1111
|
+
readonly "base.errors.errorUnknown": "An unknown error occurred.";
|
|
1112
|
+
readonly "errors.DUPLICATE": "The field <b>{{field}}</b> must be unique.";
|
|
1113
|
+
readonly "errors.FOREIGN_KEY_NOT_FOUND": "The field <b>{{field}}</b> must reference an existing item.";
|
|
1114
|
+
readonly "errors.INVALID_EMAIL": "The field <b>{{field}}</b> must be a valid email address.";
|
|
1115
|
+
readonly "errors.INVALID_OBJECT_ID": "The field <b>{{field}}</b> must be a valid value.";
|
|
1116
|
+
readonly "errors.IN_USE": "The item is currently in use and cannot be deleted.";
|
|
1117
|
+
readonly "errors.MAX_LENGTH": "The field <b>{{field}}</b> must not exceed <b>{{maxLength}}</b> characters.";
|
|
1118
|
+
readonly "errors.MIN_LENGTH": "The field <b>{{field}}</b> must have at least <b>{{minLength}}</b> characters.";
|
|
1119
|
+
readonly "errors.MUST_NOT_BE_EMAIL": "The field <b>{{field}}</b> must not be an email address.";
|
|
1120
|
+
readonly "errors.NO_PERMISSION": "You do not have permission to perform this action.";
|
|
1121
|
+
readonly "errors.NO_SPACES": "The field <b>{{field}}</b> must not contain spaces.";
|
|
1122
|
+
readonly "errors.ONE_OR_MORE_OPERATIONS_FAILED": "Operation error";
|
|
1123
|
+
readonly "errors.REQUIRED": "The field <b>{{field}}</b> is required.";
|
|
1124
|
+
readonly "errors.TOKEN_HAS_EXPIRED": "Your session has expired, please log in again.";
|
|
1125
|
+
readonly "errors.TOO_MANY_REQUESTS": "Request limit reached. Please try again later.";
|
|
1126
|
+
readonly "errors.UNAUTHORIZED": "You are not authorized to perform this action.";
|
|
1127
|
+
readonly "errors.all_password_fields_required": "All password fields are required";
|
|
1128
|
+
readonly "errors.auth.INVALID_API_KEY": "Invalid API key";
|
|
1129
|
+
readonly "errors.auth.INVALID_CREDENTIALS": "Incorrect username and/or password";
|
|
1130
|
+
readonly "errors.auth.NO_PERMISSION": "Insufficient permissions";
|
|
1131
|
+
readonly "errors.auth.SESSION_EXPIRED": "Your session has expired. Please log in again.";
|
|
1132
|
+
readonly "errors.auth.TOO_MANY_REQUESTS": "Too many attempts. Please wait 15 minutes and try again";
|
|
1133
|
+
readonly "errors.auth.UNAUTHORIZED": "You don't have permission to perform this action";
|
|
1134
|
+
readonly "errors.auth.USER_NOT_ACTIVE": "User account is not active";
|
|
1135
|
+
readonly "errors.auth.USER_NOT_FOUND": "User not found";
|
|
1136
|
+
readonly "errors.data.BAD_REQUEST": "Invalid request";
|
|
1137
|
+
readonly "errors.data.FIELD_ERROR": "Error in the provided data";
|
|
1138
|
+
readonly "errors.data.IN_USE": "The item is in use and cannot be deleted";
|
|
1139
|
+
readonly "errors.data.ITEM_NOT_FOUND": "The requested item was not found";
|
|
1140
|
+
readonly "errors.data.NOT_FOUND": "The requested resource was not found";
|
|
1141
|
+
readonly "errors.internal_error_changing_password": "Internal error changing password. Please try again";
|
|
1142
|
+
readonly "errors.password_min_length": "Password must be at least 8 characters";
|
|
1143
|
+
readonly "errors.password_mismatch": "Passwords do not match";
|
|
1144
|
+
readonly "errors.password_must_be_different": "New password must be different from current password";
|
|
1145
|
+
readonly "errors.system.DATABASE_CONNECTION_ERROR": "Connection error. Please check your internet connection.";
|
|
1146
|
+
readonly "errors.system.INTERNAL_SERVER_ERROR": "Internal server error. Please try again.";
|
|
1147
|
+
readonly "errors.system.INVALID_CONFIGURATION": "System configuration error";
|
|
1148
|
+
readonly "errors.system.TOO_MANY_REQUESTS": "Too many requests. Please wait a moment and try again";
|
|
1149
|
+
readonly "errors.system.UNKNOWN_OPERATION": "Unrecognized operation";
|
|
1150
|
+
readonly "errors.users_module_not_configured": "Users module not configured";
|
|
1151
|
+
readonly "footer.copyright": "Nocios S.R.L. All Rights Reserved.";
|
|
1152
|
+
readonly "footer.version": "Version";
|
|
1153
|
+
readonly "forgotPassword.checkEmailInstructions": "Check your inbox for the verification code";
|
|
1154
|
+
readonly "forgotPassword.codeAlreadyExistsMessage": "A code was already sent and is still valid";
|
|
1155
|
+
readonly "forgotPassword.emailLabel": "Email Address";
|
|
1156
|
+
readonly "forgotPassword.emailPlaceholder": "Enter your email address";
|
|
1157
|
+
readonly "forgotPassword.emailRequired": "Email address is required";
|
|
1158
|
+
readonly "forgotPassword.emailSentMessage": "Code sent successfully";
|
|
1159
|
+
readonly "forgotPassword.enterCodeLink": "Enter Code";
|
|
1160
|
+
readonly "forgotPassword.instructions": "Enter your email address and we'll send you a code to reset your password.";
|
|
1161
|
+
readonly "forgotPassword.invalidEmail": "Enter a valid email address";
|
|
1162
|
+
readonly "forgotPassword.sendCodeButton": "Send Code";
|
|
1163
|
+
readonly "forgotPassword.title": "Reset Password";
|
|
1164
|
+
readonly "base.loading.configInitial": "Loading initial configuration...";
|
|
1165
|
+
readonly "base.loading.pleaseWait": "Loading, please wait...";
|
|
1166
|
+
readonly "base.loading.starting": "Starting application...";
|
|
1167
|
+
readonly "base.loading.themeSetup": "Generating theme...";
|
|
1168
|
+
readonly "base.loading.validatingSession": "Validating session...";
|
|
1169
|
+
readonly "login.alreadyHaveCodeLink": "Already have a code?";
|
|
1170
|
+
readonly "login.forgotPasswordLink": "Forgot Password?";
|
|
1171
|
+
readonly "login.initializationError": "Initialization error";
|
|
1172
|
+
readonly "login.initializing": "Initializing...";
|
|
1173
|
+
readonly "login.loginButton": "Log In";
|
|
1174
|
+
readonly "login.logoAlt": "Logo";
|
|
1175
|
+
readonly "login.noAccountPrompt": "Don't have an account?";
|
|
1176
|
+
readonly "login.notInitialized": "System not initialized";
|
|
1177
|
+
readonly "login.passwordLabel": "Password";
|
|
1178
|
+
readonly "login.passwordPlaceholder": "Enter your password";
|
|
1179
|
+
readonly "login.passwordRequired": "Password is required";
|
|
1180
|
+
readonly "login.signUpLink": "Sign up";
|
|
1181
|
+
readonly "login.usernameOrEmailLabel": "Username or Email";
|
|
1182
|
+
readonly "login.usernameOrEmailPlaceholder": "Enter your username or email";
|
|
1183
|
+
readonly "login.usernameRequired": "Username or email is required";
|
|
1184
|
+
readonly "resetPassword.codeExpiredOrInvalid": "Code expired or invalid";
|
|
1185
|
+
readonly "resetPassword.confirmPasswordLabel": "Confirm Password";
|
|
1186
|
+
readonly "resetPassword.confirmPasswordPlaceholder": "Confirm your new password";
|
|
1187
|
+
readonly "resetPassword.confirmPasswordRequired": "Confirm your password";
|
|
1188
|
+
readonly "resetPassword.goToLoginButton": "Go to Login";
|
|
1189
|
+
readonly "resetPassword.instructions": "Enter your new password.";
|
|
1190
|
+
readonly "resetPassword.invalidCode": "The verification code is invalid. Please check the link or request a new one.";
|
|
1191
|
+
readonly "resetPassword.missingParameters": "Missing required parameters";
|
|
1192
|
+
readonly "resetPassword.newPasswordLabel": "New Password";
|
|
1193
|
+
readonly "resetPassword.newPasswordPlaceholder": "Enter your new password";
|
|
1194
|
+
readonly "resetPassword.newPasswordRequired": "New password is required";
|
|
1195
|
+
readonly "resetPassword.passwordTooShort": "Password must be at least 8 characters";
|
|
1196
|
+
readonly "resetPassword.passwordsDoNotMatch": "Passwords do not match";
|
|
1197
|
+
readonly "resetPassword.requestNewCodeButton": "Request New Code";
|
|
1198
|
+
readonly "resetPassword.resetPasswordButton": "Reset Password";
|
|
1199
|
+
readonly "resetPassword.successInstructions": "You can now log in with your new password";
|
|
1200
|
+
readonly "resetPassword.successMessage": "Password reset successfully";
|
|
1201
|
+
readonly "resetPassword.title": "New Password";
|
|
1202
|
+
readonly "resetPassword.validatingCode": "Validating code...";
|
|
1203
|
+
readonly "resetPassword.passwordRequirementsNotMet": "Password does not meet all requirements";
|
|
1204
|
+
readonly "passwordRequirements.minLength": "Minimum 8 characters";
|
|
1205
|
+
readonly "passwordRequirements.uppercase": "One uppercase letter";
|
|
1206
|
+
readonly "passwordRequirements.lowercase": "One lowercase letter";
|
|
1207
|
+
readonly "passwordRequirements.number": "One number";
|
|
1208
|
+
readonly "passwordRequirements.special": "One special character (!@#$%...)";
|
|
1209
|
+
readonly "base.btn.showPassword": "Show password";
|
|
1210
|
+
readonly "base.btn.hidePassword": "Hide password";
|
|
1211
|
+
readonly "publicPolicies.fields.conditions.customEdit": "Custom Edit";
|
|
1212
|
+
readonly "base.file.clickToPreview": "Click to preview";
|
|
1213
|
+
readonly "base.file.clickToDownload": "Click to download";
|
|
1214
|
+
readonly "base.file.privateFile": "Private file";
|
|
1215
|
+
readonly "base.file.noPreview": "No preview";
|
|
1216
|
+
readonly "base.file.dropHere": "Drop file here";
|
|
1217
|
+
readonly "base.file.dragOrClick": "Drag files here or click to select";
|
|
1218
|
+
readonly "base.file.uploading": "Uploading files...";
|
|
1219
|
+
readonly "base.file.restore": "Restore";
|
|
1220
|
+
readonly "base.file.delete": "Delete";
|
|
1221
|
+
readonly "base.file.pendingDeletion": "Pending deletion";
|
|
1222
|
+
readonly "base.file.allowedTypes": "Allowed types: {{types}}";
|
|
1223
|
+
readonly "base.file.maxSize": "Max {{size}} per file";
|
|
1224
|
+
readonly "base.file.maxFiles": "Max {{count}} files";
|
|
1225
|
+
readonly "base.file.validation.minFilesRequired": "At least one file is required";
|
|
1226
|
+
readonly "base.file.validation.minFilesRequiredPlural": "At least {{count}} files are required";
|
|
1227
|
+
readonly "base.file.validation.maxFilesExceeded": "Maximum {{count}} files allowed";
|
|
1228
|
+
readonly "base.file.validation.filesWithErrors": "Some files have errors";
|
|
1229
|
+
readonly "base.file.confirmDelete.title": "Delete file";
|
|
1230
|
+
readonly "base.file.confirmDelete.message": "Are you sure you want to delete this file? This action cannot be undone.";
|
|
1231
|
+
readonly "base.file.confirmDelete.confirm": "Delete";
|
|
1232
|
+
readonly "base.file.deleting": "Deleting...";
|
|
1233
|
+
readonly "base.file.confirmDelete.cancel": "Cancel";
|
|
1234
|
+
};
|
|
1235
|
+
};
|
|
1236
|
+
type CriticalTranslationKey = keyof typeof CRITICAL_TRANSLATIONS.es;
|
|
1237
|
+
type SupportedLanguage = keyof typeof CRITICAL_TRANSLATIONS;
|
|
1238
|
+
/**
|
|
1239
|
+
* Get list of supported languages
|
|
1240
|
+
*/
|
|
1241
|
+
declare const getCriticalLanguages: () => SupportedLanguage[];
|
|
1242
|
+
/**
|
|
1243
|
+
* Get critical translations for a specific language
|
|
1244
|
+
* Falls back to Spanish if language not found
|
|
1245
|
+
*/
|
|
1246
|
+
declare const getCriticalTranslations: (language: string) => Record<string, string>;
|
|
1247
|
+
|
|
1248
|
+
/**
|
|
1249
|
+
* crudifyAdmin wrapper with auto-initialization.
|
|
1250
|
+
* Automatically injects JWT token in each request and handles token refresh on 401 errors.
|
|
1251
|
+
*/
|
|
1252
|
+
declare const crudifyAdmin: {
|
|
1253
|
+
listModules: () => Promise<ApiResponse<IModule[]>>;
|
|
1254
|
+
getModule: (moduleKey: string) => Promise<ApiResponse<IModule>>;
|
|
1255
|
+
createModule: (moduleData: ModuleCreateInput) => Promise<ApiResponse<IModule>>;
|
|
1256
|
+
editModule: (moduleKey: string, moduleData: ModuleEditInput) => Promise<ApiResponse<IModule>>;
|
|
1257
|
+
deleteModule: (moduleKey: string) => Promise<ApiResponse>;
|
|
1258
|
+
activateModule: (moduleKey: string) => Promise<ApiResponse<IModule>>;
|
|
1259
|
+
deactivateModule: (moduleKey: string) => Promise<ApiResponse<IModule>>;
|
|
1260
|
+
getModuleVersions: (moduleKey: string) => Promise<ApiResponse<any[]>>;
|
|
1261
|
+
listActions: (filters?: ActionListFilters) => Promise<ApiResponse<IAction[]>>;
|
|
1262
|
+
getAction: (actionKey: string) => Promise<ApiResponse<IAction>>;
|
|
1263
|
+
createAction: (actionData: ActionCreateInput) => Promise<ApiResponse<IAction>>;
|
|
1264
|
+
editAction: (actionKey: string, actionData: ActionEditInput) => Promise<ApiResponse<IAction>>;
|
|
1265
|
+
deleteAction: (actionKey: string) => Promise<ApiResponse>;
|
|
1266
|
+
activateAction: (actionKey: string) => Promise<ApiResponse<IAction>>;
|
|
1267
|
+
deactivateAction: (actionKey: string) => Promise<ApiResponse<IAction>>;
|
|
1268
|
+
getActionVersions: (actionKey: string) => Promise<ApiResponse<any[]>>;
|
|
1269
|
+
getActionsByProfile: (profileId: string) => Promise<ApiResponse<IAction[]>>;
|
|
1270
|
+
updateActionsProfiles: (data: UpdateActionsProfilesInput) => Promise<ApiResponse<UpdateActionsProfilesResponse>>;
|
|
1271
|
+
calculatePermissions: (data: CalculatePermissionsInput) => Promise<ApiResponse<CalculatePermissionsResponse>>;
|
|
1272
|
+
};
|
|
1273
|
+
|
|
1274
|
+
export { AuthRoute, type AuthRouteProps, CRITICAL_TRANSLATIONS, type CriticalTranslationKey, type CrossTabListener, type CrossTabMessage, type CrossTabMessageType, CrossTabSyncManager, CrudifyInitializationManager, CrudifyInitializer, type CrudifyInitializerConfig, type CrudifyInitializerProps, CrudifyLoginConfig, CrudifyProvider, CrudifyThemeProvider, type CrudifyThemeProviderProps, EvaluatedPasswordRule, type FetchTranslationsOptions, GuestRoute, type GuestRouteBehavior, type GuestRouteProps, type InitializationPriority, type InitializationRequest, type InitializationStatus, type LogContext, type LogLevel, PasswordRequirements, type PasswordRequirementsProps, PasswordRule, ProtectedRoute, type ProtectedRouteProps, SessionLoadingScreen, type SessionLoadingScreenProps, type SupportedLanguage, type TranslationResponse, TranslationService, type TranslationsContextValue, TranslationsProvider, type TranslationsProviderProps, allPasswordRulesPassed, clearCorruptedTokens, crossTabSync, crudifyAdmin, crudifyInitManager, evaluatePasswordRules, extractSafeRedirectFromUrl, getCriticalLanguages, getCriticalTranslations, hasCorruptedTokens, hasEncryptionKeyHash, hasStoredTokens, logger, shouldWaitForInitialization, translationService, useCrudify, useCrudifyInitializer, useTranslations, validateInternalRedirect };
|