@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
|
@@ -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
|
-
|
|
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("
|
|
4400
|
+
if (document.getElementById("ktw-auth-modal-styles")) {
|
|
4137
4401
|
return;
|
|
4138
4402
|
}
|
|
4139
4403
|
const styleElement = document.createElement("style");
|
|
4140
|
-
styleElement.id = "
|
|
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 */
|