@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 client";
2
2
  import React, { createContext, forwardRef, useContext, useState, useMemo, useEffect, useRef, useCallback } from 'react';
3
3
  import axios from 'axios';
4
+ import { io } from 'socket.io-client';
4
5
  import { ImageManager, UpfilesClient } from '@thetechfossil/upfiles';
5
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
7
 
@@ -10,6 +11,16 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
10
11
  if (typeof require !== "undefined") return require.apply(this, arguments);
11
12
  throw Error('Dynamic require of "' + x + '" is not supported');
12
13
  });
14
+ var ERROR_MESSAGES = {
15
+ NETWORK_ERROR: "Unable to connect to the server. Please check your internet connection and try again.",
16
+ TIMEOUT: "The request took too long. Please try again.",
17
+ SERVER_ERROR: "Something went wrong on our end. Please try again later.",
18
+ UNAUTHORIZED: "Your session has expired. Please log in again.",
19
+ FORBIDDEN: "You do not have permission to perform this action.",
20
+ NOT_FOUND: "The requested resource was not found.",
21
+ RATE_LIMITED: "Too many requests. Please wait a moment and try again.",
22
+ UNKNOWN: "An unexpected error occurred. Please try again."
23
+ };
13
24
  var HttpClient = class {
14
25
  constructor(baseUrl, defaultHeaders = {}) {
15
26
  this.csrfToken = null;
@@ -44,7 +55,7 @@ var HttpClient = class {
44
55
  }
45
56
  return config;
46
57
  },
47
- (error) => Promise.reject(error)
58
+ (error) => Promise.reject(this.createUserFriendlyError(error))
48
59
  );
49
60
  this.axiosInstance.interceptors.response.use(
50
61
  (response) => response,
@@ -59,18 +70,71 @@ var HttpClient = class {
59
70
  }
60
71
  return this.axiosInstance(originalRequest);
61
72
  } catch (refreshError) {
62
- return Promise.reject(refreshError);
73
+ return Promise.reject(this.createUserFriendlyError(refreshError));
63
74
  }
64
75
  }
65
- if (error.response && error.response.data && error.response.data.message) {
66
- const customError = new Error(error.response.data.message);
67
- customError.response = error.response;
68
- return Promise.reject(customError);
69
- }
70
- return Promise.reject(error);
76
+ return Promise.reject(this.createUserFriendlyError(error));
71
77
  }
72
78
  );
73
79
  }
80
+ /**
81
+ * Creates a user-friendly error message from an Axios error
82
+ */
83
+ createUserFriendlyError(error) {
84
+ if (error instanceof Error && !error.isAxiosError) {
85
+ return error;
86
+ }
87
+ let message;
88
+ let statusCode;
89
+ if (axios.isAxiosError(error)) {
90
+ statusCode = error.response?.status;
91
+ const responseData = error.response?.data;
92
+ if (responseData?.message) {
93
+ message = responseData.message;
94
+ } else if (!error.response) {
95
+ if (error.code === "ECONNABORTED" || error.message.includes("timeout")) {
96
+ message = ERROR_MESSAGES.TIMEOUT;
97
+ } else if (error.code === "ERR_NETWORK" || error.message === "Network Error") {
98
+ message = ERROR_MESSAGES.NETWORK_ERROR;
99
+ } else {
100
+ message = ERROR_MESSAGES.NETWORK_ERROR;
101
+ }
102
+ } else {
103
+ switch (statusCode) {
104
+ case 400:
105
+ message = responseData?.message || "Invalid request. Please check your input.";
106
+ break;
107
+ case 401:
108
+ message = responseData?.message || ERROR_MESSAGES.UNAUTHORIZED;
109
+ break;
110
+ case 403:
111
+ message = responseData?.message || ERROR_MESSAGES.FORBIDDEN;
112
+ break;
113
+ case 404:
114
+ message = responseData?.message || ERROR_MESSAGES.NOT_FOUND;
115
+ break;
116
+ case 429:
117
+ message = ERROR_MESSAGES.RATE_LIMITED;
118
+ break;
119
+ case 500:
120
+ case 502:
121
+ case 503:
122
+ case 504:
123
+ message = ERROR_MESSAGES.SERVER_ERROR;
124
+ break;
125
+ default:
126
+ message = responseData?.message || ERROR_MESSAGES.UNKNOWN;
127
+ }
128
+ }
129
+ } else {
130
+ message = error?.message || ERROR_MESSAGES.UNKNOWN;
131
+ }
132
+ const customError = new Error(message);
133
+ customError.response = error?.response;
134
+ customError.statusCode = statusCode;
135
+ customError.originalError = error;
136
+ return customError;
137
+ }
74
138
  async get(endpoint, headers) {
75
139
  const response = await this.axiosInstance.get(endpoint, { headers });
76
140
  return response.data;
@@ -121,16 +185,134 @@ var HttpClient = class {
121
185
  }
122
186
  }
