@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,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
  var headers = require('next/headers');
6
7
  var navigation = require('next/navigation');
@@ -15,6 +16,16 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
15
16
  if (typeof require !== "undefined") return require.apply(this, arguments);
16
17
  throw Error('Dynamic require of "' + x + '" is not supported');
17
18
  });
19
+ var ERROR_MESSAGES = {
20
+ NETWORK_ERROR: "Unable to connect to the server. Please check your internet connection and try again.",
21
+ TIMEOUT: "The request took too long. Please try again.",
22
+ SERVER_ERROR: "Something went wrong on our end. Please try again later.",
23
+ UNAUTHORIZED: "Your session has expired. Please log in again.",
24
+ FORBIDDEN: "You do not have permission to perform this action.",
25
+ NOT_FOUND: "The requested resource was not found.",
26
+ RATE_LIMITED: "Too many requests. Please wait a moment and try again.",
27
+ UNKNOWN: "An unexpected error occurred. Please try again."
28
+ };
18
29
  var HttpClient = class {
19
30
  constructor(baseUrl, defaultHeaders = {}) {
20
31
  this.csrfToken = null;
@@ -49,7 +60,7 @@ var HttpClient = class {
49
60
  }
50
61
  return config;
51
62
  },
52
- (error) => Promise.reject(error)
63
+ (error) => Promise.reject(this.createUserFriendlyError(error))
53
64
  );
54
65
  this.axiosInstance.interceptors.response.use(
55
66
  (response) => response,
@@ -64,18 +75,71 @@ var HttpClient = class {
64
75
  }
65
76
  return this.axiosInstance(originalRequest);
66
77
  } catch (refreshError) {
67
- return Promise.reject(refreshError);
78
+ return Promise.reject(this.createUserFriendlyError(refreshError));
68
79
  }
69
80
  }
70
- if (error.response && error.response.data && error.response.data.message) {
71
- const customError = new Error(error.response.data.message);
72
- customError.response = error.response;
73
- return Promise.reject(customError);
74
- }
75
- return Promise.reject(error);
81
+ return Promise.reject(this.createUserFriendlyError(error));
76
82
  }
77
83
  );
78
84
  }
85
+ /**
86
+ * Creates a user-friendly error message from an Axios error
87
+ */
88
+ createUserFriendlyError(error) {
89
+ if (error instanceof Error && !error.isAxiosError) {
90
+ return error;
91
+ }
92
+ let message;
93
+ let statusCode;
94
+ if (axios__default.default.isAxiosError(error)) {
95
+ statusCode = error.response?.status;
96
+ const responseData = error.response?.data;
97
+ if (responseData?.message) {
98
+ message = responseData.message;
99
+ } else if (!error.response) {
100
+ if (error.code === "ECONNABORTED" || error.message.includes("timeout")) {
101
+ message = ERROR_MESSAGES.TIMEOUT;
102
+ } else if (error.code === "ERR_NETWORK" || error.message === "Network Error") {
103
+ message = ERROR_MESSAGES.NETWORK_ERROR;
104
+ } else {
105
+ message = ERROR_MESSAGES.NETWORK_ERROR;
106
+ }
107
+ } else {
108
+ switch (statusCode) {
109
+ case 400:
110
+ message = responseData?.message || "Invalid request. Please check your input.";
111
+ break;
112
+ case 401:
113
+ message = responseData?.message || ERROR_MESSAGES.UNAUTHORIZED;
114
+ break;
115
+ case 403:
116
+ message = responseData?.message || ERROR_MESSAGES.FORBIDDEN;
117
+ break;
118
+ case 404:
119
+ message = responseData?.message || ERROR_MESSAGES.NOT_FOUND;
120
+ break;
121
+ case 429:
122
+ message = ERROR_MESSAGES.RATE_LIMITED;
123
+ break;
124
+ case 500:
125
+ case 502:
126
+ case 503:
127
+ case 504:
128
+ message = ERROR_MESSAGES.SERVER_ERROR;
129
+ break;
130
+ default:
131
+ message = responseData?.message || ERROR_MESSAGES.UNKNOWN;
132
+ }
133
+ }
134
+ } else {
135
+ message = error?.message || ERROR_MESSAGES.UNKNOWN;
136
+ }
137
+ const customError = new Error(message);
138
+ customError.response = error?.response;
139
+ customError.statusCode = statusCode;
140
+ customError.originalError = error;
141
+ return customError;
142
+ }
79
143
  async get(endpoint, headers) {
80
144
  const response = await this.axiosInstance.get(endpoint, { headers });
81
145
  return response.data;
@@ -126,16 +190,134 @@ var HttpClient = class {
126
190
  }
127
191
  }
