@communecter/cocolight-api-client 1.0.17 → 1.0.18

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.17",
3
+ "version": "1.0.18",
4
4
  "description": "Client Axios simplifié pour l'API cocolight",
5
5
  "repository": {
6
6
  "type": "git",
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 { MultiServerTokenStorageStrategy } from "./utils/MultiServerTokenStorageStrategy.js";
15
16
  import { MemoryStorageStrategy } from "./utils/TokenStorage.js";
16
17
 
17
18
 
@@ -150,6 +151,10 @@ export default class ApiClient extends EventEmitter {
150
151
  this._accessToken = null;
151
152
  this._refreshToken = null;
152
153
 
154
+ if (tokenStorageStrategy instanceof MultiServerTokenStorageStrategy) {
155
+ tokenStorageStrategy.use(this._baseURL);
156
+ }
157
+
153
158
  this._tokenStorage = tokenStorageStrategy || new MemoryStorageStrategy();
154
159
 
155
160
  if (
package/src/api/User.js CHANGED
@@ -491,6 +491,7 @@ export class User {
491
491
  this.#initialDraftData = JSON.parse(JSON.stringify(this.#draftData));
492
492
  }
493
493
 
494
+ // TODO: ne fonctionne pas
494
495
  hasChanges() {
495
496
  return JSON.stringify(this.#draftData) !== JSON.stringify(this.#initialDraftData);
496
497
  }
package/src/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import Api from "./Api.js";
2
2
  import ApiClient from "./ApiClient.js";
3
3
  import * as error from "./error.js";
4
+ import { createDefaultMultiServerTokenStorageStrategy } from "./utils/createDefaultMultiServerTokenStorageStrategy.js";
4
5
  import { createDefaultTokenStorageStrategy } from "./utils/createDefaultTokenStorageStrategy.js";
6
+ import { MultiServerTokenStorageStrategy } from "./utils/MultiServerTokenStorageStrategy.js";
5
7
  import OfflineClientManager from "./utils/OfflineClientManager.js";
6
8
  import { TokenStorageStrategy } from "./utils/TokenStorage.js";
7
9
 
8
- export default { ApiClient, Api, error, tokenStorageStrategy: { createDefaultTokenStorageStrategy, TokenStorageStrategy }, OfflineClientManager };
10
+ export default { ApiClient, Api, error, tokenStorageStrategy: { createDefaultTokenStorageStrategy, TokenStorageStrategy, createDefaultMultiServerTokenStorageStrategy, MultiServerTokenStorageStrategy }, OfflineClientManager };
@@ -0,0 +1,65 @@
1
+ import fs from "fs";
2
+ import os from "os";
3
+ import path from "path";
4
+
5
+ import { MultiServerTokenStorageStrategy } from "./MultiServerTokenStorageStrategy.js";
6
+
7
+ export class MultiServerFileStorageStrategy extends MultiServerTokenStorageStrategy {
8
+ constructor(filename = "tokens.json", dir = path.join(os.homedir(), ".config", "cocolight")) {
9
+ super();
10
+ this.filePath = path.join(dir, filename);
11
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
12
+ }
13
+
14
+ _readFile() {
15
+ if (!fs.existsSync(this.filePath)) return {};
16
+ try {
17
+ return JSON.parse(fs.readFileSync(this.filePath, "utf8"));
18
+ } catch {
19
+ return {};
20
+ }
21
+ }
22
+
23
+ _writeFile(data) {
24
+ fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), "utf8");
25
+ }
26
+
27
+ getAccessToken() {
28
+ this._ensureContext();
29
+ return this._readFile()[this._currentBaseURL]?.accessToken || null;
30
+ }
31
+
32
+ setAccessToken(token) {
33
+ this._ensureContext();
34
+ const all = this._readFile();
35
+ all[this._currentBaseURL] = { ...(all[this._currentBaseURL] || {}), accessToken: token };
36
+ this._writeFile(all);
37
+ }
38
+
39
+ getRefreshToken() {
40
+ this._ensureContext();
41
+ return this._readFile()[this._currentBaseURL]?.refreshToken || null;
42
+ }
43
+
44
+ setRefreshToken(token) {
45
+ this._ensureContext();
46
+ const all = this._readFile();
47
+ all[this._currentBaseURL] = { ...(all[this._currentBaseURL] || {}), refreshToken: token };
48
+ this._writeFile(all);
49
+ }
50
+
51
+ clear() {
52
+ this._ensureContext();
53
+ const all = this._readFile();
54
+ delete all[this._currentBaseURL];
55
+ this._writeFile(all);
56
+ }
57
+
58
+ getServers() {
59
+ return Object.keys(this._readFile());
60
+ }
61
+
62
+ exportAll() {
63
+ return this._readFile();
64
+ }
65
+ }
@@ -0,0 +1,131 @@
1
+ // MultiServerTokenStorageStrategy.js
2
+ import { TokenStorageStrategy } from "./TokenStorage.js";
3
+
4
+ export class MultiServerTokenStorageStrategy extends TokenStorageStrategy {
5
+ constructor() {
6
+ super();
7
+ this._currentBaseURL = null;
8
+ }
9
+
10
+ use(baseURL) {
11
+ if (!baseURL) throw new Error("baseURL est requis");
12
+ this._currentBaseURL = baseURL.replace(/\/+$/, "");
13
+ }
14
+
15
+ _ensureContext() {
16
+ if (!this._currentBaseURL) throw new Error("baseURL non défini. Appelez use(baseURL)");
17
+ }
18
+
19
+ getServers() {
20
+ throw new Error("getServers() doit être implémenté");
21
+ }
22
+
23
+ exportAll() {
24
+ throw new Error("exportAll() doit être implémenté");
25
+ }
26
+ }
27
+
28
+ // Mémoire
29
+ export class MultiServerMemoryStorageStrategy extends MultiServerTokenStorageStrategy {
30
+ constructor() {
31
+ super();
32
+ this._storage = new Map();
33
+ }
34
+
35
+ getAccessToken() {
36
+ this._ensureContext();
37
+ return this._storage.get(this._currentBaseURL)?.accessToken || null;
38
+ }
39
+
40
+ setAccessToken(token) {
41
+ this._ensureContext();
42
+ const current = this._storage.get(this._currentBaseURL) || {};
43
+ this._storage.set(this._currentBaseURL, { ...current, accessToken: token });
44
+ }
45
+
46
+ getRefreshToken() {
47
+ this._ensureContext();
48
+ return this._storage.get(this._currentBaseURL)?.refreshToken || null;
49
+ }
50
+
51
+ setRefreshToken(token) {
52
+ this._ensureContext();
53
+ const current = this._storage.get(this._currentBaseURL) || {};
54
+ this._storage.set(this._currentBaseURL, { ...current, refreshToken: token });
55
+ }
56
+
57
+ clear() {
58
+ this._ensureContext();
59
+ this._storage.delete(this._currentBaseURL);
60
+ }
61
+
62
+ getServers() {
63
+ return [...this._storage.keys()];
64
+ }
65
+
66
+ exportAll() {
67
+ return Object.fromEntries(this._storage.entries());
68
+ }
69
+ }
70
+
71
+ // Navigateur (localStorage)
72
+ export class MultiServerLocalStorageStrategy extends MultiServerTokenStorageStrategy {
73
+ constructor(prefix = "cocolight") {
74
+ super();
75
+ this.prefix = prefix;
76
+ }
77
+
78
+ _key(baseURL) {
79
+ return `${this.prefix}_tokens_${baseURL}`;
80
+ }
81
+
82
+ _getData() {
83
+ this._ensureContext();
84
+ const raw = localStorage.getItem(this._key(this._currentBaseURL));
85
+ return raw ? JSON.parse(raw) : {};
86
+ }
87
+
88
+ _setData(data) {
89
+ localStorage.setItem(this._key(this._currentBaseURL), JSON.stringify(data));
90
+ }
91
+
92
+ getAccessToken() {
93
+ return this._getData().accessToken || null;
94
+ }
95
+
96
+ setAccessToken(token) {
97
+ const data = this._getData();
98
+ data.accessToken = token;
99
+ this._setData(data);
100
+ }
101
+
102
+ getRefreshToken() {
103
+ return this._getData().refreshToken || null;
104
+ }
105
+
106
+ setRefreshToken(token) {
107
+ const data = this._getData();
108
+ data.refreshToken = token;
109
+ this._setData(data);
110
+ }
111
+
112
+ clear() {
113
+ localStorage.removeItem(this._key(this._currentBaseURL));
114
+ }
115
+
116
+ getServers() {
117
+ const keys = Object.keys(localStorage);
118
+ return keys
119
+ .filter(k => k.startsWith(`${this.prefix}_tokens_`))
120
+ .map(k => k.replace(`${this.prefix}_tokens_`, ""));
121
+ }
122
+
123
+ exportAll() {
124
+ const result = {};
125
+ for (const baseURL of this.getServers()) {
126
+ const raw = localStorage.getItem(this._key(baseURL));
127
+ if (raw) result[baseURL] = JSON.parse(raw);
128
+ }
129
+ return result;
130
+ }
131
+ }
@@ -0,0 +1,45 @@
1
+ import {
2
+ MultiServerMemoryStorageStrategy,
3
+ MultiServerLocalStorageStrategy,
4
+ } from "./MultiServerTokenStorageStrategy.js";
5
+
6
+ /**
7
+ * Crée une stratégie de stockage de tokens multi-serveurs adaptée à l’environnement.
8
+ *
9
+ * @param {string} [strategyType="auto"] - Type de stockage souhaité :
10
+ * - "memory" : en mémoire (non persistant)
11
+ * - "localStorage" : navigateur uniquement
12
+ * - "file" : Node.js uniquement
13
+ * - "auto" : choisit automatiquement selon l’environnement
14
+ * @returns {Promise<MultiServerTokenStorageStrategy>}
15
+ */
16
+ export async function createDefaultMultiServerTokenStorageStrategy(strategyType = "auto") {
17
+ if (strategyType === "memory") {
18
+ return new MultiServerMemoryStorageStrategy();
19
+ }
20
+
21
+ if (strategyType === "localStorage") {
22
+ if (typeof window !== "undefined" && window.localStorage) {
23
+ return new MultiServerLocalStorageStrategy();
24
+ } else {
25
+ throw new Error("localStorage n’est pas disponible dans cet environnement.");
26
+ }
27
+ }
28
+
29
+ if (strategyType === "file") {
30
+ if (typeof window !== "undefined" && window.localStorage) {
31
+ throw new Error("Le stockage fichier n’est pas disponible côté navigateur.");
32
+ }
33
+ const { MultiServerFileStorageStrategy } = await import("./MultiServerFileStorageStrategy.node.js");
34
+ return new MultiServerFileStorageStrategy();
35
+ }
36
+
37
+ // stratégie "auto"
38
+ if (typeof window !== "undefined" && window.localStorage) {
39
+ return new MultiServerLocalStorageStrategy();
40
+ } else {
41
+ const { MultiServerFileStorageStrategy } = await import("./MultiServerTokenStorageStrategy.js");
42
+ return new MultiServerFileStorageStrategy();
43
+ }
44
+ }
45
+
@@ -1,7 +1,5 @@
1
1
  import { LocalStorageStrategy, MemoryStorageStrategy } from "./TokenStorage.js";
2
2
 
3
- // src/utils/createDefaultTokenStorageStrategy.js
4
-
5
3
  /**
6
4
  * Crée une stratégie de stockage de jetons par défaut en fonction de l'option fournie.
7
5
  *