@nocios/crudify-ui 1.2.23 → 1.2.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +201 -0
- package/dist/{CrudifyDataProvider-VQUGF4OL.mjs → CrudifyDataProvider-BLW4PCVZ.mjs} +1 -1
- package/dist/{chunk-UAYA54B3.mjs → chunk-LR5FXHGC.mjs} +43 -11
- package/dist/index.d.mts +18 -22
- package/dist/index.d.ts +18 -22
- package/dist/index.js +100 -134
- package/dist/index.mjs +61 -127
- package/package.json +1 -1
package/MIGRATION.md
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Guía de Migración - useCrudifyUser v1.2.25+
|
|
2
|
+
|
|
3
|
+
## Cambios Importantes
|
|
4
|
+
|
|
5
|
+
A partir de la versión 1.2.25, el hook `useCrudifyUser` ha sido completamente reestructurado para ser más simple y claro.
|
|
6
|
+
|
|
7
|
+
## Antes (❌ Estructura Anterior)
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
const {
|
|
11
|
+
userEmail,
|
|
12
|
+
userId,
|
|
13
|
+
userIdentifier,
|
|
14
|
+
userProfile,
|
|
15
|
+
profileLoading,
|
|
16
|
+
profileError,
|
|
17
|
+
extendedData,
|
|
18
|
+
refreshProfile,
|
|
19
|
+
clearProfile
|
|
20
|
+
} = useCrudifyUser();
|
|
21
|
+
|
|
22
|
+
// Acceso a datos
|
|
23
|
+
console.log(extendedData.fullProfile);
|
|
24
|
+
console.log(extendedData.displayData);
|
|
25
|
+
console.log(extendedData.totalFields);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Ahora (✅ Nueva Estructura)
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
const {
|
|
32
|
+
user,
|
|
33
|
+
loading,
|
|
34
|
+
error,
|
|
35
|
+
refreshProfile,
|
|
36
|
+
clearProfile
|
|
37
|
+
} = useCrudifyUser();
|
|
38
|
+
|
|
39
|
+
// Acceso a datos
|
|
40
|
+
console.log(user.session); // Datos del JWT token
|
|
41
|
+
console.log(user.data); // Datos de la base de datos
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Estructura del objeto `user`
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
interface CrudifyUserData {
|
|
48
|
+
session: JWTPayload | null; // Datos del token JWT
|
|
49
|
+
data: UserProfile | null; // Datos de la base de datos
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `user.session` (Datos del JWT)
|
|
54
|
+
- `user.session.sub` - User ID
|
|
55
|
+
- `user.session.email` - Email del usuario
|
|
56
|
+
- `user.session.name` - Nombre del usuario
|
|
57
|
+
- `user.session.exp` - Timestamp de expiración
|
|
58
|
+
- `user.session.iat` - Timestamp de emisión
|
|
59
|
+
- Y todos los demás campos del JWT token
|
|
60
|
+
|
|
61
|
+
### `user.data` (Datos de la Base de Datos)
|
|
62
|
+
- `user.data.id` - ID del perfil en la BD
|
|
63
|
+
- `user.data.email` - Email del perfil
|
|
64
|
+
- `user.data.firstName` - Nombre
|
|
65
|
+
- `user.data.lastName` - Apellido
|
|
66
|
+
- `user.data.role` - Rol del usuario
|
|
67
|
+
- Y todos los demás campos del perfil de usuario
|
|
68
|
+
|
|
69
|
+
## Migraciones Necesarias
|
|
70
|
+
|
|
71
|
+
### 1. Cambiar las destructuraciones
|
|
72
|
+
```typescript
|
|
73
|
+
// ❌ Antes
|
|
74
|
+
const { userProfile, profileLoading, profileError } = useCrudifyUser();
|
|
75
|
+
|
|
76
|
+
// ✅ Ahora
|
|
77
|
+
const { user, loading, error } = useCrudifyUser();
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 2. Actualizar acceso a datos de sesión
|
|
81
|
+
```typescript
|
|
82
|
+
// ❌ Antes
|
|
83
|
+
const email = userEmail;
|
|
84
|
+
const userId = userId;
|
|
85
|
+
|
|
86
|
+
// ✅ Ahora
|
|
87
|
+
const email = user.session?.email;
|
|
88
|
+
const userId = user.session?.sub;
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3. Actualizar acceso a datos de perfil
|
|
92
|
+
```typescript
|
|
93
|
+
// ❌ Antes
|
|
94
|
+
const profileData = userProfile;
|
|
95
|
+
const fullName = extendedData.displayData.fullName;
|
|
96
|
+
|
|
97
|
+
// ✅ Ahora
|
|
98
|
+
const profileData = user.data;
|
|
99
|
+
const fullName = user.data?.fullName;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 4. Actualizar estados de carga y error
|
|
103
|
+
```typescript
|
|
104
|
+
// ❌ Antes
|
|
105
|
+
if (profileLoading) return <Loading />;
|
|
106
|
+
if (profileError) return <Error message={profileError} />;
|
|
107
|
+
|
|
108
|
+
// ✅ Ahora
|
|
109
|
+
if (loading) return <Loading />;
|
|
110
|
+
if (error) return <Error message={error} />;
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Beneficios de la Nueva Estructura
|
|
114
|
+
|
|
115
|
+
1. **Más Simple**: Solo un objeto `user` con `session` y `data`
|
|
116
|
+
2. **Más Claro**: Es obvio qué viene del JWT (`session`) y qué de la DB (`data`)
|
|
117
|
+
3. **Sin Duplicación**: La información no se repite en múltiples lugares
|
|
118
|
+
4. **Mejor TypeScript**: Tipos más precisos y claros
|
|
119
|
+
5. **Más Fácil de Usar**: Los desarrolladores entienden inmediatamente la estructura
|
|
120
|
+
|
|
121
|
+
## Ejemplo Completo de Migración
|
|
122
|
+
|
|
123
|
+
### Antes
|
|
124
|
+
```tsx
|
|
125
|
+
function UserProfile() {
|
|
126
|
+
const {
|
|
127
|
+
userEmail,
|
|
128
|
+
userProfile,
|
|
129
|
+
profileLoading,
|
|
130
|
+
profileError,
|
|
131
|
+
extendedData,
|
|
132
|
+
refreshProfile
|
|
133
|
+
} = useCrudifyUser();
|
|
134
|
+
|
|
135
|
+
if (profileLoading) return <div>Cargando...</div>;
|
|
136
|
+
if (profileError) return <div>Error: {profileError}</div>;
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<div>
|
|
140
|
+
<h1>Welcome {userProfile?.fullName || userEmail}</h1>
|
|
141
|
+
<p>Total fields: {extendedData.totalFields}</p>
|
|
142
|
+
<pre>{JSON.stringify(extendedData.displayData, null, 2)}</pre>
|
|
143
|
+
<button onClick={refreshProfile}>Refresh</button>
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Después
|
|
150
|
+
```tsx
|
|
151
|
+
function UserProfile() {
|
|
152
|
+
const {
|
|
153
|
+
user,
|
|
154
|
+
loading,
|
|
155
|
+
error,
|
|
156
|
+
refreshProfile
|
|
157
|
+
} = useCrudifyUser();
|
|
158
|
+
|
|
159
|
+
if (loading) return <div>Cargando...</div>;
|
|
160
|
+
if (error) return <div>Error: {error}</div>;
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<div>
|
|
164
|
+
<h1>Welcome {user.data?.fullName || user.session?.email}</h1>
|
|
165
|
+
<h2>Datos de Sesión:</h2>
|
|
166
|
+
<pre>{JSON.stringify(user.session, null, 2)}</pre>
|
|
167
|
+
<h2>Datos de Perfil:</h2>
|
|
168
|
+
<pre>{JSON.stringify(user.data, null, 2)}</pre>
|
|
169
|
+
<button onClick={refreshProfile}>Refresh</button>
|
|
170
|
+
</div>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Retrocompatibilidad
|
|
176
|
+
|
|
177
|
+
Para mantener compatibilidad temporal, puedes crear un wrapper:
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// wrapper temporal para compatibilidad
|
|
181
|
+
export const useLegacyUserProfile = () => {
|
|
182
|
+
const { user, loading, error, refreshProfile, clearProfile } = useCrudifyUser();
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
userEmail: user.session?.email || null,
|
|
186
|
+
userId: user.session?.sub || null,
|
|
187
|
+
userProfile: user.data,
|
|
188
|
+
profileLoading: loading,
|
|
189
|
+
profileError: error,
|
|
190
|
+
extendedData: {
|
|
191
|
+
fullProfile: user.data,
|
|
192
|
+
displayData: user.data,
|
|
193
|
+
totalFields: user.data ? Object.keys(user.data).length : 0
|
|
194
|
+
},
|
|
195
|
+
refreshProfile,
|
|
196
|
+
clearProfile
|
|
197
|
+
};
|
|
198
|
+
};
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Nota**: Este wrapper es solo para facilitar la migración. Se recomienda migrar completamente a la nueva estructura.
|
|
@@ -52,9 +52,30 @@ var _ConfigurationManager = class _ConfigurationManager {
|
|
|
52
52
|
colors: "default"
|
|
53
53
|
};
|
|
54
54
|
const env = this.resolveValue("env", propsConfig.env, envConfig.env, cookieConfig.env, "prod", configSource);
|
|
55
|
-
const publicApiKey = this.resolveValue(
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
const publicApiKey = this.resolveValue(
|
|
56
|
+
"publicApiKey",
|
|
57
|
+
propsConfig.publicApiKey,
|
|
58
|
+
envConfig.publicApiKey,
|
|
59
|
+
cookieConfig.publicApiKey,
|
|
60
|
+
void 0,
|
|
61
|
+
configSource
|
|
62
|
+
);
|
|
63
|
+
const loginActions = this.resolveValue(
|
|
64
|
+
"loginActions",
|
|
65
|
+
propsConfig.loginActions,
|
|
66
|
+
envConfig.loginActions,
|
|
67
|
+
cookieConfig.loginActions,
|
|
68
|
+
[],
|
|
69
|
+
configSource
|
|
70
|
+
);
|
|
71
|
+
const appName = this.resolveValue(
|
|
72
|
+
"appName",
|
|
73
|
+
propsConfig.appName,
|
|
74
|
+
envConfig.appName,
|
|
75
|
+
cookieConfig.appName,
|
|
76
|
+
"Crudify App",
|
|
77
|
+
configSource
|
|
78
|
+
);
|
|
58
79
|
const logo = this.resolveValue("logo", propsConfig.logo, envConfig.logo, cookieConfig.logo, "", configSource);
|
|
59
80
|
const colors = this.resolveValue("colors", propsConfig.colors, envConfig.colors, cookieConfig.colors, {}, configSource);
|
|
60
81
|
console.log("\u{1F50D} ConfigurationManager - Resolved values:");
|
|
@@ -652,7 +673,7 @@ var _TokenManager = class _TokenManager {
|
|
|
652
673
|
console.log("\u{1F510} TokenManager - Initialization complete");
|
|
653
674
|
}
|
|
654
675
|
/**
|
|
655
|
-
* Migrate tokens from localStorage to
|
|
676
|
+
* Migrate tokens from plain localStorage to encrypted localStorage
|
|
656
677
|
* This ensures compatibility with older implementations
|
|
657
678
|
*/
|
|
658
679
|
migrateFromLocalStorage() {
|
|
@@ -660,9 +681,9 @@ var _TokenManager = class _TokenManager {
|
|
|
660
681
|
const legacyKeys = ["authToken", "token", "jwt", "jwtToken"];
|
|
661
682
|
for (const key of legacyKeys) {
|
|
662
683
|
const token = localStorage.getItem(key);
|
|
663
|
-
if (token && !
|
|
684
|
+
if (token && !secureLocalStorage.getToken()) {
|
|
664
685
|
console.log(`\u{1F510} TokenManager - Migrating token from localStorage key: ${key}`);
|
|
665
|
-
|
|
686
|
+
secureLocalStorage.setToken(token);
|
|
666
687
|
localStorage.removeItem(key);
|
|
667
688
|
break;
|
|
668
689
|
}
|
|
@@ -677,8 +698,8 @@ var _TokenManager = class _TokenManager {
|
|
|
677
698
|
loadTokenFromStorage() {
|
|
678
699
|
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Entry point - loading token from storage");
|
|
679
700
|
try {
|
|
680
|
-
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Getting token from secure
|
|
681
|
-
const storedToken =
|
|
701
|
+
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Getting token from secure local storage");
|
|
702
|
+
const storedToken = secureLocalStorage.getToken();
|
|
682
703
|
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token exists:", !!storedToken);
|
|
683
704
|
if (storedToken && this.isTokenValid(storedToken)) {
|
|
684
705
|
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token is valid, updating cache");
|
|
@@ -741,7 +762,7 @@ var _TokenManager = class _TokenManager {
|
|
|
741
762
|
this.tokenCache = token;
|
|
742
763
|
this.parsedTokenCache = this.parseToken(token);
|
|
743
764
|
console.log("\u{1F510} TokenManager - SET_TOKEN: Storing token in secure storage");
|
|
744
|
-
|
|
765
|
+
secureLocalStorage.setToken(token);
|
|
745
766
|
console.log("\u{1F510} TokenManager - SET_TOKEN: Synchronizing with crudify");
|
|
746
767
|
this.syncTokenWithCrudify(token);
|
|
747
768
|
console.log("\u{1F510} TokenManager - SET_TOKEN: Token set and synchronized successfully");
|
|
@@ -843,7 +864,7 @@ var _TokenManager = class _TokenManager {
|
|
|
843
864
|
this.tokenCache = null;
|
|
844
865
|
this.parsedTokenCache = null;
|
|
845
866
|
console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing from secure storage");
|
|
846
|
-
|
|
867
|
+
secureLocalStorage.removeItem(this.TOKEN_KEY);
|
|
847
868
|
console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing from crudify");
|
|
848
869
|
crudify2.setToken("");
|
|
849
870
|
console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Token cleared from all storages successfully");
|
|
@@ -1107,7 +1128,18 @@ var CrudifyDataProvider = ({
|
|
|
1107
1128
|
tokenManager: tokenManager.getDebugInfo(),
|
|
1108
1129
|
crudifyInitializer: crudifyInitializer.getStatus()
|
|
1109
1130
|
};
|
|
1110
|
-
}, [
|
|
1131
|
+
}, [
|
|
1132
|
+
isConfigured,
|
|
1133
|
+
configError,
|
|
1134
|
+
isInitialized,
|
|
1135
|
+
isInitializing,
|
|
1136
|
+
initializationError,
|
|
1137
|
+
isAuthenticated,
|
|
1138
|
+
config,
|
|
1139
|
+
token,
|
|
1140
|
+
user,
|
|
1141
|
+
tokenExpiration
|
|
1142
|
+
]);
|
|
1111
1143
|
useEffect(() => {
|
|
1112
1144
|
const resolvedConfig = initializeConfiguration();
|
|
1113
1145
|
updateAuthenticationState();
|
package/dist/index.d.mts
CHANGED
|
@@ -314,7 +314,7 @@ interface JWTPayload$1 extends JwtPayload {
|
|
|
314
314
|
* Key features:
|
|
315
315
|
* - Automatic storage <-> crudify synchronization
|
|
316
316
|
* - Token validation and expiration checking
|
|
317
|
-
* - Migration support from localStorage to
|
|
317
|
+
* - Migration support from plain localStorage to encrypted localStorage
|
|
318
318
|
* - Backward compatibility with existing token storage keys
|
|
319
319
|
* - Automatic cleanup of expired tokens
|
|
320
320
|
*/
|
|
@@ -339,7 +339,7 @@ declare class TokenManager {
|
|
|
339
339
|
*/
|
|
340
340
|
private initializeTokenManager;
|
|
341
341
|
/**
|
|
342
|
-
* Migrate tokens from localStorage to
|
|
342
|
+
* Migrate tokens from plain localStorage to encrypted localStorage
|
|
343
343
|
* This ensures compatibility with older implementations
|
|
344
344
|
*/
|
|
345
345
|
private migrateFromLocalStorage;
|
|
@@ -535,24 +535,19 @@ interface UseCrudifyAuthReturn {
|
|
|
535
535
|
declare const useCrudifyAuth: () => UseCrudifyAuthReturn;
|
|
536
536
|
|
|
537
537
|
/**
|
|
538
|
-
*
|
|
538
|
+
* Complete user data structure
|
|
539
539
|
*/
|
|
540
|
-
interface
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
displayData: Record<string, any>;
|
|
540
|
+
interface CrudifyUserData {
|
|
541
|
+
session: JWTPayload$1 | null;
|
|
542
|
+
data: UserProfile | null;
|
|
544
543
|
}
|
|
545
544
|
/**
|
|
546
545
|
* Return type for useCrudifyUser hook
|
|
547
546
|
*/
|
|
548
547
|
interface UseCrudifyUserReturn {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
userProfile: UserProfile | null;
|
|
553
|
-
profileLoading: boolean;
|
|
554
|
-
profileError: string | null;
|
|
555
|
-
extendedData: ExtendedUserData;
|
|
548
|
+
user: CrudifyUserData;
|
|
549
|
+
loading: boolean;
|
|
550
|
+
error: string | null;
|
|
556
551
|
refreshProfile: () => Promise<void>;
|
|
557
552
|
clearProfile: () => void;
|
|
558
553
|
}
|
|
@@ -588,19 +583,20 @@ interface UseCrudifyUserOptions {
|
|
|
588
583
|
* ```tsx
|
|
589
584
|
* function UserProfilePage() {
|
|
590
585
|
* const {
|
|
591
|
-
*
|
|
592
|
-
*
|
|
593
|
-
*
|
|
594
|
-
* extendedData,
|
|
586
|
+
* user,
|
|
587
|
+
* loading,
|
|
588
|
+
* error,
|
|
595
589
|
* refreshProfile
|
|
596
590
|
* } = useCrudifyUser({ autoFetch: true });
|
|
597
591
|
*
|
|
598
|
-
* if (
|
|
592
|
+
* if (loading) return <LoadingSpinner />;
|
|
593
|
+
* if (error) return <div>Error: {error}</div>;
|
|
599
594
|
*
|
|
600
595
|
* return (
|
|
601
596
|
* <div>
|
|
602
|
-
* <h1>Welcome {
|
|
603
|
-
* <p>
|
|
597
|
+
* <h1>Welcome {user.data?.fullName || user.session?.email}</h1>
|
|
598
|
+
* <p>Session data: {JSON.stringify(user.session, null, 2)}</p>
|
|
599
|
+
* <p>Profile data: {JSON.stringify(user.data, null, 2)}</p>
|
|
604
600
|
* <button onClick={refreshProfile}>Refresh</button>
|
|
605
601
|
* </div>
|
|
606
602
|
* );
|
|
@@ -921,4 +917,4 @@ declare function parseJavaScriptError(error: unknown): ParsedError;
|
|
|
921
917
|
*/
|
|
922
918
|
declare function handleCrudifyError(error: unknown): ParsedError[];
|
|
923
919
|
|
|
924
|
-
export { type ApiError, type BoxScreenType, type CrudifyApiResponse, type CrudifyConfig, type CrudifyDataContextState, CrudifyDataProvider, type CrudifyDataProviderProps, CrudifyLogin, type CrudifyLoginConfig, type CrudifyLoginProps, type CrudifyLoginTranslations, type CrudifyTransactionResponse, ERROR_CODES, ERROR_SEVERITY_MAP, type ErrorCode, type ErrorSeverity, type
|
|
920
|
+
export { type ApiError, type BoxScreenType, type CrudifyApiResponse, type CrudifyConfig, type CrudifyDataContextState, CrudifyDataProvider, type CrudifyDataProviderProps, CrudifyLogin, type CrudifyLoginConfig, type CrudifyLoginProps, type CrudifyLoginTranslations, type CrudifyTransactionResponse, type CrudifyUserData, ERROR_CODES, ERROR_SEVERITY_MAP, type ErrorCode, type ErrorSeverity, type ForgotPasswordRequest, type JWTPayload$1 as JWTPayload, type JwtPayload, type LoginRequest, type LoginResponse, type ParsedError, type ResetPasswordRequest, type ResolvedConfig, type TransactionResponseData, type UseCrudifyAuthReturn, type UseCrudifyConfigReturn, type UseCrudifyDataReturn, type UseCrudifyInstanceReturn, type UseCrudifyUserOptions, type UseCrudifyUserReturn, type UserLoginData, type UserProfile, UserProfileDisplay, type ValidateCodeRequest, type ValidationError, configurationManager, crudifyInitializer, decodeJwtSafely, getCookie, getCrudifyInstanceAsync, getCrudifyInstanceSync, getCurrentUserEmail, getErrorMessage, handleCrudifyError, isTokenExpired, parseApiError, parseJavaScriptError, parseTransactionError, secureLocalStorage, secureSessionStorage, tokenManager, useCrudifyAuth, useCrudifyConfig, useCrudifyData, useCrudifyDataContext, useCrudifyInstance, useCrudifyLogin, useCrudifyUser, useUserProfile };
|
package/dist/index.d.ts
CHANGED
|
@@ -314,7 +314,7 @@ interface JWTPayload$1 extends JwtPayload {
|
|
|
314
314
|
* Key features:
|
|
315
315
|
* - Automatic storage <-> crudify synchronization
|
|
316
316
|
* - Token validation and expiration checking
|
|
317
|
-
* - Migration support from localStorage to
|
|
317
|
+
* - Migration support from plain localStorage to encrypted localStorage
|
|
318
318
|
* - Backward compatibility with existing token storage keys
|
|
319
319
|
* - Automatic cleanup of expired tokens
|
|
320
320
|
*/
|
|
@@ -339,7 +339,7 @@ declare class TokenManager {
|
|
|
339
339
|
*/
|
|
340
340
|
private initializeTokenManager;
|
|
341
341
|
/**
|
|
342
|
-
* Migrate tokens from localStorage to
|
|
342
|
+
* Migrate tokens from plain localStorage to encrypted localStorage
|
|
343
343
|
* This ensures compatibility with older implementations
|
|
344
344
|
*/
|
|
345
345
|
private migrateFromLocalStorage;
|
|
@@ -535,24 +535,19 @@ interface UseCrudifyAuthReturn {
|
|
|
535
535
|
declare const useCrudifyAuth: () => UseCrudifyAuthReturn;
|
|
536
536
|
|
|
537
537
|
/**
|
|
538
|
-
*
|
|
538
|
+
* Complete user data structure
|
|
539
539
|
*/
|
|
540
|
-
interface
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
displayData: Record<string, any>;
|
|
540
|
+
interface CrudifyUserData {
|
|
541
|
+
session: JWTPayload$1 | null;
|
|
542
|
+
data: UserProfile | null;
|
|
544
543
|
}
|
|
545
544
|
/**
|
|
546
545
|
* Return type for useCrudifyUser hook
|
|
547
546
|
*/
|
|
548
547
|
interface UseCrudifyUserReturn {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
userProfile: UserProfile | null;
|
|
553
|
-
profileLoading: boolean;
|
|
554
|
-
profileError: string | null;
|
|
555
|
-
extendedData: ExtendedUserData;
|
|
548
|
+
user: CrudifyUserData;
|
|
549
|
+
loading: boolean;
|
|
550
|
+
error: string | null;
|
|
556
551
|
refreshProfile: () => Promise<void>;
|
|
557
552
|
clearProfile: () => void;
|
|
558
553
|
}
|
|
@@ -588,19 +583,20 @@ interface UseCrudifyUserOptions {
|
|
|
588
583
|
* ```tsx
|
|
589
584
|
* function UserProfilePage() {
|
|
590
585
|
* const {
|
|
591
|
-
*
|
|
592
|
-
*
|
|
593
|
-
*
|
|
594
|
-
* extendedData,
|
|
586
|
+
* user,
|
|
587
|
+
* loading,
|
|
588
|
+
* error,
|
|
595
589
|
* refreshProfile
|
|
596
590
|
* } = useCrudifyUser({ autoFetch: true });
|
|
597
591
|
*
|
|
598
|
-
* if (
|
|
592
|
+
* if (loading) return <LoadingSpinner />;
|
|
593
|
+
* if (error) return <div>Error: {error}</div>;
|
|
599
594
|
*
|
|
600
595
|
* return (
|
|
601
596
|
* <div>
|
|
602
|
-
* <h1>Welcome {
|
|
603
|
-
* <p>
|
|
597
|
+
* <h1>Welcome {user.data?.fullName || user.session?.email}</h1>
|
|
598
|
+
* <p>Session data: {JSON.stringify(user.session, null, 2)}</p>
|
|
599
|
+
* <p>Profile data: {JSON.stringify(user.data, null, 2)}</p>
|
|
604
600
|
* <button onClick={refreshProfile}>Refresh</button>
|
|
605
601
|
* </div>
|
|
606
602
|
* );
|
|
@@ -921,4 +917,4 @@ declare function parseJavaScriptError(error: unknown): ParsedError;
|
|
|
921
917
|
*/
|
|
922
918
|
declare function handleCrudifyError(error: unknown): ParsedError[];
|
|
923
919
|
|
|
924
|
-
export { type ApiError, type BoxScreenType, type CrudifyApiResponse, type CrudifyConfig, type CrudifyDataContextState, CrudifyDataProvider, type CrudifyDataProviderProps, CrudifyLogin, type CrudifyLoginConfig, type CrudifyLoginProps, type CrudifyLoginTranslations, type CrudifyTransactionResponse, ERROR_CODES, ERROR_SEVERITY_MAP, type ErrorCode, type ErrorSeverity, type
|
|
920
|
+
export { type ApiError, type BoxScreenType, type CrudifyApiResponse, type CrudifyConfig, type CrudifyDataContextState, CrudifyDataProvider, type CrudifyDataProviderProps, CrudifyLogin, type CrudifyLoginConfig, type CrudifyLoginProps, type CrudifyLoginTranslations, type CrudifyTransactionResponse, type CrudifyUserData, ERROR_CODES, ERROR_SEVERITY_MAP, type ErrorCode, type ErrorSeverity, type ForgotPasswordRequest, type JWTPayload$1 as JWTPayload, type JwtPayload, type LoginRequest, type LoginResponse, type ParsedError, type ResetPasswordRequest, type ResolvedConfig, type TransactionResponseData, type UseCrudifyAuthReturn, type UseCrudifyConfigReturn, type UseCrudifyDataReturn, type UseCrudifyInstanceReturn, type UseCrudifyUserOptions, type UseCrudifyUserReturn, type UserLoginData, type UserProfile, UserProfileDisplay, type ValidateCodeRequest, type ValidationError, configurationManager, crudifyInitializer, decodeJwtSafely, getCookie, getCrudifyInstanceAsync, getCrudifyInstanceSync, getCurrentUserEmail, getErrorMessage, handleCrudifyError, isTokenExpired, parseApiError, parseJavaScriptError, parseTransactionError, secureLocalStorage, secureSessionStorage, tokenManager, useCrudifyAuth, useCrudifyConfig, useCrudifyData, useCrudifyDataContext, useCrudifyInstance, useCrudifyLogin, useCrudifyUser, useUserProfile };
|
package/dist/index.js
CHANGED
|
@@ -209,9 +209,30 @@ var init_ConfigurationManager = __esm({
|
|
|
209
209
|
colors: "default"
|
|
210
210
|
};
|
|
211
211
|
const env = this.resolveValue("env", propsConfig.env, envConfig.env, cookieConfig.env, "prod", configSource);
|
|
212
|
-
const publicApiKey = this.resolveValue(
|
|
213
|
-
|
|
214
|
-
|
|
212
|
+
const publicApiKey = this.resolveValue(
|
|
213
|
+
"publicApiKey",
|
|
214
|
+
propsConfig.publicApiKey,
|
|
215
|
+
envConfig.publicApiKey,
|
|
216
|
+
cookieConfig.publicApiKey,
|
|
217
|
+
void 0,
|
|
218
|
+
configSource
|
|
219
|
+
);
|
|
220
|
+
const loginActions = this.resolveValue(
|
|
221
|
+
"loginActions",
|
|
222
|
+
propsConfig.loginActions,
|
|
223
|
+
envConfig.loginActions,
|
|
224
|
+
cookieConfig.loginActions,
|
|
225
|
+
[],
|
|
226
|
+
configSource
|
|
227
|
+
);
|
|
228
|
+
const appName = this.resolveValue(
|
|
229
|
+
"appName",
|
|
230
|
+
propsConfig.appName,
|
|
231
|
+
envConfig.appName,
|
|
232
|
+
cookieConfig.appName,
|
|
233
|
+
"Crudify App",
|
|
234
|
+
configSource
|
|
235
|
+
);
|
|
215
236
|
const logo = this.resolveValue("logo", propsConfig.logo, envConfig.logo, cookieConfig.logo, "", configSource);
|
|
216
237
|
const colors = this.resolveValue("colors", propsConfig.colors, envConfig.colors, cookieConfig.colors, {}, configSource);
|
|
217
238
|
console.log("\u{1F50D} ConfigurationManager - Resolved values:");
|
|
@@ -718,7 +739,7 @@ var init_TokenManager = __esm({
|
|
|
718
739
|
console.log("\u{1F510} TokenManager - Initialization complete");
|
|
719
740
|
}
|
|
720
741
|
/**
|
|
721
|
-
* Migrate tokens from localStorage to
|
|
742
|
+
* Migrate tokens from plain localStorage to encrypted localStorage
|
|
722
743
|
* This ensures compatibility with older implementations
|
|
723
744
|
*/
|
|
724
745
|
migrateFromLocalStorage() {
|
|
@@ -726,9 +747,9 @@ var init_TokenManager = __esm({
|
|
|
726
747
|
const legacyKeys = ["authToken", "token", "jwt", "jwtToken"];
|
|
727
748
|
for (const key of legacyKeys) {
|
|
728
749
|
const token = localStorage.getItem(key);
|
|
729
|
-
if (token && !
|
|
750
|
+
if (token && !secureLocalStorage.getToken()) {
|
|
730
751
|
console.log(`\u{1F510} TokenManager - Migrating token from localStorage key: ${key}`);
|
|
731
|
-
|
|
752
|
+
secureLocalStorage.setToken(token);
|
|
732
753
|
localStorage.removeItem(key);
|
|
733
754
|
break;
|
|
734
755
|
}
|
|
@@ -743,8 +764,8 @@ var init_TokenManager = __esm({
|
|
|
743
764
|
loadTokenFromStorage() {
|
|
744
765
|
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Entry point - loading token from storage");
|
|
745
766
|
try {
|
|
746
|
-
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Getting token from secure
|
|
747
|
-
const storedToken =
|
|
767
|
+
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Getting token from secure local storage");
|
|
768
|
+
const storedToken = secureLocalStorage.getToken();
|
|
748
769
|
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token exists:", !!storedToken);
|
|
749
770
|
if (storedToken && this.isTokenValid(storedToken)) {
|
|
750
771
|
console.log("\u{1F510} TokenManager - LOAD_FROM_STORAGE: Stored token is valid, updating cache");
|
|
@@ -807,7 +828,7 @@ var init_TokenManager = __esm({
|
|
|
807
828
|
this.tokenCache = token;
|
|
808
829
|
this.parsedTokenCache = this.parseToken(token);
|
|
809
830
|
console.log("\u{1F510} TokenManager - SET_TOKEN: Storing token in secure storage");
|
|
810
|
-
|
|
831
|
+
secureLocalStorage.setToken(token);
|
|
811
832
|
console.log("\u{1F510} TokenManager - SET_TOKEN: Synchronizing with crudify");
|
|
812
833
|
this.syncTokenWithCrudify(token);
|
|
813
834
|
console.log("\u{1F510} TokenManager - SET_TOKEN: Token set and synchronized successfully");
|
|
@@ -909,7 +930,7 @@ var init_TokenManager = __esm({
|
|
|
909
930
|
this.tokenCache = null;
|
|
910
931
|
this.parsedTokenCache = null;
|
|
911
932
|
console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing from secure storage");
|
|
912
|
-
|
|
933
|
+
secureLocalStorage.removeItem(this.TOKEN_KEY);
|
|
913
934
|
console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Clearing from crudify");
|
|
914
935
|
import_crudify_browser3.default.setToken("");
|
|
915
936
|
console.log("\u{1F510} TokenManager - CLEAR_TOKEN: Token cleared from all storages successfully");
|
|
@@ -1191,7 +1212,18 @@ var init_CrudifyDataProvider = __esm({
|
|
|
1191
1212
|
tokenManager: tokenManager.getDebugInfo(),
|
|
1192
1213
|
crudifyInitializer: crudifyInitializer.getStatus()
|
|
1193
1214
|
};
|
|
1194
|
-
}, [
|
|
1215
|
+
}, [
|
|
1216
|
+
isConfigured,
|
|
1217
|
+
configError,
|
|
1218
|
+
isInitialized,
|
|
1219
|
+
isInitializing,
|
|
1220
|
+
initializationError,
|
|
1221
|
+
isAuthenticated,
|
|
1222
|
+
config,
|
|
1223
|
+
token,
|
|
1224
|
+
user,
|
|
1225
|
+
tokenExpiration
|
|
1226
|
+
]);
|
|
1195
1227
|
(0, import_react5.useEffect)(() => {
|
|
1196
1228
|
const resolvedConfig = initializeConfiguration();
|
|
1197
1229
|
updateAuthenticationState();
|
|
@@ -2820,7 +2852,14 @@ var useCrudifyLogin = (config, _options = {}) => {
|
|
|
2820
2852
|
const finalConfig = (0, import_react10.useMemo)(() => {
|
|
2821
2853
|
const publicApiKey = config.publicApiKey || (isConfigured ? dataProviderConfig?.publicApiKey : null) || getCookie("publicApiKey") || null;
|
|
2822
2854
|
console.log("\u{1F50D} useCrudifyLogin - Resolved publicApiKey:", publicApiKey);
|
|
2823
|
-
console.log(
|
|
2855
|
+
console.log(
|
|
2856
|
+
"\u{1F50D} useCrudifyLogin - Sources - props:",
|
|
2857
|
+
config.publicApiKey,
|
|
2858
|
+
"dataProvider:",
|
|
2859
|
+
dataProviderConfig?.publicApiKey,
|
|
2860
|
+
"cookie:",
|
|
2861
|
+
getCookie("publicApiKey")
|
|
2862
|
+
);
|
|
2824
2863
|
const rawEnv = config.env || (isConfigured ? dataProviderConfig?.env : null) || getCookie("environment") || "prod";
|
|
2825
2864
|
const env = ["dev", "stg", "prod"].includes(rawEnv) ? rawEnv : "prod";
|
|
2826
2865
|
const appName = config.appName || (isConfigured ? dataProviderConfig?.appName : null) || getCookie("appName") || "Crudia";
|
|
@@ -3272,57 +3311,37 @@ init_CrudifyDataProvider();
|
|
|
3272
3311
|
var useCrudifyUser = (options = {}) => {
|
|
3273
3312
|
const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
|
|
3274
3313
|
const { isAuthenticated, isInitialized, user: jwtUser, token } = useCrudifyDataContext();
|
|
3275
|
-
const [
|
|
3276
|
-
const [
|
|
3277
|
-
const [
|
|
3278
|
-
const [extendedData, setExtendedData] = (0, import_react13.useState)({
|
|
3279
|
-
fullProfile: null,
|
|
3280
|
-
totalFields: 0,
|
|
3281
|
-
displayData: {}
|
|
3282
|
-
});
|
|
3314
|
+
const [userData, setUserData] = (0, import_react13.useState)(null);
|
|
3315
|
+
const [loading, setLoading] = (0, import_react13.useState)(false);
|
|
3316
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
3283
3317
|
const abortControllerRef = (0, import_react13.useRef)(null);
|
|
3284
3318
|
const mountedRef = (0, import_react13.useRef)(true);
|
|
3285
3319
|
const requestIdRef = (0, import_react13.useRef)(0);
|
|
3286
3320
|
const retryCountRef = (0, import_react13.useRef)(0);
|
|
3287
|
-
const
|
|
3288
|
-
if (!jwtUser)
|
|
3289
|
-
|
|
3290
|
-
userEmail: null,
|
|
3291
|
-
userId: null,
|
|
3292
|
-
userIdentifier: null
|
|
3293
|
-
};
|
|
3294
|
-
}
|
|
3295
|
-
return {
|
|
3296
|
-
userEmail: jwtUser.email || jwtUser["cognito:username"] || null,
|
|
3297
|
-
userId: jwtUser.sub || null,
|
|
3298
|
-
userIdentifier: jwtUser["cognito:username"] || jwtUser.email || jwtUser.sub || null
|
|
3299
|
-
};
|
|
3321
|
+
const getUserEmailFromJWT = (0, import_react13.useCallback)(() => {
|
|
3322
|
+
if (!jwtUser) return null;
|
|
3323
|
+
return jwtUser.email || jwtUser["cognito:username"] || null;
|
|
3300
3324
|
}, [jwtUser]);
|
|
3301
3325
|
const clearProfile = (0, import_react13.useCallback)(() => {
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
setExtendedData({
|
|
3306
|
-
fullProfile: null,
|
|
3307
|
-
totalFields: 0,
|
|
3308
|
-
displayData: {}
|
|
3309
|
-
});
|
|
3326
|
+
setUserData(null);
|
|
3327
|
+
setError(null);
|
|
3328
|
+
setLoading(false);
|
|
3310
3329
|
retryCountRef.current = 0;
|
|
3311
3330
|
}, []);
|
|
3312
3331
|
const refreshProfile = (0, import_react13.useCallback)(async () => {
|
|
3313
|
-
const
|
|
3314
|
-
console.log("\u{1F464} useCrudifyUser - Refreshing profile for:",
|
|
3315
|
-
if (!
|
|
3332
|
+
const userEmail = getUserEmailFromJWT();
|
|
3333
|
+
console.log("\u{1F464} useCrudifyUser - Refreshing profile for:", userEmail);
|
|
3334
|
+
if (!userEmail) {
|
|
3316
3335
|
if (mountedRef.current) {
|
|
3317
|
-
|
|
3318
|
-
|
|
3336
|
+
setError("No user email available from JWT token");
|
|
3337
|
+
setLoading(false);
|
|
3319
3338
|
}
|
|
3320
3339
|
return;
|
|
3321
3340
|
}
|
|
3322
3341
|
if (!isInitialized) {
|
|
3323
3342
|
if (mountedRef.current) {
|
|
3324
|
-
|
|
3325
|
-
|
|
3343
|
+
setError("Crudify not initialized");
|
|
3344
|
+
setLoading(false);
|
|
3326
3345
|
}
|
|
3327
3346
|
return;
|
|
3328
3347
|
}
|
|
@@ -3334,19 +3353,19 @@ var useCrudifyUser = (options = {}) => {
|
|
|
3334
3353
|
const currentRequestId = ++requestIdRef.current;
|
|
3335
3354
|
try {
|
|
3336
3355
|
if (mountedRef.current) {
|
|
3337
|
-
|
|
3338
|
-
|
|
3356
|
+
setLoading(true);
|
|
3357
|
+
setError(null);
|
|
3339
3358
|
}
|
|
3340
3359
|
console.log("\u{1F464} useCrudifyUser - Fetching profile data from database");
|
|
3341
3360
|
const response = await import_crudify_browser5.default.readItems("users", {
|
|
3342
|
-
filter: { email:
|
|
3361
|
+
filter: { email: userEmail },
|
|
3343
3362
|
pagination: { limit: 1 }
|
|
3344
3363
|
});
|
|
3345
3364
|
console.log("\u{1F464} useCrudifyUser - Database response:", response);
|
|
3346
3365
|
console.log("\u{1F464} useCrudifyUser - response.data:", response.data);
|
|
3347
3366
|
console.log("\u{1F464} useCrudifyUser - response.data type:", typeof response.data);
|
|
3348
3367
|
if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
|
|
3349
|
-
let
|
|
3368
|
+
let userData2 = null;
|
|
3350
3369
|
if (response.success) {
|
|
3351
3370
|
console.log("\u{1F464} useCrudifyUser - Processing successful response:", {
|
|
3352
3371
|
dataType: typeof response.data,
|
|
@@ -3357,7 +3376,7 @@ var useCrudifyUser = (options = {}) => {
|
|
|
3357
3376
|
});
|
|
3358
3377
|
if (Array.isArray(response.data) && response.data.length > 0) {
|
|
3359
3378
|
console.log("\u{1F464} useCrudifyUser - Found direct array format");
|
|
3360
|
-
|
|
3379
|
+
userData2 = response.data[0];
|
|
3361
3380
|
} else if (response.data?.response?.data) {
|
|
3362
3381
|
console.log("\u{1F464} useCrudifyUser - Found nested response.data format");
|
|
3363
3382
|
try {
|
|
@@ -3367,8 +3386,8 @@ var useCrudifyUser = (options = {}) => {
|
|
|
3367
3386
|
const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
3368
3387
|
console.log("\u{1F464} useCrudifyUser - Parsed nested data:", parsedData);
|
|
3369
3388
|
if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
|
|
3370
|
-
|
|
3371
|
-
console.log("\u{1F464} useCrudifyUser - Extracted user from nested items:",
|
|
3389
|
+
userData2 = parsedData.items[0];
|
|
3390
|
+
console.log("\u{1F464} useCrudifyUser - Extracted user from nested items:", userData2);
|
|
3372
3391
|
} else {
|
|
3373
3392
|
console.log("\u{1F464} useCrudifyUser - No items found in parsed data or items array is empty");
|
|
3374
3393
|
}
|
|
@@ -3379,7 +3398,7 @@ var useCrudifyUser = (options = {}) => {
|
|
|
3379
3398
|
console.log("\u{1F464} useCrudifyUser - Found object format, checking for items");
|
|
3380
3399
|
if (response.data.items && Array.isArray(response.data.items) && response.data.items.length > 0) {
|
|
3381
3400
|
console.log("\u{1F464} useCrudifyUser - Found items in object format");
|
|
3382
|
-
|
|
3401
|
+
userData2 = response.data.items[0];
|
|
3383
3402
|
} else {
|
|
3384
3403
|
console.log("\u{1F464} useCrudifyUser - No items found in object format");
|
|
3385
3404
|
}
|
|
@@ -3391,77 +3410,34 @@ var useCrudifyUser = (options = {}) => {
|
|
|
3391
3410
|
const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
3392
3411
|
console.log("\u{1F464} useCrudifyUser - Parsed double-nested data:", parsedData);
|
|
3393
3412
|
if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
|
|
3394
|
-
|
|
3395
|
-
console.log("\u{1F464} useCrudifyUser - Extracted user from double-nested items:",
|
|
3413
|
+
userData2 = parsedData.items[0];
|
|
3414
|
+
console.log("\u{1F464} useCrudifyUser - Extracted user from double-nested items:", userData2);
|
|
3396
3415
|
}
|
|
3397
3416
|
} catch (parseError) {
|
|
3398
3417
|
console.error("\u{1F464} useCrudifyUser - Error parsing double-nested response data:", parseError);
|
|
3399
3418
|
}
|
|
3400
3419
|
}
|
|
3401
3420
|
}
|
|
3402
|
-
if (
|
|
3403
|
-
console.log("\u{1F464} useCrudifyUser - User data found:",
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
fullProfile: userData,
|
|
3407
|
-
totalFields: Object.keys(userData).length,
|
|
3408
|
-
displayData: {
|
|
3409
|
-
id: userData.id || userData._id,
|
|
3410
|
-
email: userData.email,
|
|
3411
|
-
username: userData.username,
|
|
3412
|
-
firstName: userData.firstName || userData.name,
|
|
3413
|
-
lastName: userData.lastName,
|
|
3414
|
-
fullName: userData.fullName || `${userData.firstName || userData.name || ""} ${userData.lastName || ""}`.trim() || null,
|
|
3415
|
-
role: userData.role,
|
|
3416
|
-
permissions: userData.permissions || [],
|
|
3417
|
-
isActive: userData.isActive,
|
|
3418
|
-
lastLogin: userData.lastLogin,
|
|
3419
|
-
createdAt: userData.createdAt,
|
|
3420
|
-
updatedAt: userData.updatedAt,
|
|
3421
|
-
// Include any custom fields
|
|
3422
|
-
...Object.keys(userData).filter(
|
|
3423
|
-
(key) => ![
|
|
3424
|
-
"id",
|
|
3425
|
-
"_id",
|
|
3426
|
-
"email",
|
|
3427
|
-
"username",
|
|
3428
|
-
"firstName",
|
|
3429
|
-
"name",
|
|
3430
|
-
"lastName",
|
|
3431
|
-
"fullName",
|
|
3432
|
-
"role",
|
|
3433
|
-
"permissions",
|
|
3434
|
-
"isActive",
|
|
3435
|
-
"lastLogin",
|
|
3436
|
-
"createdAt",
|
|
3437
|
-
"updatedAt"
|
|
3438
|
-
].includes(key)
|
|
3439
|
-
).reduce((acc, key) => ({ ...acc, [key]: userData[key] }), {})
|
|
3440
|
-
}
|
|
3441
|
-
};
|
|
3442
|
-
setExtendedData(extended);
|
|
3443
|
-
setProfileError(null);
|
|
3421
|
+
if (userData2) {
|
|
3422
|
+
console.log("\u{1F464} useCrudifyUser - User data found:", userData2);
|
|
3423
|
+
setUserData(userData2);
|
|
3424
|
+
setError(null);
|
|
3444
3425
|
retryCountRef.current = 0;
|
|
3445
|
-
console.log("\u{1F464} useCrudifyUser - Profile loaded successfully:",
|
|
3426
|
+
console.log("\u{1F464} useCrudifyUser - Profile loaded successfully:", userData2);
|
|
3446
3427
|
} else {
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
fullProfile: null,
|
|
3451
|
-
totalFields: 0,
|
|
3452
|
-
displayData: {}
|
|
3453
|
-
});
|
|
3454
|
-
console.warn("\u{1F464} useCrudifyUser - User not found for email:", userEmail2);
|
|
3428
|
+
setError("User profile not found in database");
|
|
3429
|
+
setUserData(null);
|
|
3430
|
+
console.warn("\u{1F464} useCrudifyUser - User not found for email:", userEmail);
|
|
3455
3431
|
}
|
|
3456
3432
|
}
|
|
3457
3433
|
} catch (err) {
|
|
3458
3434
|
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
3459
|
-
const
|
|
3460
|
-
console.error("\u{1F464} useCrudifyUser - Error fetching profile:",
|
|
3461
|
-
if (
|
|
3435
|
+
const error2 = err;
|
|
3436
|
+
console.error("\u{1F464} useCrudifyUser - Error fetching profile:", error2);
|
|
3437
|
+
if (error2.name === "AbortError") {
|
|
3462
3438
|
return;
|
|
3463
3439
|
}
|
|
3464
|
-
const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (
|
|
3440
|
+
const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
|
|
3465
3441
|
if (shouldRetry) {
|
|
3466
3442
|
retryCountRef.current++;
|
|
3467
3443
|
console.log(`\u{1F464} useCrudifyUser - Retrying profile fetch (${retryCountRef.current}/${maxRetries})`);
|
|
@@ -3471,24 +3447,19 @@ var useCrudifyUser = (options = {}) => {
|
|
|
3471
3447
|
}
|
|
3472
3448
|
}, 1e3 * retryCountRef.current);
|
|
3473
3449
|
} else {
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
setExtendedData({
|
|
3477
|
-
fullProfile: null,
|
|
3478
|
-
totalFields: 0,
|
|
3479
|
-
displayData: {}
|
|
3480
|
-
});
|
|
3450
|
+
setError("Failed to load user profile from database");
|
|
3451
|
+
setUserData(null);
|
|
3481
3452
|
}
|
|
3482
3453
|
}
|
|
3483
3454
|
} finally {
|
|
3484
3455
|
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
3485
|
-
|
|
3456
|
+
setLoading(false);
|
|
3486
3457
|
}
|
|
3487
3458
|
if (abortControllerRef.current === abortController) {
|
|
3488
3459
|
abortControllerRef.current = null;
|
|
3489
3460
|
}
|
|
3490
3461
|
}
|
|
3491
|
-
}, [isInitialized,
|
|
3462
|
+
}, [isInitialized, getUserEmailFromJWT, retryOnError, maxRetries]);
|
|
3492
3463
|
(0, import_react13.useEffect)(() => {
|
|
3493
3464
|
if (autoFetch && isAuthenticated && isInitialized) {
|
|
3494
3465
|
refreshProfile();
|
|
@@ -3506,19 +3477,14 @@ var useCrudifyUser = (options = {}) => {
|
|
|
3506
3477
|
}
|
|
3507
3478
|
};
|
|
3508
3479
|
}, []);
|
|
3509
|
-
const
|
|
3480
|
+
const user = {
|
|
3481
|
+
session: jwtUser,
|
|
3482
|
+
data: userData
|
|
3483
|
+
};
|
|
3510
3484
|
return {
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
userIdentifier,
|
|
3515
|
-
// Perfil completo desde BD
|
|
3516
|
-
userProfile,
|
|
3517
|
-
profileLoading,
|
|
3518
|
-
profileError,
|
|
3519
|
-
// Datos extendidos formateados
|
|
3520
|
-
extendedData,
|
|
3521
|
-
// Acciones
|
|
3485
|
+
user,
|
|
3486
|
+
loading,
|
|
3487
|
+
error,
|
|
3522
3488
|
refreshProfile,
|
|
3523
3489
|
clearProfile
|
|
3524
3490
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
secureSessionStorage,
|
|
11
11
|
tokenManager,
|
|
12
12
|
useCrudifyDataContext
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-LR5FXHGC.mjs";
|
|
14
14
|
|
|
15
15
|
// src/index.ts
|
|
16
16
|
import { default as default2 } from "@nocios/crudify-browser";
|
|
@@ -1551,7 +1551,14 @@ var useCrudifyLogin = (config, _options = {}) => {
|
|
|
1551
1551
|
const finalConfig = useMemo2(() => {
|
|
1552
1552
|
const publicApiKey = config.publicApiKey || (isConfigured ? dataProviderConfig?.publicApiKey : null) || getCookie("publicApiKey") || null;
|
|
1553
1553
|
console.log("\u{1F50D} useCrudifyLogin - Resolved publicApiKey:", publicApiKey);
|
|
1554
|
-
console.log(
|
|
1554
|
+
console.log(
|
|
1555
|
+
"\u{1F50D} useCrudifyLogin - Sources - props:",
|
|
1556
|
+
config.publicApiKey,
|
|
1557
|
+
"dataProvider:",
|
|
1558
|
+
dataProviderConfig?.publicApiKey,
|
|
1559
|
+
"cookie:",
|
|
1560
|
+
getCookie("publicApiKey")
|
|
1561
|
+
);
|
|
1555
1562
|
const rawEnv = config.env || (isConfigured ? dataProviderConfig?.env : null) || getCookie("environment") || "prod";
|
|
1556
1563
|
const env = ["dev", "stg", "prod"].includes(rawEnv) ? rawEnv : "prod";
|
|
1557
1564
|
const appName = config.appName || (isConfigured ? dataProviderConfig?.appName : null) || getCookie("appName") || "Crudia";
|
|
@@ -2024,57 +2031,37 @@ import crudify3 from "@nocios/crudify-browser";
|
|
|
2024
2031
|
var useCrudifyUser = (options = {}) => {
|
|
2025
2032
|
const { autoFetch = true, retryOnError = false, maxRetries = 3 } = options;
|
|
2026
2033
|
const { isAuthenticated, isInitialized, user: jwtUser, token } = useCrudifyDataContext();
|
|
2027
|
-
const [
|
|
2028
|
-
const [
|
|
2029
|
-
const [
|
|
2030
|
-
const [extendedData, setExtendedData] = useState8({
|
|
2031
|
-
fullProfile: null,
|
|
2032
|
-
totalFields: 0,
|
|
2033
|
-
displayData: {}
|
|
2034
|
-
});
|
|
2034
|
+
const [userData, setUserData] = useState8(null);
|
|
2035
|
+
const [loading, setLoading] = useState8(false);
|
|
2036
|
+
const [error, setError] = useState8(null);
|
|
2035
2037
|
const abortControllerRef = useRef3(null);
|
|
2036
2038
|
const mountedRef = useRef3(true);
|
|
2037
2039
|
const requestIdRef = useRef3(0);
|
|
2038
2040
|
const retryCountRef = useRef3(0);
|
|
2039
|
-
const
|
|
2040
|
-
if (!jwtUser)
|
|
2041
|
-
|
|
2042
|
-
userEmail: null,
|
|
2043
|
-
userId: null,
|
|
2044
|
-
userIdentifier: null
|
|
2045
|
-
};
|
|
2046
|
-
}
|
|
2047
|
-
return {
|
|
2048
|
-
userEmail: jwtUser.email || jwtUser["cognito:username"] || null,
|
|
2049
|
-
userId: jwtUser.sub || null,
|
|
2050
|
-
userIdentifier: jwtUser["cognito:username"] || jwtUser.email || jwtUser.sub || null
|
|
2051
|
-
};
|
|
2041
|
+
const getUserEmailFromJWT = useCallback2(() => {
|
|
2042
|
+
if (!jwtUser) return null;
|
|
2043
|
+
return jwtUser.email || jwtUser["cognito:username"] || null;
|
|
2052
2044
|
}, [jwtUser]);
|
|
2053
2045
|
const clearProfile = useCallback2(() => {
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
setExtendedData({
|
|
2058
|
-
fullProfile: null,
|
|
2059
|
-
totalFields: 0,
|
|
2060
|
-
displayData: {}
|
|
2061
|
-
});
|
|
2046
|
+
setUserData(null);
|
|
2047
|
+
setError(null);
|
|
2048
|
+
setLoading(false);
|
|
2062
2049
|
retryCountRef.current = 0;
|
|
2063
2050
|
}, []);
|
|
2064
2051
|
const refreshProfile = useCallback2(async () => {
|
|
2065
|
-
const
|
|
2066
|
-
console.log("\u{1F464} useCrudifyUser - Refreshing profile for:",
|
|
2067
|
-
if (!
|
|
2052
|
+
const userEmail = getUserEmailFromJWT();
|
|
2053
|
+
console.log("\u{1F464} useCrudifyUser - Refreshing profile for:", userEmail);
|
|
2054
|
+
if (!userEmail) {
|
|
2068
2055
|
if (mountedRef.current) {
|
|
2069
|
-
|
|
2070
|
-
|
|
2056
|
+
setError("No user email available from JWT token");
|
|
2057
|
+
setLoading(false);
|
|
2071
2058
|
}
|
|
2072
2059
|
return;
|
|
2073
2060
|
}
|
|
2074
2061
|
if (!isInitialized) {
|
|
2075
2062
|
if (mountedRef.current) {
|
|
2076
|
-
|
|
2077
|
-
|
|
2063
|
+
setError("Crudify not initialized");
|
|
2064
|
+
setLoading(false);
|
|
2078
2065
|
}
|
|
2079
2066
|
return;
|
|
2080
2067
|
}
|
|
@@ -2086,19 +2073,19 @@ var useCrudifyUser = (options = {}) => {
|
|
|
2086
2073
|
const currentRequestId = ++requestIdRef.current;
|
|
2087
2074
|
try {
|
|
2088
2075
|
if (mountedRef.current) {
|
|
2089
|
-
|
|
2090
|
-
|
|
2076
|
+
setLoading(true);
|
|
2077
|
+
setError(null);
|
|
2091
2078
|
}
|
|
2092
2079
|
console.log("\u{1F464} useCrudifyUser - Fetching profile data from database");
|
|
2093
2080
|
const response = await crudify3.readItems("users", {
|
|
2094
|
-
filter: { email:
|
|
2081
|
+
filter: { email: userEmail },
|
|
2095
2082
|
pagination: { limit: 1 }
|
|
2096
2083
|
});
|
|
2097
2084
|
console.log("\u{1F464} useCrudifyUser - Database response:", response);
|
|
2098
2085
|
console.log("\u{1F464} useCrudifyUser - response.data:", response.data);
|
|
2099
2086
|
console.log("\u{1F464} useCrudifyUser - response.data type:", typeof response.data);
|
|
2100
2087
|
if (currentRequestId === requestIdRef.current && mountedRef.current && !abortController.signal.aborted) {
|
|
2101
|
-
let
|
|
2088
|
+
let userData2 = null;
|
|
2102
2089
|
if (response.success) {
|
|
2103
2090
|
console.log("\u{1F464} useCrudifyUser - Processing successful response:", {
|
|
2104
2091
|
dataType: typeof response.data,
|
|
@@ -2109,7 +2096,7 @@ var useCrudifyUser = (options = {}) => {
|
|
|
2109
2096
|
});
|
|
2110
2097
|
if (Array.isArray(response.data) && response.data.length > 0) {
|
|
2111
2098
|
console.log("\u{1F464} useCrudifyUser - Found direct array format");
|
|
2112
|
-
|
|
2099
|
+
userData2 = response.data[0];
|
|
2113
2100
|
} else if (response.data?.response?.data) {
|
|
2114
2101
|
console.log("\u{1F464} useCrudifyUser - Found nested response.data format");
|
|
2115
2102
|
try {
|
|
@@ -2119,8 +2106,8 @@ var useCrudifyUser = (options = {}) => {
|
|
|
2119
2106
|
const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
2120
2107
|
console.log("\u{1F464} useCrudifyUser - Parsed nested data:", parsedData);
|
|
2121
2108
|
if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
|
|
2122
|
-
|
|
2123
|
-
console.log("\u{1F464} useCrudifyUser - Extracted user from nested items:",
|
|
2109
|
+
userData2 = parsedData.items[0];
|
|
2110
|
+
console.log("\u{1F464} useCrudifyUser - Extracted user from nested items:", userData2);
|
|
2124
2111
|
} else {
|
|
2125
2112
|
console.log("\u{1F464} useCrudifyUser - No items found in parsed data or items array is empty");
|
|
2126
2113
|
}
|
|
@@ -2131,7 +2118,7 @@ var useCrudifyUser = (options = {}) => {
|
|
|
2131
2118
|
console.log("\u{1F464} useCrudifyUser - Found object format, checking for items");
|
|
2132
2119
|
if (response.data.items && Array.isArray(response.data.items) && response.data.items.length > 0) {
|
|
2133
2120
|
console.log("\u{1F464} useCrudifyUser - Found items in object format");
|
|
2134
|
-
|
|
2121
|
+
userData2 = response.data.items[0];
|
|
2135
2122
|
} else {
|
|
2136
2123
|
console.log("\u{1F464} useCrudifyUser - No items found in object format");
|
|
2137
2124
|
}
|
|
@@ -2143,77 +2130,34 @@ var useCrudifyUser = (options = {}) => {
|
|
|
2143
2130
|
const parsedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
2144
2131
|
console.log("\u{1F464} useCrudifyUser - Parsed double-nested data:", parsedData);
|
|
2145
2132
|
if (parsedData && parsedData.items && Array.isArray(parsedData.items) && parsedData.items.length > 0) {
|
|
2146
|
-
|
|
2147
|
-
console.log("\u{1F464} useCrudifyUser - Extracted user from double-nested items:",
|
|
2133
|
+
userData2 = parsedData.items[0];
|
|
2134
|
+
console.log("\u{1F464} useCrudifyUser - Extracted user from double-nested items:", userData2);
|
|
2148
2135
|
}
|
|
2149
2136
|
} catch (parseError) {
|
|
2150
2137
|
console.error("\u{1F464} useCrudifyUser - Error parsing double-nested response data:", parseError);
|
|
2151
2138
|
}
|
|
2152
2139
|
}
|
|
2153
2140
|
}
|
|
2154
|
-
if (
|
|
2155
|
-
console.log("\u{1F464} useCrudifyUser - User data found:",
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
fullProfile: userData,
|
|
2159
|
-
totalFields: Object.keys(userData).length,
|
|
2160
|
-
displayData: {
|
|
2161
|
-
id: userData.id || userData._id,
|
|
2162
|
-
email: userData.email,
|
|
2163
|
-
username: userData.username,
|
|
2164
|
-
firstName: userData.firstName || userData.name,
|
|
2165
|
-
lastName: userData.lastName,
|
|
2166
|
-
fullName: userData.fullName || `${userData.firstName || userData.name || ""} ${userData.lastName || ""}`.trim() || null,
|
|
2167
|
-
role: userData.role,
|
|
2168
|
-
permissions: userData.permissions || [],
|
|
2169
|
-
isActive: userData.isActive,
|
|
2170
|
-
lastLogin: userData.lastLogin,
|
|
2171
|
-
createdAt: userData.createdAt,
|
|
2172
|
-
updatedAt: userData.updatedAt,
|
|
2173
|
-
// Include any custom fields
|
|
2174
|
-
...Object.keys(userData).filter(
|
|
2175
|
-
(key) => ![
|
|
2176
|
-
"id",
|
|
2177
|
-
"_id",
|
|
2178
|
-
"email",
|
|
2179
|
-
"username",
|
|
2180
|
-
"firstName",
|
|
2181
|
-
"name",
|
|
2182
|
-
"lastName",
|
|
2183
|
-
"fullName",
|
|
2184
|
-
"role",
|
|
2185
|
-
"permissions",
|
|
2186
|
-
"isActive",
|
|
2187
|
-
"lastLogin",
|
|
2188
|
-
"createdAt",
|
|
2189
|
-
"updatedAt"
|
|
2190
|
-
].includes(key)
|
|
2191
|
-
).reduce((acc, key) => ({ ...acc, [key]: userData[key] }), {})
|
|
2192
|
-
}
|
|
2193
|
-
};
|
|
2194
|
-
setExtendedData(extended);
|
|
2195
|
-
setProfileError(null);
|
|
2141
|
+
if (userData2) {
|
|
2142
|
+
console.log("\u{1F464} useCrudifyUser - User data found:", userData2);
|
|
2143
|
+
setUserData(userData2);
|
|
2144
|
+
setError(null);
|
|
2196
2145
|
retryCountRef.current = 0;
|
|
2197
|
-
console.log("\u{1F464} useCrudifyUser - Profile loaded successfully:",
|
|
2146
|
+
console.log("\u{1F464} useCrudifyUser - Profile loaded successfully:", userData2);
|
|
2198
2147
|
} else {
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
fullProfile: null,
|
|
2203
|
-
totalFields: 0,
|
|
2204
|
-
displayData: {}
|
|
2205
|
-
});
|
|
2206
|
-
console.warn("\u{1F464} useCrudifyUser - User not found for email:", userEmail2);
|
|
2148
|
+
setError("User profile not found in database");
|
|
2149
|
+
setUserData(null);
|
|
2150
|
+
console.warn("\u{1F464} useCrudifyUser - User not found for email:", userEmail);
|
|
2207
2151
|
}
|
|
2208
2152
|
}
|
|
2209
2153
|
} catch (err) {
|
|
2210
2154
|
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
2211
|
-
const
|
|
2212
|
-
console.error("\u{1F464} useCrudifyUser - Error fetching profile:",
|
|
2213
|
-
if (
|
|
2155
|
+
const error2 = err;
|
|
2156
|
+
console.error("\u{1F464} useCrudifyUser - Error fetching profile:", error2);
|
|
2157
|
+
if (error2.name === "AbortError") {
|
|
2214
2158
|
return;
|
|
2215
2159
|
}
|
|
2216
|
-
const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (
|
|
2160
|
+
const shouldRetry = retryOnError && retryCountRef.current < maxRetries && (error2.message?.includes("Network Error") || error2.message?.includes("Failed to fetch"));
|
|
2217
2161
|
if (shouldRetry) {
|
|
2218
2162
|
retryCountRef.current++;
|
|
2219
2163
|
console.log(`\u{1F464} useCrudifyUser - Retrying profile fetch (${retryCountRef.current}/${maxRetries})`);
|
|
@@ -2223,24 +2167,19 @@ var useCrudifyUser = (options = {}) => {
|
|
|
2223
2167
|
}
|
|
2224
2168
|
}, 1e3 * retryCountRef.current);
|
|
2225
2169
|
} else {
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
setExtendedData({
|
|
2229
|
-
fullProfile: null,
|
|
2230
|
-
totalFields: 0,
|
|
2231
|
-
displayData: {}
|
|
2232
|
-
});
|
|
2170
|
+
setError("Failed to load user profile from database");
|
|
2171
|
+
setUserData(null);
|
|
2233
2172
|
}
|
|
2234
2173
|
}
|
|
2235
2174
|
} finally {
|
|
2236
2175
|
if (currentRequestId === requestIdRef.current && mountedRef.current) {
|
|
2237
|
-
|
|
2176
|
+
setLoading(false);
|
|
2238
2177
|
}
|
|
2239
2178
|
if (abortControllerRef.current === abortController) {
|
|
2240
2179
|
abortControllerRef.current = null;
|
|
2241
2180
|
}
|
|
2242
2181
|
}
|
|
2243
|
-
}, [isInitialized,
|
|
2182
|
+
}, [isInitialized, getUserEmailFromJWT, retryOnError, maxRetries]);
|
|
2244
2183
|
useEffect8(() => {
|
|
2245
2184
|
if (autoFetch && isAuthenticated && isInitialized) {
|
|
2246
2185
|
refreshProfile();
|
|
@@ -2258,19 +2197,14 @@ var useCrudifyUser = (options = {}) => {
|
|
|
2258
2197
|
}
|
|
2259
2198
|
};
|
|
2260
2199
|
}, []);
|
|
2261
|
-
const
|
|
2200
|
+
const user = {
|
|
2201
|
+
session: jwtUser,
|
|
2202
|
+
data: userData
|
|
2203
|
+
};
|
|
2262
2204
|
return {
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
userIdentifier,
|
|
2267
|
-
// Perfil completo desde BD
|
|
2268
|
-
userProfile,
|
|
2269
|
-
profileLoading,
|
|
2270
|
-
profileError,
|
|
2271
|
-
// Datos extendidos formateados
|
|
2272
|
-
extendedData,
|
|
2273
|
-
// Acciones
|
|
2205
|
+
user,
|
|
2206
|
+
loading,
|
|
2207
|
+
error,
|
|
2274
2208
|
refreshProfile,
|
|
2275
2209
|
clearProfile
|
|
2276
2210
|
};
|
|
@@ -2454,7 +2388,7 @@ var useCrudifyInstance = () => {
|
|
|
2454
2388
|
}
|
|
2455
2389
|
try {
|
|
2456
2390
|
console.log("\u{1F504} useCrudifyInstance - waitForReady: Using CrudifyInitializer.waitForInitialization()");
|
|
2457
|
-
const { crudifyInitializer: crudifyInitializer2 } = await import("./CrudifyDataProvider-
|
|
2391
|
+
const { crudifyInitializer: crudifyInitializer2 } = await import("./CrudifyDataProvider-BLW4PCVZ.mjs");
|
|
2458
2392
|
await crudifyInitializer2.waitForInitialization();
|
|
2459
2393
|
console.log("\u2705 useCrudifyInstance - waitForReady: CrudifyInitializer completed");
|
|
2460
2394
|
if (!crudifyInitializer2.isReady()) {
|
|
@@ -2596,7 +2530,7 @@ var useCrudifyInstance = () => {
|
|
|
2596
2530
|
};
|
|
2597
2531
|
var getCrudifyInstanceAsync = async () => {
|
|
2598
2532
|
console.log("\u{1F504} getCrudifyInstanceAsync - Starting");
|
|
2599
|
-
const { crudifyInitializer: crudifyInitializer2 } = await import("./CrudifyDataProvider-
|
|
2533
|
+
const { crudifyInitializer: crudifyInitializer2 } = await import("./CrudifyDataProvider-BLW4PCVZ.mjs");
|
|
2600
2534
|
console.log("\u{1F504} getCrudifyInstanceAsync - Checking if ready");
|
|
2601
2535
|
console.log(" - crudifyInitializer.isReady():", crudifyInitializer2.isReady());
|
|
2602
2536
|
console.log(" - crudifyInitializer.getStatus():", crudifyInitializer2.getStatus());
|
|
@@ -2615,7 +2549,7 @@ var getCrudifyInstanceAsync = async () => {
|
|
|
2615
2549
|
return crudify5;
|
|
2616
2550
|
};
|
|
2617
2551
|
var getCrudifyInstanceSync = async () => {
|
|
2618
|
-
const { crudifyInitializer: crudifyInitializer2 } = await import("./CrudifyDataProvider-
|
|
2552
|
+
const { crudifyInitializer: crudifyInitializer2 } = await import("./CrudifyDataProvider-BLW4PCVZ.mjs");
|
|
2619
2553
|
if (!crudifyInitializer2.isReady()) {
|
|
2620
2554
|
throw new Error("Crudify not ready. Use getCrudifyInstanceAsync() or call this from within a React component using useCrudifyInstance()");
|
|
2621
2555
|
}
|