falconhub-apilibrary 1.3.1-dev.99 → 1.4.0-dev.111
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 +309 -79
- package/dist/index.mjs +185 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -356,9 +356,6 @@ interface Gender {
|
|
|
356
356
|
genderId: number;
|
|
357
357
|
gender: string;
|
|
358
358
|
key: string;
|
|
359
|
-
createdAt: string;
|
|
360
|
-
updatedAt: string | null;
|
|
361
|
-
deleted: boolean;
|
|
362
359
|
}
|
|
363
360
|
/**
|
|
364
361
|
* Request para crear o actualizar un género.
|
|
@@ -376,6 +373,10 @@ interface GendersFilter {
|
|
|
376
373
|
/** Filtro por nombre del género (búsqueda parcial) */
|
|
377
374
|
Gender?: string;
|
|
378
375
|
}
|
|
376
|
+
interface GenderUserProfile {
|
|
377
|
+
genderId: number;
|
|
378
|
+
gender: string;
|
|
379
|
+
}
|
|
379
380
|
|
|
380
381
|
/**
|
|
381
382
|
* Interfaz que representa un código de área del catálogo.
|
|
@@ -386,9 +387,6 @@ interface AreaCode {
|
|
|
386
387
|
iso: string;
|
|
387
388
|
countryName: string;
|
|
388
389
|
isActive: boolean;
|
|
389
|
-
createdAt: string;
|
|
390
|
-
updatedAt: string | null;
|
|
391
|
-
deleted: boolean;
|
|
392
390
|
}
|
|
393
391
|
/**
|
|
394
392
|
* Request para crear o actualizar un código de área.
|
|
@@ -414,6 +412,11 @@ interface AreaCodesFilter {
|
|
|
414
412
|
/** Filtro por estado activo/inactivo */
|
|
415
413
|
IsActive?: boolean;
|
|
416
414
|
}
|
|
415
|
+
interface AreaCodeUserProfile {
|
|
416
|
+
areaCodeId: number;
|
|
417
|
+
countryCode: string;
|
|
418
|
+
country: string;
|
|
419
|
+
}
|
|
417
420
|
|
|
418
421
|
/**
|
|
419
422
|
* Utilidad para construir query params a partir de objetos de filtro.
|
|
@@ -617,13 +620,11 @@ interface Location {
|
|
|
617
620
|
areaCodeId: number;
|
|
618
621
|
contactPhone: string;
|
|
619
622
|
contactEmail: string;
|
|
623
|
+
isActive: boolean;
|
|
624
|
+
isPhysical: boolean;
|
|
625
|
+
parentLocationId: number | null;
|
|
620
626
|
url: string;
|
|
621
627
|
apiKey: string;
|
|
622
|
-
parentLocationId: number | null;
|
|
623
|
-
isPhysical: boolean;
|
|
624
|
-
isActive: boolean;
|
|
625
|
-
createdAt: string;
|
|
626
|
-
updatedAt: string | null;
|
|
627
628
|
}
|
|
628
629
|
interface LocationsRequest {
|
|
629
630
|
locationName: string;
|
|
@@ -661,8 +662,8 @@ interface InventoryStatus {
|
|
|
661
662
|
description: string;
|
|
662
663
|
}
|
|
663
664
|
interface InventoryStatusRequest {
|
|
664
|
-
key?: string;
|
|
665
665
|
inventoryStatus: string;
|
|
666
|
+
key?: string;
|
|
666
667
|
description: string;
|
|
667
668
|
}
|
|
668
669
|
interface InventoryStatusesFilter {
|
|
@@ -678,14 +679,14 @@ interface Packing {
|
|
|
678
679
|
packingId: number;
|
|
679
680
|
packing: string;
|
|
680
681
|
key: string;
|
|
682
|
+
materialId: number;
|
|
681
683
|
length: number;
|
|
682
684
|
width: number;
|
|
683
685
|
height: number;
|
|
684
686
|
weightLimit: number | null;
|
|
685
687
|
cost: number;
|
|
686
|
-
isActive: boolean;
|
|
687
|
-
materialId: number;
|
|
688
688
|
providerId: number;
|
|
689
|
+
isActive: boolean;
|
|
689
690
|
}
|
|
690
691
|
/**
|
|
691
692
|
* Request para crear o actualizar un empaque.
|
|
@@ -748,7 +749,7 @@ interface MaterialsFilter {
|
|
|
748
749
|
/**
|
|
749
750
|
* Interfaz que representa un proveedor del inventario.
|
|
750
751
|
*/
|
|
751
|
-
interface
|
|
752
|
+
interface Provider {
|
|
752
753
|
providerId: number;
|
|
753
754
|
provider: string;
|
|
754
755
|
contactName: string;
|
|
@@ -760,7 +761,7 @@ interface InventoryProvider {
|
|
|
760
761
|
/**
|
|
761
762
|
* Request para crear o actualizar un proveedor.
|
|
762
763
|
*/
|
|
763
|
-
interface
|
|
764
|
+
interface ProviderRequest {
|
|
764
765
|
provider: string;
|
|
765
766
|
contactName: string;
|
|
766
767
|
areaCodeId: number;
|
|
@@ -771,7 +772,7 @@ interface InventoryProviderRequest {
|
|
|
771
772
|
/**
|
|
772
773
|
* Filtros disponibles para buscar proveedores.
|
|
773
774
|
*/
|
|
774
|
-
interface
|
|
775
|
+
interface ProvidersFilter {
|
|
775
776
|
Search?: string;
|
|
776
777
|
Provider?: string;
|
|
777
778
|
IsActive?: boolean;
|
|
@@ -918,7 +919,7 @@ declare class InventoryService {
|
|
|
918
919
|
* Obtiene todos los proveedores con filtros opcionales.
|
|
919
920
|
* @param filter - Filtros opcionales para la búsqueda
|
|
920
921
|
*/
|
|
921
|
-
getProviders(filter?:
|
|
922
|
+
getProviders(filter?: ProvidersFilter): Promise<ResponseModel<Provider[]>>;
|
|
922
923
|
/**
|
|
923
924
|
* Obtiene el modelo de filtros disponibles para proveedores.
|
|
924
925
|
*/
|
|
@@ -927,23 +928,23 @@ declare class InventoryService {
|
|
|
927
928
|
* Obtiene un proveedor por su ID.
|
|
928
929
|
* @param id - ID del proveedor
|
|
929
930
|
*/
|
|
930
|
-
getProviderById(id: number): Promise<ResponseModel<
|
|
931
|
+
getProviderById(id: number): Promise<ResponseModel<Provider>>;
|
|
931
932
|
/**
|
|
932
933
|
* Crea un nuevo proveedor.
|
|
933
934
|
* @param request - Datos del proveedor a crear
|
|
934
935
|
*/
|
|
935
|
-
createProvider(request:
|
|
936
|
+
createProvider(request: ProviderRequest): Promise<ResponseModel<Provider>>;
|
|
936
937
|
/**
|
|
937
938
|
* Actualiza un proveedor existente.
|
|
938
939
|
* @param id - ID del proveedor a actualizar
|
|
939
940
|
* @param request - Nuevos datos del proveedor
|
|
940
941
|
*/
|
|
941
|
-
updateProvider(id: number, request:
|
|
942
|
+
updateProvider(id: number, request: ProviderRequest): Promise<ResponseModel<Provider>>;
|
|
942
943
|
/**
|
|
943
944
|
* Activa o desactiva un proveedor.
|
|
944
945
|
* @param id - ID del proveedor
|
|
945
946
|
*/
|
|
946
|
-
toggleProviderStatus(id: number): Promise<ResponseModel<
|
|
947
|
+
toggleProviderStatus(id: number): Promise<ResponseModel<Provider>>;
|
|
947
948
|
/**
|
|
948
949
|
* Elimina un proveedor.
|
|
949
950
|
* @param id - ID del proveedor a eliminar
|
|
@@ -959,9 +960,6 @@ interface Module {
|
|
|
959
960
|
module: string;
|
|
960
961
|
description: string;
|
|
961
962
|
isActive: boolean;
|
|
962
|
-
createdAt: string;
|
|
963
|
-
updatedAt: string | null;
|
|
964
|
-
deleted: boolean;
|
|
965
963
|
}
|
|
966
964
|
/**
|
|
967
965
|
* Request para crear o actualizar un módulo.
|
|
@@ -1001,9 +999,6 @@ interface Endpoint {
|
|
|
1001
999
|
requiresHeader: boolean;
|
|
1002
1000
|
allowedOrigins: string;
|
|
1003
1001
|
isActive: boolean;
|
|
1004
|
-
createdAt: string;
|
|
1005
|
-
updatedAt: string | null;
|
|
1006
|
-
deleted: boolean;
|
|
1007
1002
|
}
|
|
1008
1003
|
/**
|
|
1009
1004
|
* Request para crear o actualizar un endpoint.
|
|
@@ -1062,9 +1057,6 @@ interface UIRoute {
|
|
|
1062
1057
|
path: string;
|
|
1063
1058
|
description: string;
|
|
1064
1059
|
isActive: boolean;
|
|
1065
|
-
createdAt: string;
|
|
1066
|
-
updatedAt: string | null;
|
|
1067
|
-
deleted: boolean;
|
|
1068
1060
|
}
|
|
1069
1061
|
/**
|
|
1070
1062
|
* Request para crear o actualizar una ruta de UI.
|
|
@@ -1227,7 +1219,6 @@ interface AdminUser {
|
|
|
1227
1219
|
isActive: boolean;
|
|
1228
1220
|
createdAt: string;
|
|
1229
1221
|
updatedAt: string | null;
|
|
1230
|
-
deleted: boolean;
|
|
1231
1222
|
}
|
|
1232
1223
|
interface AdminAuthentication {
|
|
1233
1224
|
userAuthenticationId: number;
|
|
@@ -1347,9 +1338,12 @@ interface RolesFilter {
|
|
|
1347
1338
|
/** Filtro por estado activo/inactivo */
|
|
1348
1339
|
IsActive?: boolean;
|
|
1349
1340
|
}
|
|
1341
|
+
interface RoleUserProfile {
|
|
1342
|
+
roleId: number;
|
|
1343
|
+
role: string;
|
|
1344
|
+
}
|
|
1350
1345
|
|
|
1351
1346
|
interface UserBasicResponse {
|
|
1352
|
-
userId: number;
|
|
1353
1347
|
username: string;
|
|
1354
1348
|
firstName: string;
|
|
1355
1349
|
lastName: string;
|
|
@@ -1382,29 +1376,42 @@ interface UserDataUpdateRequest {
|
|
|
1382
1376
|
profilePhoto: string;
|
|
1383
1377
|
}
|
|
1384
1378
|
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1379
|
+
/**
|
|
1380
|
+
* Interfaz que representa un tipo de usuario.
|
|
1381
|
+
*/
|
|
1382
|
+
interface UserType {
|
|
1383
|
+
userTypeId: number;
|
|
1384
|
+
userType: string;
|
|
1385
|
+
key?: string;
|
|
1386
|
+
description?: string;
|
|
1389
1387
|
}
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1388
|
+
/**
|
|
1389
|
+
* Request para crear o actualizar un tipo de usuario.
|
|
1390
|
+
*/
|
|
1391
|
+
interface UserTypeRequest {
|
|
1392
|
+
userType: string;
|
|
1393
|
+
key?: string;
|
|
1394
|
+
description?: string;
|
|
1394
1395
|
}
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1396
|
+
/**
|
|
1397
|
+
* Filtros disponibles para buscar tipos de usuario.
|
|
1398
|
+
*/
|
|
1399
|
+
interface UserTypesFilter {
|
|
1400
|
+
/** Búsqueda general */
|
|
1401
|
+
Search?: string;
|
|
1402
|
+
/** Filtro por tipo de usuario (búsqueda parcial) */
|
|
1403
|
+
UserType?: string;
|
|
1404
|
+
/** Filtro por key (búsqueda parcial) */
|
|
1405
|
+
Key?: string;
|
|
1406
|
+
/** Filtro por descripción (búsqueda parcial) */
|
|
1407
|
+
Description?: string;
|
|
1399
1408
|
}
|
|
1400
|
-
|
|
1401
1409
|
interface UserTypeUserProfile {
|
|
1402
1410
|
userTypeId: number;
|
|
1403
1411
|
userType: string;
|
|
1404
1412
|
}
|
|
1405
1413
|
|
|
1406
1414
|
interface UserProfileResponse {
|
|
1407
|
-
userId: number;
|
|
1408
1415
|
username: string;
|
|
1409
1416
|
firstName: string;
|
|
1410
1417
|
lastName: string;
|
|
@@ -1429,37 +1436,6 @@ interface UserProfileResponse {
|
|
|
1429
1436
|
updatedAt: Date;
|
|
1430
1437
|
}
|
|
1431
1438
|
|
|
1432
|
-
/**
|
|
1433
|
-
* Interfaz que representa un tipo de usuario.
|
|
1434
|
-
*/
|
|
1435
|
-
interface UserType {
|
|
1436
|
-
userTypeId: number;
|
|
1437
|
-
userType: string;
|
|
1438
|
-
key?: string;
|
|
1439
|
-
description?: string;
|
|
1440
|
-
}
|
|
1441
|
-
/**
|
|
1442
|
-
* Request para crear o actualizar un tipo de usuario.
|
|
1443
|
-
*/
|
|
1444
|
-
interface UserTypeRequest {
|
|
1445
|
-
userType: string;
|
|
1446
|
-
key?: string;
|
|
1447
|
-
description?: string;
|
|
1448
|
-
}
|
|
1449
|
-
/**
|
|
1450
|
-
* Filtros disponibles para buscar tipos de usuario.
|
|
1451
|
-
*/
|
|
1452
|
-
interface UserTypesFilter {
|
|
1453
|
-
/** Búsqueda general */
|
|
1454
|
-
Search?: string;
|
|
1455
|
-
/** Filtro por tipo de usuario (búsqueda parcial) */
|
|
1456
|
-
UserType?: string;
|
|
1457
|
-
/** Filtro por key (búsqueda parcial) */
|
|
1458
|
-
Key?: string;
|
|
1459
|
-
/** Filtro por descripción (búsqueda parcial) */
|
|
1460
|
-
Description?: string;
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
1439
|
declare class UserService {
|
|
1464
1440
|
private api;
|
|
1465
1441
|
private readonly BASE_PATH;
|
|
@@ -1528,6 +1504,16 @@ declare class UserService {
|
|
|
1528
1504
|
* @param request - Nuevos datos de autenticación
|
|
1529
1505
|
*/
|
|
1530
1506
|
updateAdminAuthentication(id: number, request: UserAuthUpdateRequest): Promise<ResponseModel<AdminAuthentication>>;
|
|
1507
|
+
/**
|
|
1508
|
+
* Elimina un administrador.
|
|
1509
|
+
* @param id - ID del administrador
|
|
1510
|
+
*/
|
|
1511
|
+
deleteAdmin(id: number): Promise<ResponseModel>;
|
|
1512
|
+
/**
|
|
1513
|
+
* Reenvía el correo de confirmación al usuario.
|
|
1514
|
+
* @param id - ID del usuario
|
|
1515
|
+
*/
|
|
1516
|
+
resendEmailConfirmation(id: number): Promise<ResponseModel>;
|
|
1531
1517
|
/**
|
|
1532
1518
|
* Obtiene todos los tipos de usuario con filtros opcionales.
|
|
1533
1519
|
* @param filter - Filtros opcionales para la búsqueda
|
|
@@ -1639,6 +1625,250 @@ declare class FalconHUBSDK {
|
|
|
1639
1625
|
getTimeUntilExpiry(): number | null;
|
|
1640
1626
|
}
|
|
1641
1627
|
|
|
1628
|
+
/**
|
|
1629
|
+
* Interfaz que representa un color.
|
|
1630
|
+
*/
|
|
1631
|
+
interface Color {
|
|
1632
|
+
colorId: number;
|
|
1633
|
+
color: string;
|
|
1634
|
+
key: string;
|
|
1635
|
+
createdAt: string;
|
|
1636
|
+
updatedAt?: string;
|
|
1637
|
+
deleted: boolean;
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* Request para crear o actualizar un color.
|
|
1641
|
+
*/
|
|
1642
|
+
interface ColorRequest {
|
|
1643
|
+
color: string;
|
|
1644
|
+
key: string;
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Filtros disponibles para buscar colores.
|
|
1648
|
+
*/
|
|
1649
|
+
interface ColorsFilter {
|
|
1650
|
+
Search?: string;
|
|
1651
|
+
Color?: string;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
/**
|
|
1655
|
+
* Interfaz que representa un grupo de tallas.
|
|
1656
|
+
*/
|
|
1657
|
+
interface SizeGroup {
|
|
1658
|
+
sizeGroupId: number;
|
|
1659
|
+
sizeGroup: string;
|
|
1660
|
+
key: string;
|
|
1661
|
+
description: string;
|
|
1662
|
+
createdAt: string;
|
|
1663
|
+
updatedAt?: string;
|
|
1664
|
+
deleted: boolean;
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Request para crear o actualizar un grupo de tallas.
|
|
1668
|
+
*/
|
|
1669
|
+
interface SizeGroupRequest {
|
|
1670
|
+
sizeGroup: string;
|
|
1671
|
+
key: string;
|
|
1672
|
+
description: string;
|
|
1673
|
+
}
|
|
1674
|
+
/**
|
|
1675
|
+
* Filtros disponibles para buscar grupos de tallas.
|
|
1676
|
+
*/
|
|
1677
|
+
interface SizeGroupsFilter {
|
|
1678
|
+
Search?: string;
|
|
1679
|
+
SizeGroup?: string;
|
|
1680
|
+
Description?: string;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* Interfaz que representa una talla.
|
|
1685
|
+
*/
|
|
1686
|
+
interface Size {
|
|
1687
|
+
sizeId: number;
|
|
1688
|
+
size: string;
|
|
1689
|
+
iso: string;
|
|
1690
|
+
width: string;
|
|
1691
|
+
length: string;
|
|
1692
|
+
sizeGroupId: number;
|
|
1693
|
+
createdAt: string;
|
|
1694
|
+
updatedAt?: string;
|
|
1695
|
+
deleted: boolean;
|
|
1696
|
+
sizeGroup?: SizeGroup;
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Request para crear o actualizar una talla.
|
|
1700
|
+
*/
|
|
1701
|
+
interface SizeRequest {
|
|
1702
|
+
size: string;
|
|
1703
|
+
iso: string;
|
|
1704
|
+
width: string;
|
|
1705
|
+
length: string;
|
|
1706
|
+
sizeGroupId: number;
|
|
1707
|
+
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Filtros disponibles para buscar tallas.
|
|
1710
|
+
*/
|
|
1711
|
+
interface SizesFilter {
|
|
1712
|
+
Search?: string;
|
|
1713
|
+
Size?: string;
|
|
1714
|
+
SizeGroupId?: number;
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
/**
|
|
1718
|
+
* Interfaz que representa un Blank en el catálogo de productos.
|
|
1719
|
+
*/
|
|
1720
|
+
interface Blank {
|
|
1721
|
+
blankId: number;
|
|
1722
|
+
blank: string;
|
|
1723
|
+
sku: string;
|
|
1724
|
+
cost: number;
|
|
1725
|
+
isActive: boolean;
|
|
1726
|
+
colorId: number;
|
|
1727
|
+
providerId: number;
|
|
1728
|
+
materialId: number;
|
|
1729
|
+
sizeId: number;
|
|
1730
|
+
createdAt: string;
|
|
1731
|
+
updatedAt?: string;
|
|
1732
|
+
deleted: boolean;
|
|
1733
|
+
color?: Color;
|
|
1734
|
+
size?: Size;
|
|
1735
|
+
provider?: Provider;
|
|
1736
|
+
material?: Material;
|
|
1737
|
+
}
|
|
1738
|
+
/**
|
|
1739
|
+
* Request para crear o actualizar un Blank.
|
|
1740
|
+
*/
|
|
1741
|
+
interface BlankRequest {
|
|
1742
|
+
blank: string;
|
|
1743
|
+
sku: string;
|
|
1744
|
+
cost: number;
|
|
1745
|
+
colorId: number;
|
|
1746
|
+
providerId: number;
|
|
1747
|
+
materialId: number;
|
|
1748
|
+
sizeId: number;
|
|
1749
|
+
isActive: boolean;
|
|
1750
|
+
}
|
|
1751
|
+
/**
|
|
1752
|
+
* Filtros disponibles para buscar Blanks.
|
|
1753
|
+
*/
|
|
1754
|
+
interface BlanksFilter {
|
|
1755
|
+
Search?: string;
|
|
1756
|
+
SKU?: string;
|
|
1757
|
+
Provider: string;
|
|
1758
|
+
Material: string;
|
|
1759
|
+
Size: string;
|
|
1760
|
+
IsActive?: boolean;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
/**
|
|
1764
|
+
* Servicio para gestionar entidades relacionadas a Productos (Blanks, Colors, Sizes, SizeGroups, etc.)
|
|
1765
|
+
*/
|
|
1766
|
+
declare class ProductService {
|
|
1767
|
+
private api;
|
|
1768
|
+
private readonly BASE_PATH;
|
|
1769
|
+
constructor(api: API);
|
|
1770
|
+
/**
|
|
1771
|
+
* Obtiene todos los colores con filtros opcionales.
|
|
1772
|
+
*/
|
|
1773
|
+
getColors(filter?: ColorsFilter): Promise<ResponseModel<Color[]>>;
|
|
1774
|
+
/**
|
|
1775
|
+
* Obtiene el modelo de filtros disponibles para colores.
|
|
1776
|
+
*/
|
|
1777
|
+
getColorsFilters(): Promise<ResponseModel<FilterGroupsModel>>;
|
|
1778
|
+
/**
|
|
1779
|
+
* Obtiene un color por su ID.
|
|
1780
|
+
*/
|
|
1781
|
+
getColorById(id: number): Promise<ResponseModel<Color>>;
|
|
1782
|
+
/**
|
|
1783
|
+
* Crea un nuevo color.
|
|
1784
|
+
*/
|
|
1785
|
+
createColor(request: ColorRequest): Promise<ResponseModel<Color>>;
|
|
1786
|
+
/**
|
|
1787
|
+
* Actualiza un color existente.
|
|
1788
|
+
*/
|
|
1789
|
+
updateColor(id: number, request: ColorRequest): Promise<ResponseModel<Color>>;
|
|
1790
|
+
/**
|
|
1791
|
+
* Elimina un color.
|
|
1792
|
+
*/
|
|
1793
|
+
deleteColor(id: number): Promise<ResponseModel<void>>;
|
|
1794
|
+
/**
|
|
1795
|
+
* Obtiene todos los grupos de tallas con filtros opcionales.
|
|
1796
|
+
*/
|
|
1797
|
+
getSizeGroups(filter?: SizeGroupsFilter): Promise<ResponseModel<SizeGroup[]>>;
|
|
1798
|
+
/**
|
|
1799
|
+
* Obtiene el modelo de filtros disponibles para grupos de tallas.
|
|
1800
|
+
*/
|
|
1801
|
+
getSizeGroupsFilters(): Promise<ResponseModel<FilterGroupsModel>>;
|
|
1802
|
+
/**
|
|
1803
|
+
* Obtiene un grupo de tallas por su ID.
|
|
1804
|
+
*/
|
|
1805
|
+
getSizeGroupById(id: number): Promise<ResponseModel<SizeGroup>>;
|
|
1806
|
+
/**
|
|
1807
|
+
* Crea un nuevo grupo de tallas.
|
|
1808
|
+
*/
|
|
1809
|
+
createSizeGroup(request: SizeGroupRequest): Promise<ResponseModel<SizeGroup>>;
|
|
1810
|
+
/**
|
|
1811
|
+
* Actualiza un grupo de tallas existente.
|
|
1812
|
+
*/
|
|
1813
|
+
updateSizeGroup(id: number, request: SizeGroupRequest): Promise<ResponseModel<SizeGroup>>;
|
|
1814
|
+
/**
|
|
1815
|
+
* Elimina un grupo de tallas.
|
|
1816
|
+
*/
|
|
1817
|
+
deleteSizeGroup(id: number): Promise<ResponseModel<void>>;
|
|
1818
|
+
/**
|
|
1819
|
+
* Obtiene todas las tallas con filtros opcionales.
|
|
1820
|
+
*/
|
|
1821
|
+
getSizes(filter?: SizesFilter): Promise<ResponseModel<Size[]>>;
|
|
1822
|
+
/**
|
|
1823
|
+
* Obtiene el modelo de filtros disponibles para tallas.
|
|
1824
|
+
*/
|
|
1825
|
+
getSizesFilters(): Promise<ResponseModel<FilterGroupsModel>>;
|
|
1826
|
+
/**
|
|
1827
|
+
* Obtiene una talla por su ID.
|
|
1828
|
+
*/
|
|
1829
|
+
getSizeById(id: number): Promise<ResponseModel<Size>>;
|
|
1830
|
+
/**
|
|
1831
|
+
* Crea una nueva talla.
|
|
1832
|
+
*/
|
|
1833
|
+
createSize(request: SizeRequest): Promise<ResponseModel<Size>>;
|
|
1834
|
+
/**
|
|
1835
|
+
* Actualiza una talla existente.
|
|
1836
|
+
*/
|
|
1837
|
+
updateSize(id: number, request: SizeRequest): Promise<ResponseModel<Size>>;
|
|
1838
|
+
/**
|
|
1839
|
+
* Elimina una talla.
|
|
1840
|
+
*/
|
|
1841
|
+
deleteSize(id: number): Promise<ResponseModel<void>>;
|
|
1842
|
+
/**
|
|
1843
|
+
* Obtiene todos los blanks con filtros opcionales.
|
|
1844
|
+
*/
|
|
1845
|
+
getBlanks(filter?: BlanksFilter): Promise<ResponseModel<Blank[]>>;
|
|
1846
|
+
/**
|
|
1847
|
+
* Obtiene el modelo de filtros disponibles para blanks.
|
|
1848
|
+
*/
|
|
1849
|
+
getBlanksFilters(): Promise<ResponseModel<FilterGroupsModel>>;
|
|
1850
|
+
/**
|
|
1851
|
+
* Obtiene un blank por su ID.
|
|
1852
|
+
*/
|
|
1853
|
+
getBlankById(id: number): Promise<ResponseModel<Blank>>;
|
|
1854
|
+
/**
|
|
1855
|
+
* Crea un nuevo blank.
|
|
1856
|
+
*/
|
|
1857
|
+
createBlank(request: BlankRequest): Promise<ResponseModel<Blank>>;
|
|
1858
|
+
/**
|
|
1859
|
+
* Actualiza un blank existente.
|
|
1860
|
+
*/
|
|
1861
|
+
updateBlank(id: number, request: BlankRequest): Promise<ResponseModel<Blank>>;
|
|
1862
|
+
/**
|
|
1863
|
+
* Alterna el estado activo de un blank.
|
|
1864
|
+
*/
|
|
1865
|
+
toggleBlankStatus(id: number): Promise<ResponseModel<Blank>>;
|
|
1866
|
+
/**
|
|
1867
|
+
* Elimina un blank.
|
|
1868
|
+
*/
|
|
1869
|
+
deleteBlank(id: number): Promise<ResponseModel<void>>;
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1642
1872
|
declare function decrypt(encryptedBase64: string, secret: string, timestamp: string): string;
|
|
1643
1873
|
|
|
1644
|
-
export { API, type AdminAuthentication, type AdminUser, type AreaCode, type AreaCodeRequest, type AreaCodesFilter, AuthInterceptor, type AuthInterceptorConfig, AuthService, CatalogService, type ChangePasswordAdminRequest, type ChangePasswordRequest, type ChangePasswordUserRequest, type ConfirmEmailRequest, CryptoService, type Endpoint, type EndpointRequest, type EndpointsFilter, ErrorResponse, FalconHUBSDK, FilterBuilder, type FilterFieldMetadata, type FilterGroup, type FilterGroupOption, type FilterGroupsModel, type FilterMetadataModel, type FilterModel, type Gender, type GenderRequest, type GendersFilter, type GetSecretKeyRequest, type GetSecretKeyResponse, type HttpMethodType, type InterceptorContext,
|
|
1874
|
+
export { API, type AdminAuthentication, type AdminUser, type AreaCode, type AreaCodeRequest, type AreaCodeUserProfile, type AreaCodesFilter, AuthInterceptor, type AuthInterceptorConfig, AuthService, type Blank, type BlankRequest, type BlanksFilter, CatalogService, type ChangePasswordAdminRequest, type ChangePasswordRequest, type ChangePasswordUserRequest, type Color, type ColorRequest, type ColorsFilter, type ConfirmEmailRequest, CryptoService, type Endpoint, type EndpointRequest, type EndpointsFilter, ErrorResponse, FalconHUBSDK, FilterBuilder, type FilterFieldMetadata, type FilterGroup, type FilterGroupOption, type FilterGroupsModel, type FilterMetadataModel, type FilterModel, type Gender, type GenderRequest, type GenderUserProfile, type GendersFilter, type GetSecretKeyRequest, type GetSecretKeyResponse, type HttpMethodType, type InterceptorContext, InventoryService, type InventoryStatus, type InventoryStatusRequest, type InventoryStatusesFilter, type Location, type LocationsFilter, type LocationsRequest, type LoginRequest, type LoginResponse, type Material, type MaterialRequest, type MaterialsFilter, type MethodTypes, type Module, type ModuleRequest, type ModulesFilter, type Packing, type PackingRequest, type PackingsFilter, ProductService, type Provider, type ProviderRequest, type ProvidersFilter, type RefreshTokenRequest, type RefreshTokenResponse, type RequestConfig, type RequestInterceptor, type RequestOptions, type ResponseModel, type Role, type RoleRequest, type RoleUserProfile, type RolesFilter, type SendOtpRequest, type ServiceProperties, type Size, type SizeGroup, type SizeGroupRequest, type SizeGroupsFilter, type SizeRequest, type SizesFilter, SystemService, type TokenData, TokenManager, type UIRoute, type UIRouteRequest, type UIRoutesFilter, type UserAdminFilter, type UserAdminRequest, type UserAdminUpdateRequest, type UserAuthAdminRequest, type UserAuthUpdateRequest, type UserBasicResponse, type UserDataUpdateRequest, type UserProfileResponse, UserService, type UserType, type UserTypeRequest, type UserTypeUserProfile, type UserTypesFilter, type ValidateOtpRequest, type ValidateSessionRenewedResponse, type ValidateSessionResponse, decrypt };
|
package/dist/index.mjs
CHANGED
|
@@ -1355,6 +1355,20 @@ var UserService = class {
|
|
|
1355
1355
|
async updateAdminAuthentication(id, request) {
|
|
1356
1356
|
return this.api.executePUT(`${this.BASE_PATH}/admin/authentication/${id}`, request);
|
|
1357
1357
|
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Elimina un administrador.
|
|
1360
|
+
* @param id - ID del administrador
|
|
1361
|
+
*/
|
|
1362
|
+
async deleteAdmin(id) {
|
|
1363
|
+
return this.api.executeDELETE(`${this.BASE_PATH}/admin/${id}`);
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* Reenvía el correo de confirmación al usuario.
|
|
1367
|
+
* @param id - ID del usuario
|
|
1368
|
+
*/
|
|
1369
|
+
async resendEmailConfirmation(id) {
|
|
1370
|
+
return this.api.executePOST(`${this.BASE_PATH}/admin/authentication/${id}/resend-confirmation`);
|
|
1371
|
+
}
|
|
1358
1372
|
// #endregion
|
|
1359
1373
|
// #region User Types
|
|
1360
1374
|
/**
|
|
@@ -1580,6 +1594,176 @@ var FalconHUBSDK = class {
|
|
|
1580
1594
|
}
|
|
1581
1595
|
};
|
|
1582
1596
|
|
|
1597
|
+
// src/services/ProductService.ts
|
|
1598
|
+
var ProductService = class {
|
|
1599
|
+
constructor(api) {
|
|
1600
|
+
this.BASE_PATH = "products";
|
|
1601
|
+
this.api = api;
|
|
1602
|
+
}
|
|
1603
|
+
// #region COLORS
|
|
1604
|
+
/**
|
|
1605
|
+
* Obtiene todos los colores con filtros opcionales.
|
|
1606
|
+
*/
|
|
1607
|
+
async getColors(filter) {
|
|
1608
|
+
const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/colors`, filter);
|
|
1609
|
+
return this.api.executeGET(endpoint, false);
|
|
1610
|
+
}
|
|
1611
|
+
/**
|
|
1612
|
+
* Obtiene el modelo de filtros disponibles para colores.
|
|
1613
|
+
*/
|
|
1614
|
+
async getColorsFilters() {
|
|
1615
|
+
return this.api.executeGET(`${this.BASE_PATH}/colors/filters`, false);
|
|
1616
|
+
}
|
|
1617
|
+
/**
|
|
1618
|
+
* Obtiene un color por su ID.
|
|
1619
|
+
*/
|
|
1620
|
+
async getColorById(id) {
|
|
1621
|
+
return this.api.executeGET(`${this.BASE_PATH}/colors/${id}`, false);
|
|
1622
|
+
}
|
|
1623
|
+
/**
|
|
1624
|
+
* Crea un nuevo color.
|
|
1625
|
+
*/
|
|
1626
|
+
async createColor(request) {
|
|
1627
|
+
return this.api.executePOST(`${this.BASE_PATH}/colors`, request);
|
|
1628
|
+
}
|
|
1629
|
+
/**
|
|
1630
|
+
* Actualiza un color existente.
|
|
1631
|
+
*/
|
|
1632
|
+
async updateColor(id, request) {
|
|
1633
|
+
return this.api.executePUT(`${this.BASE_PATH}/colors/${id}`, request);
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1636
|
+
* Elimina un color.
|
|
1637
|
+
*/
|
|
1638
|
+
async deleteColor(id) {
|
|
1639
|
+
return this.api.executeDELETE(`${this.BASE_PATH}/colors/${id}`);
|
|
1640
|
+
}
|
|
1641
|
+
// #endregion
|
|
1642
|
+
// #region SIZE GROUPS
|
|
1643
|
+
/**
|
|
1644
|
+
* Obtiene todos los grupos de tallas con filtros opcionales.
|
|
1645
|
+
*/
|
|
1646
|
+
async getSizeGroups(filter) {
|
|
1647
|
+
const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/size-groups`, filter);
|
|
1648
|
+
return this.api.executeGET(endpoint, false);
|
|
1649
|
+
}
|
|
1650
|
+
/**
|
|
1651
|
+
* Obtiene el modelo de filtros disponibles para grupos de tallas.
|
|
1652
|
+
*/
|
|
1653
|
+
async getSizeGroupsFilters() {
|
|
1654
|
+
return this.api.executeGET(`${this.BASE_PATH}/size-groups/filters`, false);
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* Obtiene un grupo de tallas por su ID.
|
|
1658
|
+
*/
|
|
1659
|
+
async getSizeGroupById(id) {
|
|
1660
|
+
return this.api.executeGET(`${this.BASE_PATH}/size-groups/${id}`, false);
|
|
1661
|
+
}
|
|
1662
|
+
/**
|
|
1663
|
+
* Crea un nuevo grupo de tallas.
|
|
1664
|
+
*/
|
|
1665
|
+
async createSizeGroup(request) {
|
|
1666
|
+
return this.api.executePOST(`${this.BASE_PATH}/size-groups`, request);
|
|
1667
|
+
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Actualiza un grupo de tallas existente.
|
|
1670
|
+
*/
|
|
1671
|
+
async updateSizeGroup(id, request) {
|
|
1672
|
+
return this.api.executePUT(`${this.BASE_PATH}/size-groups/${id}`, request);
|
|
1673
|
+
}
|
|
1674
|
+
/**
|
|
1675
|
+
* Elimina un grupo de tallas.
|
|
1676
|
+
*/
|
|
1677
|
+
async deleteSizeGroup(id) {
|
|
1678
|
+
return this.api.executeDELETE(`${this.BASE_PATH}/size-groups/${id}`);
|
|
1679
|
+
}
|
|
1680
|
+
// #endregion
|
|
1681
|
+
// #region SIZES
|
|
1682
|
+
/**
|
|
1683
|
+
* Obtiene todas las tallas con filtros opcionales.
|
|
1684
|
+
*/
|
|
1685
|
+
async getSizes(filter) {
|
|
1686
|
+
const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/sizes`, filter);
|
|
1687
|
+
return this.api.executeGET(endpoint, false);
|
|
1688
|
+
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Obtiene el modelo de filtros disponibles para tallas.
|
|
1691
|
+
*/
|
|
1692
|
+
async getSizesFilters() {
|
|
1693
|
+
return this.api.executeGET(`${this.BASE_PATH}/sizes/filters`, false);
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* Obtiene una talla por su ID.
|
|
1697
|
+
*/
|
|
1698
|
+
async getSizeById(id) {
|
|
1699
|
+
return this.api.executeGET(`${this.BASE_PATH}/sizes/${id}`, false);
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* Crea una nueva talla.
|
|
1703
|
+
*/
|
|
1704
|
+
async createSize(request) {
|
|
1705
|
+
return this.api.executePOST(`${this.BASE_PATH}/sizes`, request);
|
|
1706
|
+
}
|
|
1707
|
+
/**
|
|
1708
|
+
* Actualiza una talla existente.
|
|
1709
|
+
*/
|
|
1710
|
+
async updateSize(id, request) {
|
|
1711
|
+
return this.api.executePUT(`${this.BASE_PATH}/sizes/${id}`, request);
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Elimina una talla.
|
|
1715
|
+
*/
|
|
1716
|
+
async deleteSize(id) {
|
|
1717
|
+
return this.api.executeDELETE(`${this.BASE_PATH}/sizes/${id}`);
|
|
1718
|
+
}
|
|
1719
|
+
// #endregion
|
|
1720
|
+
// #region BLANKS
|
|
1721
|
+
/**
|
|
1722
|
+
* Obtiene todos los blanks con filtros opcionales.
|
|
1723
|
+
*/
|
|
1724
|
+
async getBlanks(filter) {
|
|
1725
|
+
const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/blanks`, filter);
|
|
1726
|
+
return this.api.executeGET(endpoint, false);
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* Obtiene el modelo de filtros disponibles para blanks.
|
|
1730
|
+
*/
|
|
1731
|
+
async getBlanksFilters() {
|
|
1732
|
+
return this.api.executeGET(`${this.BASE_PATH}/blanks/filters`, false);
|
|
1733
|
+
}
|
|
1734
|
+
/**
|
|
1735
|
+
* Obtiene un blank por su ID.
|
|
1736
|
+
*/
|
|
1737
|
+
async getBlankById(id) {
|
|
1738
|
+
return this.api.executeGET(`${this.BASE_PATH}/blanks/${id}`, false);
|
|
1739
|
+
}
|
|
1740
|
+
/**
|
|
1741
|
+
* Crea un nuevo blank.
|
|
1742
|
+
*/
|
|
1743
|
+
async createBlank(request) {
|
|
1744
|
+
return this.api.executePOST(`${this.BASE_PATH}/blanks`, request);
|
|
1745
|
+
}
|
|
1746
|
+
/**
|
|
1747
|
+
* Actualiza un blank existente.
|
|
1748
|
+
*/
|
|
1749
|
+
async updateBlank(id, request) {
|
|
1750
|
+
return this.api.executePUT(`${this.BASE_PATH}/blanks/${id}`, request);
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* Alterna el estado activo de un blank.
|
|
1754
|
+
*/
|
|
1755
|
+
async toggleBlankStatus(id) {
|
|
1756
|
+
return this.api.executePUT(`${this.BASE_PATH}/blanks/${id}/toggle-status`);
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Elimina un blank.
|
|
1760
|
+
*/
|
|
1761
|
+
async deleteBlank(id) {
|
|
1762
|
+
return this.api.executeDELETE(`${this.BASE_PATH}/blanks/${id}`);
|
|
1763
|
+
}
|
|
1764
|
+
// #endregion
|
|
1765
|
+
};
|
|
1766
|
+
|
|
1583
1767
|
// src/core/Encryption.ts
|
|
1584
1768
|
import CryptoJS2 from "crypto-js";
|
|
1585
1769
|
function decrypt(encryptedBase64, secret, timestamp) {
|
|
@@ -1608,6 +1792,7 @@ export {
|
|
|
1608
1792
|
FalconHUBSDK,
|
|
1609
1793
|
FilterBuilder,
|
|
1610
1794
|
InventoryService,
|
|
1795
|
+
ProductService,
|
|
1611
1796
|
SystemService,
|
|
1612
1797
|
TokenManager,
|
|
1613
1798
|
UserService,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/API.ts","../src/core/CryptoService.ts","../src/core/TokenManager.ts","../src/core/interceptors/AuthInterceptor.ts","../src/types/ErrorResponse.ts","../src/services/AuthService.ts","../src/utils/FilterBuilder.ts","../src/services/CatalogService.ts","../src/services/InventoryService.ts","../src/services/SystemService.ts","../src/services/UserService.ts","../src/FalconHUBSDK.ts","../src/core/Encryption.ts"],"sourcesContent":["import { ServiceProperties } from \"@/types/ServiceProperties\";\nimport { CryptoService } from \"./CryptoService\";\nimport { MethodTypes, RequestOptions } from \"@/types/RequestOptions\";\nimport { RequestConfig } from \"@/types/RequestConfig\";\nimport { AuthInterceptor } from \"./interceptors/AuthInterceptor\";\nimport { InterceptorContext } from \"@/core/interceptors/types/InterceptorContext\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\n\n\n/**\n * Clase base para la ejecución de request HTTP al API\n */\nexport class API {\n private properties: ServiceProperties;\n private cryptoService: CryptoService;\n private authInterceptor: AuthInterceptor | null;\n\n private getAccessToken: () => string | null;\n private getRefreshToken: () => string | null;\n\n constructor(\n properties: ServiceProperties,\n cryptoService: CryptoService,\n authInterceptor: AuthInterceptor | null,\n getAccessToken: () => string | null,\n getRefreshToken: () => string | null\n ) {\n this.properties = properties;\n this.cryptoService = cryptoService;\n this.getAccessToken = getAccessToken;\n this.getRefreshToken = getRefreshToken;\n this.authInterceptor = authInterceptor;\n };\n\n /**\n * Ejecuta una request HTTP al API\n *\n * @param options - Opciones de la request\n * @returns Respuesta del tipo ResponseModel\n */\n private async apiExecute<T>(options: RequestOptions): Promise<ResponseModel<T>> {\n const {\n endpoint,\n method,\n body,\n requiresAuth,\n timeStamp\n } = options;\n\n const context: InterceptorContext = {\n requestId: this.cryptoService.generateUniqueId(),\n startTime: Date.now(),\n retryCount: 0,\n metadata: {}\n };\n\n try {\n const url = `${this.properties.url}/${endpoint}`;\n const headers: Record<string, string> = {};\n\n if (body && method !== 'GET') {\n headers['Content-Type'] = 'application/json';\n };\n\n const accessToken = this.getAccessToken();\n if (accessToken) {\n headers['Authorization'] = `Bearer ${accessToken}`;\n };\n\n const newTimeStamp = timeStamp || new Date().toISOString();\n\n headers[\"X-Origin-Request\"] = this.properties.originRequest;\n headers['X-Timestamp'] = newTimeStamp;\n headers[\"X-Domain\"] = this.properties.domain;\n headers[\"X-Device\"] = this.properties.device;\n headers[\"X-Source\"] = this.properties.source;\n\n let bodyString: string | undefined;\n if (body && method !== 'GET') {\n bodyString = JSON.stringify(body);\n };\n\n const requestConfig: RequestConfig = {\n url,\n method,\n headers,\n body: bodyString,\n requiresAuth\n };\n\n const modifiedConfig = this.authInterceptor\n ? await this.authInterceptor.onRequest(requestConfig, context)\n : requestConfig;\n\n const requestInit: RequestInit = {\n method: modifiedConfig.method,\n headers: modifiedConfig.headers,\n mode: 'cors',\n credentials: 'omit'\n };\n\n if (modifiedConfig.body && modifiedConfig.method !== 'GET') {\n requestInit.body = typeof modifiedConfig.body === 'string'\n ? modifiedConfig.body\n : JSON.stringify(modifiedConfig.body);\n };\n\n const response = await fetch(\n modifiedConfig.url,\n requestInit\n );\n\n const newAccessToken = response.headers.get('X-New-Access-Token');\n const newRefreshToken = response.headers.get('X-New-Refresh-Token');\n\n if (newAccessToken || newRefreshToken) {\n this.properties.onTokensRefreshed?.({\n accessToken: newAccessToken,\n refreshToken: newRefreshToken\n });\n };\n\n let result: any;\n\n try {\n result = await response.json();\n } catch (e) {\n // Fallback en caso de que la respuesta no sea un JSON válido (errores de servidor 500, 502, etc.)\n return {\n success: false,\n message: `Error de servidor (${response.status}: ${response.statusText || 'Formato de respuesta no reconocido'})`,\n data: null,\n responseTime: new Date().toISOString()\n };\n }\n\n // Manejo de errores de validación (RFC 9110)\n if (result && result.errors && typeof result.errors === 'object') {\n const errorMessages: string[] = [];\n\n Object.values(result.errors).forEach((errors: any) => {\n if (Array.isArray(errors)) {\n errorMessages.push(...errors);\n } else if (typeof errors === 'string') {\n errorMessages.push(errors);\n }\n });\n\n if (errorMessages.length > 0) {\n return {\n success: false,\n message: errorMessages.join(', '),\n data: result.data ?? null,\n responseTime: result.responseTime ?? new Date().toISOString()\n } as ResponseModel<T>;\n }\n }\n\n return result as ResponseModel<T>;\n\n } catch (error) {\n return {\n success: false,\n message: error instanceof Error ? error.message : 'Error inesperado durante la petición al API.',\n data: null,\n responseTime: new Date().toISOString()\n };\n };\n };\n\n\n //#region REQUEST METHODS\n\n async executeGET<T>(\n endpoint: string,\n requiresAuth: boolean = false\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method: 'GET',\n requiresAuth: requiresAuth\n });\n };\n\n async executePOST<T>(\n endpoint: string,\n body?: any,\n requiresAuth: boolean = true,\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method: 'POST',\n body,\n requiresAuth: requiresAuth\n });\n };\n\n async executePATCH<T>(\n endpoint: string,\n body?: any,\n requiresAuth: boolean = true,\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method: 'PATCH',\n body,\n requiresAuth: requiresAuth\n });\n };\n\n async executeDELETE<T>(\n endpoint: string,\n body?: any,\n requiresAuth: boolean = true,\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method: 'DELETE',\n body,\n requiresAuth: requiresAuth\n });\n };\n\n async executePUT<T>(\n endpoint: string,\n body?: any,\n requiresAuth: boolean = true\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method: 'PUT',\n body,\n requiresAuth: requiresAuth,\n });\n };\n\n async executePublicRequest<T>(\n endpoint: string,\n method: MethodTypes,\n body?: any,\n timestamp?: string\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method,\n body,\n requiresAuth: false,\n timeStamp: timestamp\n });\n };\n\n //#endregion\n}\n","import * as CryptoJS from \"crypto-js\";\n\nexport class CryptoService {\n /**\n * Genera un hash SHA256 de un texto (útil para fingerprints)\n *\n * @param text - Texto a hashear\n * @returns Hash en formato hexadecimal\n */\n sha256(text: string): string {\n return CryptoJS.SHA256(text).toString(CryptoJS.enc.Hex);\n }\n\n /**\n * Genera un identificador único basado en timestamp y random\n * (útil para request IDs)\n *\n * @returns ID único\n */\n generateUniqueId(): string {\n const timestamp = Date.now().toString(36);\n const randomPart = Math.random().toString(36).substring(2, 15);\n return `${timestamp}-${randomPart}`;\n }\n}\n","import { TokenData } from \"@/types/TokenData\";\n\n/**\n * Manages authentication tokens.\n */\nexport class TokenManager {\n private tokens: TokenData | null = null;\n private onTokensChanged?: (tokens: TokenData | null) => void;\n private sessionCheckInterval: NodeJS.Timeout | null = null;\n private autoRefreshTimeout: NodeJS.Timeout | null = null;\n private onSessionExpiring?: (remainingMinutes: number) => void;\n private onSessionExpired?: () => Promise<void>;\n private onSessionRecovery?: () => Promise<boolean>;\n private hasNotifiedExpiring: boolean = false;\n private autoRefreshThresholdMinutes: number = 5;\n\n constructor(\n onTokensChanged?: (tokens: TokenData | null) => void,\n onSessionExpiring?: (remainingMinutes: number) => void,\n onSessionExpired?: () => Promise<void>,\n onSessionRecovery?: () => Promise<boolean>,\n autoRefreshThresholdMinutes?: number\n ) {\n this.onTokensChanged = onTokensChanged;\n this.onSessionExpiring = onSessionExpiring;\n this.onSessionExpired = onSessionExpired;\n this.onSessionRecovery = onSessionRecovery;\n this.autoRefreshThresholdMinutes = autoRefreshThresholdMinutes ?? 5;\n };\n\n /**\n * Guarda los tokens de autenticación y dispara el callback onTokensChanged.\n */\n setTokens(tokens: TokenData) {\n this.tokens = tokens;\n this.hasNotifiedExpiring = false;\n\n this.onTokensChanged?.(this.tokens);\n\n if (!tokens.rememberMe) {\n this.startExpirationCheck();\n this.stopAutoRefreshTimer();\n } else {\n this.stopExpirationCheck();\n this.scheduleAutoRefresh();\n };\n };\n\n /**\n * Guarda los tokens sin disparar el callback onTokensChanged.\n * Usar para inyectar tokens desde storage externo (cookies/localStorage).\n */\n setTokensSilent(tokens: TokenData) {\n this.tokens = tokens;\n this.hasNotifiedExpiring = false;\n\n if (!tokens.rememberMe) {\n this.startExpirationCheck();\n this.stopAutoRefreshTimer();\n } else {\n this.stopExpirationCheck();\n this.scheduleAutoRefresh();\n };\n };\n\n /**\n * Obtiene los tokens de autenticación almacenados.\n */\n getTokens(): TokenData | null {\n return this.tokens;\n };\n\n /**\n * Limpia los tokens de autenticación almacenados y dispara el callback onTokensChanged.\n */\n clearTokens() {\n this.stopExpirationCheck();\n this.stopAutoRefreshTimer();\n this.tokens = null;\n this.onTokensChanged?.(this.tokens);\n };\n\n /**\n * Valida si existen tokens y si el access token no ha expirado.\n */\n hasValidTokens(): boolean {\n if (!this.tokens) return false;\n\n return Date.now() < this.tokens.expiresAt;\n };\n\n /**\n * Valida si el access token expirará dentro del umbral especificado (en minutos).\n */\n isTokenExpiringSoon(thresholdMinutes: number): boolean {\n if (!this.tokens) return false;\n\n const thresholdMs = thresholdMinutes * 60 * 1000;\n const timeLeft = this.tokens.expiresAt - Date.now();\n\n return timeLeft > 0 && timeLeft <= thresholdMs;\n };\n\n /**\n * Obtiene el tiempo restante hasta la expiración del access token en milisegundos.\n */\n getTimeUntilExpiry(): number | null {\n if (!this.tokens) return null;\n\n return Math.max(0, this.tokens.expiresAt - Date.now());\n };\n\n /**\n * Obtiene el access token almacenado.\n */\n getAccessToken(): string | null {\n return this.tokens ? this.tokens.accessToken : null;\n };\n\n /**\n * Obtiene el refresh token almacenado.\n */\n getRefreshToken(): string | null {\n return this.tokens ? this.tokens.refreshToken : null;\n };\n\n /**\n * Verifica si el auto-refresh debe ejecutarse\n * Solo si el usuario activó \"rememberMe\" durante el login\n */\n shouldAutoRefresh(): boolean {\n if (!this.tokens) return false;\n\n return this.tokens.rememberMe === true;\n }\n\n /**\n * Inicia el monitoreo de expiración para sesiones sin rememberMe\n * - Notifica cuando quedan 5 minutos (onSessionExpiring)\n */\n private startExpirationCheck(): void {\n this.stopExpirationCheck();\n\n this.sessionCheckInterval = setInterval(async () => {\n if (!this.tokens) {\n this.stopExpirationCheck();\n return;\n };\n\n const timeLeft = this.getTimeUntilExpiry();\n if (timeLeft === null) return;\n\n const minutesLeft = Math.floor(timeLeft / (60 * 1000));\n\n if (minutesLeft <= 5 && minutesLeft > 1 && !this.hasNotifiedExpiring) {\n this.hasNotifiedExpiring = true;\n this.onSessionExpiring?.(minutesLeft);\n };\n\n if (minutesLeft <= 1) {\n this.stopExpirationCheck();\n\n if (this.onSessionRecovery) {\n try {\n const recovered = await this.onSessionRecovery();\n if (recovered) return;\n } catch (error) {\n }\n }\n\n if (this.onSessionExpired) {\n await this.onSessionExpired();\n };\n };\n }, 60000);\n }\n\n /**\n * Programa un auto-refresh proactivo para sesiones con rememberMe.\n * Se ejecuta X minutos antes de que expire el token\n */\n private scheduleAutoRefresh(): void {\n this.stopAutoRefreshTimer();\n\n if (!this.tokens || !this.tokens.rememberMe) return;\n\n const timeLeft = this.getTimeUntilExpiry();\n if (timeLeft === null || timeLeft <= 0) return;\n\n const thresholdMs = this.autoRefreshThresholdMinutes * 60 * 1000;\n const delay = Math.max(0, timeLeft - thresholdMs);\n\n this.autoRefreshTimeout = setTimeout(async () => {\n if (!this.tokens || !this.tokens.rememberMe) return;\n\n if (this.onSessionRecovery) {\n try {\n const recovered = await this.onSessionRecovery();\n if (recovered) return;\n } catch (error) {\n }\n }\n\n if (this.onSessionExpired) {\n await this.onSessionExpired();\n }\n }, delay);\n }\n\n /**\n * Detiene el monitoreo de expiración\n */\n private stopExpirationCheck(): void {\n if (this.sessionCheckInterval) {\n clearInterval(this.sessionCheckInterval);\n this.sessionCheckInterval = null;\n };\n }\n\n /**\n * Detiene el timer de auto-refresh proactivo\n */\n private stopAutoRefreshTimer(): void {\n if (this.autoRefreshTimeout) {\n clearTimeout(this.autoRefreshTimeout);\n this.autoRefreshTimeout = null;\n };\n }\n};\n","import { AuthInterceptorConfig } from \"./types/AuthInterceptorConfig\";\nimport { InterceptorContext } from \"@/core/interceptors/types/InterceptorContext\";\nimport { RequestConfig } from \"@/types/RequestConfig\";\nimport { RequestInterceptor } from \"./types/RequestInterceptor\";\n\nexport class AuthInterceptor implements RequestInterceptor {\n readonly name = \"AuthInterceptor\";\n\n private config: Required<AuthInterceptorConfig>;\n private refreshPromise: Promise<void> | null = null;\n private isRefreshing = false;\n\n constructor(config: AuthInterceptorConfig) {\n this.config = {\n enabled: config.enabled ?? true,\n thresholdMinutes: config.thresholdMinutes ?? 5,\n isTokenExpiringSoon: config.isTokenExpiringSoon,\n hasValidTokens: config.hasValidTokens,\n shouldAutoRefresh: config.shouldAutoRefresh,\n refreshSession: config.refreshSession\n };\n };\n\n async onRequest(\n config: RequestConfig,\n context: InterceptorContext\n ): Promise<RequestConfig> {\n\n //Actua en solicitudes que requieren autenticación\n if (!config.requiresAuth || !this.config.enabled) {\n return config;\n };\n\n //Actúa SOLO si los tokens son válidos\n if (!this.config.hasValidTokens()) {\n return config;\n };\n\n if (!this.config.shouldAutoRefresh()) {\n return config;\n };\n\n if (this.config.isTokenExpiringSoon()) {\n try {\n //Evita múltiples llamadas de actualización simultáneas\n if (this.isRefreshing && this.refreshPromise) {\n await this.refreshPromise;\n } else {\n this.isRefreshing = true;\n this.refreshPromise = this.config.refreshSession();\n await this.refreshPromise;\n this.isRefreshing = false;\n this.refreshPromise = null;\n };\n } catch (error) {\n this.isRefreshing = false;\n this.refreshPromise = null;\n };\n };\n\n return config;\n };\n\n updateConfig(config: Partial<AuthInterceptorConfig>): void {\n this.config = {\n ...this.config,\n ...config\n } as Required<AuthInterceptorConfig>;\n };\n\n reset(): void {\n this.isRefreshing = false;\n this.refreshPromise = null;\n };\n};\n","export class ErrorResponse extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n public responseData?: any\n ){\n super(message);\n this.name = \"FalconHUB API Error\";\n };\n};\n","import { API } from \"@/core/API\";\nimport { CryptoService } from \"@/core/CryptoService\";\nimport { TokenManager } from \"@/core/TokenManager\";\nimport { ChangePasswordRequest } from \"@/interfaces/Auth/ChangePassword/ChangePasswordRequest\";\nimport { ConfirmEmailRequest } from \"@/interfaces/Auth/ConfirmEmail/ConfirmEmailRequest\";\nimport { GetSecretKeyRequest } from \"@/interfaces/Auth/GetSecretKey/GetSecretKeyRequest\";\nimport { GetSecretKeyResponse } from \"@/interfaces/Auth/GetSecretKey/GetSecretKeyResponse\";\nimport { LoginRequest } from \"@/interfaces/Auth/Login/LoginRequest\";\nimport { LoginResponse } from \"@/interfaces/Auth/Login/LoginResponse\";\nimport { RefreshTokenRequest } from \"@/interfaces/Auth/RefreshTokens/RefreshTokenRequest\";\nimport { RefreshTokenResponse } from \"@/interfaces/Auth/RefreshTokens/RefreshTokenResponse\";\nimport { SendOtpRequest } from \"@/interfaces/Auth/SendOtp/SendOtpRequest\";\nimport { ValidateOtpRequest } from \"@/interfaces/Auth/ValidateOtp/ValidateOtpRequest\";\nimport { ValidateSessionRenewedResponse, ValidateSessionResponse } from \"@/interfaces/Auth/ValidateSession/ValidateSessionResponse\";\nimport { ErrorResponse } from \"@/types/ErrorResponse\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\nimport { ServiceProperties } from \"@/types/ServiceProperties\";\nimport { TokenData } from \"@/types/TokenData\";\n\n//Validado, integrado en su totalidad.\nexport class AuthService {\n private api: API;\n private crytpoService: CryptoService;\n private tokenManager: TokenManager;\n private serviceProperties: ServiceProperties;\n\n constructor(\n serviceProperties: ServiceProperties,\n tokenManager: TokenManager,\n cryptoService: CryptoService,\n api: API\n ) {\n this.api = api;\n this.crytpoService = cryptoService;\n this.tokenManager = tokenManager;\n this.serviceProperties = serviceProperties;\n };\n\n /**\n * Login con las credenciales proporcionadas\n * @param credentials - Objeto con email, password y rememberMe\n * @returns Retorna el cuerpo de respuesta del login.\n */\n async login(credentials: LoginRequest): Promise<ResponseModel<LoginResponse>> {\n const timestamp = Date.now().toString();\n\n const loginData: LoginRequest = {\n email: credentials.email,\n password: credentials.password,\n rememberMe: credentials.rememberMe\n };\n\n const response = await this.api.executePublicRequest<LoginResponse>(\n 'oauth/login',\n 'POST',\n loginData,\n timestamp\n );\n\n if (!response) {\n throw new ErrorResponse('No response from server');\n };\n\n if (response.success && response.data) {\n const data: LoginResponse = response.data;\n\n const expiresIn = parseInt(data.expiresIn.replace('s', ''));\n const expiresAt = Date.now() + expiresIn * 1000;\n\n const tokens: TokenData = {\n accessToken: data.accessToken,\n refreshToken: data.refreshToken,\n expiresAt,\n rememberMe: credentials.rememberMe\n };\n\n await this.tokenManager.setTokens(tokens);\n\n this.serviceProperties.onTokensUpdated?.(tokens);\n }\n\n return response;\n };\n\n /**\n * Valida la sesión actual y retorna información de expiración\n *\n * El servidor puede responder de 2 formas:\n * 1. Sesión renovada (sliding window): retorna nuevos tokens\n * 2. Sesión válida: retorna info de expiración sin renovar\n */\n async validateSession(): Promise<ResponseModel<ValidateSessionRenewedResponse | ValidateSessionResponse>> {\n const response = await this.api.executePOST<ValidateSessionRenewedResponse | ValidateSessionResponse>(\n 'oauth/validateSession'\n );\n\n if (!response) {\n throw new ErrorResponse('No response from server');\n };\n\n if (response.success && response.data) {\n const respData = response.data;\n\n if ('expiresIn' in respData && respData.expiresIn) {\n const sessionData = respData as ValidateSessionRenewedResponse;\n const expiresIn = parseInt(sessionData.expiresIn.replace('s', ''));\n const expiresAt = Date.now() + expiresIn * 1000;\n\n const currentTokens = this.tokenManager.getTokens();\n const rememberMe = currentTokens?.rememberMe ?? sessionData.isRemembered;\n\n const tokens: TokenData = {\n accessToken: sessionData.accessToken,\n refreshToken: sessionData.refreshToken,\n expiresAt,\n rememberMe\n };\n\n this.tokenManager.setTokens(tokens);\n this.serviceProperties.onTokensUpdated?.(tokens);\n }\n else if ('expiresAt' in respData && respData.expiresAt) {\n const sessionData = respData as ValidateSessionResponse;\n\n if (sessionData.remainingMinutes <= 5 && sessionData.remainingMinutes > 1) {\n this.serviceProperties.onSessionExpiring?.(sessionData.remainingMinutes);\n } else if (sessionData.remainingMinutes <= 1) {\n if (this.serviceProperties.onSessionExpired) {\n await this.serviceProperties.onSessionExpired();\n }\n }\n }\n };\n\n return response;\n };\n\n /**\n * Refresca los tokens usando el refresh token\n */\n async refreshTokens(refreshRequest: RefreshTokenRequest): Promise<ResponseModel<RefreshTokenResponse>> {\n const currentTokens = this.tokenManager.getTokens();\n const refreshToken = this.tokenManager.getRefreshToken() ?? refreshRequest.refreshToken;\n\n if (!refreshToken) {\n throw new ErrorResponse('No refresh token available');\n };\n\n const refreshRequestData: RefreshTokenRequest = {\n refreshToken: refreshToken,\n rememberMe: refreshRequest.rememberMe ?? currentTokens?.rememberMe\n }\n\n const response = await this.api.executePublicRequest<RefreshTokenResponse>(\n 'oauth/refresh',\n 'POST',\n refreshRequestData\n );\n\n if (!response) {\n throw new ErrorResponse('No response from server');\n };\n\n if (response.success && response.data) {\n const sessionData: RefreshTokenResponse = response.data;\n\n\n const shouldRemember = refreshRequest.rememberMe ?? currentTokens?.rememberMe ?? false;\n const expiresIn = parseInt(sessionData.expiresIn.replace('s', ''));\n const expiresAt = Date.now() + expiresIn * 1000;\n\n const tokens: TokenData = {\n accessToken: sessionData.accessToken,\n refreshToken: sessionData.refreshToken,\n expiresAt,\n rememberMe: shouldRemember\n };\n\n this.tokenManager.setTokens(tokens);\n this.serviceProperties.onTokensUpdated?.(tokens);\n };\n\n return response;\n };\n\n /**\n * Cierra sesión: notifica al servidor y limpia tokens\n */\n async logout(): Promise<ResponseModel> {\n const res = await this.api.executePOST('oauth/logout');\n\n if (res.success) {\n this.tokenManager.clearTokens();\n this.serviceProperties.onTokensUpdated?.(null);\n }\n\n return res;\n }\n\n /**\n * Obtiene la SecretKey del usuario autenticado.\n * Requiere sesión activa. Si el usuario tiene 2FA habilitado, se debe proveer el OTP.\n * @param request - Objeto opcional con otpCode (requerido si IsTwoFactorEnabled)\n */\n async getSecretKey(request?: GetSecretKeyRequest): Promise<ResponseModel<GetSecretKeyResponse>> {\n const response = await this.api.executePOST<GetSecretKeyResponse>(\n 'oauth/secret-key',\n request\n );\n\n if (!response) {\n throw new ErrorResponse('No response from server');\n }\n\n return response;\n }\n\n // #region Email & OTP & Password (public - no auth)\n\n /**\n * Confirma el correo electrónico de un usuario.\n * @param request - Email y expiresAt\n */\n async confirmEmail(request: ConfirmEmailRequest): Promise<ResponseModel> {\n return this.api.executePublicRequest('oauth/email/confirm', 'PUT', request);\n }\n\n /**\n * Envía un código OTP al correo electrónico.\n * @param request - Email del usuario\n */\n async sendOtp(request: SendOtpRequest): Promise<ResponseModel> {\n return this.api.executePublicRequest('oauth/otp', 'POST', request);\n }\n\n /**\n * Valida un código OTP.\n * @param request - Email y código OTP\n */\n async validateOtp(request: ValidateOtpRequest): Promise<ResponseModel> {\n return this.api.executePublicRequest('oauth/otp/verify', 'POST', request);\n }\n\n /**\n * Cambia la contraseña del usuario (flujo público, sin sesión).\n * @param request - Email, contraseña actual y nueva contraseña\n */\n async changePassword(request: ChangePasswordRequest): Promise<ResponseModel> {\n return this.api.executePublicRequest('oauth/password', 'PUT', request);\n }\n\n // #endregion\n\n /**\n * Verifica si el usuario está autenticado\n */\n isAuthenticated(): boolean {\n return this.tokenManager.hasValidTokens();\n };\n\n /**\n * Obtiene los tokens actuales\n */\n getTokens(): TokenData | null {\n return this.tokenManager.getTokens();\n };\n\n}\n","/**\n * Utilidad para construir query params a partir de objetos de filtro.\n *\n * @example\n * ```typescript\n * const filter: EndpointsFilter = { HttpMethod: 'GET', IsActive: true };\n * const queryString = FilterBuilder.toQueryString(filter);\n * // Result: \"HttpMethod=GET&IsActive=true\"\n * ```\n */\nexport class FilterBuilder {\n /**\n * Convierte un objeto de filtro a query string.\n * Ignora valores null, undefined y strings vacíos.\n *\n * @param filter - Objeto con los filtros a aplicar\n * @returns Query string sin el \"?\" inicial\n */\n static toQueryString<T extends Record<string, any>>(filter: T): string {\n const params = new URLSearchParams();\n\n for (const [key, value] of Object.entries(filter)) {\n if (value !== null && value !== undefined && value !== '') {\n params.append(key, String(value));\n }\n }\n\n return params.toString();\n }\n\n /**\n * Construye la URL completa con filtros aplicados.\n *\n * @param baseEndpoint - Endpoint base sin query params\n * @param filter - Objeto con los filtros a aplicar\n * @returns Endpoint con query params si hay filtros, o el endpoint base si no hay\n */\n static buildEndpoint<T extends Record<string, any>>(baseEndpoint: string, filter?: T): string {\n if (!filter) return baseEndpoint;\n\n const queryString = this.toQueryString(filter);\n\n if (!queryString) return baseEndpoint;\n\n return `${baseEndpoint}?${queryString}`;\n }\n\n /**\n * Verifica si un objeto de filtro tiene al menos un valor válido.\n *\n * @param filter - Objeto con los filtros a verificar\n * @returns true si hay al menos un filtro con valor válido\n */\n static hasFilters<T extends Record<string, any>>(filter?: T): boolean {\n if (!filter) return false;\n\n return Object.values(filter).some(\n value => value !== null && value !== undefined && value !== ''\n );\n }\n\n /**\n * Limpia un objeto de filtro removiendo valores vacíos.\n * Útil para normalizar filtros antes de enviarlos.\n *\n * @param filter - Objeto con los filtros\n * @returns Nuevo objeto solo con valores válidos\n */\n static clean<T extends Record<string, any>>(filter: T): Partial<T> {\n const cleaned: Partial<T> = {};\n\n for (const [key, value] of Object.entries(filter)) {\n if (value !== null && value !== undefined && value !== '') {\n (cleaned as any)[key] = value;\n }\n }\n\n return cleaned;\n }\n}\n\n/**\n * Tipo base para modelos de filtro.\n * Todos los campos son opcionales y pueden ser string, number, boolean o null.\n */\nexport type FilterModel = Record<string, string | number | boolean | null | undefined>;\n\n/**\n * Tipo para definir metadatos de un campo de filtro.\n */\nexport interface FilterFieldMetadata {\n /** Tipo de filtro */\n type: 'search' | 'string' | 'boolean' | 'number' | 'select' | 'multiselect' | 'date' | 'daterange';\n /** Descripción / label del filtro */\n description: string;\n /** Orden de renderizado (menor = primero, default 99) */\n order?: number;\n /** Opciones para select / multiselect */\n options?: string[];\n /** Labels personalizados para boolean (default: Activo/Inactivo) */\n labels?: { true: string; false: string };\n /** Campos en los que busca el backend (solo para type: 'search') */\n searchIn?: string[];\n /** Valor mínimo (para number) */\n min?: number;\n /** Valor máximo (para number) */\n max?: number;\n /** Fecha mínima (para date / daterange) */\n minDate?: string;\n /** Fecha máxima (para date / daterange) */\n maxDate?: string;\n}\n\n/**\n * Tipo para el modelo de filtros retornado por el endpoint /filters.\n */\nexport type FilterMetadataModel = Record<string, FilterFieldMetadata>;\n\n// ── Filter Groups (array-based format) ──\n\n/**\n * Opción dentro de un grupo de filtros.\n */\nexport interface FilterGroupOption {\n /** Campo del backend (e.g. \"Module\", \"IsActive\") */\n key: string;\n /** Label visible en el frontend */\n label: string;\n /** Placeholder del input (solo para string) */\n placeholder?: string;\n /** Opciones disponibles (solo para select) */\n values?: string[];\n /** Label cuando el valor es true (solo para boolean) */\n trueLabel?: string;\n /** Label cuando el valor es false (solo para boolean) */\n falseLabel?: string;\n}\n\n/**\n * Grupo de filtros agrupados por tipo.\n * El frontend renderiza cada grupo de forma diferente.\n */\nexport interface FilterGroup {\n /** Tipo de filtro: \"string\" | \"boolean\" | \"select\" | \"date\" */\n type: 'string' | 'boolean' | 'select' | 'date';\n /** Label del grupo */\n label: string;\n /** Opciones del grupo */\n options: FilterGroupOption[];\n}\n\n/**\n * Modelo retornado por el endpoint /filters (formato array-based).\n */\nexport type FilterGroupsModel = FilterGroup[];\n","import { API } from \"@/core/API\";\nimport {\n AreaCode,\n AreaCodeRequest,\n AreaCodesFilter,\n Gender,\n GenderRequest,\n GendersFilter\n} from \"@/interfaces/Catalogs\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\nimport { FilterBuilder, type FilterGroupsModel } from \"@/utils/FilterBuilder\";\n\n/**\n * Servicio para gestionar catálogos públicos.\n * No requiere autenticación.\n */\n\n//Validado, se integró CAT_Genders y CAT_AreaCodes\nexport class CatalogService {\n private api: API;\n private readonly BASE_PATH = 'catalogs';\n\n constructor(api: API) {\n this.api = api;\n }\n\n // #region GENDERS\n\n /**\n * Obtiene todos los géneros con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getGenders(filter?: GendersFilter): Promise<ResponseModel<Gender[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/genders`, filter);\n return this.api.executeGET<Gender[]>(endpoint, false);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para géneros.\n */\n async getGendersFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/genders/filters`, false);\n }\n\n /**\n * Obtiene un género por su ID.\n * @param id - ID del género\n */\n async getGenderById(id: number): Promise<ResponseModel<Gender>> {\n return this.api.executeGET<Gender>(`${this.BASE_PATH}/genders/${id}`, false);\n }\n\n /**\n * Crea un nuevo género.\n * @param request - Datos del género a crear\n */\n async createGender(request: GenderRequest): Promise<ResponseModel<Gender>> {\n return this.api.executePOST<Gender>(`${this.BASE_PATH}/genders`, request);\n }\n\n /**\n * Actualiza un género existente.\n * @param id - ID del género a actualizar\n * @param request - Nuevos datos del género\n */\n async updateGender(id: number, request: GenderRequest): Promise<ResponseModel<Gender>> {\n return this.api.executePUT<Gender>(`${this.BASE_PATH}/genders/${id}`, request);\n }\n\n /**\n * Elimina un género.\n * @param id - ID del género a eliminar\n */\n async deleteGender(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/genders/${id}`);\n }\n\n // #endregion\n\n // #region AREA CODES\n\n /**\n * Obtiene todos los códigos de área con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getAreaCodes(filter?: AreaCodesFilter): Promise<ResponseModel<AreaCode[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/area-codes`, filter);\n return this.api.executeGET<AreaCode[]>(endpoint, false);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para códigos de área.\n */\n async getAreaCodesFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/area-codes/filters`, false);\n }\n\n /**\n * Obtiene un código de área por su ID.\n * @param id - ID del código de área\n */\n async getAreaCodeById(id: number): Promise<ResponseModel<AreaCode>> {\n return this.api.executeGET<AreaCode>(`${this.BASE_PATH}/area-codes/${id}`, false);\n }\n\n /**\n * Crea un nuevo código de área.\n * @param request - Datos del código de área a crear\n */\n async createAreaCode(request: AreaCodeRequest): Promise<ResponseModel<AreaCode>> {\n return this.api.executePOST<AreaCode>(`${this.BASE_PATH}/area-codes`, request);\n }\n\n /**\n * Actualiza un código de área existente.\n * @param id - ID del código de área a actualizar\n * @param request - Nuevos datos del código de área\n */\n async updateAreaCode(id: number, request: AreaCodeRequest): Promise<ResponseModel<AreaCode>> {\n return this.api.executePUT<AreaCode>(`${this.BASE_PATH}/area-codes/${id}`, request);\n }\n\n /**\n * Activa o desactiva un código de área.\n * @param id - ID del código de área\n */\n async toggleAreaCodeStatus(id: number): Promise<ResponseModel<AreaCode>> {\n return this.api.executePUT<AreaCode>(`${this.BASE_PATH}/area-codes/${id}/toggle-status`);\n }\n\n /**\n * Elimina un código de área.\n * @param id - ID del código de área a eliminar\n */\n async deleteAreaCode(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/area-codes/${id}`);\n }\n\n // #endregion\n}\n","import { API } from \"@/core/API\";\nimport {\n InventoryProvider,\n InventoryProviderRequest,\n InventoryProvidersFilter,\n InventoryStatus,\n InventoryStatusRequest,\n InventoryStatusesFilter,\n Location,\n LocationsFilter,\n LocationsRequest,\n Material,\n MaterialRequest,\n MaterialsFilter,\n Packing,\n PackingRequest,\n PackingsFilter\n} from \"@/interfaces/Inventory\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\nimport { FilterBuilder, type FilterGroupsModel } from \"@/utils/FilterBuilder\";\n\n/**\n * Servicio para gestionar inventario: ubicaciones, estatus, empaques y materiales.\n */\n\n//Validado, se integró: Locations, CAT_InventoryStatuses, CAT_Packings, CAT_Materials, CAT_Providers\nexport class InventoryService {\n private api: API;\n private readonly BASE_PATH = 'inventory';\n\n constructor(api: API) {\n this.api = api;\n }\n\n // #region LOCATIONS\n\n /**\n * Obtiene todas las ubicaciones con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getLocations(filter?: LocationsFilter): Promise<ResponseModel<Location[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/locations`, filter);\n return this.api.executeGET<Location[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para ubicaciones.\n */\n async getLocationFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/locations/filters`, true);\n }\n\n /**\n * Obtiene una ubicación por su ID.\n * @param id - ID de la ubicación\n */\n async getLocationById(id: number): Promise<ResponseModel<Location>> {\n return this.api.executeGET<Location>(`${this.BASE_PATH}/locations/${id}`, true);\n }\n\n /**\n * Crea una nueva ubicación.\n * @param request - Datos de la ubicación a crear\n */\n async createLocation(request: LocationsRequest): Promise<ResponseModel<Location>> {\n return this.api.executePOST<Location>(`${this.BASE_PATH}/locations`, request);\n }\n\n /**\n * Actualiza una ubicación existente.\n * @param id - ID de la ubicación a actualizar\n * @param request - Nuevos datos de la ubicación\n */\n async updateLocation(id: number, request: LocationsRequest): Promise<ResponseModel<Location>> {\n return this.api.executePUT<Location>(`${this.BASE_PATH}/locations/${id}`, request);\n }\n\n /**\n * Activa o desactiva una ubicación.\n * @param id - ID de la ubicación\n */\n async toggleLocationStatus(id: number): Promise<ResponseModel<Location>> {\n return this.api.executePUT<Location>(`${this.BASE_PATH}/locations/${id}/toggle-status`);\n }\n\n /**\n * Elimina una ubicación.\n * @param id - ID de la ubicación a eliminar\n */\n async deleteLocation(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/locations/${id}`);\n }\n\n // #endregion\n\n // #region STATUSES\n\n /**\n * Obtiene todos los estatus de inventario con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getStatuses(filter?: InventoryStatusesFilter): Promise<ResponseModel<InventoryStatus[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/statuses`, filter);\n return this.api.executeGET<InventoryStatus[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para estatus de inventario.\n */\n async getStatusFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/statuses/filters`, true);\n }\n\n /**\n * Obtiene un estatus de inventario por su ID.\n * @param id - ID del estatus\n */\n async getStatusById(id: number): Promise<ResponseModel<InventoryStatus>> {\n return this.api.executeGET<InventoryStatus>(`${this.BASE_PATH}/catalogs/statuses/${id}`, true);\n }\n\n /**\n * Crea un nuevo estatus de inventario.\n * @param request - Datos del estatus a crear\n */\n async createStatus(request: InventoryStatusRequest): Promise<ResponseModel<InventoryStatus>> {\n return this.api.executePOST<InventoryStatus>(`${this.BASE_PATH}/catalogs/statuses`, request);\n }\n\n /**\n * Actualiza un estatus de inventario existente.\n * @param id - ID del estatus a actualizar\n * @param request - Nuevos datos del estatus\n */\n async updateStatus(id: number, request: InventoryStatusRequest): Promise<ResponseModel<InventoryStatus>> {\n return this.api.executePUT<InventoryStatus>(`${this.BASE_PATH}/catalogs/statuses/${id}`, request);\n }\n\n /**\n * Elimina un estatus de inventario.\n * @param id - ID del estatus a eliminar\n */\n async deleteStatus(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/statuses/${id}`);\n }\n\n // #endregion\n\n // #region PACKINGS\n\n /**\n * Obtiene todos los empaques con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getPackings(filter?: PackingsFilter): Promise<ResponseModel<Packing[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/packings`, filter);\n return this.api.executeGET<Packing[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para empaques.\n */\n async getPackingFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/packings/filters`, true);\n }\n\n /**\n * Obtiene un empaque por su ID.\n * @param id - ID del empaque\n */\n async getPackingById(id: number): Promise<ResponseModel<Packing>> {\n return this.api.executeGET<Packing>(`${this.BASE_PATH}/catalogs/packings/${id}`, true);\n }\n\n /**\n * Crea un nuevo empaque.\n * @param request - Datos del empaque a crear\n */\n async createPacking(request: PackingRequest): Promise<ResponseModel<Packing>> {\n return this.api.executePOST<Packing>(`${this.BASE_PATH}/catalogs/packings`, request);\n }\n\n /**\n * Actualiza un empaque existente.\n * @param id - ID del empaque a actualizar\n * @param request - Nuevos datos del empaque\n */\n async updatePacking(id: number, request: PackingRequest): Promise<ResponseModel<Packing>> {\n return this.api.executePUT<Packing>(`${this.BASE_PATH}/catalogs/packings/${id}`, request);\n }\n\n /**\n * Activa o desactiva un empaque.\n * @param id - ID del empaque\n */\n async togglePackingStatus(id: number): Promise<ResponseModel<Packing>> {\n return this.api.executePUT<Packing>(`${this.BASE_PATH}/catalogs/packings/${id}/toggle-status`);\n }\n\n /**\n * Elimina un empaque.\n * @param id - ID del empaque a eliminar\n */\n async deletePacking(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/packings/${id}`);\n }\n\n // #endregion\n\n // #region MATERIALS\n\n /**\n * Obtiene todos los materiales con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getMaterials(filter?: MaterialsFilter): Promise<ResponseModel<Material[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/materials`, filter);\n return this.api.executeGET<Material[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para materiales.\n */\n async getMaterialFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/materials/filters`, true);\n }\n\n /**\n * Obtiene un material por su ID.\n * @param id - ID del material\n */\n async getMaterialById(id: number): Promise<ResponseModel<Material>> {\n return this.api.executeGET<Material>(`${this.BASE_PATH}/catalogs/materials/${id}`, true);\n }\n\n /**\n * Crea un nuevo material.\n * @param request - Datos del material a crear\n */\n async createMaterial(request: MaterialRequest): Promise<ResponseModel<Material>> {\n return this.api.executePOST<Material>(`${this.BASE_PATH}/catalogs/materials`, request);\n }\n\n /**\n * Actualiza un material existente.\n * @param id - ID del material a actualizar\n * @param request - Nuevos datos del material\n */\n async updateMaterial(id: number, request: MaterialRequest): Promise<ResponseModel<Material>> {\n return this.api.executePUT<Material>(`${this.BASE_PATH}/catalogs/materials/${id}`, request);\n }\n\n /**\n * Elimina un material.\n * @param id - ID del material a eliminar\n */\n async deleteMaterial(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/materials/${id}`);\n }\n\n // #endregion\n\n // #region PROVIDERS\n\n /**\n * Obtiene todos los proveedores con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getProviders(filter?: InventoryProvidersFilter): Promise<ResponseModel<InventoryProvider[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/providers`, filter);\n return this.api.executeGET<InventoryProvider[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para proveedores.\n */\n async getProviderFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/providers/filters`, true);\n }\n\n /**\n * Obtiene un proveedor por su ID.\n * @param id - ID del proveedor\n */\n async getProviderById(id: number): Promise<ResponseModel<InventoryProvider>> {\n return this.api.executeGET<InventoryProvider>(`${this.BASE_PATH}/catalogs/providers/${id}`, true);\n }\n\n /**\n * Crea un nuevo proveedor.\n * @param request - Datos del proveedor a crear\n */\n async createProvider(request: InventoryProviderRequest): Promise<ResponseModel<InventoryProvider>> {\n return this.api.executePOST<InventoryProvider>(`${this.BASE_PATH}/catalogs/providers`, request);\n }\n\n /**\n * Actualiza un proveedor existente.\n * @param id - ID del proveedor a actualizar\n * @param request - Nuevos datos del proveedor\n */\n async updateProvider(id: number, request: InventoryProviderRequest): Promise<ResponseModel<InventoryProvider>> {\n return this.api.executePUT<InventoryProvider>(`${this.BASE_PATH}/catalogs/providers/${id}`, request);\n }\n\n /**\n * Activa o desactiva un proveedor.\n * @param id - ID del proveedor\n */\n async toggleProviderStatus(id: number): Promise<ResponseModel<InventoryProvider>> {\n return this.api.executePUT<InventoryProvider>(`${this.BASE_PATH}/catalogs/providers/${id}/toggle-status`);\n }\n\n /**\n * Elimina un proveedor.\n * @param id - ID del proveedor a eliminar\n */\n async deleteProvider(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/providers/${id}`);\n }\n\n // #endregion\n}\n","import { API } from \"@/core/API\";\nimport {\n Endpoint,\n EndpointRequest,\n EndpointsFilter,\n Module,\n ModuleRequest,\n ModulesFilter,\n UIRoute,\n UIRouteRequest,\n UIRoutesFilter\n} from \"@/interfaces/System\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\nimport { FilterBuilder, type FilterGroupsModel } from \"@/utils/FilterBuilder\";\n\n/**\n * Servicio para gestionar las configuraciones del sistema.\n */\n\n//Validado, todos los métodos integrados.\nexport class SystemService {\n private api: API;\n private readonly BASE_PATH = 'system';\n\n constructor(api: API) {\n this.api = api;\n }\n\n // #region MODULES\n\n /**\n * Obtiene todos los módulos con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getModules(filter?: ModulesFilter): Promise<ResponseModel<Module[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/modules`, filter);\n return this.api.executeGET<Module[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para módulos.\n */\n async getModulesFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/modules/filters`, true);\n }\n\n /**\n * Obtiene un módulo por su ID.\n * @param id - ID del módulo\n */\n async getModuleById(id: number): Promise<ResponseModel<Module>> {\n return this.api.executeGET<Module>(`${this.BASE_PATH}/modules/${id}`, true);\n }\n\n /**\n * Crea un nuevo módulo.\n * @param request - Datos del módulo a crear\n */\n async createModule(request: ModuleRequest): Promise<ResponseModel<Module>> {\n return this.api.executePOST<Module>(`${this.BASE_PATH}/modules`, request);\n }\n\n /**\n * Actualiza un módulo existente.\n * @param id - ID del módulo a actualizar\n * @param request - Nuevos datos del módulo\n */\n async updateModule(id: number, request: ModuleRequest): Promise<ResponseModel<Module>> {\n return this.api.executePUT<Module>(`${this.BASE_PATH}/modules/${id}`, request);\n }\n\n /**\n * Activa o desactiva un módulo.\n * @param id - ID del módulo\n */\n async toggleModuleStatus(id: number): Promise<ResponseModel<Module>> {\n return this.api.executePUT<Module>(`${this.BASE_PATH}/modules/${id}/toggle-status`);\n }\n\n /**\n * Elimina un módulo.\n * @param id - ID del módulo a eliminar\n */\n async deleteModule(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/modules/${id}`);\n }\n\n // #endregion\n\n // #region ENDPOINTS\n\n /**\n * Obtiene todos los endpoints con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getEndpoints(filter?: EndpointsFilter): Promise<ResponseModel<Endpoint[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/endpoints`, filter);\n return this.api.executeGET<Endpoint[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para endpoints.\n */\n async getEndpointsFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/endpoints/filters`, true);\n }\n\n /**\n * Obtiene los módulos disponibles (valores únicos del primer segmento del path).\n */\n async getEndpointModules(): Promise<ResponseModel<string[]>> {\n return this.api.executeGET<string[]>(`${this.BASE_PATH}/endpoints/modules`, true);\n }\n\n /**\n * Obtiene un endpoint por su ID.\n * @param id - ID del endpoint\n */\n async getEndpointById(id: number): Promise<ResponseModel<Endpoint>> {\n return this.api.executeGET<Endpoint>(`${this.BASE_PATH}/endpoints/${id}`, true);\n }\n\n /**\n * Crea un nuevo endpoint.\n * @param request - Datos del endpoint a crear\n */\n async createEndpoint(request: EndpointRequest): Promise<ResponseModel<Endpoint>> {\n return this.api.executePOST<Endpoint>(`${this.BASE_PATH}/endpoints`, request);\n }\n\n /**\n * Actualiza un endpoint existente.\n * @param id - ID del endpoint a actualizar\n * @param request - Nuevos datos del endpoint\n */\n async updateEndpoint(id: number, request: EndpointRequest): Promise<ResponseModel<Endpoint>> {\n return this.api.executePUT<Endpoint>(`${this.BASE_PATH}/endpoints/${id}`, request);\n }\n\n /**\n * Activa o desactiva un endpoint.\n * @param id - ID del endpoint\n */\n async toggleEndpointStatus(id: number): Promise<ResponseModel<Endpoint>> {\n return this.api.executePUT<Endpoint>(`${this.BASE_PATH}/endpoints/${id}/toggle-status`);\n }\n\n /**\n * Elimina un endpoint.\n * @param id - ID del endpoint a eliminar\n */\n async deleteEndpoint(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/endpoints/${id}`);\n }\n\n // #endregion\n\n // #region UI ROUTES\n\n /**\n * Obtiene todas las rutas de UI con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getUIRoutes(filter?: UIRoutesFilter): Promise<ResponseModel<UIRoute[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/ui-routes`, filter);\n return this.api.executeGET<UIRoute[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para rutas de UI.\n */\n async getUIRoutesFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/ui-routes/filters`, true);\n }\n\n /**\n * Obtiene una ruta de UI por su ID.\n * @param id - ID de la ruta\n */\n async getUIRouteById(id: number): Promise<ResponseModel<UIRoute>> {\n return this.api.executeGET<UIRoute>(`${this.BASE_PATH}/ui-routes/${id}`, true);\n }\n\n /**\n * Crea una nueva ruta de UI.\n * @param request - Datos de la ruta a crear\n */\n async createUIRoute(request: UIRouteRequest): Promise<ResponseModel<UIRoute>> {\n return this.api.executePOST<UIRoute>(`${this.BASE_PATH}/ui-routes`, request);\n }\n\n /**\n * Actualiza una ruta de UI existente.\n * @param id - ID de la ruta a actualizar\n * @param request - Nuevos datos de la ruta\n */\n async updateUIRoute(id: number, request: UIRouteRequest): Promise<ResponseModel<UIRoute>> {\n return this.api.executePUT<UIRoute>(`${this.BASE_PATH}/ui-routes/${id}`, request);\n }\n\n /**\n * Activa o desactiva una ruta de UI.\n * @param id - ID de la ruta\n */\n async toggleUIRouteStatus(id: number): Promise<ResponseModel<UIRoute>> {\n return this.api.executePUT<UIRoute>(`${this.BASE_PATH}/ui-routes/${id}/toggle-status`);\n }\n\n /**\n * Elimina una ruta de UI.\n * @param id - ID de la ruta a eliminar\n */\n async deleteUIRoute(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/ui-routes/${id}`);\n }\n\n // #endregion\n}\n","import { API } from \"@/core/API\";\nimport {\n AdminAuthentication,\n AdminUser,\n ChangePasswordAdminRequest,\n UserAdminFilter,\n UserAdminRequest,\n UserAdminUpdateRequest,\n UserAuthAdminRequest,\n UserAuthUpdateRequest\n} from \"@/interfaces/User/Admin\";\nimport { ChangePasswordUserRequest } from \"@/interfaces/User/ChangePassword/ChangePasswordUserRequest\";\nimport {\n Role,\n RoleRequest,\n RolesFilter\n} from \"@/interfaces/User/Roles/RolesInterface\";\nimport { UserBasicResponse } from \"@/interfaces/User/UserBasicResponse\";\nimport { UserDataUpdateRequest } from \"@/interfaces/User/UserDataUpdateRequest\";\nimport { UserProfileResponse } from \"@/interfaces/User/UserProfileResponse\";\nimport {\n UserType,\n UserTypeRequest,\n UserTypesFilter\n} from \"@/interfaces/User/UserTypes/UserTypesInterface\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\nimport { FilterBuilder, type FilterGroupsModel } from \"@/utils/FilterBuilder\";\n\n//Validado, todos los métodos fueron integrados.\nexport class UserService {\n private api: API;\n private readonly BASE_PATH = 'users';\n\n constructor(\n api: API,\n ){\n this.api = api;\n };\n\n /**\n * Obtiene la información básica del usuario.\n * @returns retorna un objeto con la información básica del usuario\n */\n async me(): Promise<ResponseModel<UserBasicResponse>> {\n const response: ResponseModel<UserBasicResponse> = await this.api.executeGET(\n `${this.BASE_PATH}/me`,\n true,\n );\n\n return response;\n };\n\n /**\n * Obtiene la información general del usuario para la vista de perfil.\n * @returns\n */\n async profile(): Promise<ResponseModel<UserProfileResponse>>{\n const response: ResponseModel<UserProfileResponse> = await this.api.executeGET(\n `${this.BASE_PATH}/profile`,\n true\n );\n\n return response;\n }\n\n async changePasswordUser(request: ChangePasswordUserRequest): Promise<ResponseModel>{\n return this.api.executePUT(`${this.BASE_PATH}/me/password`, request);\n }\n\n async updateUserData(request: UserDataUpdateRequest): Promise<ResponseModel>{\n return this.api.executePUT(`${this.BASE_PATH}/me`, request);\n }\n\n // #region Admin CRUD\n\n /**\n * Crea un nuevo usuario administrador.\n * @param request - Datos del nuevo administrador\n */\n async newAdminUser(request: UserAdminRequest): Promise<ResponseModel<AdminUser>> {\n return this.api.executePOST<AdminUser>(`${this.BASE_PATH}/admin`, request);\n }\n\n /**\n * Crea la autenticación para un usuario.\n * @param request - Datos de autenticación del usuario\n */\n async createUserAuthentication(request: UserAuthAdminRequest): Promise<ResponseModel<AdminAuthentication>> {\n return this.api.executePOST<AdminAuthentication>(`${this.BASE_PATH}/admin/authentication`, request);\n }\n\n /**\n * Cambia la contraseña de un administrador.\n * @param id - ID del usuario\n * @param request - Nueva contraseña\n */\n async changePasswordAdmin(id: number, request: ChangePasswordAdminRequest): Promise<ResponseModel> {\n return this.api.executePOST(`${this.BASE_PATH}/admin/${id}/password`, request);\n }\n\n /**\n * Obtiene todos los administradores con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getAllAdmins(filter?: UserAdminFilter): Promise<ResponseModel<AdminUser[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/admin`, filter);\n return this.api.executeGET<AdminUser[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para administradores.\n */\n async getAdminFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/admin/filters`, true);\n }\n\n /**\n * Obtiene un administrador por su ID.\n * @param id - ID del administrador\n */\n async getAdminById(id: number): Promise<ResponseModel<AdminUser>> {\n return this.api.executeGET<AdminUser>(`${this.BASE_PATH}/admin/${id}`, true);\n }\n\n /**\n * Obtiene la autenticación de un administrador.\n * @param id - ID del usuario\n */\n async getAdminAuthentication(id: number): Promise<ResponseModel<AdminAuthentication>> {\n return this.api.executeGET<AdminAuthentication>(`${this.BASE_PATH}/admin/authentication/${id}`, true);\n }\n\n /**\n * Actualiza un administrador existente.\n * @param id - ID del administrador\n * @param request - Nuevos datos del administrador\n */\n async updateAdmin(id: number, request: UserAdminUpdateRequest): Promise<ResponseModel<AdminUser>> {\n return this.api.executePUT<AdminUser>(`${this.BASE_PATH}/admin/${id}`, request);\n }\n\n /**\n * Activa o desactiva un administrador.\n * @param id - ID del administrador\n */\n async toggleAdminStatus(id: number): Promise<ResponseModel<AdminUser>> {\n return this.api.executePUT<AdminUser>(`${this.BASE_PATH}/admin/${id}/toggle-status`);\n }\n\n /**\n * Actualiza la autenticación de un administrador.\n * @param id - ID del usuario\n * @param request - Nuevos datos de autenticación\n */\n async updateAdminAuthentication(id: number, request: UserAuthUpdateRequest): Promise<ResponseModel<AdminAuthentication>> {\n return this.api.executePUT<AdminAuthentication>(`${this.BASE_PATH}/admin/authentication/${id}`, request);\n }\n\n // #endregion\n\n // #region User Types\n\n /**\n * Obtiene todos los tipos de usuario con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getUserTypes(filter?: UserTypesFilter): Promise<ResponseModel<UserType[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/user-types`, filter);\n return this.api.executeGET<UserType[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para tipos de usuario.\n */\n async getUserTypesFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/user-types/filters`, true);\n }\n\n /**\n * Obtiene un tipo de usuario por su ID.\n * @param id - ID del tipo de usuario\n */\n async getUserTypeById(id: number): Promise<ResponseModel<UserType>> {\n return this.api.executeGET<UserType>(`${this.BASE_PATH}/catalogs/user-types/${id}`, true);\n }\n\n /**\n * Crea un nuevo tipo de usuario.\n * @param request - Datos del tipo de usuario a crear\n */\n async createUserType(request: UserTypeRequest): Promise<ResponseModel<UserType>> {\n return this.api.executePOST<UserType>(`${this.BASE_PATH}/catalogs/user-types`, request);\n }\n\n /**\n * Actualiza un tipo de usuario existente.\n * @param id - ID del tipo de usuario a actualizar\n * @param request - Nuevos datos del tipo de usuario\n */\n async updateUserType(id: number, request: UserTypeRequest): Promise<ResponseModel<UserType>> {\n return this.api.executePUT<UserType>(`${this.BASE_PATH}/catalogs/user-types/${id}`, request);\n }\n\n /**\n * Elimina un tipo de usuario.\n * @param id - ID del tipo de usuario a eliminar\n */\n async deleteUserType(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/user-types/${id}`);\n }\n\n // #endregion\n\n // #region Roles\n\n /**\n * Obtiene todos los roles con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getRoles(filter?: RolesFilter): Promise<ResponseModel<Role[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/roles`, filter);\n return this.api.executeGET<Role[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para roles.\n */\n async getRolesFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/roles/filters`, true);\n }\n\n /**\n * Obtiene un rol por su ID.\n * @param id - ID del rol\n */\n async getRoleById(id: number): Promise<ResponseModel<Role>> {\n return this.api.executeGET<Role>(`${this.BASE_PATH}/catalogs/roles/${id}`, true);\n }\n\n /**\n * Obtiene los roles asociados a un tipo de usuario.\n * @param userTypeId - ID del tipo de usuario\n */\n async getRolesByUserType(userTypeId: number): Promise<ResponseModel<Role[]>> {\n return this.api.executeGET<Role[]>(`${this.BASE_PATH}/catalogs/roles/user-type/${userTypeId}`, true);\n }\n\n /**\n * Crea un nuevo rol.\n * @param request - Datos del rol a crear\n */\n async createRole(request: RoleRequest): Promise<ResponseModel<Role>> {\n return this.api.executePOST<Role>(`${this.BASE_PATH}/catalogs/roles`, request);\n }\n\n /**\n * Actualiza un rol existente.\n * @param id - ID del rol a actualizar\n * @param request - Nuevos datos del rol\n */\n async updateRole(id: number, request: RoleRequest): Promise<ResponseModel<Role>> {\n return this.api.executePUT<Role>(`${this.BASE_PATH}/catalogs/roles/${id}`, request);\n }\n\n /**\n * Activa o desactiva un rol.\n * @param id - ID del rol\n */\n async toggleRoleStatus(id: number): Promise<ResponseModel<Role>> {\n return this.api.executePUT<Role>(`${this.BASE_PATH}/catalogs/roles/${id}/toggle-status`);\n }\n\n /**\n * Elimina un rol.\n * @param id - ID del rol a eliminar\n */\n async deleteRole(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/roles/${id}`);\n }\n\n // #endregion\n}\n","import { API } from \"./core/API\";\nimport { CryptoService } from \"./core/CryptoService\";\nimport { TokenManager } from \"./core/TokenManager\";\nimport { AuthInterceptor } from \"./core/interceptors/AuthInterceptor\";\nimport { AuthService } from \"./services/AuthService\";\nimport { CatalogService } from \"./services/CatalogService\";\nimport { InventoryService } from \"./services/InventoryService\";\nimport { SystemService } from \"./services/SystemService\";\nimport { UserService } from \"./services/UserService\";\nimport { ServiceProperties } from \"./types/ServiceProperties\";\nimport { TokenData } from \"./types/TokenData\";\n\n/**\n * SDK principal de FalconHUB\n */\nexport class FalconHUBSDK {\n public auth: AuthService;\n public user: UserService;\n public system: SystemService;\n public inventory: InventoryService;\n public catalog: CatalogService;\n\n private serviceProperties: ServiceProperties;\n private cryptoService: CryptoService;\n private tokenManager: TokenManager;\n private authInterceptor: AuthInterceptor | null;\n private api: API;\n\n constructor(serviceProperties: ServiceProperties) {\n this.serviceProperties = serviceProperties;\n\n this.cryptoService = new CryptoService();\n\n const autoRefreshConfig = this.normalizeAutoRefreshConfig(this.serviceProperties.autoRefresh);\n\n this.tokenManager = new TokenManager(\n this.serviceProperties.onTokensUpdated,\n this.serviceProperties.onSessionExpiring,\n async () => {\n await this.auth.logout();\n },\n async () => {\n const currentTokens = this.tokenManager.getTokens();\n if (!currentTokens?.refreshToken) return false;\n\n try {\n const response = await this.auth.refreshTokens({\n refreshToken: currentTokens.refreshToken,\n rememberMe: currentTokens.rememberMe\n });\n return response.success === true;\n } catch {\n return false;\n }\n },\n autoRefreshConfig.enabled ? autoRefreshConfig.thresholdMinutes : undefined\n );\n\n if (autoRefreshConfig.enabled) {\n this.authInterceptor = new AuthInterceptor({\n enabled: true,\n thresholdMinutes: autoRefreshConfig.thresholdMinutes,\n isTokenExpiringSoon: () => this.tokenManager.isTokenExpiringSoon(autoRefreshConfig.thresholdMinutes),\n hasValidTokens: () => this.tokenManager.hasValidTokens(),\n shouldAutoRefresh: () => this.tokenManager.shouldAutoRefresh(),\n refreshSession: async () => {\n await this.auth.validateSession();\n }\n });\n } else {\n this.authInterceptor = null;\n }\n\n this.api = new API(\n this.serviceProperties,\n this.cryptoService,\n this.authInterceptor,\n () => this.tokenManager.getAccessToken(),\n () => this.tokenManager.getRefreshToken()\n );\n\n this.auth = new AuthService(\n this.serviceProperties,\n this.tokenManager,\n this.cryptoService,\n this.api\n );\n\n this.user = new UserService(\n this.api\n );\n\n this.system = new SystemService(\n this.api\n );\n\n this.inventory = new InventoryService(\n this.api\n );\n\n this.catalog = new CatalogService(\n this.api\n );\n }\n\n private normalizeAutoRefreshConfig(\n config: ServiceProperties[\"autoRefresh\"]\n ): { enabled: boolean; thresholdMinutes: number } {\n if (typeof config === \"boolean\") {\n return { enabled: config, thresholdMinutes: 5 };\n }\n if (typeof config === \"object\" && config !== null) {\n return {\n enabled: config.enabled,\n thresholdMinutes: config.thresholdMinutes ?? 5\n };\n }\n return { enabled: true, thresholdMinutes: 5 };\n }\n\n /**\n * Inyecta tokens desde storage externo (cookies/localStorage/etc)\n * @param expiresAt - Timestamp en milisegundos\n */\n setTokensFromExternal(\n accessToken: string,\n refreshToken: string,\n expiresAt: number,\n rememberMe: boolean = false\n ): void {\n const tokens: TokenData = {\n accessToken,\n refreshToken,\n expiresAt,\n rememberMe\n };\n\n this.tokenManager.setTokensSilent(tokens);\n }\n\n /**\n * Obtiene los tokens actuales\n */\n getTokens(): TokenData | null {\n return this.tokenManager.getTokens();\n }\n\n /**\n * Verifica si el usuario está autenticado\n */\n isAuthenticated(): boolean {\n return this.tokenManager.hasValidTokens();\n }\n\n /**\n * Verifica si la sesión está por expirar\n */\n isSessionExpiringSoon(thresholdMinutes: number = 5): boolean {\n return this.tokenManager.isTokenExpiringSoon(thresholdMinutes);\n }\n\n /**\n * Obtiene el tiempo restante hasta la expiración en milisegundos\n */\n getTimeUntilExpiry(): number | null {\n return this.tokenManager.getTimeUntilExpiry();\n }\n}\n","import CryptoJS from 'crypto-js';\n\nexport function decrypt(encryptedBase64: string, secret: string, timestamp: string): string {\n const fullKey = `${secret}:${timestamp}`;\n // Generate key using SHA256\n const key = CryptoJS.SHA256(fullKey);\n\n // Parse total encrypted data from Base64\n const allData = CryptoJS.enc.Base64.parse(encryptedBase64);\n\n // Extract IV (first 16 bytes = 4 words)\n const iv = CryptoJS.lib.WordArray.create(allData.words.slice(0, 4), 16);\n\n // Extract ciphertext (remaining bytes)\n const ciphertext = CryptoJS.lib.WordArray.create(allData.words.slice(4), allData.sigBytes - 16);\n\n // Decrypt using AES-256-CBC\n // We use PKCS7 padding as it's the default in Node.js createDecipheriv for aes-256-cbc\n const decrypted = CryptoJS.AES.decrypt(\n { ciphertext: ciphertext } as any,\n key,\n {\n iv: iv,\n mode: CryptoJS.mode.CBC,\n padding: CryptoJS.pad.Pkcs7\n }\n );\n\n return decrypted.toString(CryptoJS.enc.Utf8);\n}\n"],"mappings":"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","names":["CryptoJS"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/API.ts","../src/core/CryptoService.ts","../src/core/TokenManager.ts","../src/core/interceptors/AuthInterceptor.ts","../src/types/ErrorResponse.ts","../src/services/AuthService.ts","../src/utils/FilterBuilder.ts","../src/services/CatalogService.ts","../src/services/InventoryService.ts","../src/services/SystemService.ts","../src/services/UserService.ts","../src/FalconHUBSDK.ts","../src/services/ProductService.ts","../src/core/Encryption.ts"],"sourcesContent":["import { ServiceProperties } from \"@/types/ServiceProperties\";\nimport { CryptoService } from \"./CryptoService\";\nimport { MethodTypes, RequestOptions } from \"@/types/RequestOptions\";\nimport { RequestConfig } from \"@/types/RequestConfig\";\nimport { AuthInterceptor } from \"./interceptors/AuthInterceptor\";\nimport { InterceptorContext } from \"@/core/interceptors/types/InterceptorContext\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\n\n\n/**\n * Clase base para la ejecución de request HTTP al API\n */\nexport class API {\n private properties: ServiceProperties;\n private cryptoService: CryptoService;\n private authInterceptor: AuthInterceptor | null;\n\n private getAccessToken: () => string | null;\n private getRefreshToken: () => string | null;\n\n constructor(\n properties: ServiceProperties,\n cryptoService: CryptoService,\n authInterceptor: AuthInterceptor | null,\n getAccessToken: () => string | null,\n getRefreshToken: () => string | null\n ) {\n this.properties = properties;\n this.cryptoService = cryptoService;\n this.getAccessToken = getAccessToken;\n this.getRefreshToken = getRefreshToken;\n this.authInterceptor = authInterceptor;\n };\n\n /**\n * Ejecuta una request HTTP al API\n *\n * @param options - Opciones de la request\n * @returns Respuesta del tipo ResponseModel\n */\n private async apiExecute<T>(options: RequestOptions): Promise<ResponseModel<T>> {\n const {\n endpoint,\n method,\n body,\n requiresAuth,\n timeStamp\n } = options;\n\n const context: InterceptorContext = {\n requestId: this.cryptoService.generateUniqueId(),\n startTime: Date.now(),\n retryCount: 0,\n metadata: {}\n };\n\n try {\n const url = `${this.properties.url}/${endpoint}`;\n const headers: Record<string, string> = {};\n\n if (body && method !== 'GET') {\n headers['Content-Type'] = 'application/json';\n };\n\n const accessToken = this.getAccessToken();\n if (accessToken) {\n headers['Authorization'] = `Bearer ${accessToken}`;\n };\n\n const newTimeStamp = timeStamp || new Date().toISOString();\n\n headers[\"X-Origin-Request\"] = this.properties.originRequest;\n headers['X-Timestamp'] = newTimeStamp;\n headers[\"X-Domain\"] = this.properties.domain;\n headers[\"X-Device\"] = this.properties.device;\n headers[\"X-Source\"] = this.properties.source;\n\n let bodyString: string | undefined;\n if (body && method !== 'GET') {\n bodyString = JSON.stringify(body);\n };\n\n const requestConfig: RequestConfig = {\n url,\n method,\n headers,\n body: bodyString,\n requiresAuth\n };\n\n const modifiedConfig = this.authInterceptor\n ? await this.authInterceptor.onRequest(requestConfig, context)\n : requestConfig;\n\n const requestInit: RequestInit = {\n method: modifiedConfig.method,\n headers: modifiedConfig.headers,\n mode: 'cors',\n credentials: 'omit'\n };\n\n if (modifiedConfig.body && modifiedConfig.method !== 'GET') {\n requestInit.body = typeof modifiedConfig.body === 'string'\n ? modifiedConfig.body\n : JSON.stringify(modifiedConfig.body);\n };\n\n const response = await fetch(\n modifiedConfig.url,\n requestInit\n );\n\n const newAccessToken = response.headers.get('X-New-Access-Token');\n const newRefreshToken = response.headers.get('X-New-Refresh-Token');\n\n if (newAccessToken || newRefreshToken) {\n this.properties.onTokensRefreshed?.({\n accessToken: newAccessToken,\n refreshToken: newRefreshToken\n });\n };\n\n let result: any;\n\n try {\n result = await response.json();\n } catch (e) {\n // Fallback en caso de que la respuesta no sea un JSON válido (errores de servidor 500, 502, etc.)\n return {\n success: false,\n message: `Error de servidor (${response.status}: ${response.statusText || 'Formato de respuesta no reconocido'})`,\n data: null,\n responseTime: new Date().toISOString()\n };\n }\n\n // Manejo de errores de validación (RFC 9110)\n if (result && result.errors && typeof result.errors === 'object') {\n const errorMessages: string[] = [];\n\n Object.values(result.errors).forEach((errors: any) => {\n if (Array.isArray(errors)) {\n errorMessages.push(...errors);\n } else if (typeof errors === 'string') {\n errorMessages.push(errors);\n }\n });\n\n if (errorMessages.length > 0) {\n return {\n success: false,\n message: errorMessages.join(', '),\n data: result.data ?? null,\n responseTime: result.responseTime ?? new Date().toISOString()\n } as ResponseModel<T>;\n }\n }\n\n return result as ResponseModel<T>;\n\n } catch (error) {\n return {\n success: false,\n message: error instanceof Error ? error.message : 'Error inesperado durante la petición al API.',\n data: null,\n responseTime: new Date().toISOString()\n };\n };\n };\n\n\n //#region REQUEST METHODS\n\n async executeGET<T>(\n endpoint: string,\n requiresAuth: boolean = false\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method: 'GET',\n requiresAuth: requiresAuth\n });\n };\n\n async executePOST<T>(\n endpoint: string,\n body?: any,\n requiresAuth: boolean = true,\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method: 'POST',\n body,\n requiresAuth: requiresAuth\n });\n };\n\n async executePATCH<T>(\n endpoint: string,\n body?: any,\n requiresAuth: boolean = true,\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method: 'PATCH',\n body,\n requiresAuth: requiresAuth\n });\n };\n\n async executeDELETE<T>(\n endpoint: string,\n body?: any,\n requiresAuth: boolean = true,\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method: 'DELETE',\n body,\n requiresAuth: requiresAuth\n });\n };\n\n async executePUT<T>(\n endpoint: string,\n body?: any,\n requiresAuth: boolean = true\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method: 'PUT',\n body,\n requiresAuth: requiresAuth,\n });\n };\n\n async executePublicRequest<T>(\n endpoint: string,\n method: MethodTypes,\n body?: any,\n timestamp?: string\n ): Promise<ResponseModel<T>> {\n return this.apiExecute<T>({\n endpoint,\n method,\n body,\n requiresAuth: false,\n timeStamp: timestamp\n });\n };\n\n //#endregion\n}\n","import * as CryptoJS from \"crypto-js\";\n\nexport class CryptoService {\n /**\n * Genera un hash SHA256 de un texto (útil para fingerprints)\n *\n * @param text - Texto a hashear\n * @returns Hash en formato hexadecimal\n */\n sha256(text: string): string {\n return CryptoJS.SHA256(text).toString(CryptoJS.enc.Hex);\n }\n\n /**\n * Genera un identificador único basado en timestamp y random\n * (útil para request IDs)\n *\n * @returns ID único\n */\n generateUniqueId(): string {\n const timestamp = Date.now().toString(36);\n const randomPart = Math.random().toString(36).substring(2, 15);\n return `${timestamp}-${randomPart}`;\n }\n}\n","import { TokenData } from \"@/types/TokenData\";\n\n/**\n * Manages authentication tokens.\n */\nexport class TokenManager {\n private tokens: TokenData | null = null;\n private onTokensChanged?: (tokens: TokenData | null) => void;\n private sessionCheckInterval: NodeJS.Timeout | null = null;\n private autoRefreshTimeout: NodeJS.Timeout | null = null;\n private onSessionExpiring?: (remainingMinutes: number) => void;\n private onSessionExpired?: () => Promise<void>;\n private onSessionRecovery?: () => Promise<boolean>;\n private hasNotifiedExpiring: boolean = false;\n private autoRefreshThresholdMinutes: number = 5;\n\n constructor(\n onTokensChanged?: (tokens: TokenData | null) => void,\n onSessionExpiring?: (remainingMinutes: number) => void,\n onSessionExpired?: () => Promise<void>,\n onSessionRecovery?: () => Promise<boolean>,\n autoRefreshThresholdMinutes?: number\n ) {\n this.onTokensChanged = onTokensChanged;\n this.onSessionExpiring = onSessionExpiring;\n this.onSessionExpired = onSessionExpired;\n this.onSessionRecovery = onSessionRecovery;\n this.autoRefreshThresholdMinutes = autoRefreshThresholdMinutes ?? 5;\n };\n\n /**\n * Guarda los tokens de autenticación y dispara el callback onTokensChanged.\n */\n setTokens(tokens: TokenData) {\n this.tokens = tokens;\n this.hasNotifiedExpiring = false;\n\n this.onTokensChanged?.(this.tokens);\n\n if (!tokens.rememberMe) {\n this.startExpirationCheck();\n this.stopAutoRefreshTimer();\n } else {\n this.stopExpirationCheck();\n this.scheduleAutoRefresh();\n };\n };\n\n /**\n * Guarda los tokens sin disparar el callback onTokensChanged.\n * Usar para inyectar tokens desde storage externo (cookies/localStorage).\n */\n setTokensSilent(tokens: TokenData) {\n this.tokens = tokens;\n this.hasNotifiedExpiring = false;\n\n if (!tokens.rememberMe) {\n this.startExpirationCheck();\n this.stopAutoRefreshTimer();\n } else {\n this.stopExpirationCheck();\n this.scheduleAutoRefresh();\n };\n };\n\n /**\n * Obtiene los tokens de autenticación almacenados.\n */\n getTokens(): TokenData | null {\n return this.tokens;\n };\n\n /**\n * Limpia los tokens de autenticación almacenados y dispara el callback onTokensChanged.\n */\n clearTokens() {\n this.stopExpirationCheck();\n this.stopAutoRefreshTimer();\n this.tokens = null;\n this.onTokensChanged?.(this.tokens);\n };\n\n /**\n * Valida si existen tokens y si el access token no ha expirado.\n */\n hasValidTokens(): boolean {\n if (!this.tokens) return false;\n\n return Date.now() < this.tokens.expiresAt;\n };\n\n /**\n * Valida si el access token expirará dentro del umbral especificado (en minutos).\n */\n isTokenExpiringSoon(thresholdMinutes: number): boolean {\n if (!this.tokens) return false;\n\n const thresholdMs = thresholdMinutes * 60 * 1000;\n const timeLeft = this.tokens.expiresAt - Date.now();\n\n return timeLeft > 0 && timeLeft <= thresholdMs;\n };\n\n /**\n * Obtiene el tiempo restante hasta la expiración del access token en milisegundos.\n */\n getTimeUntilExpiry(): number | null {\n if (!this.tokens) return null;\n\n return Math.max(0, this.tokens.expiresAt - Date.now());\n };\n\n /**\n * Obtiene el access token almacenado.\n */\n getAccessToken(): string | null {\n return this.tokens ? this.tokens.accessToken : null;\n };\n\n /**\n * Obtiene el refresh token almacenado.\n */\n getRefreshToken(): string | null {\n return this.tokens ? this.tokens.refreshToken : null;\n };\n\n /**\n * Verifica si el auto-refresh debe ejecutarse\n * Solo si el usuario activó \"rememberMe\" durante el login\n */\n shouldAutoRefresh(): boolean {\n if (!this.tokens) return false;\n\n return this.tokens.rememberMe === true;\n }\n\n /**\n * Inicia el monitoreo de expiración para sesiones sin rememberMe\n * - Notifica cuando quedan 5 minutos (onSessionExpiring)\n */\n private startExpirationCheck(): void {\n this.stopExpirationCheck();\n\n this.sessionCheckInterval = setInterval(async () => {\n if (!this.tokens) {\n this.stopExpirationCheck();\n return;\n };\n\n const timeLeft = this.getTimeUntilExpiry();\n if (timeLeft === null) return;\n\n const minutesLeft = Math.floor(timeLeft / (60 * 1000));\n\n if (minutesLeft <= 5 && minutesLeft > 1 && !this.hasNotifiedExpiring) {\n this.hasNotifiedExpiring = true;\n this.onSessionExpiring?.(minutesLeft);\n };\n\n if (minutesLeft <= 1) {\n this.stopExpirationCheck();\n\n if (this.onSessionRecovery) {\n try {\n const recovered = await this.onSessionRecovery();\n if (recovered) return;\n } catch (error) {\n }\n }\n\n if (this.onSessionExpired) {\n await this.onSessionExpired();\n };\n };\n }, 60000);\n }\n\n /**\n * Programa un auto-refresh proactivo para sesiones con rememberMe.\n * Se ejecuta X minutos antes de que expire el token\n */\n private scheduleAutoRefresh(): void {\n this.stopAutoRefreshTimer();\n\n if (!this.tokens || !this.tokens.rememberMe) return;\n\n const timeLeft = this.getTimeUntilExpiry();\n if (timeLeft === null || timeLeft <= 0) return;\n\n const thresholdMs = this.autoRefreshThresholdMinutes * 60 * 1000;\n const delay = Math.max(0, timeLeft - thresholdMs);\n\n this.autoRefreshTimeout = setTimeout(async () => {\n if (!this.tokens || !this.tokens.rememberMe) return;\n\n if (this.onSessionRecovery) {\n try {\n const recovered = await this.onSessionRecovery();\n if (recovered) return;\n } catch (error) {\n }\n }\n\n if (this.onSessionExpired) {\n await this.onSessionExpired();\n }\n }, delay);\n }\n\n /**\n * Detiene el monitoreo de expiración\n */\n private stopExpirationCheck(): void {\n if (this.sessionCheckInterval) {\n clearInterval(this.sessionCheckInterval);\n this.sessionCheckInterval = null;\n };\n }\n\n /**\n * Detiene el timer de auto-refresh proactivo\n */\n private stopAutoRefreshTimer(): void {\n if (this.autoRefreshTimeout) {\n clearTimeout(this.autoRefreshTimeout);\n this.autoRefreshTimeout = null;\n };\n }\n};\n","import { AuthInterceptorConfig } from \"./types/AuthInterceptorConfig\";\nimport { InterceptorContext } from \"@/core/interceptors/types/InterceptorContext\";\nimport { RequestConfig } from \"@/types/RequestConfig\";\nimport { RequestInterceptor } from \"./types/RequestInterceptor\";\n\nexport class AuthInterceptor implements RequestInterceptor {\n readonly name = \"AuthInterceptor\";\n\n private config: Required<AuthInterceptorConfig>;\n private refreshPromise: Promise<void> | null = null;\n private isRefreshing = false;\n\n constructor(config: AuthInterceptorConfig) {\n this.config = {\n enabled: config.enabled ?? true,\n thresholdMinutes: config.thresholdMinutes ?? 5,\n isTokenExpiringSoon: config.isTokenExpiringSoon,\n hasValidTokens: config.hasValidTokens,\n shouldAutoRefresh: config.shouldAutoRefresh,\n refreshSession: config.refreshSession\n };\n };\n\n async onRequest(\n config: RequestConfig,\n context: InterceptorContext\n ): Promise<RequestConfig> {\n\n //Actua en solicitudes que requieren autenticación\n if (!config.requiresAuth || !this.config.enabled) {\n return config;\n };\n\n //Actúa SOLO si los tokens son válidos\n if (!this.config.hasValidTokens()) {\n return config;\n };\n\n if (!this.config.shouldAutoRefresh()) {\n return config;\n };\n\n if (this.config.isTokenExpiringSoon()) {\n try {\n //Evita múltiples llamadas de actualización simultáneas\n if (this.isRefreshing && this.refreshPromise) {\n await this.refreshPromise;\n } else {\n this.isRefreshing = true;\n this.refreshPromise = this.config.refreshSession();\n await this.refreshPromise;\n this.isRefreshing = false;\n this.refreshPromise = null;\n };\n } catch (error) {\n this.isRefreshing = false;\n this.refreshPromise = null;\n };\n };\n\n return config;\n };\n\n updateConfig(config: Partial<AuthInterceptorConfig>): void {\n this.config = {\n ...this.config,\n ...config\n } as Required<AuthInterceptorConfig>;\n };\n\n reset(): void {\n this.isRefreshing = false;\n this.refreshPromise = null;\n };\n};\n","export class ErrorResponse extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n public responseData?: any\n ){\n super(message);\n this.name = \"FalconHUB API Error\";\n };\n};\n","import { API } from \"@/core/API\";\nimport { CryptoService } from \"@/core/CryptoService\";\nimport { TokenManager } from \"@/core/TokenManager\";\nimport { ChangePasswordRequest } from \"@/interfaces/Auth/ChangePassword/ChangePasswordRequest\";\nimport { ConfirmEmailRequest } from \"@/interfaces/Auth/ConfirmEmail/ConfirmEmailRequest\";\nimport { GetSecretKeyRequest } from \"@/interfaces/Auth/GetSecretKey/GetSecretKeyRequest\";\nimport { GetSecretKeyResponse } from \"@/interfaces/Auth/GetSecretKey/GetSecretKeyResponse\";\nimport { LoginRequest } from \"@/interfaces/Auth/Login/LoginRequest\";\nimport { LoginResponse } from \"@/interfaces/Auth/Login/LoginResponse\";\nimport { RefreshTokenRequest } from \"@/interfaces/Auth/RefreshTokens/RefreshTokenRequest\";\nimport { RefreshTokenResponse } from \"@/interfaces/Auth/RefreshTokens/RefreshTokenResponse\";\nimport { SendOtpRequest } from \"@/interfaces/Auth/SendOtp/SendOtpRequest\";\nimport { ValidateOtpRequest } from \"@/interfaces/Auth/ValidateOtp/ValidateOtpRequest\";\nimport { ValidateSessionRenewedResponse, ValidateSessionResponse } from \"@/interfaces/Auth/ValidateSession/ValidateSessionResponse\";\nimport { ErrorResponse } from \"@/types/ErrorResponse\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\nimport { ServiceProperties } from \"@/types/ServiceProperties\";\nimport { TokenData } from \"@/types/TokenData\";\n\n//Validado, integrado en su totalidad.\nexport class AuthService {\n private api: API;\n private crytpoService: CryptoService;\n private tokenManager: TokenManager;\n private serviceProperties: ServiceProperties;\n\n constructor(\n serviceProperties: ServiceProperties,\n tokenManager: TokenManager,\n cryptoService: CryptoService,\n api: API\n ) {\n this.api = api;\n this.crytpoService = cryptoService;\n this.tokenManager = tokenManager;\n this.serviceProperties = serviceProperties;\n };\n\n /**\n * Login con las credenciales proporcionadas\n * @param credentials - Objeto con email, password y rememberMe\n * @returns Retorna el cuerpo de respuesta del login.\n */\n async login(credentials: LoginRequest): Promise<ResponseModel<LoginResponse>> {\n const timestamp = Date.now().toString();\n\n const loginData: LoginRequest = {\n email: credentials.email,\n password: credentials.password,\n rememberMe: credentials.rememberMe\n };\n\n const response = await this.api.executePublicRequest<LoginResponse>(\n 'oauth/login',\n 'POST',\n loginData,\n timestamp\n );\n\n if (!response) {\n throw new ErrorResponse('No response from server');\n };\n\n if (response.success && response.data) {\n const data: LoginResponse = response.data;\n\n const expiresIn = parseInt(data.expiresIn.replace('s', ''));\n const expiresAt = Date.now() + expiresIn * 1000;\n\n const tokens: TokenData = {\n accessToken: data.accessToken,\n refreshToken: data.refreshToken,\n expiresAt,\n rememberMe: credentials.rememberMe\n };\n\n await this.tokenManager.setTokens(tokens);\n\n this.serviceProperties.onTokensUpdated?.(tokens);\n }\n\n return response;\n };\n\n /**\n * Valida la sesión actual y retorna información de expiración\n *\n * El servidor puede responder de 2 formas:\n * 1. Sesión renovada (sliding window): retorna nuevos tokens\n * 2. Sesión válida: retorna info de expiración sin renovar\n */\n async validateSession(): Promise<ResponseModel<ValidateSessionRenewedResponse | ValidateSessionResponse>> {\n const response = await this.api.executePOST<ValidateSessionRenewedResponse | ValidateSessionResponse>(\n 'oauth/validateSession'\n );\n\n if (!response) {\n throw new ErrorResponse('No response from server');\n };\n\n if (response.success && response.data) {\n const respData = response.data;\n\n if ('expiresIn' in respData && respData.expiresIn) {\n const sessionData = respData as ValidateSessionRenewedResponse;\n const expiresIn = parseInt(sessionData.expiresIn.replace('s', ''));\n const expiresAt = Date.now() + expiresIn * 1000;\n\n const currentTokens = this.tokenManager.getTokens();\n const rememberMe = currentTokens?.rememberMe ?? sessionData.isRemembered;\n\n const tokens: TokenData = {\n accessToken: sessionData.accessToken,\n refreshToken: sessionData.refreshToken,\n expiresAt,\n rememberMe\n };\n\n this.tokenManager.setTokens(tokens);\n this.serviceProperties.onTokensUpdated?.(tokens);\n }\n else if ('expiresAt' in respData && respData.expiresAt) {\n const sessionData = respData as ValidateSessionResponse;\n\n if (sessionData.remainingMinutes <= 5 && sessionData.remainingMinutes > 1) {\n this.serviceProperties.onSessionExpiring?.(sessionData.remainingMinutes);\n } else if (sessionData.remainingMinutes <= 1) {\n if (this.serviceProperties.onSessionExpired) {\n await this.serviceProperties.onSessionExpired();\n }\n }\n }\n };\n\n return response;\n };\n\n /**\n * Refresca los tokens usando el refresh token\n */\n async refreshTokens(refreshRequest: RefreshTokenRequest): Promise<ResponseModel<RefreshTokenResponse>> {\n const currentTokens = this.tokenManager.getTokens();\n const refreshToken = this.tokenManager.getRefreshToken() ?? refreshRequest.refreshToken;\n\n if (!refreshToken) {\n throw new ErrorResponse('No refresh token available');\n };\n\n const refreshRequestData: RefreshTokenRequest = {\n refreshToken: refreshToken,\n rememberMe: refreshRequest.rememberMe ?? currentTokens?.rememberMe\n }\n\n const response = await this.api.executePublicRequest<RefreshTokenResponse>(\n 'oauth/refresh',\n 'POST',\n refreshRequestData\n );\n\n if (!response) {\n throw new ErrorResponse('No response from server');\n };\n\n if (response.success && response.data) {\n const sessionData: RefreshTokenResponse = response.data;\n\n\n const shouldRemember = refreshRequest.rememberMe ?? currentTokens?.rememberMe ?? false;\n const expiresIn = parseInt(sessionData.expiresIn.replace('s', ''));\n const expiresAt = Date.now() + expiresIn * 1000;\n\n const tokens: TokenData = {\n accessToken: sessionData.accessToken,\n refreshToken: sessionData.refreshToken,\n expiresAt,\n rememberMe: shouldRemember\n };\n\n this.tokenManager.setTokens(tokens);\n this.serviceProperties.onTokensUpdated?.(tokens);\n };\n\n return response;\n };\n\n /**\n * Cierra sesión: notifica al servidor y limpia tokens\n */\n async logout(): Promise<ResponseModel> {\n const res = await this.api.executePOST('oauth/logout');\n\n if (res.success) {\n this.tokenManager.clearTokens();\n this.serviceProperties.onTokensUpdated?.(null);\n }\n\n return res;\n }\n\n /**\n * Obtiene la SecretKey del usuario autenticado.\n * Requiere sesión activa. Si el usuario tiene 2FA habilitado, se debe proveer el OTP.\n * @param request - Objeto opcional con otpCode (requerido si IsTwoFactorEnabled)\n */\n async getSecretKey(request?: GetSecretKeyRequest): Promise<ResponseModel<GetSecretKeyResponse>> {\n const response = await this.api.executePOST<GetSecretKeyResponse>(\n 'oauth/secret-key',\n request\n );\n\n if (!response) {\n throw new ErrorResponse('No response from server');\n }\n\n return response;\n }\n\n // #region Email & OTP & Password (public - no auth)\n\n /**\n * Confirma el correo electrónico de un usuario.\n * @param request - Email y expiresAt\n */\n async confirmEmail(request: ConfirmEmailRequest): Promise<ResponseModel> {\n return this.api.executePublicRequest('oauth/email/confirm', 'PUT', request);\n }\n\n /**\n * Envía un código OTP al correo electrónico.\n * @param request - Email del usuario\n */\n async sendOtp(request: SendOtpRequest): Promise<ResponseModel> {\n return this.api.executePublicRequest('oauth/otp', 'POST', request);\n }\n\n /**\n * Valida un código OTP.\n * @param request - Email y código OTP\n */\n async validateOtp(request: ValidateOtpRequest): Promise<ResponseModel> {\n return this.api.executePublicRequest('oauth/otp/verify', 'POST', request);\n }\n\n /**\n * Cambia la contraseña del usuario (flujo público, sin sesión).\n * @param request - Email, contraseña actual y nueva contraseña\n */\n async changePassword(request: ChangePasswordRequest): Promise<ResponseModel> {\n return this.api.executePublicRequest('oauth/password', 'PUT', request);\n }\n\n // #endregion\n\n /**\n * Verifica si el usuario está autenticado\n */\n isAuthenticated(): boolean {\n return this.tokenManager.hasValidTokens();\n };\n\n /**\n * Obtiene los tokens actuales\n */\n getTokens(): TokenData | null {\n return this.tokenManager.getTokens();\n };\n\n}\n","/**\n * Utilidad para construir query params a partir de objetos de filtro.\n *\n * @example\n * ```typescript\n * const filter: EndpointsFilter = { HttpMethod: 'GET', IsActive: true };\n * const queryString = FilterBuilder.toQueryString(filter);\n * // Result: \"HttpMethod=GET&IsActive=true\"\n * ```\n */\nexport class FilterBuilder {\n /**\n * Convierte un objeto de filtro a query string.\n * Ignora valores null, undefined y strings vacíos.\n *\n * @param filter - Objeto con los filtros a aplicar\n * @returns Query string sin el \"?\" inicial\n */\n static toQueryString<T extends Record<string, any>>(filter: T): string {\n const params = new URLSearchParams();\n\n for (const [key, value] of Object.entries(filter)) {\n if (value !== null && value !== undefined && value !== '') {\n params.append(key, String(value));\n }\n }\n\n return params.toString();\n }\n\n /**\n * Construye la URL completa con filtros aplicados.\n *\n * @param baseEndpoint - Endpoint base sin query params\n * @param filter - Objeto con los filtros a aplicar\n * @returns Endpoint con query params si hay filtros, o el endpoint base si no hay\n */\n static buildEndpoint<T extends Record<string, any>>(baseEndpoint: string, filter?: T): string {\n if (!filter) return baseEndpoint;\n\n const queryString = this.toQueryString(filter);\n\n if (!queryString) return baseEndpoint;\n\n return `${baseEndpoint}?${queryString}`;\n }\n\n /**\n * Verifica si un objeto de filtro tiene al menos un valor válido.\n *\n * @param filter - Objeto con los filtros a verificar\n * @returns true si hay al menos un filtro con valor válido\n */\n static hasFilters<T extends Record<string, any>>(filter?: T): boolean {\n if (!filter) return false;\n\n return Object.values(filter).some(\n value => value !== null && value !== undefined && value !== ''\n );\n }\n\n /**\n * Limpia un objeto de filtro removiendo valores vacíos.\n * Útil para normalizar filtros antes de enviarlos.\n *\n * @param filter - Objeto con los filtros\n * @returns Nuevo objeto solo con valores válidos\n */\n static clean<T extends Record<string, any>>(filter: T): Partial<T> {\n const cleaned: Partial<T> = {};\n\n for (const [key, value] of Object.entries(filter)) {\n if (value !== null && value !== undefined && value !== '') {\n (cleaned as any)[key] = value;\n }\n }\n\n return cleaned;\n }\n}\n\n/**\n * Tipo base para modelos de filtro.\n * Todos los campos son opcionales y pueden ser string, number, boolean o null.\n */\nexport type FilterModel = Record<string, string | number | boolean | null | undefined>;\n\n/**\n * Tipo para definir metadatos de un campo de filtro.\n */\nexport interface FilterFieldMetadata {\n /** Tipo de filtro */\n type: 'search' | 'string' | 'boolean' | 'number' | 'select' | 'multiselect' | 'date' | 'daterange';\n /** Descripción / label del filtro */\n description: string;\n /** Orden de renderizado (menor = primero, default 99) */\n order?: number;\n /** Opciones para select / multiselect */\n options?: string[];\n /** Labels personalizados para boolean (default: Activo/Inactivo) */\n labels?: { true: string; false: string };\n /** Campos en los que busca el backend (solo para type: 'search') */\n searchIn?: string[];\n /** Valor mínimo (para number) */\n min?: number;\n /** Valor máximo (para number) */\n max?: number;\n /** Fecha mínima (para date / daterange) */\n minDate?: string;\n /** Fecha máxima (para date / daterange) */\n maxDate?: string;\n}\n\n/**\n * Tipo para el modelo de filtros retornado por el endpoint /filters.\n */\nexport type FilterMetadataModel = Record<string, FilterFieldMetadata>;\n\n// ── Filter Groups (array-based format) ──\n\n/**\n * Opción dentro de un grupo de filtros.\n */\nexport interface FilterGroupOption {\n /** Campo del backend (e.g. \"Module\", \"IsActive\") */\n key: string;\n /** Label visible en el frontend */\n label: string;\n /** Placeholder del input (solo para string) */\n placeholder?: string;\n /** Opciones disponibles (solo para select) */\n values?: string[];\n /** Label cuando el valor es true (solo para boolean) */\n trueLabel?: string;\n /** Label cuando el valor es false (solo para boolean) */\n falseLabel?: string;\n}\n\n/**\n * Grupo de filtros agrupados por tipo.\n * El frontend renderiza cada grupo de forma diferente.\n */\nexport interface FilterGroup {\n /** Tipo de filtro: \"string\" | \"boolean\" | \"select\" | \"date\" */\n type: 'string' | 'boolean' | 'select' | 'date';\n /** Label del grupo */\n label: string;\n /** Opciones del grupo */\n options: FilterGroupOption[];\n}\n\n/**\n * Modelo retornado por el endpoint /filters (formato array-based).\n */\nexport type FilterGroupsModel = FilterGroup[];\n","import { API } from \"@/core/API\";\nimport {\n AreaCode,\n AreaCodeRequest,\n AreaCodesFilter,\n Gender,\n GenderRequest,\n GendersFilter\n} from \"@/interfaces/Catalog\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\nimport { FilterBuilder, type FilterGroupsModel } from \"@/utils/FilterBuilder\";\n\n/**\n * Servicio para gestionar catálogos públicos.\n * No requiere autenticación.\n */\n\n//Validado, se integró CAT_Genders y CAT_AreaCodes\nexport class CatalogService {\n private api: API;\n private readonly BASE_PATH = 'catalogs';\n\n constructor(api: API) {\n this.api = api;\n }\n\n // #region GENDERS\n\n /**\n * Obtiene todos los géneros con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getGenders(filter?: GendersFilter): Promise<ResponseModel<Gender[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/genders`, filter);\n return this.api.executeGET<Gender[]>(endpoint, false);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para géneros.\n */\n async getGendersFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/genders/filters`, false);\n }\n\n /**\n * Obtiene un género por su ID.\n * @param id - ID del género\n */\n async getGenderById(id: number): Promise<ResponseModel<Gender>> {\n return this.api.executeGET<Gender>(`${this.BASE_PATH}/genders/${id}`, false);\n }\n\n /**\n * Crea un nuevo género.\n * @param request - Datos del género a crear\n */\n async createGender(request: GenderRequest): Promise<ResponseModel<Gender>> {\n return this.api.executePOST<Gender>(`${this.BASE_PATH}/genders`, request);\n }\n\n /**\n * Actualiza un género existente.\n * @param id - ID del género a actualizar\n * @param request - Nuevos datos del género\n */\n async updateGender(id: number, request: GenderRequest): Promise<ResponseModel<Gender>> {\n return this.api.executePUT<Gender>(`${this.BASE_PATH}/genders/${id}`, request);\n }\n\n /**\n * Elimina un género.\n * @param id - ID del género a eliminar\n */\n async deleteGender(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/genders/${id}`);\n }\n\n // #endregion\n\n // #region AREA CODES\n\n /**\n * Obtiene todos los códigos de área con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getAreaCodes(filter?: AreaCodesFilter): Promise<ResponseModel<AreaCode[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/area-codes`, filter);\n return this.api.executeGET<AreaCode[]>(endpoint, false);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para códigos de área.\n */\n async getAreaCodesFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/area-codes/filters`, false);\n }\n\n /**\n * Obtiene un código de área por su ID.\n * @param id - ID del código de área\n */\n async getAreaCodeById(id: number): Promise<ResponseModel<AreaCode>> {\n return this.api.executeGET<AreaCode>(`${this.BASE_PATH}/area-codes/${id}`, false);\n }\n\n /**\n * Crea un nuevo código de área.\n * @param request - Datos del código de área a crear\n */\n async createAreaCode(request: AreaCodeRequest): Promise<ResponseModel<AreaCode>> {\n return this.api.executePOST<AreaCode>(`${this.BASE_PATH}/area-codes`, request);\n }\n\n /**\n * Actualiza un código de área existente.\n * @param id - ID del código de área a actualizar\n * @param request - Nuevos datos del código de área\n */\n async updateAreaCode(id: number, request: AreaCodeRequest): Promise<ResponseModel<AreaCode>> {\n return this.api.executePUT<AreaCode>(`${this.BASE_PATH}/area-codes/${id}`, request);\n }\n\n /**\n * Activa o desactiva un código de área.\n * @param id - ID del código de área\n */\n async toggleAreaCodeStatus(id: number): Promise<ResponseModel<AreaCode>> {\n return this.api.executePUT<AreaCode>(`${this.BASE_PATH}/area-codes/${id}/toggle-status`);\n }\n\n /**\n * Elimina un código de área.\n * @param id - ID del código de área a eliminar\n */\n async deleteAreaCode(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/area-codes/${id}`);\n }\n\n // #endregion\n}\n","import { API } from \"@/core/API\";\nimport {\n InventoryStatus,\n InventoryStatusRequest,\n InventoryStatusesFilter,\n Location,\n LocationsFilter,\n LocationsRequest,\n Material,\n MaterialRequest,\n MaterialsFilter,\n Packing,\n PackingRequest,\n PackingsFilter,\n Provider,\n ProviderRequest,\n ProvidersFilter\n} from \"@/interfaces/Inventory\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\nimport { FilterBuilder, type FilterGroupsModel } from \"@/utils/FilterBuilder\";\n\n/**\n * Servicio para gestionar inventario: ubicaciones, estatus, empaques y materiales.\n */\n\n//Validado, se integró: Locations, CAT_InventoryStatuses, CAT_Packings, CAT_Materials, CAT_Providers\nexport class InventoryService {\n private api: API;\n private readonly BASE_PATH = 'inventory';\n\n constructor(api: API) {\n this.api = api;\n }\n\n // #region LOCATIONS\n\n /**\n * Obtiene todas las ubicaciones con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getLocations(filter?: LocationsFilter): Promise<ResponseModel<Location[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/locations`, filter);\n return this.api.executeGET<Location[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para ubicaciones.\n */\n async getLocationFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/locations/filters`, true);\n }\n\n /**\n * Obtiene una ubicación por su ID.\n * @param id - ID de la ubicación\n */\n async getLocationById(id: number): Promise<ResponseModel<Location>> {\n return this.api.executeGET<Location>(`${this.BASE_PATH}/locations/${id}`, true);\n }\n\n /**\n * Crea una nueva ubicación.\n * @param request - Datos de la ubicación a crear\n */\n async createLocation(request: LocationsRequest): Promise<ResponseModel<Location>> {\n return this.api.executePOST<Location>(`${this.BASE_PATH}/locations`, request);\n }\n\n /**\n * Actualiza una ubicación existente.\n * @param id - ID de la ubicación a actualizar\n * @param request - Nuevos datos de la ubicación\n */\n async updateLocation(id: number, request: LocationsRequest): Promise<ResponseModel<Location>> {\n return this.api.executePUT<Location>(`${this.BASE_PATH}/locations/${id}`, request);\n }\n\n /**\n * Activa o desactiva una ubicación.\n * @param id - ID de la ubicación\n */\n async toggleLocationStatus(id: number): Promise<ResponseModel<Location>> {\n return this.api.executePUT<Location>(`${this.BASE_PATH}/locations/${id}/toggle-status`);\n }\n\n /**\n * Elimina una ubicación.\n * @param id - ID de la ubicación a eliminar\n */\n async deleteLocation(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/locations/${id}`);\n }\n\n // #endregion\n\n // #region STATUSES\n\n /**\n * Obtiene todos los estatus de inventario con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getStatuses(filter?: InventoryStatusesFilter): Promise<ResponseModel<InventoryStatus[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/statuses`, filter);\n return this.api.executeGET<InventoryStatus[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para estatus de inventario.\n */\n async getStatusFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/statuses/filters`, true);\n }\n\n /**\n * Obtiene un estatus de inventario por su ID.\n * @param id - ID del estatus\n */\n async getStatusById(id: number): Promise<ResponseModel<InventoryStatus>> {\n return this.api.executeGET<InventoryStatus>(`${this.BASE_PATH}/catalogs/statuses/${id}`, true);\n }\n\n /**\n * Crea un nuevo estatus de inventario.\n * @param request - Datos del estatus a crear\n */\n async createStatus(request: InventoryStatusRequest): Promise<ResponseModel<InventoryStatus>> {\n return this.api.executePOST<InventoryStatus>(`${this.BASE_PATH}/catalogs/statuses`, request);\n }\n\n /**\n * Actualiza un estatus de inventario existente.\n * @param id - ID del estatus a actualizar\n * @param request - Nuevos datos del estatus\n */\n async updateStatus(id: number, request: InventoryStatusRequest): Promise<ResponseModel<InventoryStatus>> {\n return this.api.executePUT<InventoryStatus>(`${this.BASE_PATH}/catalogs/statuses/${id}`, request);\n }\n\n /**\n * Elimina un estatus de inventario.\n * @param id - ID del estatus a eliminar\n */\n async deleteStatus(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/statuses/${id}`);\n }\n\n // #endregion\n\n // #region PACKINGS\n\n /**\n * Obtiene todos los empaques con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getPackings(filter?: PackingsFilter): Promise<ResponseModel<Packing[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/packings`, filter);\n return this.api.executeGET<Packing[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para empaques.\n */\n async getPackingFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/packings/filters`, true);\n }\n\n /**\n * Obtiene un empaque por su ID.\n * @param id - ID del empaque\n */\n async getPackingById(id: number): Promise<ResponseModel<Packing>> {\n return this.api.executeGET<Packing>(`${this.BASE_PATH}/catalogs/packings/${id}`, true);\n }\n\n /**\n * Crea un nuevo empaque.\n * @param request - Datos del empaque a crear\n */\n async createPacking(request: PackingRequest): Promise<ResponseModel<Packing>> {\n return this.api.executePOST<Packing>(`${this.BASE_PATH}/catalogs/packings`, request);\n }\n\n /**\n * Actualiza un empaque existente.\n * @param id - ID del empaque a actualizar\n * @param request - Nuevos datos del empaque\n */\n async updatePacking(id: number, request: PackingRequest): Promise<ResponseModel<Packing>> {\n return this.api.executePUT<Packing>(`${this.BASE_PATH}/catalogs/packings/${id}`, request);\n }\n\n /**\n * Activa o desactiva un empaque.\n * @param id - ID del empaque\n */\n async togglePackingStatus(id: number): Promise<ResponseModel<Packing>> {\n return this.api.executePUT<Packing>(`${this.BASE_PATH}/catalogs/packings/${id}/toggle-status`);\n }\n\n /**\n * Elimina un empaque.\n * @param id - ID del empaque a eliminar\n */\n async deletePacking(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/packings/${id}`);\n }\n\n // #endregion\n\n // #region MATERIALS\n\n /**\n * Obtiene todos los materiales con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getMaterials(filter?: MaterialsFilter): Promise<ResponseModel<Material[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/materials`, filter);\n return this.api.executeGET<Material[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para materiales.\n */\n async getMaterialFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/materials/filters`, true);\n }\n\n /**\n * Obtiene un material por su ID.\n * @param id - ID del material\n */\n async getMaterialById(id: number): Promise<ResponseModel<Material>> {\n return this.api.executeGET<Material>(`${this.BASE_PATH}/catalogs/materials/${id}`, true);\n }\n\n /**\n * Crea un nuevo material.\n * @param request - Datos del material a crear\n */\n async createMaterial(request: MaterialRequest): Promise<ResponseModel<Material>> {\n return this.api.executePOST<Material>(`${this.BASE_PATH}/catalogs/materials`, request);\n }\n\n /**\n * Actualiza un material existente.\n * @param id - ID del material a actualizar\n * @param request - Nuevos datos del material\n */\n async updateMaterial(id: number, request: MaterialRequest): Promise<ResponseModel<Material>> {\n return this.api.executePUT<Material>(`${this.BASE_PATH}/catalogs/materials/${id}`, request);\n }\n\n /**\n * Elimina un material.\n * @param id - ID del material a eliminar\n */\n async deleteMaterial(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/materials/${id}`);\n }\n\n // #endregion\n\n // #region PROVIDERS\n\n /**\n * Obtiene todos los proveedores con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getProviders(filter?: ProvidersFilter): Promise<ResponseModel<Provider[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/providers`, filter);\n return this.api.executeGET<Provider[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para proveedores.\n */\n async getProviderFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/providers/filters`, true);\n }\n\n /**\n * Obtiene un proveedor por su ID.\n * @param id - ID del proveedor\n */\n async getProviderById(id: number): Promise<ResponseModel<Provider>> {\n return this.api.executeGET<Provider>(`${this.BASE_PATH}/catalogs/providers/${id}`, true);\n }\n\n /**\n * Crea un nuevo proveedor.\n * @param request - Datos del proveedor a crear\n */\n async createProvider(request: ProviderRequest): Promise<ResponseModel<Provider>> {\n return this.api.executePOST<Provider>(`${this.BASE_PATH}/catalogs/providers`, request);\n }\n\n /**\n * Actualiza un proveedor existente.\n * @param id - ID del proveedor a actualizar\n * @param request - Nuevos datos del proveedor\n */\n async updateProvider(id: number, request: ProviderRequest): Promise<ResponseModel<Provider>> {\n return this.api.executePUT<Provider>(`${this.BASE_PATH}/catalogs/providers/${id}`, request);\n }\n\n /**\n * Activa o desactiva un proveedor.\n * @param id - ID del proveedor\n */\n async toggleProviderStatus(id: number): Promise<ResponseModel<Provider>> {\n return this.api.executePUT<Provider>(`${this.BASE_PATH}/catalogs/providers/${id}/toggle-status`);\n }\n\n /**\n * Elimina un proveedor.\n * @param id - ID del proveedor a eliminar\n */\n async deleteProvider(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/providers/${id}`);\n }\n\n // #endregion\n}\n","import { API } from \"@/core/API\";\nimport {\n Endpoint,\n EndpointRequest,\n EndpointsFilter,\n Module,\n ModuleRequest,\n ModulesFilter,\n UIRoute,\n UIRouteRequest,\n UIRoutesFilter\n} from \"@/interfaces/System\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\nimport { FilterBuilder, type FilterGroupsModel } from \"@/utils/FilterBuilder\";\n\n/**\n * Servicio para gestionar las configuraciones del sistema.\n */\n\n//Validado, todos los métodos integrados.\nexport class SystemService {\n private api: API;\n private readonly BASE_PATH = 'system';\n\n constructor(api: API) {\n this.api = api;\n }\n\n // #region MODULES\n\n /**\n * Obtiene todos los módulos con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getModules(filter?: ModulesFilter): Promise<ResponseModel<Module[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/modules`, filter);\n return this.api.executeGET<Module[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para módulos.\n */\n async getModulesFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/modules/filters`, true);\n }\n\n /**\n * Obtiene un módulo por su ID.\n * @param id - ID del módulo\n */\n async getModuleById(id: number): Promise<ResponseModel<Module>> {\n return this.api.executeGET<Module>(`${this.BASE_PATH}/modules/${id}`, true);\n }\n\n /**\n * Crea un nuevo módulo.\n * @param request - Datos del módulo a crear\n */\n async createModule(request: ModuleRequest): Promise<ResponseModel<Module>> {\n return this.api.executePOST<Module>(`${this.BASE_PATH}/modules`, request);\n }\n\n /**\n * Actualiza un módulo existente.\n * @param id - ID del módulo a actualizar\n * @param request - Nuevos datos del módulo\n */\n async updateModule(id: number, request: ModuleRequest): Promise<ResponseModel<Module>> {\n return this.api.executePUT<Module>(`${this.BASE_PATH}/modules/${id}`, request);\n }\n\n /**\n * Activa o desactiva un módulo.\n * @param id - ID del módulo\n */\n async toggleModuleStatus(id: number): Promise<ResponseModel<Module>> {\n return this.api.executePUT<Module>(`${this.BASE_PATH}/modules/${id}/toggle-status`);\n }\n\n /**\n * Elimina un módulo.\n * @param id - ID del módulo a eliminar\n */\n async deleteModule(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/modules/${id}`);\n }\n\n // #endregion\n\n // #region ENDPOINTS\n\n /**\n * Obtiene todos los endpoints con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getEndpoints(filter?: EndpointsFilter): Promise<ResponseModel<Endpoint[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/endpoints`, filter);\n return this.api.executeGET<Endpoint[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para endpoints.\n */\n async getEndpointsFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/endpoints/filters`, true);\n }\n\n /**\n * Obtiene los módulos disponibles (valores únicos del primer segmento del path).\n */\n async getEndpointModules(): Promise<ResponseModel<string[]>> {\n return this.api.executeGET<string[]>(`${this.BASE_PATH}/endpoints/modules`, true);\n }\n\n /**\n * Obtiene un endpoint por su ID.\n * @param id - ID del endpoint\n */\n async getEndpointById(id: number): Promise<ResponseModel<Endpoint>> {\n return this.api.executeGET<Endpoint>(`${this.BASE_PATH}/endpoints/${id}`, true);\n }\n\n /**\n * Crea un nuevo endpoint.\n * @param request - Datos del endpoint a crear\n */\n async createEndpoint(request: EndpointRequest): Promise<ResponseModel<Endpoint>> {\n return this.api.executePOST<Endpoint>(`${this.BASE_PATH}/endpoints`, request);\n }\n\n /**\n * Actualiza un endpoint existente.\n * @param id - ID del endpoint a actualizar\n * @param request - Nuevos datos del endpoint\n */\n async updateEndpoint(id: number, request: EndpointRequest): Promise<ResponseModel<Endpoint>> {\n return this.api.executePUT<Endpoint>(`${this.BASE_PATH}/endpoints/${id}`, request);\n }\n\n /**\n * Activa o desactiva un endpoint.\n * @param id - ID del endpoint\n */\n async toggleEndpointStatus(id: number): Promise<ResponseModel<Endpoint>> {\n return this.api.executePUT<Endpoint>(`${this.BASE_PATH}/endpoints/${id}/toggle-status`);\n }\n\n /**\n * Elimina un endpoint.\n * @param id - ID del endpoint a eliminar\n */\n async deleteEndpoint(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/endpoints/${id}`);\n }\n\n // #endregion\n\n // #region UI ROUTES\n\n /**\n * Obtiene todas las rutas de UI con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getUIRoutes(filter?: UIRoutesFilter): Promise<ResponseModel<UIRoute[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/ui-routes`, filter);\n return this.api.executeGET<UIRoute[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para rutas de UI.\n */\n async getUIRoutesFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/ui-routes/filters`, true);\n }\n\n /**\n * Obtiene una ruta de UI por su ID.\n * @param id - ID de la ruta\n */\n async getUIRouteById(id: number): Promise<ResponseModel<UIRoute>> {\n return this.api.executeGET<UIRoute>(`${this.BASE_PATH}/ui-routes/${id}`, true);\n }\n\n /**\n * Crea una nueva ruta de UI.\n * @param request - Datos de la ruta a crear\n */\n async createUIRoute(request: UIRouteRequest): Promise<ResponseModel<UIRoute>> {\n return this.api.executePOST<UIRoute>(`${this.BASE_PATH}/ui-routes`, request);\n }\n\n /**\n * Actualiza una ruta de UI existente.\n * @param id - ID de la ruta a actualizar\n * @param request - Nuevos datos de la ruta\n */\n async updateUIRoute(id: number, request: UIRouteRequest): Promise<ResponseModel<UIRoute>> {\n return this.api.executePUT<UIRoute>(`${this.BASE_PATH}/ui-routes/${id}`, request);\n }\n\n /**\n * Activa o desactiva una ruta de UI.\n * @param id - ID de la ruta\n */\n async toggleUIRouteStatus(id: number): Promise<ResponseModel<UIRoute>> {\n return this.api.executePUT<UIRoute>(`${this.BASE_PATH}/ui-routes/${id}/toggle-status`);\n }\n\n /**\n * Elimina una ruta de UI.\n * @param id - ID de la ruta a eliminar\n */\n async deleteUIRoute(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/ui-routes/${id}`);\n }\n\n // #endregion\n}\n","import { API } from \"@/core/API\";\nimport {\n AdminAuthentication,\n AdminUser,\n ChangePasswordAdminRequest,\n UserAdminFilter,\n UserAdminRequest,\n UserAdminUpdateRequest,\n UserAuthAdminRequest,\n UserAuthUpdateRequest\n} from \"@/interfaces/User/Admin\";\nimport { ChangePasswordUserRequest } from \"@/interfaces/User/ChangePassword/ChangePasswordUserRequest\";\nimport {\n Role,\n RoleRequest,\n RolesFilter\n} from \"@/interfaces/User/Role/RoleInterface\";\nimport { UserBasicResponse } from \"@/interfaces/User/UserBasicResponse\";\nimport { UserDataUpdateRequest } from \"@/interfaces/User/UserDataUpdateRequest\";\nimport { UserProfileResponse } from \"@/interfaces/User/UserProfileResponse\";\nimport {\n UserType,\n UserTypeRequest,\n UserTypesFilter\n} from \"@/interfaces/User/UserType/UserTypeInterface\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\nimport { FilterBuilder, type FilterGroupsModel } from \"@/utils/FilterBuilder\";\n\n//Validado, todos los métodos fueron integrados.\nexport class UserService {\n private api: API;\n private readonly BASE_PATH = 'users';\n\n constructor(\n api: API,\n ){\n this.api = api;\n };\n\n /**\n * Obtiene la información básica del usuario.\n * @returns retorna un objeto con la información básica del usuario\n */\n async me(): Promise<ResponseModel<UserBasicResponse>> {\n const response: ResponseModel<UserBasicResponse> = await this.api.executeGET(\n `${this.BASE_PATH}/me`,\n true,\n );\n\n return response;\n };\n\n /**\n * Obtiene la información general del usuario para la vista de perfil.\n * @returns\n */\n async profile(): Promise<ResponseModel<UserProfileResponse>>{\n const response: ResponseModel<UserProfileResponse> = await this.api.executeGET(\n `${this.BASE_PATH}/profile`,\n true\n );\n\n return response;\n }\n\n async changePasswordUser(request: ChangePasswordUserRequest): Promise<ResponseModel>{\n return this.api.executePUT(`${this.BASE_PATH}/me/password`, request);\n }\n\n async updateUserData(request: UserDataUpdateRequest): Promise<ResponseModel>{\n return this.api.executePUT(`${this.BASE_PATH}/me`, request);\n }\n\n // #region Admin CRUD\n\n /**\n * Crea un nuevo usuario administrador.\n * @param request - Datos del nuevo administrador\n */\n async newAdminUser(request: UserAdminRequest): Promise<ResponseModel<AdminUser>> {\n return this.api.executePOST<AdminUser>(`${this.BASE_PATH}/admin`, request);\n }\n\n /**\n * Crea la autenticación para un usuario.\n * @param request - Datos de autenticación del usuario\n */\n async createUserAuthentication(request: UserAuthAdminRequest): Promise<ResponseModel<AdminAuthentication>> {\n return this.api.executePOST<AdminAuthentication>(`${this.BASE_PATH}/admin/authentication`, request);\n }\n\n /**\n * Cambia la contraseña de un administrador.\n * @param id - ID del usuario\n * @param request - Nueva contraseña\n */\n async changePasswordAdmin(id: number, request: ChangePasswordAdminRequest): Promise<ResponseModel> {\n return this.api.executePOST(`${this.BASE_PATH}/admin/${id}/password`, request);\n }\n\n /**\n * Obtiene todos los administradores con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getAllAdmins(filter?: UserAdminFilter): Promise<ResponseModel<AdminUser[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/admin`, filter);\n return this.api.executeGET<AdminUser[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para administradores.\n */\n async getAdminFiltersModel(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/admin/filters`, true);\n }\n\n /**\n * Obtiene un administrador por su ID.\n * @param id - ID del administrador\n */\n async getAdminById(id: number): Promise<ResponseModel<AdminUser>> {\n return this.api.executeGET<AdminUser>(`${this.BASE_PATH}/admin/${id}`, true);\n }\n\n /**\n * Obtiene la autenticación de un administrador.\n * @param id - ID del usuario\n */\n async getAdminAuthentication(id: number): Promise<ResponseModel<AdminAuthentication>> {\n return this.api.executeGET<AdminAuthentication>(`${this.BASE_PATH}/admin/authentication/${id}`, true);\n }\n\n /**\n * Actualiza un administrador existente.\n * @param id - ID del administrador\n * @param request - Nuevos datos del administrador\n */\n async updateAdmin(id: number, request: UserAdminUpdateRequest): Promise<ResponseModel<AdminUser>> {\n return this.api.executePUT<AdminUser>(`${this.BASE_PATH}/admin/${id}`, request);\n }\n\n /**\n * Activa o desactiva un administrador.\n * @param id - ID del administrador\n */\n async toggleAdminStatus(id: number): Promise<ResponseModel<AdminUser>> {\n return this.api.executePUT<AdminUser>(`${this.BASE_PATH}/admin/${id}/toggle-status`);\n }\n\n /**\n * Actualiza la autenticación de un administrador.\n * @param id - ID del usuario\n * @param request - Nuevos datos de autenticación\n */\n async updateAdminAuthentication(id: number, request: UserAuthUpdateRequest): Promise<ResponseModel<AdminAuthentication>> {\n return this.api.executePUT<AdminAuthentication>(`${this.BASE_PATH}/admin/authentication/${id}`, request);\n }\n\n /**\n * Elimina un administrador.\n * @param id - ID del administrador\n */\n async deleteAdmin(id: number): Promise<ResponseModel>{\n return this.api.executeDELETE(`${this.BASE_PATH}/admin/${id}`);\n }\n\n /**\n * Reenvía el correo de confirmación al usuario.\n * @param id - ID del usuario\n */\n async resendEmailConfirmation(id: number): Promise<ResponseModel>{\n return this.api.executePOST(`${this.BASE_PATH}/admin/authentication/${id}/resend-confirmation`)\n }\n\n // #endregion\n\n // #region User Types\n\n /**\n * Obtiene todos los tipos de usuario con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getUserTypes(filter?: UserTypesFilter): Promise<ResponseModel<UserType[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/user-types`, filter);\n return this.api.executeGET<UserType[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para tipos de usuario.\n */\n async getUserTypesFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/user-types/filters`, true);\n }\n\n /**\n * Obtiene un tipo de usuario por su ID.\n * @param id - ID del tipo de usuario\n */\n async getUserTypeById(id: number): Promise<ResponseModel<UserType>> {\n return this.api.executeGET<UserType>(`${this.BASE_PATH}/catalogs/user-types/${id}`, true);\n }\n\n /**\n * Crea un nuevo tipo de usuario.\n * @param request - Datos del tipo de usuario a crear\n */\n async createUserType(request: UserTypeRequest): Promise<ResponseModel<UserType>> {\n return this.api.executePOST<UserType>(`${this.BASE_PATH}/catalogs/user-types`, request);\n }\n\n /**\n * Actualiza un tipo de usuario existente.\n * @param id - ID del tipo de usuario a actualizar\n * @param request - Nuevos datos del tipo de usuario\n */\n async updateUserType(id: number, request: UserTypeRequest): Promise<ResponseModel<UserType>> {\n return this.api.executePUT<UserType>(`${this.BASE_PATH}/catalogs/user-types/${id}`, request);\n }\n\n /**\n * Elimina un tipo de usuario.\n * @param id - ID del tipo de usuario a eliminar\n */\n async deleteUserType(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/user-types/${id}`);\n }\n\n // #endregion\n\n // #region Roles\n\n /**\n * Obtiene todos los roles con filtros opcionales.\n * @param filter - Filtros opcionales para la búsqueda\n */\n async getRoles(filter?: RolesFilter): Promise<ResponseModel<Role[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/catalogs/roles`, filter);\n return this.api.executeGET<Role[]>(endpoint, true);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para roles.\n */\n async getRolesFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/catalogs/roles/filters`, true);\n }\n\n /**\n * Obtiene un rol por su ID.\n * @param id - ID del rol\n */\n async getRoleById(id: number): Promise<ResponseModel<Role>> {\n return this.api.executeGET<Role>(`${this.BASE_PATH}/catalogs/roles/${id}`, true);\n }\n\n /**\n * Obtiene los roles asociados a un tipo de usuario.\n * @param userTypeId - ID del tipo de usuario\n */\n async getRolesByUserType(userTypeId: number): Promise<ResponseModel<Role[]>> {\n return this.api.executeGET<Role[]>(`${this.BASE_PATH}/catalogs/roles/user-type/${userTypeId}`, true);\n }\n\n /**\n * Crea un nuevo rol.\n * @param request - Datos del rol a crear\n */\n async createRole(request: RoleRequest): Promise<ResponseModel<Role>> {\n return this.api.executePOST<Role>(`${this.BASE_PATH}/catalogs/roles`, request);\n }\n\n /**\n * Actualiza un rol existente.\n * @param id - ID del rol a actualizar\n * @param request - Nuevos datos del rol\n */\n async updateRole(id: number, request: RoleRequest): Promise<ResponseModel<Role>> {\n return this.api.executePUT<Role>(`${this.BASE_PATH}/catalogs/roles/${id}`, request);\n }\n\n /**\n * Activa o desactiva un rol.\n * @param id - ID del rol\n */\n async toggleRoleStatus(id: number): Promise<ResponseModel<Role>> {\n return this.api.executePUT<Role>(`${this.BASE_PATH}/catalogs/roles/${id}/toggle-status`);\n }\n\n /**\n * Elimina un rol.\n * @param id - ID del rol a eliminar\n */\n async deleteRole(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/catalogs/roles/${id}`);\n }\n\n // #endregion\n}\n","import { API } from \"./core/API\";\nimport { CryptoService } from \"./core/CryptoService\";\nimport { TokenManager } from \"./core/TokenManager\";\nimport { AuthInterceptor } from \"./core/interceptors/AuthInterceptor\";\nimport { AuthService } from \"./services/AuthService\";\nimport { CatalogService } from \"./services/CatalogService\";\nimport { InventoryService } from \"./services/InventoryService\";\nimport { SystemService } from \"./services/SystemService\";\nimport { UserService } from \"./services/UserService\";\nimport { ServiceProperties } from \"./types/ServiceProperties\";\nimport { TokenData } from \"./types/TokenData\";\n\n/**\n * SDK principal de FalconHUB\n */\nexport class FalconHUBSDK {\n public auth: AuthService;\n public user: UserService;\n public system: SystemService;\n public inventory: InventoryService;\n public catalog: CatalogService;\n\n private serviceProperties: ServiceProperties;\n private cryptoService: CryptoService;\n private tokenManager: TokenManager;\n private authInterceptor: AuthInterceptor | null;\n private api: API;\n\n constructor(serviceProperties: ServiceProperties) {\n this.serviceProperties = serviceProperties;\n\n this.cryptoService = new CryptoService();\n\n const autoRefreshConfig = this.normalizeAutoRefreshConfig(this.serviceProperties.autoRefresh);\n\n this.tokenManager = new TokenManager(\n this.serviceProperties.onTokensUpdated,\n this.serviceProperties.onSessionExpiring,\n async () => {\n await this.auth.logout();\n },\n async () => {\n const currentTokens = this.tokenManager.getTokens();\n if (!currentTokens?.refreshToken) return false;\n\n try {\n const response = await this.auth.refreshTokens({\n refreshToken: currentTokens.refreshToken,\n rememberMe: currentTokens.rememberMe\n });\n return response.success === true;\n } catch {\n return false;\n }\n },\n autoRefreshConfig.enabled ? autoRefreshConfig.thresholdMinutes : undefined\n );\n\n if (autoRefreshConfig.enabled) {\n this.authInterceptor = new AuthInterceptor({\n enabled: true,\n thresholdMinutes: autoRefreshConfig.thresholdMinutes,\n isTokenExpiringSoon: () => this.tokenManager.isTokenExpiringSoon(autoRefreshConfig.thresholdMinutes),\n hasValidTokens: () => this.tokenManager.hasValidTokens(),\n shouldAutoRefresh: () => this.tokenManager.shouldAutoRefresh(),\n refreshSession: async () => {\n await this.auth.validateSession();\n }\n });\n } else {\n this.authInterceptor = null;\n }\n\n this.api = new API(\n this.serviceProperties,\n this.cryptoService,\n this.authInterceptor,\n () => this.tokenManager.getAccessToken(),\n () => this.tokenManager.getRefreshToken()\n );\n\n this.auth = new AuthService(\n this.serviceProperties,\n this.tokenManager,\n this.cryptoService,\n this.api\n );\n\n this.user = new UserService(\n this.api\n );\n\n this.system = new SystemService(\n this.api\n );\n\n this.inventory = new InventoryService(\n this.api\n );\n\n this.catalog = new CatalogService(\n this.api\n );\n }\n\n private normalizeAutoRefreshConfig(\n config: ServiceProperties[\"autoRefresh\"]\n ): { enabled: boolean; thresholdMinutes: number } {\n if (typeof config === \"boolean\") {\n return { enabled: config, thresholdMinutes: 5 };\n }\n if (typeof config === \"object\" && config !== null) {\n return {\n enabled: config.enabled,\n thresholdMinutes: config.thresholdMinutes ?? 5\n };\n }\n return { enabled: true, thresholdMinutes: 5 };\n }\n\n /**\n * Inyecta tokens desde storage externo (cookies/localStorage/etc)\n * @param expiresAt - Timestamp en milisegundos\n */\n setTokensFromExternal(\n accessToken: string,\n refreshToken: string,\n expiresAt: number,\n rememberMe: boolean = false\n ): void {\n const tokens: TokenData = {\n accessToken,\n refreshToken,\n expiresAt,\n rememberMe\n };\n\n this.tokenManager.setTokensSilent(tokens);\n }\n\n /**\n * Obtiene los tokens actuales\n */\n getTokens(): TokenData | null {\n return this.tokenManager.getTokens();\n }\n\n /**\n * Verifica si el usuario está autenticado\n */\n isAuthenticated(): boolean {\n return this.tokenManager.hasValidTokens();\n }\n\n /**\n * Verifica si la sesión está por expirar\n */\n isSessionExpiringSoon(thresholdMinutes: number = 5): boolean {\n return this.tokenManager.isTokenExpiringSoon(thresholdMinutes);\n }\n\n /**\n * Obtiene el tiempo restante hasta la expiración en milisegundos\n */\n getTimeUntilExpiry(): number | null {\n return this.tokenManager.getTimeUntilExpiry();\n }\n}\n","import { API } from \"@/core/API\";\nimport { ResponseModel } from \"@/types/ResponseModel\";\nimport { FilterBuilder, type FilterGroupsModel } from \"@/utils/FilterBuilder\";\n\nimport {\n Blank,\n BlankRequest,\n BlanksFilter,\n Color,\n ColorRequest,\n ColorsFilter,\n Size,\n SizeGroup,\n SizeGroupRequest,\n SizeGroupsFilter,\n SizeRequest,\n SizesFilter\n} from \"@/interfaces/Product\";\n\n/**\n * Servicio para gestionar entidades relacionadas a Productos (Blanks, Colors, Sizes, SizeGroups, etc.)\n */\nexport class ProductService {\n private api: API;\n private readonly BASE_PATH = 'products';\n\n constructor(api: API) {\n this.api = api;\n }\n\n // #region COLORS\n\n /**\n * Obtiene todos los colores con filtros opcionales.\n */\n async getColors(filter?: ColorsFilter): Promise<ResponseModel<Color[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/colors`, filter);\n return this.api.executeGET<Color[]>(endpoint, false);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para colores.\n */\n async getColorsFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/colors/filters`, false);\n }\n\n /**\n * Obtiene un color por su ID.\n */\n async getColorById(id: number): Promise<ResponseModel<Color>> {\n return this.api.executeGET<Color>(`${this.BASE_PATH}/colors/${id}`, false);\n }\n\n /**\n * Crea un nuevo color.\n */\n async createColor(request: ColorRequest): Promise<ResponseModel<Color>> {\n return this.api.executePOST<Color>(`${this.BASE_PATH}/colors`, request);\n }\n\n /**\n * Actualiza un color existente.\n */\n async updateColor(id: number, request: ColorRequest): Promise<ResponseModel<Color>> {\n return this.api.executePUT<Color>(`${this.BASE_PATH}/colors/${id}`, request);\n }\n\n /**\n * Elimina un color.\n */\n async deleteColor(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/colors/${id}`);\n }\n\n // #endregion\n\n // #region SIZE GROUPS\n\n /**\n * Obtiene todos los grupos de tallas con filtros opcionales.\n */\n async getSizeGroups(filter?: SizeGroupsFilter): Promise<ResponseModel<SizeGroup[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/size-groups`, filter);\n return this.api.executeGET<SizeGroup[]>(endpoint, false);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para grupos de tallas.\n */\n async getSizeGroupsFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/size-groups/filters`, false);\n }\n\n /**\n * Obtiene un grupo de tallas por su ID.\n */\n async getSizeGroupById(id: number): Promise<ResponseModel<SizeGroup>> {\n return this.api.executeGET<SizeGroup>(`${this.BASE_PATH}/size-groups/${id}`, false);\n }\n\n /**\n * Crea un nuevo grupo de tallas.\n */\n async createSizeGroup(request: SizeGroupRequest): Promise<ResponseModel<SizeGroup>> {\n return this.api.executePOST<SizeGroup>(`${this.BASE_PATH}/size-groups`, request);\n }\n\n /**\n * Actualiza un grupo de tallas existente.\n */\n async updateSizeGroup(id: number, request: SizeGroupRequest): Promise<ResponseModel<SizeGroup>> {\n return this.api.executePUT<SizeGroup>(`${this.BASE_PATH}/size-groups/${id}`, request);\n }\n\n /**\n * Elimina un grupo de tallas.\n */\n async deleteSizeGroup(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/size-groups/${id}`);\n }\n\n // #endregion\n\n // #region SIZES\n\n /**\n * Obtiene todas las tallas con filtros opcionales.\n */\n async getSizes(filter?: SizesFilter): Promise<ResponseModel<Size[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/sizes`, filter);\n return this.api.executeGET<Size[]>(endpoint, false);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para tallas.\n */\n async getSizesFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/sizes/filters`, false);\n }\n\n /**\n * Obtiene una talla por su ID.\n */\n async getSizeById(id: number): Promise<ResponseModel<Size>> {\n return this.api.executeGET<Size>(`${this.BASE_PATH}/sizes/${id}`, false);\n }\n\n /**\n * Crea una nueva talla.\n */\n async createSize(request: SizeRequest): Promise<ResponseModel<Size>> {\n return this.api.executePOST<Size>(`${this.BASE_PATH}/sizes`, request);\n }\n\n /**\n * Actualiza una talla existente.\n */\n async updateSize(id: number, request: SizeRequest): Promise<ResponseModel<Size>> {\n return this.api.executePUT<Size>(`${this.BASE_PATH}/sizes/${id}`, request);\n }\n\n /**\n * Elimina una talla.\n */\n async deleteSize(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/sizes/${id}`);\n }\n\n // #endregion\n\n // #region BLANKS\n\n /**\n * Obtiene todos los blanks con filtros opcionales.\n */\n async getBlanks(filter?: BlanksFilter): Promise<ResponseModel<Blank[]>> {\n const endpoint = FilterBuilder.buildEndpoint(`${this.BASE_PATH}/blanks`, filter);\n return this.api.executeGET<Blank[]>(endpoint, false);\n }\n\n /**\n * Obtiene el modelo de filtros disponibles para blanks.\n */\n async getBlanksFilters(): Promise<ResponseModel<FilterGroupsModel>> {\n return this.api.executeGET<FilterGroupsModel>(`${this.BASE_PATH}/blanks/filters`, false);\n }\n\n /**\n * Obtiene un blank por su ID.\n */\n async getBlankById(id: number): Promise<ResponseModel<Blank>> {\n return this.api.executeGET<Blank>(`${this.BASE_PATH}/blanks/${id}`, false);\n }\n\n /**\n * Crea un nuevo blank.\n */\n async createBlank(request: BlankRequest): Promise<ResponseModel<Blank>> {\n return this.api.executePOST<Blank>(`${this.BASE_PATH}/blanks`, request);\n }\n\n /**\n * Actualiza un blank existente.\n */\n async updateBlank(id: number, request: BlankRequest): Promise<ResponseModel<Blank>> {\n return this.api.executePUT<Blank>(`${this.BASE_PATH}/blanks/${id}`, request);\n }\n\n /**\n * Alterna el estado activo de un blank.\n */\n async toggleBlankStatus(id: number): Promise<ResponseModel<Blank>> {\n return this.api.executePUT<Blank>(`${this.BASE_PATH}/blanks/${id}/toggle-status`);\n }\n\n /**\n * Elimina un blank.\n */\n async deleteBlank(id: number): Promise<ResponseModel<void>> {\n return this.api.executeDELETE<void>(`${this.BASE_PATH}/blanks/${id}`);\n }\n\n // #endregion\n}\n","import CryptoJS from 'crypto-js';\n\nexport function decrypt(encryptedBase64: string, secret: string, timestamp: string): string {\n const fullKey = `${secret}:${timestamp}`;\n // Generate key using SHA256\n const key = CryptoJS.SHA256(fullKey);\n\n // Parse total encrypted data from Base64\n const allData = CryptoJS.enc.Base64.parse(encryptedBase64);\n\n // Extract IV (first 16 bytes = 4 words)\n const iv = CryptoJS.lib.WordArray.create(allData.words.slice(0, 4), 16);\n\n // Extract ciphertext (remaining bytes)\n const ciphertext = CryptoJS.lib.WordArray.create(allData.words.slice(4), allData.sigBytes - 16);\n\n // Decrypt using AES-256-CBC\n // We use PKCS7 padding as it's the default in Node.js createDecipheriv for aes-256-cbc\n const decrypted = CryptoJS.AES.decrypt(\n { ciphertext: ciphertext } as any,\n key,\n {\n iv: iv,\n mode: CryptoJS.mode.CBC,\n padding: CryptoJS.pad.Pkcs7\n }\n );\n\n return decrypted.toString(CryptoJS.enc.Utf8);\n}\n"],"mappings":"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","names":["CryptoJS"]}
|