128
192
  };
193
+ var SocketService = class {
194
+ constructor(config) {
195
+ this.socket = null;
196
+ this.token = null;
197
+ this.eventHandlers = /* @__PURE__ */ new Map();
198
+ this.isConnecting = false;
199
+ this.config = {
200
+ autoConnect: false,
201
+ reconnection: true,
202
+ reconnectionAttempts: 5,
203
+ reconnectionDelay: 1e3,
204
+ ...config
205
+ };
206
+ }
207
+ connect(token) {
208
+ if (this.socket?.connected || this.isConnecting) {
209
+ return;
210
+ }
211
+ this.token = token;
212
+ this.isConnecting = true;
213
+ this.socket = socket_ioClient.io(this.config.baseUrl, {
214
+ auth: { token },
215
+ autoConnect: true,
216
+ reconnection: this.config.reconnection,
217
+ reconnectionAttempts: this.config.reconnectionAttempts,
218
+ reconnectionDelay: this.config.reconnectionDelay,
219
+ transports: ["websocket", "polling"]
220
+ });
221
+ this.setupEventListeners();
222
+ }
223
+ setupEventListeners() {
224
+ if (!this.socket) return;
225
+ this.socket.on("connect", () => {
226
+ this.isConnecting = false;
227
+ console.log("[Auth SDK] Socket connected");
228
+ this.emit("connected", {});
229
+ });
230
+ this.socket.on("disconnect", (reason) => {
231
+ console.log("[Auth SDK] Socket disconnected:", reason);
232
+ this.emit("disconnected", { reason });
233
+ });
234
+ this.socket.on("connect_error", (error) => {
235
+ this.isConnecting = false;
236
+ console.error("[Auth SDK] Socket connection error:", error.message);
237
+ this.emit("error", { error: error.message });
238
+ });
239
+ this.socket.on("user:updated", (data) => {
240
+ this.emit("user:updated", data);
241
+ });
242
+ this.socket.on("session:revoked", (data) => {
243
+ this.emit("session:revoked", data);
244
+ });
245
+ this.socket.on("session:all-revoked", () => {
246
+ this.emit("session:all-revoked", {});
247
+ });
248
+ this.socket.on("auth:password-changed", () => {
249
+ this.emit("auth:password-changed", {});
250
+ });
251
+ this.socket.on("auth:2fa-changed", (data) => {
252
+ this.emit("auth:2fa-changed", data);
253
+ });
254
+ this.socket.on("user:refresh", () => {
255
+ this.emit("user:refresh", {});
256
+ });
257
+ }
258
+ disconnect() {
259
+ if (this.socket) {
260
+ this.socket.disconnect();
261
+ this.socket = null;
262
+ this.token = null;
263
+ this.isConnecting = false;
264
+ }
265
+ }
266
+ isConnected() {
267
+ return this.socket?.connected ?? false;
268
+ }
269
+ // Event subscription
270
+ on(event, handler) {
271
+ if (!this.eventHandlers.has(event)) {
272
+ this.eventHandlers.set(event, /* @__PURE__ */ new Set());
273
+ }
274
+ this.eventHandlers.get(event).add(handler);
275
+ return () => {
276
+ this.eventHandlers.get(event)?.delete(handler);
277
+ };
278
+ }
279
+ off(event, handler) {
280
+ if (handler) {
281
+ this.eventHandlers.get(event)?.delete(handler);
282
+ } else {
283
+ this.eventHandlers.delete(event);
284
+ }
285
+ }
286
+ emit(event, data) {
287
+ const handlers = this.eventHandlers.get(event);
288
+ if (handlers) {
289
+ handlers.forEach((handler) => {
290
+ try {
291
+ handler(data);
292
+ } catch (error) {
293
+ console.error(`[Auth SDK] Error in event handler for ${event}:`, error);
294
+ }
295
+ });
296
+ }
297
+ }
298
+ // Request fresh user data from server
299
+ requestUserRefresh() {
300
+ if (this.socket?.connected) {
301
+ this.socket.emit("request:user");
302
+ }
303
+ }
304
+ };
129
305
  var AuthService = class {
306
+ // 5 minutes cache
130
307
  constructor(config) {
131
308
  this.token = null;
132
309
  this.upfilesClient = null;
310
+ this.cachedUser = null;
311
+ this.userCacheTimestamp = 0;
312
+ this.USER_CACHE_TTL = 5 * 60 * 1e3;
133
313
  this.config = {
134
314
  localStorageKey: "auth_token",
135
315
  csrfEnabled: true,
316
+ enableSocket: true,
136
317
  ...config
137
318
  };
138
319
  this.httpClient = new HttpClient(this.config.baseUrl);
320
+ this.socketService = new SocketService({ baseUrl: this.config.baseUrl });
139
321
  this.loadTokenFromStorage();
140
322
  if (this.config.upfilesConfig) {
141
323
  this.upfilesClient = new upfiles.UpfilesClient({
@@ -152,6 +334,9 @@ var AuthService = class {
152
334
  this.httpClient.setFrontendBaseUrl(frontendBaseUrl);
153
335
  }
154
336
  }
337
+ if (this.token && this.config.enableSocket !== false) {
338
+ this.connectSocket();
339
+ }
155
340
  }
156
341
  loadTokenFromStorage() {
157
342
  if (typeof window !== "undefined" && this.config.localStorageKey) {
@@ -184,6 +369,57 @@ var AuthService = class {
184
369
  }
185
370
  }
186
371
  }
372
+ // Socket connection management
373
+ connectSocket() {
374
+ if (this.token && this.config.enableSocket !== false && typeof window !== "undefined") {
375
+ this.socketService.connect(this.token);
376
+ }
377
+ }
378
+ disconnectSocket() {
379
+ this.socketService.disconnect();
380
+ }
381
+ // Socket event subscription
382
+ onUserUpdated(handler) {
383
+ return this.socketService.on("user:updated", (data) => {
384
+ if (data.user) {
385
+ this.cachedUser = data.user;
386
+ this.userCacheTimestamp = Date.now();
387
+ }
388
+ handler(data);
389
+ });
390
+ }
391
+ onSessionRevoked(handler) {
392
+ return this.socketService.on("session:revoked", handler);
393
+ }
394
+ onAllSessionsRevoked(handler) {
395
+ return this.socketService.on("session:all-revoked", handler);
396
+ }
397
+ onPasswordChanged(handler) {
398
+ return this.socketService.on("auth:password-changed", handler);
399
+ }
400
+ on2FAChanged(handler) {
401
+ return this.socketService.on("auth:2fa-changed", handler);
402
+ }
403
+ onSocketConnected(handler) {
404
+ return this.socketService.on("connected", handler);
405
+ }
406
+ onSocketDisconnected(handler) {
407
+ return this.socketService.on("disconnected", handler);
408
+ }
409
+ onSocketError(handler) {
410
+ return this.socketService.on("error", handler);
411
+ }
412
+ isSocketConnected() {
413
+ return this.socketService.isConnected();
414
+ }
415
+ // Cache management
416
+ clearUserCache() {
417
+ this.cachedUser = null;
418
+ this.userCacheTimestamp = 0;
419
+ }
420
+ isCacheValid() {
421
+ return this.cachedUser !== null && Date.now() - this.userCacheTimestamp < this.USER_CACHE_TTL;
422
+ }
187
423
  isAuthenticated() {
188
424
  return !!this.token;
189
425
  }
@@ -249,6 +485,11 @@ var AuthService = class {
249
485
  this.token = response.token;
250
486
  this.httpClient.setAuthToken(response.token);
251
487
  this.saveTokenToStorage(response.token);
488
+ if (response.user) {
489
+ this.cachedUser = response.user;
490
+ this.userCacheTimestamp = Date.now();
491
+ }
492
+ this.connectSocket();
252
493
  return response;
253
494
  }
254
495
  if (response.success && (response.message === "OTP sent to your email." || response.message === "OTP sent to your phone number.")) {
@@ -258,6 +499,11 @@ var AuthService = class {
258
499
  this.token = response.token;
259
500
  this.httpClient.setAuthToken(response.token);
260
501
  this.saveTokenToStorage(response.token);
502
+ if (response.user) {
503
+ this.cachedUser = response.user;
504
+ this.userCacheTimestamp = Date.now();
505
+ }
506
+ this.connectSocket();
261
507
  return response;
262
508
  }
263
509
  throw new Error(response.message || "Login failed");
@@ -301,21 +547,29 @@ var AuthService = class {
301
547
  }
302
548
  }
303
549
  async logout() {
550
+ this.disconnectSocket();
304
551
  try {
305
552
  await this.httpClient.post("/api/v1/auth/logout", {});
306
553
  } catch (error) {
307
554
  console.warn("Failed to call logout endpoint:", error);
308
555
  }
309
556
  this.token = null;
557
+ this.cachedUser = null;
558
+ this.userCacheTimestamp = 0;
310
559
  this.httpClient.removeAuthToken();
311
560
  this.httpClient.removeCsrfToken();
312
561
  this.removeTokenFromStorage();
313
562
  }
314
- async getProfile() {
563
+ async getProfile(forceRefresh = false) {
315
564
  if (!this.token) {
316
565
  throw new Error("Not authenticated");
317
566
  }
567
+ if (!forceRefresh && this.isCacheValid() && this.cachedUser) {
568
+ return this.cachedUser;
569
+ }
318
570
  const response = await this.httpClient.get("/api/v1/user/me");
571
+ this.cachedUser = response.user;
572
+ this.userCacheTimestamp = Date.now();
319
573
  return response.user;
320
574
  }
321
575
  async updateProfile(data) {
@@ -479,6 +733,16 @@ var AuthService = class {
479
733
  );
480
734
  return response;
481
735
  }
736
+ async adminCreateUser(data) {
737
+ if (!this.token) {
738
+ throw new Error("Not authenticated");
739
+ }
740
+ const response = await this.httpClient.post(
741
+ "/api/v1/admin/create-user",
742
+ data
743
+ );
744
+ return response;
745
+ }
482
746
  async adminVerifyUser(userId) {
483
747
  if (!this.token) {
484
748
  throw new Error("Not authenticated");
@@ -587,6 +851,135 @@ var AuthClient = class extends AuthService {
587
851
  }
588
852
  };
589
853
 
854
+ // src/node/token-verifier.ts
855
+ var TokenVerifier = class {
856
+ constructor(config) {
857
+ this.cache = /* @__PURE__ */ new Map();
858
+ this.cleanupInterval = null;
859
+ this.config = {
860
+ cacheTTL: 6e4,
861
+ // 1 minute default
862
+ cacheEnabled: true,
863
+ ...config
864
+ };
865
+ if (this.config.cacheEnabled) {
866
+ this.startCleanup();
867
+ }
868
+ }
869
+ /**
870
+ * Verify a JWT token and get user data
871
+ * Returns cached user if available and valid
872
+ */
873
+ async verifyToken(token) {
874
+ if (!token) {
875
+ return null;
876
+ }
877
+ if (this.config.cacheEnabled) {
878
+ const cached = this.getFromCache(token);
879
+ if (cached) {
880
+ return cached;
881
+ }
882
+ }
883
+ try {
884
+ const response = await fetch(`${this.config.authServiceUrl}/api/v1/user/me`, {
885
+ headers: {
886
+ "Authorization": `Bearer ${token}`,
887
+ "Content-Type": "application/json"
888
+ }
889
+ });
890
+ if (!response.ok) {
891
+ this.cache.delete(token);
892
+ return null;
893
+ }
894
+ const data = await response.json();
895
+ const user = data.user || null;
896
+ if (user && this.config.cacheEnabled) {
897
+ this.setCache(token, user);
898
+ }
899
+ return user;
900
+ } catch (error) {
901
+ console.error("[TokenVerifier] Auth service verification failed:", error);
902
+ return null;
903
+ }
904
+ }
905
+ /**
906
+ * Invalidate cache for a specific token
907
+ */
908
+ invalidateToken(token) {
909
+ this.cache.delete(token);
910
+ }
911
+ /**
912
+ * Clear all cached tokens
913
+ */
914
+ clearCache() {
915
+ this.cache.clear();
916
+ }
917
+ /**
918
+ * Get cache statistics
919
+ */
920
+ getCacheStats() {
921
+ return {
922
+ size: this.cache.size,
923
+ enabled: this.config.cacheEnabled,
924
+ ttl: this.config.cacheTTL
925
+ };
926
+ }
927
+ /**
928
+ * Stop the cleanup interval (call when shutting down)
929
+ */
930
+ destroy() {
931
+ if (this.cleanupInterval) {
932
+ clearInterval(this.cleanupInterval);
933
+ this.cleanupInterval = null;
934
+ }
935
+ this.cache.clear();
936
+ }
937
+ getFromCache(token) {
938
+ const entry = this.cache.get(token);
939
+ if (!entry) {
940
+ return null;
941
+ }
942
+ if (Date.now() > entry.expiresAt) {
943
+ this.cache.delete(token);
944
+ return null;
945
+ }
946
+ return entry.user;
947
+ }
948
+ setCache(token, user) {
949
+ this.cache.set(token, {
950
+ user,
951
+ expiresAt: Date.now() + this.config.cacheTTL
952
+ });
953
+ }
954
+ startCleanup() {
955
+ this.cleanupInterval = setInterval(() => {
956
+ const now = Date.now();
957
+ for (const [token, entry] of this.cache.entries()) {
958
+ if (now > entry.expiresAt) {
959
+ this.cache.delete(token);
960
+ }
961
+ }
962
+ }, 6e4);
963
+ if (this.cleanupInterval && this.cleanupInterval.unref) {
964
+ this.cleanupInterval.unref();
965
+ }
966
+ }
967
+ };
968
+ var defaultVerifier = null;
969
+ function createTokenVerifier(config) {
970
+ defaultVerifier = new TokenVerifier(config);
971
+ return defaultVerifier;
972
+ }
973
+ function getTokenVerifier() {
974
+ if (!defaultVerifier) {
975
+ throw new Error("TokenVerifier not initialized. Call createTokenVerifier() first.");
976
+ }
977
+ return defaultVerifier;
978
+ }
979
+ async function verifyToken(token) {
980
+ return getTokenVerifier().verifyToken(token);
981
+ }
982
+
590
983
  // src/nextjs/server-auth.ts
591
984
  var NextServerAuth = class _NextServerAuth extends AuthClient {
592
985
  constructor(config) {
@@ -790,12 +1183,16 @@ exports.AuthServer = AuthServer;
790
1183
  exports.AuthService = AuthService;
791
1184
  exports.HttpClient = HttpClient;
792
1185
  exports.NextServerAuth = NextServerAuth;
1186
+ exports.TokenVerifier = TokenVerifier;
793
1187
  exports.auth = auth;
794
1188
  exports.authMiddleware = authMiddleware;
795
1189
  exports.createAuthMiddleware = createAuthMiddleware;
1190
+ exports.createTokenVerifier = createTokenVerifier;
796
1191
  exports.currentUser = currentUser;
797
1192
  exports.getAuthServer = getAuthServer;
1193
+ exports.getTokenVerifier = getTokenVerifier;
798
1194
  exports.redirectIfAuthenticated = redirectIfAuthenticated;
799
1195
  exports.requireAuth = requireAuth;
1196
+ exports.verifyToken = verifyToken;
800
1197
  //# sourceMappingURL=index.next.server.js.map
801
1198
  //# sourceMappingURL=index.next.server.js.map