@zerosls/clm-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/.docs/publicacion-npm.md +111 -0
  2. package/.env.example +14 -0
  3. package/.gitlab-ci.yml +23 -0
  4. package/README.md +202 -0
  5. package/dist/config/config.d.ts +3 -0
  6. package/dist/config/config.js +21 -0
  7. package/dist/core/api-client.d.ts +27 -0
  8. package/dist/core/api-client.js +183 -0
  9. package/dist/core/api-error.d.ts +15 -0
  10. package/dist/core/api-error.js +46 -0
  11. package/dist/core/event-emitter.d.ts +11 -0
  12. package/dist/core/event-emitter.js +32 -0
  13. package/dist/index.d.ts +41 -0
  14. package/dist/index.js +59 -0
  15. package/dist/modules/legacy/areas/areas-api.d.ts +34 -0
  16. package/dist/modules/legacy/areas/areas-api.js +44 -0
  17. package/dist/modules/legacy/areas/types.d.ts +37 -0
  18. package/dist/modules/legacy/areas/types.js +1 -0
  19. package/dist/modules/legacy/classificationtypes/classificationtypes-api.d.ts +34 -0
  20. package/dist/modules/legacy/classificationtypes/classificationtypes-api.js +46 -0
  21. package/dist/modules/legacy/classificationtypes/types.d.ts +41 -0
  22. package/dist/modules/legacy/classificationtypes/types.js +1 -0
  23. package/dist/modules/v1/auth/auth-api.d.ts +17 -0
  24. package/dist/modules/v1/auth/auth-api.js +63 -0
  25. package/dist/modules/v1/auth/types.d.ts +18 -0
  26. package/dist/modules/v1/auth/types.js +1 -0
  27. package/dist/modules/v1/main/main-api.d.ts +11 -0
  28. package/dist/modules/v1/main/main-api.js +14 -0
  29. package/dist/modules/v1/main/types.d.ts +3 -0
  30. package/dist/modules/v1/main/types.js +1 -0
  31. package/dist/modules/v1/notifications/notification-api.d.ts +16 -0
  32. package/dist/modules/v1/notifications/notification-api.js +26 -0
  33. package/dist/modules/v1/notifications/types.d.ts +53 -0
  34. package/dist/modules/v1/notifications/types.js +1 -0
  35. package/dist/modules/v1/users/types.d.ts +64 -0
  36. package/dist/modules/v1/users/types.js +1 -0
  37. package/dist/modules/v1/users/users-api.d.ts +81 -0
  38. package/dist/modules/v1/users/users-api.js +113 -0
  39. package/dist/types/common.d.ts +18 -0
  40. package/dist/types/common.js +1 -0
  41. package/dist/types/sdk.d.ts +42 -0
  42. package/dist/types/sdk.js +11 -0
  43. package/dist/utils/cache.d.ts +10 -0
  44. package/dist/utils/cache.js +43 -0
  45. package/dist/utils/http.d.ts +5 -0
  46. package/dist/utils/http.js +56 -0
  47. package/package.json +38 -0
  48. package/src/config/config.ts +24 -0
  49. package/src/core/api-client.ts +272 -0
  50. package/src/core/api-error.ts +54 -0
  51. package/src/core/event-emitter.ts +43 -0
  52. package/src/index.ts +89 -0
  53. package/src/modules/legacy/areas/areas-api.ts +73 -0
  54. package/src/modules/legacy/areas/types.ts +49 -0
  55. package/src/modules/legacy/classificationtypes/classificationtypes-api.ts +80 -0
  56. package/src/modules/legacy/classificationtypes/types.ts +52 -0
  57. package/src/modules/v1/auth/auth-api.ts +75 -0
  58. package/src/modules/v1/auth/types.ts +20 -0
  59. package/src/modules/v1/main/main-api.ts +20 -0
  60. package/src/modules/v1/main/types.ts +3 -0
  61. package/src/modules/v1/notifications/notification-api.ts +55 -0
  62. package/src/modules/v1/notifications/types.ts +58 -0
  63. package/src/modules/v1/users/types.ts +83 -0
  64. package/src/modules/v1/users/users-api.ts +148 -0
  65. package/src/types/common.ts +22 -0
  66. package/src/types/sdk.ts +38 -0
  67. package/src/utils/cache.ts +58 -0
  68. package/src/utils/http.ts +77 -0
  69. package/tests/integration/legacy/auth-areas.test.ts +115 -0
  70. package/tests/integration/legacy/auth-classification-types.test.ts +80 -0
  71. package/tests/integration/v1/auth-logs.test.ts +145 -0
  72. package/tests/integration/v1/auth-users.test.ts +189 -0
  73. package/tests/modules/legacy/areas/areas-api.test.ts +232 -0
  74. package/tests/modules/legacy/classification-types/classification-types-api.test.ts +100 -0
  75. package/tests/modules/v1/auth/auth-api.test.ts +134 -0
  76. package/tests/modules/v1/users/users-api.test.ts +176 -0
  77. package/tests/setup.ts +12 -0
  78. package/tests/utils/test-utils.ts +453 -0
  79. package/tsconfig.json +16 -0
  80. package/tsconfig.test.json +13 -0
  81. package/vitest.config.ts +16 -0
