@communecter/cocolight-api-client 1.0.4 → 1.0.6

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.4",
3
+ "version": "1.0.6",
4
4
  "description": "Client Axios simplifié pour l'API cocolight",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,9 +22,10 @@
22
22
  "build:browser": "webpack --config webpack.config.standalone.js",
23
23
  "build:node": "webpack --config webpack.config.node.js",
24
24
  "build:esm": "webpack --config webpack.config.esm.mjs",
25
- "build": "npm run generate:module && npm run generate:doc && npm run lint:fix && npm run build:browser && npm run build:node && npm run build:esm",
25
+ "build": "npm run generate:module:publish && npm run generate:doc && npm run lint:fix && npm run build:browser && npm run build:node && npm run build:esm",
26
26
  "build:publish": "npm run build && npm publish --access public",
27
27
  "generate:module": "node ./scripts/transform-json-module.js",
28
+ "generate:module:publish": "node ./scripts/transform-json-module.publish.js",
28
29
  "generate:doc": "node ./scripts/generate-doc.js",
29
30
  "generate:test": "node ./scripts/generate-tests.js",
30
31
  "generate:testdata": "node ./scripts/generate-test-data.js"
@@ -39,10 +40,10 @@
39
40
  "author": "Thomas",
40
41
  "license": "MIT",
41
42
  "files": [
42
- "dist/",
43
- "src/",
44
- "package.json",
45
- "README.md"
43
+ "dist/",
44
+ "src/",
45
+ "package.json",
46
+ "README.md"
46
47
  ],
47
48
  "peerDependencies": {
48
49
  "ajv": "^8.17.1",
@@ -52,27 +53,29 @@
52
53
  "ejson": "^2.2.3",
53
54
  "events": "^3.3.0",
54
55
  "pino": "^9.6.0",
55
- "pino-pretty": "^13.0.0"
56
+ "pino-pretty": "^13.0.0",
57
+ "jwt-decode": "^4.0.0"
56
58
  },
57
59
  "devDependencies": {
60
+ "@babel/core": "^7.26.10",
61
+ "@babel/preset-env": "^7.26.9",
62
+ "@eslint/js": "^9.23.0",
58
63
  "ajv": "^8.17.1",
59
64
  "ajv-formats": "^3.0.1",
60
65
  "axios": "^1.4.0",
61
66
  "axios-retry": "^4.5.0",
62
- "ejson": "^2.2.3",
63
- "events": "^3.3.0",
64
- "pino": "^9.6.0",
65
- "pino-pretty": "^13.0.0",
66
- "@babel/core": "^7.26.10",
67
- "@babel/preset-env": "^7.26.9",
68
- "@eslint/js": "^9.23.0",
67
+ "jwt-decode": "^4.0.0",
69
68
  "babel-jest": "^29.7.0",
70
69
  "babel-loader": "^10.0.0",
70
+ "ejson": "^2.2.3",
71
71
  "eslint": "^9.23.0",
72
72
  "eslint-plugin-import": "^2.31.0",
73
+ "events": "^3.3.0",
73
74
  "globals": "^16.0.0",
74
75
  "jest": "^29.7.0",
75
76
  "nodemon": "^3.1.9",
77
+ "pino": "^9.6.0",
78
+ "pino-pretty": "^13.0.0",
76
79
  "webpack": "^5.98.0",
77
80
  "webpack-cli": "^6.0.1"
78
81
  }
package/src/ApiClient.js CHANGED
@@ -5,6 +5,7 @@ import addFormats from "ajv-formats";
5
5
  import axios from "axios";
6
6
  import axiosRetry from "axios-retry";
7
7
  import EJSON from "ejson";
8
+ import { jwtDecode } from "jwt-decode";
8
9
  import pino from "pino";
9
10
 
10
11
  import MongoID from "./EJSONType.js";
