@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
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://
|
|
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
|
package/dist/index.components.js
CHANGED
|
@@ -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
|
-
|
|
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("
|
|
4407
|
+
if (document.getElementById("ktw-auth-modal-styles")) {
|
|
4144
4408
|
return;
|
|
4145
4409
|
}
|
|
4146
4410
|
const styleElement = document.createElement("style");
|
|
4147
|
-
styleElement.id = "
|
|
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 */
|