@zerosls/clm-sdk 1.0.0 → 1.1.1

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.
@@ -1,21 +1,30 @@
1
- // Valores por defecto para la configuración
1
+ function normalizeUrl(url) {
2
+ return url.trim().replace(/\/+$/, "");
3
+ }
4
+ function resolveDefaultBaseUrl() {
5
+ var _a;
6
+ const fromWindow = (_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis.SDK_CONFIG) === null || _a === void 0 ? void 0 : _a.API_BASE_URL;
7
+ if (fromWindow)
8
+ return normalizeUrl(String(fromWindow));
9
+ return "https://api.clm-app.com/api";
10
+ }
2
11
  export const DEFAULT_CONFIG = {
3
- baseUrl: "https://api.clm-app.com/api",
12
+ baseUrl: resolveDefaultBaseUrl(),
4
13
  organization: "default-org",
5
- cache: {
6
- enabled: true,
7
- ttl: 60000, // 1 minuto
8
- },
14
+ cache: { enabled: true, ttl: 60000 },
9
15
  debug: true,
16
+ credentials: "include",
10
17
  };
11
- // Función para combinar configuración del usuario con valores por defecto
12
18
  export function mergeWithDefaultConfig(config) {
19
+ var _a;
13
20
  return {
14
21
  ...DEFAULT_CONFIG,
15
22
  ...config,
23
+ baseUrl: normalizeUrl(String((_a = config.baseUrl) !== null && _a !== void 0 ? _a : DEFAULT_CONFIG.baseUrl)),
16
24
  cache: {
17
25
  ...DEFAULT_CONFIG.cache,
18
- ...(config.cache || {}), // Usar un objeto vacío si config.cache es undefined
26
+ ...(config.cache || {}),
19
27
  },
28
+ credentials: config.credentials || DEFAULT_CONFIG.credentials,
20
29
  };
21
30
  }
