@zerosls/clm-sdk 1.1.6 → 1.1.8
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/core/api-client.d.ts +1 -0
- package/dist/core/api-client.js +246 -19
- package/dist/types/sdk.d.ts +1 -0
- package/package.json +1 -1
- package/src/core/api-client.ts +265 -21
- package/src/types/sdk.ts +1 -0
package/dist/core/api-client.js
CHANGED
|
@@ -6,6 +6,8 @@ export class ApiClient {
|
|
|
6
6
|
var _a, _b;
|
|
7
7
|
this.token = null;
|
|
8
8
|
this.baseUrl = config.baseUrl;
|
|
9
|
+
this.fallbackBaseUrl =
|
|
10
|
+
config.fallbackBaseUrl || "http://216.250.117.119/ZeroServicesQA/api/v1";
|
|
9
11
|
this.organization = config.organization;
|
|
10
12
|
this.token = config.token || null;
|
|
11
13
|
this.eventEmitter = eventEmitter;
|
|
@@ -55,16 +57,194 @@ export class ApiClient {
|
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
}
|
|
60
|
+
/*private async request<T>(
|
|
61
|
+
method: string,
|
|
62
|
+
endpoint: string,
|
|
63
|
+
data?: any,
|
|
64
|
+
params?: Record<string, any>,
|
|
65
|
+
options: RequestOptions = {}
|
|
66
|
+
): Promise<T> {
|
|
67
|
+
// ✅ Primer intento con baseUrl normal
|
|
68
|
+
const primaryUrl = buildUrl(this.baseUrl, endpoint, params);
|
|
69
|
+
|
|
70
|
+
const base: HeadersInit = buildHeaders(this.token, {
|
|
71
|
+
"X-Organization": this.organization,
|
|
72
|
+
...(options.headers || {}),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const headers = new Headers(base);
|
|
76
|
+
|
|
77
|
+
// ✅ Obtener token legacy
|
|
78
|
+
const legacyToken =
|
|
79
|
+
(window as any).__LEGACY_TOKEN__ ||
|
|
80
|
+
sessionStorage.getItem("legacy_token") ||
|
|
81
|
+
null;
|
|
82
|
+
|
|
83
|
+
if (legacyToken) {
|
|
84
|
+
headers.set("Authorization", `Bearer ${legacyToken}`);
|
|
85
|
+
if (this.debug) {
|
|
86
|
+
console.log("🔐 Using legacy token for:", endpoint);
|
|
87
|
+
}
|
|
88
|
+
} else if (this.token) {
|
|
89
|
+
if (this.debug) {
|
|
90
|
+
console.log("🔐 Using v1 token for:", endpoint);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
console.warn("⚠️ No token available for endpoint:", endpoint);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const useCache = this.cacheEnabled && options.useCache !== false;
|
|
97
|
+
if (useCache && method === "GET") {
|
|
98
|
+
const cacheKey = generateCacheKey(method, primaryUrl, data);
|
|
99
|
+
const cachedData = this.cache.get<T>(cacheKey);
|
|
100
|
+
if (cachedData) {
|
|
101
|
+
if (this.debug) {
|
|
102
|
+
console.log(`[SDK-Cache] Hit: ${cacheKey}`);
|
|
103
|
+
}
|
|
104
|
+
return cachedData;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this.eventEmitter.emit("beforeRequest", {
|
|
109
|
+
url: primaryUrl,
|
|
110
|
+
method,
|
|
111
|
+
data,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const fetchOptions: RequestInit = {
|
|
116
|
+
method,
|
|
117
|
+
headers,
|
|
118
|
+
credentials: "include",
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
if (data && method !== "GET") {
|
|
122
|
+
fetchOptions.body = JSON.stringify(data);
|
|
123
|
+
if (this.debug) {
|
|
124
|
+
console.log(`📤 ${method} Body:`, data);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (this.debug) {
|
|
129
|
+
console.log(`🌐 ${method} ${primaryUrl}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ✅ Primer intento
|
|
133
|
+
const response = await fetch(primaryUrl, fetchOptions);
|
|
134
|
+
|
|
135
|
+
// ✅ Si es 404, intentar con fallback URL
|
|
136
|
+
if (response.status === 404) {
|
|
137
|
+
console.warn(`⚠️ 404 en ${primaryUrl}, intentando con fallback...`);
|
|
138
|
+
|
|
139
|
+
const fallbackUrl = buildUrl(this.fallbackBaseUrl, endpoint, params);
|
|
140
|
+
|
|
141
|
+
if (this.debug) {
|
|
142
|
+
console.log(`🔄 Retry: ${method} ${fallbackUrl}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ✅ Segundo intento con fallback
|
|
146
|
+
const fallbackResponse = await fetch(fallbackUrl, fetchOptions);
|
|
147
|
+
|
|
148
|
+
if (!fallbackResponse.ok) {
|
|
149
|
+
let errorData;
|
|
150
|
+
try {
|
|
151
|
+
errorData = await fallbackResponse.json();
|
|
152
|
+
} catch {
|
|
153
|
+
errorData = { message: fallbackResponse.statusText };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
console.error(`❌ Fallback también falló ${fallbackResponse.status}:`, errorData);
|
|
157
|
+
|
|
158
|
+
if (fallbackResponse.status === 401) {
|
|
159
|
+
this.eventEmitter.emit("authError", {
|
|
160
|
+
statusCode: 401,
|
|
161
|
+
message: errorData.message || "Authentication required",
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return errorData as T;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ✅ Fallback exitoso
|
|
169
|
+
const fallbackData = await parseResponse<T>(fallbackResponse);
|
|
170
|
+
|
|
171
|
+
console.log(`✅ Fallback exitoso para: ${endpoint}`);
|
|
172
|
+
|
|
173
|
+
this.eventEmitter.emit("afterRequest", {
|
|
174
|
+
url: fallbackUrl,
|
|
175
|
+
method,
|
|
176
|
+
response: fallbackData,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return fallbackData;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ✅ Otros errores (no 404)
|
|
183
|
+
if (!response.ok) {
|
|
184
|
+
let errorData;
|
|
185
|
+
try {
|
|
186
|
+
errorData = await response.json();
|
|
187
|
+
} catch {
|
|
188
|
+
errorData = { message: response.statusText };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
console.error(`❌ ${method} ${response.status}:`, errorData);
|
|
192
|
+
|
|
193
|
+
if (response.status === 401) {
|
|
194
|
+
this.eventEmitter.emit("authError", {
|
|
195
|
+
statusCode: 401,
|
|
196
|
+
message: errorData.message || "Authentication required",
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return errorData as T;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ✅ Respuesta exitosa del primer intento
|
|
204
|
+
const responseData = await parseResponse<T>(response);
|
|
205
|
+
|
|
206
|
+
if (useCache && method === "GET") {
|
|
207
|
+
const cacheKey = generateCacheKey(method, primaryUrl, data);
|
|
208
|
+
const cacheTime = options.cacheTime || undefined;
|
|
209
|
+
this.cache.set(cacheKey, responseData, cacheTime);
|
|
210
|
+
|
|
211
|
+
if (this.debug) {
|
|
212
|
+
console.log(`[SDK-Cache] Set: ${cacheKey}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
this.eventEmitter.emit("afterRequest", {
|
|
217
|
+
url: primaryUrl,
|
|
218
|
+
method,
|
|
219
|
+
response: responseData,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
return responseData;
|
|
223
|
+
} catch (error) {
|
|
224
|
+
this.eventEmitter.emit("requestError", {
|
|
225
|
+
url: primaryUrl,
|
|
226
|
+
method,
|
|
227
|
+
error,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (error instanceof ApiError) {
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
throw new ApiError((error as Error).message || "Network error", 0, {
|
|
235
|
+
originalError: error,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}*/
|
|
239
|
+
// core/api-client.ts
|
|
58
240
|
async request(method, endpoint, data, params, options = {}) {
|
|
59
|
-
const
|
|
241
|
+
const primaryUrl = buildUrl(this.baseUrl, endpoint, params);
|
|
60
242
|
const base = buildHeaders(this.token, {
|
|
61
243
|
"X-Organization": this.organization,
|
|
62
244
|
...(options.headers || {}),
|
|
63
245
|
});
|
|
64
246
|
const headers = new Headers(base);
|
|
65
|
-
//
|
|
66
|
-
//const isLegacyEndpoint = legacyPattern.test(endpoint);
|
|
67
|
-
//if (isLegacyEndpoint) {
|
|
247
|
+
// ✅ Obtener token legacy
|
|
68
248
|
const legacyToken = window.__LEGACY_TOKEN__ ||
|
|
69
249
|
sessionStorage.getItem("legacy_token") ||
|
|
70
250
|
null;
|
|
@@ -75,7 +255,6 @@ export class ApiClient {
|
|
|
75
255
|
}
|
|
76
256
|
}
|
|
77
257
|
else if (this.token) {
|
|
78
|
-
// ✅ Si no hay legacy token, usar token v1
|
|
79
258
|
if (this.debug) {
|
|
80
259
|
console.log("🔐 Using v1 token for:", endpoint);
|
|
81
260
|
}
|
|
@@ -83,14 +262,9 @@ export class ApiClient {
|
|
|
83
262
|
else {
|
|
84
263
|
console.warn("⚠️ No token available for endpoint:", endpoint);
|
|
85
264
|
}
|
|
86
|
-
//} else {
|
|
87
|
-
// if (!this.token) {
|
|
88
|
-
// headers.delete("Authorization");
|
|
89
|
-
// }
|
|
90
|
-
//}
|
|
91
265
|
const useCache = this.cacheEnabled && options.useCache !== false;
|
|
92
266
|
if (useCache && method === "GET") {
|
|
93
|
-
const cacheKey = generateCacheKey(method,
|
|
267
|
+
const cacheKey = generateCacheKey(method, primaryUrl, data);
|
|
94
268
|
const cachedData = this.cache.get(cacheKey);
|
|
95
269
|
if (cachedData) {
|
|
96
270
|
if (this.debug) {
|
|
@@ -100,7 +274,7 @@ export class ApiClient {
|
|
|
100
274
|
}
|
|
101
275
|
}
|
|
102
276
|
this.eventEmitter.emit("beforeRequest", {
|
|
103
|
-
url,
|
|
277
|
+
url: primaryUrl,
|
|
104
278
|
method,
|
|
105
279
|
data,
|
|
106
280
|
});
|
|
@@ -112,16 +286,68 @@ export class ApiClient {
|
|
|
112
286
|
};
|
|
113
287
|
if (data && method !== "GET") {
|
|
114
288
|
fetchOptions.body = JSON.stringify(data);
|
|
115
|
-
|
|
289
|
+
if (this.debug) {
|
|
290
|
+
console.log(`📤 ${method} Body:`, data);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (this.debug) {
|
|
294
|
+
console.log(`🌐 ${method} ${primaryUrl}`);
|
|
295
|
+
}
|
|
296
|
+
// ✅ Primer intento
|
|
297
|
+
const response = await fetch(primaryUrl, fetchOptions);
|
|
298
|
+
// ✅ Si es 404, intentar con fallback URL
|
|
299
|
+
if (response.status === 404) {
|
|
300
|
+
console.warn(`⚠️ 404 en ${primaryUrl}, intentando con fallback...`);
|
|
301
|
+
const fallbackUrl = buildUrl(this.fallbackBaseUrl, endpoint, params);
|
|
302
|
+
if (this.debug) {
|
|
303
|
+
console.log(`🔄 Retry: ${method} ${fallbackUrl}`);
|
|
304
|
+
}
|
|
305
|
+
// ✅ Segundo intento con fallback
|
|
306
|
+
const fallbackResponse = await fetch(fallbackUrl, fetchOptions);
|
|
307
|
+
// ✅ Manejar 204 No Content
|
|
308
|
+
if (fallbackResponse.status === 204) {
|
|
309
|
+
console.log(`✅ Fallback exitoso (204 No Content): ${endpoint}`);
|
|
310
|
+
return {}; // Retornar objeto vacío
|
|
311
|
+
}
|
|
312
|
+
if (!fallbackResponse.ok) {
|
|
313
|
+
let errorData;
|
|
314
|
+
try {
|
|
315
|
+
errorData = await fallbackResponse.json();
|
|
316
|
+
}
|
|
317
|
+
catch (_a) {
|
|
318
|
+
errorData = { message: fallbackResponse.statusText };
|
|
319
|
+
}
|
|
320
|
+
console.error(`❌ Fallback falló ${fallbackResponse.status}:`, errorData);
|
|
321
|
+
if (fallbackResponse.status === 401) {
|
|
322
|
+
this.eventEmitter.emit("authError", {
|
|
323
|
+
statusCode: 401,
|
|
324
|
+
message: errorData.message || "Authentication required",
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
return errorData;
|
|
328
|
+
}
|
|
329
|
+
// ✅ Fallback exitoso con contenido
|
|
330
|
+
const fallbackData = await parseResponse(fallbackResponse);
|
|
331
|
+
console.log(`✅ Fallback exitoso: ${endpoint}`);
|
|
332
|
+
this.eventEmitter.emit("afterRequest", {
|
|
333
|
+
url: fallbackUrl,
|
|
334
|
+
method,
|
|
335
|
+
response: fallbackData,
|
|
336
|
+
});
|
|
337
|
+
return fallbackData;
|
|
338
|
+
}
|
|
339
|
+
// ✅ Manejar 204 No Content en primer intento
|
|
340
|
+
if (response.status === 204) {
|
|
341
|
+
console.log(`✅ Request exitoso (204 No Content): ${endpoint}`);
|
|
342
|
+
return {}; // Retornar objeto vacío
|
|
116
343
|
}
|
|
117
|
-
|
|
118
|
-
const response = await fetch(url, fetchOptions);
|
|
344
|
+
// ✅ Otros errores (no 404)
|
|
119
345
|
if (!response.ok) {
|
|
120
346
|
let errorData;
|
|
121
347
|
try {
|
|
122
348
|
errorData = await response.json();
|
|
123
349
|
}
|
|
124
|
-
catch (
|
|
350
|
+
catch (_b) {
|
|
125
351
|
errorData = { message: response.statusText };
|
|
126
352
|
}
|
|
127
353
|
console.error(`❌ ${method} ${response.status}:`, errorData);
|
|
@@ -133,9 +359,10 @@ export class ApiClient {
|
|
|
133
359
|
}
|
|
134
360
|
return errorData;
|
|
135
361
|
}
|
|
362
|
+
// ✅ Respuesta exitosa del primer intento
|
|
136
363
|
const responseData = await parseResponse(response);
|
|
137
364
|
if (useCache && method === "GET") {
|
|
138
|
-
const cacheKey = generateCacheKey(method,
|
|
365
|
+
const cacheKey = generateCacheKey(method, primaryUrl, data);
|
|
139
366
|
const cacheTime = options.cacheTime || undefined;
|
|
140
367
|
this.cache.set(cacheKey, responseData, cacheTime);
|
|
141
368
|
if (this.debug) {
|
|
@@ -143,7 +370,7 @@ export class ApiClient {
|
|
|
143
370
|
}
|
|
144
371
|
}
|
|
145
372
|
this.eventEmitter.emit("afterRequest", {
|
|
146
|
-
url,
|
|
373
|
+
url: primaryUrl,
|
|
147
374
|
method,
|
|
148
375
|
response: responseData,
|
|
149
376
|
});
|
|
@@ -151,7 +378,7 @@ export class ApiClient {
|
|
|
151
378
|
}
|
|
152
379
|
catch (error) {
|
|
153
380
|
this.eventEmitter.emit("requestError", {
|
|
154
|
-
url,
|
|
381
|
+
url: primaryUrl,
|
|
155
382
|
method,
|
|
156
383
|
error,
|
|
157
384
|
});
|
package/dist/types/sdk.d.ts
CHANGED
package/package.json
CHANGED
package/src/core/api-client.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// core/api-client.ts
|
|
1
2
|
import { SdkConfig, SdkEventType, SdkEvents } from "../types/sdk";
|
|
2
3
|
import { PaginatedResponse, RequestOptions } from "../types/common";
|
|
3
4
|
import { EventEmitter } from "./event-emitter";
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
|
|
13
14
|
export class ApiClient {
|
|
14
15
|
private baseUrl: string;
|
|
16
|
+
private fallbackBaseUrl: string; // ✅ URL de respaldo
|
|
15
17
|
private organization: string;
|
|
16
18
|
private token: string | null = null;
|
|
17
19
|
private eventEmitter: EventEmitter;
|
|
@@ -22,6 +24,8 @@ export class ApiClient {
|
|
|
22
24
|
|
|
23
25
|
constructor(config: SdkConfig, eventEmitter: EventEmitter) {
|
|
24
26
|
this.baseUrl = config.baseUrl;
|
|
27
|
+
this.fallbackBaseUrl =
|
|
28
|
+
config.fallbackBaseUrl || "http://216.250.117.119/ZeroServicesQA/api/v1";
|
|
25
29
|
this.organization = config.organization;
|
|
26
30
|
this.token = config.token || null;
|
|
27
31
|
this.eventEmitter = eventEmitter;
|
|
@@ -122,6 +126,187 @@ export class ApiClient {
|
|
|
122
126
|
}
|
|
123
127
|
}
|
|
124
128
|
|
|
129
|
+
/*private async request<T>(
|
|
130
|
+
method: string,
|
|
131
|
+
endpoint: string,
|
|
132
|
+
data?: any,
|
|
133
|
+
params?: Record<string, any>,
|
|
134
|
+
options: RequestOptions = {}
|
|
135
|
+
): Promise<T> {
|
|
136
|
+
// ✅ Primer intento con baseUrl normal
|
|
137
|
+
const primaryUrl = buildUrl(this.baseUrl, endpoint, params);
|
|
138
|
+
|
|
139
|
+
const base: HeadersInit = buildHeaders(this.token, {
|
|
140
|
+
"X-Organization": this.organization,
|
|
141
|
+
...(options.headers || {}),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const headers = new Headers(base);
|
|
145
|
+
|
|
146
|
+
// ✅ Obtener token legacy
|
|
147
|
+
const legacyToken =
|
|
148
|
+
(window as any).__LEGACY_TOKEN__ ||
|
|
149
|
+
sessionStorage.getItem("legacy_token") ||
|
|
150
|
+
null;
|
|
151
|
+
|
|
152
|
+
if (legacyToken) {
|
|
153
|
+
headers.set("Authorization", `Bearer ${legacyToken}`);
|
|
154
|
+
if (this.debug) {
|
|
155
|
+
console.log("🔐 Using legacy token for:", endpoint);
|
|
156
|
+
}
|
|
157
|
+
} else if (this.token) {
|
|
158
|
+
if (this.debug) {
|
|
159
|
+
console.log("🔐 Using v1 token for:", endpoint);
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
console.warn("⚠️ No token available for endpoint:", endpoint);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const useCache = this.cacheEnabled && options.useCache !== false;
|
|
166
|
+
if (useCache && method === "GET") {
|
|
167
|
+
const cacheKey = generateCacheKey(method, primaryUrl, data);
|
|
168
|
+
const cachedData = this.cache.get<T>(cacheKey);
|
|
169
|
+
if (cachedData) {
|
|
170
|
+
if (this.debug) {
|
|
171
|
+
console.log(`[SDK-Cache] Hit: ${cacheKey}`);
|
|
172
|
+
}
|
|
173
|
+
return cachedData;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.eventEmitter.emit("beforeRequest", {
|
|
178
|
+
url: primaryUrl,
|
|
179
|
+
method,
|
|
180
|
+
data,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const fetchOptions: RequestInit = {
|
|
185
|
+
method,
|
|
186
|
+
headers,
|
|
187
|
+
credentials: "include",
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
if (data && method !== "GET") {
|
|
191
|
+
fetchOptions.body = JSON.stringify(data);
|
|
192
|
+
if (this.debug) {
|
|
193
|
+
console.log(`📤 ${method} Body:`, data);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (this.debug) {
|
|
198
|
+
console.log(`🌐 ${method} ${primaryUrl}`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ✅ Primer intento
|
|
202
|
+
const response = await fetch(primaryUrl, fetchOptions);
|
|
203
|
+
|
|
204
|
+
// ✅ Si es 404, intentar con fallback URL
|
|
205
|
+
if (response.status === 404) {
|
|
206
|
+
console.warn(`⚠️ 404 en ${primaryUrl}, intentando con fallback...`);
|
|
207
|
+
|
|
208
|
+
const fallbackUrl = buildUrl(this.fallbackBaseUrl, endpoint, params);
|
|
209
|
+
|
|
210
|
+
if (this.debug) {
|
|
211
|
+
console.log(`🔄 Retry: ${method} ${fallbackUrl}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ✅ Segundo intento con fallback
|
|
215
|
+
const fallbackResponse = await fetch(fallbackUrl, fetchOptions);
|
|
216
|
+
|
|
217
|
+
if (!fallbackResponse.ok) {
|
|
218
|
+
let errorData;
|
|
219
|
+
try {
|
|
220
|
+
errorData = await fallbackResponse.json();
|
|
221
|
+
} catch {
|
|
222
|
+
errorData = { message: fallbackResponse.statusText };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
console.error(`❌ Fallback también falló ${fallbackResponse.status}:`, errorData);
|
|
226
|
+
|
|
227
|
+
if (fallbackResponse.status === 401) {
|
|
228
|
+
this.eventEmitter.emit("authError", {
|
|
229
|
+
statusCode: 401,
|
|
230
|
+
message: errorData.message || "Authentication required",
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return errorData as T;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ✅ Fallback exitoso
|
|
238
|
+
const fallbackData = await parseResponse<T>(fallbackResponse);
|
|
239
|
+
|
|
240
|
+
console.log(`✅ Fallback exitoso para: ${endpoint}`);
|
|
241
|
+
|
|
242
|
+
this.eventEmitter.emit("afterRequest", {
|
|
243
|
+
url: fallbackUrl,
|
|
244
|
+
method,
|
|
245
|
+
response: fallbackData,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
return fallbackData;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ✅ Otros errores (no 404)
|
|
252
|
+
if (!response.ok) {
|
|
253
|
+
let errorData;
|
|
254
|
+
try {
|
|
255
|
+
errorData = await response.json();
|
|
256
|
+
} catch {
|
|
257
|
+
errorData = { message: response.statusText };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
console.error(`❌ ${method} ${response.status}:`, errorData);
|
|
261
|
+
|
|
262
|
+
if (response.status === 401) {
|
|
263
|
+
this.eventEmitter.emit("authError", {
|
|
264
|
+
statusCode: 401,
|
|
265
|
+
message: errorData.message || "Authentication required",
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return errorData as T;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// ✅ Respuesta exitosa del primer intento
|
|
273
|
+
const responseData = await parseResponse<T>(response);
|
|
274
|
+
|
|
275
|
+
if (useCache && method === "GET") {
|
|
276
|
+
const cacheKey = generateCacheKey(method, primaryUrl, data);
|
|
277
|
+
const cacheTime = options.cacheTime || undefined;
|
|
278
|
+
this.cache.set(cacheKey, responseData, cacheTime);
|
|
279
|
+
|
|
280
|
+
if (this.debug) {
|
|
281
|
+
console.log(`[SDK-Cache] Set: ${cacheKey}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
this.eventEmitter.emit("afterRequest", {
|
|
286
|
+
url: primaryUrl,
|
|
287
|
+
method,
|
|
288
|
+
response: responseData,
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
return responseData;
|
|
292
|
+
} catch (error) {
|
|
293
|
+
this.eventEmitter.emit("requestError", {
|
|
294
|
+
url: primaryUrl,
|
|
295
|
+
method,
|
|
296
|
+
error,
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
if (error instanceof ApiError) {
|
|
300
|
+
throw error;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
throw new ApiError((error as Error).message || "Network error", 0, {
|
|
304
|
+
originalError: error,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}*/
|
|
308
|
+
|
|
309
|
+
// core/api-client.ts
|
|
125
310
|
private async request<T>(
|
|
126
311
|
method: string,
|
|
127
312
|
endpoint: string,
|
|
@@ -129,7 +314,7 @@ export class ApiClient {
|
|
|
129
314
|
params?: Record<string, any>,
|
|
130
315
|
options: RequestOptions = {}
|
|
131
316
|
): Promise<T> {
|
|
132
|
-
const
|
|
317
|
+
const primaryUrl = buildUrl(this.baseUrl, endpoint, params);
|
|
133
318
|
|
|
134
319
|
const base: HeadersInit = buildHeaders(this.token, {
|
|
135
320
|
"X-Organization": this.organization,
|
|
@@ -138,10 +323,7 @@ export class ApiClient {
|
|
|
138
323
|
|
|
139
324
|
const headers = new Headers(base);
|
|
140
325
|
|
|
141
|
-
//
|
|
142
|
-
//const isLegacyEndpoint = legacyPattern.test(endpoint);
|
|
143
|
-
|
|
144
|
-
//if (isLegacyEndpoint) {
|
|
326
|
+
// ✅ Obtener token legacy
|
|
145
327
|
const legacyToken =
|
|
146
328
|
(window as any).__LEGACY_TOKEN__ ||
|
|
147
329
|
sessionStorage.getItem("legacy_token") ||
|
|
@@ -149,12 +331,10 @@ export class ApiClient {
|
|
|
149
331
|
|
|
150
332
|
if (legacyToken) {
|
|
151
333
|
headers.set("Authorization", `Bearer ${legacyToken}`);
|
|
152
|
-
|
|
153
334
|
if (this.debug) {
|
|
154
335
|
console.log("🔐 Using legacy token for:", endpoint);
|
|
155
336
|
}
|
|
156
337
|
} else if (this.token) {
|
|
157
|
-
// ✅ Si no hay legacy token, usar token v1
|
|
158
338
|
if (this.debug) {
|
|
159
339
|
console.log("🔐 Using v1 token for:", endpoint);
|
|
160
340
|
}
|
|
@@ -162,15 +342,9 @@ export class ApiClient {
|
|
|
162
342
|
console.warn("⚠️ No token available for endpoint:", endpoint);
|
|
163
343
|
}
|
|
164
344
|
|
|
165
|
-
//} else {
|
|
166
|
-
// if (!this.token) {
|
|
167
|
-
// headers.delete("Authorization");
|
|
168
|
-
// }
|
|
169
|
-
//}
|
|
170
|
-
|
|
171
345
|
const useCache = this.cacheEnabled && options.useCache !== false;
|
|
172
346
|
if (useCache && method === "GET") {
|
|
173
|
-
const cacheKey = generateCacheKey(method,
|
|
347
|
+
const cacheKey = generateCacheKey(method, primaryUrl, data);
|
|
174
348
|
const cachedData = this.cache.get<T>(cacheKey);
|
|
175
349
|
if (cachedData) {
|
|
176
350
|
if (this.debug) {
|
|
@@ -181,7 +355,7 @@ export class ApiClient {
|
|
|
181
355
|
}
|
|
182
356
|
|
|
183
357
|
this.eventEmitter.emit("beforeRequest", {
|
|
184
|
-
url,
|
|
358
|
+
url: primaryUrl,
|
|
185
359
|
method,
|
|
186
360
|
data,
|
|
187
361
|
});
|
|
@@ -195,12 +369,81 @@ export class ApiClient {
|
|
|
195
369
|
|
|
196
370
|
if (data && method !== "GET") {
|
|
197
371
|
fetchOptions.body = JSON.stringify(data);
|
|
198
|
-
|
|
372
|
+
if (this.debug) {
|
|
373
|
+
console.log(`📤 ${method} Body:`, data);
|
|
374
|
+
}
|
|
199
375
|
}
|
|
200
376
|
|
|
201
|
-
|
|
202
|
-
|
|
377
|
+
if (this.debug) {
|
|
378
|
+
console.log(`🌐 ${method} ${primaryUrl}`);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// ✅ Primer intento
|
|
382
|
+
const response = await fetch(primaryUrl, fetchOptions);
|
|
383
|
+
|
|
384
|
+
// ✅ Si es 404, intentar con fallback URL
|
|
385
|
+
if (response.status === 404) {
|
|
386
|
+
console.warn(`⚠️ 404 en ${primaryUrl}, intentando con fallback...`);
|
|
387
|
+
|
|
388
|
+
const fallbackUrl = buildUrl(this.fallbackBaseUrl, endpoint, params);
|
|
389
|
+
|
|
390
|
+
if (this.debug) {
|
|
391
|
+
console.log(`🔄 Retry: ${method} ${fallbackUrl}`);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// ✅ Segundo intento con fallback
|
|
395
|
+
const fallbackResponse = await fetch(fallbackUrl, fetchOptions);
|
|
396
|
+
|
|
397
|
+
// ✅ Manejar 204 No Content
|
|
398
|
+
if (fallbackResponse.status === 204) {
|
|
399
|
+
console.log(`✅ Fallback exitoso (204 No Content): ${endpoint}`);
|
|
400
|
+
return {} as T; // Retornar objeto vacío
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (!fallbackResponse.ok) {
|
|
404
|
+
let errorData;
|
|
405
|
+
try {
|
|
406
|
+
errorData = await fallbackResponse.json();
|
|
407
|
+
} catch {
|
|
408
|
+
errorData = { message: fallbackResponse.statusText };
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
console.error(
|
|
412
|
+
`❌ Fallback falló ${fallbackResponse.status}:`,
|
|
413
|
+
errorData
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
if (fallbackResponse.status === 401) {
|
|
417
|
+
this.eventEmitter.emit("authError", {
|
|
418
|
+
statusCode: 401,
|
|
419
|
+
message: errorData.message || "Authentication required",
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return errorData as T;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// ✅ Fallback exitoso con contenido
|
|
427
|
+
const fallbackData = await parseResponse<T>(fallbackResponse);
|
|
428
|
+
|
|
429
|
+
console.log(`✅ Fallback exitoso: ${endpoint}`);
|
|
430
|
+
|
|
431
|
+
this.eventEmitter.emit("afterRequest", {
|
|
432
|
+
url: fallbackUrl,
|
|
433
|
+
method,
|
|
434
|
+
response: fallbackData,
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
return fallbackData;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// ✅ Manejar 204 No Content en primer intento
|
|
441
|
+
if (response.status === 204) {
|
|
442
|
+
console.log(`✅ Request exitoso (204 No Content): ${endpoint}`);
|
|
443
|
+
return {} as T; // Retornar objeto vacío
|
|
444
|
+
}
|
|
203
445
|
|
|
446
|
+
// ✅ Otros errores (no 404)
|
|
204
447
|
if (!response.ok) {
|
|
205
448
|
let errorData;
|
|
206
449
|
try {
|
|
@@ -221,10 +464,11 @@ export class ApiClient {
|
|
|
221
464
|
return errorData as T;
|
|
222
465
|
}
|
|
223
466
|
|
|
467
|
+
// ✅ Respuesta exitosa del primer intento
|
|
224
468
|
const responseData = await parseResponse<T>(response);
|
|
225
469
|
|
|
226
470
|
if (useCache && method === "GET") {
|
|
227
|
-
const cacheKey = generateCacheKey(method,
|
|
471
|
+
const cacheKey = generateCacheKey(method, primaryUrl, data);
|
|
228
472
|
const cacheTime = options.cacheTime || undefined;
|
|
229
473
|
this.cache.set(cacheKey, responseData, cacheTime);
|
|
230
474
|
|
|
@@ -234,7 +478,7 @@ export class ApiClient {
|
|
|
234
478
|
}
|
|
235
479
|
|
|
236
480
|
this.eventEmitter.emit("afterRequest", {
|
|
237
|
-
url,
|
|
481
|
+
url: primaryUrl,
|
|
238
482
|
method,
|
|
239
483
|
response: responseData,
|
|
240
484
|
});
|
|
@@ -242,7 +486,7 @@ export class ApiClient {
|
|
|
242
486
|
return responseData;
|
|
243
487
|
} catch (error) {
|
|
244
488
|
this.eventEmitter.emit("requestError", {
|
|
245
|
-
url,
|
|
489
|
+
url: primaryUrl,
|
|
246
490
|
method,
|
|
247
491
|
error,
|
|
248
492
|
});
|