@oxyhq/services 5.8.11 → 5.9.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/lib/commonjs/core/index.js +207 -283
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/node/index.js +0 -9
- package/lib/commonjs/node/index.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +3 -9
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +0 -4
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js +0 -4
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +16 -27
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignUpScreen.js +4 -18
- package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +1 -2
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
- package/lib/module/core/index.js +207 -283
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/node/index.js +0 -4
- package/lib/module/node/index.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +3 -9
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +0 -4
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/RecoverAccountScreen.js +0 -4
- package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +16 -27
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/SignUpScreen.js +4 -18
- package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +1 -2
- package/lib/module/ui/styles/authStyles.js.map +1 -1
- package/lib/typescript/core/index.d.ts +29 -79
- package/lib/typescript/core/index.d.ts.map +1 -1
- package/lib/typescript/node/index.d.ts +0 -2
- package/lib/typescript/node/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/screens/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +0 -1
- package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/core/index.ts +213 -254
- package/src/node/index.ts +0 -4
- package/src/ui/components/OxyProvider.tsx +3 -9
- package/src/ui/screens/FeedbackScreen.tsx +0 -4
- package/src/ui/screens/RecoverAccountScreen.tsx +0 -4
- package/src/ui/screens/SignInScreen.tsx +16 -20
- package/src/ui/screens/SignUpScreen.tsx +4 -14
- package/src/ui/styles/authStyles.ts +0 -1
- package/lib/commonjs/node/createAuth.js +0 -95
- package/lib/commonjs/node/createAuth.js.map +0 -1
- package/lib/module/node/createAuth.js +0 -90
- package/lib/module/node/createAuth.js.map +0 -1
- package/lib/typescript/node/createAuth.d.ts +0 -7
- package/lib/typescript/node/createAuth.d.ts.map +0 -1
- package/src/node/createAuth.ts +0 -116
package/src/core/index.ts
CHANGED
|
@@ -66,7 +66,6 @@ export class OxyServices {
|
|
|
66
66
|
private client: AxiosInstance;
|
|
67
67
|
private accessToken: string | null = null;
|
|
68
68
|
private refreshToken: string | null = null;
|
|
69
|
-
private refreshPromise: Promise<{ accessToken: string; refreshToken: string }> | null = null;
|
|
70
69
|
|
|
71
70
|
/**
|
|
72
71
|
* Creates a new instance of the OxyServices client
|
|
@@ -82,14 +81,25 @@ export class OxyServices {
|
|
|
82
81
|
this.client.interceptors.request.use(async (req: InternalAxiosRequestConfig) => {
|
|
83
82
|
if (!this.accessToken) {
|
|
84
83
|
return req;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Check if token is expired and refresh if needed
|
|
87
|
+
try {
|
|
88
|
+
const decoded = jwtDecode<JwtPayload>(this.accessToken);
|
|
89
|
+
const currentTime = Math.floor(Date.now() / 1000);
|
|
90
|
+
|
|
90
91
|
// If token expires in less than 60 seconds, refresh it
|
|
91
92
|
if (decoded.exp - currentTime < 60) {
|
|
92
|
-
|
|
93
|
+
// For session-based tokens, get a new token from the session
|
|
94
|
+
if (decoded.sessionId) {
|
|
95
|
+
try {
|
|
96
|
+
const res = await this.client.get(`/secure-session/token/${decoded.sessionId}`);
|
|
97
|
+
this.accessToken = res.data.accessToken;
|
|
98
|
+
} catch (refreshError) {
|
|
99
|
+
// If refresh fails, clear tokens
|
|
100
|
+
this.clearTokens();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
93
103
|
}
|
|
94
104
|
} catch (error) {
|
|
95
105
|
// If token can't be decoded, continue with request and let server handle it
|
|
@@ -109,19 +119,25 @@ export class OxyServices {
|
|
|
109
119
|
// If the error is due to an expired token and we haven't tried refreshing yet
|
|
110
120
|
if (
|
|
111
121
|
error.response?.status === 401 &&
|
|
112
|
-
this.
|
|
122
|
+
this.accessToken &&
|
|
113
123
|
originalRequest &&
|
|
114
124
|
!originalRequest.headers?.['X-Retry-After-Refresh']
|
|
115
125
|
) {
|
|
116
126
|
try {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
127
|
+
// Check if token is session-based and try to refresh
|
|
128
|
+
const decoded = jwtDecode<JwtPayload>(this.accessToken);
|
|
129
|
+
if (decoded.sessionId) {
|
|
130
|
+
const res = await this.client.get(`/secure-session/token/${decoded.sessionId}`);
|
|
131
|
+
this.accessToken = res.data.accessToken;
|
|
132
|
+
|
|
133
|
+
// Retry the original request with new token
|
|
134
|
+
const newRequest = { ...originalRequest };
|
|
135
|
+
if (newRequest.headers) {
|
|
136
|
+
newRequest.headers.Authorization = `Bearer ${this.accessToken}`;
|
|
137
|
+
newRequest.headers['X-Retry-After-Refresh'] = 'true';
|
|
138
|
+
}
|
|
139
|
+
return this.client(newRequest);
|
|
123
140
|
}
|
|
124
|
-
return this.client(newRequest);
|
|
125
141
|
} catch (refreshError) {
|
|
126
142
|
// If refresh fails, force user to login again
|
|
127
143
|
this.clearTokens();
|
|
@@ -156,44 +172,17 @@ export class OxyServices {
|
|
|
156
172
|
}
|
|
157
173
|
|
|
158
174
|
/**
|
|
159
|
-
*
|
|
160
|
-
* @
|
|
161
|
-
|
|
162
|
-
public getCurrentUserId(): string | null {
|
|
163
|
-
if (!this.accessToken) return null;
|
|
164
|
-
|
|
165
|
-
try {
|
|
166
|
-
const decoded = jwtDecode<JwtPayload>(this.accessToken);
|
|
167
|
-
|
|
168
|
-
// Check for both userId (preferred) and id (fallback) for compatibility
|
|
169
|
-
return decoded.userId || (decoded as any).id || null;
|
|
170
|
-
} catch (error) {
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Internal method to check if we have an access token
|
|
177
|
-
* @private
|
|
178
|
-
* @returns Boolean indicating if access token exists
|
|
179
|
-
* @internal - Use `isAuthenticated` from useOxy() context in UI components instead
|
|
175
|
+
* Set authentication tokens manually
|
|
176
|
+
* @param accessToken - The access token
|
|
177
|
+
* @param refreshToken - The refresh token (optional for session-based auth)
|
|
180
178
|
*/
|
|
181
|
-
|
|
182
|
-
return this.accessToken !== null;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Sets authentication tokens directly (useful for initializing from storage)
|
|
187
|
-
* @param accessToken - JWT access token
|
|
188
|
-
* @param refreshToken - Refresh token for getting new access tokens
|
|
189
|
-
*/
|
|
190
|
-
public setTokens(accessToken: string, refreshToken: string): void {
|
|
179
|
+
public setTokens(accessToken: string, refreshToken: string = ''): void {
|
|
191
180
|
this.accessToken = accessToken;
|
|
192
181
|
this.refreshToken = refreshToken;
|
|
193
182
|
}
|
|
194
|
-
|
|
183
|
+
|
|
195
184
|
/**
|
|
196
|
-
*
|
|
185
|
+
* Clear stored authentication tokens
|
|
197
186
|
*/
|
|
198
187
|
public clearTokens(): void {
|
|
199
188
|
this.accessToken = null;
|
|
@@ -201,89 +190,28 @@ export class OxyServices {
|
|
|
201
190
|
}
|
|
202
191
|
|
|
203
192
|
/**
|
|
204
|
-
*
|
|
205
|
-
* @
|
|
206
|
-
* @param email - User's email address
|
|
207
|
-
* @param password - User's password
|
|
208
|
-
* @returns Object containing the message, token and user data
|
|
193
|
+
* Get the current user ID from the stored token
|
|
194
|
+
* @returns User ID or null if not authenticated
|
|
209
195
|
*/
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const res = await this.client.post('/auth/signup', { username, email, password });
|
|
213
|
-
const { message, token, user } = res.data;
|
|
214
|
-
this.accessToken = token;
|
|
215
|
-
return { message, token, user };
|
|
216
|
-
} catch (error) {
|
|
217
|
-
throw this.handleError(error);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Log in and store tokens
|
|
223
|
-
* @param username - User's username or email
|
|
224
|
-
* @param password - User's password
|
|
225
|
-
* @returns Login response containing tokens and user data
|
|
226
|
-
*/
|
|
227
|
-
async login(username: string, password: string): Promise<LoginResponse> {
|
|
228
|
-
try {
|
|
229
|
-
const res = await this.client.post('/auth/login', { username, password });
|
|
230
|
-
const { accessToken, refreshToken, user } = res.data;
|
|
231
|
-
this.accessToken = accessToken;
|
|
232
|
-
this.refreshToken = refreshToken;
|
|
233
|
-
return { accessToken, refreshToken, user };
|
|
234
|
-
} catch (error) {
|
|
235
|
-
throw this.handleError(error);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Log out user
|
|
241
|
-
*/
|
|
242
|
-
async logout(): Promise<void> {
|
|
243
|
-
if (!this.refreshToken) return;
|
|
196
|
+
public getCurrentUserId(): string | null {
|
|
197
|
+
if (!this.accessToken) return null;
|
|
244
198
|
|
|
245
199
|
try {
|
|
246
|
-
|
|
200
|
+
const decoded = jwtDecode<JwtPayload>(this.accessToken);
|
|
201
|
+
return decoded.userId || decoded.id || null;
|
|
247
202
|
} catch (error) {
|
|
248
|
-
|
|
249
|
-
} finally {
|
|
250
|
-
this.accessToken = null;
|
|
251
|
-
this.refreshToken = null;
|
|
203
|
+
return null;
|
|
252
204
|
}
|
|
253
205
|
}
|
|
254
|
-
|
|
206
|
+
|
|
255
207
|
/**
|
|
256
|
-
*
|
|
257
|
-
* @
|
|
208
|
+
* Internal method to check if we have an access token
|
|
209
|
+
* @private
|
|
210
|
+
* @returns Boolean indicating if access token exists
|
|
211
|
+
* @internal - Use `isAuthenticated` from useOxy() context in UI components instead
|
|
258
212
|
*/
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
throw new Error('No refresh token available');
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// If a refresh is already in progress, return that promise
|
|
265
|
-
if (this.refreshPromise) {
|
|
266
|
-
return this.refreshPromise;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Create a new refresh promise
|
|
270
|
-
this.refreshPromise = (async () => {
|
|
271
|
-
try {
|
|
272
|
-
const res = await this.client.post('/auth/refresh', { refreshToken: this.refreshToken });
|
|
273
|
-
const { accessToken, refreshToken } = res.data;
|
|
274
|
-
this.accessToken = accessToken;
|
|
275
|
-
this.refreshToken = refreshToken;
|
|
276
|
-
return { accessToken, refreshToken };
|
|
277
|
-
} catch (error) {
|
|
278
|
-
this.accessToken = null;
|
|
279
|
-
this.refreshToken = null;
|
|
280
|
-
throw this.handleError(error);
|
|
281
|
-
} finally {
|
|
282
|
-
this.refreshPromise = null;
|
|
283
|
-
}
|
|
284
|
-
})();
|
|
285
|
-
|
|
286
|
-
return this.refreshPromise;
|
|
213
|
+
private hasAccessToken(): boolean {
|
|
214
|
+
return this.accessToken !== null;
|
|
287
215
|
}
|
|
288
216
|
|
|
289
217
|
/**
|
|
@@ -292,6 +220,22 @@ export class OxyServices {
|
|
|
292
220
|
*/
|
|
293
221
|
async validate(): Promise<boolean> {
|
|
294
222
|
try {
|
|
223
|
+
// Check if token contains sessionId (new session-based system)
|
|
224
|
+
if (this.accessToken) {
|
|
225
|
+
try {
|
|
226
|
+
const decoded = jwtDecode<JwtPayload>(this.accessToken);
|
|
227
|
+
if (decoded.sessionId) {
|
|
228
|
+
// Use session-based validation
|
|
229
|
+
const res = await this.client.get(`/secure-session/validate/${decoded.sessionId}`);
|
|
230
|
+
return res.data.valid;
|
|
231
|
+
}
|
|
232
|
+
} catch (decodeError) {
|
|
233
|
+
// If token can't be decoded, fall back to old validation
|
|
234
|
+
console.warn('Error decoding JWT token for session validation:', decodeError);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Fall back to old validation method
|
|
295
239
|
const res = await this.client.get('/auth/validate');
|
|
296
240
|
return res.data.valid;
|
|
297
241
|
} catch (error) {
|
|
@@ -301,59 +245,6 @@ export class OxyServices {
|
|
|
301
245
|
|
|
302
246
|
/* Session Management Methods */
|
|
303
247
|
|
|
304
|
-
/**
|
|
305
|
-
* Get active sessions for the authenticated user
|
|
306
|
-
* @returns Array of active session objects
|
|
307
|
-
*/
|
|
308
|
-
async getUserSessions(): Promise<any[]> {
|
|
309
|
-
try {
|
|
310
|
-
const res = await this.client.get('/sessions');
|
|
311
|
-
return res.data;
|
|
312
|
-
} catch (error) {
|
|
313
|
-
throw this.handleError(error);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Logout from a specific session
|
|
319
|
-
* @param sessionId - The session ID to logout from
|
|
320
|
-
* @returns Success status
|
|
321
|
-
*/
|
|
322
|
-
async logoutSession(sessionId: string): Promise<{ success: boolean; message: string }> {
|
|
323
|
-
try {
|
|
324
|
-
const res = await this.client.delete(`/sessions/${sessionId}`);
|
|
325
|
-
return res.data;
|
|
326
|
-
} catch (error) {
|
|
327
|
-
throw this.handleError(error);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Logout from all other sessions (keep current session active)
|
|
333
|
-
* @returns Success status
|
|
334
|
-
*/
|
|
335
|
-
async logoutOtherSessions(): Promise<{ success: boolean; message: string }> {
|
|
336
|
-
try {
|
|
337
|
-
const res = await this.client.post('/sessions/logout-others');
|
|
338
|
-
return res.data;
|
|
339
|
-
} catch (error) {
|
|
340
|
-
throw this.handleError(error);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Logout from all sessions
|
|
346
|
-
* @returns Success status
|
|
347
|
-
*/
|
|
348
|
-
async logoutAllSessions(): Promise<{ success: boolean; message: string }> {
|
|
349
|
-
try {
|
|
350
|
-
const res = await this.client.post('/sessions/logout-all');
|
|
351
|
-
return res.data;
|
|
352
|
-
} catch (error) {
|
|
353
|
-
throw this.handleError(error);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
248
|
/**
|
|
358
249
|
* Get device sessions for a specific session ID
|
|
359
250
|
* @param sessionId - The session ID to get device sessions for
|
|
@@ -1177,12 +1068,41 @@ export class OxyServices {
|
|
|
1177
1068
|
}
|
|
1178
1069
|
|
|
1179
1070
|
/**
|
|
1180
|
-
*
|
|
1071
|
+
* Sign up a new user and create a session
|
|
1072
|
+
* @param username - Desired username
|
|
1073
|
+
* @param email - User's email address
|
|
1074
|
+
* @param password - User's password
|
|
1075
|
+
* @returns Object containing the message, token and user data
|
|
1076
|
+
*/
|
|
1077
|
+
async signUp(username: string, email: string, password: string): Promise<{ message: string; token: string; user: User }> {
|
|
1078
|
+
try {
|
|
1079
|
+
// First, create the user account
|
|
1080
|
+
const res = await this.client.post('/secure-session/register', { username, email, password });
|
|
1081
|
+
const { message, user } = res.data;
|
|
1082
|
+
|
|
1083
|
+
// Then log them in to create a session
|
|
1084
|
+
const loginRes = await this.secureLogin(username, password);
|
|
1085
|
+
|
|
1086
|
+
// Get the access token for the session
|
|
1087
|
+
const tokenRes = await this.getTokenBySession(loginRes.sessionId);
|
|
1088
|
+
|
|
1089
|
+
return {
|
|
1090
|
+
message,
|
|
1091
|
+
token: tokenRes.accessToken,
|
|
1092
|
+
user: loginRes.user as User
|
|
1093
|
+
};
|
|
1094
|
+
} catch (error) {
|
|
1095
|
+
throw this.handleError(error);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/**
|
|
1100
|
+
* Secure login that creates a device-based session
|
|
1181
1101
|
* @param username - User's username or email
|
|
1182
1102
|
* @param password - User's password
|
|
1183
|
-
* @param deviceName - Optional device name
|
|
1184
|
-
* @param deviceFingerprint -
|
|
1185
|
-
* @returns
|
|
1103
|
+
* @param deviceName - Optional device name
|
|
1104
|
+
* @param deviceFingerprint - Optional device fingerprint
|
|
1105
|
+
* @returns Login response with session data
|
|
1186
1106
|
*/
|
|
1187
1107
|
async secureLogin(username: string, password: string, deviceName?: string, deviceFingerprint?: any): Promise<SecureLoginResponse> {
|
|
1188
1108
|
try {
|
|
@@ -1395,19 +1315,50 @@ export class OxyServices {
|
|
|
1395
1315
|
});
|
|
1396
1316
|
}
|
|
1397
1317
|
|
|
1398
|
-
//
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
});
|
|
1402
|
-
tempOxyServices.setTokens(token, ''); // Set access token
|
|
1403
|
-
|
|
1404
|
-
// Validate token using the validate method
|
|
1405
|
-
const isValid = await tempOxyServices.validate();
|
|
1318
|
+
// Check if token contains sessionId (new session-based system)
|
|
1319
|
+
let isValid = false;
|
|
1320
|
+
let userId: string | null = null;
|
|
1406
1321
|
|
|
1407
|
-
|
|
1322
|
+
try {
|
|
1323
|
+
const decoded = jwtDecode<JwtPayload>(token);
|
|
1324
|
+
userId = decoded.userId || decoded.id;
|
|
1325
|
+
|
|
1326
|
+
if (decoded.sessionId) {
|
|
1327
|
+
// Use session-based validation
|
|
1328
|
+
const tempOxyServices = new OxyServices({
|
|
1329
|
+
baseURL: this.client.defaults.baseURL || ''
|
|
1330
|
+
});
|
|
1331
|
+
tempOxyServices.setTokens(token, '');
|
|
1332
|
+
|
|
1333
|
+
const validation = await tempOxyServices.validateSession(decoded.sessionId);
|
|
1334
|
+
isValid = validation.valid;
|
|
1335
|
+
|
|
1336
|
+
if (isValid && loadFullUser) {
|
|
1337
|
+
req.user = validation.user;
|
|
1338
|
+
}
|
|
1339
|
+
} else {
|
|
1340
|
+
// Use old validation method
|
|
1341
|
+
const tempOxyServices = new OxyServices({
|
|
1342
|
+
baseURL: this.client.defaults.baseURL || ''
|
|
1343
|
+
});
|
|
1344
|
+
tempOxyServices.setTokens(token, '');
|
|
1345
|
+
|
|
1346
|
+
isValid = await tempOxyServices.validate();
|
|
1347
|
+
|
|
1348
|
+
if (isValid && loadFullUser) {
|
|
1349
|
+
try {
|
|
1350
|
+
const userProfile = await tempOxyServices.getUserById(userId!);
|
|
1351
|
+
req.user = userProfile;
|
|
1352
|
+
} catch (userError) {
|
|
1353
|
+
// If we can't load user, continue with just ID
|
|
1354
|
+
req.user = { id: userId };
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
} catch (decodeError) {
|
|
1408
1359
|
const error = {
|
|
1409
|
-
message: 'Invalid
|
|
1410
|
-
code: '
|
|
1360
|
+
message: 'Invalid token payload',
|
|
1361
|
+
code: 'INVALID_PAYLOAD',
|
|
1411
1362
|
status: 403
|
|
1412
1363
|
};
|
|
1413
1364
|
|
|
@@ -1416,20 +1367,15 @@ export class OxyServices {
|
|
|
1416
1367
|
}
|
|
1417
1368
|
|
|
1418
1369
|
return res.status(403).json({
|
|
1419
|
-
message: 'Invalid
|
|
1420
|
-
code: '
|
|
1370
|
+
message: 'Invalid token payload',
|
|
1371
|
+
code: 'INVALID_PAYLOAD'
|
|
1421
1372
|
});
|
|
1422
1373
|
}
|
|
1423
1374
|
|
|
1424
|
-
|
|
1425
|
-
let userId: string | null = null;
|
|
1426
|
-
try {
|
|
1427
|
-
const decoded = jwtDecode<JwtPayload>(token);
|
|
1428
|
-
userId = decoded.userId || decoded.id;
|
|
1429
|
-
} catch (decodeError) {
|
|
1375
|
+
if (!isValid) {
|
|
1430
1376
|
const error = {
|
|
1431
|
-
message: 'Invalid token
|
|
1432
|
-
code: '
|
|
1377
|
+
message: 'Invalid or expired token',
|
|
1378
|
+
code: 'INVALID_TOKEN',
|
|
1433
1379
|
status: 403
|
|
1434
1380
|
};
|
|
1435
1381
|
|
|
@@ -1438,8 +1384,8 @@ export class OxyServices {
|
|
|
1438
1384
|
}
|
|
1439
1385
|
|
|
1440
1386
|
return res.status(403).json({
|
|
1441
|
-
message: 'Invalid token
|
|
1442
|
-
code: '
|
|
1387
|
+
message: 'Invalid or expired token',
|
|
1388
|
+
code: 'INVALID_TOKEN'
|
|
1443
1389
|
});
|
|
1444
1390
|
}
|
|
1445
1391
|
|
|
@@ -1464,16 +1410,8 @@ export class OxyServices {
|
|
|
1464
1410
|
req.userId = userId;
|
|
1465
1411
|
req.accessToken = token;
|
|
1466
1412
|
|
|
1467
|
-
//
|
|
1468
|
-
if (
|
|
1469
|
-
try {
|
|
1470
|
-
const userProfile = await tempOxyServices.getUserById(userId);
|
|
1471
|
-
req.user = userProfile;
|
|
1472
|
-
} catch (userError) {
|
|
1473
|
-
// If we can't load user, continue with just ID
|
|
1474
|
-
req.user = { id: userId };
|
|
1475
|
-
}
|
|
1476
|
-
} else {
|
|
1413
|
+
// Set user object if not already set by session validation
|
|
1414
|
+
if (!req.user) {
|
|
1477
1415
|
req.user = { id: userId };
|
|
1478
1416
|
}
|
|
1479
1417
|
|
|
@@ -1513,55 +1451,76 @@ export class OxyServices {
|
|
|
1513
1451
|
};
|
|
1514
1452
|
}
|
|
1515
1453
|
|
|
1516
|
-
//
|
|
1517
|
-
const tempOxyServices = new OxyServices({
|
|
1518
|
-
baseURL: this.client.defaults.baseURL || ''
|
|
1519
|
-
});
|
|
1520
|
-
tempOxyServices.setTokens(token, '');
|
|
1521
|
-
|
|
1522
|
-
// Validate token
|
|
1523
|
-
const isValid = await tempOxyServices.validate();
|
|
1524
|
-
|
|
1525
|
-
if (!isValid) {
|
|
1526
|
-
return {
|
|
1527
|
-
valid: false,
|
|
1528
|
-
error: 'Invalid or expired token'
|
|
1529
|
-
};
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
// Get user ID from token using JWT decode
|
|
1533
|
-
let userId: string | null = null;
|
|
1454
|
+
// Check if token contains sessionId (new session-based system)
|
|
1534
1455
|
try {
|
|
1535
1456
|
const decoded = jwtDecode<JwtPayload>(token);
|
|
1536
|
-
userId = decoded.userId || decoded.id;
|
|
1457
|
+
const userId = decoded.userId || decoded.id;
|
|
1458
|
+
|
|
1459
|
+
if (decoded.sessionId) {
|
|
1460
|
+
// Use session-based validation
|
|
1461
|
+
const tempOxyServices = new OxyServices({
|
|
1462
|
+
baseURL: this.client.defaults.baseURL || ''
|
|
1463
|
+
});
|
|
1464
|
+
tempOxyServices.setTokens(token, '');
|
|
1465
|
+
|
|
1466
|
+
const validation = await tempOxyServices.validateSession(decoded.sessionId);
|
|
1467
|
+
|
|
1468
|
+
if (validation.valid) {
|
|
1469
|
+
return {
|
|
1470
|
+
valid: true,
|
|
1471
|
+
userId,
|
|
1472
|
+
user: validation.user
|
|
1473
|
+
};
|
|
1474
|
+
} else {
|
|
1475
|
+
return {
|
|
1476
|
+
valid: false,
|
|
1477
|
+
error: 'Invalid or expired session'
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
} else {
|
|
1481
|
+
// Use old validation method
|
|
1482
|
+
const tempOxyServices = new OxyServices({
|
|
1483
|
+
baseURL: this.client.defaults.baseURL || ''
|
|
1484
|
+
});
|
|
1485
|
+
tempOxyServices.setTokens(token, '');
|
|
1486
|
+
|
|
1487
|
+
const isValid = await tempOxyServices.validate();
|
|
1488
|
+
|
|
1489
|
+
if (!isValid) {
|
|
1490
|
+
return {
|
|
1491
|
+
valid: false,
|
|
1492
|
+
error: 'Invalid or expired token'
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
if (!userId) {
|
|
1497
|
+
return {
|
|
1498
|
+
valid: false,
|
|
1499
|
+
error: 'Invalid token payload'
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
// Try to get user profile
|
|
1504
|
+
let user;
|
|
1505
|
+
try {
|
|
1506
|
+
user = await tempOxyServices.getUserById(userId);
|
|
1507
|
+
} catch (error) {
|
|
1508
|
+
// Continue without full user data
|
|
1509
|
+
user = { id: userId };
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
return {
|
|
1513
|
+
valid: true,
|
|
1514
|
+
userId,
|
|
1515
|
+
user
|
|
1516
|
+
};
|
|
1517
|
+
}
|
|
1537
1518
|
} catch (decodeError) {
|
|
1538
1519
|
return {
|
|
1539
1520
|
valid: false,
|
|
1540
1521
|
error: 'Invalid token payload'
|
|
1541
1522
|
};
|
|
1542
1523
|
}
|
|
1543
|
-
|
|
1544
|
-
if (!userId) {
|
|
1545
|
-
return {
|
|
1546
|
-
valid: false,
|
|
1547
|
-
error: 'Invalid token payload'
|
|
1548
|
-
};
|
|
1549
|
-
}
|
|
1550
|
-
|
|
1551
|
-
// Try to get user profile
|
|
1552
|
-
let user;
|
|
1553
|
-
try {
|
|
1554
|
-
user = await tempOxyServices.getUserById(userId);
|
|
1555
|
-
} catch (error) {
|
|
1556
|
-
// Continue without full user data
|
|
1557
|
-
user = { id: userId };
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
return {
|
|
1561
|
-
valid: true,
|
|
1562
|
-
userId,
|
|
1563
|
-
user
|
|
1564
|
-
};
|
|
1565
1524
|
} catch (error) {
|
|
1566
1525
|
return {
|
|
1567
1526
|
valid: false,
|
package/src/node/index.ts
CHANGED
|
@@ -4,15 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
// ------------- Core Imports -------------
|
|
6
6
|
import { OxyServices, OXY_CLOUD_URL } from '../core'; // Adjusted path
|
|
7
|
-
import { createAuth } from './createAuth';
|
|
8
7
|
import * as Models from '../models/interfaces'; // Adjusted path
|
|
9
8
|
|
|
10
9
|
// ------------- Core Exports -------------
|
|
11
10
|
export { OxyServices, OXY_CLOUD_URL };
|
|
12
11
|
|
|
13
|
-
// Zero-config auth and session router
|
|
14
|
-
export { createAuth };
|
|
15
|
-
|
|
16
12
|
// ------------- Model Exports -------------
|
|
17
13
|
export { Models }; // Export all models as a namespace
|
|
18
14
|
export * from '../models/interfaces'; // Export all models directly
|
|
@@ -148,9 +148,6 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
|
|
|
148
148
|
console.log('Bottom sheet ref methods exposed:', Object.keys(bottomSheetRef.current));
|
|
149
149
|
}
|
|
150
150
|
}, [bottomSheetRef, modalRef]);
|
|
151
|
-
// Track if the bottom sheet is expanded
|
|
152
|
-
const [isSheetExpanded, setIsSheetExpanded] = useState(false);
|
|
153
|
-
|
|
154
151
|
// Keyboard handling (unchanged)
|
|
155
152
|
const [keyboardVisible, setKeyboardVisible] = useState(false);
|
|
156
153
|
const insets = useSafeAreaInsets();
|
|
@@ -159,7 +156,7 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
|
|
|
159
156
|
Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow',
|
|
160
157
|
() => {
|
|
161
158
|
setKeyboardVisible(true);
|
|
162
|
-
if (modalRef.current
|
|
159
|
+
if (modalRef.current) {
|
|
163
160
|
requestAnimationFrame(() => {
|
|
164
161
|
modalRef.current?.expand?.();
|
|
165
162
|
});
|
|
@@ -176,7 +173,7 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
|
|
|
176
173
|
keyboardWillShowListener.remove();
|
|
177
174
|
keyboardWillHideListener.remove();
|
|
178
175
|
};
|
|
179
|
-
}, [
|
|
176
|
+
}, []);
|
|
180
177
|
// Present the modal when component mounts, but only if autoPresent is true
|
|
181
178
|
useEffect(() => {
|
|
182
179
|
if (bottomSheetRef && modalRef.current) {
|
|
@@ -292,10 +289,7 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
|
|
|
292
289
|
width: 40,
|
|
293
290
|
height: 4,
|
|
294
291
|
}}
|
|
295
|
-
onChange={
|
|
296
|
-
setIsSheetExpanded(index === 0);
|
|
297
|
-
handleSheetChanges?.(index);
|
|
298
|
-
}}
|
|
292
|
+
onChange={handleSheetChanges}
|
|
299
293
|
style={styles.bottomSheetContainer}
|
|
300
294
|
keyboardBehavior="interactive"
|
|
301
295
|
keyboardBlurBehavior="restore"
|
|
@@ -1034,8 +1034,6 @@ const FeedbackScreen: React.FC<BaseScreenProps> = ({
|
|
|
1034
1034
|
<KeyboardAvoidingView
|
|
1035
1035
|
style={[styles.container, { backgroundColor: colors.background }]}
|
|
1036
1036
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
|
1037
|
-
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 20}
|
|
1038
|
-
enabled={Platform.OS !== 'web'}
|
|
1039
1037
|
>
|
|
1040
1038
|
<StatusBar
|
|
1041
1039
|
barStyle={theme === 'dark' ? 'light-content' : 'dark-content'}
|
|
@@ -1046,8 +1044,6 @@ const FeedbackScreen: React.FC<BaseScreenProps> = ({
|
|
|
1046
1044
|
contentContainerStyle={styles.scrollContent}
|
|
1047
1045
|
showsVerticalScrollIndicator={false}
|
|
1048
1046
|
keyboardShouldPersistTaps="handled"
|
|
1049
|
-
keyboardDismissMode="interactive"
|
|
1050
|
-
automaticallyAdjustKeyboardInsets={Platform.OS === 'ios'}
|
|
1051
1047
|
>
|
|
1052
1048
|
{feedbackState.status !== 'success' && (
|
|
1053
1049
|
<ProgressIndicator currentStep={currentStep} totalSteps={4} colors={colors} styles={styles} />
|
|
@@ -108,8 +108,6 @@ const RecoverAccountScreen: React.FC<RecoverAccountScreenProps> = ({ navigate, g
|
|
|
108
108
|
<KeyboardAvoidingView
|
|
109
109
|
style={[styles.container, { backgroundColor: colors.background }]}
|
|
110
110
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
|
111
|
-
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 20}
|
|
112
|
-
enabled={Platform.OS !== 'web'}
|
|
113
111
|
>
|
|
114
112
|
<StatusBar
|
|
115
113
|
barStyle={theme === 'dark' ? 'light-content' : 'dark-content'}
|
|
@@ -119,8 +117,6 @@ const RecoverAccountScreen: React.FC<RecoverAccountScreenProps> = ({ navigate, g
|
|
|
119
117
|
contentContainerStyle={styles.scrollContent}
|
|
120
118
|
showsVerticalScrollIndicator={false}
|
|
121
119
|
keyboardShouldPersistTaps="handled"
|
|
122
|
-
keyboardDismissMode="interactive"
|
|
123
|
-
automaticallyAdjustKeyboardInsets={Platform.OS === 'ios'}
|
|
124
120
|
>
|
|
125
121
|
<Animated.View style={[
|
|
126
122
|
styles.stepContainer,
|