@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@communecter/cocolight-api-client",
3
- "version": "1.0.2",
3
+ "version": "1.0.5",
4
4
  "description": "Client Axios simplifié pour l'API cocolight",
5
5
  "repository": {
6
6
  "type": "git",
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
- // vous pouvez ajouter d'autres alias ici
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
- if (typeof obj === "string" && obj.startsWith("@")) {
292
- const varName = obj.slice(1);
293
- return typeof aliasMap[varName] === "function" ? aliasMap[varName]() : obj;
294
- } else if (Array.isArray(obj)) {
295
- for (let i = 0; i < obj.length; i++) {
296
- obj[i] = this._resolveSpecialValuesInPlace(obj[i]);
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
- for (const key in obj) {
300
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
301
- obj[key] = this._resolveSpecialValuesInPlace(obj[key]);
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(pathSchema);
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
- const resolvedParams = this._resolveSpecialValuesInPlace(pathParams);
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(requestSchema);
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
- if (obj === null || typeof obj !== "object") return obj;
826
-
827
- // Si c'est un tableau, on traite chaque élément récursivement.
828
- if (Array.isArray(obj)) {
829
- return obj.map(item => this._normalizeDatesRecursively(item));
830
- }
831
-
832
- Object.keys(obj).forEach((key) => {
833
- if (this._dateFields.includes(key)) {
834
- if (obj[key] && typeof obj[key] === "object" && obj[key].sec && typeof obj[key].sec === "number") {
835
- obj[key] = { $date: obj[key].sec * 1000 };
836
- } else if (typeof obj[key] === "number") {
837
- obj[key] = { $date: obj[key] * 1000 };
838
- }
839
- }
840
- if (obj[key] && typeof obj[key] === "object") {
841
- this._normalizeDatesRecursively(obj[key]);
842
- }
843
- });
844
- return obj;
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
- if (obj === null || typeof obj !== "object") return obj;
858
-
859
- // Si c'est un tableau, on traite chaque élément récursivement.
860
- if (Array.isArray(obj)) {
861
- return obj.map(item => this._normalizeImagesRecursively(item));
862
- }
863
-
864
- Object.keys(obj).forEach((key) => {
865
- if (this._imageFields.includes(key) && typeof obj[key] === "string" && obj[key].trim() !== "") {
866
- obj[key] = this._ensureFullURL(obj[key]);
867
- }
868
-
869
- // Cas particulier pour content.image
870
- if (key === "content" && obj[key]?.image) {
871
- obj[key].image = this._ensureFullURL(obj[key].image);
872
- }
873
-
874
- if (obj[key] && typeof obj[key] === "object") {
875
- this._normalizeImagesRecursively(obj[key]);
876
- }
877
- });
878
- return obj;
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
- if (obj === null || typeof obj !== "object") return obj;
891
-
892
- // Si c'est un tableau, on traite chaque élément récursivement.
893
- if (Array.isArray(obj)) {
894
- return obj.map(item => this._normalizeIdRecursively(item));
895
- }
896
-
897
- // Vérifier et normaliser l'ID dans l'objet
898
- if (obj._id && obj._id.$id && /^[0-9a-fA-F]{24}$/.test(obj._id.$id)) {
899
- obj.id = obj._id.$id;
900
- obj._id = { $type: "oid", $value: obj._id.$id };
901
- }
902
- if (obj.id && obj.id.$id && /^[0-9a-fA-F]{24}$/.test(obj.id.$id)) {
903
- obj._id = { $type: "oid", $value: obj.id.$id };
904
- obj.id = obj.id.$id;
905
- }
906
-
907
- // Appel récursif pour chaque propriété de l'objet
908
- Object.keys(obj).forEach(key => {
909
- if (obj[key] && typeof obj[key] === "object") {
910
- obj[key] = this._normalizeIdRecursively(obj[key]);
911
- }
912
- });
913
-
914
- return obj;
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
- if (typeof data === "string") {
926
- if (data === "true") return true;
927
- if (data === "false") return false;
928
- return data;
929
- }
930
- if (Array.isArray(data)) {
931
- return data.map(item => this._normalizeBooleansRecursively(item));
932
- }
933
- if (data !== null && typeof data === "object") {
934
- Object.keys(data).forEach(key => {
935
- data[key] = this._normalizeBooleansRecursively(data[key]);
936
- });
937
- }
938
- return data;
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.