123
187
  };
188
+ var SocketService = class {
189
+ constructor(config) {
190
+ this.socket = null;
191
+ this.token = null;
192
+ this.eventHandlers = /* @__PURE__ */ new Map();
193
+ this.isConnecting = false;
194
+ this.config = {
195
+ autoConnect: false,
196
+ reconnection: true,
197
+ reconnectionAttempts: 5,
198
+ reconnectionDelay: 1e3,
199
+ ...config
200
+ };
201
+ }
202
+ connect(token) {
203
+ if (this.socket?.connected || this.isConnecting) {
204
+ return;
205
+ }
206
+ this.token = token;
207
+ this.isConnecting = true;
208
+ this.socket = io(this.config.baseUrl, {
209
+ auth: { token },
210
+ autoConnect: true,
211
+ reconnection: this.config.reconnection,
212
+ reconnectionAttempts: this.config.reconnectionAttempts,
213
+ reconnectionDelay: this.config.reconnectionDelay,
214
+ transports: ["websocket", "polling"]
215
+ });
216
+ this.setupEventListeners();
217
+ }
218
+ setupEventListeners() {
219
+ if (!this.socket) return;
220
+ this.socket.on("connect", () => {
221
+ this.isConnecting = false;
222
+ console.log("[Auth SDK] Socket connected");
223
+ this.emit("connected", {});
224
+ });
225
+ this.socket.on("disconnect", (reason) => {
226
+ console.log("[Auth SDK] Socket disconnected:", reason);
227
+ this.emit("disconnected", { reason });
228
+ });
229
+ this.socket.on("connect_error", (error) => {
230
+ this.isConnecting = false;
231
+ console.error("[Auth SDK] Socket connection error:", error.message);
232
+ this.emit("error", { error: error.message });
233
+ });
234
+ this.socket.on("user:updated", (data) => {
235
+ this.emit("user:updated", data);
236
+ });
237
+ this.socket.on("session:revoked", (data) => {
238
+ this.emit("session:revoked", data);
239
+ });
240
+ this.socket.on("session:all-revoked", () => {
241
+ this.emit("session:all-revoked", {});
242
+ });
243
+ this.socket.on("auth:password-changed", () => {
244
+ this.emit("auth:password-changed", {});
245
+ });
246
+ this.socket.on("auth:2fa-changed", (data) => {
247
+ this.emit("auth:2fa-changed", data);
248
+ });
249
+ this.socket.on("user:refresh", () => {
250
+ this.emit("user:refresh", {});
251
+ });
252
+ }
253
+ disconnect() {
254
+ if (this.socket) {
255
+ this.socket.disconnect();
256
+ this.socket = null;
257
+ this.token = null;
258
+ this.isConnecting = false;
259
+ }
260
+ }
261
+ isConnected() {
262
+ return this.socket?.connected ?? false;
263
+ }
264
+ // Event subscription
265
+ on(event, handler) {
266
+ if (!this.eventHandlers.has(event)) {
267
+ this.eventHandlers.set(event, /* @__PURE__ */ new Set());
268
+ }
269
+ this.eventHandlers.get(event).add(handler);
270
+ return () => {
271
+ this.eventHandlers.get(event)?.delete(handler);
272
+ };
273
+ }
274
+ off(event, handler) {
275
+ if (handler) {
276
+ this.eventHandlers.get(event)?.delete(handler);
277
+ } else {
278
+ this.eventHandlers.delete(event);
279
+ }
280
+ }
281
+ emit(event, data) {
282
+ const handlers = this.eventHandlers.get(event);
283
+ if (handlers) {
284
+ handlers.forEach((handler) => {
285
+ try {
286
+ handler(data);
287
+ } catch (error) {
288
+ console.error(`[Auth SDK] Error in event handler for ${event}:`, error);
289
+ }
290
+ });
291
+ }
292
+ }
293
+ // Request fresh user data from server
294
+ requestUserRefresh() {
295
+ if (this.socket?.connected) {
296
+ this.socket.emit("request:user");
297
+ }
298
+ }
299
+ };
124
300
  var AuthService = class {
301
+ // 5 minutes cache
125
302
  constructor(config) {
126
303
  this.token = null;
127
304
  this.upfilesClient = null;
305
+ this.cachedUser = null;
306
+ this.userCacheTimestamp = 0;
307
+ this.USER_CACHE_TTL = 5 * 60 * 1e3;
128
308
  this.config = {
129
309
  localStorageKey: "auth_token",
130
310
  csrfEnabled: true,
311
+ enableSocket: true,
131
312
  ...config
132
313
  };
133
314
  this.httpClient = new HttpClient(this.config.baseUrl);
315
+ this.socketService = new SocketService({ baseUrl: this.config.baseUrl });
134
316
  this.loadTokenFromStorage();
135
317
  if (this.config.upfilesConfig) {
136
318
  this.upfilesClient = new UpfilesClient({
@@ -147,6 +329,9 @@ var AuthService = class {
147
329
  this.httpClient.setFrontendBaseUrl(frontendBaseUrl);
148
330
  }
149
331
  }
332
+ if (this.token && this.config.enableSocket !== false) {
333
+ this.connectSocket();
334
+ }
150
335
  }
151
336
  loadTokenFromStorage() {
152
337
  if (typeof window !== "undefined" && this.config.localStorageKey) {
@@ -179,6 +364,57 @@ var AuthService = class {
179
364
  }
180
365
  }
181
366
  }
367
+ // Socket connection management
368
+ connectSocket() {
369
+ if (this.token && this.config.enableSocket !== false && typeof window !== "undefined") {
370
+ this.socketService.connect(this.token);
371
+ }
372
+ }
373
+ disconnectSocket() {
374
+ this.socketService.disconnect();
375
+ }
376
+ // Socket event subscription
377
+ onUserUpdated(handler) {
378
+ return this.socketService.on("user:updated", (data) => {
379
+ if (data.user) {
380
+ this.cachedUser = data.user;
381
+ this.userCacheTimestamp = Date.now();
382
+ }
383
+ handler(data);
384
+ });
385
+ }
386
+ onSessionRevoked(handler) {
387
+ return this.socketService.on("session:revoked", handler);
388
+ }
389
+ onAllSessionsRevoked(handler) {
390
+ return this.socketService.on("session:all-revoked", handler);
391
+ }
392
+ onPasswordChanged(handler) {
393
+ return this.socketService.on("auth:password-changed", handler);
394
+ }
395
+ on2FAChanged(handler) {
396
+ return this.socketService.on("auth:2fa-changed", handler);
397
+ }
398
+ onSocketConnected(handler) {
399
+ return this.socketService.on("connected", handler);
400
+ }
401
+ onSocketDisconnected(handler) {
402
+ return this.socketService.on("disconnected", handler);
403
+ }
404
+ onSocketError(handler) {
405
+ return this.socketService.on("error", handler);
406
+ }
407
+ isSocketConnected() {
408
+ return this.socketService.isConnected();
409
+ }
410
+ // Cache management
411
+ clearUserCache() {
412
+ this.cachedUser = null;
413
+ this.userCacheTimestamp = 0;
414
+ }
415
+ isCacheValid() {
416
+ return this.cachedUser !== null && Date.now() - this.userCacheTimestamp < this.USER_CACHE_TTL;
417
+ }
182
418
  isAuthenticated() {
183
419
  return !!this.token;
184
420
  }
@@ -244,6 +480,11 @@ var AuthService = class {
244
480
  this.token = response.token;
245
481
  this.httpClient.setAuthToken(response.token);
246
482
  this.saveTokenToStorage(response.token);
483
+ if (response.user) {
484
+ this.cachedUser = response.user;
485
+ this.userCacheTimestamp = Date.now();
486
+ }
487
+ this.connectSocket();
247
488
  return response;
248
489
  }
249
490
  if (response.success && (response.message === "OTP sent to your email." || response.message === "OTP sent to your phone number.")) {
@@ -253,6 +494,11 @@ var AuthService = class {
253
494
  this.token = response.token;
254
495
  this.httpClient.setAuthToken(response.token);
255
496
  this.saveTokenToStorage(response.token);
497
+ if (response.user) {
498
+ this.cachedUser = response.user;
499
+ this.userCacheTimestamp = Date.now();
500
+ }
501
+ this.connectSocket();
256
502
  return response;
257
503
  }
258
504
  throw new Error(response.message || "Login failed");
@@ -296,21 +542,29 @@ var AuthService = class {
296
542
  }
297
543
  }
298
544
  async logout() {
545
+ this.disconnectSocket();
299
546
  try {
300
547
  await this.httpClient.post("/api/v1/auth/logout", {});
301
548
  } catch (error) {
302
549
  console.warn("Failed to call logout endpoint:", error);
303
550
  }
304
551
  this.token = null;
552
+ this.cachedUser = null;
553
+ this.userCacheTimestamp = 0;
305
554
  this.httpClient.removeAuthToken();
306
555
  this.httpClient.removeCsrfToken();
307
556
  this.removeTokenFromStorage();
308
557
  }
309
- async getProfile() {
558
+ async getProfile(forceRefresh = false) {
310
559
  if (!this.token) {
311
560
  throw new Error("Not authenticated");
312
561
  }
562
+ if (!forceRefresh && this.isCacheValid() && this.cachedUser) {
563
+ return this.cachedUser;
564
+ }
313
565
  const response = await this.httpClient.get("/api/v1/user/me");
566
+ this.cachedUser = response.user;
567
+ this.userCacheTimestamp = Date.now();
314
568
  return response.user;
315
569
  }
316
570
  async updateProfile(data) {
@@ -474,6 +728,16 @@ var AuthService = class {
474
728
  );
475
729
  return response;
476
730
  }
731
+ async adminCreateUser(data) {
732
+ if (!this.token) {
733
+ throw new Error("Not authenticated");
734
+ }
735
+ const response = await this.httpClient.post(
736
+ "/api/v1/admin/create-user",
737
+ data
738
+ );
739
+ return response;
740
+ }
477
741
  async adminVerifyUser(userId) {
478
742
  if (!this.token) {
479
743
  throw new Error("Not authenticated");
@@ -4133,11 +4397,11 @@ var ChangePassword = ({ onSuccess, appearance }) => {
4133
4397
 
4134
4398
  // src/react/components/utils/injectModalStyles.ts
4135
4399
  var injectModalStyles = () => {
4136
- if (document.getElementById("ttf-auth-modal-styles")) {
4400
+ if (document.getElementById("ktw-auth-modal-styles")) {
4137
4401
  return;
4138
4402
  }
4139
4403
  const styleElement = document.createElement("style");
4140
- styleElement.id = "ttf-auth-modal-styles";
4404
+ styleElement.id = "ktw-auth-modal-styles";
4141
4405
  styleElement.textContent = `
4142
4406
  /* ImageManager Modal Styles - Critical for proper modal display */
4143
4407
  /* Radix UI Dialog styles - Force visibility */