@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
package/README.md CHANGED
@@ -15,7 +15,7 @@ A lightweight, easy-to-use authentication SDK for integrating with the Auth back
15
15
 
16
16
  ## Documentation
17
17
 
18
- 📚 **Complete documentation is available at:** [https://ttf-auth-docs.netlify.app/](https://ttf-auth-docs.netlify.app/)
18
+ 📚 **Complete documentation is available at:** [https://ktw-auth-docs.netlify.app/](https://ktw-auth-docs.netlify.app/)
19
19
 
20
20
  The documentation includes:
21
21
  - Getting started guides
@@ -24,6 +24,7 @@ interface AuthConfig {
24
24
  localStorageKey?: string;
25
25
  token?: string;
26
26
  csrfEnabled?: boolean;
27
+ enableSocket?: boolean;
27
28
  upfilesConfig?: UpfilesConfig;
28
29
  }
29
30
  interface UpfilesConfig {
@@ -24,6 +24,7 @@ interface AuthConfig {
24
24
  localStorageKey?: string;
25
25
  token?: string;
26
26
  csrfEnabled?: boolean;
27
+ enableSocket?: boolean;
27
28
  upfilesConfig?: UpfilesConfig;
28
29
  }
29
30
  interface UpfilesConfig {
@@ -3,6 +3,7 @@
3
3
 
4
4
  var React = require('react');
5
5
  var axios = require('axios');
6
+ var socket_ioClient = require('socket.io-client');
6
7
  var upfiles = require('@thetechfossil/upfiles');
7
8
  var jsxRuntime = require('react/jsx-runtime');
8
9
 
@@ -17,6 +18,16 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
17
18
  if (typeof require !== "undefined") return require.apply(this, arguments);
18
19
  throw Error('Dynamic require of "' + x + '" is not supported');
19
20
  });
21
+ var ERROR_MESSAGES = {
22
+ NETWORK_ERROR: "Unable to connect to the server. Please check your internet connection and try again.",
23
+ TIMEOUT: "The request took too long. Please try again.",
24
+ SERVER_ERROR: "Something went wrong on our end. Please try again later.",
25
+ UNAUTHORIZED: "Your session has expired. Please log in again.",
26
+ FORBIDDEN: "You do not have permission to perform this action.",
27
+ NOT_FOUND: "The requested resource was not found.",
28
+ RATE_LIMITED: "Too many requests. Please wait a moment and try again.",
29
+ UNKNOWN: "An unexpected error occurred. Please try again."
30
+ };
20
31
  var HttpClient = class {
21
32
  constructor(baseUrl, defaultHeaders = {}) {
22
33
  this.csrfToken = null;
@@ -51,7 +62,7 @@ var HttpClient = class {
51
62
  }
52
63
  return config;
53
64
  },
54
- (error) => Promise.reject(error)
65
+ (error) => Promise.reject(this.createUserFriendlyError(error))
55
66
  );
56
67
  this.axiosInstance.interceptors.response.use(
57
68
  (response) => response,
@@ -66,18 +77,71 @@ var HttpClient = class {
66
77
  }
67
78
  return this.axiosInstance(originalRequest);
68
79
  } catch (refreshError) {
69
- return Promise.reject(refreshError);
80
+ return Promise.reject(this.createUserFriendlyError(refreshError));
70
81
  }
71
82
  }
72
- if (error.response && error.response.data && error.response.data.message) {
73
- const customError = new Error(error.response.data.message);
74
- customError.response = error.response;
75
- return Promise.reject(customError);
76
- }
77
- return Promise.reject(error);
83
+ return Promise.reject(this.createUserFriendlyError(error));
78
84
  }
79
85
  );
80
86
  }
