falconhub-apilibrary 1.1.0

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/dist/index.js ADDED
@@ -0,0 +1,867 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ API: () => API,
34
+ AuthInterceptor: () => AuthInterceptor,
35
+ AuthService: () => AuthService,
36
+ CryptoService: () => CryptoService,
37
+ FalconHUBSDK: () => FalconHUBSDK,
38
+ TokenManager: () => TokenManager
39
+ });
40
+ module.exports = __toCommonJS(index_exports);
41
+
42
+ // src/types/ErrorResponse.ts
43
+ var ErrorResponse = class extends Error {
44
+ constructor(message, statusCode, responseData) {
45
+ super(message);
46
+ this.statusCode = statusCode;
47
+ this.responseData = responseData;
48
+ this.name = "FalconHUB API Error";
49
+ }
50
+ };
51
+
52
+ // src/core/API.ts
53
+ var API = class {
54
+ constructor(properties, cryptoService, authInterceptor, getAccessToken, getRefreshToken) {
55
+ this.properties = properties;
56
+ this.cryptoService = cryptoService;
57
+ this.getAccessToken = getAccessToken;
58
+ this.getRefreshToken = getRefreshToken;
59
+ this.authInterceptor = authInterceptor;
60
+ }
61
+ /**
62
+ * Ejecuta una request HTTP al API
63
+ *
64
+ * @param options - Opciones de la request
65
+ * @returns Respuesta parseada del tipo esperado
66
+ */
67
+ async apiExecute(options) {
68
+ const {
69
+ endpoint,
70
+ method,
71
+ body,
72
+ requiresSignature,
73
+ requiresAuth,
74
+ timeStamp
75
+ } = options;
76
+ const context = {
77
+ requestId: this.cryptoService.generateUniqueId(),
78
+ startTime: Date.now(),
79
+ retryCount: 0,
80
+ metadata: {}
81
+ };
82
+ try {
83
+ const url = `${this.properties.url}/${endpoint}`;
84
+ const headers = {};
85
+ if (body && method !== "GET") {
86
+ headers["Content-Type"] = "application/json";
87
+ }
88
+ ;
89
+ const accessToken = this.getAccessToken();
90
+ if (accessToken) {
91
+ headers["Authorization"] = `Bearer ${accessToken}`;
92
+ }
93
+ ;
94
+ const newTimeStamp = timeStamp || (/* @__PURE__ */ new Date()).toString();
95
+ headers["X-Timestamp"] = newTimeStamp;
96
+ let bodyString;
97
+ if (body && method !== "GET") {
98
+ bodyString = JSON.stringify(body);
99
+ }
100
+ ;
101
+ if (requiresSignature && bodyString) {
102
+ try {
103
+ const refreshToken = this.getRefreshToken();
104
+ if (refreshToken) {
105
+ const signature = this.cryptoService.genSignature(
106
+ bodyString,
107
+ newTimeStamp,
108
+ refreshToken
109
+ );
110
+ if (signature) {
111
+ headers["X-Signature"] = signature;
112
+ }
113
+ ;
114
+ }
115
+ ;
116
+ } catch (error) {
117
+ throw new ErrorResponse(
118
+ "Failed to generate request signature.",
119
+ 401
120
+ );
121
+ }
122
+ ;
123
+ }
124
+ ;
125
+ const requestConfig = {
126
+ url,
127
+ method,
128
+ headers,
129
+ body: bodyString,
130
+ requiresAuth,
131
+ requiresSignature
132
+ };
133
+ const modifiedConfig = this.authInterceptor ? await this.authInterceptor.onRequest(requestConfig, context) : requestConfig;
134
+ const requestInit = {
135
+ method: modifiedConfig.method,
136
+ headers: modifiedConfig.headers,
137
+ mode: "cors",
138
+ credentials: "omit"
139
+ };
140
+ if (bodyString) {
141
+ requestInit.body = bodyString;
142
+ }
143
+ ;
144
+ const response = await fetch(
145
+ modifiedConfig.url,
146
+ requestInit
147
+ );
148
+ if (response.ok) {
149
+ const newAccessToken = response.headers.get("X-New-Access-Token");
150
+ const newRefreshToken = response.headers.get("X-New-Refresh-Token");
151
+ if (newAccessToken || newRefreshToken) {
152
+ this.properties.onTokensRefreshed?.({
153
+ accessToken: newAccessToken,
154
+ refreshToken: newRefreshToken
155
+ });
156
+ }
157
+ ;
158
+ const contentType = response.headers.get("Content-Type");
159
+ if (contentType && contentType.includes("application/json")) {
160
+ const responseText = await response.text();
161
+ return JSON.parse(responseText);
162
+ }
163
+ ;
164
+ return void 0;
165
+ } else {
166
+ await this.handleErrorResponse(response);
167
+ }
168
+ ;
169
+ } catch (error) {
170
+ if (error instanceof ErrorResponse) {
171
+ throw error;
172
+ }
173
+ ;
174
+ throw new ErrorResponse(
175
+ "Unexpected error occurred during API request.",
176
+ 500
177
+ );
178
+ }
179
+ ;
180
+ }
181
+ /**
182
+ * Maneja errores HTTP y lanza excepciones apropiadas
183
+ */
184
+ async handleErrorResponse(response) {
185
+ const statusCode = response.status;
186
+ let errorMessage = `Error ${statusCode}`;
187
+ let responseData = null;
188
+ try {
189
+ const contentType = response.headers.get("Content-Type");
190
+ if (contentType && contentType.includes("application/json")) {
191
+ responseData = await response.json();
192
+ errorMessage = responseData.message || responseData.error || errorMessage;
193
+ } else {
194
+ errorMessage = await response.text();
195
+ }
196
+ ;
197
+ } catch (error) {
198
+ }
199
+ ;
200
+ switch (statusCode) {
201
+ case 401:
202
+ const authError = new ErrorResponse(
203
+ "Unauthorized access.",
204
+ 401,
205
+ responseData
206
+ );
207
+ this.properties.onAuthError?.(authError);
208
+ throw authError;
209
+ case 403:
210
+ throw new ErrorResponse(
211
+ "No tienes permisos para realizar esta acci\xF3n.",
212
+ 403,
213
+ responseData
214
+ );
215
+ case 404:
216
+ throw new ErrorResponse(
217
+ "Recurso no encontrado.",
218
+ 404,
219
+ responseData
220
+ );
221
+ case 422:
222
+ throw new ErrorResponse(
223
+ errorMessage || "Datos de entrada inv\xE1lidos.",
224
+ 422,
225
+ responseData
226
+ );
227
+ case 500:
228
+ throw new ErrorResponse(
229
+ "Error interno del servidor.",
230
+ 500,
231
+ responseData
232
+ );
233
+ default:
234
+ throw new ErrorResponse(
235
+ errorMessage,
236
+ statusCode,
237
+ responseData
238
+ );
239
+ }
240
+ ;
241
+ }
242
+ //#region REQUEST METHODS
243
+ async executeGET(endpoint, requiresAuth = false) {
244
+ return this.apiExecute({
245
+ endpoint,
246
+ method: "GET",
247
+ requiresAuth,
248
+ requiresSignature: false
249
+ });
250
+ }
251
+ async executePOST(endpoint, body, requiresAuth = true, requiresSignature = true) {
252
+ return this.apiExecute({
253
+ endpoint,
254
+ method: "POST",
255
+ body,
256
+ requiresAuth,
257
+ requiresSignature
258
+ });
259
+ }
260
+ async executePATCH(endpoint, body, requiresAuth = true, requiresSignature = true) {
261
+ return this.apiExecute({
262
+ endpoint,
263
+ method: "PATCH",
264
+ body,
265
+ requiresAuth,
266
+ requiresSignature
267
+ });
268
+ }
269
+ async executeDELETE(endpoint, body, requiresAuth = true, requiresSignature = false) {
270
+ return this.apiExecute({
271
+ endpoint,
272
+ method: "DELETE",
273
+ body,
274
+ requiresAuth,
275
+ requiresSignature
276
+ });
277
+ }
278
+ async executePUT(endpoint, body, requiresAuth = true, requiresSignature = true) {
279
+ return this.apiExecute({
280
+ endpoint,
281
+ method: "PUT",
282
+ body,
283
+ requiresAuth,
284
+ requiresSignature
285
+ });
286
+ }
287
+ async executePublicRequest(endpoint, method, body, timestamp) {
288
+ return this.apiExecute({
289
+ endpoint,
290
+ method,
291
+ body,
292
+ requiresAuth: false,
293
+ requiresSignature: false,
294
+ timeStamp: timestamp
295
+ });
296
+ }
297
+ //#endregion
298
+ };
299
+
300
+ // src/core/CryptoService.ts
301
+ var CryptoJS = __toESM(require("crypto-js"));
302
+ var CryptoService = class {
303
+ /**
304
+ * Encripta el texto plano utilizando AES con una clave derivada del secretWord y el timestamp
305
+ *
306
+ * @param plaintText -- Texto plano a encriptar
307
+ * @param secretWord - Palabra secreta utilizada para derivar la clave
308
+ * @param timestamp - Timestamp actual
309
+ * @returns Texto encriptado en formato Base64
310
+ */
311
+ encrypt(plaintText, secretWord, timestamp) {
312
+ const fullKey = `${secretWord}:${timestamp}`;
313
+ const key = CryptoJS.SHA256(fullKey);
314
+ const iv = CryptoJS.lib.WordArray.random(16);
315
+ const encrypted = CryptoJS.AES.encrypt(plaintText, key, {
316
+ iv,
317
+ mode: CryptoJS.mode.CBC,
318
+ padding: CryptoJS.pad.Pkcs7
319
+ });
320
+ const ivAndCipher = iv.concat(encrypted.ciphertext);
321
+ return CryptoJS.enc.Base64.stringify(ivAndCipher);
322
+ }
323
+ /**
324
+ * Genera la firma Signature para las operaciones de tipo POST
325
+ *
326
+ * @param body - Cuerpo de la solicitud
327
+ * @param timestamp - Timestamp actual
328
+ * @param refreshToken - Refresh token del usuario
329
+ * @returns Firma signature en formato Base64
330
+ */
331
+ genSignature(body, timestamp, refreshToken) {
332
+ const message = `${body}:${timestamp}`;
333
+ const hmac = CryptoJS.HmacSHA256(message, refreshToken);
334
+ return CryptoJS.enc.Base64.stringify(hmac);
335
+ }
336
+ /**
337
+ * Desencripta texto usando AES-256-CBC
338
+ *
339
+ * @param encryptedBase64 - Texto encriptado en base64
340
+ * @param secret - Clave secreta
341
+ * @param timestamp - Timestamp usado en la encriptación
342
+ * @returns Texto desencriptado
343
+ */
344
+ decrypt(encryptedText, secretWord, timestamp) {
345
+ try {
346
+ const fullKey = `${secretWord}:${timestamp}`;
347
+ const key = CryptoJS.SHA256(fullKey);
348
+ const ivAndCipher = CryptoJS.enc.Base64.parse(encryptedText);
349
+ const iv = CryptoJS.lib.WordArray.create(ivAndCipher.words.slice(0, 4));
350
+ const ciphertext = CryptoJS.lib.WordArray.create(
351
+ ivAndCipher.words.slice(4),
352
+ ivAndCipher.sigBytes - 16
353
+ );
354
+ const decrypted = CryptoJS.AES.decrypt(
355
+ { ciphertext },
356
+ key,
357
+ {
358
+ iv,
359
+ mode: CryptoJS.mode.CBC,
360
+ padding: CryptoJS.pad.Pkcs7
361
+ }
362
+ );
363
+ return CryptoJS.enc.Utf8.stringify(decrypted);
364
+ } catch (error) {
365
+ throw new Error("Decryption failed, ex:" + error);
366
+ }
367
+ }
368
+ /**
369
+ * Verifica una firma HMAC-SHA256 (útil para testing o validación)
370
+ *
371
+ * @param body - Cuerpo original
372
+ * @param timestamp - Timestamp original
373
+ * @param refreshToken - Token usado como clave
374
+ * @param signature - Firma a verificar
375
+ * @returns true si la firma es válida
376
+ */
377
+ verifySignature(body, timestamp, refreshToken, signature) {
378
+ try {
379
+ const expectedSignature = this.genSignature(body, timestamp, refreshToken);
380
+ return expectedSignature === signature;
381
+ } catch {
382
+ return false;
383
+ }
384
+ }
385
+ /**
386
+ * Genera un hash SHA256 de un texto (útil para fingerprints)
387
+ *
388
+ * @param text - Texto a hashear
389
+ * @returns Hash en formato hexadecimal
390
+ */
391
+ sha256(text) {
392
+ return CryptoJS.SHA256(text).toString(CryptoJS.enc.Hex);
393
+ }
394
+ /**
395
+ * Genera un identificador único basado en timestamp y random
396
+ * (útil para request IDs)
397
+ *
398
+ * @returns ID único
399
+ */
400
+ generateUniqueId() {
401
+ const timestamp = Date.now().toString(36);
402
+ const randomPart = Math.random().toString(36).substring(2, 15);
403
+ return `${timestamp}-${randomPart}`;
404
+ }
405
+ };
406
+
407
+ // src/core/TokenManager.ts
408
+ var TokenManager = class {
409
+ constructor(onTokensChanged, onSessionExpiring, onSessionExpired) {
410
+ this.tokens = null;
411
+ this.sessionCheckInterval = null;
412
+ this.hasNotifiedExpiring = false;
413
+ this.onTokensChanged = onTokensChanged;
414
+ this.onSessionExpiring = onSessionExpiring;
415
+ this.onSessionExpired = onSessionExpired;
416
+ }
417
+ /**
418
+ * Guarda los tokens de autenticación y dispara el callback onTokensChanged.
419
+ */
420
+ setTokens(tokens) {
421
+ this.tokens = tokens;
422
+ this.hasNotifiedExpiring = false;
423
+ this.onTokensChanged?.(this.tokens);
424
+ if (!tokens.rememberMe) {
425
+ this.startExpirationCheck();
426
+ } else {
427
+ this.stopExpirationCheck();
428
+ }
429
+ ;
430
+ }
431
+ /**
432
+ * Obtiene los tokens de autenticación almacenados.
433
+ */
434
+ getTokens() {
435
+ return this.tokens;
436
+ }
437
+ /**
438
+ * Limpia los tokens de autenticación almacenados y dispara el callback onTokensChanged.
439
+ */
440
+ clearTokens() {
441
+ this.stopExpirationCheck();
442
+ this.tokens = null;
443
+ this.onTokensChanged?.(this.tokens);
444
+ }
445
+ /**
446
+ * Valida si existen tokens y si el access token no ha expirado.
447
+ */
448
+ hasValidTokens() {
449
+ if (!this.tokens) return false;
450
+ const now = Date.now();
451
+ const expiresAt = this.tokens.expiresAt.getTime();
452
+ return now < expiresAt;
453
+ }
454
+ /**
455
+ * Valida si el access token expirará dentro del umbral especificado (en minutos).
456
+ */
457
+ isTokenExpiringSoon(thresholdMinutes) {
458
+ if (!this.tokens) return false;
459
+ const now = Date.now();
460
+ const expiresAt = this.tokens.expiresAt.getTime();
461
+ const thresholdMs = thresholdMinutes * 60 * 1e3;
462
+ const timeLeft = expiresAt - now;
463
+ return timeLeft > 0 && timeLeft <= thresholdMs;
464
+ }
465
+ /**
466
+ * Obtiene el tiempo restante hasta la expiración del access token en milisegundos.
467
+ */
468
+ getTimeUntilExpiry() {
469
+ if (!this.tokens) return null;
470
+ const now = Date.now();
471
+ const expiresAt = this.tokens.expiresAt.getTime();
472
+ const timeLeft = Math.max(0, expiresAt - now);
473
+ return timeLeft;
474
+ }
475
+ /**
476
+ * Obtiene el access token almacenado.
477
+ */
478
+ getAccessToken() {
479
+ return this.tokens ? this.tokens.accessToken : null;
480
+ }
481
+ /**
482
+ * Obtiene el refresh token almacenado.
483
+ */
484
+ getRefreshToken() {
485
+ return this.tokens ? this.tokens.refreshToken : null;
486
+ }
487
+ /**
488
+ * Verifica si el auto-refresh debe ejecutarse
489
+ * Solo si el usuario activó "rememberMe" durante el login
490
+ */
491
+ shouldAutoRefresh() {
492
+ if (!this.tokens) return false;
493
+ return this.tokens.rememberMe === true;
494
+ }
495
+ /**
496
+ * Inicia el monitoreo de expiración para sesiones sin rememberMe
497
+ * - Notifica cuando quedan 5 minutos (onSessionExpiring)
498
+ * - Ejecuta logout cuando queda 1 minuto (onSessionExpired)
499
+ */
500
+ startExpirationCheck() {
501
+ this.stopExpirationCheck();
502
+ this.sessionCheckInterval = setInterval(async () => {
503
+ if (!this.tokens) {
504
+ this.stopExpirationCheck();
505
+ return;
506
+ }
507
+ ;
508
+ const timeLeft = this.getTimeUntilExpiry();
509
+ if (timeLeft === null) return;
510
+ const minutesLeft = Math.floor(timeLeft / (60 * 1e3));
511
+ if (minutesLeft <= 5 && minutesLeft > 1 && !this.hasNotifiedExpiring) {
512
+ this.hasNotifiedExpiring = true;
513
+ this.onSessionExpiring?.(minutesLeft);
514
+ }
515
+ ;
516
+ if (minutesLeft <= 1) {
517
+ this.stopExpirationCheck();
518
+ if (this.onSessionExpired) {
519
+ await this.onSessionExpired();
520
+ }
521
+ ;
522
+ }
523
+ ;
524
+ }, 6e4);
525
+ }
526
+ /**
527
+ * Detiene el monitoreo de expiración
528
+ */
529
+ stopExpirationCheck() {
530
+ if (this.sessionCheckInterval) {
531
+ clearInterval(this.sessionCheckInterval);
532
+ this.sessionCheckInterval = null;
533
+ }
534
+ ;
535
+ }
536
+ };
537
+
538
+ // src/core/interceptors/AuthInterceptor.ts
539
+ var AuthInterceptor = class {
540
+ constructor(config) {
541
+ this.name = "AuthInterceptor";
542
+ this.refreshPromise = null;
543
+ this.isRefreshing = false;
544
+ this.config = {
545
+ enabled: config.enabled ?? true,
546
+ thresholdMinutes: config.thresholdMinutes ?? 5,
547
+ isTokenExpiringSoon: config.isTokenExpiringSoon,
548
+ hasValidTokens: config.hasValidTokens,
549
+ shouldAutoRefresh: config.shouldAutoRefresh,
550
+ refreshSession: config.refreshSession
551
+ };
552
+ }
553
+ async onRequest(config, context) {
554
+ if (!config.requiresAuth || !this.config.enabled) {
555
+ return config;
556
+ }
557
+ ;
558
+ if (!this.config.hasValidTokens()) {
559
+ return config;
560
+ }
561
+ ;
562
+ if (!this.config.shouldAutoRefresh()) {
563
+ return config;
564
+ }
565
+ ;
566
+ if (this.config.isTokenExpiringSoon()) {
567
+ try {
568
+ if (this.isRefreshing && this.refreshPromise) {
569
+ await this.refreshPromise;
570
+ } else {
571
+ this.isRefreshing = true;
572
+ this.refreshPromise = this.config.refreshSession();
573
+ await this.refreshPromise;
574
+ this.isRefreshing = false;
575
+ this.refreshPromise = null;
576
+ }
577
+ ;
578
+ } catch (error) {
579
+ this.isRefreshing = false;
580
+ this.refreshPromise = null;
581
+ }
582
+ ;
583
+ }
584
+ ;
585
+ return config;
586
+ }
587
+ updateConfig(config) {
588
+ this.config = {
589
+ ...this.config,
590
+ ...config
591
+ };
592
+ }
593
+ reset() {
594
+ this.isRefreshing = false;
595
+ this.refreshPromise = null;
596
+ }
597
+ };
598
+
599
+ // src/services/AuthService.ts
600
+ var AuthService = class {
601
+ constructor(serviceProperties, tokenManager, cryptoService, api) {
602
+ this.api = api;
603
+ this.crytpoService = cryptoService;
604
+ this.tokenManager = tokenManager;
605
+ this.serviceProperties = serviceProperties;
606
+ }
607
+ /**
608
+ * Login con las credenciales proporcionadas
609
+ * @param credentials - Objeto con email, password y rememberMe
610
+ * @returns Retorna el cuerpo de respuesta del login.
611
+ */
612
+ async login(credentials) {
613
+ const timestamp = Date.now().toString();
614
+ const encryptedEmail = this.crytpoService.encrypt(
615
+ credentials.email,
616
+ `${this.serviceProperties.originRequest}_${this.serviceProperties.domain}`,
617
+ timestamp
618
+ );
619
+ const encryptedPassword = this.crytpoService.encrypt(
620
+ credentials.password,
621
+ `${this.serviceProperties.originRequest}_${this.serviceProperties.domain}`,
622
+ timestamp
623
+ );
624
+ const loginData = {
625
+ email: encryptedEmail,
626
+ password: encryptedPassword,
627
+ rememberMe: credentials.rememberMe
628
+ };
629
+ const response = await this.api.executePublicRequest(
630
+ "oauth/login",
631
+ "POST",
632
+ loginData,
633
+ timestamp
634
+ );
635
+ if (!response) {
636
+ throw new ErrorResponse("No response from server");
637
+ }
638
+ ;
639
+ if (response.success) {
640
+ const data = response.data;
641
+ const expiresIn = parseInt(data.expiresIn.replace("s", ""));
642
+ const expiresAt = new Date(Date.now() + expiresIn * 1e3);
643
+ const tokens = {
644
+ accessToken: data.accessToken,
645
+ refreshToken: data.refreshToken,
646
+ expiresAt,
647
+ rememberMe: credentials.rememberMe
648
+ };
649
+ await this.tokenManager.setTokens(tokens);
650
+ this.serviceProperties.onTokensUpdated?.(tokens);
651
+ const responseData = {
652
+ success: data.accessToken ? true : false,
653
+ data,
654
+ message: response.message,
655
+ responseTime: "3s"
656
+ };
657
+ return responseData;
658
+ }
659
+ return response;
660
+ }
661
+ /**
662
+ * Valida la sesión actual y retorna información de expiración
663
+ *
664
+ * El servidor puede responder de 2 formas:
665
+ * 1. Sesión renovada (sliding window): retorna nuevos tokens
666
+ * 2. Sesión válida: retorna info de expiración sin renovar
667
+ */
668
+ async validateSession() {
669
+ const response = await this.api.executePOST(
670
+ "oauth/validateSession"
671
+ );
672
+ if (!response) {
673
+ throw new ErrorResponse("No response from server");
674
+ }
675
+ ;
676
+ if (response.success && response.data) {
677
+ const respData = response.data;
678
+ if ("expiresIn" in respData && respData.expiresIn) {
679
+ const sessionData = respData;
680
+ const expiresIn = parseInt(sessionData.expiresIn.replace("s", ""));
681
+ const expiresAt = new Date(Date.now() + expiresIn * 1e3);
682
+ const currentTokens = this.tokenManager.getTokens();
683
+ const rememberMe = currentTokens?.rememberMe ?? sessionData.isRemembered;
684
+ const tokens = {
685
+ accessToken: sessionData.accessToken,
686
+ refreshToken: sessionData.refreshToken,
687
+ expiresAt,
688
+ rememberMe
689
+ };
690
+ this.tokenManager.setTokens(tokens);
691
+ this.serviceProperties.onTokensUpdated?.(tokens);
692
+ } else if ("expiresAt" in respData && respData.expiresAt) {
693
+ const sessionData = respData;
694
+ if (sessionData.remainingMinutes <= 5 && sessionData.remainingMinutes > 1) {
695
+ this.serviceProperties.onSessionExpiring?.(sessionData.remainingMinutes);
696
+ } else if (sessionData.remainingMinutes <= 1) {
697
+ if (this.serviceProperties.onSessionExpired) {
698
+ await this.serviceProperties.onSessionExpired();
699
+ }
700
+ }
701
+ }
702
+ }
703
+ ;
704
+ return response;
705
+ }
706
+ /**
707
+ * Refresca los tokens usando el refresh token
708
+ */
709
+ async refreshTokens(rememberMe) {
710
+ const refreshToken = this.tokenManager.getRefreshToken();
711
+ if (!refreshToken) {
712
+ throw new ErrorResponse("No refresh token available");
713
+ }
714
+ ;
715
+ const response = await this.api.executePublicRequest(
716
+ "oauth/refresh",
717
+ "POST",
718
+ { refreshToken }
719
+ );
720
+ if (!response) {
721
+ throw new ErrorResponse("No response from server");
722
+ }
723
+ ;
724
+ if (response.success) {
725
+ const sessionData = response.data;
726
+ const currentTokens = this.tokenManager.getTokens();
727
+ const shouldRemember = rememberMe ?? currentTokens?.rememberMe ?? false;
728
+ const expiresIn = parseInt(sessionData.expiresIn.replace("s", ""));
729
+ const expiresAt = new Date(Date.now() + expiresIn * 1e3);
730
+ const tokens = {
731
+ accessToken: sessionData.accessToken,
732
+ refreshToken: sessionData.refreshToken,
733
+ expiresAt,
734
+ rememberMe: shouldRemember
735
+ };
736
+ this.tokenManager.setTokens(tokens);
737
+ this.serviceProperties.onTokensUpdated?.(tokens);
738
+ }
739
+ ;
740
+ return response;
741
+ }
742
+ /**
743
+ * Cierra sesión: notifica al servidor y limpia tokens
744
+ */
745
+ async logout() {
746
+ try {
747
+ await this.api.executePOST("oauth/logout");
748
+ } catch (error) {
749
+ }
750
+ ;
751
+ this.tokenManager.clearTokens();
752
+ this.serviceProperties.onTokensUpdated?.(null);
753
+ }
754
+ /**
755
+ * Verifica si el usuario está autenticado
756
+ */
757
+ isAuthenticated() {
758
+ return this.tokenManager.hasValidTokens();
759
+ }
760
+ /**
761
+ * Obtiene los tokens actuales
762
+ */
763
+ getTokens() {
764
+ return this.tokenManager.getTokens();
765
+ }
766
+ };
767
+
768
+ // src/FalconHUBSDK.ts
769
+ var FalconHUBSDK = class {
770
+ constructor(serviceProperties) {
771
+ this.serviceProperties = serviceProperties;
772
+ this.cryptoService = new CryptoService();
773
+ this.tokenManager = new TokenManager(
774
+ this.serviceProperties.onTokensUpdated,
775
+ this.serviceProperties.onSessionExpiring,
776
+ async () => {
777
+ await this.auth.logout();
778
+ }
779
+ );
780
+ const autoRefreshConfig = this.normalizeAutoRefreshConfig(this.serviceProperties.autoRefresh);
781
+ if (autoRefreshConfig.enabled) {
782
+ this.authInterceptor = new AuthInterceptor({
783
+ enabled: true,
784
+ thresholdMinutes: autoRefreshConfig.thresholdMinutes,
785
+ isTokenExpiringSoon: () => this.tokenManager.isTokenExpiringSoon(autoRefreshConfig.thresholdMinutes),
786
+ hasValidTokens: () => this.tokenManager.hasValidTokens(),
787
+ shouldAutoRefresh: () => this.tokenManager.shouldAutoRefresh(),
788
+ refreshSession: async () => {
789
+ await this.auth.validateSession();
790
+ }
791
+ });
792
+ } else {
793
+ this.authInterceptor = null;
794
+ }
795
+ this.api = new API(
796
+ this.serviceProperties,
797
+ this.cryptoService,
798
+ this.authInterceptor,
799
+ () => this.tokenManager.getAccessToken(),
800
+ () => this.tokenManager.getRefreshToken()
801
+ );
802
+ this.auth = new AuthService(
803
+ this.serviceProperties,
804
+ this.tokenManager,
805
+ this.cryptoService,
806
+ this.api
807
+ );
808
+ }
809
+ normalizeAutoRefreshConfig(config) {
810
+ if (typeof config === "boolean") {
811
+ return { enabled: config, thresholdMinutes: 5 };
812
+ }
813
+ if (typeof config === "object" && config !== null) {
814
+ return {
815
+ enabled: config.enabled,
816
+ thresholdMinutes: config.thresholdMinutes ?? 5
817
+ };
818
+ }
819
+ return { enabled: true, thresholdMinutes: 5 };
820
+ }
821
+ /**
822
+ * Inyecta tokens desde storage externo (cookies/localStorage/etc)
823
+ */
824
+ setTokensFromExternal(accessToken, refreshToken, expiresAt, rememberMe = false) {
825
+ const tokens = {
826
+ accessToken,
827
+ refreshToken,
828
+ expiresAt,
829
+ rememberMe
830
+ };
831
+ this.tokenManager.setTokens(tokens);
832
+ }
833
+ /**
834
+ * Obtiene los tokens actuales
835
+ */
836
+ getTokens() {
837
+ return this.tokenManager.getTokens();
838
+ }
839
+ /**
840
+ * Verifica si el usuario está autenticado
841
+ */
842
+ isAuthenticated() {
843
+ return this.tokenManager.hasValidTokens();
844
+ }
845
+ /**
846
+ * Verifica si la sesión está por expirar
847
+ */
848
+ isSessionExpiringSoon(thresholdMinutes = 5) {
849
+ return this.tokenManager.isTokenExpiringSoon(thresholdMinutes);
850
+ }
851
+ /**
852
+ * Obtiene el tiempo restante hasta la expiración en milisegundos
853
+ */
854
+ getTimeUntilExpiry() {
855
+ return this.tokenManager.getTimeUntilExpiry();
856
+ }
857
+ };
858
+ // Annotate the CommonJS export names for ESM import in node:
859
+ 0 && (module.exports = {
860
+ API,
861
+ AuthInterceptor,
862
+ AuthService,
863
+ CryptoService,
864
+ FalconHUBSDK,
865
+ TokenManager
866
+ });
867
+ //# sourceMappingURL=index.js.map