@communecter/cocolight-api-client 1.0.8 → 1.0.10
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/22.cocolight-api-client.mjs.js +1 -0
- package/dist/320.cocolight-api-client.browser.js +1 -0
- package/dist/931.cocolight-api-client.browser.js +1 -0
- package/dist/931.cocolight-api-client.cjs +1 -0
- package/dist/cocolight-api-client.browser.js +3 -3
- package/dist/cocolight-api-client.cjs +1 -2
- package/dist/cocolight-api-client.mjs.js +1 -2
- package/package.json +6 -3
- package/src/Api.js +36 -19
- package/src/ApiClient.js +56 -11
- package/src/api/EndpointApi.js +1534 -0
- package/src/api/News.js +327 -0
- package/src/api/Organization.js +268 -84
- package/src/api/Project.js +287 -93
- package/src/api/User.js +397 -87
- package/src/api/UserApi.js +5 -1
- package/src/endpoints.module.js +2 -2
- package/src/mixin/DraftStateMixin.js +176 -0
- package/src/mixin/EntityMixin.js +109 -0
- package/src/mixin/MutualEntityMixin.js +48 -0
- package/src/mixin/NewsMixin.js +42 -0
- package/src/mixin/UserMixin.js +8 -0
- package/src/mixin/UtilMixin.js +294 -0
- package/src/utils/stream-utils.node.js +10 -0
- package/dist/cocolight-api-client.cjs.LICENSE.txt +0 -1
- package/dist/cocolight-api-client.mjs.js.LICENSE.txt +0 -1
- package/src/api/EntityMixin.js +0 -249
- package/src/api/NewsMixin.js +0 -168
- package/src/api/UserMixin.js +0 -59
- package/src/api/UtilMixin.js +0 -82
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@communecter/cocolight-api-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "Client Axios simplifié pour l'API cocolight",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"generate:testdata": "node ./scripts/generate-test-data.js",
|
|
33
33
|
"generate:reponses": "node ./scripts/generate-constant-response-200.js",
|
|
34
34
|
"generate:methodeapi": "node ./scripts/generate-methode-api.js",
|
|
35
|
-
"generate:ajv-standalone": "node ./scripts/generate-validate-function-ajv.js"
|
|
35
|
+
"generate:ajv-standalone": "node ./scripts/generate-validate-function-ajv.js",
|
|
36
|
+
"generate:entities": "node scripts/generate-entities.js"
|
|
36
37
|
},
|
|
37
38
|
"keywords": [
|
|
38
39
|
"communecter",
|
|
@@ -60,7 +61,8 @@
|
|
|
60
61
|
"jwt-decode": "^4.0.0",
|
|
61
62
|
"pino": "^9.6.0",
|
|
62
63
|
"pino-pretty": "^13.0.0",
|
|
63
|
-
"file-type": "^20.4.1"
|
|
64
|
+
"file-type": "^20.4.1",
|
|
65
|
+
"bson-objectid": "^2.0.4"
|
|
64
66
|
},
|
|
65
67
|
"devDependencies": {
|
|
66
68
|
"@babel/core": "^7.26.10",
|
|
@@ -72,6 +74,7 @@
|
|
|
72
74
|
"axios": "^1.4.0",
|
|
73
75
|
"axios-retry": "^4.5.0",
|
|
74
76
|
"file-type": "^20.4.1",
|
|
77
|
+
"bson-objectid": "^2.0.4",
|
|
75
78
|
"babel-jest": "^29.7.0",
|
|
76
79
|
"babel-loader": "^10.0.0",
|
|
77
80
|
"ejson": "^2.2.3",
|
package/src/Api.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// Api.js
|
|
2
|
+
import EndpointApi from "./api/EndpointApi.js";
|
|
3
|
+
import { News } from "./api/News.js";
|
|
2
4
|
import { Organization } from "./api/Organization.js";
|
|
3
5
|
import { Project } from "./api/Project.js";
|
|
4
6
|
import { User } from "./api/User.js";
|
|
@@ -75,12 +77,14 @@ export default class Api {
|
|
|
75
77
|
/**
|
|
76
78
|
* Retourne l'utilisateur connecté.
|
|
77
79
|
*
|
|
78
|
-
* @returns {User} L'utilisateur connecté.
|
|
80
|
+
* @returns {Promise<User>} L'utilisateur connecté.
|
|
81
|
+
* @throws {ApiAuthenticationError} Si l'utilisateur n'est pas authentifié.
|
|
79
82
|
*/
|
|
80
|
-
me() {
|
|
83
|
+
async me() {
|
|
81
84
|
if (!this._loggedUser) {
|
|
82
85
|
throw new ApiAuthenticationError("Accès refusé : utilisateur non authentifié.");
|
|
83
86
|
}
|
|
87
|
+
await this._loggedUser.get();
|
|
84
88
|
return this._loggedUser;
|
|
85
89
|
}
|
|
86
90
|
|
|
@@ -88,11 +92,18 @@ export default class Api {
|
|
|
88
92
|
* Crée une instance User pour un utilisateur donné (autre que le connecté).
|
|
89
93
|
*
|
|
90
94
|
* @param {Object} userData - Les données de l'utilisateur public.
|
|
91
|
-
* @returns {User}
|
|
95
|
+
* @returns {Promise<User>} Une promesse qui résout l'instance User.
|
|
96
|
+
* @throws {Error} Si une erreur se produit lors de la création de l'utilisateur.
|
|
92
97
|
*/
|
|
93
|
-
user(userData) {
|
|
98
|
+
async user(userData) {
|
|
94
99
|
try {
|
|
95
|
-
|
|
100
|
+
if (!userData.id && !userData.slug) {
|
|
101
|
+
return new User(this._client, userData, { EndpointApi, Organization, Project, News });
|
|
102
|
+
} else {
|
|
103
|
+
const user = new User(this._client, userData, { EndpointApi, Organization, Project, News });
|
|
104
|
+
await user.get();
|
|
105
|
+
return user;
|
|
106
|
+
}
|
|
96
107
|
} catch (error) {
|
|
97
108
|
console.error("[Api.user] Erreur lors de la création d'un objet utilisateur public :", error.message);
|
|
98
109
|
throw error;
|
|
@@ -104,18 +115,17 @@ export default class Api {
|
|
|
104
115
|
* Creates an Organization object and optionally retrieves its profile.
|
|
105
116
|
*
|
|
106
117
|
* @param {Object} organizationData - The data required to initialize the Organization object.
|
|
107
|
-
* @param {Object} [options={ getProfile: true }] - Additional options for the organization creation.
|
|
108
|
-
* @param {boolean} [options.getProfile=true] - Whether to fetch the organization's profile after creation.
|
|
109
118
|
* @returns {Promise<Organization>} A promise that resolves to the created Organization object.
|
|
110
119
|
* @throws {Error} Throws an error if the organization creation or profile retrieval fails.
|
|
111
120
|
*/
|
|
112
|
-
async organization(organizationData
|
|
121
|
+
async organization(organizationData) {
|
|
113
122
|
try {
|
|
114
|
-
const
|
|
115
|
-
if (
|
|
116
|
-
|
|
123
|
+
const organization = new Organization(this._client, organizationData, { EndpointApi, User, Project, News });
|
|
124
|
+
if (!organizationData.id && !organizationData.slug) {
|
|
125
|
+
throw new Error("Vous devez fournir un id ou un slug pour créer une instance Organization.");
|
|
117
126
|
}
|
|
118
|
-
|
|
127
|
+
await organization.get();
|
|
128
|
+
return organization;
|
|
119
129
|
} catch (error) {
|
|
120
130
|
console.error("[Api.organization] Erreur lors de la création d'un objet organisation :", error.message);
|
|
121
131
|
throw error;
|
|
@@ -126,17 +136,16 @@ export default class Api {
|
|
|
126
136
|
* Creates a new Project instance and optionally retrieves its profile.
|
|
127
137
|
*
|
|
128
138
|
* @param {Object} projectData - The data used to initialize the Project instance.
|
|
129
|
-
* @param {Object} [options={ getProfile: true }] - Additional options for project creation.
|
|
130
|
-
* @param {boolean} [options.getProfile=true] - Whether to retrieve the project's profile after creation.
|
|
131
139
|
* @returns {Promise<Project>} A promise that resolves to the created Project instance.
|
|
132
140
|
* @throws {Error} If an error occurs during project creation or profile retrieval.
|
|
133
141
|
*/
|
|
134
|
-
async project(projectData
|
|
142
|
+
async project(projectData) {
|
|
135
143
|
try {
|
|
136
|
-
const project = new Project(this._client, projectData);
|
|
137
|
-
if (
|
|
138
|
-
|
|
144
|
+
const project = new Project(this._client, projectData, { User, News, EndpointApi });
|
|
145
|
+
if (!projectData.id && !projectData.slug) {
|
|
146
|
+
throw new Error("Vous devez fournir un id ou un slug pour créer une instance Project.");
|
|
139
147
|
}
|
|
148
|
+
await project.get();
|
|
140
149
|
return project;
|
|
141
150
|
} catch (error) {
|
|
142
151
|
console.error("[Api.project] Erreur lors de la création d'un objet projet :", error.message);
|
|
@@ -149,9 +158,17 @@ export default class Api {
|
|
|
149
158
|
*
|
|
150
159
|
* @returns {ApiClient}
|
|
151
160
|
*/
|
|
152
|
-
|
|
153
161
|
get client() {
|
|
154
162
|
return this._client;
|
|
155
163
|
}
|
|
156
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Retourne l'instance d'EndpointApi.
|
|
167
|
+
*
|
|
168
|
+
* @returns {EndpointApi}
|
|
169
|
+
*/
|
|
170
|
+
get endpointApi() {
|
|
171
|
+
return new EndpointApi(this._client);
|
|
172
|
+
}
|
|
173
|
+
|
|
157
174
|
}
|
package/src/ApiClient.js
CHANGED
|
@@ -51,6 +51,8 @@ export default class ApiClient extends EventEmitter {
|
|
|
51
51
|
throw new ApiClientError("Le paramètre \"baseURL\" est obligatoire.", 500);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
this.__entityTag = "ApiClient";
|
|
55
|
+
|
|
54
56
|
this._baseURL = baseURL;
|
|
55
57
|
this._refreshToken = refreshToken;
|
|
56
58
|
this._refreshUrl = refreshUrl;
|
|
@@ -78,8 +80,14 @@ export default class ApiClient extends EventEmitter {
|
|
|
78
80
|
this._ajv = new Ajv({ strict: false, useDefaults: true, allErrors: true, verbose: true });
|
|
79
81
|
addFormats(this._ajv);
|
|
80
82
|
|
|
83
|
+
this._ajv.addKeyword({
|
|
84
|
+
keyword: "startBeforeEnd",
|
|
85
|
+
type: "object",
|
|
86
|
+
errors: true,
|
|
87
|
+
validate: this._startBeforeEndValidate
|
|
88
|
+
});
|
|
89
|
+
|
|
81
90
|
// Pino logger
|
|
82
|
-
// (Ici en mode pretty-print sur la console, tu peux configurer comme tu veux)
|
|
83
91
|
this._logger = pino({
|
|
84
92
|
transport: {
|
|
85
93
|
target: "pino-pretty",
|
|
@@ -582,9 +590,9 @@ export default class ApiClient extends EventEmitter {
|
|
|
582
590
|
const validateRequest = this._ajv.compile(schemaToCompile);
|
|
583
591
|
const valid = validateRequest(cleanedData);
|
|
584
592
|
if (!valid) {
|
|
585
|
-
const errorMessages = this._ajvErrorHuman(validateRequest.errors);
|
|
593
|
+
const errorMessages = validateRequest.errors ? this._ajvErrorHuman(validateRequest.errors) : [];
|
|
586
594
|
this.emit("validationError", { stage: "request", errors: validateRequest.errors });
|
|
587
|
-
throw new ApiValidationError("Request validation failed.", 400, errorMessages, validateRequest.errors);
|
|
595
|
+
throw new ApiValidationError("Request validation failed.", 400, errorMessages , validateRequest.errors);
|
|
588
596
|
}
|
|
589
597
|
|
|
590
598
|
data = this._resolveSpecialValuesInPlace(cleanedData, resolvedParams);
|
|
@@ -679,11 +687,16 @@ export default class ApiClient extends EventEmitter {
|
|
|
679
687
|
} catch (error) {
|
|
680
688
|
this._updateCircuitBreakerError();
|
|
681
689
|
this._logger.error(`[ApiClient] Erreur lors de l'appel de ${constant}: ${error.message}`);
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
690
|
+
if(error instanceof ApiValidationError) {
|
|
691
|
+
throw error;
|
|
692
|
+
} else {
|
|
693
|
+
throw new ApiClientError(
|
|
694
|
+
`Erreur lors de l'appel de l'API : ${error.message}`,
|
|
695
|
+
error.response ? error.response.status : 500,
|
|
696
|
+
error.response ? error.response.data : null
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
|
|
687
700
|
}
|
|
688
701
|
}
|
|
689
702
|
|
|
@@ -694,9 +707,14 @@ export default class ApiClient extends EventEmitter {
|
|
|
694
707
|
* @returns {Array<string>} An array of human-readable error messages extracted from the AJV errors.
|
|
695
708
|
*/
|
|
696
709
|
_ajvErrorHuman(errors){
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
710
|
+
try {
|
|
711
|
+
const errorsMessages = new AggregateAjvError(errors);
|
|
712
|
+
const messages = errorsMessages.errors.map(({ message }) => message);
|
|
713
|
+
return messages;
|
|
714
|
+
} catch (e) {
|
|
715
|
+
this._logger.error("[ApiClient] _ajvErrorHuman", e);
|
|
716
|
+
return errors.map(({ message }) => message);
|
|
717
|
+
}
|
|
700
718
|
}
|
|
701
719
|
|
|
702
720
|
/**
|
|
@@ -1343,5 +1361,32 @@ export default class ApiClient extends EventEmitter {
|
|
|
1343
1361
|
return data;
|
|
1344
1362
|
}
|
|
1345
1363
|
|
|
1364
|
+
_startBeforeEndValidate = (schema, data) => {
|
|
1365
|
+
if (!data.startDate || !data.endDate) return true;
|
|
1366
|
+
|
|
1367
|
+
const isValid = new Date(data.startDate) < new Date(data.endDate);
|
|
1368
|
+
if (!isValid) {
|
|
1369
|
+
this._startBeforeEndValidate.errors = [
|
|
1370
|
+
{
|
|
1371
|
+
instancePath: "", // ou "." si tu veux le chemin actuel
|
|
1372
|
+
schemaPath: "#/startBeforeEnd",
|
|
1373
|
+
keyword: "startBeforeEnd",
|
|
1374
|
+
params: {},
|
|
1375
|
+
message: "startDate must be before endDate"
|
|
1376
|
+
}
|
|
1377
|
+
];
|
|
1378
|
+
}
|
|
1379
|
+
return isValid;
|
|
1380
|
+
};
|
|
1381
|
+
|
|
1382
|
+
|
|
1383
|
+
getRequestSchema(constant) {
|
|
1384
|
+
const endpoint = this._endpoints.find(e => e.constant === constant);
|
|
1385
|
+
return endpoint?.request || null;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
getPathSchema(constant) {
|
|
1389
|
+
return this._endpoints.find(e => e.constant === constant)?.pathParams || null;
|
|
1390
|
+
}
|
|
1346
1391
|
|
|
1347
1392
|
}
|