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/LICENSE +15 -0
- package/README.md +22 -0
- package/dist/index.d.mts +357 -0
- package/dist/index.d.ts +357 -0
- package/dist/index.js +867 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +825 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types/ErrorResponse.ts","../src/core/API.ts","../src/core/CryptoService.ts","../src/core/TokenManager.ts","../src/core/interceptors/AuthInterceptor.ts","../src/services/AuthService.ts","../src/FalconHUBSDK.ts"],"sourcesContent":["/**\n * FalconHUB API Library\n *\n * SDK cliente para consumir el API de FalconHUB\n *\n * @packageDocumentation\n */\n\nexport { FalconHUBSDK } from './FalconHUBSDK';\n\nexport { AuthService } from './services/AuthService';\n\nexport type { ServiceProperties } from './types/ServiceProperties';\nexport type { TokenData } from './types/TokenData';\nexport type { ErrorResponse } from './types/ErrorResponse';\nexport type { ResponseModel } from './types/ResponseModel';\nexport type { RequestOptions, MethodTypes } from './types/RequestOptions';\nexport type { RequestConfig } from './types/RequestConfig';\n\nexport { API } from './core/API';\nexport { TokenManager } from './core/TokenManager';\nexport { CryptoService } from './core/CryptoService';\n\nexport { AuthInterceptor } from './core/interceptors/AuthInterceptor';\nexport type { AuthInterceptorConfig } from './core/interceptors/types/AuthInterceptorConfig';\nexport type { InterceptorContext } from './core/interceptors/types/InterceptorContext';\nexport type { RequestInterceptor } from './core/interceptors/types/RequestInterceptor';\n\nexport type { LoginRequest } from './interfaces/Auth/Login/LoginRequest';\nexport type { LoginResponse } from './interfaces/Auth/Login/LoginResponse';\nexport type { RefreshTokenRequest } from './interfaces/Auth/RefreshTokens/RefreshTokenRequest';\nexport type { RefreshTokenResponse } from './interfaces/Auth/RefreshTokens/RefreshTokenResponse';\nexport type { ValidateSessionResponse, ValidateSessionRenewedResponse } from './interfaces/Auth/ValidateSession/ValidateSessionResponse';\n","export class ErrorResponse extends Error {\r\n constructor(\r\n message: string,\r\n public statusCode?: number,\r\n public responseData?: any\r\n ){\r\n super(message);\r\n this.name = \"FalconHUB API Error\";\r\n };\r\n};\r\n","import { ServiceProperties } from \"@/types/ServiceProperties\";\r\nimport { CryptoService } from \"./CryptoService\";\r\nimport { MethodTypes, RequestOptions } from \"@/types/RequestOptions\";\r\nimport { ErrorResponse } from \"@/types/ErrorResponse\";\r\nimport { RequestConfig } from \"@/types/RequestConfig\";\r\nimport { AuthInterceptor } from \"./interceptors/AuthInterceptor\";\r\nimport { InterceptorContext } from \"@/core/interceptors/types/InterceptorContext\";\r\n\r\n\r\n/**\r\n * Clase base para la ejecución de request HTTP al API\r\n */\r\nexport class API {\r\n private properties: ServiceProperties;\r\n private cryptoService: CryptoService;\r\n private authInterceptor: AuthInterceptor | null;\r\n\r\n private getAccessToken: () => string | null;\r\n private getRefreshToken: () => string | null;\r\n\r\n constructor(\r\n properties: ServiceProperties,\r\n cryptoService: CryptoService,\r\n authInterceptor: AuthInterceptor | null,\r\n getAccessToken: () => string | null,\r\n getRefreshToken: () => string | null\r\n ) {\r\n this.properties = properties;\r\n this.cryptoService = cryptoService;\r\n this.getAccessToken = getAccessToken;\r\n this.getRefreshToken = getRefreshToken;\r\n this.authInterceptor = authInterceptor;\r\n };\r\n\r\n /**\r\n * Ejecuta una request HTTP al API\r\n *\r\n * @param options - Opciones de la request\r\n * @returns Respuesta parseada del tipo esperado\r\n */\r\n private async apiExecute<T>(options: RequestOptions): Promise<T | undefined> {\r\n const {\r\n endpoint,\r\n method,\r\n body,\r\n requiresSignature,\r\n requiresAuth,\r\n timeStamp\r\n } = options;\r\n\r\n const context: InterceptorContext = {\r\n requestId: this.cryptoService.generateUniqueId(),\r\n startTime: Date.now(),\r\n retryCount: 0,\r\n metadata: {}\r\n };\r\n\r\n try {\r\n const url = `${this.properties.url}/${endpoint}`;\r\n\r\n const headers: Record<string, string> = {};\r\n\r\n if (body && method !== 'GET') {\r\n headers['Content-Type'] = 'application/json';\r\n };\r\n\r\n const accessToken = this.getAccessToken();\r\n\r\n if (accessToken) {\r\n headers['Authorization'] = `Bearer ${accessToken}`;\r\n };\r\n\r\n const newTimeStamp = timeStamp || new Date().toString();\r\n\r\n headers['X-Timestamp'] = newTimeStamp;\r\n\r\n let bodyString: string | undefined;\r\n\r\n if (body && method !== 'GET') {\r\n bodyString = JSON.stringify(body);\r\n };\r\n\r\n if (requiresSignature && bodyString) {\r\n try {\r\n const refreshToken = this.getRefreshToken();\r\n\r\n if (refreshToken) {\r\n const signature = this.cryptoService.genSignature(\r\n bodyString,\r\n newTimeStamp,\r\n refreshToken\r\n );\r\n\r\n if (signature) {\r\n headers['X-Signature'] = signature;\r\n };\r\n };\r\n } catch (error) {\r\n throw new ErrorResponse(\r\n \"Failed to generate request signature.\",\r\n 401\r\n );\r\n };\r\n };\r\n\r\n const requestConfig: RequestConfig = {\r\n url,\r\n method,\r\n headers,\r\n body: bodyString,\r\n requiresAuth,\r\n requiresSignature\r\n };\r\n\r\n const modifiedConfig = this.authInterceptor\r\n ? await this.authInterceptor.onRequest(requestConfig, context)\r\n : requestConfig;\r\n\r\n const requestInit: RequestInit = {\r\n method: modifiedConfig.method,\r\n headers: modifiedConfig.headers,\r\n mode: 'cors',\r\n credentials: 'omit'\r\n };\r\n\r\n if (bodyString) {\r\n requestInit.body = bodyString;\r\n };\r\n\r\n const response = await fetch(\r\n modifiedConfig.url,\r\n requestInit\r\n );\r\n\r\n if (response.ok) {\r\n // Detectar sliding window: nuevos tokens en headers\r\n const newAccessToken = response.headers.get('X-New-Access-Token');\r\n const newRefreshToken = response.headers.get('X-New-Refresh-Token');\r\n\r\n if (newAccessToken || newRefreshToken) {\r\n this.properties.onTokensRefreshed?.({\r\n accessToken: newAccessToken,\r\n refreshToken: newRefreshToken\r\n });\r\n };\r\n\r\n const contentType = response.headers.get('Content-Type');\r\n\r\n if (contentType && contentType.includes('application/json')) {\r\n const responseText = await response.text();\r\n\r\n return JSON.parse(responseText) as T;\r\n };\r\n\r\n return undefined;\r\n } else {\r\n await this.handleErrorResponse(response);\r\n };\r\n } catch (error) {\r\n if (error instanceof ErrorResponse) {\r\n throw error;\r\n };\r\n\r\n throw new ErrorResponse(\r\n 'Unexpected error occurred during API request.',\r\n 500\r\n );\r\n };\r\n };\r\n\r\n /**\r\n * Maneja errores HTTP y lanza excepciones apropiadas\r\n */\r\n private async handleErrorResponse(\r\n response: Response\r\n ): Promise<never> {\r\n\r\n const statusCode = response.status;\r\n let errorMessage = `Error ${statusCode}`;\r\n let responseData: any = null;\r\n\r\n try {\r\n const contentType = response.headers.get('Content-Type');\r\n if (contentType && contentType.includes('application/json')) {\r\n responseData = await response.json();\r\n errorMessage = responseData.message || responseData.error || errorMessage;\r\n } else {\r\n errorMessage = await response.text();\r\n };\r\n } catch (error) {\r\n\r\n };\r\n\r\n switch (statusCode) {\r\n case 401:\r\n const authError = new ErrorResponse(\r\n 'Unauthorized access.',\r\n 401,\r\n responseData\r\n );\r\n\r\n this.properties.onAuthError?.(authError);\r\n throw authError;\r\n case 403:\r\n throw new ErrorResponse(\r\n 'No tienes permisos para realizar esta acción.',\r\n 403,\r\n responseData\r\n );\r\n\r\n case 404:\r\n throw new ErrorResponse(\r\n 'Recurso no encontrado.',\r\n 404,\r\n responseData\r\n );\r\n\r\n case 422:\r\n throw new ErrorResponse(\r\n errorMessage || 'Datos de entrada inválidos.',\r\n 422,\r\n responseData\r\n );\r\n\r\n case 500:\r\n throw new ErrorResponse(\r\n 'Error interno del servidor.',\r\n 500,\r\n responseData\r\n );\r\n\r\n default:\r\n throw new ErrorResponse(\r\n errorMessage,\r\n statusCode,\r\n responseData\r\n );\r\n };\r\n };\r\n\r\n //#region REQUEST METHODS\r\n\r\n async executeGET<T>(\r\n endpoint: string,\r\n requiresAuth: boolean = false\r\n ): Promise<T | undefined> {\r\n return this.apiExecute<T>({\r\n endpoint,\r\n method: 'GET',\r\n requiresAuth: requiresAuth,\r\n requiresSignature: false\r\n });\r\n };\r\n\r\n async executePOST<T>(\r\n endpoint: string,\r\n body?: any,\r\n requiresAuth: boolean = true,\r\n requiresSignature: boolean = true\r\n ): Promise<T | undefined> {\r\n return this.apiExecute<T>({\r\n endpoint,\r\n method: 'POST',\r\n body,\r\n requiresAuth: requiresAuth,\r\n requiresSignature: requiresSignature\r\n });\r\n };\r\n\r\n async executePATCH<T>(\r\n endpoint: string,\r\n body?: any,\r\n requiresAuth: boolean = true,\r\n requiresSignature: boolean = true\r\n ): Promise<T | undefined> {\r\n return this.apiExecute<T>({\r\n endpoint,\r\n method: 'PATCH',\r\n body,\r\n requiresAuth: requiresAuth,\r\n requiresSignature: requiresSignature\r\n });\r\n };\r\n\r\n async executeDELETE<T>(\r\n endpoint: string,\r\n body?: any,\r\n requiresAuth: boolean = true,\r\n requiresSignature: boolean = false\r\n ): Promise<T | undefined> {\r\n return this.apiExecute<T>({\r\n endpoint,\r\n method: 'DELETE',\r\n body,\r\n requiresAuth: requiresAuth,\r\n requiresSignature: requiresSignature\r\n });\r\n };\r\n\r\n async executePUT<T>(\r\n endpoint: string,\r\n body?: any,\r\n requiresAuth: boolean = true,\r\n requiresSignature: boolean = true\r\n ): Promise<T | undefined> {\r\n return this.apiExecute<T>({\r\n endpoint,\r\n method: 'PUT',\r\n body,\r\n requiresAuth: requiresAuth,\r\n requiresSignature: requiresSignature\r\n });\r\n };\r\n\r\n async executePublicRequest<T>(\r\n endpoint: string,\r\n method: MethodTypes,\r\n body?: any,\r\n timestamp?: string\r\n ): Promise<T | undefined> {\r\n return this.apiExecute<T>({\r\n endpoint,\r\n method,\r\n body,\r\n requiresAuth: false,\r\n requiresSignature: false,\r\n timeStamp: timestamp\r\n });\r\n };\r\n\r\n //#endregion\r\n}\r\n","import * as CryptoJS from 'crypto-js';\r\n\r\nexport class CryptoService {\r\n\r\n /**\r\n * Encripta el texto plano utilizando AES con una clave derivada del secretWord y el timestamp\r\n *\r\n * @param plaintText -- Texto plano a encriptar\r\n * @param secretWord - Palabra secreta utilizada para derivar la clave\r\n * @param timestamp - Timestamp actual\r\n * @returns Texto encriptado en formato Base64\r\n */\r\n encrypt(plaintText: string, secretWord: string, timestamp: string): string {\r\n const fullKey = `${secretWord}:${timestamp}`;\r\n const key = CryptoJS.SHA256(fullKey);\r\n\r\n const iv = CryptoJS.lib.WordArray.random(16);\r\n const encrypted = CryptoJS.AES.encrypt(plaintText, key, {\r\n iv: iv,\r\n mode: CryptoJS.mode.CBC,\r\n padding: CryptoJS.pad.Pkcs7\r\n });\r\n\r\n const ivAndCipher = iv.concat(encrypted.ciphertext);\r\n return CryptoJS.enc.Base64.stringify(ivAndCipher);\r\n };\r\n\r\n /**\r\n * Genera la firma Signature para las operaciones de tipo POST\r\n *\r\n * @param body - Cuerpo de la solicitud\r\n * @param timestamp - Timestamp actual\r\n * @param refreshToken - Refresh token del usuario\r\n * @returns Firma signature en formato Base64\r\n */\r\n genSignature(body: string, timestamp: string, refreshToken: string): string {\r\n const message = `${body}:${timestamp}`;\r\n const hmac = CryptoJS.HmacSHA256(message, refreshToken);\r\n\r\n return CryptoJS.enc.Base64.stringify(hmac);\r\n };\r\n\r\n /**\r\n * Desencripta texto usando AES-256-CBC\r\n *\r\n * @param encryptedBase64 - Texto encriptado en base64\r\n * @param secret - Clave secreta\r\n * @param timestamp - Timestamp usado en la encriptación\r\n * @returns Texto desencriptado\r\n */\r\n decrypt(encryptedText: string, secretWord: string, timestamp: string): string {\r\n try {\r\n const fullKey = `${secretWord}:${timestamp}`;\r\n const key = CryptoJS.SHA256(fullKey);\r\n\r\n const ivAndCipher = CryptoJS.enc.Base64.parse(encryptedText);\r\n const iv = CryptoJS.lib.WordArray.create(ivAndCipher.words.slice(0, 4));\r\n\r\n const ciphertext = CryptoJS.lib.WordArray.create(\r\n ivAndCipher.words.slice(4),\r\n ivAndCipher.sigBytes - 16\r\n );\r\n\r\n const decrypted = CryptoJS.AES.decrypt(\r\n { ciphertext } as any,\r\n key,\r\n {\r\n iv: iv,\r\n mode: CryptoJS.mode.CBC,\r\n padding: CryptoJS.pad.Pkcs7\r\n }\r\n );\r\n\r\n return CryptoJS.enc.Utf8.stringify(decrypted);\r\n } catch (error) {\r\n throw new Error('Decryption failed, ex:' + error);\r\n }\r\n };\r\n\r\n /**\r\n * Verifica una firma HMAC-SHA256 (útil para testing o validación)\r\n *\r\n * @param body - Cuerpo original\r\n * @param timestamp - Timestamp original\r\n * @param refreshToken - Token usado como clave\r\n * @param signature - Firma a verificar\r\n * @returns true si la firma es válida\r\n */\r\n verifySignature(body: string, timestamp: string, refreshToken: string, signature: string): boolean {\r\n try {\r\n const expectedSignature = this.genSignature(body, timestamp, refreshToken);\r\n return expectedSignature === signature;\r\n } catch {\r\n return false;\r\n }\r\n };\r\n\r\n /**\r\n * Genera un hash SHA256 de un texto (útil para fingerprints)\r\n *\r\n * @param text - Texto a hashear\r\n * @returns Hash en formato hexadecimal\r\n */\r\n sha256(text: string): string {\r\n return CryptoJS.SHA256(text).toString(CryptoJS.enc.Hex);\r\n }\r\n\r\n /**\r\n * Genera un identificador único basado en timestamp y random\r\n * (útil para request IDs)\r\n *\r\n * @returns ID único\r\n */\r\n generateUniqueId(): string {\r\n const timestamp = Date.now().toString(36);\r\n const randomPart = Math.random().toString(36).substring(2, 15);\r\n return `${timestamp}-${randomPart}`;\r\n };\r\n\r\n}\r\n","import { TokenData } from \"@/types/TokenData\";\r\n\r\n/**\r\n * Manages authentication tokens.\r\n */\r\nexport class TokenManager {\r\n private tokens: TokenData | null = null;\r\n private onTokensChanged?: (tokens: TokenData | null) => void;\r\n private sessionCheckInterval: NodeJS.Timeout | null = null;\r\n private onSessionExpiring?: (remainingMinutes: number) => void;\r\n private onSessionExpired?: () => Promise<void>;\r\n private hasNotifiedExpiring: boolean = false;\r\n\r\n constructor(\r\n onTokensChanged?: (tokens: TokenData | null) => void,\r\n onSessionExpiring?: (remainingMinutes: number) => void,\r\n onSessionExpired?: () => Promise<void>\r\n ) {\r\n this.onTokensChanged = onTokensChanged;\r\n this.onSessionExpiring = onSessionExpiring;\r\n this.onSessionExpired = onSessionExpired;\r\n };\r\n\r\n /**\r\n * Guarda los tokens de autenticación y dispara el callback onTokensChanged.\r\n */\r\n setTokens(tokens: TokenData) {\r\n this.tokens = tokens;\r\n this.hasNotifiedExpiring = false; // Resetear flag\r\n\r\n this.onTokensChanged?.(this.tokens);\r\n\r\n // Si NO tiene rememberMe, iniciar monitoreo de expiración\r\n if (!tokens.rememberMe) {\r\n this.startExpirationCheck();\r\n } else {\r\n this.stopExpirationCheck();\r\n };\r\n };\r\n\r\n /**\r\n * Obtiene los tokens de autenticación almacenados.\r\n */\r\n getTokens(): TokenData | null {\r\n return this.tokens;\r\n };\r\n\r\n /**\r\n * Limpia los tokens de autenticación almacenados y dispara el callback onTokensChanged.\r\n */\r\n clearTokens() {\r\n this.stopExpirationCheck();\r\n this.tokens = null;\r\n this.onTokensChanged?.(this.tokens);\r\n };\r\n\r\n /**\r\n * Valida si existen tokens y si el access token no ha expirado.\r\n */\r\n hasValidTokens(): boolean {\r\n if (!this.tokens) return false;\r\n\r\n const now = Date.now();\r\n const expiresAt = this.tokens.expiresAt.getTime();\r\n\r\n return now < expiresAt;\r\n };\r\n\r\n /**\r\n * Valida si el access token expirará dentro del umbral especificado (en minutos).\r\n */\r\n isTokenExpiringSoon(thresholdMinutes: number): boolean {\r\n if (!this.tokens) return false;\r\n\r\n const now = Date.now();\r\n const expiresAt = this.tokens.expiresAt.getTime();\r\n const thresholdMs = thresholdMinutes * 60 * 1000;\r\n\r\n const timeLeft = expiresAt - now;\r\n return timeLeft > 0 && timeLeft <= thresholdMs;\r\n };\r\n\r\n /**\r\n * Obtiene el tiempo restante hasta la expiración del access token en milisegundos.\r\n */\r\n getTimeUntilExpiry(): number | null {\r\n if (!this.tokens) return null;\r\n\r\n const now = Date.now();\r\n const expiresAt = this.tokens.expiresAt.getTime();\r\n const timeLeft = Math.max(0, expiresAt - now);\r\n\r\n return timeLeft;\r\n };\r\n\r\n /**\r\n * Obtiene el access token almacenado.\r\n */\r\n getAccessToken(): string | null {\r\n return this.tokens ? this.tokens.accessToken : null;\r\n };\r\n\r\n /**\r\n * Obtiene el refresh token almacenado.\r\n */\r\n getRefreshToken(): string | null {\r\n return this.tokens ? this.tokens.refreshToken : null;\r\n };\r\n\r\n /**\r\n * Verifica si el auto-refresh debe ejecutarse\r\n * Solo si el usuario activó \"rememberMe\" durante el login\r\n */\r\n shouldAutoRefresh(): boolean {\r\n if (!this.tokens) return false;\r\n\r\n return this.tokens.rememberMe === true;\r\n }\r\n\r\n /**\r\n * Inicia el monitoreo de expiración para sesiones sin rememberMe\r\n * - Notifica cuando quedan 5 minutos (onSessionExpiring)\r\n * - Ejecuta logout cuando queda 1 minuto (onSessionExpired)\r\n */\r\n private startExpirationCheck(): void {\r\n this.stopExpirationCheck();\r\n\r\n this.sessionCheckInterval = setInterval(async () => {\r\n if (!this.tokens) {\r\n this.stopExpirationCheck();\r\n return;\r\n };\r\n\r\n const timeLeft = this.getTimeUntilExpiry();\r\n if (timeLeft === null) return;\r\n\r\n const minutesLeft = Math.floor(timeLeft / (60 * 1000));\r\n\r\n // Notificar cuando quedan 5 minutos (solo una vez)\r\n if (minutesLeft <= 5 && minutesLeft > 1 && !this.hasNotifiedExpiring) {\r\n this.hasNotifiedExpiring = true;\r\n this.onSessionExpiring?.(minutesLeft);\r\n };\r\n\r\n // Cuando queda 1 minuto o menos: ejecutar logout automático\r\n if (minutesLeft <= 1) {\r\n this.stopExpirationCheck();\r\n\r\n // Ejecutar callback para logout en servidor\r\n if (this.onSessionExpired) {\r\n await this.onSessionExpired();\r\n };\r\n };\r\n }, 60000); // Cada 1 minuto\r\n }\r\n\r\n /**\r\n * Detiene el monitoreo de expiración\r\n */\r\n private stopExpirationCheck(): void {\r\n if (this.sessionCheckInterval) {\r\n clearInterval(this.sessionCheckInterval);\r\n this.sessionCheckInterval = null;\r\n };\r\n }\r\n};\r\n","import { AuthInterceptorConfig } from \"./types/AuthInterceptorConfig\";\r\nimport { InterceptorContext } from \"@/core/interceptors/types/InterceptorContext\";\r\nimport { RequestConfig } from \"@/types/RequestConfig\";\r\nimport { RequestInterceptor } from \"./types/RequestInterceptor\";\r\n\r\nexport class AuthInterceptor implements RequestInterceptor {\r\n readonly name = \"AuthInterceptor\";\r\n\r\n private config: Required<AuthInterceptorConfig>;\r\n private refreshPromise: Promise<void> | null = null;\r\n private isRefreshing = false;\r\n\r\n constructor(config: AuthInterceptorConfig) {\r\n this.config = {\r\n enabled: config.enabled ?? true,\r\n thresholdMinutes: config.thresholdMinutes ?? 5,\r\n isTokenExpiringSoon: config.isTokenExpiringSoon,\r\n hasValidTokens: config.hasValidTokens,\r\n shouldAutoRefresh: config.shouldAutoRefresh,\r\n refreshSession: config.refreshSession\r\n };\r\n };\r\n\r\n async onRequest(\r\n config: RequestConfig,\r\n context: InterceptorContext\r\n ): Promise<RequestConfig> {\r\n\r\n //Actua en solicitudes que requieren autenticación\r\n if (!config.requiresAuth || !this.config.enabled) {\r\n return config;\r\n };\r\n\r\n //Actúa SOLO si los tokens son válidos\r\n if (!this.config.hasValidTokens()) {\r\n return config;\r\n };\r\n\r\n if (!this.config.shouldAutoRefresh()) {\r\n return config;\r\n };\r\n\r\n if (this.config.isTokenExpiringSoon()) {\r\n try {\r\n //Evita múltiples llamadas de actualización simultáneas\r\n if (this.isRefreshing && this.refreshPromise) {\r\n await this.refreshPromise;\r\n } else {\r\n this.isRefreshing = true;\r\n this.refreshPromise = this.config.refreshSession();\r\n await this.refreshPromise;\r\n this.isRefreshing = false;\r\n this.refreshPromise = null;\r\n };\r\n } catch (error) {\r\n this.isRefreshing = false;\r\n this.refreshPromise = null;\r\n };\r\n };\r\n\r\n return config;\r\n };\r\n\r\n updateConfig(config: Partial<AuthInterceptorConfig>): void {\r\n this.config = {\r\n ...this.config,\r\n ...config\r\n } as Required<AuthInterceptorConfig>;\r\n };\r\n\r\n reset(): void {\r\n this.isRefreshing = false;\r\n this.refreshPromise = null;\r\n };\r\n};\r\n","import { API } from \"@/core/API\";\r\nimport { CryptoService } from \"@/core/CryptoService\";\r\nimport { TokenManager } from \"@/core/TokenManager\";\r\nimport { LoginRequest } from \"@/interfaces/Auth/Login/LoginRequest\";\r\nimport { LoginResponse } from \"@/interfaces/Auth/Login/LoginResponse\";\r\nimport { RefreshTokenResponse } from \"@/interfaces/Auth/RefreshTokens/RefreshTokenResponse\";\r\nimport { ValidateSessionRenewedResponse, ValidateSessionResponse } from \"@/interfaces/Auth/ValidateSession/ValidateSessionResponse\";\r\nimport { ErrorResponse } from \"@/types/ErrorResponse\";\r\nimport { ResponseModel } from \"@/types/ResponseModel\";\r\nimport { ServiceProperties } from \"@/types/ServiceProperties\";\r\nimport { TokenData } from \"@/types/TokenData\";\r\n\r\nexport class AuthService {\r\n private api: API;\r\n private crytpoService: CryptoService;\r\n private tokenManager: TokenManager;\r\n private serviceProperties: ServiceProperties;\r\n\r\n constructor(\r\n serviceProperties: ServiceProperties,\r\n tokenManager: TokenManager,\r\n cryptoService: CryptoService,\r\n api: API\r\n ) {\r\n this.api = api;\r\n this.crytpoService = cryptoService;\r\n this.tokenManager = tokenManager;\r\n this.serviceProperties = serviceProperties;\r\n };\r\n\r\n /**\r\n * Login con las credenciales proporcionadas\r\n * @param credentials - Objeto con email, password y rememberMe\r\n * @returns Retorna el cuerpo de respuesta del login.\r\n */\r\n async login(credentials: LoginRequest): Promise<ResponseModel<LoginResponse>> {\r\n const timestamp = Date.now().toString();\r\n\r\n const encryptedEmail = this.crytpoService.encrypt(\r\n credentials.email,\r\n `${this.serviceProperties.originRequest}_${this.serviceProperties.domain}`,\r\n timestamp\r\n );\r\n\r\n const encryptedPassword = this.crytpoService.encrypt(\r\n credentials.password,\r\n `${this.serviceProperties.originRequest}_${this.serviceProperties.domain}`,\r\n timestamp\r\n );\r\n\r\n const loginData: LoginRequest = {\r\n email: encryptedEmail,\r\n password: encryptedPassword,\r\n rememberMe: credentials.rememberMe\r\n };\r\n\r\n const response = await this.api.executePublicRequest<ResponseModel>(\r\n 'oauth/login',\r\n 'POST',\r\n loginData,\r\n timestamp\r\n );\r\n\r\n if (!response) {\r\n throw new ErrorResponse('No response from server');\r\n };\r\n\r\n if (response.success) {\r\n const data: LoginResponse = response.data;\r\n\r\n const expiresIn = parseInt(data.expiresIn.replace('s', ''));\r\n const expiresAt = new Date(Date.now() + expiresIn * 1000);\r\n\r\n const tokens: TokenData = {\r\n accessToken: data.accessToken,\r\n refreshToken: data.refreshToken,\r\n expiresAt: expiresAt,\r\n rememberMe: credentials.rememberMe\r\n };\r\n\r\n await this.tokenManager.setTokens(tokens);\r\n\r\n this.serviceProperties.onTokensUpdated?.(tokens);\r\n\r\n const responseData: ResponseModel<LoginResponse> = {\r\n success: data.accessToken ? true : false,\r\n data: data,\r\n message: response.message,\r\n responseTime: '3s'\r\n };\r\n\r\n return responseData;\r\n }\r\n\r\n return response;\r\n };\r\n\r\n\r\n /**\r\n * Valida la sesión actual y retorna información de expiración\r\n *\r\n * El servidor puede responder de 2 formas:\r\n * 1. Sesión renovada (sliding window): retorna nuevos tokens\r\n * 2. Sesión válida: retorna info de expiración sin renovar\r\n */\r\n async validateSession(): Promise<ResponseModel<ValidateSessionRenewedResponse | ValidateSessionResponse>> {\r\n const response = await this.api.executePOST<ResponseModel<ValidateSessionRenewedResponse | ValidateSessionResponse>>(\r\n 'oauth/validateSession'\r\n );\r\n\r\n if (!response) {\r\n throw new ErrorResponse('No response from server');\r\n };\r\n\r\n if (response.success && response.data) {\r\n const respData = response.data;\r\n\r\n if ('expiresIn' in respData && respData.expiresIn) {\r\n const sessionData = respData as ValidateSessionRenewedResponse;\r\n const expiresIn = parseInt(sessionData.expiresIn.replace('s', ''));\r\n const expiresAt = new Date(Date.now() + expiresIn * 1000);\r\n\r\n const currentTokens = this.tokenManager.getTokens();\r\n const rememberMe = currentTokens?.rememberMe ?? sessionData.isRemembered;\r\n\r\n const tokens: TokenData = {\r\n accessToken: sessionData.accessToken,\r\n refreshToken: sessionData.refreshToken,\r\n expiresAt: expiresAt,\r\n rememberMe: rememberMe\r\n };\r\n\r\n this.tokenManager.setTokens(tokens);\r\n this.serviceProperties.onTokensUpdated?.(tokens);\r\n }\r\n else if ('expiresAt' in respData && respData.expiresAt) {\r\n const sessionData = respData as ValidateSessionResponse;\r\n\r\n if (sessionData.remainingMinutes <= 5 && sessionData.remainingMinutes > 1) {\r\n this.serviceProperties.onSessionExpiring?.(sessionData.remainingMinutes);\r\n } else if (sessionData.remainingMinutes <= 1) {\r\n if (this.serviceProperties.onSessionExpired) {\r\n await this.serviceProperties.onSessionExpired();\r\n }\r\n }\r\n }\r\n };\r\n\r\n return response;\r\n };\r\n\r\n /**\r\n * Refresca los tokens usando el refresh token\r\n */\r\n async refreshTokens(rememberMe?: boolean): Promise<ResponseModel<RefreshTokenResponse>> {\r\n const refreshToken = this.tokenManager.getRefreshToken();\r\n\r\n if (!refreshToken) {\r\n throw new ErrorResponse('No refresh token available');\r\n };\r\n\r\n const response = await this.api.executePublicRequest<ResponseModel<any>>(\r\n 'oauth/refresh',\r\n 'POST',\r\n { refreshToken }\r\n );\r\n\r\n if (!response) {\r\n throw new ErrorResponse('No response from server');\r\n };\r\n\r\n if (response.success) {\r\n const sessionData: RefreshTokenResponse = response.data;\r\n\r\n const currentTokens = this.tokenManager.getTokens();\r\n const shouldRemember = rememberMe ?? currentTokens?.rememberMe ?? false;\r\n const expiresIn = parseInt(sessionData.expiresIn.replace('s', ''));\r\n const expiresAt = new Date(Date.now() + expiresIn * 1000);\r\n\r\n const tokens: TokenData = {\r\n accessToken: sessionData.accessToken,\r\n refreshToken: sessionData.refreshToken,\r\n expiresAt: expiresAt,\r\n rememberMe: shouldRemember\r\n };\r\n\r\n this.tokenManager.setTokens(tokens);\r\n this.serviceProperties.onTokensUpdated?.(tokens);\r\n };\r\n\r\n return response;\r\n };\r\n\r\n /**\r\n * Cierra sesión: notifica al servidor y limpia tokens\r\n */\r\n async logout(): Promise<void> {\r\n try {\r\n await this.api.executePOST('oauth/logout');\r\n } catch (error) {\r\n // Continuar con logout local aunque falle el servidor\r\n };\r\n\r\n this.tokenManager.clearTokens();\r\n this.serviceProperties.onTokensUpdated?.(null);\r\n };\r\n\r\n /**\r\n * Verifica si el usuario está autenticado\r\n */\r\n isAuthenticated(): boolean {\r\n return this.tokenManager.hasValidTokens();\r\n };\r\n\r\n /**\r\n * Obtiene los tokens actuales\r\n */\r\n getTokens(): TokenData | null {\r\n return this.tokenManager.getTokens();\r\n };\r\n\r\n}\r\n","import { API } from \"./core/API\";\r\nimport { CryptoService } from \"./core/CryptoService\";\r\nimport { TokenManager } from \"./core/TokenManager\";\r\nimport { AuthInterceptor } from \"./core/interceptors/AuthInterceptor\";\r\nimport { ServiceProperties } from \"./types/ServiceProperties\";\r\nimport { TokenData } from \"./types/TokenData\";\r\nimport { AuthService } from \"./services/AuthService\";\r\n\r\n/**\r\n * SDK principal de FalconHUB\r\n */\r\nexport class FalconHUBSDK {\r\n public auth: AuthService;\r\n\r\n private serviceProperties: ServiceProperties;\r\n private cryptoService: CryptoService;\r\n private tokenManager: TokenManager;\r\n private authInterceptor: AuthInterceptor | null;\r\n private api: API;\r\n\r\n constructor(serviceProperties: ServiceProperties) {\r\n this.serviceProperties = serviceProperties;\r\n\r\n this.cryptoService = new CryptoService();\r\n\r\n this.tokenManager = new TokenManager(\r\n this.serviceProperties.onTokensUpdated,\r\n this.serviceProperties.onSessionExpiring,\r\n async () => {\r\n await this.auth.logout();\r\n }\r\n );\r\n\r\n const autoRefreshConfig = this.normalizeAutoRefreshConfig(this.serviceProperties.autoRefresh);\r\n\r\n if (autoRefreshConfig.enabled) {\r\n this.authInterceptor = new AuthInterceptor({\r\n enabled: true,\r\n thresholdMinutes: autoRefreshConfig.thresholdMinutes,\r\n isTokenExpiringSoon: () => this.tokenManager.isTokenExpiringSoon(autoRefreshConfig.thresholdMinutes),\r\n hasValidTokens: () => this.tokenManager.hasValidTokens(),\r\n shouldAutoRefresh: () => this.tokenManager.shouldAutoRefresh(),\r\n refreshSession: async () => {\r\n await this.auth.validateSession();\r\n }\r\n });\r\n } else {\r\n this.authInterceptor = null;\r\n }\r\n\r\n this.api = new API(\r\n this.serviceProperties,\r\n this.cryptoService,\r\n this.authInterceptor,\r\n () => this.tokenManager.getAccessToken(),\r\n () => this.tokenManager.getRefreshToken()\r\n );\r\n\r\n this.auth = new AuthService(\r\n this.serviceProperties,\r\n this.tokenManager,\r\n this.cryptoService,\r\n this.api\r\n );\r\n }\r\n\r\n private normalizeAutoRefreshConfig(\r\n config: ServiceProperties[\"autoRefresh\"]\r\n ): { enabled: boolean; thresholdMinutes: number } {\r\n if (typeof config === \"boolean\") {\r\n return { enabled: config, thresholdMinutes: 5 };\r\n }\r\n if (typeof config === \"object\" && config !== null) {\r\n return {\r\n enabled: config.enabled,\r\n thresholdMinutes: config.thresholdMinutes ?? 5\r\n };\r\n }\r\n return { enabled: true, thresholdMinutes: 5 };\r\n }\r\n\r\n /**\r\n * Inyecta tokens desde storage externo (cookies/localStorage/etc)\r\n */\r\n setTokensFromExternal(\r\n accessToken: string,\r\n refreshToken: string,\r\n expiresAt: Date,\r\n rememberMe: boolean = false\r\n ): void {\r\n const tokens: TokenData = {\r\n accessToken,\r\n refreshToken,\r\n expiresAt,\r\n rememberMe\r\n };\r\n\r\n this.tokenManager.setTokens(tokens);\r\n }\r\n\r\n /**\r\n * Obtiene los tokens actuales\r\n */\r\n getTokens(): TokenData | null {\r\n return this.tokenManager.getTokens();\r\n }\r\n\r\n /**\r\n * Verifica si el usuario está autenticado\r\n */\r\n isAuthenticated(): boolean {\r\n return this.tokenManager.hasValidTokens();\r\n }\r\n\r\n /**\r\n * Verifica si la sesión está por expirar\r\n */\r\n isSessionExpiringSoon(thresholdMinutes: number = 5): boolean {\r\n return this.tokenManager.isTokenExpiringSoon(thresholdMinutes);\r\n }\r\n\r\n /**\r\n * Obtiene el tiempo restante hasta la expiración en milisegundos\r\n */\r\n getTimeUntilExpiry(): number | null {\r\n return this.tokenManager.getTimeUntilExpiry();\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
|