@@ -146,6 +147,12 @@ export default class ApiClient extends EventEmitter {
146
147
  setToken(token) {
147
148
  this._accessToken = token;
148
149
  this._client.defaults.headers.common["Authorization"] = "Bearer " + token;
150
+ // Extrait l'id depuis le token et le stocke si disponible
151
+ const userId = this._getIdFromToken(token);
152
+ if (userId) {
153
+ this._setUserId(userId);
154
+ this._logger.debug(`[ApiClient] userId extrait et défini : ${userId}`);
155
+ }
149
156
  this._logger.debug(`[ApiClient] setToken: ${token}`);
150
157
  }
151
158
 
@@ -165,6 +172,12 @@ export default class ApiClient extends EventEmitter {
165
172
  */
166
173
  setRefreshToken(rt) {
167
174
  this._refreshToken = rt;
175
+ // Vous pouvez faire de même ici si besoin
176
+ const userId = this._getIdFromToken(rt);
177
+ if (userId) {
178
+ this._setUserId(userId);
179
+ this._logger.debug(`[ApiClient] userId extrait depuis refreshToken : ${userId}`);
180
+ }
168
181
  this._logger.debug(`[ApiClient] setRefreshToken: ${rt}`);
169
182
  }
170
183
 
@@ -177,6 +190,26 @@ export default class ApiClient extends EventEmitter {
177
190
  return this._refreshToken;
178
191
  }
179
192
 
193
+ /**
194
+ * Extrait l'identifiant depuis un JWT.
195
+ *
196
+ * @param {string} token - Le token JWT (accessToken ou refreshToken).
197
+ * @returns {string|null} L'identifiant extrait ou null si non trouvé.
198
+ */
199
+ _getIdFromToken(token) {
200
+ if (!token) return null;
201
+ try {
202
+ // Décodage du token grâce à jwt-decode
203
+ const payload = jwtDecode(token);
204
+ // L'identifiant peut être dans "id" ou "userId"
205
+ this._logger.log("[ApiClient] Payload décodé :", payload);
206
+ return payload.id || payload.userId || null;
207
+ } catch (err) {
208
+ this._logger.error("[ApiClient] Erreur lors du décodage du token :", err.message);
209
+ return null;
210
+ }
211
+ }
212
+
180
213
  /**
181
214
  * Méthode simplifiée de refresh (en JSON).
182
215
  * Emet un event refreshSuccess si ça marche
@@ -274,25 +307,69 @@ export default class ApiClient extends EventEmitter {
274
307
  return obj;
275
308
  }
276
309
 
277
- _resolveSpecialValuesInPlace(obj) {
310
+ _resolveSpecialValuesInPlace(obj, pathParams = {}) {
278
311
  const aliasMap = {
279
312
  userId: () => this.userId,
280
313
  accessToken: () => this._accessToken,
281
314
  refreshToken: () => this._refreshToken,
282
- baseURL: () => this._baseURL
315
+ baseURL: () => this._baseURL,
316
+ pathParams: (subPath) => {
317
+ // Si la valeur existe dans pathParams, on la retourne
318
+ const value = this._getValueByPath(pathParams, subPath);
319
+ return value !== undefined && value !== null ? value : undefined;
320
+ }
283
321
  };
284
322
 
323
+ // Expression régulière qui capture les alias sous forme délimitée @{...} ou simple @...
324
+ const regex = /@(?:\{([^}]+)\}|([\w.]+))/g;
325
+
285
326
  const resolveString = (str) => {
286
327
  if (typeof str !== "string") return str;
287
- return str.replace(/@(\w+)/g, (_, key) => {
288
- const fn = aliasMap[key];
289
- const value = typeof fn === "function" ? fn() : undefined;
290
- if (value === undefined || value === null) {
291
- return `@${key}`; // on laisse tel quel si la valeur n'est pas définie
328
+ return str.replace(regex, (_, delimitedAlias, plainAlias) => {
329
+ // Si alias délimité, on traite toute la chaîne à l'intérieur des accolades.
330
+ if (delimitedAlias) {
331
+ // On s'attend à une forme comme "pathParams.id.autre"
332
+ if (delimitedAlias.startsWith("pathParams.")) {
333
+ const subPath = delimitedAlias.substring("pathParams.".length);
334
+ const value = aliasMap.pathParams(subPath);
335
+ return value !== undefined && value !== null ? value : `@{${delimitedAlias}}`;
336
+ } else {
337
+ // Pour d'autres alias délimités, on cherche directement dans aliasMap
338
+ const fn = aliasMap[delimitedAlias];
339
+ if (typeof fn === "function") {
340
+ const value = fn();
341
+ return value !== undefined && value !== null ? value : `@{${delimitedAlias}}`;
342
+ }
343
+ return `@{${delimitedAlias}}`;
344
+ }
345
+ } else if (plainAlias) {
346
+ // Traitement de l'alias simple, potentiellement avec des segments
347
+ // Vérifier s'il commence par "pathParams."
348
+ if (plainAlias.startsWith("pathParams.")) {
349
+ // Extrait la partie après "pathParams." et sépare le premier segment et le reste.
350
+ const match = plainAlias.match(/^pathParams\.([^.]+)(.*)$/);
351
+ if (match) {
352
+ const subKey = match[1]; // ex: "id"
353
+ const remainder = match[2]; // ex: "" ou ".autrechose"
354
+ // Si le reste est vide, ou s'il ne doit pas être remplacé (on remplace toujours le premier segment uniquement)
355
+ const value = aliasMap.pathParams(subKey);
356
+ return value !== undefined && value !== null ? value + remainder : `@${plainAlias}`;
357
+ }
358
+ return `@${plainAlias}`;
359
+ } else {
360
+ // Pour tout autre alias simple sans point ou autre
361
+ const fn = aliasMap[plainAlias];
362
+ if (typeof fn === "function") {
363
+ const value = fn();
364
+ return value !== undefined && value !== null ? value : `@${plainAlias}`;
365
+ }
366
+ return `@${plainAlias}`;
367
+ }
292
368
  }
293
- return value;
369
+ return str;
294
370
  });
295
371
  };
372
+
296
373
 
297
374
  // Vérifie si l'objet est un binaire (par exemple un flux ou un Buffer)
298
375
  const isBinary = (input) => {
@@ -432,6 +509,7 @@ export default class ApiClient extends EventEmitter {
432
509
 
433
510
  // === 1. PathParams ===
434
511
  let resolvedPath = path;
512
+ let resolvedParams = {};
435
513
  if (pathSchema) {
436
514
 
437
515
  // Si auth est "none" et que userId n'est pas défini, on nettoie le schéma
@@ -449,7 +527,7 @@ export default class ApiClient extends EventEmitter {
449
527
  throw new ApiClientError("Path parameter validation failed.", 400, validatePathParams.errors);
450
528
  }
451
529
 
452
- const resolvedParams = this._resolveSpecialValuesInPlace(pathParams);
530
+ resolvedParams = this._resolveSpecialValuesInPlace(pathParams);
453
531
 
454
532
  resolvedPath = resolvedPath.replace(/\{(\w+)\}/g, (_, key) => {
455
533
  const val = resolvedParams[key];
@@ -477,7 +555,7 @@ export default class ApiClient extends EventEmitter {
477
555
  throw new ApiClientError("Request validation failed.", 400, validateRequest.errors);
478
556
  }
479
557
 
480
- data = this._resolveSpecialValuesInPlace(cleanedData);
558
+ data = this._resolveSpecialValuesInPlace(cleanedData, resolvedParams);
481
559
  }
482
560
 
483
561
  // === 3. Payload ===
@@ -533,9 +611,9 @@ export default class ApiClient extends EventEmitter {
533
611
  this.setRefreshToken(value);
534
612
  break;
535
613
 
536
- case "setUserId":
537
- this._setUserId(value);
538
- break;
614
+ // case "setUserId":
615
+ // this._setUserId(value);
616
+ // break;
539
617
 
540
618
  case "resetSession":
541
619
  this.resetSession();
@@ -910,28 +988,28 @@ export default class ApiClient extends EventEmitter {
910
988
  * @param {Object} obj - L’objet à normaliser.
911
989
  * @returns {Object} L’objet normalisé.
912
990
  */
913
- _normalizeDatesRecursively(obj) {
914
- if (obj === null || typeof obj !== "object") return obj;
915
-
916
- // Si c'est un tableau, on traite chaque élément récursivement.
917
- if (Array.isArray(obj)) {
918
- return obj.map(item => this._normalizeDatesRecursively(item));
919
- }
920
-
921
- Object.keys(obj).forEach((key) => {
922
- if (this._dateFields.includes(key)) {
923
- if (obj[key] && typeof obj[key] === "object" && obj[key].sec && typeof obj[key].sec === "number") {
924
- obj[key] = { $date: obj[key].sec * 1000 };
925
- } else if (typeof obj[key] === "number") {
926
- obj[key] = { $date: obj[key] * 1000 };
927
- }
928
- }
929
- if (obj[key] && typeof obj[key] === "object") {
930
- this._normalizeDatesRecursively(obj[key]);
931
- }
932
- });
933
- return obj;
934
- }
991
+ // _normalizeDatesRecursively(obj) {
992
+ // if (obj === null || typeof obj !== "object") return obj;
993
+
994
+ // // Si c'est un tableau, on traite chaque élément récursivement.
995
+ // if (Array.isArray(obj)) {
996
+ // return obj.map(item => this._normalizeDatesRecursively(item));
997
+ // }
998
+
999
+ // Object.keys(obj).forEach((key) => {
1000
+ // if (this._dateFields.includes(key)) {
1001
+ // if (obj[key] && typeof obj[key] === "object" && obj[key].sec && typeof obj[key].sec === "number") {
1002
+ // obj[key] = { $date: obj[key].sec * 1000 };
1003
+ // } else if (typeof obj[key] === "number") {
1004
+ // obj[key] = { $date: obj[key] * 1000 };
1005
+ // }
1006
+ // }
1007
+ // if (obj[key] && typeof obj[key] === "object") {
1008
+ // this._normalizeDatesRecursively(obj[key]);
1009
+ // }
1010
+ // });
1011
+ // return obj;
1012
+ // }
935
1013
 
936
1014
  /**
937
1015
  * Parcourt récursivement un objet pour normaliser les chemins d'images.
@@ -942,30 +1020,30 @@ export default class ApiClient extends EventEmitter {
942
1020
  * @param {Object} obj - L’objet à normaliser.
943
1021
  * @returns {Object} L’objet normalisé.
944
1022
  */
945
- _normalizeImagesRecursively(obj) {
946
- if (obj === null || typeof obj !== "object") return obj;
947
-
948
- // Si c'est un tableau, on traite chaque élément récursivement.
949
- if (Array.isArray(obj)) {
950
- return obj.map(item => this._normalizeImagesRecursively(item));
951
- }
952
-
953
- Object.keys(obj).forEach((key) => {
954
- if (this._imageFields.includes(key) && typeof obj[key] === "string" && obj[key].trim() !== "") {
955
- obj[key] = this._ensureFullURL(obj[key]);
956
- }
957
-
958
- // Cas particulier pour content.image
959
- if (key === "content" && obj[key]?.image) {
960
- obj[key].image = this._ensureFullURL(obj[key].image);
961
- }
962
-
963
- if (obj[key] && typeof obj[key] === "object") {
964
- this._normalizeImagesRecursively(obj[key]);
965
- }
966
- });
967
- return obj;
968
- }
1023
+ // _normalizeImagesRecursively(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._normalizeImagesRecursively(item));
1029
+ // }
1030
+
1031
+ // Object.keys(obj).forEach((key) => {
1032
+ // if (this._imageFields.includes(key) && typeof obj[key] === "string" && obj[key].trim() !== "") {
1033
+ // obj[key] = this._ensureFullURL(obj[key]);
1034
+ // }
1035
+
1036
+ // // Cas particulier pour content.image
1037
+ // if (key === "content" && obj[key]?.image) {
1038
+ // obj[key].image = this._ensureFullURL(obj[key].image);
1039
+ // }
1040
+
1041
+ // if (obj[key] && typeof obj[key] === "object") {
1042
+ // this._normalizeImagesRecursively(obj[key]);
1043
+ // }
1044
+ // });
1045
+ // return obj;
1046
+ // }
969
1047
 
970
1048
  /**
971
1049
  * Parcourt récursivement un objet ou un tableau pour normaliser les identifiants (ID).
@@ -975,33 +1053,33 @@ export default class ApiClient extends EventEmitter {
975
1053
  * @param {Object|Array} obj - L'objet ou le tableau à normaliser.
976
1054
  * @returns {Object|Array} L'objet ou le tableau normalisé.
977
1055
  */
978
- _normalizeIdRecursively(obj) {
979
- if (obj === null || typeof obj !== "object") return obj;
980
-
981
- // Si c'est un tableau, on traite chaque élément récursivement.
982
- if (Array.isArray(obj)) {
983
- return obj.map(item => this._normalizeIdRecursively(item));
984
- }
985
-
986
- // Vérifier et normaliser l'ID dans l'objet
987
- if (obj._id && obj._id.$id && /^[0-9a-fA-F]{24}$/.test(obj._id.$id)) {
988
- obj.id = obj._id.$id;
989
- obj._id = { $type: "oid", $value: obj._id.$id };
990
- }
991
- if (obj.id && obj.id.$id && /^[0-9a-fA-F]{24}$/.test(obj.id.$id)) {
992
- obj._id = { $type: "oid", $value: obj.id.$id };
993
- obj.id = obj.id.$id;
994
- }
995
-
996
- // Appel récursif pour chaque propriété de l'objet
997
- Object.keys(obj).forEach(key => {
998
- if (obj[key] && typeof obj[key] === "object") {
999
- obj[key] = this._normalizeIdRecursively(obj[key]);
1000
- }
1001
- });
1002
-
1003
- return obj;
1004
- }
1056
+ // _normalizeIdRecursively(obj) {
1057
+ // if (obj === null || typeof obj !== "object") return obj;
1058
+
1059
+ // // Si c'est un tableau, on traite chaque élément récursivement.
1060
+ // if (Array.isArray(obj)) {
1061
+ // return obj.map(item => this._normalizeIdRecursively(item));
1062
+ // }
1063
+
1064
+ // // Vérifier et normaliser l'ID dans l'objet
1065
+ // if (obj._id && obj._id.$id && /^[0-9a-fA-F]{24}$/.test(obj._id.$id)) {
1066
+ // obj.id = obj._id.$id;
1067
+ // obj._id = { $type: "oid", $value: obj._id.$id };
1068
+ // }
1069
+ // if (obj.id && obj.id.$id && /^[0-9a-fA-F]{24}$/.test(obj.id.$id)) {
1070
+ // obj._id = { $type: "oid", $value: obj.id.$id };
1071
+ // obj.id = obj.id.$id;
1072
+ // }
1073
+
1074
+ // // Appel récursif pour chaque propriété de l'objet
1075
+ // Object.keys(obj).forEach(key => {
1076
+ // if (obj[key] && typeof obj[key] === "object") {
1077
+ // obj[key] = this._normalizeIdRecursively(obj[key]);
1078
+ // }
1079
+ // });
1080
+
1081
+ // return obj;
1082
+ // }
1005
1083
 
1006
1084
  /**
1007
1085
  * Normalise récursivement les valeurs booléennes.
@@ -1010,22 +1088,22 @@ export default class ApiClient extends EventEmitter {
1010
1088
  * @param {any} data - L'objet, le tableau ou la valeur à normaliser.
1011
1089
  * @returns {any} La donnée normalisée.
1012
1090
  */
1013
- _normalizeBooleansRecursively(data) {
1014
- if (typeof data === "string") {
1015
- if (data === "true") return true;
1016
- if (data === "false") return false;
1017
- return data;
1018
- }
1019
- if (Array.isArray(data)) {
1020
- return data.map(item => this._normalizeBooleansRecursively(item));
1021
- }
1022
- if (data !== null && typeof data === "object") {
1023
- Object.keys(data).forEach(key => {
1024
- data[key] = this._normalizeBooleansRecursively(data[key]);
1025
- });
1026
- }
1027
- return data;
1028
- }
1091
+ // _normalizeBooleansRecursively(data) {
1092
+ // if (typeof data === "string") {
1093
+ // if (data === "true") return true;
1094
+ // if (data === "false") return false;
1095
+ // return data;
1096
+ // }
1097
+ // if (Array.isArray(data)) {
1098
+ // return data.map(item => this._normalizeBooleansRecursively(item));
1099
+ // }
1100
+ // if (data !== null && typeof data === "object") {
1101
+ // Object.keys(data).forEach(key => {
1102
+ // data[key] = this._normalizeBooleansRecursively(data[key]);
1103
+ // });
1104
+ // }
1105
+ // return data;
1106
+ // }
1029
1107
 
1030
1108
  /**
1031
1109
  * Transforme une chaîne "true" ou "false" en booléen.