@thetechfossil/auth2 1.2.19 → 1.2.21
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/README.md +1 -1
- package/dist/index.components.d.mts +1 -0
- package/dist/index.components.d.ts +1 -0
- package/dist/index.components.js +275 -11
- package/dist/index.components.js.map +1 -1
- package/dist/index.components.mjs +275 -11
- package/dist/index.components.mjs.map +1 -1
- package/dist/index.d.mts +111 -3
- package/dist/index.d.ts +111 -3
- package/dist/index.js +470 -30
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +471 -32
- package/dist/index.mjs.map +1 -1
- package/dist/index.next.d.mts +54 -1
- package/dist/index.next.d.ts +54 -1
- package/dist/index.next.js +332 -26
- package/dist/index.next.js.map +1 -1
- package/dist/index.next.mjs +332 -26
- package/dist/index.next.mjs.map +1 -1
- package/dist/index.next.server.d.mts +81 -2
- package/dist/index.next.server.d.ts +81 -2
- package/dist/index.next.server.js +406 -9
- package/dist/index.next.server.js.map +1 -1
- package/dist/index.next.server.mjs +403 -10
- package/dist/index.next.server.mjs.map +1 -1
- package/dist/index.node.d.mts +81 -2
- package/dist/index.node.d.ts +81 -2
- package/dist/index.node.js +406 -9
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.mjs +403 -10
- package/dist/index.node.mjs.map +1 -1
- package/dist/index.react-native.d.mts +227 -0
- package/dist/index.react-native.d.ts +227 -0
- package/dist/index.react-native.js +1684 -0
- package/dist/index.react-native.js.map +1 -0
- package/dist/index.react-native.mjs +1648 -0
- package/dist/index.react-native.mjs.map +1 -0
- package/package.json +119 -102
package/dist/index.node.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ interface User {
|
|
|
14
14
|
phoneNumber?: string;
|
|
15
15
|
avatar?: string;
|
|
16
16
|
role: string;
|
|
17
|
+
emailVerified?: boolean;
|
|
18
|
+
twoFactorEnabled?: boolean;
|
|
17
19
|
linkedAccounts?: LinkedAccount[];
|
|
18
20
|
createdAt: string;
|
|
19
21
|
updatedAt: string;
|
|
@@ -63,6 +65,7 @@ interface AuthConfig {
|
|
|
63
65
|
localStorageKey?: string;
|
|
64
66
|
token?: string;
|
|
65
67
|
csrfEnabled?: boolean;
|
|
68
|
+
enableSocket?: boolean;
|
|
66
69
|
upfilesConfig?: UpfilesConfig;
|
|
67
70
|
}
|
|
68
71
|
interface UpfilesConfig {
|
|
@@ -130,17 +133,57 @@ interface UseAuthReturn {
|
|
|
130
133
|
}>;
|
|
131
134
|
revokeSession: (sessionId: string) => Promise<AuthResponse>;
|
|
132
135
|
revokeAllSessions: () => Promise<AuthResponse>;
|
|
136
|
+
adminCreateUser: (data: {
|
|
137
|
+
email: string;
|
|
138
|
+
name: string;
|
|
139
|
+
phoneNumber?: string;
|
|
140
|
+
password?: string;
|
|
141
|
+
}) => Promise<AuthResponse & {
|
|
142
|
+
user?: User;
|
|
143
|
+
}>;
|
|
144
|
+
adminVerifyUser: (userId: string) => Promise<AuthResponse>;
|
|
145
|
+
adminSuspendUser: (userId: string) => Promise<AuthResponse>;
|
|
146
|
+
adminActivateUser: (userId: string) => Promise<AuthResponse>;
|
|
133
147
|
}
|
|
134
148
|
|
|
149
|
+
type SocketEventHandler<T = any> = (data: T) => void;
|
|
150
|
+
|
|
135
151
|
declare class AuthService {
|
|
136
152
|
private httpClient;
|
|
153
|
+
private socketService;
|
|
137
154
|
private config;
|
|
138
155
|
private token;
|
|
139
156
|
private upfilesClient;
|
|
157
|
+
private cachedUser;
|
|
158
|
+
private userCacheTimestamp;
|
|
159
|
+
private readonly USER_CACHE_TTL;
|
|
140
160
|
constructor(config: AuthConfig);
|
|
141
161
|
private loadTokenFromStorage;
|
|
142
162
|
private saveTokenToStorage;
|
|
143
163
|
private removeTokenFromStorage;
|
|
164
|
+
private connectSocket;
|
|
165
|
+
private disconnectSocket;
|
|
166
|
+
onUserUpdated(handler: SocketEventHandler<{
|
|
167
|
+
user: User;
|
|
168
|
+
}>): () => void;
|
|
169
|
+
onSessionRevoked(handler: SocketEventHandler<{
|
|
170
|
+
sessionId?: string;
|
|
171
|
+
}>): () => void;
|
|
172
|
+
onAllSessionsRevoked(handler: SocketEventHandler<{}>): () => void;
|
|
173
|
+
onPasswordChanged(handler: SocketEventHandler<{}>): () => void;
|
|
174
|
+
on2FAChanged(handler: SocketEventHandler<{
|
|
175
|
+
enabled: boolean;
|
|
176
|
+
}>): () => void;
|
|
177
|
+
onSocketConnected(handler: SocketEventHandler<{}>): () => void;
|
|
178
|
+
onSocketDisconnected(handler: SocketEventHandler<{
|
|
179
|
+
reason: string;
|
|
180
|
+
}>): () => void;
|
|
181
|
+
onSocketError(handler: SocketEventHandler<{
|
|
182
|
+
error: string;
|
|
183
|
+
}>): () => void;
|
|
184
|
+
isSocketConnected(): boolean;
|
|
185
|
+
clearUserCache(): void;
|
|
186
|
+
private isCacheValid;
|
|
144
187
|
isAuthenticated(): boolean;
|
|
145
188
|
getToken(): string | null;
|
|
146
189
|
getCurrentUser(): User | null;
|
|
@@ -154,7 +197,7 @@ declare class AuthService {
|
|
|
154
197
|
verify(data: VerifyData): Promise<AuthResponse>;
|
|
155
198
|
verifyEmailToken(token: string): Promise<AuthResponse>;
|
|
156
199
|
logout(): Promise<void>;
|
|
157
|
-
getProfile(): Promise<User>;
|
|
200
|
+
getProfile(forceRefresh?: boolean): Promise<User>;
|
|
158
201
|
updateProfile(data: UpdateUserData): Promise<AuthResponse>;
|
|
159
202
|
getAllUsers(): Promise<User[]>;
|
|
160
203
|
getUserById(id: string): Promise<User>;
|
|
@@ -185,6 +228,14 @@ declare class AuthService {
|
|
|
185
228
|
success: boolean;
|
|
186
229
|
logs: any[];
|
|
187
230
|
}>;
|
|
231
|
+
adminCreateUser(data: {
|
|
232
|
+
email: string;
|
|
233
|
+
name: string;
|
|
234
|
+
phoneNumber?: string;
|
|
235
|
+
password?: string;
|
|
236
|
+
}): Promise<AuthResponse & {
|
|
237
|
+
user?: User;
|
|
238
|
+
}>;
|
|
188
239
|
adminVerifyUser(userId: string): Promise<AuthResponse>;
|
|
189
240
|
adminForcePasswordReset(userId: string): Promise<AuthResponse>;
|
|
190
241
|
adminSuspendUser(userId: string): Promise<AuthResponse>;
|
|
@@ -197,6 +248,7 @@ declare class HttpClient {
|
|
|
197
248
|
private frontendBaseUrl;
|
|
198
249
|
private baseUrl;
|
|
199
250
|
constructor(baseUrl: string, defaultHeaders?: Record<string, string>);
|
|
251
|
+
private createUserFriendlyError;
|
|
200
252
|
get<T>(endpoint: string, headers?: Record<string, string>): Promise<T>;
|
|
201
253
|
post<T>(endpoint: string, data?: any, headers?: Record<string, string>): Promise<T>;
|
|
202
254
|
put<T>(endpoint: string, data?: any, headers?: Record<string, string>): Promise<T>;
|
|
@@ -224,4 +276,31 @@ declare class AuthClient extends AuthService {
|
|
|
224
276
|
getAllUsers(): Promise<User[]>;
|
|
225
277
|
}
|
|
226
278
|
|
|
227
|
-
|
|
279
|
+
interface TokenVerifierConfig {
|
|
280
|
+
authServiceUrl: string;
|
|
281
|
+
cacheTTL?: number;
|
|
282
|
+
cacheEnabled?: boolean;
|
|
283
|
+
}
|
|
284
|
+
declare class TokenVerifier {
|
|
285
|
+
private config;
|
|
286
|
+
private cache;
|
|
287
|
+
private cleanupInterval;
|
|
288
|
+
constructor(config: TokenVerifierConfig);
|
|
289
|
+
verifyToken(token: string): Promise<User | null>;
|
|
290
|
+
invalidateToken(token: string): void;
|
|
291
|
+
clearCache(): void;
|
|
292
|
+
getCacheStats(): {
|
|
293
|
+
size: number;
|
|
294
|
+
enabled: boolean;
|
|
295
|
+
ttl: number;
|
|
296
|
+
};
|
|
297
|
+
destroy(): void;
|
|
298
|
+
private getFromCache;
|
|
299
|
+
private setCache;
|
|
300
|
+
private startCleanup;
|
|
301
|
+
}
|
|
302
|
+
declare function createTokenVerifier(config: TokenVerifierConfig): TokenVerifier;
|
|
303
|
+
declare function getTokenVerifier(): TokenVerifier;
|
|
304
|
+
declare function verifyToken(token: string): Promise<User | null>;
|
|
305
|
+
|
|
306
|
+
export { type AuditLog, AuthClient, type AuthConfig, type AuthResponse, AuthService, type CsrfTokenResponse, HttpClient, type LinkedAccount, type LoginData, type MFASetup, type OAuthConfig, type OAuthProvider, type RegisterData, type Session, TokenVerifier, type UpdateUserData, type UpfilesConfig, type UseAuthReturn, type User, type VerifyData, createTokenVerifier, getTokenVerifier, verifyToken };
|
package/dist/index.node.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var axios = require('axios');
|
|
4
|
+
var socket_ioClient = require('socket.io-client');
|
|
4
5
|
var upfiles = require('@thetechfossil/upfiles');
|
|
5
6
|
|
|
6
7
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -8,6 +9,16 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
8
9
|
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
9
10
|
|
|
10
11
|
// src/core/http-client.ts
|
|
12
|
+
var ERROR_MESSAGES = {
|
|
13
|
+
NETWORK_ERROR: "Unable to connect to the server. Please check your internet connection and try again.",
|
|
14
|
+
TIMEOUT: "The request took too long. Please try again.",
|
|
15
|
+
SERVER_ERROR: "Something went wrong on our end. Please try again later.",
|
|
16
|
+
UNAUTHORIZED: "Your session has expired. Please log in again.",
|
|
17
|
+
FORBIDDEN: "You do not have permission to perform this action.",
|
|
18
|
+
NOT_FOUND: "The requested resource was not found.",
|
|
19
|
+
RATE_LIMITED: "Too many requests. Please wait a moment and try again.",
|
|
20
|
+
UNKNOWN: "An unexpected error occurred. Please try again."
|
|
21
|
+
};
|
|
11
22
|
var HttpClient = class {
|
|
12
23
|
constructor(baseUrl, defaultHeaders = {}) {
|
|
13
24
|
this.csrfToken = null;
|
|
@@ -42,7 +53,7 @@ var HttpClient = class {
|
|
|
42
53
|
}
|
|
43
54
|
return config;
|
|
44
55
|
},
|
|
45
|
-
(error) => Promise.reject(error)
|
|
56
|
+
(error) => Promise.reject(this.createUserFriendlyError(error))
|
|
46
57
|
);
|
|
47
58
|
this.axiosInstance.interceptors.response.use(
|
|
48
59
|
(response) => response,
|
|
@@ -57,18 +68,71 @@ var HttpClient = class {
|
|
|
57
68
|
}
|
|
58
69
|
return this.axiosInstance(originalRequest);
|
|
59
70
|
} catch (refreshError) {
|
|
60
|
-
return Promise.reject(refreshError);
|
|
71
|
+
return Promise.reject(this.createUserFriendlyError(refreshError));
|
|
61
72
|
}
|
|
62
73
|
}
|
|
63
|
-
|
|
64
|
-
const customError = new Error(error.response.data.message);
|
|
65
|
-
customError.response = error.response;
|
|
66
|
-
return Promise.reject(customError);
|
|
67
|
-
}
|
|
68
|
-
return Promise.reject(error);
|
|
74
|
+
return Promise.reject(this.createUserFriendlyError(error));
|
|
69
75
|
}
|
|
70
76
|
);
|
|
71
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Creates a user-friendly error message from an Axios error
|
|
80
|
+
*/
|
|
81
|
+
createUserFriendlyError(error) {
|
|
82
|
+
if (error instanceof Error && !error.isAxiosError) {
|
|
83
|
+
return error;
|
|
84
|
+
}
|
|
85
|
+
let message;
|
|
86
|
+
let statusCode;
|
|
87
|
+
if (axios__default.default.isAxiosError(error)) {
|
|
88
|
+
statusCode = error.response?.status;
|
|
89
|
+
const responseData = error.response?.data;
|
|
90
|
+
if (responseData?.message) {
|
|
91
|
+
message = responseData.message;
|
|
92
|
+
} else if (!error.response) {
|
|
93
|
+
if (error.code === "ECONNABORTED" || error.message.includes("timeout")) {
|
|
94
|
+
message = ERROR_MESSAGES.TIMEOUT;
|
|
95
|
+
} else if (error.code === "ERR_NETWORK" || error.message === "Network Error") {
|
|
96
|
+
message = ERROR_MESSAGES.NETWORK_ERROR;
|
|
97
|
+
} else {
|
|
98
|
+
message = ERROR_MESSAGES.NETWORK_ERROR;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
switch (statusCode) {
|
|
102
|
+
case 400:
|
|
103
|
+
message = responseData?.message || "Invalid request. Please check your input.";
|
|
104
|
+
break;
|
|
105
|
+
case 401:
|
|
106
|
+
message = responseData?.message || ERROR_MESSAGES.UNAUTHORIZED;
|
|
107
|
+
break;
|
|
108
|
+
case 403:
|
|
109
|
+
message = responseData?.message || ERROR_MESSAGES.FORBIDDEN;
|
|
110
|
+
break;
|
|
111
|
+
case 404:
|
|
112
|
+
message = responseData?.message || ERROR_MESSAGES.NOT_FOUND;
|
|
113
|
+
break;
|
|
114
|
+
case 429:
|
|
115
|
+
message = ERROR_MESSAGES.RATE_LIMITED;
|
|
116
|
+
break;
|
|
117
|
+
case 500:
|
|
118
|
+
case 502:
|
|
119
|
+
case 503:
|
|
120
|
+
case 504:
|
|
121
|
+
message = ERROR_MESSAGES.SERVER_ERROR;
|
|
122
|
+
break;
|
|
123
|
+
default:
|
|
124
|
+
message = responseData?.message || ERROR_MESSAGES.UNKNOWN;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
message = error?.message || ERROR_MESSAGES.UNKNOWN;
|
|
129
|
+
}
|
|
130
|
+
const customError = new Error(message);
|
|
131
|
+
customError.response = error?.response;
|
|
132
|
+
customError.statusCode = statusCode;
|
|
133
|
+
customError.originalError = error;
|
|
134
|
+
return customError;
|
|
135
|
+
}
|
|
72
136
|
async get(endpoint, headers) {
|
|
73
137
|
const response = await this.axiosInstance.get(endpoint, { headers });
|
|
74
138
|
return response.data;
|
|
@@ -119,16 +183,134 @@ var HttpClient = class {
|
|
|
119
183
|
}
|
|
120
184
|
}
|
|
121
185
|
};
|
|
186
|
+
var SocketService = class {
|
|
187
|
+
constructor(config) {
|
|
188
|
+
this.socket = null;
|
|
189
|
+
this.token = null;
|
|
190
|
+
this.eventHandlers = /* @__PURE__ */ new Map();
|
|
191
|
+
this.isConnecting = false;
|
|
192
|
+
this.config = {
|
|
193
|
+
autoConnect: false,
|
|
194
|
+
reconnection: true,
|
|
195
|
+
reconnectionAttempts: 5,
|
|
196
|
+
reconnectionDelay: 1e3,
|
|
197
|
+
...config
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
connect(token) {
|
|
201
|
+
if (this.socket?.connected || this.isConnecting) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
this.token = token;
|
|
205
|
+
this.isConnecting = true;
|
|
206
|
+
this.socket = socket_ioClient.io(this.config.baseUrl, {
|
|
207
|
+
auth: { token },
|
|
208
|
+
autoConnect: true,
|
|
209
|
+
reconnection: this.config.reconnection,
|
|
210
|
+
reconnectionAttempts: this.config.reconnectionAttempts,
|
|
211
|
+
reconnectionDelay: this.config.reconnectionDelay,
|
|
212
|
+
transports: ["websocket", "polling"]
|
|
213
|
+
});
|
|
214
|
+
this.setupEventListeners();
|
|
215
|
+
}
|
|
216
|
+
setupEventListeners() {
|
|
217
|
+
if (!this.socket) return;
|
|
218
|
+
this.socket.on("connect", () => {
|
|
219
|
+
this.isConnecting = false;
|
|
220
|
+
console.log("[Auth SDK] Socket connected");
|
|
221
|
+
this.emit("connected", {});
|
|
222
|
+
});
|
|
223
|
+
this.socket.on("disconnect", (reason) => {
|
|
224
|
+
console.log("[Auth SDK] Socket disconnected:", reason);
|
|
225
|
+
this.emit("disconnected", { reason });
|
|
226
|
+
});
|
|
227
|
+
this.socket.on("connect_error", (error) => {
|
|
228
|
+
this.isConnecting = false;
|
|
229
|
+
console.error("[Auth SDK] Socket connection error:", error.message);
|
|
230
|
+
this.emit("error", { error: error.message });
|
|
231
|
+
});
|
|
232
|
+
this.socket.on("user:updated", (data) => {
|
|
233
|
+
this.emit("user:updated", data);
|
|
234
|
+
});
|
|
235
|
+
this.socket.on("session:revoked", (data) => {
|
|
236
|
+
this.emit("session:revoked", data);
|
|
237
|
+
});
|
|
238
|
+
this.socket.on("session:all-revoked", () => {
|
|
239
|
+
this.emit("session:all-revoked", {});
|
|
240
|
+
});
|
|
241
|
+
this.socket.on("auth:password-changed", () => {
|
|
242
|
+
this.emit("auth:password-changed", {});
|
|
243
|
+
});
|
|
244
|
+
this.socket.on("auth:2fa-changed", (data) => {
|
|
245
|
+
this.emit("auth:2fa-changed", data);
|
|
246
|
+
});
|
|
247
|
+
this.socket.on("user:refresh", () => {
|
|
248
|
+
this.emit("user:refresh", {});
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
disconnect() {
|
|
252
|
+
if (this.socket) {
|
|
253
|
+
this.socket.disconnect();
|
|
254
|
+
this.socket = null;
|
|
255
|
+
this.token = null;
|
|
256
|
+
this.isConnecting = false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
isConnected() {
|
|
260
|
+
return this.socket?.connected ?? false;
|
|
261
|
+
}
|
|
262
|
+
// Event subscription
|
|
263
|
+
on(event, handler) {
|
|
264
|
+
if (!this.eventHandlers.has(event)) {
|
|
265
|
+
this.eventHandlers.set(event, /* @__PURE__ */ new Set());
|
|
266
|
+
}
|
|
267
|
+
this.eventHandlers.get(event).add(handler);
|
|
268
|
+
return () => {
|
|
269
|
+
this.eventHandlers.get(event)?.delete(handler);
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
off(event, handler) {
|
|
273
|
+
if (handler) {
|
|
274
|
+
this.eventHandlers.get(event)?.delete(handler);
|
|
275
|
+
} else {
|
|
276
|
+
this.eventHandlers.delete(event);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
emit(event, data) {
|
|
280
|
+
const handlers = this.eventHandlers.get(event);
|
|
281
|
+
if (handlers) {
|
|
282
|
+
handlers.forEach((handler) => {
|
|
283
|
+
try {
|
|
284
|
+
handler(data);
|
|
285
|
+
} catch (error) {
|
|
286
|
+
console.error(`[Auth SDK] Error in event handler for ${event}:`, error);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Request fresh user data from server
|
|
292
|
+
requestUserRefresh() {
|
|
293
|
+
if (this.socket?.connected) {
|
|
294
|
+
this.socket.emit("request:user");
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
122
298
|
var AuthService = class {
|
|
299
|
+
// 5 minutes cache
|
|
123
300
|
constructor(config) {
|
|
124
301
|
this.token = null;
|
|
125
302
|
this.upfilesClient = null;
|
|
303
|
+
this.cachedUser = null;
|
|
304
|
+
this.userCacheTimestamp = 0;
|
|
305
|
+
this.USER_CACHE_TTL = 5 * 60 * 1e3;
|
|
126
306
|
this.config = {
|
|
127
307
|
localStorageKey: "auth_token",
|
|
128
308
|
csrfEnabled: true,
|
|
309
|
+
enableSocket: true,
|
|
129
310
|
...config
|
|
130
311
|
};
|
|
131
312
|
this.httpClient = new HttpClient(this.config.baseUrl);
|
|
313
|
+
this.socketService = new SocketService({ baseUrl: this.config.baseUrl });
|
|
132
314
|
this.loadTokenFromStorage();
|
|
133
315
|
if (this.config.upfilesConfig) {
|
|
134
316
|
this.upfilesClient = new upfiles.UpfilesClient({
|
|
@@ -145,6 +327,9 @@ var AuthService = class {
|
|
|
145
327
|
this.httpClient.setFrontendBaseUrl(frontendBaseUrl);
|
|
146
328
|
}
|
|
147
329
|
}
|
|
330
|
+
if (this.token && this.config.enableSocket !== false) {
|
|
331
|
+
this.connectSocket();
|
|
332
|
+
}
|
|
148
333
|
}
|
|
149
334
|
loadTokenFromStorage() {
|
|
150
335
|
if (typeof window !== "undefined" && this.config.localStorageKey) {
|
|
@@ -177,6 +362,57 @@ var AuthService = class {
|
|
|
177
362
|
}
|
|
178
363
|
}
|
|
179
364
|
}
|
|
365
|
+
// Socket connection management
|
|
366
|
+
connectSocket() {
|
|
367
|
+
if (this.token && this.config.enableSocket !== false && typeof window !== "undefined") {
|
|
368
|
+
this.socketService.connect(this.token);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
disconnectSocket() {
|
|
372
|
+
this.socketService.disconnect();
|
|
373
|
+
}
|
|
374
|
+
// Socket event subscription
|
|
375
|
+
onUserUpdated(handler) {
|
|
376
|
+
return this.socketService.on("user:updated", (data) => {
|
|
377
|
+
if (data.user) {
|
|
378
|
+
this.cachedUser = data.user;
|
|
379
|
+
this.userCacheTimestamp = Date.now();
|
|
380
|
+
}
|
|
381
|
+
handler(data);
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
onSessionRevoked(handler) {
|
|
385
|
+
return this.socketService.on("session:revoked", handler);
|
|
386
|
+
}
|
|
387
|
+
onAllSessionsRevoked(handler) {
|
|
388
|
+
return this.socketService.on("session:all-revoked", handler);
|
|
389
|
+
}
|
|
390
|
+
onPasswordChanged(handler) {
|
|
391
|
+
return this.socketService.on("auth:password-changed", handler);
|
|
392
|
+
}
|
|
393
|
+
on2FAChanged(handler) {
|
|
394
|
+
return this.socketService.on("auth:2fa-changed", handler);
|
|
395
|
+
}
|
|
396
|
+
onSocketConnected(handler) {
|
|
397
|
+
return this.socketService.on("connected", handler);
|
|
398
|
+
}
|
|
399
|
+
onSocketDisconnected(handler) {
|
|
400
|
+
return this.socketService.on("disconnected", handler);
|
|
401
|
+
}
|
|
402
|
+
onSocketError(handler) {
|
|
403
|
+
return this.socketService.on("error", handler);
|
|
404
|
+
}
|
|
405
|
+
isSocketConnected() {
|
|
406
|
+
return this.socketService.isConnected();
|
|
407
|
+
}
|
|
408
|
+
// Cache management
|
|
409
|
+
clearUserCache() {
|
|
410
|
+
this.cachedUser = null;
|
|
411
|
+
this.userCacheTimestamp = 0;
|
|
412
|
+
}
|
|
413
|
+
isCacheValid() {
|
|
414
|
+
return this.cachedUser !== null && Date.now() - this.userCacheTimestamp < this.USER_CACHE_TTL;
|
|
415
|
+
}
|
|
180
416
|
isAuthenticated() {
|
|
181
417
|
return !!this.token;
|
|
182
418
|
}
|
|
@@ -242,6 +478,11 @@ var AuthService = class {
|
|
|
242
478
|
this.token = response.token;
|
|
243
479
|
this.httpClient.setAuthToken(response.token);
|
|
244
480
|
this.saveTokenToStorage(response.token);
|
|
481
|
+
if (response.user) {
|
|
482
|
+
this.cachedUser = response.user;
|
|
483
|
+
this.userCacheTimestamp = Date.now();
|
|
484
|
+
}
|
|
485
|
+
this.connectSocket();
|
|
245
486
|
return response;
|
|
246
487
|
}
|
|
247
488
|
if (response.success && (response.message === "OTP sent to your email." || response.message === "OTP sent to your phone number.")) {
|
|
@@ -251,6 +492,11 @@ var AuthService = class {
|
|
|
251
492
|
this.token = response.token;
|
|
252
493
|
this.httpClient.setAuthToken(response.token);
|
|
253
494
|
this.saveTokenToStorage(response.token);
|
|
495
|
+
if (response.user) {
|
|
496
|
+
this.cachedUser = response.user;
|
|
497
|
+
this.userCacheTimestamp = Date.now();
|
|
498
|
+
}
|
|
499
|
+
this.connectSocket();
|
|
254
500
|
return response;
|
|
255
501
|
}
|
|
256
502
|
throw new Error(response.message || "Login failed");
|
|
@@ -294,21 +540,29 @@ var AuthService = class {
|
|
|
294
540
|
}
|
|
295
541
|
}
|
|
296
542
|
async logout() {
|
|
543
|
+
this.disconnectSocket();
|
|
297
544
|
try {
|
|
298
545
|
await this.httpClient.post("/api/v1/auth/logout", {});
|
|
299
546
|
} catch (error) {
|
|
300
547
|
console.warn("Failed to call logout endpoint:", error);
|
|
301
548
|
}
|
|
302
549
|
this.token = null;
|
|
550
|
+
this.cachedUser = null;
|
|
551
|
+
this.userCacheTimestamp = 0;
|
|
303
552
|
this.httpClient.removeAuthToken();
|
|
304
553
|
this.httpClient.removeCsrfToken();
|
|
305
554
|
this.removeTokenFromStorage();
|
|
306
555
|
}
|
|
307
|
-
async getProfile() {
|
|
556
|
+
async getProfile(forceRefresh = false) {
|
|
308
557
|
if (!this.token) {
|
|
309
558
|
throw new Error("Not authenticated");
|
|
310
559
|
}
|
|
560
|
+
if (!forceRefresh && this.isCacheValid() && this.cachedUser) {
|
|
561
|
+
return this.cachedUser;
|
|
562
|
+
}
|
|
311
563
|
const response = await this.httpClient.get("/api/v1/user/me");
|
|
564
|
+
this.cachedUser = response.user;
|
|
565
|
+
this.userCacheTimestamp = Date.now();
|
|
312
566
|
return response.user;
|
|
313
567
|
}
|
|
314
568
|
async updateProfile(data) {
|
|
@@ -472,6 +726,16 @@ var AuthService = class {
|
|
|
472
726
|
);
|
|
473
727
|
return response;
|
|
474
728
|
}
|
|
729
|
+
async adminCreateUser(data) {
|
|
730
|
+
if (!this.token) {
|
|
731
|
+
throw new Error("Not authenticated");
|
|
732
|
+
}
|
|
733
|
+
const response = await this.httpClient.post(
|
|
734
|
+
"/api/v1/admin/create-user",
|
|
735
|
+
data
|
|
736
|
+
);
|
|
737
|
+
return response;
|
|
738
|
+
}
|
|
475
739
|
async adminVerifyUser(userId) {
|
|
476
740
|
if (!this.token) {
|
|
477
741
|
throw new Error("Not authenticated");
|
|
@@ -580,8 +844,141 @@ var AuthClient = class extends AuthService {
|
|
|
580
844
|
}
|
|
581
845
|
};
|
|
582
846
|
|
|
847
|
+
// src/node/token-verifier.ts
|
|
848
|
+
var TokenVerifier = class {
|
|
849
|
+
constructor(config) {
|
|
850
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
851
|
+
this.cleanupInterval = null;
|
|
852
|
+
this.config = {
|
|
853
|
+
cacheTTL: 6e4,
|
|
854
|
+
// 1 minute default
|
|
855
|
+
cacheEnabled: true,
|
|
856
|
+
...config
|
|
857
|
+
};
|
|
858
|
+
if (this.config.cacheEnabled) {
|
|
859
|
+
this.startCleanup();
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
/**
|
|
863
|
+
* Verify a JWT token and get user data
|
|
864
|
+
* Returns cached user if available and valid
|
|
865
|
+
*/
|
|
866
|
+
async verifyToken(token) {
|
|
867
|
+
if (!token) {
|
|
868
|
+
return null;
|
|
869
|
+
}
|
|
870
|
+
if (this.config.cacheEnabled) {
|
|
871
|
+
const cached = this.getFromCache(token);
|
|
872
|
+
if (cached) {
|
|
873
|
+
return cached;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
try {
|
|
877
|
+
const response = await fetch(`${this.config.authServiceUrl}/api/v1/user/me`, {
|
|
878
|
+
headers: {
|
|
879
|
+
"Authorization": `Bearer ${token}`,
|
|
880
|
+
"Content-Type": "application/json"
|
|
881
|
+
}
|
|
882
|
+
});
|
|
883
|
+
if (!response.ok) {
|
|
884
|
+
this.cache.delete(token);
|
|
885
|
+
return null;
|
|
886
|
+
}
|
|
887
|
+
const data = await response.json();
|
|
888
|
+
const user = data.user || null;
|
|
889
|
+
if (user && this.config.cacheEnabled) {
|
|
890
|
+
this.setCache(token, user);
|
|
891
|
+
}
|
|
892
|
+
return user;
|
|
893
|
+
} catch (error) {
|
|
894
|
+
console.error("[TokenVerifier] Auth service verification failed:", error);
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Invalidate cache for a specific token
|
|
900
|
+
*/
|
|
901
|
+
invalidateToken(token) {
|
|
902
|
+
this.cache.delete(token);
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Clear all cached tokens
|
|
906
|
+
*/
|
|
907
|
+
clearCache() {
|
|
908
|
+
this.cache.clear();
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Get cache statistics
|
|
912
|
+
*/
|
|
913
|
+
getCacheStats() {
|
|
914
|
+
return {
|
|
915
|
+
size: this.cache.size,
|
|
916
|
+
enabled: this.config.cacheEnabled,
|
|
917
|
+
ttl: this.config.cacheTTL
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Stop the cleanup interval (call when shutting down)
|
|
922
|
+
*/
|
|
923
|
+
destroy() {
|
|
924
|
+
if (this.cleanupInterval) {
|
|
925
|
+
clearInterval(this.cleanupInterval);
|
|
926
|
+
this.cleanupInterval = null;
|
|
927
|
+
}
|
|
928
|
+
this.cache.clear();
|
|
929
|
+
}
|
|
930
|
+
getFromCache(token) {
|
|
931
|
+
const entry = this.cache.get(token);
|
|
932
|
+
if (!entry) {
|
|
933
|
+
return null;
|
|
934
|
+
}
|
|
935
|
+
if (Date.now() > entry.expiresAt) {
|
|
936
|
+
this.cache.delete(token);
|
|
937
|
+
return null;
|
|
938
|
+
}
|
|
939
|
+
return entry.user;
|
|
940
|
+
}
|
|
941
|
+
setCache(token, user) {
|
|
942
|
+
this.cache.set(token, {
|
|
943
|
+
user,
|
|
944
|
+
expiresAt: Date.now() + this.config.cacheTTL
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
startCleanup() {
|
|
948
|
+
this.cleanupInterval = setInterval(() => {
|
|
949
|
+
const now = Date.now();
|
|
950
|
+
for (const [token, entry] of this.cache.entries()) {
|
|
951
|
+
if (now > entry.expiresAt) {
|
|
952
|
+
this.cache.delete(token);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
}, 6e4);
|
|
956
|
+
if (this.cleanupInterval && this.cleanupInterval.unref) {
|
|
957
|
+
this.cleanupInterval.unref();
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
var defaultVerifier = null;
|
|
962
|
+
function createTokenVerifier(config) {
|
|
963
|
+
defaultVerifier = new TokenVerifier(config);
|
|
964
|
+
return defaultVerifier;
|
|
965
|
+
}
|
|
966
|
+
function getTokenVerifier() {
|
|
967
|
+
if (!defaultVerifier) {
|
|
968
|
+
throw new Error("TokenVerifier not initialized. Call createTokenVerifier() first.");
|
|
969
|
+
}
|
|
970
|
+
return defaultVerifier;
|
|
971
|
+
}
|
|
972
|
+
async function verifyToken(token) {
|
|
973
|
+
return getTokenVerifier().verifyToken(token);
|
|
974
|
+
}
|
|
975
|
+
|
|
583
976
|
exports.AuthClient = AuthClient;
|
|
584
977
|
exports.AuthService = AuthService;
|
|
585
978
|
exports.HttpClient = HttpClient;
|
|
979
|
+
exports.TokenVerifier = TokenVerifier;
|
|
980
|
+
exports.createTokenVerifier = createTokenVerifier;
|
|
981
|
+
exports.getTokenVerifier = getTokenVerifier;
|
|
982
|
+
exports.verifyToken = verifyToken;
|
|
586
983
|
//# sourceMappingURL=index.node.js.map
|
|
587
984
|
//# sourceMappingURL=index.node.js.map
|