falconhub-apilibrary 1.4.0-dev.113 → 1.4.0-dev.115
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.d.mts +1044 -1019
- package/dist/index.mjs +573 -537
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,451 +1,24 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* Ejecuta una request HTTP al API
|
|
12
|
-
*
|
|
13
|
-
* @param options - Opciones de la request
|
|
14
|
-
* @returns Respuesta del tipo ResponseModel
|
|
15
|
-
*/
|
|
16
|
-
async apiExecute(options) {
|
|
17
|
-
const {
|
|
18
|
-
endpoint,
|
|
19
|
-
method,
|
|
20
|
-
body,
|
|
21
|
-
requiresAuth,
|
|
22
|
-
timeStamp
|
|
23
|
-
} = options;
|
|
24
|
-
const context = {
|
|
25
|
-
requestId: this.cryptoService.generateUniqueId(),
|
|
26
|
-
startTime: Date.now(),
|
|
27
|
-
retryCount: 0,
|
|
28
|
-
metadata: {}
|
|
29
|
-
};
|
|
30
|
-
try {
|
|
31
|
-
const url = `${this.properties.url}/${endpoint}`;
|
|
32
|
-
const headers = {};
|
|
33
|
-
if (body && method !== "GET") {
|
|
34
|
-
headers["Content-Type"] = "application/json";
|
|
35
|
-
}
|
|
36
|
-
;
|
|
37
|
-
const accessToken = this.getAccessToken();
|
|
38
|
-
if (accessToken) {
|
|
39
|
-
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
40
|
-
}
|
|
41
|
-
;
|
|
42
|
-
const newTimeStamp = timeStamp || (/* @__PURE__ */ new Date()).toISOString();
|
|
43
|
-
headers["X-Origin-Request"] = this.properties.originRequest;
|
|
44
|
-
headers["X-Timestamp"] = newTimeStamp;
|
|
45
|
-
headers["X-Domain"] = this.properties.domain;
|
|
46
|
-
headers["X-Device"] = this.properties.device;
|
|
47
|
-
headers["X-Source"] = this.properties.source;
|
|
48
|
-
let bodyString;
|
|
49
|
-
if (body && method !== "GET") {
|
|
50
|
-
bodyString = JSON.stringify(body);
|
|
51
|
-
}
|
|
52
|
-
;
|
|
53
|
-
const requestConfig = {
|
|
54
|
-
url,
|
|
55
|
-
method,
|
|
56
|
-
headers,
|
|
57
|
-
body: bodyString,
|
|
58
|
-
requiresAuth
|
|
59
|
-
};
|
|
60
|
-
const modifiedConfig = this.authInterceptor ? await this.authInterceptor.onRequest(requestConfig, context) : requestConfig;
|
|
61
|
-
const requestInit = {
|
|
62
|
-
method: modifiedConfig.method,
|
|
63
|
-
headers: modifiedConfig.headers,
|
|
64
|
-
mode: "cors",
|
|
65
|
-
credentials: "omit"
|
|
66
|
-
};
|
|
67
|
-
if (modifiedConfig.body && modifiedConfig.method !== "GET") {
|
|
68
|
-
requestInit.body = typeof modifiedConfig.body === "string" ? modifiedConfig.body : JSON.stringify(modifiedConfig.body);
|
|
69
|
-
}
|
|
70
|
-
;
|
|
71
|
-
const response = await fetch(
|
|
72
|
-
modifiedConfig.url,
|
|
73
|
-
requestInit
|
|
74
|
-
);
|
|
75
|
-
const newAccessToken = response.headers.get("X-New-Access-Token");
|
|
76
|
-
const newRefreshToken = response.headers.get("X-New-Refresh-Token");
|
|
77
|
-
if (newAccessToken || newRefreshToken) {
|
|
78
|
-
this.properties.onTokensRefreshed?.({
|
|
79
|
-
accessToken: newAccessToken,
|
|
80
|
-
refreshToken: newRefreshToken
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
;
|
|
84
|
-
let result;
|
|
85
|
-
try {
|
|
86
|
-
result = await response.json();
|
|
87
|
-
} catch (e) {
|
|
88
|
-
return {
|
|
89
|
-
success: false,
|
|
90
|
-
message: `Error de servidor (${response.status}: ${response.statusText || "Formato de respuesta no reconocido"})`,
|
|
91
|
-
data: null,
|
|
92
|
-
responseTime: (/* @__PURE__ */ new Date()).toISOString()
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
if (result && result.errors && typeof result.errors === "object") {
|
|
96
|
-
const errorMessages = [];
|
|
97
|
-
Object.values(result.errors).forEach((errors) => {
|
|
98
|
-
if (Array.isArray(errors)) {
|
|
99
|
-
errorMessages.push(...errors);
|
|
100
|
-
} else if (typeof errors === "string") {
|
|
101
|
-
errorMessages.push(errors);
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
if (errorMessages.length > 0) {
|
|
105
|
-
return {
|
|
106
|
-
success: false,
|
|
107
|
-
message: errorMessages.join(", "),
|
|
108
|
-
data: result.data ?? null,
|
|
109
|
-
responseTime: result.responseTime ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return result;
|
|
114
|
-
} catch (error) {
|
|
115
|
-
return {
|
|
116
|
-
success: false,
|
|
117
|
-
message: error instanceof Error ? error.message : "Error inesperado durante la petici\xF3n al API.",
|
|
118
|
-
data: null,
|
|
119
|
-
responseTime: (/* @__PURE__ */ new Date()).toISOString()
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
;
|
|
123
|
-
}
|
|
124
|
-
//#region REQUEST METHODS
|
|
125
|
-
async executeGET(endpoint, requiresAuth = false) {
|
|
126
|
-
return this.apiExecute({
|
|
127
|
-
endpoint,
|
|
128
|
-
method: "GET",
|
|
129
|
-
requiresAuth
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
async executePOST(endpoint, body, requiresAuth = true) {
|
|
133
|
-
return this.apiExecute({
|
|
134
|
-
endpoint,
|
|
135
|
-
method: "POST",
|
|
136
|
-
body,
|
|
137
|
-
requiresAuth
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
async executePATCH(endpoint, body, requiresAuth = true) {
|
|
141
|
-
return this.apiExecute({
|
|
142
|
-
endpoint,
|
|
143
|
-
method: "PATCH",
|
|
144
|
-
body,
|
|
145
|
-
requiresAuth
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
async executeDELETE(endpoint, body, requiresAuth = true) {
|
|
149
|
-
return this.apiExecute({
|
|
150
|
-
endpoint,
|
|
151
|
-
method: "DELETE",
|
|
152
|
-
body,
|
|
153
|
-
requiresAuth
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
async executePUT(endpoint, body, requiresAuth = true) {
|
|
157
|
-
return this.apiExecute({
|
|
158
|
-
endpoint,
|
|
159
|
-
method: "PUT",
|
|
160
|
-
body,
|
|
161
|
-
requiresAuth
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
async executePublicRequest(endpoint, method, body, timestamp) {
|
|
165
|
-
return this.apiExecute({
|
|
166
|
-
endpoint,
|
|
167
|
-
method,
|
|
168
|
-
body,
|
|
169
|
-
requiresAuth: false,
|
|
170
|
-
timeStamp: timestamp
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
//#endregion
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
// src/core/CryptoService.ts
|
|
177
|
-
import * as CryptoJS from "crypto-js";
|
|
178
|
-
var CryptoService = class {
|
|
179
|
-
/**
|
|
180
|
-
* Genera un hash SHA256 de un texto (útil para fingerprints)
|
|
181
|
-
*
|
|
182
|
-
* @param text - Texto a hashear
|
|
183
|
-
* @returns Hash en formato hexadecimal
|
|
184
|
-
*/
|
|
185
|
-
sha256(text) {
|
|
186
|
-
return CryptoJS.SHA256(text).toString(CryptoJS.enc.Hex);
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Genera un identificador único basado en timestamp y random
|
|
190
|
-
* (útil para request IDs)
|
|
191
|
-
*
|
|
192
|
-
* @returns ID único
|
|
193
|
-
*/
|
|
194
|
-
generateUniqueId() {
|
|
195
|
-
const timestamp = Date.now().toString(36);
|
|
196
|
-
const randomPart = Math.random().toString(36).substring(2, 15);
|
|
197
|
-
return `${timestamp}-${randomPart}`;
|
|
198
|
-
}
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
// src/core/TokenManager.ts
|
|
202
|
-
var TokenManager = class {
|
|
203
|
-
constructor(onTokensChanged, onSessionExpiring, onSessionExpired, onSessionRecovery, autoRefreshThresholdMinutes) {
|
|
204
|
-
this.tokens = null;
|
|
205
|
-
this.sessionCheckInterval = null;
|
|
206
|
-
this.autoRefreshTimeout = null;
|
|
207
|
-
this.hasNotifiedExpiring = false;
|
|
208
|
-
this.autoRefreshThresholdMinutes = 5;
|
|
209
|
-
this.onTokensChanged = onTokensChanged;
|
|
210
|
-
this.onSessionExpiring = onSessionExpiring;
|
|
211
|
-
this.onSessionExpired = onSessionExpired;
|
|
212
|
-
this.onSessionRecovery = onSessionRecovery;
|
|
213
|
-
this.autoRefreshThresholdMinutes = autoRefreshThresholdMinutes ?? 5;
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Guarda los tokens de autenticación y dispara el callback onTokensChanged.
|
|
217
|
-
*/
|
|
218
|
-
setTokens(tokens) {
|
|
219
|
-
this.tokens = tokens;
|
|
220
|
-
this.hasNotifiedExpiring = false;
|
|
221
|
-
this.onTokensChanged?.(this.tokens);
|
|
222
|
-
if (!tokens.rememberMe) {
|
|
223
|
-
this.startExpirationCheck();
|
|
224
|
-
this.stopAutoRefreshTimer();
|
|
225
|
-
} else {
|
|
226
|
-
this.stopExpirationCheck();
|
|
227
|
-
this.scheduleAutoRefresh();
|
|
228
|
-
}
|
|
229
|
-
;
|
|
230
|
-
}
|
|
231
|
-
/**
|
|
232
|
-
* Guarda los tokens sin disparar el callback onTokensChanged.
|
|
233
|
-
* Usar para inyectar tokens desde storage externo (cookies/localStorage).
|
|
234
|
-
*/
|
|
235
|
-
setTokensSilent(tokens) {
|
|
236
|
-
this.tokens = tokens;
|
|
237
|
-
this.hasNotifiedExpiring = false;
|
|
238
|
-
if (!tokens.rememberMe) {
|
|
239
|
-
this.startExpirationCheck();
|
|
240
|
-
this.stopAutoRefreshTimer();
|
|
241
|
-
} else {
|
|
242
|
-
this.stopExpirationCheck();
|
|
243
|
-
this.scheduleAutoRefresh();
|
|
244
|
-
}
|
|
245
|
-
;
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Obtiene los tokens de autenticación almacenados.
|
|
249
|
-
*/
|
|
250
|
-
getTokens() {
|
|
251
|
-
return this.tokens;
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Limpia los tokens de autenticación almacenados y dispara el callback onTokensChanged.
|
|
255
|
-
*/
|
|
256
|
-
clearTokens() {
|
|
257
|
-
this.stopExpirationCheck();
|
|
258
|
-
this.stopAutoRefreshTimer();
|
|
259
|
-
this.tokens = null;
|
|
260
|
-
this.onTokensChanged?.(this.tokens);
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Valida si existen tokens y si el access token no ha expirado.
|
|
264
|
-
*/
|
|
265
|
-
hasValidTokens() {
|
|
266
|
-
if (!this.tokens) return false;
|
|
267
|
-
return Date.now() < this.tokens.expiresAt;
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Valida si el access token expirará dentro del umbral especificado (en minutos).
|
|
271
|
-
*/
|
|
272
|
-
isTokenExpiringSoon(thresholdMinutes) {
|
|
273
|
-
if (!this.tokens) return false;
|
|
274
|
-
const thresholdMs = thresholdMinutes * 60 * 1e3;
|
|
275
|
-
const timeLeft = this.tokens.expiresAt - Date.now();
|
|
276
|
-
return timeLeft > 0 && timeLeft <= thresholdMs;
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Obtiene el tiempo restante hasta la expiración del access token en milisegundos.
|
|
280
|
-
*/
|
|
281
|
-
getTimeUntilExpiry() {
|
|
282
|
-
if (!this.tokens) return null;
|
|
283
|
-
return Math.max(0, this.tokens.expiresAt - Date.now());
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Obtiene el access token almacenado.
|
|
287
|
-
*/
|
|
288
|
-
getAccessToken() {
|
|
289
|
-
return this.tokens ? this.tokens.accessToken : null;
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* Obtiene el refresh token almacenado.
|
|
293
|
-
*/
|
|
294
|
-
getRefreshToken() {
|
|
295
|
-
return this.tokens ? this.tokens.refreshToken : null;
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Verifica si el auto-refresh debe ejecutarse
|
|
299
|
-
* Solo si el usuario activó "rememberMe" durante el login
|
|
300
|
-
*/
|
|
301
|
-
shouldAutoRefresh() {
|
|
302
|
-
if (!this.tokens) return false;
|
|
303
|
-
return this.tokens.rememberMe === true;
|
|
304
|
-
}
|
|
305
|
-
/**
|
|
306
|
-
* Inicia el monitoreo de expiración para sesiones sin rememberMe
|
|
307
|
-
* - Notifica cuando quedan 5 minutos (onSessionExpiring)
|
|
308
|
-
*/
|
|
309
|
-
startExpirationCheck() {
|
|
310
|
-
this.stopExpirationCheck();
|
|
311
|
-
this.sessionCheckInterval = setInterval(async () => {
|
|
312
|
-
if (!this.tokens) {
|
|
313
|
-
this.stopExpirationCheck();
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
;
|
|
317
|
-
const timeLeft = this.getTimeUntilExpiry();
|
|
318
|
-
if (timeLeft === null) return;
|
|
319
|
-
const minutesLeft = Math.floor(timeLeft / (60 * 1e3));
|
|
320
|
-
if (minutesLeft <= 5 && minutesLeft > 1 && !this.hasNotifiedExpiring) {
|
|
321
|
-
this.hasNotifiedExpiring = true;
|
|
322
|
-
this.onSessionExpiring?.(minutesLeft);
|
|
323
|
-
}
|
|
324
|
-
;
|
|
325
|
-
if (minutesLeft <= 1) {
|
|
326
|
-
this.stopExpirationCheck();
|
|
327
|
-
if (this.onSessionRecovery) {
|
|
328
|
-
try {
|
|
329
|
-
const recovered = await this.onSessionRecovery();
|
|
330
|
-
if (recovered) return;
|
|
331
|
-
} catch (error) {
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
if (this.onSessionExpired) {
|
|
335
|
-
await this.onSessionExpired();
|
|
336
|
-
}
|
|
337
|
-
;
|
|
338
|
-
}
|
|
339
|
-
;
|
|
340
|
-
}, 6e4);
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* Programa un auto-refresh proactivo para sesiones con rememberMe.
|
|
344
|
-
* Se ejecuta X minutos antes de que expire el token
|
|
345
|
-
*/
|
|
346
|
-
scheduleAutoRefresh() {
|
|
347
|
-
this.stopAutoRefreshTimer();
|
|
348
|
-
if (!this.tokens || !this.tokens.rememberMe) return;
|
|
349
|
-
const timeLeft = this.getTimeUntilExpiry();
|
|
350
|
-
if (timeLeft === null || timeLeft <= 0) return;
|
|
351
|
-
const thresholdMs = this.autoRefreshThresholdMinutes * 60 * 1e3;
|
|
352
|
-
const delay = Math.max(0, timeLeft - thresholdMs);
|
|
353
|
-
this.autoRefreshTimeout = setTimeout(async () => {
|
|
354
|
-
if (!this.tokens || !this.tokens.rememberMe) return;
|
|
355
|
-
if (this.onSessionRecovery) {
|
|
356
|
-
try {
|
|
357
|
-
const recovered = await this.onSessionRecovery();
|
|
358
|
-
if (recovered) return;
|
|
359
|
-
} catch (error) {
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
if (this.onSessionExpired) {
|
|
363
|
-
await this.onSessionExpired();
|
|
364
|
-
}
|
|
365
|
-
}, delay);
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* Detiene el monitoreo de expiración
|
|
369
|
-
*/
|
|
370
|
-
stopExpirationCheck() {
|
|
371
|
-
if (this.sessionCheckInterval) {
|
|
372
|
-
clearInterval(this.sessionCheckInterval);
|
|
373
|
-
this.sessionCheckInterval = null;
|
|
374
|
-
}
|
|
375
|
-
;
|
|
376
|
-
}
|
|
377
|
-
/**
|
|
378
|
-
* Detiene el timer de auto-refresh proactivo
|
|
379
|
-
*/
|
|
380
|
-
stopAutoRefreshTimer() {
|
|
381
|
-
if (this.autoRefreshTimeout) {
|
|
382
|
-
clearTimeout(this.autoRefreshTimeout);
|
|
383
|
-
this.autoRefreshTimeout = null;
|
|
384
|
-
}
|
|
385
|
-
;
|
|
386
|
-
}
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
// src/core/interceptors/AuthInterceptor.ts
|
|
390
|
-
var AuthInterceptor = class {
|
|
391
|
-
constructor(config) {
|
|
392
|
-
this.name = "AuthInterceptor";
|
|
393
|
-
this.refreshPromise = null;
|
|
394
|
-
this.isRefreshing = false;
|
|
395
|
-
this.config = {
|
|
396
|
-
enabled: config.enabled ?? true,
|
|
397
|
-
thresholdMinutes: config.thresholdMinutes ?? 5,
|
|
398
|
-
isTokenExpiringSoon: config.isTokenExpiringSoon,
|
|
399
|
-
hasValidTokens: config.hasValidTokens,
|
|
400
|
-
shouldAutoRefresh: config.shouldAutoRefresh,
|
|
401
|
-
refreshSession: config.refreshSession
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
async onRequest(config, context) {
|
|
405
|
-
if (!config.requiresAuth || !this.config.enabled) {
|
|
406
|
-
return config;
|
|
407
|
-
}
|
|
408
|
-
;
|
|
409
|
-
if (!this.config.hasValidTokens()) {
|
|
410
|
-
return config;
|
|
411
|
-
}
|
|
412
|
-
;
|
|
413
|
-
if (!this.config.shouldAutoRefresh()) {
|
|
414
|
-
return config;
|
|
415
|
-
}
|
|
416
|
-
;
|
|
417
|
-
if (this.config.isTokenExpiringSoon()) {
|
|
418
|
-
try {
|
|
419
|
-
if (this.isRefreshing && this.refreshPromise) {
|
|
420
|
-
await this.refreshPromise;
|
|
421
|
-
} else {
|
|
422
|
-
this.isRefreshing = true;
|
|
423
|
-
this.refreshPromise = this.config.refreshSession();
|
|
424
|
-
await this.refreshPromise;
|
|
425
|
-
this.isRefreshing = false;
|
|
426
|
-
this.refreshPromise = null;
|
|
427
|
-
}
|
|
428
|
-
;
|
|
429
|
-
} catch (error) {
|
|
430
|
-
this.isRefreshing = false;
|
|
431
|
-
this.refreshPromise = null;
|
|
432
|
-
}
|
|
433
|
-
;
|
|
434
|
-
}
|
|
435
|
-
;
|
|
436
|
-
return config;
|
|
437
|
-
}
|
|
438
|
-
updateConfig(config) {
|
|
439
|
-
this.config = {
|
|
440
|
-
...this.config,
|
|
441
|
-
...config
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
reset() {
|
|
445
|
-
this.isRefreshing = false;
|
|
446
|
-
this.refreshPromise = null;
|
|
447
|
-
}
|
|
1
|
+
// src/interfaces/Product/Blank/BlankInterface.ts
|
|
2
|
+
var BLANKS_BULK_COLUMN_MAP = {
|
|
3
|
+
"Titulo del Blank": "blank",
|
|
4
|
+
"SKU": "sku",
|
|
5
|
+
"Costo": "cost",
|
|
6
|
+
"Color": "color",
|
|
7
|
+
"Proveedor": "provider",
|
|
8
|
+
"Material": "material",
|
|
9
|
+
"Talla": "size",
|
|
10
|
+
"Activo": "isActive"
|
|
448
11
|
};
|
|
12
|
+
var BLANKS_BULK_SPANISH_HEADERS = [
|
|
13
|
+
"Titulo del Blank",
|
|
14
|
+
"SKU",
|
|
15
|
+
"Costo",
|
|
16
|
+
"Color",
|
|
17
|
+
"Proveedor",
|
|
18
|
+
"Material",
|
|
19
|
+
"Talla",
|
|
20
|
+
"Activo"
|
|
21
|
+
];
|
|
449
22
|
|
|
450
23
|
// src/types/ErrorResponse.ts
|
|
451
24
|
var ErrorResponse = class extends Error {
|
|
@@ -1244,6 +817,18 @@ var ProductService = class {
|
|
|
1244
817
|
async deleteBlank(id) {
|
|
1245
818
|
return this.api.executeDELETE(`${this.BASE_PATH}/blanks/${id}`);
|
|
1246
819
|
}
|
|
820
|
+
/**
|
|
821
|
+
* Obtiene la plantilla para la carga masiva de blanks.
|
|
822
|
+
*/
|
|
823
|
+
async getBlanksBulkTemplate() {
|
|
824
|
+
return this.api.executeGET(`${this.BASE_PATH}/blanks/bulk/template`, false);
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Realiza una carga masiva de blanks.
|
|
828
|
+
*/
|
|
829
|
+
async bulkCreateBlanks(request) {
|
|
830
|
+
return this.api.executePOST(`${this.BASE_PATH}/blanks/bulk`, request);
|
|
831
|
+
}
|
|
1247
832
|
// #endregion
|
|
1248
833
|
};
|
|
1249
834
|
|
|
@@ -1496,154 +1081,603 @@ var UserService = class {
|
|
|
1496
1081
|
return this.api.executeGET(`${this.BASE_PATH}/admin/${id}`, true);
|
|
1497
1082
|
}
|
|
1498
1083
|
/**
|
|
1499
|
-
* Obtiene la autenticación de un administrador.
|
|
1500
|
-
* @param id - ID del usuario
|
|
1084
|
+
* Obtiene la autenticación de un administrador.
|
|
1085
|
+
* @param id - ID del usuario
|
|
1086
|
+
*/
|
|
1087
|
+
async getAdminAuthentication(id) {
|
|
1088
|
+
return this.api.executeGET(`${this.BASE_PATH}/admin/authentication/${id}`, true);
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Actualiza un administrador existente.
|
|
1092
|
+
* @param id - ID del administrador
|
|
1093
|
+
* @param request - Nuevos datos del administrador
|
|
1094
|
+
*/
|
|
1095
|
+
async updateAdmin(id, request) {
|
|
1096
|
+
return this.api.executePUT(`${this.BASE_PATH}/admin/${id}`, request);
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Activa o desactiva un administrador.
|
|
1100
|
+
* @param id - ID del administrador
|
|
1101
|
+
*/
|
|
1102
|
+
async toggleAdminStatus(id) {
|
|
1103
|
+
return this.api.executePUT(`${this.BASE_PATH}/admin/${id}/toggle-status`);
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Actualiza la autenticación de un administrador.
|
|
1107
|
+
* @param id - ID del usuario
|
|
1108
|
+
* @param request - Nuevos datos de autenticación
|
|
1109
|
+
*/
|
|
1110
|
+
async updateAdminAuthentication(id, request) {
|
|
1111
|
+
return this.api.executePUT(`${this.BASE_PATH}/admin/authentication/${id}`, request);
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* Elimina un administrador.
|
|
1115
|
+
* @param id - ID del administrador
|
|
1116
|
+
*/
|
|
1117
|
+
async deleteAdmin(id) {
|
|
1118
|
+
return this.api.executeDELETE(`${this.BASE_PATH}/admin/${id}`);
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Reenvía el correo de confirmación al usuario.
|
|
1122
|
+
* @param id - ID del usuario
|
|
1123
|
+
*/
|
|
1124
|
+
async resendEmailConfirmation(id) {
|
|
1125
|
+
return this.api.executePOST(`${this.BASE_PATH}/admin/authentication/${id}/resend-confirmation`);
|
|
1126
|
+
}
|
|
1127
|
+
// #endregion
|
|
1128
|
+
// #region User Types
|
|
1129
|
+
/**
|
|
1130
|
+
* Obtiene todos los tipos de usuario con filtros opcionales.
|
|
1131
|
+
* @param filter - Filtros opcionales para la búsqueda
|
|
1132
|
+
*/
|
|
1133
|
+
async getUserTypes(filter) {
|
|
1134
|
+
const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/user-types`, filter);
|
|
1135
|
+
return this.api.executeGET(endpoint, true);
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Obtiene el modelo de filtros disponibles para tipos de usuario.
|
|
1139
|
+
*/
|
|
1140
|
+
async getUserTypesFilters() {
|
|
1141
|
+
return this.api.executeGET(`${this.BASE_PATH}/catalogs/user-types/filters`, true);
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Obtiene un tipo de usuario por su ID.
|
|
1145
|
+
* @param id - ID del tipo de usuario
|
|
1146
|
+
*/
|
|
1147
|
+
async getUserTypeById(id) {
|
|
1148
|
+
return this.api.executeGET(`${this.BASE_PATH}/catalogs/user-types/${id}`, true);
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* Crea un nuevo tipo de usuario.
|
|
1152
|
+
* @param request - Datos del tipo de usuario a crear
|
|
1153
|
+
*/
|
|
1154
|
+
async createUserType(request) {
|
|
1155
|
+
return this.api.executePOST(`${this.BASE_PATH}/catalogs/user-types`, request);
|
|
1156
|
+
}
|
|
1157
|
+
/**
|
|
1158
|
+
* Actualiza un tipo de usuario existente.
|
|
1159
|
+
* @param id - ID del tipo de usuario a actualizar
|
|
1160
|
+
* @param request - Nuevos datos del tipo de usuario
|
|
1161
|
+
*/
|
|
1162
|
+
async updateUserType(id, request) {
|
|
1163
|
+
return this.api.executePUT(`${this.BASE_PATH}/catalogs/user-types/${id}`, request);
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Elimina un tipo de usuario.
|
|
1167
|
+
* @param id - ID del tipo de usuario a eliminar
|
|
1168
|
+
*/
|
|
1169
|
+
async deleteUserType(id) {
|
|
1170
|
+
return this.api.executeDELETE(`${this.BASE_PATH}/catalogs/user-types/${id}`);
|
|
1171
|
+
}
|
|
1172
|
+
// #endregion
|
|
1173
|
+
// #region Roles
|
|
1174
|
+
/**
|
|
1175
|
+
* Obtiene todos los roles con filtros opcionales.
|
|
1176
|
+
* @param filter - Filtros opcionales para la búsqueda
|
|
1177
|
+
*/
|
|
1178
|
+
async getRoles(filter) {
|
|
1179
|
+
const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/roles`, filter);
|
|
1180
|
+
return this.api.executeGET(endpoint, true);
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Obtiene el modelo de filtros disponibles para roles.
|
|
1184
|
+
*/
|
|
1185
|
+
async getRolesFilters() {
|
|
1186
|
+
return this.api.executeGET(`${this.BASE_PATH}/catalogs/roles/filters`, true);
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Obtiene un rol por su ID.
|
|
1190
|
+
* @param id - ID del rol
|
|
1191
|
+
*/
|
|
1192
|
+
async getRoleById(id) {
|
|
1193
|
+
return this.api.executeGET(`${this.BASE_PATH}/catalogs/roles/${id}`, true);
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Obtiene los roles asociados a un tipo de usuario.
|
|
1197
|
+
* @param userTypeId - ID del tipo de usuario
|
|
1198
|
+
*/
|
|
1199
|
+
async getRolesByUserType(userTypeId) {
|
|
1200
|
+
return this.api.executeGET(`${this.BASE_PATH}/catalogs/roles/user-type/${userTypeId}`, true);
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Crea un nuevo rol.
|
|
1204
|
+
* @param request - Datos del rol a crear
|
|
1501
1205
|
*/
|
|
1502
|
-
async
|
|
1503
|
-
return this.api.
|
|
1206
|
+
async createRole(request) {
|
|
1207
|
+
return this.api.executePOST(`${this.BASE_PATH}/catalogs/roles`, request);
|
|
1504
1208
|
}
|
|
1505
1209
|
/**
|
|
1506
|
-
* Actualiza un
|
|
1507
|
-
* @param id - ID del
|
|
1508
|
-
* @param request - Nuevos datos del
|
|
1210
|
+
* Actualiza un rol existente.
|
|
1211
|
+
* @param id - ID del rol a actualizar
|
|
1212
|
+
* @param request - Nuevos datos del rol
|
|
1509
1213
|
*/
|
|
1510
|
-
async
|
|
1511
|
-
return this.api.executePUT(`${this.BASE_PATH}/
|
|
1214
|
+
async updateRole(id, request) {
|
|
1215
|
+
return this.api.executePUT(`${this.BASE_PATH}/catalogs/roles/${id}`, request);
|
|
1512
1216
|
}
|
|
1513
1217
|
/**
|
|
1514
|
-
* Activa o desactiva un
|
|
1515
|
-
* @param id - ID del
|
|
1218
|
+
* Activa o desactiva un rol.
|
|
1219
|
+
* @param id - ID del rol
|
|
1516
1220
|
*/
|
|
1517
|
-
async
|
|
1518
|
-
return this.api.executePUT(`${this.BASE_PATH}/
|
|
1221
|
+
async toggleRoleStatus(id) {
|
|
1222
|
+
return this.api.executePUT(`${this.BASE_PATH}/catalogs/roles/${id}/toggle-status`);
|
|
1519
1223
|
}
|
|
1520
1224
|
/**
|
|
1521
|
-
*
|
|
1522
|
-
* @param id - ID del
|
|
1523
|
-
* @param request - Nuevos datos de autenticación
|
|
1225
|
+
* Elimina un rol.
|
|
1226
|
+
* @param id - ID del rol a eliminar
|
|
1524
1227
|
*/
|
|
1525
|
-
async
|
|
1526
|
-
return this.api.
|
|
1228
|
+
async deleteRole(id) {
|
|
1229
|
+
return this.api.executeDELETE(`${this.BASE_PATH}/catalogs/roles/${id}`);
|
|
1230
|
+
}
|
|
1231
|
+
// #endregion
|
|
1232
|
+
};
|
|
1233
|
+
|
|
1234
|
+
// src/core/API.ts
|
|
1235
|
+
var API = class {
|
|
1236
|
+
constructor(properties, cryptoService, authInterceptor, getAccessToken, getRefreshToken) {
|
|
1237
|
+
this.properties = properties;
|
|
1238
|
+
this.cryptoService = cryptoService;
|
|
1239
|
+
this.getAccessToken = getAccessToken;
|
|
1240
|
+
this.getRefreshToken = getRefreshToken;
|
|
1241
|
+
this.authInterceptor = authInterceptor;
|
|
1527
1242
|
}
|
|
1528
1243
|
/**
|
|
1529
|
-
*
|
|
1530
|
-
*
|
|
1244
|
+
* Ejecuta una request HTTP al API
|
|
1245
|
+
*
|
|
1246
|
+
* @param options - Opciones de la request
|
|
1247
|
+
* @returns Respuesta del tipo ResponseModel
|
|
1531
1248
|
*/
|
|
1532
|
-
async
|
|
1533
|
-
|
|
1249
|
+
async apiExecute(options) {
|
|
1250
|
+
const {
|
|
1251
|
+
endpoint,
|
|
1252
|
+
method,
|
|
1253
|
+
body,
|
|
1254
|
+
requiresAuth,
|
|
1255
|
+
timeStamp
|
|
1256
|
+
} = options;
|
|
1257
|
+
const context = {
|
|
1258
|
+
requestId: this.cryptoService.generateUniqueId(),
|
|
1259
|
+
startTime: Date.now(),
|
|
1260
|
+
retryCount: 0,
|
|
1261
|
+
metadata: {}
|
|
1262
|
+
};
|
|
1263
|
+
try {
|
|
1264
|
+
const url = `${this.properties.url}/${endpoint}`;
|
|
1265
|
+
const headers = {};
|
|
1266
|
+
if (body && method !== "GET") {
|
|
1267
|
+
headers["Content-Type"] = "application/json";
|
|
1268
|
+
}
|
|
1269
|
+
;
|
|
1270
|
+
const accessToken = this.getAccessToken();
|
|
1271
|
+
if (accessToken) {
|
|
1272
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1273
|
+
}
|
|
1274
|
+
;
|
|
1275
|
+
const newTimeStamp = timeStamp || (/* @__PURE__ */ new Date()).toISOString();
|
|
1276
|
+
headers["X-Origin-Request"] = this.properties.originRequest;
|
|
1277
|
+
headers["X-Timestamp"] = newTimeStamp;
|
|
1278
|
+
headers["X-Domain"] = this.properties.domain;
|
|
1279
|
+
headers["X-Device"] = this.properties.device;
|
|
1280
|
+
headers["X-Source"] = this.properties.source;
|
|
1281
|
+
let bodyString;
|
|
1282
|
+
if (body && method !== "GET") {
|
|
1283
|
+
bodyString = JSON.stringify(body);
|
|
1284
|
+
}
|
|
1285
|
+
;
|
|
1286
|
+
const requestConfig = {
|
|
1287
|
+
url,
|
|
1288
|
+
method,
|
|
1289
|
+
headers,
|
|
1290
|
+
body: bodyString,
|
|
1291
|
+
requiresAuth
|
|
1292
|
+
};
|
|
1293
|
+
const modifiedConfig = this.authInterceptor ? await this.authInterceptor.onRequest(requestConfig, context) : requestConfig;
|
|
1294
|
+
const requestInit = {
|
|
1295
|
+
method: modifiedConfig.method,
|
|
1296
|
+
headers: modifiedConfig.headers,
|
|
1297
|
+
mode: "cors",
|
|
1298
|
+
credentials: "omit"
|
|
1299
|
+
};
|
|
1300
|
+
if (modifiedConfig.body && modifiedConfig.method !== "GET") {
|
|
1301
|
+
requestInit.body = typeof modifiedConfig.body === "string" ? modifiedConfig.body : JSON.stringify(modifiedConfig.body);
|
|
1302
|
+
}
|
|
1303
|
+
;
|
|
1304
|
+
const response = await fetch(
|
|
1305
|
+
modifiedConfig.url,
|
|
1306
|
+
requestInit
|
|
1307
|
+
);
|
|
1308
|
+
const newAccessToken = response.headers.get("X-New-Access-Token");
|
|
1309
|
+
const newRefreshToken = response.headers.get("X-New-Refresh-Token");
|
|
1310
|
+
if (newAccessToken || newRefreshToken) {
|
|
1311
|
+
this.properties.onTokensRefreshed?.({
|
|
1312
|
+
accessToken: newAccessToken,
|
|
1313
|
+
refreshToken: newRefreshToken
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
;
|
|
1317
|
+
let result;
|
|
1318
|
+
try {
|
|
1319
|
+
result = await response.json();
|
|
1320
|
+
} catch (e) {
|
|
1321
|
+
return {
|
|
1322
|
+
success: false,
|
|
1323
|
+
message: `Error de servidor (${response.status}: ${response.statusText || "Formato de respuesta no reconocido"})`,
|
|
1324
|
+
data: null,
|
|
1325
|
+
responseTime: (/* @__PURE__ */ new Date()).toISOString()
|
|
1326
|
+
};
|
|
1327
|
+
}
|
|
1328
|
+
if (result && result.errors && typeof result.errors === "object") {
|
|
1329
|
+
const errorMessages = [];
|
|
1330
|
+
Object.values(result.errors).forEach((errors) => {
|
|
1331
|
+
if (Array.isArray(errors)) {
|
|
1332
|
+
errorMessages.push(...errors);
|
|
1333
|
+
} else if (typeof errors === "string") {
|
|
1334
|
+
errorMessages.push(errors);
|
|
1335
|
+
}
|
|
1336
|
+
});
|
|
1337
|
+
if (errorMessages.length > 0) {
|
|
1338
|
+
return {
|
|
1339
|
+
success: false,
|
|
1340
|
+
message: errorMessages.join(", "),
|
|
1341
|
+
data: result.data ?? null,
|
|
1342
|
+
responseTime: result.responseTime ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
return result;
|
|
1347
|
+
} catch (error) {
|
|
1348
|
+
return {
|
|
1349
|
+
success: false,
|
|
1350
|
+
message: error instanceof Error ? error.message : "Error inesperado durante la petici\xF3n al API.",
|
|
1351
|
+
data: null,
|
|
1352
|
+
responseTime: (/* @__PURE__ */ new Date()).toISOString()
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
;
|
|
1356
|
+
}
|
|
1357
|
+
//#region REQUEST METHODS
|
|
1358
|
+
async executeGET(endpoint, requiresAuth = false) {
|
|
1359
|
+
return this.apiExecute({
|
|
1360
|
+
endpoint,
|
|
1361
|
+
method: "GET",
|
|
1362
|
+
requiresAuth
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
async executePOST(endpoint, body, requiresAuth = true) {
|
|
1366
|
+
return this.apiExecute({
|
|
1367
|
+
endpoint,
|
|
1368
|
+
method: "POST",
|
|
1369
|
+
body,
|
|
1370
|
+
requiresAuth
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
async executePATCH(endpoint, body, requiresAuth = true) {
|
|
1374
|
+
return this.apiExecute({
|
|
1375
|
+
endpoint,
|
|
1376
|
+
method: "PATCH",
|
|
1377
|
+
body,
|
|
1378
|
+
requiresAuth
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
async executeDELETE(endpoint, body, requiresAuth = true) {
|
|
1382
|
+
return this.apiExecute({
|
|
1383
|
+
endpoint,
|
|
1384
|
+
method: "DELETE",
|
|
1385
|
+
body,
|
|
1386
|
+
requiresAuth
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
async executePUT(endpoint, body, requiresAuth = true) {
|
|
1390
|
+
return this.apiExecute({
|
|
1391
|
+
endpoint,
|
|
1392
|
+
method: "PUT",
|
|
1393
|
+
body,
|
|
1394
|
+
requiresAuth
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
async executePublicRequest(endpoint, method, body, timestamp) {
|
|
1398
|
+
return this.apiExecute({
|
|
1399
|
+
endpoint,
|
|
1400
|
+
method,
|
|
1401
|
+
body,
|
|
1402
|
+
requiresAuth: false,
|
|
1403
|
+
timeStamp: timestamp
|
|
1404
|
+
});
|
|
1534
1405
|
}
|
|
1406
|
+
//#endregion
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
// src/core/CryptoService.ts
|
|
1410
|
+
import * as CryptoJS from "crypto-js";
|
|
1411
|
+
var CryptoService = class {
|
|
1535
1412
|
/**
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1413
|
+
* Genera un hash SHA256 de un texto (útil para fingerprints)
|
|
1414
|
+
*
|
|
1415
|
+
* @param text - Texto a hashear
|
|
1416
|
+
* @returns Hash en formato hexadecimal
|
|
1417
|
+
*/
|
|
1418
|
+
sha256(text) {
|
|
1419
|
+
return CryptoJS.SHA256(text).toString(CryptoJS.enc.Hex);
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* Genera un identificador único basado en timestamp y random
|
|
1423
|
+
* (útil para request IDs)
|
|
1424
|
+
*
|
|
1425
|
+
* @returns ID único
|
|
1426
|
+
*/
|
|
1427
|
+
generateUniqueId() {
|
|
1428
|
+
const timestamp = Date.now().toString(36);
|
|
1429
|
+
const randomPart = Math.random().toString(36).substring(2, 15);
|
|
1430
|
+
return `${timestamp}-${randomPart}`;
|
|
1431
|
+
}
|
|
1432
|
+
};
|
|
1433
|
+
|
|
1434
|
+
// src/core/TokenManager.ts
|
|
1435
|
+
var TokenManager = class {
|
|
1436
|
+
constructor(onTokensChanged, onSessionExpiring, onSessionExpired, onSessionRecovery, autoRefreshThresholdMinutes) {
|
|
1437
|
+
this.tokens = null;
|
|
1438
|
+
this.sessionCheckInterval = null;
|
|
1439
|
+
this.autoRefreshTimeout = null;
|
|
1440
|
+
this.hasNotifiedExpiring = false;
|
|
1441
|
+
this.autoRefreshThresholdMinutes = 5;
|
|
1442
|
+
this.onTokensChanged = onTokensChanged;
|
|
1443
|
+
this.onSessionExpiring = onSessionExpiring;
|
|
1444
|
+
this.onSessionExpired = onSessionExpired;
|
|
1445
|
+
this.onSessionRecovery = onSessionRecovery;
|
|
1446
|
+
this.autoRefreshThresholdMinutes = autoRefreshThresholdMinutes ?? 5;
|
|
1541
1447
|
}
|
|
1542
|
-
// #endregion
|
|
1543
|
-
// #region User Types
|
|
1544
1448
|
/**
|
|
1545
|
-
*
|
|
1546
|
-
* @param filter - Filtros opcionales para la búsqueda
|
|
1449
|
+
* Guarda los tokens de autenticación y dispara el callback onTokensChanged.
|
|
1547
1450
|
*/
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1451
|
+
setTokens(tokens) {
|
|
1452
|
+
this.tokens = tokens;
|
|
1453
|
+
this.hasNotifiedExpiring = false;
|
|
1454
|
+
this.onTokensChanged?.(this.tokens);
|
|
1455
|
+
if (!tokens.rememberMe) {
|
|
1456
|
+
this.startExpirationCheck();
|
|
1457
|
+
this.stopAutoRefreshTimer();
|
|
1458
|
+
} else {
|
|
1459
|
+
this.stopExpirationCheck();
|
|
1460
|
+
this.scheduleAutoRefresh();
|
|
1461
|
+
}
|
|
1462
|
+
;
|
|
1551
1463
|
}
|
|
1552
1464
|
/**
|
|
1553
|
-
*
|
|
1465
|
+
* Guarda los tokens sin disparar el callback onTokensChanged.
|
|
1466
|
+
* Usar para inyectar tokens desde storage externo (cookies/localStorage).
|
|
1554
1467
|
*/
|
|
1555
|
-
|
|
1556
|
-
|
|
1468
|
+
setTokensSilent(tokens) {
|
|
1469
|
+
this.tokens = tokens;
|
|
1470
|
+
this.hasNotifiedExpiring = false;
|
|
1471
|
+
if (!tokens.rememberMe) {
|
|
1472
|
+
this.startExpirationCheck();
|
|
1473
|
+
this.stopAutoRefreshTimer();
|
|
1474
|
+
} else {
|
|
1475
|
+
this.stopExpirationCheck();
|
|
1476
|
+
this.scheduleAutoRefresh();
|
|
1477
|
+
}
|
|
1478
|
+
;
|
|
1557
1479
|
}
|
|
1558
1480
|
/**
|
|
1559
|
-
* Obtiene
|
|
1560
|
-
* @param id - ID del tipo de usuario
|
|
1481
|
+
* Obtiene los tokens de autenticación almacenados.
|
|
1561
1482
|
*/
|
|
1562
|
-
|
|
1563
|
-
return this.
|
|
1483
|
+
getTokens() {
|
|
1484
|
+
return this.tokens;
|
|
1564
1485
|
}
|
|
1565
1486
|
/**
|
|
1566
|
-
*
|
|
1567
|
-
* @param request - Datos del tipo de usuario a crear
|
|
1487
|
+
* Limpia los tokens de autenticación almacenados y dispara el callback onTokensChanged.
|
|
1568
1488
|
*/
|
|
1569
|
-
|
|
1570
|
-
|
|
1489
|
+
clearTokens() {
|
|
1490
|
+
this.stopExpirationCheck();
|
|
1491
|
+
this.stopAutoRefreshTimer();
|
|
1492
|
+
this.tokens = null;
|
|
1493
|
+
this.onTokensChanged?.(this.tokens);
|
|
1571
1494
|
}
|
|
1572
1495
|
/**
|
|
1573
|
-
*
|
|
1574
|
-
* @param id - ID del tipo de usuario a actualizar
|
|
1575
|
-
* @param request - Nuevos datos del tipo de usuario
|
|
1496
|
+
* Valida si existen tokens y si el access token no ha expirado.
|
|
1576
1497
|
*/
|
|
1577
|
-
|
|
1578
|
-
|
|
1498
|
+
hasValidTokens() {
|
|
1499
|
+
if (!this.tokens) return false;
|
|
1500
|
+
return Date.now() < this.tokens.expiresAt;
|
|
1579
1501
|
}
|
|
1580
1502
|
/**
|
|
1581
|
-
*
|
|
1582
|
-
* @param id - ID del tipo de usuario a eliminar
|
|
1503
|
+
* Valida si el access token expirará dentro del umbral especificado (en minutos).
|
|
1583
1504
|
*/
|
|
1584
|
-
|
|
1585
|
-
|
|
1505
|
+
isTokenExpiringSoon(thresholdMinutes) {
|
|
1506
|
+
if (!this.tokens) return false;
|
|
1507
|
+
const thresholdMs = thresholdMinutes * 60 * 1e3;
|
|
1508
|
+
const timeLeft = this.tokens.expiresAt - Date.now();
|
|
1509
|
+
return timeLeft > 0 && timeLeft <= thresholdMs;
|
|
1586
1510
|
}
|
|
1587
|
-
// #endregion
|
|
1588
|
-
// #region Roles
|
|
1589
1511
|
/**
|
|
1590
|
-
* Obtiene
|
|
1591
|
-
* @param filter - Filtros opcionales para la búsqueda
|
|
1512
|
+
* Obtiene el tiempo restante hasta la expiración del access token en milisegundos.
|
|
1592
1513
|
*/
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
return this.
|
|
1514
|
+
getTimeUntilExpiry() {
|
|
1515
|
+
if (!this.tokens) return null;
|
|
1516
|
+
return Math.max(0, this.tokens.expiresAt - Date.now());
|
|
1596
1517
|
}
|
|
1597
1518
|
/**
|
|
1598
|
-
* Obtiene el
|
|
1519
|
+
* Obtiene el access token almacenado.
|
|
1599
1520
|
*/
|
|
1600
|
-
|
|
1601
|
-
return this.
|
|
1521
|
+
getAccessToken() {
|
|
1522
|
+
return this.tokens ? this.tokens.accessToken : null;
|
|
1602
1523
|
}
|
|
1603
1524
|
/**
|
|
1604
|
-
* Obtiene
|
|
1605
|
-
* @param id - ID del rol
|
|
1525
|
+
* Obtiene el refresh token almacenado.
|
|
1606
1526
|
*/
|
|
1607
|
-
|
|
1608
|
-
return this.
|
|
1527
|
+
getRefreshToken() {
|
|
1528
|
+
return this.tokens ? this.tokens.refreshToken : null;
|
|
1609
1529
|
}
|
|
1610
1530
|
/**
|
|
1611
|
-
*
|
|
1612
|
-
*
|
|
1531
|
+
* Verifica si el auto-refresh debe ejecutarse
|
|
1532
|
+
* Solo si el usuario activó "rememberMe" durante el login
|
|
1613
1533
|
*/
|
|
1614
|
-
|
|
1615
|
-
|
|
1534
|
+
shouldAutoRefresh() {
|
|
1535
|
+
if (!this.tokens) return false;
|
|
1536
|
+
return this.tokens.rememberMe === true;
|
|
1616
1537
|
}
|
|
1617
1538
|
/**
|
|
1618
|
-
*
|
|
1619
|
-
*
|
|
1539
|
+
* Inicia el monitoreo de expiración para sesiones sin rememberMe
|
|
1540
|
+
* - Notifica cuando quedan 5 minutos (onSessionExpiring)
|
|
1620
1541
|
*/
|
|
1621
|
-
|
|
1622
|
-
|
|
1542
|
+
startExpirationCheck() {
|
|
1543
|
+
this.stopExpirationCheck();
|
|
1544
|
+
this.sessionCheckInterval = setInterval(async () => {
|
|
1545
|
+
if (!this.tokens) {
|
|
1546
|
+
this.stopExpirationCheck();
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
;
|
|
1550
|
+
const timeLeft = this.getTimeUntilExpiry();
|
|
1551
|
+
if (timeLeft === null) return;
|
|
1552
|
+
const minutesLeft = Math.floor(timeLeft / (60 * 1e3));
|
|
1553
|
+
if (minutesLeft <= 5 && minutesLeft > 1 && !this.hasNotifiedExpiring) {
|
|
1554
|
+
this.hasNotifiedExpiring = true;
|
|
1555
|
+
this.onSessionExpiring?.(minutesLeft);
|
|
1556
|
+
}
|
|
1557
|
+
;
|
|
1558
|
+
if (minutesLeft <= 1) {
|
|
1559
|
+
this.stopExpirationCheck();
|
|
1560
|
+
if (this.onSessionRecovery) {
|
|
1561
|
+
try {
|
|
1562
|
+
const recovered = await this.onSessionRecovery();
|
|
1563
|
+
if (recovered) return;
|
|
1564
|
+
} catch (error) {
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
if (this.onSessionExpired) {
|
|
1568
|
+
await this.onSessionExpired();
|
|
1569
|
+
}
|
|
1570
|
+
;
|
|
1571
|
+
}
|
|
1572
|
+
;
|
|
1573
|
+
}, 6e4);
|
|
1623
1574
|
}
|
|
1624
1575
|
/**
|
|
1625
|
-
*
|
|
1626
|
-
*
|
|
1627
|
-
* @param request - Nuevos datos del rol
|
|
1576
|
+
* Programa un auto-refresh proactivo para sesiones con rememberMe.
|
|
1577
|
+
* Se ejecuta X minutos antes de que expire el token
|
|
1628
1578
|
*/
|
|
1629
|
-
|
|
1630
|
-
|
|
1579
|
+
scheduleAutoRefresh() {
|
|
1580
|
+
this.stopAutoRefreshTimer();
|
|
1581
|
+
if (!this.tokens || !this.tokens.rememberMe) return;
|
|
1582
|
+
const timeLeft = this.getTimeUntilExpiry();
|
|
1583
|
+
if (timeLeft === null || timeLeft <= 0) return;
|
|
1584
|
+
const thresholdMs = this.autoRefreshThresholdMinutes * 60 * 1e3;
|
|
1585
|
+
const delay = Math.max(0, timeLeft - thresholdMs);
|
|
1586
|
+
this.autoRefreshTimeout = setTimeout(async () => {
|
|
1587
|
+
if (!this.tokens || !this.tokens.rememberMe) return;
|
|
1588
|
+
if (this.onSessionRecovery) {
|
|
1589
|
+
try {
|
|
1590
|
+
const recovered = await this.onSessionRecovery();
|
|
1591
|
+
if (recovered) return;
|
|
1592
|
+
} catch (error) {
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
if (this.onSessionExpired) {
|
|
1596
|
+
await this.onSessionExpired();
|
|
1597
|
+
}
|
|
1598
|
+
}, delay);
|
|
1631
1599
|
}
|
|
1632
1600
|
/**
|
|
1633
|
-
*
|
|
1634
|
-
* @param id - ID del rol
|
|
1601
|
+
* Detiene el monitoreo de expiración
|
|
1635
1602
|
*/
|
|
1636
|
-
|
|
1637
|
-
|
|
1603
|
+
stopExpirationCheck() {
|
|
1604
|
+
if (this.sessionCheckInterval) {
|
|
1605
|
+
clearInterval(this.sessionCheckInterval);
|
|
1606
|
+
this.sessionCheckInterval = null;
|
|
1607
|
+
}
|
|
1608
|
+
;
|
|
1638
1609
|
}
|
|
1639
1610
|
/**
|
|
1640
|
-
*
|
|
1641
|
-
* @param id - ID del rol a eliminar
|
|
1611
|
+
* Detiene el timer de auto-refresh proactivo
|
|
1642
1612
|
*/
|
|
1643
|
-
|
|
1644
|
-
|
|
1613
|
+
stopAutoRefreshTimer() {
|
|
1614
|
+
if (this.autoRefreshTimeout) {
|
|
1615
|
+
clearTimeout(this.autoRefreshTimeout);
|
|
1616
|
+
this.autoRefreshTimeout = null;
|
|
1617
|
+
}
|
|
1618
|
+
;
|
|
1619
|
+
}
|
|
1620
|
+
};
|
|
1621
|
+
|
|
1622
|
+
// src/core/interceptors/AuthInterceptor.ts
|
|
1623
|
+
var AuthInterceptor = class {
|
|
1624
|
+
constructor(config) {
|
|
1625
|
+
this.name = "AuthInterceptor";
|
|
1626
|
+
this.refreshPromise = null;
|
|
1627
|
+
this.isRefreshing = false;
|
|
1628
|
+
this.config = {
|
|
1629
|
+
enabled: config.enabled ?? true,
|
|
1630
|
+
thresholdMinutes: config.thresholdMinutes ?? 5,
|
|
1631
|
+
isTokenExpiringSoon: config.isTokenExpiringSoon,
|
|
1632
|
+
hasValidTokens: config.hasValidTokens,
|
|
1633
|
+
shouldAutoRefresh: config.shouldAutoRefresh,
|
|
1634
|
+
refreshSession: config.refreshSession
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
async onRequest(config, context) {
|
|
1638
|
+
if (!config.requiresAuth || !this.config.enabled) {
|
|
1639
|
+
return config;
|
|
1640
|
+
}
|
|
1641
|
+
;
|
|
1642
|
+
if (!this.config.hasValidTokens()) {
|
|
1643
|
+
return config;
|
|
1644
|
+
}
|
|
1645
|
+
;
|
|
1646
|
+
if (!this.config.shouldAutoRefresh()) {
|
|
1647
|
+
return config;
|
|
1648
|
+
}
|
|
1649
|
+
;
|
|
1650
|
+
if (this.config.isTokenExpiringSoon()) {
|
|
1651
|
+
try {
|
|
1652
|
+
if (this.isRefreshing && this.refreshPromise) {
|
|
1653
|
+
await this.refreshPromise;
|
|
1654
|
+
} else {
|
|
1655
|
+
this.isRefreshing = true;
|
|
1656
|
+
this.refreshPromise = this.config.refreshSession();
|
|
1657
|
+
await this.refreshPromise;
|
|
1658
|
+
this.isRefreshing = false;
|
|
1659
|
+
this.refreshPromise = null;
|
|
1660
|
+
}
|
|
1661
|
+
;
|
|
1662
|
+
} catch (error) {
|
|
1663
|
+
this.isRefreshing = false;
|
|
1664
|
+
this.refreshPromise = null;
|
|
1665
|
+
}
|
|
1666
|
+
;
|
|
1667
|
+
}
|
|
1668
|
+
;
|
|
1669
|
+
return config;
|
|
1670
|
+
}
|
|
1671
|
+
updateConfig(config) {
|
|
1672
|
+
this.config = {
|
|
1673
|
+
...this.config,
|
|
1674
|
+
...config
|
|
1675
|
+
};
|
|
1676
|
+
}
|
|
1677
|
+
reset() {
|
|
1678
|
+
this.isRefreshing = false;
|
|
1679
|
+
this.refreshPromise = null;
|
|
1645
1680
|
}
|
|
1646
|
-
// #endregion
|
|
1647
1681
|
};
|
|
1648
1682
|
|
|
1649
1683
|
// src/FalconHUBSDK.ts
|
|
@@ -1790,6 +1824,8 @@ export {
|
|
|
1790
1824
|
API,
|
|
1791
1825
|
AuthInterceptor,
|
|
1792
1826
|
AuthService,
|
|
1827
|
+
BLANKS_BULK_COLUMN_MAP,
|
|
1828
|
+
BLANKS_BULK_SPANISH_HEADERS,
|
|
1793
1829
|
CatalogService,
|
|
1794
1830
|
CryptoService,
|
|
1795
1831
|
FalconHUBSDK,
|