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