@@ -0,0 +1,111 @@
1
+ # Guía de Publicación del SDK
2
+
3
+ Este documento describe el proceso para publicar nuevas versiones del SDK en npm usando GitLab CI.
4
+
5
+ ## Requisitos previos
6
+
7
+ - Token NPM configurado en GitLab CI/CD Variables como `NPM_TOKEN`
8
+ - Archivo `.gitlab-ci.yml` correctamente configurado
9
+
10
+ ## Proceso de publicación
11
+
12
+ ### 1. Desarrollo y pruebas
13
+
14
+ ```bash
15
+ # Instalar dependencias
16
+ npm install
17
+
18
+ # Ejecutar pruebas
19
+ npm test
20
+
21
+ # Desarrollo con enlace local
22
+ npm link # En el SDK
23
+ npm link @zero/clm-sdk # En el proyecto frontend
24
+ ```
25
+
26
+ ### 2. Actualizar versión
27
+
28
+ ```bash
29
+ # Incremento de versión patch (1.0.0 -> 1.0.1)
30
+ npm version patch
31
+
32
+ # Incremento de versión minor (1.0.0 -> 1.1.0)
33
+ npm version minor
34
+
35
+ # Incremento de versión major (1.0.0 -> 2.0.0)
36
+ npm version major
37
+ ```
38
+
39
+ Estos comandos:
40
+ - Actualizan la versión en `package.json`
41
+ - Crean un commit con el cambio
42
+ - Crean un tag con formato `v1.0.0`
43
+
44
+ ### 3. Publicar a GitLab y npm
45
+
46
+ ```bash
47
+ # Enviar cambios y tags a GitLab
48
+ git push --follow-tags
49
+ ```
50
+
51
+ El pipeline de GitLab CI se activará automáticamente cuando detecte un tag con formato `v*`, compilando y publicando el paquete en npm.
52
+
53
+ ### 4. Verificar publicación
54
+
55
+ Verificar que la nueva versión aparece en npm:
56
+
57
+ ```bash
58
+ npm view @zero/clm-sdk versions
59
+ ```
60
+
61
+ ## Gestión de tags
62
+
63
+ ### Crear tag manualmente
64
+
65
+ ```bash
66
+ # Crear tag
67
+ git tag v1.0.1
68
+
69
+ # Enviar tag a GitLab
70
+ git push origin v1.0.1
71
+ ```
72
+
73
+ ### Eliminar tag (si es necesario)
74
+
75
+ ```bash
76
+ # Eliminar tag local
77
+ git tag -d v1.0.1
78
+
79
+ # Eliminar tag en GitLab
80
+ git push origin :refs/tags/v1.0.1
81
+ ```
82
+
83
+ ## Desarrollo con npm link
84
+
85
+ Para desarrollar el SDK mientras se prueba en un proyecto frontend:
86
+
87
+ ```bash
88
+ # En el directorio del SDK
89
+ npm link
90
+ npm run dev
91
+
92
+ # En el directorio del frontend
93
+ npm link @zero/clm-sdk
94
+ ```
95
+
96
+ Para desconectar:
97
+
98
+ ```bash
99
+ # En el directorio del frontend
100
+ npm unlink --no-save @zero/clm-sdk
101
+ npm install
102
+ ```
103
+
104
+ ## Solución de problemas
105
+
106
+ ### Fallo en la publicación
107
+
108
+ 1. Verificar logs en GitLab CI
109
+ 2. Comprobar que el token NPM es válido y está configurado correctamente
110
+ 3. Asegurar que la versión no existe ya en npm
111
+ ```
package/.env.example ADDED
@@ -0,0 +1,14 @@
1
+ # Base URL configuration
2
+ SDK_BASE_URL=https://dev-api.zeroclm.io/zeroclm-api
3
+ SDK_DEFAULT_ORGANIZATION=default-org
4
+
5
+ # Cache settings
6
+ SDK_CACHE_TTL=60000
7
+
8
+ # Version information
9
+ SDK_VERSION=1.0.0
10
+
11
+ # API endpoints
12
+ SDK_AUTH_ENDPOINT=/auth
13
+ SDK_USERS_ENDPOINT=/users
14
+ SDK_SETTINGS_ENDPOINT=/settings
package/.gitlab-ci.yml ADDED
@@ -0,0 +1,23 @@
1
+ stages:
2
+ - build
3
+ - publish
4
+
5
+ build:
6
+ stage: build
7
+ image: node:latest
8
+ script:
9
+ - npm ci
10
+ - npm run build
11
+ artifacts:
12
+ paths:
13
+ - dist/
14
+
15
+ publish:
16
+ stage: publish
17
+ image: node:latest
18
+ script:
19
+ - npm ci
20
+ - echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc
21
+ - npm publish --access public
22
+ rules:
23
+ - if: $CI_COMMIT_BRANCH == "main"
package/README.md ADDED
@@ -0,0 +1,202 @@
1
+ # CLM SDK
2
+
3
+ Cliente TypeScript para consumir la API de ZeroCLM.
4
+
5
+ ## Instalación
6
+
7
+ ```bash
8
+ npm install @zero/clm-sdk
9
+ ```
10
+
11
+ ## Uso básico
12
+
13
+ ```typescript
14
+ import { ClmSdk } from '@zero/clm-sdk';
15
+
16
+ // Crear instancia del SDK
17
+ const sdk = new ClmSdk({
18
+ baseUrl: 'https://api.clm-app.com/api', // URL base de la API
19
+ organization: 'mi-organizacion', // ID de organización
20
+ token: 'jwt-token-opcional' // Token JWT (opcional)
21
+ });
22
+
23
+ // Login
24
+ async function login() {
25
+ try {
26
+ const response = await sdk.auth.login({
27
+ email: 'usuario@ejemplo.com',
28
+ password: 'contraseña'
29
+ });
30
+
31
+ console.log('Usuario logueado:', response.user);
32
+ // El token se establece automáticamente para futuras peticiones
33
+ } catch (error) {
34
+ console.error('Error de login:', error);
35
+ }
36
+ }
37
+
38
+ // Obtener configuraciones
39
+ async function getSettings() {
40
+ try {
41
+ const settings = await sdk.settings.getAll({
42
+ group: 'general',
43
+ enabled: true
44
+ });
45
+
46
+ console.log('Configuraciones:', settings);
47
+ } catch (error) {
48
+ console.error('Error al obtener configuraciones:', error);
49
+ }
50
+ }
51
+ ```
52
+
53
+ ## Módulos disponibles
54
+
55
+ ### Auth
56
+
57
+ Gestión de autenticación y tokens:
58
+
59
+ ```typescript
60
+ // Login
61
+ const loginResponse = await sdk.auth.login({ email, password });
62
+
63
+ // Refresh token
64
+ const refreshResponse = await sdk.auth.refreshToken({ refreshToken });
65
+
66
+ // Logout
67
+ await sdk.auth.logout();
68
+
69
+ // Verificar si está autenticado
70
+ const isAuthenticated = sdk.auth.isAuthenticated();
71
+ ```
72
+
73
+ ### Settings
74
+
75
+ Gestión de configuraciones:
76
+
77
+ ```typescript
78
+ // Obtener todas las configuraciones
79
+ const settings = await sdk.settings.getAll();
80
+
81
+ // Obtener configuración por ID
82
+ const setting = await sdk.settings.getById('config-id');
83
+
84
+ // Obtener por grupo y nombre
85
+ const appName = await sdk.settings.getByName('general', 'app_name');
86
+
87
+ // Crear configuración
88
+ const newSetting = await sdk.settings.create({
89
+ group_name: 'app',
90
+ name: 'theme',
91
+ value: 'dark',
92
+ data_type: 'string',
93
+ description: 'Tema de la aplicación'
94
+ });
95
+
96
+ // Actualizar configuración
97
+ await sdk.settings.update('config-id', { value: 'nuevo-valor' });
98
+
99
+ // Activar/desactivar configuración
100
+ await sdk.settings.toggleEnabled('config-id', true);
101
+
102
+ // Eliminar configuración
103
+ await sdk.settings.delete('config-id');
104
+ ```
105
+
106
+ ## Manejo de errores
107
+
108
+ El SDK incluye un sistema de manejo de errores personalizado:
109
+
110
+ ```typescript
111
+ import { ApiError, ErrorType } from '@zero/clm-sdk';
112
+
113
+ try {
114
+ await sdk.settings.getById('id-inexistente');
115
+ } catch (error) {
116
+ if (error instanceof ApiError) {
117
+ console.log('Código de estado:', error.statusCode);
118
+ console.log('Tipo de error:', error.type);
119
+ console.log('Es error de autenticación:', error.isAuthenticationError);
120
+ console.log('Detalles:', error.details);
121
+ }
122
+ }
123
+ ```
124
+
125
+ ## Eventos
126
+
127
+ El SDK emite eventos que puedes escuchar:
128
+
129
+ ```typescript
130
+ // Escuchar cambios de token
131
+ const subscription = sdk.on('tokenChanged', (token) => {
132
+ console.log('Token cambiado:', token);
133
+ });
134
+
135
+ // Escuchar errores de autenticación
136
+ sdk.on('authError', (error) => {
137
+ console.log('Error de autenticación:', error);
138
+ // Redirigir a login, etc.
139
+ });
140
+
141
+ // Cancelar suscripción cuando ya no sea necesaria
142
+ subscription.unsubscribe();
143
+ ```
144
+
145
+ ## Caché
146
+
147
+ El SDK incluye un sistema de caché para optimizar peticiones:
148
+
149
+ ```typescript
150
+ // Limpiar toda la caché
151
+ sdk.cache.clear();
152
+
153
+ // Limpiar sólo caché de settings
154
+ sdk.cache.clearByPrefix('/settings');
155
+ ```
156
+
157
+ ## Configuración avanzada
158
+
159
+ ```typescript
160
+ const sdk = new ClmSdk({
161
+ baseUrl: 'https://api.clm-app.com/api',
162
+ organization: 'mi-organizacion',
163
+ cache: {
164
+ enabled: true, // Activar/desactivar caché
165
+ ttl: 60000 // Tiempo de vida en ms (default: 1 minuto)
166
+ },
167
+ debug: true // Activar logs de depuración
168
+ });
169
+ ```
170
+
171
+ ## Desarrollo
172
+
173
+ ### Instalación de dependencias
174
+
175
+ ```bash
176
+ npm install
177
+ ```
178
+
179
+ ### Ejecutar tests
180
+
181
+ ```bash
182
+ npm test # Ejecutar tests
183
+ npm run test:watch # Ejecutar tests en modo watch
184
+ npm run test:coverage # Generar reporte de cobertura
185
+ ```
186
+
187
+ ### Compilación
188
+
189
+ ```bash
190
+ npm run build # Compilar a JavaScript
191
+ npm run dev # Compilar en modo watch
192
+ ```
193
+
194
+ ### Lint
195
+
196
+ ```bash
197
+ npm run lint
198
+ ```
199
+
200
+ ## Licencia
201
+
202
+ MIT
@@ -0,0 +1,3 @@
1
+ import { SdkConfig } from "../types/sdk";
2
+ export declare const DEFAULT_CONFIG: Partial<SdkConfig>;
3
+ export declare function mergeWithDefaultConfig(config: Partial<SdkConfig>): SdkConfig;
@@ -0,0 +1,21 @@
1
+ // Valores por defecto para la configuración
2
+ export const DEFAULT_CONFIG = {
3
+ baseUrl: "https://api.clm-app.com/api",
4
+ organization: "default-org",
5
+ cache: {
6
+ enabled: true,
7
+ ttl: 60000, // 1 minuto
8
+ },
9
+ debug: true,
10
+ };
11
+ // Función para combinar configuración del usuario con valores por defecto
12
+ export function mergeWithDefaultConfig(config) {
13
+ return {
14
+ ...DEFAULT_CONFIG,
15
+ ...config,
16
+ cache: {
17
+ ...DEFAULT_CONFIG.cache,
18
+ ...(config.cache || {}), // Usar un objeto vacío si config.cache es undefined
19
+ },
20
+ };
21
+ }
@@ -0,0 +1,27 @@
1
+ import { SdkConfig } from "../types/sdk";
2
+ import { RequestOptions } from "../types/common";
3
+ import { EventEmitter } from "./event-emitter";
4
+ export declare class ApiClient {
5
+ private baseUrl;
6
+ private organization;
7
+ private token;
8
+ private eventEmitter;
9
+ private cache;
10
+ private debug;
11
+ private cacheEnabled;
12
+ constructor(config: SdkConfig, eventEmitter: EventEmitter);
13
+ setToken(token: string | null): void;
14
+ getToken(): string | null;
15
+ setOrganization(organization: string): void;
16
+ get<T>(endpoint: string, params?: Record<string, any>, options?: RequestOptions): Promise<T>;
17
+ post<T>(endpoint: string, data?: any, options?: RequestOptions): Promise<T>;
18
+ patch<T>(endpoint: string, data?: any, options?: RequestOptions): Promise<T>;
19
+ put<T>(endpoint: string, data?: any, options?: RequestOptions): Promise<T>;
20
+ delete<T>(endpoint: string, data?: any, // ✅ Cambiar params por data para enviarlo en el body
21
+ options?: RequestOptions): Promise<T>;
22
+ /**
23
+ * Invalida la caché relacionada con un endpoint específico
24
+ */
25
+ private invalidateCache;
26
+ private request;
27
+ }
@@ -0,0 +1,183 @@
1
+ import { ApiError } from "./api-error";
2
+ import { Cache } from "../utils/cache";
3
+ import { buildUrl, buildHeaders, generateCacheKey, parseResponse, } from "../utils/http";
4
+ export class ApiClient {
5
+ constructor(config, eventEmitter) {
6
+ var _a, _b;
7
+ this.token = null;
8
+ this.baseUrl = config.baseUrl;
9
+ this.organization = config.organization;
10
+ this.token = config.token || null;
11
+ this.eventEmitter = eventEmitter;
12
+ this.cacheEnabled = ((_a = config.cache) === null || _a === void 0 ? void 0 : _a.enabled) !== false;
13
+ this.cache = new Cache((_b = config.cache) === null || _b === void 0 ? void 0 : _b.ttl);
14
+ this.debug = config.debug || false;
15
+ }
16
+ // Métodos para gestión del token
17
+ setToken(token) {
18
+ this.token = token;
19
+ this.eventEmitter.emit("tokenChanged", token);
20
+ }
21
+ getToken() {
22
+ return this.token;
23
+ }
24
+ setOrganization(organization) {
25
+ this.organization = organization;
26
+ }
27
+ // Método GET
28
+ async get(endpoint, params, options) {
29
+ return this.request("GET", endpoint, undefined, params, options);
30
+ }
31
+ // Método POST
32
+ async post(endpoint, data, options) {
33
+ return this.request("POST", endpoint, data, undefined, options);
34
+ }
35
+ // Método PATCH
36
+ async patch(endpoint, data, options) {
37
+ const result = await this.request("PATCH", endpoint, data, undefined, options);
38
+ this.invalidateCache(endpoint);
39
+ return result;
40
+ }
41
+ // Método PUT
42
+ async put(endpoint, data, options) {
43
+ const result = await this.request("PUT", endpoint, data, undefined, options);
44
+ this.invalidateCache(endpoint);
45
+ return result;
46
+ }
47
+ // ✅ Método DELETE - CORREGIDO
48
+ async delete(endpoint, data, // ✅ Cambiar params por data para enviarlo en el body
49
+ options) {
50
+ console.log("🗑️ DELETE request:", { endpoint, data });
51
+ const result = await this.request("DELETE", endpoint, data, // ✅ Enviar como body (data)
52
+ undefined, // ✅ params es undefined
53
+ options);
54
+ this.invalidateCache(endpoint);
55
+ console.log("✅ DELETE response:", result);
56
+ return result;
57
+ }
58
+ /**
59
+ * Invalida la caché relacionada con un endpoint específico
60
+ */
61
+ invalidateCache(endpoint) {
62
+ if (this.cacheEnabled) {
63
+ const basePath = endpoint.split("/").slice(0, 2).join("/");
64
+ this.cache.clearByPrefix(`GET:${this.baseUrl}${basePath}`);
65
+ if (this.debug) {
66
+ console.log(`[SDK-Cache] Invalidated cache for: ${basePath}`);
67
+ }
68
+ }
69
+ }
70
+ // Método central para todas las peticiones HTTP
71
+ async request(method, endpoint, data, params, options = {}) {
72
+ const url = buildUrl(this.baseUrl, endpoint, params);
73
+ // =====================================================
74
+ // 1. Construir headers base
75
+ // =====================================================
76
+ const base = buildHeaders(this.token, {
77
+ "X-Organization": this.organization,
78
+ ...(options.headers || {}),
79
+ });
80
+ const headers = new Headers(base);
81
+ if (!this.token) {
82
+ headers.delete("Authorization");
83
+ }
84
+ // =====================================================
85
+ // 2. Si el endpoint es /legacy/** → agregar Bearer legacy
86
+ // =====================================================
87
+ if (endpoint.startsWith("/legacy/")) {
88
+ const legacyToken = window.__LEGACY_TOKEN__ ||
89
+ sessionStorage.getItem("legacy_token") ||
90
+ null;
91
+ if (legacyToken) {
92
+ headers.set("Authorization", `Bearer ${legacyToken}`);
93
+ }
94
+ }
95
+ // =====================================================
96
+ // 3. Cache
97
+ // =====================================================
98
+ const useCache = this.cacheEnabled && options.useCache !== false;
99
+ if (useCache && method === "GET") {
100
+ const cacheKey = generateCacheKey(method, url, data);
101
+ const cachedData = this.cache.get(cacheKey);
102
+ if (cachedData) {
103
+ if (this.debug) {
104
+ console.log(`[SDK-Cache] Hit: ${cacheKey}`);
105
+ }
106
+ return cachedData;
107
+ }
108
+ }
109
+ this.eventEmitter.emit("beforeRequest", {
110
+ url,
111
+ method,
112
+ data,
113
+ });
114
+ try {
115
+ // =====================================================
116
+ // 4. Preparar options de fetch
117
+ // =====================================================
118
+ const fetchOptions = {
119
+ method,
120
+ headers,
121
+ credentials: "include",
122
+ };
123
+ // ✅ CRÍTICO: Agregar body para POST, PUT, PATCH y DELETE
124
+ if (data && method !== "GET") {
125
+ fetchOptions.body = JSON.stringify(data);
126
+ console.log(`📤 ${method} Body:`, data);
127
+ }
128
+ // =====================================================
129
+ // 5. Hacer la llamada real
130
+ // =====================================================
131
+ console.log(`🌐 ${method} ${url}`, fetchOptions);
132
+ const response = await fetch(url, fetchOptions);
133
+ // Manejo de errores HTTP
134
+ if (!response.ok) {
135
+ let errorData;
136
+ try {
137
+ errorData = await response.json();
138
+ }
139
+ catch (_a) {
140
+ errorData = { message: response.statusText };
141
+ }
142
+ console.error(`❌ ${method} ${response.status}:`, errorData);
143
+ if (response.status === 401) {
144
+ this.eventEmitter.emit("authError", {
145
+ statusCode: 401,
146
+ message: errorData.message || "Authentication required",
147
+ });
148
+ }
149
+ return errorData;
150
+ }
151
+ // Parsear respuesta exitosa
152
+ const responseData = await parseResponse(response);
153
+ // Guardar en caché si aplica
154
+ if (useCache && method === "GET") {
155
+ const cacheKey = generateCacheKey(method, url, data);
156
+ const cacheTime = options.cacheTime || undefined;
157
+ this.cache.set(cacheKey, responseData, cacheTime);
158
+ if (this.debug) {
159
+ console.log(`[SDK-Cache] Set: ${cacheKey}`);
160
+ }
161
+ }
162
+ this.eventEmitter.emit("afterRequest", {
163
+ url,
164
+ method,
165
+ response: responseData,
166
+ });
167
+ return responseData;
168
+ }
169
+ catch (error) {
170
+ this.eventEmitter.emit("requestError", {
171
+ url,
172
+ method,
173
+ error,
174
+ });
175
+ if (error instanceof ApiError) {
176
+ throw error;
177
+ }
178
+ throw new ApiError(error.message || "Network error", 0, {
179
+ originalError: error,
180
+ });
181
+ }
182
+ }
183
+ }
@@ -0,0 +1,15 @@
1
+ import { ErrorType } from '../types/sdk';
2
+ export declare class ApiError extends Error {
3
+ readonly isApiError = true;
4
+ readonly statusCode: number;
5
+ readonly type: ErrorType;
6
+ readonly details?: any;
7
+ constructor(message: string, statusCode: number, details?: any);
8
+ private determineErrorType;
9
+ get isNetworkError(): boolean;
10
+ get isAuthenticationError(): boolean;
11
+ get isAuthorizationError(): boolean;
12
+ get isNotFoundError(): boolean;
13
+ get isValidationError(): boolean;
14
+ get isServerError(): boolean;
15
+ }
@@ -0,0 +1,46 @@
1
+ import { ErrorType } from '../types/sdk';
2
+ export class ApiError extends Error {
3
+ constructor(message, statusCode, details) {
4
+ super(message);
5
+ this.isApiError = true;
6
+ this.name = 'ApiError';
7
+ this.statusCode = statusCode;
8
+ this.details = details;
9
+ this.type = this.determineErrorType(statusCode);
10
+ // Para que instanceof funcione correctamente con clases extendidas
11
+ Object.setPrototypeOf(this, ApiError.prototype);
12
+ }
13
+ // Determina el tipo de error según el código HTTP
14
+ determineErrorType(statusCode) {
15
+ if (statusCode === 401)
16
+ return ErrorType.AUTHENTICATION;
17
+ if (statusCode === 403)
18
+ return ErrorType.AUTHORIZATION;
19
+ if (statusCode === 404)
20
+ return ErrorType.NOT_FOUND;
21
+ if (statusCode >= 400 && statusCode < 500)
22
+ return ErrorType.VALIDATION;
23
+ if (statusCode >= 500)
24
+ return ErrorType.SERVER;
25
+ return ErrorType.UNKNOWN;
26
+ }
27
+ // Propiedades útiles para verificación de tipo de error
28
+ get isNetworkError() {
29
+ return this.type === ErrorType.NETWORK;
30
+ }
31
+ get isAuthenticationError() {
32
+ return this.type === ErrorType.AUTHENTICATION;
33
+ }
34
+ get isAuthorizationError() {
35
+ return this.type === ErrorType.AUTHORIZATION;
36
+ }
37
+ get isNotFoundError() {
38
+ return this.type === ErrorType.NOT_FOUND;
39
+ }
40
+ get isValidationError() {
41
+ return this.type === ErrorType.VALIDATION;
42
+ }
43
+ get isServerError() {
44
+ return this.type === ErrorType.SERVER;
45
+ }
46
+ }
@@ -0,0 +1,11 @@
1
+ import { SdkEventType, SdkEvents } from '../types/sdk';
2
+ type Listener<T> = (data: T) => void;
3
+ interface Subscription {
4
+ unsubscribe: () => void;
5
+ }
6
+ export declare class EventEmitter {
7
+ private listeners;
8
+ on<K extends SdkEventType>(event: K, listener: Listener<SdkEvents[K]>): Subscription;
9
+ emit<K extends SdkEventType>(event: K, data: SdkEvents[K]): void;
10
+ }
11
+ export {};
@@ -0,0 +1,32 @@
1
+ export class EventEmitter {
2
+ constructor() {
3
+ this.listeners = new Map();
4
+ }
5
+ // Suscribirse a un evento
6
+ on(event, listener) {
7
+ if (!this.listeners.has(event)) {
8
+ this.listeners.set(event, []);
9
+ }
10
+ const eventListeners = this.listeners.get(event);
11
+ eventListeners.push(listener);
12
+ // Devolver objeto para cancelar suscripción
13
+ return {
14
+ unsubscribe: () => {
15
+ const index = eventListeners.indexOf(listener);
16
+ if (index !== -1) {
17
+ eventListeners.splice(index, 1);
18
+ }
19
+ }
20
+ };
21
+ }
22
+ // Emitir un evento con datos
23
+ emit(event, data) {
24
+ if (!this.listeners.has(event)) {
25
+ return;
26
+ }
27
+ const eventListeners = this.listeners.get(event);
28
+ for (const listener of eventListeners) {
29
+ listener(data);
30
+ }
31
+ }
32
+ }