87
+ /**
88
+ * Creates a user-friendly error message from an Axios error
89
+ */
90
+ createUserFriendlyError(error) {
91
+ if (error instanceof Error && !error.isAxiosError) {
92
+ return error;
93
+ }
94
+ let message;
95
+ let statusCode;
96
+ if (axios__default.default.isAxiosError(error)) {
97
+ statusCode = error.response?.status;
98
+ const responseData = error.response?.data;
99
+ if (responseData?.message) {
100
+ message = responseData.message;
101
+ } else if (!error.response) {
102
+ if (error.code === "ECONNABORTED" || error.message.includes("timeout")) {
103
+ message = ERROR_MESSAGES.TIMEOUT;
104
+ } else if (error.code === "ERR_NETWORK" || error.message === "Network Error") {
105
+ message = ERROR_MESSAGES.NETWORK_ERROR;
106
+ } else {
107
+ message = ERROR_MESSAGES.NETWORK_ERROR;
108
+ }
109
+ } else {
110
+ switch (statusCode) {
111
+ case 400:
112
+ message = responseData?.message || "Invalid request. Please check your input.";
113
+ break;
114
+ case 401:
115
+ message = responseData?.message || ERROR_MESSAGES.UNAUTHORIZED;
116
+ break;
117
+ case 403:
118
+ message = responseData?.message || ERROR_MESSAGES.FORBIDDEN;
119
+ break;
120
+ case 404:
121
+ message = responseData?.message || ERROR_MESSAGES.NOT_FOUND;
122
+ break;
123
+ case 429:
124
+ message = ERROR_MESSAGES.RATE_LIMITED;
125
+ break;
126
+ case 500:
127
+ case 502:
128
+ case 503:
129
+ case 504:
130
+ message = ERROR_MESSAGES.SERVER_ERROR;
131
+ break;
132
+ default:
133
+ message = responseData?.message || ERROR_MESSAGES.UNKNOWN;
134
+ }
135
+ }
136
+ } else {
137
+ message = error?.message || ERROR_MESSAGES.UNKNOWN;
138
+ }
139
+ const customError = new Error(message);
140
+ customError.response = error?.response;
141
+ customError.statusCode = statusCode;
142
+ customError.originalError = error;
143
+ return customError;
144
+ }
81
145
  async get(endpoint, headers) {
82
146
  const response = await this.axiosInstance.get(endpoint, { headers });
83
147
  return response.data;
@@ -128,16 +192,134 @@ var HttpClient = class {
128
192
  }
129
193
  }
130
194
  };
