@communecter/cocolight-api-client 1.0.2 → 1.0.5
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/package.json
CHANGED
package/src/ApiClient.js
CHANGED
|
@@ -273,34 +273,154 @@ export default class ApiClient extends EventEmitter {
|
|
|
273
273
|
}
|
|
274
274
|
return obj;
|
|
275
275
|
}
|
|
276
|
-
|
|
277
|
-
_resolveSpecialValuesInPlace(obj) {
|
|
278
|
-
// Si l'objet ressemble à un fichier uploadé (détecte la présence d'un stream dans la propriété value), ne rien modifier.
|
|
279
|
-
if (obj && typeof obj === "object" && obj.value && typeof obj.value.pipe === "function") {
|
|
280
|
-
return obj;
|
|
281
|
-
}
|
|
282
|
-
|
|
276
|
+
|
|
277
|
+
_resolveSpecialValuesInPlace(obj, pathParams = {}) {
|
|
283
278
|
const aliasMap = {
|
|
284
279
|
userId: () => this.userId,
|
|
285
280
|
accessToken: () => this._accessToken,
|
|
286
281
|
refreshToken: () => this._refreshToken,
|
|
287
282
|
baseURL: () => this._baseURL,
|
|
288
|
-
|
|
283
|
+
pathParams: (subPath) => {
|
|
284
|
+
// Si la valeur existe dans pathParams, on la retourne
|
|
285
|
+
const value = this._getValueByPath(pathParams, subPath);
|
|
286
|
+
return value !== undefined && value !== null ? value : undefined;
|
|
287
|
+
}
|
|
289
288
|
};
|
|
290
289
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
290
|
+
// Expression régulière qui capture les alias sous forme délimitée @{...} ou simple @...
|
|
291
|
+
const regex = /@(?:\{([^}]+)\}|([\w.]+))/g;
|
|
292
|
+
|
|
293
|
+
const resolveString = (str) => {
|
|
294
|
+
if (typeof str !== "string") return str;
|
|
295
|
+
return str.replace(regex, (_, delimitedAlias, plainAlias) => {
|
|
296
|
+
// Si alias délimité, on traite toute la chaîne à l'intérieur des accolades.
|
|
297
|
+
if (delimitedAlias) {
|
|
298
|
+
// On s'attend à une forme comme "pathParams.id.autre"
|
|
299
|
+
if (delimitedAlias.startsWith("pathParams.")) {
|
|
300
|
+
const subPath = delimitedAlias.substring("pathParams.".length);
|
|
301
|
+
const value = aliasMap.pathParams(subPath);
|
|
302
|
+
return value !== undefined && value !== null ? value : `@{${delimitedAlias}}`;
|
|
303
|
+
} else {
|
|
304
|
+
// Pour d'autres alias délimités, on cherche directement dans aliasMap
|
|
305
|
+
const fn = aliasMap[delimitedAlias];
|
|
306
|
+
if (typeof fn === "function") {
|
|
307
|
+
const value = fn();
|
|
308
|
+
return value !== undefined && value !== null ? value : `@{${delimitedAlias}}`;
|
|
309
|
+
}
|
|
310
|
+
return `@{${delimitedAlias}}`;
|
|
311
|
+
}
|
|
312
|
+
} else if (plainAlias) {
|
|
313
|
+
// Traitement de l'alias simple, potentiellement avec des segments
|
|
314
|
+
// Vérifier s'il commence par "pathParams."
|
|
315
|
+
if (plainAlias.startsWith("pathParams.")) {
|
|
316
|
+
// Extrait la partie après "pathParams." et sépare le premier segment et le reste.
|
|
317
|
+
const match = plainAlias.match(/^pathParams\.([^.]+)(.*)$/);
|
|
318
|
+
if (match) {
|
|
319
|
+
const subKey = match[1]; // ex: "id"
|
|
320
|
+
const remainder = match[2]; // ex: "" ou ".autrechose"
|
|
321
|
+
// Si le reste est vide, ou s'il ne doit pas être remplacé (on remplace toujours le premier segment uniquement)
|
|
322
|
+
const value = aliasMap.pathParams(subKey);
|
|
323
|
+
return value !== undefined && value !== null ? value + remainder : `@${plainAlias}`;
|
|
324
|
+
}
|
|
325
|
+
return `@${plainAlias}`;
|
|
326
|
+
} else {
|
|
327
|
+
// Pour tout autre alias simple sans point ou autre
|
|
328
|
+
const fn = aliasMap[plainAlias];
|
|
329
|
+
if (typeof fn === "function") {
|
|
330
|
+
const value = fn();
|
|
331
|
+
return value !== undefined && value !== null ? value : `@${plainAlias}`;
|
|
332
|
+
}
|
|
333
|
+
return `@${plainAlias}`;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return str;
|
|
337
|
+
});
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
// Vérifie si l'objet est un binaire (par exemple un flux ou un Buffer)
|
|
342
|
+
const isBinary = (input) => {
|
|
343
|
+
return input && typeof input === "object" &&
|
|
344
|
+
(typeof input.pipe === "function" || (typeof Buffer !== "undefined" && input instanceof Buffer));
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
// Vérifie si l'objet est un "plain object"
|
|
348
|
+
const isPlainObject = (input) => {
|
|
349
|
+
return Object.prototype.toString.call(input) === "[object Object]";
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const internal = (input) => {
|
|
353
|
+
// Si c'est un binaire, ne rien modifier
|
|
354
|
+
if (isBinary(input)) {
|
|
355
|
+
return input;
|
|
356
|
+
}
|
|
357
|
+
// Si c'est un tableau, on traite chaque élément
|
|
358
|
+
if (Array.isArray(input)) {
|
|
359
|
+
return input.map(internal);
|
|
360
|
+
}
|
|
361
|
+
// Si c'est un plain object, on crée un nouvel objet avec remplacement dans les clés et valeurs
|
|
362
|
+
if (isPlainObject(input)) {
|
|
363
|
+
const result = {};
|
|
364
|
+
for (const [key, value] of Object.entries(input)) {
|
|
365
|
+
const resolvedKey = resolveString(key);
|
|
366
|
+
result[resolvedKey] = internal(value);
|
|
367
|
+
}
|
|
368
|
+
return result;
|
|
369
|
+
}
|
|
370
|
+
// Si c'est une string, on applique le remplacement
|
|
371
|
+
if (typeof input === "string") {
|
|
372
|
+
return resolveString(input);
|
|
297
373
|
}
|
|
374
|
+
// Sinon (nombre, booléen, etc.), on retourne la valeur telle quelle
|
|
375
|
+
return input;
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
return internal(obj);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
_cleanSchemaLeftoverAlias(obj) {
|
|
383
|
+
// Expression régulière qui détecte n'importe quel alias du type "@quelqueChose"
|
|
384
|
+
const aliasRegex = /@\w+/;
|
|
385
|
+
|
|
386
|
+
if (Array.isArray(obj)) {
|
|
387
|
+
return obj.map(item => this._cleanSchemaLeftoverAlias(item));
|
|
298
388
|
} else if (obj && typeof obj === "object") {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
389
|
+
const newObj = {};
|
|
390
|
+
for (const key of Object.keys(obj)) {
|
|
391
|
+
const val = obj[key];
|
|
392
|
+
|
|
393
|
+
// Si le nom de la clé contient un alias (exemple : "@userId", "@anything"), on ne la copie pas
|
|
394
|
+
if (aliasRegex.test(key)) {
|
|
395
|
+
continue;
|
|
302
396
|
}
|
|
397
|
+
|
|
398
|
+
// Si la propriété s'appelle "default"
|
|
399
|
+
if (key === "default") {
|
|
400
|
+
// Si la valeur est une chaîne et qu'elle contient un alias, on ne la copie pas
|
|
401
|
+
if (typeof val === "string" && aliasRegex.test(val)) {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
// Si la valeur est un objet, on le nettoie récursivement
|
|
405
|
+
if (val && typeof val === "object") {
|
|
406
|
+
const cleanedDefault = this._cleanSchemaLeftoverAlias(val);
|
|
407
|
+
// On ajoute seulement si l'objet nettoyé n'est pas vide
|
|
408
|
+
if (Object.keys(cleanedDefault).length > 0) {
|
|
409
|
+
newObj[key] = cleanedDefault;
|
|
410
|
+
}
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Si la valeur est une chaîne contenant un alias, on ne la copie pas
|
|
416
|
+
if (typeof val === "string" && aliasRegex.test(val)) {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Sinon, on nettoie récursivement la valeur
|
|
421
|
+
newObj[key] = this._cleanSchemaLeftoverAlias(val);
|
|
303
422
|
}
|
|
423
|
+
return newObj;
|
|
304
424
|
}
|
|
305
425
|
return obj;
|
|
306
426
|
}
|
|
@@ -356,9 +476,17 @@ export default class ApiClient extends EventEmitter {
|
|
|
356
476
|
|
|
357
477
|
// === 1. PathParams ===
|
|
358
478
|
let resolvedPath = path;
|
|
479
|
+
let resolvedParams = {};
|
|
359
480
|
if (pathSchema) {
|
|
481
|
+
|
|
482
|
+
// Si auth est "none" et que userId n'est pas défini, on nettoie le schéma
|
|
483
|
+
let schemaToCompile = pathSchema;
|
|
484
|
+
if (auth === "none" && this.userId === null) {
|
|
485
|
+
schemaToCompile = this._cleanSchemaLeftoverAlias(pathSchema);
|
|
486
|
+
}
|
|
487
|
+
|
|
360
488
|
const pathParams = data.pathParams || {};
|
|
361
|
-
const validatePathParams = this._ajv.compile(
|
|
489
|
+
const validatePathParams = this._ajv.compile(schemaToCompile);
|
|
362
490
|
const valid = validatePathParams(pathParams);
|
|
363
491
|
|
|
364
492
|
if (!valid) {
|
|
@@ -366,7 +494,7 @@ export default class ApiClient extends EventEmitter {
|
|
|
366
494
|
throw new ApiClientError("Path parameter validation failed.", 400, validatePathParams.errors);
|
|
367
495
|
}
|
|
368
496
|
|
|
369
|
-
|
|
497
|
+
resolvedParams = this._resolveSpecialValuesInPlace(pathParams);
|
|
370
498
|
|
|
371
499
|
resolvedPath = resolvedPath.replace(/\{(\w+)\}/g, (_, key) => {
|
|
372
500
|
const val = resolvedParams[key];
|
|
@@ -377,18 +505,24 @@ export default class ApiClient extends EventEmitter {
|
|
|
377
505
|
|
|
378
506
|
// === 2. Validation données (request schema) ===
|
|
379
507
|
if (requestSchema) {
|
|
508
|
+
// Si auth est "none" et que userId n'est pas défini, on nettoie le schéma
|
|
509
|
+
let schemaToCompile = requestSchema;
|
|
510
|
+
if (auth === "none" && this.userId === null) {
|
|
511
|
+
schemaToCompile = this._cleanSchemaLeftoverAlias(requestSchema);
|
|
512
|
+
}
|
|
513
|
+
|
|
380
514
|
const dataForValidation = { ...data };
|
|
381
515
|
delete dataForValidation.pathParams;
|
|
382
516
|
const cleanedData = ApiClient.stripNullsInPlace(dataForValidation);
|
|
383
|
-
|
|
384
|
-
const validateRequest = this._ajv.compile(
|
|
517
|
+
|
|
518
|
+
const validateRequest = this._ajv.compile(schemaToCompile);
|
|
385
519
|
const valid = validateRequest(cleanedData);
|
|
386
520
|
if (!valid) {
|
|
387
521
|
this.emit("validationError", { stage: "request", errors: validateRequest.errors });
|
|
388
522
|
throw new ApiClientError("Request validation failed.", 400, validateRequest.errors);
|
|
389
523
|
}
|
|
390
524
|
|
|
391
|
-
data = this._resolveSpecialValuesInPlace(cleanedData);
|
|
525
|
+
data = this._resolveSpecialValuesInPlace(cleanedData, resolvedParams);
|
|
392
526
|
}
|
|
393
527
|
|
|
394
528
|
// === 3. Payload ===
|
|
@@ -821,28 +955,28 @@ export default class ApiClient extends EventEmitter {
|
|
|
821
955
|
* @param {Object} obj - L’objet à normaliser.
|
|
822
956
|
* @returns {Object} L’objet normalisé.
|
|
823
957
|
*/
|
|
824
|
-
_normalizeDatesRecursively(obj) {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
}
|
|
958
|
+
// _normalizeDatesRecursively(obj) {
|
|
959
|
+
// if (obj === null || typeof obj !== "object") return obj;
|
|
960
|
+
|
|
961
|
+
// // Si c'est un tableau, on traite chaque élément récursivement.
|
|
962
|
+
// if (Array.isArray(obj)) {
|
|
963
|
+
// return obj.map(item => this._normalizeDatesRecursively(item));
|
|
964
|
+
// }
|
|
965
|
+
|
|
966
|
+
// Object.keys(obj).forEach((key) => {
|
|
967
|
+
// if (this._dateFields.includes(key)) {
|
|
968
|
+
// if (obj[key] && typeof obj[key] === "object" && obj[key].sec && typeof obj[key].sec === "number") {
|
|
969
|
+
// obj[key] = { $date: obj[key].sec * 1000 };
|
|
970
|
+
// } else if (typeof obj[key] === "number") {
|
|
971
|
+
// obj[key] = { $date: obj[key] * 1000 };
|
|
972
|
+
// }
|
|
973
|
+
// }
|
|
974
|
+
// if (obj[key] && typeof obj[key] === "object") {
|
|
975
|
+
// this._normalizeDatesRecursively(obj[key]);
|
|
976
|
+
// }
|
|
977
|
+
// });
|
|
978
|
+
// return obj;
|
|
979
|
+
// }
|
|
846
980
|
|
|
847
981
|
/**
|
|
848
982
|
* Parcourt récursivement un objet pour normaliser les chemins d'images.
|
|
@@ -853,30 +987,30 @@ export default class ApiClient extends EventEmitter {
|
|
|
853
987
|
* @param {Object} obj - L’objet à normaliser.
|
|
854
988
|
* @returns {Object} L’objet normalisé.
|
|
855
989
|
*/
|
|
856
|
-
_normalizeImagesRecursively(obj) {
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
}
|
|
990
|
+
// _normalizeImagesRecursively(obj) {
|
|
991
|
+
// if (obj === null || typeof obj !== "object") return obj;
|
|
992
|
+
|
|
993
|
+
// // Si c'est un tableau, on traite chaque élément récursivement.
|
|
994
|
+
// if (Array.isArray(obj)) {
|
|
995
|
+
// return obj.map(item => this._normalizeImagesRecursively(item));
|
|
996
|
+
// }
|
|
997
|
+
|
|
998
|
+
// Object.keys(obj).forEach((key) => {
|
|
999
|
+
// if (this._imageFields.includes(key) && typeof obj[key] === "string" && obj[key].trim() !== "") {
|
|
1000
|
+
// obj[key] = this._ensureFullURL(obj[key]);
|
|
1001
|
+
// }
|
|
1002
|
+
|
|
1003
|
+
// // Cas particulier pour content.image
|
|
1004
|
+
// if (key === "content" && obj[key]?.image) {
|
|
1005
|
+
// obj[key].image = this._ensureFullURL(obj[key].image);
|
|
1006
|
+
// }
|
|
1007
|
+
|
|
1008
|
+
// if (obj[key] && typeof obj[key] === "object") {
|
|
1009
|
+
// this._normalizeImagesRecursively(obj[key]);
|
|
1010
|
+
// }
|
|
1011
|
+
// });
|
|
1012
|
+
// return obj;
|
|
1013
|
+
// }
|
|
880
1014
|
|
|
881
1015
|
/**
|
|
882
1016
|
* Parcourt récursivement un objet ou un tableau pour normaliser les identifiants (ID).
|
|
@@ -886,33 +1020,33 @@ export default class ApiClient extends EventEmitter {
|
|
|
886
1020
|
* @param {Object|Array} obj - L'objet ou le tableau à normaliser.
|
|
887
1021
|
* @returns {Object|Array} L'objet ou le tableau normalisé.
|
|
888
1022
|
*/
|
|
889
|
-
_normalizeIdRecursively(obj) {
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
}
|
|
1023
|
+
// _normalizeIdRecursively(obj) {
|
|
1024
|
+
// if (obj === null || typeof obj !== "object") return obj;
|
|
1025
|
+
|
|
1026
|
+
// // Si c'est un tableau, on traite chaque élément récursivement.
|
|
1027
|
+
// if (Array.isArray(obj)) {
|
|
1028
|
+
// return obj.map(item => this._normalizeIdRecursively(item));
|
|
1029
|
+
// }
|
|
1030
|
+
|
|
1031
|
+
// // Vérifier et normaliser l'ID dans l'objet
|
|
1032
|
+
// if (obj._id && obj._id.$id && /^[0-9a-fA-F]{24}$/.test(obj._id.$id)) {
|
|
1033
|
+
// obj.id = obj._id.$id;
|
|
1034
|
+
// obj._id = { $type: "oid", $value: obj._id.$id };
|
|
1035
|
+
// }
|
|
1036
|
+
// if (obj.id && obj.id.$id && /^[0-9a-fA-F]{24}$/.test(obj.id.$id)) {
|
|
1037
|
+
// obj._id = { $type: "oid", $value: obj.id.$id };
|
|
1038
|
+
// obj.id = obj.id.$id;
|
|
1039
|
+
// }
|
|
1040
|
+
|
|
1041
|
+
// // Appel récursif pour chaque propriété de l'objet
|
|
1042
|
+
// Object.keys(obj).forEach(key => {
|
|
1043
|
+
// if (obj[key] && typeof obj[key] === "object") {
|
|
1044
|
+
// obj[key] = this._normalizeIdRecursively(obj[key]);
|
|
1045
|
+
// }
|
|
1046
|
+
// });
|
|
1047
|
+
|
|
1048
|
+
// return obj;
|
|
1049
|
+
// }
|
|
916
1050
|
|
|
917
1051
|
/**
|
|
918
1052
|
* Normalise récursivement les valeurs booléennes.
|
|
@@ -921,22 +1055,22 @@ export default class ApiClient extends EventEmitter {
|
|
|
921
1055
|
* @param {any} data - L'objet, le tableau ou la valeur à normaliser.
|
|
922
1056
|
* @returns {any} La donnée normalisée.
|
|
923
1057
|
*/
|
|
924
|
-
_normalizeBooleansRecursively(data) {
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
}
|
|
1058
|
+
// _normalizeBooleansRecursively(data) {
|
|
1059
|
+
// if (typeof data === "string") {
|
|
1060
|
+
// if (data === "true") return true;
|
|
1061
|
+
// if (data === "false") return false;
|
|
1062
|
+
// return data;
|
|
1063
|
+
// }
|
|
1064
|
+
// if (Array.isArray(data)) {
|
|
1065
|
+
// return data.map(item => this._normalizeBooleansRecursively(item));
|
|
1066
|
+
// }
|
|
1067
|
+
// if (data !== null && typeof data === "object") {
|
|
1068
|
+
// Object.keys(data).forEach(key => {
|
|
1069
|
+
// data[key] = this._normalizeBooleansRecursively(data[key]);
|
|
1070
|
+
// });
|
|
1071
|
+
// }
|
|
1072
|
+
// return data;
|
|
1073
|
+
// }
|
|
940
1074
|
|
|
941
1075
|
/**
|
|
942
1076
|
* Transforme une chaîne "true" ou "false" en booléen.
|