@@ -9,6 +9,7 @@ export declare class ApiClient {
9
9
  private cache;
10
10
  private debug;
11
11
  private cacheEnabled;
12
+ private credentials;
12
13
  constructor(config: SdkConfig, eventEmitter: EventEmitter);
13
14
  setToken(token: string | null): void;
14
15
  getToken(): string | null;
@@ -17,11 +18,7 @@ export declare class ApiClient {
17
18
  post<T>(endpoint: string, data?: any, options?: RequestOptions): Promise<T>;
18
19
  patch<T>(endpoint: string, data?: any, options?: RequestOptions): Promise<T>;
19
20
  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
- */
21
+ delete<T>(endpoint: string, data?: any, options?: RequestOptions): Promise<T>;
25
22
  private invalidateCache;
26
23
  private request;
27
24
  }
@@ -12,8 +12,8 @@ export class ApiClient {
12
12
  this.cacheEnabled = ((_a = config.cache) === null || _a === void 0 ? void 0 : _a.enabled) !== false;
13
13
  this.cache = new Cache((_b = config.cache) === null || _b === void 0 ? void 0 : _b.ttl);
14
14
  this.debug = config.debug || false;
15
+ this.credentials = config.credentials || 'include';
15
16
  }
16
- // Métodos para gestión del token
17
17
  setToken(token) {
18
18
  this.token = token;
19
19
  this.eventEmitter.emit("tokenChanged", token);
@@ -24,40 +24,28 @@ export class ApiClient {
24
24
  setOrganization(organization) {
25
25
  this.organization = organization;
26
26
  }
27
- // Método GET
28
27
  async get(endpoint, params, options) {
29
28
  return this.request("GET", endpoint, undefined, params, options);
30
29
  }
31
- // Método POST
32
30
  async post(endpoint, data, options) {
33
31
  return this.request("POST", endpoint, data, undefined, options);
34
32
  }
35
- // Método PATCH
36
33
  async patch(endpoint, data, options) {
37
34
  const result = await this.request("PATCH", endpoint, data, undefined, options);
38
35
  this.invalidateCache(endpoint);
39
36
  return result;
40
37
  }
41
- // Método PUT
42
38
  async put(endpoint, data, options) {
43
39
  const result = await this.request("PUT", endpoint, data, undefined, options);
44
40
  this.invalidateCache(endpoint);
45
41
  return result;
46
42
  }
47
- // Método DELETE - CORREGIDO
48
- async delete(endpoint, data, // ✅ Cambiar params por data para enviarlo en el body
49
- options) {
43
+ async delete(endpoint, data, options) {
50
44
  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);
45
+ const result = await this.request("DELETE", endpoint, data, undefined, options);
54
46
  this.invalidateCache(endpoint);
55
- console.log("✅ DELETE response:", result);
56
47
  return result;
57
48
  }
58
- /**
59
- * Invalida la caché relacionada con un endpoint específico
60
- */
61
49
  invalidateCache(endpoint) {
62
50
  if (this.cacheEnabled) {
63
51
  const basePath = endpoint.split("/").slice(0, 2).join("/");
@@ -67,34 +55,29 @@ export class ApiClient {
67
55
  }
68
56
  }
69
57
  }
70
- // Método central para todas las peticiones HTTP
71
58
  async request(method, endpoint, data, params, options = {}) {
72
59
  const url = buildUrl(this.baseUrl, endpoint, params);
73
- // =====================================================
74
- // 1. Construir headers base
75
- // =====================================================
76
60
  const base = buildHeaders(this.token, {
77
61
  "X-Organization": this.organization,
78
62
  ...(options.headers || {}),
79
63
  });
80
64
  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/")) {
65
+ if (endpoint.startsWith('/legacy')) {
88
66
  const legacyToken = window.__LEGACY_TOKEN__ ||
89
67
  sessionStorage.getItem("legacy_token") ||
90
68
  null;
91
69
  if (legacyToken) {
92
70
  headers.set("Authorization", `Bearer ${legacyToken}`);
93
71
  }
72
+ else {
73
+ console.warn('⚠️ No legacy token available for legacy endpoint:', endpoint);
74
+ }
75
+ }
76
+ else {
77
+ if (!this.token) {
78
+ headers.delete("Authorization");
79
+ }
94
80
  }
95
- // =====================================================
96
- // 3. Cache
97
- // =====================================================
98
81
  const useCache = this.cacheEnabled && options.useCache !== false;
99
82
  if (useCache && method === "GET") {
100
83
  const cacheKey = generateCacheKey(method, url, data);
@@ -112,25 +95,17 @@ export class ApiClient {
112
95
  data,
113
96
  });
114
97
  try {
115
- // =====================================================
116
- // 4. Preparar options de fetch
117
- // =====================================================
118
98
  const fetchOptions = {
119
99
  method,
120
100
  headers,
121
101
  credentials: "include",
122
102
  };
123
- // ✅ CRÍTICO: Agregar body para POST, PUT, PATCH y DELETE
124
103
  if (data && method !== "GET") {
125
104
  fetchOptions.body = JSON.stringify(data);
126
105
  console.log(`📤 ${method} Body:`, data);
127
106
  }
128
- // =====================================================
129
- // 5. Hacer la llamada real
130
- // =====================================================
131
107
  console.log(`🌐 ${method} ${url}`, fetchOptions);
132
108
  const response = await fetch(url, fetchOptions);
133
- // Manejo de errores HTTP
134
109
  if (!response.ok) {
135
110
  let errorData;
136
111
  try {
@@ -148,9 +123,7 @@ export class ApiClient {
148
123
  }
149
124
  return errorData;
150
125
  }
151
- // Parsear respuesta exitosa
152
126
  const responseData = await parseResponse(response);
153
- // Guardar en caché si aplica
154
127
  if (useCache && method === "GET") {
155
128
  const cacheKey = generateCacheKey(method, url, data);
156
129
  const cacheTime = options.cacheTime || undefined;
package/dist/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import { AuthApi } from "./modules/v1/auth/auth-api";
4
4
  import { UsersApi } from "./modules/v1/users/users-api";
5
5
  import { MainApi } from "./modules/v1/main/main-api";
6
6
  import { NotificationsApi } from "./modules/v1/notifications/notification-api";
7
+ import { LogsApi } from "./modules/v1/_logs/logs-api";
7
8
  import { AreasApi } from "./modules/legacy/areas/areas-api";
8
9
  import { ClassificationTypesApi } from "./modules/legacy/classificationtypes/classificationtypes-api";
9
10
  /**
@@ -17,6 +18,7 @@ export declare class ClmSdk {
17
18
  users: UsersApi;
18
19
  main: MainApi;
19
20
  notifications: NotificationsApi;
21
+ logs: LogsApi;
20
22
  areas: AreasApi;
21
23
  classificationTypes: ClassificationTypesApi;
22
24
  constructor(config: Partial<SdkConfig>);
@@ -37,5 +39,6 @@ export * from "./types/sdk";
37
39
  export * from "./modules/v1/auth/types";
38
40
  export * from "./modules/v1/users/types";
39
41
  export * from "./modules/v1/notifications/types";
42
+ export * from "./modules/v1/_logs/types";
40
43
  export * from "./modules/legacy/areas/types";
41
44
  export * from "./modules/legacy/classificationtypes/types";
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { AuthApi } from "./modules/v1/auth/auth-api";
7
7
  import { UsersApi } from "./modules/v1/users/users-api";
8
8
  import { MainApi } from "./modules/v1/main/main-api";
9
9
  import { NotificationsApi } from "./modules/v1/notifications/notification-api";
10
- //import { LogsApi } from "./modules/v1/logs/logs-api";
10
+ import { LogsApi } from "./modules/v1/_logs/logs-api";
11
11
  // Legacy
12
12
  import { AreasApi } from "./modules/legacy/areas/areas-api";
13
13
  import { ClassificationTypesApi } from "./modules/legacy/classificationtypes/classificationtypes-api";
@@ -35,7 +35,7 @@ export class ClmSdk {
35
35
  this.users = new UsersApi(this.apiClient);
36
36
  this.main = new MainApi(this.apiClient);
37
37
  this.notifications = new NotificationsApi(this.apiClient);
38
- //this.logs = new LogsApi(this.apiClient);
38
+ this.logs = new LogsApi(this.apiClient);
39
39
  // Initialize legacy modules
40
40
  this.areas = new AreasApi(this.apiClient);
41
41
  this.classificationTypes = new ClassificationTypesApi(this.apiClient);
@@ -53,7 +53,7 @@ export * from "./types/sdk";
53
53
  export * from "./modules/v1/auth/types";
54
54
  export * from "./modules/v1/users/types";
55
55
  export * from "./modules/v1/notifications/types";
56
- //export * from "./modules/v1/logs/types";
56
+ export * from "./modules/v1/_logs/types";
57
57
  // Export legacy types
58
58
  export * from "./modules/legacy/areas/types";
59
59
  export * from "./modules/legacy/classificationtypes/types";
@@ -1,28 +1,14 @@
1
1
  import { ApiClient } from "../../../core/api-client";
2
+ import { RequestOptions } from "../../../types/common";
2
3
  import { CreateClassificationTypeRequest, UpdateClassificationTypeRequest, DeleteClassificationTypeRequest, ClassificationTypeResponse, ClassificationTypesResponse } from "./types";
3
4
  export declare class ClassificationTypesApi {
4
5
  private apiClient;
5
6
  private readonly basePath;
6
7
  constructor(apiClient: ApiClient);
7
- /**
8
- * GET - Obtener todos los tipos de clasificación
9
- */
10
- getClassificationTypes(): Promise<ClassificationTypesResponse>;
11
- /**
12
- * POST - Crear un nuevo tipo de clasificación
13
- */
14
- createClassificationType(data: CreateClassificationTypeRequest): Promise<ClassificationTypeResponse>;
15
- /**
16
- * PUT - Actualizar un tipo de clasificación existente
17
- */
18
- updateClassificationType(data: UpdateClassificationTypeRequest): Promise<ClassificationTypeResponse>;
19
- /**
20
- * DELETE - Eliminar un tipo de clasificación
21
- */
22
- deleteClassificationType(data: DeleteClassificationTypeRequest): Promise<ClassificationTypeResponse>;
23
- /**
24
- * Helper: Generar datos de auditoría actuales
25
- */
8
+ getClassificationTypes(options?: RequestOptions): Promise<ClassificationTypesResponse>;
9
+ createClassificationType(data: CreateClassificationTypeRequest, options?: RequestOptions): Promise<ClassificationTypeResponse>;
10
+ updateClassificationType(data: UpdateClassificationTypeRequest, options?: RequestOptions): Promise<ClassificationTypeResponse>;
11
+ deleteClassificationType(data: DeleteClassificationTypeRequest, options?: RequestOptions): Promise<ClassificationTypeResponse>;
26
12
  generateAuditData(userId: string, userName: string): {
27
13
  createdBy: string;
28
14
  createdByName: string;
@@ -3,35 +3,32 @@ export class ClassificationTypesApi {
3
3
  this.basePath = "/legacy/catalog/clasificationtype";
4
4
  this.apiClient = apiClient;
5
5
  }
6
- /**
7
- * GET - Obtener todos los tipos de clasificación
8
- */
9
- async getClassificationTypes() {
10
- return await this.apiClient.get(this.basePath, undefined, { useCache: false });
6
+ async getClassificationTypes(options) {
7
+ const requestOptions = {
8
+ ...options,
9
+ useCache: false
10
+ };
11
+ return await this.apiClient.get(this.basePath, undefined, requestOptions);
11
12
  }
12
- /**
13
- * POST - Crear un nuevo tipo de clasificación
14
- */
15
- async createClassificationType(data) {
16
- const response = await this.apiClient.post(`${this.basePath}/create`, data);
13
+ async createClassificationType(data, options) {
14
+ const requestOptions = {
15
+ ...options,
16
+ };
17
+ const response = await this.apiClient.post(`${this.basePath}/create`, data, requestOptions);
17
18
  return response;
18
19
  }
19
- /**
20
- * PUT - Actualizar un tipo de clasificación existente
21
- */
22
- async updateClassificationType(data) {
23
- return await this.apiClient.put(`${this.basePath}/update`, // Puede necesitar /update
24
- data);
20
+ async updateClassificationType(data, options) {
21
+ const requestOptions = {
22
+ ...options,
23
+ };
24
+ return await this.apiClient.put(`${this.basePath}/update`, data, requestOptions);
25
25
  }
26
- /**
27
- * DELETE - Eliminar un tipo de clasificación
28
- */
29
- async deleteClassificationType(data) {
30
- return await this.apiClient.delete(`${this.basePath}/delete`, data);
26
+ async deleteClassificationType(data, options) {
27
+ const requestOptions = {
28
+ ...options,
29
+ };
30
+ return await this.apiClient.delete(`${this.basePath}/delete`, data, requestOptions);
31
31
  }
32
- /**
33
- * Helper: Generar datos de auditoría actuales
34
- */
35
32
  generateAuditData(userId, userName) {
36
33
  const now = new Date().toISOString();
37
34
  return {
@@ -0,0 +1,43 @@
1
+ import { ApiClient } from "../../../core/api-client";
2
+ import { CreateLogRequest, LogResponse, LogsResponse, FindLogsQueryParams, CreateLogResponse, LogLevel, LogDestination, RequestDetailType } from "./types";
3
+ export declare class LogsApi {
4
+ private apiClient;
5
+ static readonly Level: typeof LogLevel;
6
+ static readonly Destination: typeof LogDestination;
7
+ static readonly RequestType: typeof RequestDetailType;
8
+ constructor(apiClient: ApiClient);
9
+ /**
10
+ * Crear un nuevo log
11
+ * @example
12
+ * await logsApi.createLog({
13
+ * level: LogsApi.Level.INFO,
14
+ * message: 'Usuario creado',
15
+ * source: 'users.create',
16
+ * destination: LogsApi.Destination.DB
17
+ * });
18
+ */
19
+ createLog(logData: CreateLogRequest): Promise<CreateLogResponse>;
20
+ /**
21
+ * Buscar logs con filtros y paginación
22
+ * @example
23
+ * await logsApi.findLogs({
24
+ * level: LogsApi.Level.ERROR,
25
+ * page: 1,
26
+ * limit: 25
27
+ * });
28
+ */
29
+ findLogs(filters?: FindLogsQueryParams): Promise<LogsResponse>;
30
+ /**
31
+ * Obtener un log específico por ID
32
+ */
33
+ findById(id: number): Promise<LogResponse>;
34
+ /**
35
+ * Buscar logs por contenido del mensaje
36
+ * @example
37
+ * await logsApi.findByMessage('Usuario creado', { page: 1, limit: 10 });
38
+ */
39
+ findByMessage(messageQuery: string, pagination?: {
40
+ page?: number;
41
+ limit?: number;
42
+ }): Promise<LogsResponse>;
43
+ }
@@ -0,0 +1,56 @@
1
+ import { buildQueryParams } from "../../../utils/http";
2
+ import { LogLevel, LogDestination, RequestDetailType } from "./types";
3
+ export class LogsApi {
4
+ constructor(apiClient) {
5
+ this.apiClient = apiClient;
6
+ }
7
+ /**
8
+ * Crear un nuevo log
9
+ * @example
10
+ * await logsApi.createLog({
11
+ * level: LogsApi.Level.INFO,
12
+ * message: 'Usuario creado',
13
+ * source: 'users.create',
14
+ * destination: LogsApi.Destination.DB
15
+ * });
16
+ */
17
+ async createLog(logData) {
18
+ return await this.apiClient.post('/logs', logData);
19
+ }
20
+ /**
21
+ * Buscar logs con filtros y paginación
22
+ * @example
23
+ * await logsApi.findLogs({
24
+ * level: LogsApi.Level.ERROR,
25
+ * page: 1,
26
+ * limit: 25
27
+ * });
28
+ */
29
+ async findLogs(filters = {}) {
30
+ const queryParams = buildQueryParams(filters);
31
+ return await this.apiClient.get("/logs" + queryParams, undefined, { useCache: false });
32
+ }
33
+ /**
34
+ * Obtener un log específico por ID
35
+ */
36
+ async findById(id) {
37
+ return await this.apiClient.get(`/logs/${id}`);
38
+ }
39
+ /**
40
+ * Buscar logs por contenido del mensaje
41
+ * @example
42
+ * await logsApi.findByMessage('Usuario creado', { page: 1, limit: 10 });
43
+ */
44
+ async findByMessage(messageQuery, pagination) {
45
+ const params = {
46
+ message: messageQuery,
47
+ ...pagination
48
+ };
49
+ const queryParams = buildQueryParams(params);
50
+ return await this.apiClient.get("/logs/search" + queryParams, undefined, { useCache: false });
51
+ }
52
+ }
53
+ // Exportar ENUMs como propiedades estáticas
54
+ LogsApi.Level = LogLevel;
55
+ LogsApi.Destination = LogDestination;
56
+ LogsApi.RequestType = RequestDetailType;
@@ -0,0 +1,86 @@
1
+ export declare enum LogLevel {
2
+ INFO = "info",
3
+ WARNING = "warning",
4
+ ERROR = "error",
5
+ DEBUG = "debug"
6
+ }
7
+ export declare enum LogDestination {
8
+ DB = "db",
9
+ FILE = "file",
10
+ BOTH = "both"
11
+ }
12
+ export declare enum RequestDetailType {
13
+ TRANSIT = "transit",
14
+ DOCUMENT = "document",
15
+ SIGN = "sign",
16
+ COMMENT = "comment"
17
+ }
18
+ export interface DocumentRequestDetail {
19
+ request_id?: number | null;
20
+ request_folio?: string | null;
21
+ type?: RequestDetailType | string | null;
22
+ start_state?: string | null;
23
+ next_stage?: string | null;
24
+ doc_anexo_name?: string | null;
25
+ upload_date?: string | null;
26
+ delete_date?: string | null;
27
+ approved_date?: string | null;
28
+ comment_date?: string | null;
29
+ comment?: string | null;
30
+ sign_date?: string | null;
31
+ signer_name?: string | null;
32
+ }
33
+ export interface Log {
34
+ id: number;
35
+ organization_id: number;
36
+ level: LogLevel | string;
37
+ message: string;
38
+ source: string;
39
+ user_id: number | null;
40
+ ip_address: string | null;
41
+ request_data: object | null;
42
+ request_detail: DocumentRequestDetail | object | null;
43
+ stack_trace: string | null;
44
+ created_at: string;
45
+ }
46
+ export interface CreateLogRequest {
47
+ level: LogLevel | 'info' | 'warning' | 'error' | 'debug';
48
+ message: string;
49
+ source: string;
50
+ destination?: LogDestination | 'db' | 'file' | 'both';
51
+ user_id?: number | null;
52
+ ip_address?: string | null;
53
+ request_data?: object | null;
54
+ request_detail?: DocumentRequestDetail | object | null;
55
+ stack_trace?: string | null;
56
+ }
57
+ export interface CreateLogResponse {
58
+ statusCode: number;
59
+ message: string;
60
+ data: Log;
61
+ }
62
+ export interface LogResponse extends Log {
63
+ }
64
+ export interface LogsResponse {
65
+ results: Log[];
66
+ pagination: {
67
+ page: number;
68
+ limit: number;
69
+ totalItems: number;
70
+ totalPages: number;
71
+ };
72
+ }
73
+ export interface FindLogsQueryParams {
74
+ level?: LogLevel | 'info' | 'warning' | 'error' | 'debug';
75
+ source?: string;
76
+ dateFrom?: string;
77
+ dateTo?: string;
78
+ userId?: number;
79
+ page?: number;
80
+ limit?: number;
81
+ }
82
+ export interface FindLogsByMessageParams {
83
+ message: string;
84
+ page?: number;
85
+ limit?: number;
86
+ }
@@ -0,0 +1,20 @@
1
+ export var LogLevel;
2
+ (function (LogLevel) {
3
+ LogLevel["INFO"] = "info";
4
+ LogLevel["WARNING"] = "warning";
5
+ LogLevel["ERROR"] = "error";
6
+ LogLevel["DEBUG"] = "debug";
7
+ })(LogLevel || (LogLevel = {}));
8
+ export var LogDestination;
9
+ (function (LogDestination) {
10
+ LogDestination["DB"] = "db";
11
+ LogDestination["FILE"] = "file";
12
+ LogDestination["BOTH"] = "both";
13
+ })(LogDestination || (LogDestination = {}));
14
+ export var RequestDetailType;
15
+ (function (RequestDetailType) {
16
+ RequestDetailType["TRANSIT"] = "transit";
17
+ RequestDetailType["DOCUMENT"] = "document";
18
+ RequestDetailType["SIGN"] = "sign";
19
+ RequestDetailType["COMMENT"] = "comment";
20
+ })(RequestDetailType || (RequestDetailType = {}));
@@ -7,6 +7,7 @@ export interface SdkConfig {
7
7
  ttl?: number;
8
8
  };
9
9
  debug?: boolean;
10
+ credentials?: RequestCredentials;
10
11
  }
11
12
  export type SdkEventType = "tokenChanged" | "beforeRequest" | "afterRequest" | "requestError" | "authError";
12
13
  export interface SdkEvents {
package/dist/types/sdk.js CHANGED
@@ -1,4 +1,3 @@
1
- // Tipos de errores HTTP
2
1
  export var ErrorType;
3
2
  (function (ErrorType) {
4
3
  ErrorType["NETWORK"] = "NETWORK";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerosls/clm-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "SDK for ZeroCLM API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,24 +1,33 @@
1
1
  import { SdkConfig } from "../types/sdk";
2
2
 
3
- // Valores por defecto para la configuración
3
+ function normalizeUrl(url: string) {
4
+ return url.trim().replace(/\/+$/, "");
5
+ }
6
+
7
+ function resolveDefaultBaseUrl(): string {
8
+ const fromWindow = (globalThis as any)?.SDK_CONFIG?.API_BASE_URL;
9
+ if (fromWindow) return normalizeUrl(String(fromWindow));
10
+ return "https://api.clm-app.com/api";
11
+ }
12
+
13
+
4
14
  export const DEFAULT_CONFIG: Partial<SdkConfig> = {
5
- baseUrl: "https://api.clm-app.com/api",
15
+ baseUrl: resolveDefaultBaseUrl(),
6
16
  organization: "default-org",
7
- cache: {
8
- enabled: true,
9
- ttl: 60000, // 1 minuto
10
- },
17
+ cache: { enabled: true, ttl: 60000 },
11
18
  debug: true,
19
+ credentials: "include",
12
20
  };
13
21
 
14
- // Función para combinar configuración del usuario con valores por defecto
15
22
  export function mergeWithDefaultConfig(config: Partial<SdkConfig>): SdkConfig {
16
23
  return {
17
24
  ...DEFAULT_CONFIG,
18
25
  ...config,
26
+ baseUrl: normalizeUrl(String(config.baseUrl ?? DEFAULT_CONFIG.baseUrl)),
19
27
  cache: {
20
28
  ...DEFAULT_CONFIG.cache,
21
- ...(config.cache || {}), // Usar un objeto vacío si config.cache es undefined
29
+ ...(config.cache || {}),
22
30
  },
31
+ credentials: config.credentials || DEFAULT_CONFIG.credentials,
23
32
  } as SdkConfig;
24
33
  }
@@ -18,6 +18,7 @@ export class ApiClient {
18
18
  private cache: Cache;
19
19
  private debug: boolean;
20
20
  private cacheEnabled: boolean;
21
+ private credentials: RequestCredentials;
21
22
 
22
23
  constructor(config: SdkConfig, eventEmitter: EventEmitter) {
23
24
  this.baseUrl = config.baseUrl;
@@ -27,9 +28,9 @@ export class ApiClient {
27
28
  this.cacheEnabled = config.cache?.enabled !== false;
28
29
  this.cache = new Cache(config.cache?.ttl);
29
30
  this.debug = config.debug || false;
31
+ this.credentials = config.credentials || 'include';
30
32
  }
31
33
 
32
- // Métodos para gestión del token
33
34
  public setToken(token: string | null): void {
34
35
  this.token = token;
35
36
  this.eventEmitter.emit("tokenChanged", token);
@@ -43,7 +44,6 @@ export class ApiClient {
43
44
  this.organization = organization;
44
45
  }
45
46
 
46
- // Método GET
47
47
  public async get<T>(
48
48
  endpoint: string,
49
49
  params?: Record<string, any>,
@@ -52,7 +52,6 @@ export class ApiClient {
52
52
  return this.request<T>("GET", endpoint, undefined, params, options);
53
53
  }
54
54
 
55
- // Método POST
56
55
  public async post<T>(
57
56
  endpoint: string,
58
57
  data?: any,
@@ -61,7 +60,6 @@ export class ApiClient {
61
60
  return this.request<T>("POST", endpoint, data, undefined, options);
62
61
  }
63
62
 
64
- // Método PATCH
65
63
  public async patch<T>(
66
64
  endpoint: string,
67
65
  data?: any,
@@ -78,7 +76,6 @@ export class ApiClient {
78
76
  return result;
79
77
  }
80
78
 
81
- // Método PUT
82
79
  public async put<T>(
83
80
  endpoint: string,
84
81
  data?: any,
@@ -95,30 +92,26 @@ export class ApiClient {
95
92
  return result;
96
93
  }
97
94
 
98
- // ✅ Método DELETE - CORREGIDO
99
95
  public async delete<T>(
100
96
  endpoint: string,
101
- data?: any, // ✅ Cambiar params por data para enviarlo en el body
97
+ data?: any,
102
98
  options?: RequestOptions
103
99
  ): Promise<T> {
104
100
  console.log("🗑️ DELETE request:", { endpoint, data });
105
-
101
+
106
102
  const result = await this.request<T>(
107
103
  "DELETE",
108
104
  endpoint,
109
- data, // ✅ Enviar como body (data)
110
- undefined, // ✅ params es undefined
105
+ data,
106
+ undefined,
111
107
  options
112
108
  );
113
-
109
+
114
110
  this.invalidateCache(endpoint);
115
- console.log("✅ DELETE response:", result);
116
111
  return result;
117
112
  }
118
113
 
119
- /**
120
- * Invalida la caché relacionada con un endpoint específico
121
- */
114
+
122
115
  private invalidateCache(endpoint: string): void {
123
116
  if (this.cacheEnabled) {
124
117
  const basePath = endpoint.split("/").slice(0, 2).join("/");
@@ -130,7 +123,6 @@ export class ApiClient {
130
123
  }
131
124
  }
132
125
 
133
- // Método central para todas las peticiones HTTP
134
126
  private async request<T>(
135
127
  method: string,
136
128
  endpoint: string,
@@ -140,9 +132,6 @@ export class ApiClient {
140
132
  ): Promise<T> {
141
133
  const url = buildUrl(this.baseUrl, endpoint, params);
142
134
 
143
- // =====================================================
144
- // 1. Construir headers base
145
- // =====================================================
146
135
  const base: HeadersInit = buildHeaders(this.token, {
147
136
  "X-Organization": this.organization,
148
137
  ...(options.headers || {}),
@@ -150,14 +139,7 @@ export class ApiClient {
150
139
 
151
140
  const headers = new Headers(base);
152
141
 
153
- if (!this.token) {
154
- headers.delete("Authorization");
155
- }
156
-
157
- // =====================================================
158
- // 2. Si el endpoint es /legacy/** → agregar Bearer legacy
159
- // =====================================================
160
- if (endpoint.startsWith("/legacy/")) {
142
+ if (endpoint.startsWith('/legacy')) {
161
143
  const legacyToken =
162
144
  (window as any).__LEGACY_TOKEN__ ||
163
145
  sessionStorage.getItem("legacy_token") ||
@@ -165,12 +147,16 @@ export class ApiClient {
165
147
 
166
148
  if (legacyToken) {
167
149
  headers.set("Authorization", `Bearer ${legacyToken}`);
150
+ } else {
151
+ console.warn('⚠️ No legacy token available for legacy endpoint:', endpoint);
152
+ }
153
+ } else {
154
+ if (!this.token) {
155
+ headers.delete("Authorization");
168
156
  }
169
157
  }
170
158
 
171
- // =====================================================
172
- // 3. Cache
173
- // =====================================================
159
+
174
160
  const useCache = this.cacheEnabled && options.useCache !== false;
175
161
  if (useCache && method === "GET") {
176
162
  const cacheKey = generateCacheKey(method, url, data);
@@ -190,28 +176,20 @@ export class ApiClient {
190
176
  });
191
177
 
192
178
  try {
193
- // =====================================================
194
- // 4. Preparar options de fetch
195
- // =====================================================
196
179
  const fetchOptions: RequestInit = {
197
180
  method,
198
181
  headers,
199
182
  credentials: "include",
200
183
  };
201
184
 
202
- // ✅ CRÍTICO: Agregar body para POST, PUT, PATCH y DELETE
203
185
  if (data && method !== "GET") {
204
186
  fetchOptions.body = JSON.stringify(data);
205
187
  console.log(`📤 ${method} Body:`, data);
206
188
  }
207
189
 
208
- // =====================================================
209
- // 5. Hacer la llamada real
210
- // =====================================================
211
190
  console.log(`🌐 ${method} ${url}`, fetchOptions);
212
191
  const response = await fetch(url, fetchOptions);
213
192
 
214
- // Manejo de errores HTTP
215
193
  if (!response.ok) {
216
194
  let errorData;
217
195
  try {
@@ -232,10 +210,8 @@ export class ApiClient {
232
210
  return errorData as T;
233
211
  }
234
212
 
235
- // Parsear respuesta exitosa
236
213
  const responseData = await parseResponse<T>(response);
237
214
 
238
- // Guardar en caché si aplica
239
215
  if (useCache && method === "GET") {
240
216
  const cacheKey = generateCacheKey(method, url, data);
241
217
  const cacheTime = options.cacheTime || undefined;
package/src/index.ts CHANGED
@@ -10,7 +10,7 @@ import { AuthApi } from "./modules/v1/auth/auth-api";
10
10
  import { UsersApi } from "./modules/v1/users/users-api";
11
11
  import { MainApi } from "./modules/v1/main/main-api";
12
12
  import { NotificationsApi } from "./modules/v1/notifications/notification-api";
13
- //import { LogsApi } from "./modules/v1/logs/logs-api";
13
+ import { LogsApi } from "./modules/v1/_logs/logs-api";
14
14
 
15
15
  // Legacy
16
16
  import { AreasApi } from "./modules/legacy/areas/areas-api";
@@ -29,7 +29,7 @@ export class ClmSdk {
29
29
  public users: UsersApi;
30
30
  public main: MainApi;
31
31
  public notifications: NotificationsApi;
32
- //public logs: LogsApi;
32
+ public logs: LogsApi;
33
33
 
34
34
  // Public modules legacy
35
35
  public areas: AreasApi;
@@ -50,7 +50,7 @@ export class ClmSdk {
50
50
  this.users = new UsersApi(this.apiClient);
51
51
  this.main = new MainApi(this.apiClient);
52
52
  this.notifications = new NotificationsApi(this.apiClient);
53
- //this.logs = new LogsApi(this.apiClient);
53
+ this.logs = new LogsApi(this.apiClient);
54
54
 
55
55
  // Initialize legacy modules
56
56
  this.areas = new AreasApi(this.apiClient);
@@ -83,7 +83,8 @@ export * from "./types/sdk";
83
83
  export * from "./modules/v1/auth/types";
84
84
  export * from "./modules/v1/users/types";
85
85
  export * from "./modules/v1/notifications/types";
86
- //export * from "./modules/v1/logs/types";
86
+ export * from "./modules/v1/_logs/types";
87
+
87
88
  // Export legacy types
88
89
  export * from "./modules/legacy/areas/types";
89
90
  export * from "./modules/legacy/classificationtypes/types";
@@ -1,4 +1,5 @@
1
1
  import { ApiClient } from "../../../core/api-client";
2
+ import { RequestOptions } from "../../../types/common";
2
3
  import {
3
4
  CreateClassificationTypeRequest,
4
5
  UpdateClassificationTypeRequest,
@@ -15,57 +16,65 @@ export class ClassificationTypesApi {
15
16
  this.apiClient = apiClient;
16
17
  }
17
18
 
18
- /**
19
- * GET - Obtener todos los tipos de clasificación
20
- */
21
- async getClassificationTypes(): Promise<ClassificationTypesResponse> {
19
+ async getClassificationTypes(options?: RequestOptions): Promise<ClassificationTypesResponse> {
20
+ const requestOptions: RequestOptions = {
21
+ ...options,
22
+ useCache: false
23
+ };
24
+
22
25
  return await this.apiClient.get<ClassificationTypesResponse>(
23
26
  this.basePath,
24
27
  undefined,
25
- { useCache: false }
28
+ requestOptions
26
29
  );
27
30
  }
28
31
 
29
- /**
30
- * POST - Crear un nuevo tipo de clasificación
31
- */
32
32
  async createClassificationType(
33
- data: CreateClassificationTypeRequest
33
+ data: CreateClassificationTypeRequest,
34
+ options?: RequestOptions
34
35
  ): Promise<ClassificationTypeResponse> {
36
+ const requestOptions: RequestOptions = {
37
+ ...options,
38
+ };
39
+
35
40
  const response = await this.apiClient.post<ClassificationTypeResponse>(
36
41
  `${this.basePath}/create`,
37
- data
42
+ data,
43
+ requestOptions
38
44
  );
39
45
  return response;
40
46
  }
41
47
 
42
- /**
43
- * PUT - Actualizar un tipo de clasificación existente
44
- */
45
48
  async updateClassificationType(
46
- data: UpdateClassificationTypeRequest
49
+ data: UpdateClassificationTypeRequest,
50
+ options?: RequestOptions
47
51
  ): Promise<ClassificationTypeResponse> {
52
+ const requestOptions: RequestOptions = {
53
+ ...options,
54
+ };
55
+
48
56
  return await this.apiClient.put<ClassificationTypeResponse>(
49
- `${this.basePath}/update`, // Puede necesitar /update
50
- data
57
+ `${this.basePath}/update`,
58
+ data,
59
+ requestOptions
51
60
  );
52
61
  }
53
62
 
54
- /**
55
- * DELETE - Eliminar un tipo de clasificación
56
- */
57
63
  async deleteClassificationType(
58
- data: DeleteClassificationTypeRequest
64
+ data: DeleteClassificationTypeRequest,
65
+ options?: RequestOptions
59
66
  ): Promise<ClassificationTypeResponse> {
67
+ const requestOptions: RequestOptions = {
68
+ ...options,
69
+ };
70
+
60
71
  return await this.apiClient.delete<ClassificationTypeResponse>(
61
72
  `${this.basePath}/delete`,
62
- data
73
+ data,
74
+ requestOptions
63
75
  );
64
76
  }
65
77
 
66
- /**
67
- * Helper: Generar datos de auditoría actuales
68
- */
69
78
  generateAuditData(userId: string, userName: string) {
70
79
  const now = new Date().toISOString();
71
80
  return {
@@ -0,0 +1,86 @@
1
+ import { ApiClient } from "../../../core/api-client";
2
+ import { buildQueryParams } from "../../../utils/http";
3
+ import {
4
+ CreateLogRequest,
5
+ LogResponse,
6
+ LogsResponse,
7
+ FindLogsQueryParams,
8
+ FindLogsByMessageParams,
9
+ CreateLogResponse,
10
+ LogLevel,
11
+ LogDestination,
12
+ RequestDetailType
13
+ } from "./types";
14
+
15
+ export class LogsApi {
16
+ private apiClient: ApiClient;
17
+
18
+ // Exportar ENUMs como propiedades estáticas
19
+ static readonly Level = LogLevel;
20
+ static readonly Destination = LogDestination;
21
+ static readonly RequestType = RequestDetailType;
22
+
23
+ constructor(apiClient: ApiClient) {
24
+ this.apiClient = apiClient;
25
+ }
26
+
27
+ /**
28
+ * Crear un nuevo log
29
+ * @example
30
+ * await logsApi.createLog({
31
+ * level: LogsApi.Level.INFO,
32
+ * message: 'Usuario creado',
33
+ * source: 'users.create',
34
+ * destination: LogsApi.Destination.DB
35
+ * });
36
+ */
37
+ async createLog(logData: CreateLogRequest): Promise<CreateLogResponse> {
38
+ return await this.apiClient.post<CreateLogResponse>('/logs', logData);
39
+ }
40
+
41
+ /**
42
+ * Buscar logs con filtros y paginación
43
+ * @example
44
+ * await logsApi.findLogs({
45
+ * level: LogsApi.Level.ERROR,
46
+ * page: 1,
47
+ * limit: 25
48
+ * });
49
+ */
50
+ async findLogs(filters: FindLogsQueryParams = {}): Promise<LogsResponse> {
51
+ const queryParams = buildQueryParams(filters);
52
+ return await this.apiClient.get<LogsResponse>(
53
+ "/logs" + queryParams,
54
+ undefined,
55
+ { useCache: false }
56
+ );
57
+ }
58
+
59
+ /**
60
+ * Obtener un log específico por ID
61
+ */
62
+ async findById(id: number): Promise<LogResponse> {
63
+ return await this.apiClient.get<LogResponse>(`/logs/${id}`);
64
+ }
65
+
66
+ /**
67
+ * Buscar logs por contenido del mensaje
68
+ * @example
69
+ * await logsApi.findByMessage('Usuario creado', { page: 1, limit: 10 });
70
+ */
71
+ async findByMessage(
72
+ messageQuery: string,
73
+ pagination?: { page?: number; limit?: number }
74
+ ): Promise<LogsResponse> {
75
+ const params: FindLogsByMessageParams = {
76
+ message: messageQuery,
77
+ ...pagination
78
+ };
79
+ const queryParams = buildQueryParams(params);
80
+ return await this.apiClient.get<LogsResponse>(
81
+ "/logs/search" + queryParams,
82
+ undefined,
83
+ { useCache: false }
84
+ );
85
+ }
86
+ }
@@ -0,0 +1,103 @@
1
+ export enum LogLevel {
2
+ INFO = 'info',
3
+ WARNING = 'warning',
4
+ ERROR = 'error',
5
+ DEBUG = 'debug'
6
+ }
7
+
8
+ export enum LogDestination {
9
+ DB = 'db',
10
+ FILE = 'file',
11
+ BOTH = 'both'
12
+ }
13
+
14
+ export enum RequestDetailType {
15
+ TRANSIT = 'transit',
16
+ DOCUMENT = 'document',
17
+ SIGN = 'sign',
18
+ COMMENT = 'comment'
19
+ }
20
+
21
+ // Estructura completa de request_detail según el API
22
+ export interface DocumentRequestDetail {
23
+ request_id?: number | null;
24
+ request_folio?: string | null;
25
+ type?: RequestDetailType | string | null;
26
+ start_state?: string | null;
27
+ next_stage?: string | null;
28
+ doc_anexo_name?: string | null;
29
+ upload_date?: string | null;
30
+ delete_date?: string | null;
31
+ approved_date?: string | null;
32
+ comment_date?: string | null;
33
+ comment?: string | null;
34
+ sign_date?: string | null;
35
+ signer_name?: string | null;
36
+ }
37
+
38
+ // Log completo (respuesta GET)
39
+ export interface Log {
40
+ id: number;
41
+ organization_id: number;
42
+ level: LogLevel | string;
43
+ message: string;
44
+ source: string;
45
+ user_id: number | null;
46
+ ip_address: string | null;
47
+ request_data: object | null;
48
+ request_detail: DocumentRequestDetail | object | null;
49
+ stack_trace: string | null;
50
+ created_at: string;
51
+ }
52
+
53
+ // Request para crear log (POST)
54
+ export interface CreateLogRequest {
55
+ level: LogLevel | 'info' | 'warning' | 'error' | 'debug';
56
+ message: string;
57
+ source: string;
58
+ destination?: LogDestination | 'db' | 'file' | 'both';
59
+ user_id?: number | null;
60
+ ip_address?: string | null;
61
+ request_data?: object | null;
62
+ request_detail?: DocumentRequestDetail | object | null;
63
+ stack_trace?: string | null;
64
+ }
65
+
66
+ // Respuesta al crear log (POST response)
67
+ export interface CreateLogResponse {
68
+ statusCode: number;
69
+ message: string;
70
+ data: Log;
71
+ }
72
+
73
+ // Respuesta de un log individual (GET /logs/:id)
74
+ export interface LogResponse extends Log {}
75
+
76
+ // Respuesta de lista de logs (GET /logs)
77
+ export interface LogsResponse {
78
+ results: Log[];
79
+ pagination: {
80
+ page: number;
81
+ limit: number;
82
+ totalItems: number;
83
+ totalPages: number;
84
+ };
85
+ }
86
+
87
+ // Parámetros de búsqueda
88
+ export interface FindLogsQueryParams {
89
+ level?: LogLevel | 'info' | 'warning' | 'error' | 'debug';
90
+ source?: string;
91
+ dateFrom?: string; // ISO date string
92
+ dateTo?: string; // ISO date string
93
+ userId?: number;
94
+ page?: number;
95
+ limit?: number;
96
+ }
97
+
98
+ // Parámetros de búsqueda por mensaje
99
+ export interface FindLogsByMessageParams {
100
+ message: string;
101
+ page?: number;
102
+ limit?: number;
103
+ }
@@ -1,22 +1,20 @@
1
1
  export interface PaginatedResponse<T> {
2
- results: T[];
3
- pagination: {
4
- page: number;
5
- limit: number;
6
- totalPages: number;
7
- totalItems: number;
8
- };
9
- }
10
-
11
- // Opciones para peticiones HTTP
12
- export interface RequestOptions {
13
- useCache?: boolean;
14
- cacheTime?: number;
15
- headers?: Record<string, string>;
16
- }
17
-
18
- // Parámetros de paginación
19
- export interface PaginationParams {
20
- page?: number;
21
- limit?: number;
22
- }
2
+ results: T[];
3
+ pagination: {
4
+ page: number;
5
+ limit: number;
6
+ totalPages: number;
7
+ totalItems: number;
8
+ };
9
+ }
10
+
11
+ export interface RequestOptions {
12
+ useCache?: boolean;
13
+ cacheTime?: number;
14
+ headers?: Record<string, string>;
15
+ }
16
+
17
+ export interface PaginationParams {
18
+ page?: number;
19
+ limit?: number;
20
+ }
package/src/types/sdk.ts CHANGED
@@ -7,9 +7,9 @@ export interface SdkConfig {
7
7
  ttl?: number;
8
8
  };
9
9
  debug?: boolean;
10
+ credentials?: RequestCredentials;
10
11
  }
11
12
 
12
- // Tipos de eventos que puede emitir el SDK
13
13
  export type SdkEventType =
14
14
  | "tokenChanged"
15
15
  | "beforeRequest"
@@ -17,7 +17,6 @@ export type SdkEventType =
17
17
  | "requestError"
18
18
  | "authError";
19
19
 
20
- // Información de evento por tipo
21
20
  export interface SdkEvents {
22
21
  tokenChanged: string | null;
23
22
  beforeRequest: { url: string; method: string; data?: any };
@@ -26,7 +25,6 @@ export interface SdkEvents {
26
25
  authError: { statusCode: number; message: string };
27
26
  }
28
27
 
29
- // Tipos de errores HTTP
30
28
  export enum ErrorType {
31
29
  NETWORK = "NETWORK",
32
30
  AUTHENTICATION = "AUTHENTICATION",
@@ -8,7 +8,7 @@ describe('ClassificationTypesApi', () => {
8
8
 
9
9
  beforeEach(() => {
10
10
  sdk = new ClmSdk({
11
- baseUrl: 'http://216.250.117.119/ZeroServicesQA/api/v1',
11
+ baseUrl: 'http://localhost:3001',
12
12
  organization: 'default-org',
13
13
  token: TOKEN
14
14
  });