@communecter/cocolight-api-client 1.0.10 → 1.0.12
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/README.md +285 -3
- package/dist/405.cocolight-api-client.browser.js +1 -0
- package/dist/405.cocolight-api-client.cjs +1 -0
- package/dist/790.cocolight-api-client.mjs.js +1 -0
- package/dist/cocolight-api-client.browser.js +2 -2
- package/dist/cocolight-api-client.cjs +1 -1
- package/dist/cocolight-api-client.mjs.js +1 -1
- package/package.json +8 -4
- package/src/Api.js +28 -3
- package/src/ApiClient.js +85 -30
- package/src/api/UserApi.js +21 -1
- package/src/index.js +3 -1
- package/src/utils/FileStorageStrategy.node.js +60 -0
- package/src/utils/TokenStorage.js +93 -0
- package/src/utils/createDefaultTokenStorageStrategy.js +45 -0
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.12",
|
|
4
4
|
"description": "Client Axios simplifié pour l'API cocolight",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
"main": "./dist/cocolight-api-client.cjs",
|
|
11
11
|
"browser": "./dist/cocolight-api-client.browser.js",
|
|
12
12
|
"exports": {
|
|
13
|
-
"
|
|
14
|
-
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/cocolight-api-client.mjs.js",
|
|
15
|
+
"require": "./dist/cocolight-api-client.cjs"
|
|
16
|
+
},
|
|
17
|
+
"./mjs": "./dist/cocolight-api-client.mjs.js"
|
|
15
18
|
},
|
|
16
19
|
"type": "module",
|
|
17
20
|
"scripts": {
|
|
@@ -33,7 +36,8 @@
|
|
|
33
36
|
"generate:reponses": "node ./scripts/generate-constant-response-200.js",
|
|
34
37
|
"generate:methodeapi": "node ./scripts/generate-methode-api.js",
|
|
35
38
|
"generate:ajv-standalone": "node ./scripts/generate-validate-function-ajv.js",
|
|
36
|
-
"generate:entities": "node scripts/generate-entities.js"
|
|
39
|
+
"generate:entities": "node scripts/generate-entities.js",
|
|
40
|
+
"generate:all-properties-schema": "node scripts/generate-all-properties-schema.js"
|
|
37
41
|
},
|
|
38
42
|
"keywords": [
|
|
39
43
|
"communecter",
|
package/src/Api.js
CHANGED
|
@@ -5,7 +5,7 @@ import { Organization } from "./api/Organization.js";
|
|
|
5
5
|
import { Project } from "./api/Project.js";
|
|
6
6
|
import { User } from "./api/User.js";
|
|
7
7
|
import { UserApi } from "./api/UserApi.js";
|
|
8
|
-
import { ApiAuthenticationError, ApiClientError } from "./error.js";
|
|
8
|
+
import { ApiAuthenticationError, ApiClientError, ApiError } from "./error.js";
|
|
9
9
|
|
|
10
10
|
export default class Api {
|
|
11
11
|
/**
|
|
@@ -51,8 +51,27 @@ export default class Api {
|
|
|
51
51
|
*/
|
|
52
52
|
static async userApiLogin(userApi, email, password) {
|
|
53
53
|
try {
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
|
|
55
|
+
if (!userApi) {
|
|
56
|
+
throw new ApiError("userApi is not defined");
|
|
57
|
+
}
|
|
58
|
+
if(!userApi.client) {
|
|
59
|
+
throw new ApiError("userApi.client is not defined");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if(userApi.client.isConnected) {
|
|
63
|
+
// Si l'utilisateur est déjà connecté, on le récupère
|
|
64
|
+
// et on ne fait pas de login
|
|
65
|
+
const loggedUser = await userApi.meIsconnected();
|
|
66
|
+
return new Api(loggedUser, userApi.client);
|
|
67
|
+
} else {
|
|
68
|
+
if (!email || !password) {
|
|
69
|
+
throw new ApiError("email and password are required");
|
|
70
|
+
}
|
|
71
|
+
const loggedUser = await userApi.login(email, password);
|
|
72
|
+
return new Api(loggedUser, userApi.client);
|
|
73
|
+
}
|
|
74
|
+
|
|
56
75
|
} catch (error) {
|
|
57
76
|
if(error instanceof ApiClientError) {
|
|
58
77
|
if(error?.details?.error) {
|
|
@@ -170,5 +189,11 @@ export default class Api {
|
|
|
170
189
|
get endpointApi() {
|
|
171
190
|
return new EndpointApi(this._client);
|
|
172
191
|
}
|
|
192
|
+
|
|
193
|
+
logout () {
|
|
194
|
+
this.loggedUser = null;
|
|
195
|
+
this._client.resetSession();
|
|
196
|
+
this._client._logger.info("UserApi: User logged out");
|
|
197
|
+
}
|
|
173
198
|
|
|
174
199
|
}
|
package/src/ApiClient.js
CHANGED
|
@@ -12,6 +12,7 @@ import pino from "pino";
|
|
|
12
12
|
import MongoID from "./EJSONType.js";
|
|
13
13
|
import endpointsJson from "./endpoints.module.js";
|
|
14
14
|
import { ApiClientError, ApiResponseError, ApiValidationError, CircuitBreakerError } from "./error.js";
|
|
15
|
+
import { MemoryStorageStrategy } from "./utils/TokenStorage.js";
|
|
15
16
|
|
|
16
17
|
EJSON.addType("oid", value => {
|
|
17
18
|
return new MongoID.ObjectID(value);
|
|
@@ -31,6 +32,7 @@ export default class ApiClient extends EventEmitter {
|
|
|
31
32
|
* @param {number} [options.circuitBreakerThreshold=5] - Nb d'erreurs avant de bloquer
|
|
32
33
|
* @param {number} [options.circuitBreakerResetTime=60000] - Ms avant de reset le breaker
|
|
33
34
|
* @param {boolean} [options.fromJSONValue=true] - Si true, les données sont transformées en EJSON
|
|
35
|
+
* @param {TokenStorageStrategy} [options.tokenStorageStrategy=null] - Stratégie de stockage des tokens
|
|
34
36
|
*/
|
|
35
37
|
constructor({
|
|
36
38
|
baseURL,
|
|
@@ -43,7 +45,8 @@ export default class ApiClient extends EventEmitter {
|
|
|
43
45
|
maxRetries = 0,
|
|
44
46
|
circuitBreakerThreshold = 5,
|
|
45
47
|
circuitBreakerResetTime = 60000,
|
|
46
|
-
fromJSONValue = true
|
|
48
|
+
fromJSONValue = true,
|
|
49
|
+
tokenStorageStrategy = null
|
|
47
50
|
} = {}) {
|
|
48
51
|
super(); // EventEmitter
|
|
49
52
|
|
|
@@ -54,7 +57,6 @@ export default class ApiClient extends EventEmitter {
|
|
|
54
57
|
this.__entityTag = "ApiClient";
|
|
55
58
|
|
|
56
59
|
this._baseURL = baseURL;
|
|
57
|
-
this._refreshToken = refreshToken;
|
|
58
60
|
this._refreshUrl = refreshUrl;
|
|
59
61
|
this._endpoints = endpoints;
|
|
60
62
|
this._debug = debug;
|
|
@@ -122,30 +124,73 @@ export default class ApiClient extends EventEmitter {
|
|
|
122
124
|
this._breakerOpen = false;
|
|
123
125
|
this._lastBreakerOpenTime = null;
|
|
124
126
|
|
|
125
|
-
|
|
127
|
+
this._accessToken = null;
|
|
128
|
+
this._refreshToken = null;
|
|
129
|
+
|
|
130
|
+
// Applique un token initial s'il est fourni
|
|
131
|
+
if(refreshToken){
|
|
132
|
+
this.setRefreshToken(refreshToken);
|
|
133
|
+
}
|
|
134
|
+
|
|
126
135
|
if (accessToken) {
|
|
127
136
|
this.setToken(accessToken);
|
|
128
137
|
}
|
|
129
138
|
|
|
139
|
+
this._tokenStorage = tokenStorageStrategy || new MemoryStorageStrategy();
|
|
140
|
+
|
|
141
|
+
const initialAccessToken = this._tokenStorage.getAccessToken();
|
|
142
|
+
if (initialAccessToken) {
|
|
143
|
+
this.setToken(initialAccessToken);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const initialRefreshToken = this._tokenStorage.getRefreshToken();
|
|
147
|
+
if (initialRefreshToken) {
|
|
148
|
+
this.setRefreshToken(initialRefreshToken);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
130
152
|
// Intercepteur 401 -> refresh
|
|
131
153
|
this._client.interceptors.response.use(
|
|
132
|
-
|
|
133
|
-
async
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
154
|
+
response => response,
|
|
155
|
+
async error => {
|
|
156
|
+
const originalRequest = error.config;
|
|
157
|
+
|
|
158
|
+
// Si la requête est déjà réessayée, abandonne
|
|
159
|
+
if (originalRequest._retry) {
|
|
160
|
+
this._logger.error("[ApiClient] Requête déjà retentée, échec définitif.");
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (error.response && error.response.status === 401 && this._refreshToken) {
|
|
165
|
+
originalRequest._retry = true;
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
this._logger.info("[ApiClient] Tentative de refresh du token...");
|
|
169
|
+
const refreshed = await this._refreshAccessToken();
|
|
170
|
+
|
|
171
|
+
if (refreshed) {
|
|
172
|
+
this._logger.info("[ApiClient] Token rafraîchi avec succès.");
|
|
173
|
+
|
|
174
|
+
// 🔑 Mise à jour EXPLICITE du header Authorization dans la requête originale
|
|
175
|
+
originalRequest.headers["Authorization"] = "Bearer " + this.getToken();
|
|
176
|
+
|
|
177
|
+
this._logger.info("[ApiClient] Retente la requête originale avec le nouveau token.");
|
|
178
|
+
return this._client.request(originalRequest);
|
|
179
|
+
} else {
|
|
180
|
+
this.resetSession();
|
|
181
|
+
throw new ApiClientError("Impossible de rafraîchir le token.", 401);
|
|
143
182
|
}
|
|
183
|
+
} catch (err) {
|
|
184
|
+
this.resetSession();
|
|
185
|
+
throw new ApiClientError("Erreur lors du rafraîchissement du token.", 401, err);
|
|
144
186
|
}
|
|
145
187
|
}
|
|
188
|
+
|
|
146
189
|
throw error;
|
|
147
190
|
}
|
|
148
191
|
);
|
|
192
|
+
|
|
193
|
+
|
|
149
194
|
}
|
|
150
195
|
|
|
151
196
|
/**
|
|
@@ -155,6 +200,7 @@ export default class ApiClient extends EventEmitter {
|
|
|
155
200
|
*/
|
|
156
201
|
setToken(token) {
|
|
157
202
|
this._accessToken = token;
|
|
203
|
+
this._tokenStorage.setAccessToken(token);
|
|
158
204
|
this._client.defaults.headers.common["Authorization"] = "Bearer " + token;
|
|
159
205
|
// Extrait l'id depuis le token et le stocke si disponible
|
|
160
206
|
const userId = this._getIdFromToken(token);
|
|
@@ -177,17 +223,20 @@ export default class ApiClient extends EventEmitter {
|
|
|
177
223
|
/**
|
|
178
224
|
* Sets the refresh token for the API client.
|
|
179
225
|
*
|
|
180
|
-
* @param {string}
|
|
226
|
+
* @param {string} refreshToken - The refresh token to be set.
|
|
181
227
|
*/
|
|
182
|
-
setRefreshToken(
|
|
183
|
-
this._refreshToken =
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
this.
|
|
188
|
-
|
|
228
|
+
setRefreshToken(token) {
|
|
229
|
+
this._refreshToken = token;
|
|
230
|
+
this._tokenStorage.setRefreshToken(token);
|
|
231
|
+
if(this.userId === null){
|
|
232
|
+
// Extrait l'id depuis le token et le stocke si disponible
|
|
233
|
+
const userId = this._getIdFromToken(token);
|
|
234
|
+
if (userId) {
|
|
235
|
+
this._setUserId(userId);
|
|
236
|
+
this._logger.debug(`[ApiClient] userId extrait depuis refreshToken : ${userId}`);
|
|
237
|
+
}
|
|
189
238
|
}
|
|
190
|
-
this._logger.debug(`[ApiClient] setRefreshToken: ${
|
|
239
|
+
this._logger.debug(`[ApiClient] setRefreshToken: ${token}`);
|
|
191
240
|
}
|
|
192
241
|
|
|
193
242
|
/**
|
|
@@ -235,14 +284,19 @@ export default class ApiClient extends EventEmitter {
|
|
|
235
284
|
*/
|
|
236
285
|
async _refreshAccessToken() {
|
|
237
286
|
if (!this._refreshToken) return false;
|
|
287
|
+
|
|
288
|
+
const refreshClient = axios.create({
|
|
289
|
+
baseURL: this._baseURL,
|
|
290
|
+
timeout: 10000, // ajuster si nécessaire
|
|
291
|
+
headers: { "Content-Type": "application/json" }
|
|
292
|
+
});
|
|
293
|
+
|
|
238
294
|
try {
|
|
239
|
-
const response = await
|
|
240
|
-
this.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if (response.data && response.data.accessToken) {
|
|
245
|
-
this.setToken(response.data.accessToken);
|
|
295
|
+
const response = await refreshClient.post(this._refreshUrl, {
|
|
296
|
+
refreshToken: this._refreshToken
|
|
297
|
+
});
|
|
298
|
+
if (response.data && response.data.token) {
|
|
299
|
+
this.setToken(response.data.token);
|
|
246
300
|
if (response.data.refreshToken) {
|
|
247
301
|
this.setRefreshToken(response.data.refreshToken);
|
|
248
302
|
}
|
|
@@ -775,6 +829,7 @@ export default class ApiClient extends EventEmitter {
|
|
|
775
829
|
this.setToken(null);
|
|
776
830
|
this.setRefreshToken(null);
|
|
777
831
|
this._setUserId(null);
|
|
832
|
+
this._tokenStorage.clear();
|
|
778
833
|
|
|
779
834
|
// Suppression des en-têtes
|
|
780
835
|
delete this._client.defaults.headers.common["Authorization"];
|
package/src/api/UserApi.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// UserApi.js
|
|
2
2
|
import ApiClient from "../ApiClient.js";
|
|
3
|
-
import { ApiResponseError } from "../error.js";
|
|
3
|
+
import { ApiError, ApiResponseError } from "../error.js";
|
|
4
4
|
import EndpointApi from "./EndpointApi.js";
|
|
5
5
|
import { News } from "./News.js";
|
|
6
6
|
import { Organization } from "./Organization.js";
|
|
@@ -11,8 +11,17 @@ export class UserApi {
|
|
|
11
11
|
constructor(options) {
|
|
12
12
|
// Injection de dépendance : ApiClient est créé à partir des options
|
|
13
13
|
this.client = new ApiClient(options);
|
|
14
|
+
// si l'option "tokenStorageStrategy" est définie, on l'utilise pour créer une instance de ApiClient
|
|
14
15
|
this.loggedUser = null;
|
|
15
16
|
}
|
|
17
|
+
|
|
18
|
+
get isConnected() {
|
|
19
|
+
return this.client.isConnected;
|
|
20
|
+
}
|
|
21
|
+
get userId() {
|
|
22
|
+
return this.client.userId;
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
// Méthode d'authentification : récupère les données utilisateur depuis un endpoint
|
|
17
26
|
async login(email, password) {
|
|
18
27
|
return this.client.safeCall(async () => {
|
|
@@ -24,6 +33,16 @@ export class UserApi {
|
|
|
24
33
|
});
|
|
25
34
|
}
|
|
26
35
|
|
|
36
|
+
async meIsconnected() {
|
|
37
|
+
if(!this.client.isConnected || !this.client.userId) {
|
|
38
|
+
throw new ApiError("User not connected", 401);
|
|
39
|
+
}
|
|
40
|
+
this.client._logger.info("UserApi", "meIsconnected", this.client.userId);
|
|
41
|
+
this.loggedUser = new User(this.client, { id: this.client.userId }, { EndpointApi, Organization, Project, News });
|
|
42
|
+
return this.loggedUser;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
27
46
|
async register({
|
|
28
47
|
name,
|
|
29
48
|
username,
|
|
@@ -49,4 +68,5 @@ export class UserApi {
|
|
|
49
68
|
return response.data;
|
|
50
69
|
});
|
|
51
70
|
}
|
|
71
|
+
|
|
52
72
|
}
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import Api from "./Api.js";
|
|
2
2
|
import ApiClient from "./ApiClient.js";
|
|
3
3
|
import * as error from "./error.js";
|
|
4
|
+
import { createDefaultTokenStorageStrategy } from "./utils/createDefaultTokenStorageStrategy.js";
|
|
5
|
+
import { TokenStorageStrategy } from "./utils/TokenStorage.js";
|
|
4
6
|
|
|
5
|
-
export default { ApiClient, Api, error };
|
|
7
|
+
export default { ApiClient, Api, error, tokenStorageStrategy: { createDefaultTokenStorageStrategy, TokenStorageStrategy } };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// src/utils/FileStorageStrategy.node.js
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
|
|
6
|
+
import { TokenStorageStrategy } from "./TokenStorage.js";
|
|
7
|
+
|
|
8
|
+
export class FileStorageStrategy extends TokenStorageStrategy {
|
|
9
|
+
constructor(filename = "tokens.json", dir = path.join(os.homedir(), ".config", "cocolight")) {
|
|
10
|
+
super();
|
|
11
|
+
this.dir = dir;
|
|
12
|
+
this.filePath = path.join(dir, filename);
|
|
13
|
+
this._ensureDirectoryExists();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
_ensureDirectoryExists() {
|
|
17
|
+
if (!fs.existsSync(this.dir)) {
|
|
18
|
+
fs.mkdirSync(this.dir, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
_readFile() {
|
|
23
|
+
if (!fs.existsSync(this.filePath)) return {};
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(fs.readFileSync(this.filePath, "utf8"));
|
|
26
|
+
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.error("Error reading token file:", e);
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_writeFile(data) {
|
|
34
|
+
fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), "utf8");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getAccessToken() {
|
|
38
|
+
return this._readFile().accessToken || null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
setAccessToken(token) {
|
|
42
|
+
const data = this._readFile();
|
|
43
|
+
data.accessToken = token;
|
|
44
|
+
this._writeFile(data);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
getRefreshToken() {
|
|
48
|
+
return this._readFile().refreshToken || null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setRefreshToken(token) {
|
|
52
|
+
const data = this._readFile();
|
|
53
|
+
data.refreshToken = token;
|
|
54
|
+
this._writeFile(data);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
clear() {
|
|
58
|
+
this._writeFile({});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// src/utils/TokenStorage.js
|
|
2
|
+
|
|
3
|
+
export class TokenStorageStrategy {
|
|
4
|
+
getAccessToken() {
|
|
5
|
+
throw new Error("getAccessToken() doit être implémenté");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line no-unused-vars
|
|
9
|
+
setAccessToken(token) {
|
|
10
|
+
throw new Error("setAccessToken() doit être implémenté");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getRefreshToken() {
|
|
14
|
+
throw new Error("getRefreshToken() doit être implémenté");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// eslint-disable-next-line no-unused-vars
|
|
18
|
+
setRefreshToken(token) {
|
|
19
|
+
throw new Error("setRefreshToken() doit être implémenté");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
clear() {
|
|
23
|
+
throw new Error("clear() doit être implémenté");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class MemoryStorageStrategy extends TokenStorageStrategy {
|
|
28
|
+
constructor() {
|
|
29
|
+
super();
|
|
30
|
+
this._accessToken = null;
|
|
31
|
+
this._refreshToken = null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getAccessToken() {
|
|
35
|
+
return this._accessToken;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setAccessToken(token) {
|
|
39
|
+
this._accessToken = token;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getRefreshToken() {
|
|
43
|
+
return this._refreshToken;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setRefreshToken(token) {
|
|
47
|
+
this._refreshToken = token;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
clear() {
|
|
51
|
+
this._accessToken = null;
|
|
52
|
+
this._refreshToken = null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export class LocalStorageStrategy extends TokenStorageStrategy {
|
|
57
|
+
constructor(prefix = "cocolight") {
|
|
58
|
+
super();
|
|
59
|
+
this.prefix = prefix;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getAccessToken() {
|
|
63
|
+
return typeof localStorage !== "undefined"
|
|
64
|
+
? localStorage.getItem(`${this.prefix}_accessToken`)
|
|
65
|
+
: null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
setAccessToken(token) {
|
|
69
|
+
if (typeof localStorage !== "undefined") {
|
|
70
|
+
localStorage.setItem(`${this.prefix}_accessToken`, token);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getRefreshToken() {
|
|
75
|
+
return typeof localStorage !== "undefined"
|
|
76
|
+
? localStorage.getItem(`${this.prefix}_refreshToken`)
|
|
77
|
+
: null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
setRefreshToken(token) {
|
|
81
|
+
if (typeof localStorage !== "undefined") {
|
|
82
|
+
localStorage.setItem(`${this.prefix}_refreshToken`, token);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
clear() {
|
|
87
|
+
if (typeof localStorage !== "undefined") {
|
|
88
|
+
localStorage.removeItem(`${this.prefix}_accessToken`);
|
|
89
|
+
localStorage.removeItem(`${this.prefix}_refreshToken`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { LocalStorageStrategy, MemoryStorageStrategy } from "./TokenStorage.js";
|
|
2
|
+
|
|
3
|
+
// src/utils/createDefaultTokenStorageStrategy.js
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Crée une stratégie de stockage de jetons par défaut en fonction de l'option fournie.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} [tokenStorageStrategy="auto"] - La stratégie de stockage de jetons souhaitée.
|
|
9
|
+
* Les valeurs possibles sont :
|
|
10
|
+
* - "memory" : Utilise une stratégie de stockage en mémoire.
|
|
11
|
+
* - "localStorage" : Utilise le localStorage du navigateur (si disponible).
|
|
12
|
+
* - "file" : Utilise une stratégie de stockage basée sur des fichiers (non disponible dans les environnements navigateur).
|
|
13
|
+
* - "auto" : Sélectionne automatiquement la meilleure stratégie de stockage disponible.
|
|
14
|
+
*
|
|
15
|
+
* @returns {Promise<Object>} Une promesse qui se résout avec une instance de la stratégie de stockage sélectionnée.
|
|
16
|
+
*
|
|
17
|
+
* @throws {Error} Lève une erreur si la stratégie sélectionnée n'est pas disponible dans l'environnement actuel.
|
|
18
|
+
*/
|
|
19
|
+
export async function createDefaultTokenStorageStrategy(tokenStorageStrategy = "auto") {
|
|
20
|
+
if (tokenStorageStrategy === "memory") {
|
|
21
|
+
return new MemoryStorageStrategy();
|
|
22
|
+
}
|
|
23
|
+
if (tokenStorageStrategy === "localStorage") {
|
|
24
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
25
|
+
return new LocalStorageStrategy();
|
|
26
|
+
} else {
|
|
27
|
+
throw new Error("localStorage is not available in this environment.");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (tokenStorageStrategy === "file") {
|
|
31
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
32
|
+
throw new Error("file storage is not available in this environment.");
|
|
33
|
+
}
|
|
34
|
+
const { FileStorageStrategy } = await import("./FileStorageStrategy.node.js");
|
|
35
|
+
return new FileStorageStrategy();
|
|
36
|
+
}
|
|
37
|
+
if (tokenStorageStrategy === "auto") {
|
|
38
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
39
|
+
return new LocalStorageStrategy();
|
|
40
|
+
} else {
|
|
41
|
+
const { FileStorageStrategy } = await import("./FileStorageStrategy.node.js");
|
|
42
|
+
return new FileStorageStrategy();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|