195
+ var SocketService = class {
196
+ constructor(config) {
197
+ this.socket = null;
198
+ this.token = null;
199
+ this.eventHandlers = /* @__PURE__ */ new Map();
200
+ this.isConnecting = false;
201
+ this.config = {
202
+ autoConnect: false,
203
+ reconnection: true,
204
+ reconnectionAttempts: 5,
205
+ reconnectionDelay: 1e3,
206
+ ...config
207
+ };
208
+ }
209
+ connect(token) {
210
+ if (this.socket?.connected || this.isConnecting) {
211
+ return;
212
+ }
213
+ this.token = token;
214
+ this.isConnecting = true;
215
+ this.socket = socket_ioClient.io(this.config.baseUrl, {
216
+ auth: { token },
217
+ autoConnect: true,
218
+ reconnection: this.config.reconnection,
219
+ reconnectionAttempts: this.config.reconnectionAttempts,
220
+ reconnectionDelay: this.config.reconnectionDelay,
221
+ transports: ["websocket", "polling"]
222
+ });
223
+ this.setupEventListeners();
224
+ }
225
+ setupEventListeners() {
226
+ if (!this.socket) return;
227
+ this.socket.on("connect", () => {
228
+ this.isConnecting = false;
229
+ console.log("[Auth SDK] Socket connected");
230
+ this.emit("connected", {});
231
+ });
232
+ this.socket.on("disconnect", (reason) => {
233
+ console.log("[Auth SDK] Socket disconnected:", reason);
234
+ this.emit("disconnected", { reason });
235
+ });
236
+ this.socket.on("connect_error", (error) => {
237
+ this.isConnecting = false;
238
+ console.error("[Auth SDK] Socket connection error:", error.message);
239
+ this.emit("error", { error: error.message });
240
+ });
241
+ this.socket.on("user:updated", (data) => {
242
+ this.emit("user:updated", data);
243
+ });
244
+ this.socket.on("session:revoked", (data) => {
245
+ this.emit("session:revoked", data);
246
+ });
247
+ this.socket.on("session:all-revoked", () => {
248
+ this.emit("session:all-revoked", {});
249
+ });
250
+ this.socket.on("auth:password-changed", () => {
251
+ this.emit("auth:password-changed", {});
252
+ });
253
+ this.socket.on("auth:2fa-changed", (data) => {
254
+ this.emit("auth:2fa-changed", data);
255
+ });
256
+ this.socket.on("user:refresh", () => {
257
+ this.emit("user:refresh", {});
258
+ });
259
+ }
260
+ disconnect() {
261
+ if (this.socket) {
262
+ this.socket.disconnect();
263
+ this.socket = null;
264
+ this.token = null;
265
+ this.isConnecting = false;
266
+ }
267
+ }
268
+ isConnected() {
269
+ return this.socket?.connected ?? false;
270
+ }
271
+ // Event subscription
272
+ on(event, handler) {
273
+ if (!this.eventHandlers.has(event)) {
274
+ this.eventHandlers.set(event, /* @__PURE__ */ new Set());
275
+ }
276
+ this.eventHandlers.get(event).add(handler);
277
+ return () => {
278
+ this.eventHandlers.get(event)?.delete(handler);
279
+ };
280
+ }
281
+ off(event, handler) {
282
+ if (handler) {
283
+ this.eventHandlers.get(event)?.delete(handler);
284
+ } else {
285
+ this.eventHandlers.delete(event);
286
+ }
287
+ }
288
+ emit(event, data) {
289
+ const handlers = this.eventHandlers.get(event);
290
+ if (handlers) {
291
+ handlers.forEach((handler) => {
292
+ try {
293
+ handler(data);
294
+ } catch (error) {
295
+ console.error(`[Auth SDK] Error in event handler for ${event}:`, error);
296
+ }
297
+ });
298
+ }
299
+ }
300
+ // Request fresh user data from server
301
+ requestUserRefresh() {
302
+ if (this.socket?.connected) {
303
+ this.socket.emit("request:user");
304
+ }
305
+ }
306
+ };
131
307
  var AuthService = class {
308
+ // 5 minutes cache
132
309
  constructor(config) {
133
310
  this.token = null;
134
311
  this.upfilesClient = null;
312
+ this.cachedUser = null;
313
+ this.userCacheTimestamp = 0;
314
+ this.USER_CACHE_TTL = 5 * 60 * 1e3;
135
315
  this.config = {
136
316
  localStorageKey: "auth_token",
137
317
  csrfEnabled: true,
318
+ enableSocket: true,
138
319
  ...config
139
320
  };
140
321
  this.httpClient = new HttpClient(this.config.baseUrl);
322
+ this.socketService = new SocketService({ baseUrl: this.config.baseUrl });
141
323
  this.loadTokenFromStorage();
142
324
  if (this.config.upfilesConfig) {
143
325
  this.upfilesClient = new upfiles.UpfilesClient({
@@ -154,6 +336,9 @@ var AuthService = class {
154
336
  this.httpClient.setFrontendBaseUrl(frontendBaseUrl);
155
337
  }
156
338
  }
339
+ if (this.token && this.config.enableSocket !== false) {
340
+ this.connectSocket();
341
+ }
157
342
  }
158
343
  loadTokenFromStorage() {
159
344
  if (typeof window !== "undefined" && this.config.localStorageKey) {
@@ -186,6 +371,57 @@ var AuthService = class {
186
371
  }
187
372
  }
188
373
  }
374
+ // Socket connection management
375
+ connectSocket() {
376
+ if (this.token && this.config.enableSocket !== false && typeof window !== "undefined") {
377
+ this.socketService.connect(this.token);
378
+ }
379
+ }
380
+ disconnectSocket() {
381
+ this.socketService.disconnect();
382
+ }
383
+ // Socket event subscription
384
+ onUserUpdated(handler) {
385
+ return this.socketService.on("user:updated", (data) => {
386
+ if (data.user) {
387
+ this.cachedUser = data.user;
388
+ this.userCacheTimestamp = Date.now();
389
+ }
390
+ handler(data);
391
+ });
392
+ }
393
+ onSessionRevoked(handler) {
394
+ return this.socketService.on("session:revoked", handler);
395
+ }
396
+ onAllSessionsRevoked(handler) {
397
+ return this.socketService.on("session:all-revoked", handler);
398
+ }
399
+ onPasswordChanged(handler) {
400
+ return this.socketService.on("auth:password-changed", handler);
401
+ }
402
+ on2FAChanged(handler) {
403
+ return this.socketService.on("auth:2fa-changed", handler);
404
+ }
405
+ onSocketConnected(handler) {
406
+ return this.socketService.on("connected", handler);
407
+ }
408
+ onSocketDisconnected(handler) {
409
+ return this.socketService.on("disconnected", handler);
410
+ }
411
+ onSocketError(handler) {
412
+ return this.socketService.on("error", handler);
413
+ }
414
+ isSocketConnected() {
415
+ return this.socketService.isConnected();
416
+ }
417
+ // Cache management
418
+ clearUserCache() {
419
+ this.cachedUser = null;
420
+ this.userCacheTimestamp = 0;
421
+ }
422
+ isCacheValid() {
423
+ return this.cachedUser !== null && Date.now() - this.userCacheTimestamp < this.USER_CACHE_TTL;
424
+ }
189
425
  isAuthenticated() {
190
426
  return !!this.token;
191
427
  }
@@ -251,6 +487,11 @@ var AuthService = class {
251
487
  this.token = response.token;
252
488
  this.httpClient.setAuthToken(response.token);
253
489
  this.saveTokenToStorage(response.token);
490
+ if (response.user) {
491
+ this.cachedUser = response.user;
492
+ this.userCacheTimestamp = Date.now();
493
+ }
494
+ this.connectSocket();
254
495
  return response;
255
496
  }
256
497
  if (response.success && (response.message === "OTP sent to your email." || response.message === "OTP sent to your phone number.")) {
@@ -260,6 +501,11 @@ var AuthService = class {
260
501
  this.token = response.token;
261
502
  this.httpClient.setAuthToken(response.token);
262
503
  this.saveTokenToStorage(response.token);
504
+ if (response.user) {
505
+ this.cachedUser = response.user;
506
+ this.userCacheTimestamp = Date.now();
507
+ }
508
+ this.connectSocket();
263
509
  return response;
264
510
  }
265
511
  throw new Error(response.message || "Login failed");
@@ -303,21 +549,29 @@ var AuthService = class {
303
549
  }
304
550
  }
305
551
  async logout() {
552
+ this.disconnectSocket();
306
553
  try {
307
554
  await this.httpClient.post("/api/v1/auth/logout", {});
308
555
  } catch (error) {
309
556
  console.warn("Failed to call logout endpoint:", error);
310
557
  }
311
558
  this.token = null;
559
+ this.cachedUser = null;
560
+ this.userCacheTimestamp = 0;
312
561
  this.httpClient.removeAuthToken();
313
562
  this.httpClient.removeCsrfToken();
314
563
  this.removeTokenFromStorage();
315
564
  }
316
- async getProfile() {
565
+ async getProfile(forceRefresh = false) {
317
566
  if (!this.token) {
318
567
  throw new Error("Not authenticated");
319
568
  }
569
+ if (!forceRefresh && this.isCacheValid() && this.cachedUser) {
570
+ return this.cachedUser;
571
+ }
320
572
  const response = await this.httpClient.get("/api/v1/user/me");
573
+ this.cachedUser = response.user;
574
+ this.userCacheTimestamp = Date.now();
321
575
  return response.user;
322
576
  }
323
577
  async updateProfile(data) {
@@ -481,6 +735,16 @@ var AuthService = class {
481
735
  );
482
736
  return response;
483
737
  }
738
+ async adminCreateUser(data) {
739
+ if (!this.token) {
740
+ throw new Error("Not authenticated");
741
+ }
742
+ const response = await this.httpClient.post(
743
+ "/api/v1/admin/create-user",
744
+ data
745
+ );
746
+ return response;
747
+ }
484
748
  async adminVerifyUser(userId) {
485
749
  if (!this.token) {
486
750
  throw new Error("Not authenticated");
@@ -4140,11 +4404,11 @@ var ChangePassword = ({ onSuccess, appearance }) => {
4140
4404
 
4141
4405
  // src/react/components/utils/injectModalStyles.ts
4142
4406
  var injectModalStyles = () => {
4143
- if (document.getElementById("ttf-auth-modal-styles")) {
4407
+ if (document.getElementById("ktw-auth-modal-styles")) {
4144
4408
  return;
4145
4409
  }
4146
4410
  const styleElement = document.createElement("style");
4147
- styleElement.id = "ttf-auth-modal-styles";
4411
+ styleElement.id = "ktw-auth-modal-styles";
4148
4412
  styleElement.textContent = `
4149
4413
  /* ImageManager Modal Styles - Critical for proper modal display */
4150
4414
  /* Radix UI Dialog styles - Force visibility */