@communecter/cocolight-api-client 1.0.54 → 1.0.56

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.
Files changed (179) hide show
  1. package/dist/401.cocolight-api-client.browser.js +1 -0
  2. package/dist/401.cocolight-api-client.cjs +1 -0
  3. package/dist/401.cocolight-api-client.mjs.js +1 -0
  4. package/dist/588.cocolight-api-client.browser.js +1 -0
  5. package/dist/588.cocolight-api-client.cjs +1 -0
  6. package/dist/588.cocolight-api-client.mjs.js +1 -0
  7. package/dist/593.cocolight-api-client.browser.js +1 -0
  8. package/dist/593.cocolight-api-client.cjs +1 -0
  9. package/dist/593.cocolight-api-client.mjs.js +1 -0
  10. package/dist/839.cocolight-api-client.browser.js +1 -0
  11. package/dist/839.cocolight-api-client.cjs +1 -0
  12. package/dist/839.cocolight-api-client.mjs.js +1 -0
  13. package/dist/cocolight-api-client.browser.js +3 -3
  14. package/dist/cocolight-api-client.cjs +1 -1
  15. package/dist/cocolight-api-client.mjs.js +1 -1
  16. package/dist/cocolight-api-client.vite.mjs.js +1 -1
  17. package/dist/cocolight-api-client.vite.mjs.js.map +1 -1
  18. package/package.json +29 -17
  19. package/src/{Api.js → Api.ts} +85 -95
  20. package/src/{ApiClient.js → ApiClient.ts} +436 -247
  21. package/src/EJSONType.ts +103 -0
  22. package/src/api/{Badge.js → Badge.ts} +56 -45
  23. package/src/api/BaseEntity.ts +3890 -0
  24. package/src/api/Comment.ts +200 -0
  25. package/src/api/{EndpointApi.js → EndpointApi.ts} +363 -297
  26. package/src/api/EndpointApi.types.ts +4609 -0
  27. package/src/api/EntityRegistry.ts +203 -0
  28. package/src/api/Event.ts +332 -0
  29. package/src/api/News.ts +331 -0
  30. package/src/api/{Organization.js → Organization.ts} +155 -119
  31. package/src/api/{Poi.js → Poi.ts} +68 -60
  32. package/src/api/{Project.js → Project.ts} +150 -127
  33. package/src/api/{User.js → User.ts} +321 -256
  34. package/src/api/UserApi.ts +148 -0
  35. package/src/api/serverDataType/Comment.ts +88 -0
  36. package/src/api/serverDataType/Event.ts +80 -0
  37. package/src/api/serverDataType/News.ts +138 -0
  38. package/src/api/serverDataType/Organization.ts +80 -0
  39. package/src/api/serverDataType/Project.ts +71 -0
  40. package/src/api/serverDataType/User.ts +103 -0
  41. package/src/api/serverDataType/common.ts +80 -0
  42. package/src/endpoints.module.ts +2621 -0
  43. package/src/error.ts +86 -0
  44. package/src/index.ts +86 -0
  45. package/src/mixin/UserMixin.ts +4 -0
  46. package/src/types/api-responses.ts +217 -0
  47. package/src/types/entities.ts +22 -0
  48. package/src/types/error-guards.ts +230 -0
  49. package/src/types/index.ts +39 -0
  50. package/src/types/payloads.ts +21 -0
  51. package/src/types/transforms.ts +110 -0
  52. package/src/utils/{FileOfflineStorageStrategy.node.js → FileOfflineStorageStrategy.node.ts} +15 -12
  53. package/src/utils/{FileStorageStrategy.node.js → FileStorageStrategy.node.ts} +16 -39
  54. package/src/utils/MultiServerFileStorageStrategy.node.ts +67 -0
  55. package/src/utils/MultiServerTokenStorageStrategy.ts +139 -0
  56. package/src/utils/{OfflineClientManager.js → OfflineClientManager.ts} +82 -86
  57. package/src/utils/OfflineQueueStorageStrategy.ts +47 -0
  58. package/src/utils/TokenStorage.ts +77 -0
  59. package/src/utils/compat.ts +12 -0
  60. package/src/utils/createDefaultMultiServerTokenStorageStrategy.ts +35 -0
  61. package/src/utils/{createDefaultOfflineStrategy.js → createDefaultOfflineStrategy.ts} +8 -3
  62. package/src/utils/createDefaultTokenStorageStrategy.ts +33 -0
  63. package/src/utils/{reactive.js → reactive.ts} +49 -40
  64. package/src/utils/stream-utils.node.ts +12 -0
  65. package/types/Api.d.ts +38 -82
  66. package/types/Api.d.ts.map +1 -0
  67. package/types/ApiClient.d.ts +244 -184
  68. package/types/ApiClient.d.ts.map +1 -0
  69. package/types/EJSONType.d.ts +48 -22
  70. package/types/EJSONType.d.ts.map +1 -0
  71. package/types/api/Badge.d.ts +20 -20
  72. package/types/api/Badge.d.ts.map +1 -0
  73. package/types/api/BaseEntity.d.ts +751 -446
  74. package/types/api/BaseEntity.d.ts.map +1 -0
  75. package/types/api/Comment.d.ts +36 -0
  76. package/types/api/EndpointApi.d.ts +347 -295
  77. package/types/api/EndpointApi.d.ts.map +1 -0
  78. package/types/api/EndpointApi.types.d.ts +3914 -4133
  79. package/types/api/EntityRegistry.d.ts +18 -16
  80. package/types/api/EntityRegistry.d.ts.map +1 -0
  81. package/types/api/Event.d.ts +119 -35
  82. package/types/api/Event.d.ts.map +1 -0
  83. package/types/api/News.d.ts +52 -20
  84. package/types/api/News.d.ts.map +1 -0
  85. package/types/api/Organization.d.ts +165 -49
  86. package/types/api/Organization.d.ts.map +1 -0
  87. package/types/api/Poi.d.ts +51 -22
  88. package/types/api/Poi.d.ts.map +1 -0
  89. package/types/api/Project.d.ts +151 -52
  90. package/types/api/Project.d.ts.map +1 -0
  91. package/types/api/User.d.ts +222 -93
  92. package/types/api/User.d.ts.map +1 -0
  93. package/types/api/UserApi.d.ts +60 -9
  94. package/types/api/UserApi.d.ts.map +1 -0
  95. package/types/api/serverDataType/Comment.d.ts +83 -0
  96. package/types/api/serverDataType/Event.d.ts +67 -0
  97. package/types/api/serverDataType/News.d.ts +130 -0
  98. package/types/api/serverDataType/Organization.d.ts +65 -0
  99. package/types/api/serverDataType/Organization.d.ts.map +1 -0
  100. package/types/api/serverDataType/Project.d.ts +58 -0
  101. package/types/api/serverDataType/Project.d.ts.map +1 -0
  102. package/types/api/serverDataType/User.d.ts +86 -0
  103. package/types/api/serverDataType/User.d.ts.map +1 -0
  104. package/types/api/serverDataType/common.d.ts +71 -0
  105. package/types/api/serverDataType/common.d.ts.map +1 -0
  106. package/types/endpoints.module.d.ts +6922 -1215
  107. package/types/endpoints.module.d.ts.map +1 -0
  108. package/types/error.d.ts +25 -51
  109. package/types/error.d.ts.map +1 -0
  110. package/types/index.d.ts +55 -48
  111. package/types/index.d.ts.map +1 -0
  112. package/types/mixin/UserMixin.d.ts +1 -1
  113. package/types/mixin/UserMixin.d.ts.map +1 -0
  114. package/types/types/api-responses.d.ts +190 -0
  115. package/types/types/api-responses.d.ts.map +1 -0
  116. package/types/types/entities.d.ts +17 -0
  117. package/types/types/entities.d.ts.map +1 -0
  118. package/types/types/error-guards.d.ts +99 -0
  119. package/types/types/error-guards.d.ts.map +1 -0
  120. package/types/types/index.d.ts +7 -0
  121. package/types/types/payloads.d.ts +17 -0
  122. package/types/types/payloads.d.ts.map +1 -0
  123. package/types/types/transforms.d.ts +79 -0
  124. package/types/types/transforms.d.ts.map +1 -0
  125. package/types/utils/FileOfflineStorageStrategy.node.d.ts +10 -9
  126. package/types/utils/FileOfflineStorageStrategy.node.d.ts.map +1 -0
  127. package/types/utils/FileStorageStrategy.node.d.ts +9 -20
  128. package/types/utils/FileStorageStrategy.node.d.ts.map +1 -0
  129. package/types/utils/MultiServerFileStorageStrategy.node.d.ts +13 -18
  130. package/types/utils/MultiServerFileStorageStrategy.node.d.ts.map +1 -0
  131. package/types/utils/MultiServerTokenStorageStrategy.d.ts +30 -51
  132. package/types/utils/MultiServerTokenStorageStrategy.d.ts.map +1 -0
  133. package/types/utils/OfflineClientManager.d.ts +52 -88
  134. package/types/utils/OfflineClientManager.d.ts.map +1 -0
  135. package/types/utils/OfflineQueueStorageStrategy.d.ts +12 -9
  136. package/types/utils/OfflineQueueStorageStrategy.d.ts.map +1 -0
  137. package/types/utils/TokenStorage.d.ts +20 -70
  138. package/types/utils/TokenStorage.d.ts.map +1 -0
  139. package/types/utils/compat.d.ts +4 -0
  140. package/types/utils/compat.d.ts.map +1 -0
  141. package/types/utils/createDefaultMultiServerTokenStorageStrategy.d.ts +2 -11
  142. package/types/utils/createDefaultMultiServerTokenStorageStrategy.d.ts.map +1 -0
  143. package/types/utils/createDefaultOfflineStrategy.d.ts +2 -3
  144. package/types/utils/createDefaultOfflineStrategy.d.ts.map +1 -0
  145. package/types/utils/createDefaultTokenStorageStrategy.d.ts +2 -12
  146. package/types/utils/createDefaultTokenStorageStrategy.d.ts.map +1 -0
  147. package/types/utils/reactive.d.ts +10 -16
  148. package/types/utils/reactive.d.ts.map +1 -0
  149. package/types/utils/stream-utils.node.d.ts +3 -2
  150. package/types/utils/stream-utils.node.d.ts.map +1 -0
  151. package/dist/123.cocolight-api-client.browser.js +0 -1
  152. package/dist/123.cocolight-api-client.cjs +0 -1
  153. package/dist/22.cocolight-api-client.mjs.js +0 -1
  154. package/dist/339.cocolight-api-client.mjs.js +0 -1
  155. package/dist/394.cocolight-api-client.browser.js +0 -1
  156. package/dist/394.cocolight-api-client.cjs +0 -1
  157. package/dist/405.cocolight-api-client.browser.js +0 -1
  158. package/dist/405.cocolight-api-client.cjs +0 -1
  159. package/dist/774.cocolight-api-client.mjs.js +0 -1
  160. package/dist/790.cocolight-api-client.mjs.js +0 -1
  161. package/dist/931.cocolight-api-client.browser.js +0 -1
  162. package/dist/931.cocolight-api-client.cjs +0 -1
  163. package/src/EJSONType.js +0 -53
  164. package/src/api/BaseEntity.js +0 -2828
  165. package/src/api/EntityRegistry.js +0 -152
  166. package/src/api/Event.js +0 -226
  167. package/src/api/News.js +0 -244
  168. package/src/api/UserApi.js +0 -81
  169. package/src/endpoints.module.js +0 -5
  170. package/src/error.js +0 -121
  171. package/src/index.js +0 -97
  172. package/src/mixin/UserMixin.js +0 -8
  173. package/src/utils/MultiServerFileStorageStrategy.node.js +0 -87
  174. package/src/utils/MultiServerTokenStorageStrategy.js +0 -188
  175. package/src/utils/OfflineQueueStorageStrategy.js +0 -51
  176. package/src/utils/TokenStorage.js +0 -153
  177. package/src/utils/createDefaultMultiServerTokenStorageStrategy.js +0 -51
  178. package/src/utils/createDefaultTokenStorageStrategy.js +0 -49
  179. package/src/utils/stream-utils.node.js +0 -10
@@ -1,31 +1,70 @@
1
- // OfflineClientManager.js
1
+ // OfflineClientManager.ts
2
2
  import ApiClient from "../ApiClient.js";
3
3
  import { createDefaultOfflineStrategy } from "./createDefaultOfflineStrategy.js";
4
+ import { OfflineQueueStorageStrategy } from "./OfflineQueueStorageStrategy.js";
5
+
6
+ type OfflineQueueStorageStrategyAction = import("./OfflineQueueStorageStrategy.js").OfflineQueueStorageStrategy<OfflineAction>;
7
+
8
+ /**
9
+ * Métadonnées nécessaires pour rejouer une action offline sur le bon serveur.
10
+ */
11
+ interface OfflineActionMeta {
12
+ baseURL: string;
13
+ accessToken?: string | null;
14
+ refreshToken?: string | null;
15
+ timestamp: number; // Epoch ms de l'enfilement.
16
+ }
17
+
18
+ /**
19
+ * Options passées à l'appel de l'endpoint lors du replay.
20
+ */
21
+ interface OfflineActionOptions {
22
+ transformResponseData?: boolean | ((...args: any[]) => any);
23
+ validateResponseSchema?: boolean;
24
+ }
25
+
26
+ /**
27
+ * Élément de la file d'attente offline.
28
+ */
29
+ export interface OfflineAction {
30
+ constant: string; // Nom de l'endpoint à appeler.
31
+ data: unknown; // Payload d'entrée (forme dépendante de l'endpoint).
32
+ options?: OfflineActionOptions;
33
+ meta: OfflineActionMeta;
34
+ }
35
+
36
+ /**
37
+ * Options d'attache du gestionnaire offline.
38
+ */
39
+ interface AttachOptions {
40
+ offlineStorageStrategy?: "auto" | "memory" | "localStorage" | "file";
41
+ disableOfflineMonitoring?: boolean;
42
+ interval?: number; // Intervalle de ping réseau (ms), relayé à startOfflineMonitoring.
43
+ }
4
44
 
5
45
  export class OfflineClientManager {
6
- /**
7
- * Initialise un gestionnaire de mode offline pour un ApiClient donné.
8
- *
9
- * @param {ApiClient} apiClient - Instance du client principal.
10
- */
11
- constructor(apiClient) {
12
- if(!apiClient || !(apiClient instanceof ApiClient)) {
46
+ private _clients: Map<string, any>;
47
+ private _client: any;
48
+ private _offlineMode: boolean | undefined;
49
+ private _pingInterval: ReturnType<typeof setInterval> | undefined;
50
+ private _offlineQueueStorage: OfflineQueueStorageStrategyAction | undefined;
51
+ private _offlineQueue: OfflineAction[];
52
+ private _monitoringStarted: boolean | undefined;
53
+
54
+ constructor(apiClient: any) {
55
+ if (!apiClient || !(apiClient instanceof ApiClient)) {
13
56
  throw new Error("[OfflineClientManager] apiClient doit être une instance de ApiClient");
14
57
  }
15
58
  this._clients = new Map();
16
59
  this._client = apiClient;
60
+ this._offlineMode = undefined;
61
+ this._pingInterval = undefined;
62
+ this._offlineQueueStorage = undefined;
63
+ this._offlineQueue = [];
64
+ this._monitoringStarted = undefined;
17
65
  }
18
66
 
19
- /**
20
- * Attache le gestionnaire offline à une instance ApiClient.
21
- * Configure la file d'attente offline, le monitoring réseau, et le ping serveur.
22
- *
23
- * @param {ApiClient} apiClient - L'instance du client à enrichir.
24
- * @param {Object} options
25
- * @param {Object} [options.offlineStorageStrategy] - Stratégie de stockage offline.
26
- * @param {boolean} [options.disableOfflineMonitoring] - Si true, désactive le monitoring réseau.
27
- */
28
- static async attachTo(apiClient, options = {}) {
67
+ static async attachTo(apiClient: any, options: AttachOptions = {}): Promise<any> {
29
68
  apiClient._offlineClientManager = new OfflineClientManager(apiClient);
30
69
  const strategy = await createDefaultOfflineStrategy(options?.offlineStorageStrategy || "auto");
31
70
  await apiClient._offlineClientManager._initOfflineQueue(strategy);
@@ -34,14 +73,7 @@ export class OfflineClientManager {
34
73
  }
35
74
  }
36
75
 
37
- /**
38
- * Retourne un ApiClient configuré avec les bons tokens/baseURL pour rejouer une action offline.
39
- * Met en cache l'instance pour éviter les recréations.
40
- *
41
- * @param {Object} meta - Métadonnées contenant baseURL et tokens.
42
- * @returns {Promise<ApiClient>}
43
- */
44
- async getClient(meta) {
76
+ async getClient(meta: OfflineActionMeta): Promise<any> {
45
77
  const key = `${meta.baseURL}|${meta.accessToken}`;
46
78
  if (this._clients.has(key)) return this._clients.get(key);
47
79
 
@@ -56,16 +88,9 @@ export class OfflineClientManager {
56
88
  return client;
57
89
  }
58
90
 
59
- /**
60
- * Rejoue une action unique depuis la file offline.
61
- *
62
- * @param {Object} action - Objet contenant constant, data, options et meta.
63
- * @returns {Promise<any>}
64
- */
65
- async replayAction(action) {
91
+ async replayAction(action: OfflineAction): Promise<any> {
66
92
  const client = await this.getClient(action.meta);
67
93
  try {
68
-
69
94
  const result = await client.callEndpoint(
70
95
  action.constant,
71
96
  action.data,
@@ -75,20 +100,12 @@ export class OfflineClientManager {
75
100
  this._client._logger.info(`[OfflineReplay] Succès ${action.constant} sur ${action.meta.baseURL}`);
76
101
  return result;
77
102
  } catch (err) {
78
- this._client._logger.error(`[OfflineReplay] Échec ${action.constant}`, err.message);
103
+ this._client._logger.error(`[OfflineReplay] Échec ${action.constant}`, (err as Error).message);
79
104
  throw err;
80
105
  }
81
106
  }
82
107
 
83
- /**
84
- * Démarre la surveillance de l'état réseau.
85
- * Basé sur navigator.onLine + un ping serveur régulier.
86
- *
87
- * @param {Object} [options]
88
- * @param {number} [options.interval=30000] - Intervalle de vérification en ms.
89
- * @param {boolean} [options.disableOfflineMonitoring=false] - Pour désactiver.
90
- */
91
- startOfflineMonitoring({ interval = 30000, disableOfflineMonitoring = false } = {}) {
108
+ startOfflineMonitoring({ interval = 30000, disableOfflineMonitoring = false }: Pick<AttachOptions, "interval" | "disableOfflineMonitoring"> = {}) {
92
109
  if (disableOfflineMonitoring || this._monitoringStarted) return;
93
110
 
94
111
  this._monitoringStarted = true;
@@ -102,27 +119,20 @@ export class OfflineClientManager {
102
119
  this._pingInterval = setInterval(async () => {
103
120
  const wasOffline = this._offlineMode;
104
121
  try {
105
- await this._client._client.head("/api/cocolight/infoserver", { timeout: 5000 }); // ✅ utilise la fonction injectée
122
+ await this._client._client.head("/api/cocolight/infoserver", { timeout: 5000 });
106
123
  if (wasOffline) this.setOfflineMode(false);
107
124
 
108
- // eslint-disable-next-line no-unused-vars
109
- } catch (err) {
125
+ } catch {
110
126
  this._client._logger.error("[OfflineMonitor] ping() échoué → passage en offline");
111
127
  this.setOfflineMode(true);
112
128
  }
113
129
  }, interval);
114
130
  }
115
131
 
116
- /**
117
- * Change l'état offline et émet un événement si l'état change.
118
- * Déclenche la relecture de la file si on revient online.
119
- *
120
- * @param {boolean} isOffline
121
- */
122
- setOfflineMode(isOffline) {
132
+ setOfflineMode(isOffline: boolean) {
123
133
  if (this._offlineMode === isOffline) return;
124
134
  this._offlineMode = isOffline;
125
- if (typeof this._emit === "function") {
135
+ if (typeof this._client.emit === "function") {
126
136
  this._client.emit("offlineModeChanged", isOffline);
127
137
  }
128
138
  this._client._logger.info(`[ApiClient] Mode offline : ${isOffline} (set depuis monitoring)`);
@@ -132,33 +142,23 @@ export class OfflineClientManager {
132
142
  }
133
143
  }
134
144
 
135
- /**
136
- * Indique si le client est actuellement en mode offline.
137
- *
138
- * @returns {boolean}
139
- */
140
- isOffline() {
145
+ isOffline(): boolean {
141
146
  return !!this._offlineMode;
142
147
  }
143
148
 
144
- /**
145
- * Met une action API dans la file offline.
146
- *
147
- * @param {Object} params
148
- * @param {string} params.constant - Le nom de l'endpoint.
149
- * @param {Object} params.data - Données à envoyer.
150
- * @param {Object} [params.options] - Options de transformation/validation.
151
- */
152
- async _enqueueOfflineAction({ constant, data, options = {} }) {
149
+ async _enqueueOfflineAction({ constant, data, options = {} }: { constant: string; data: unknown; options?: OfflineActionOptions }): Promise<any> {
150
+ if (!this._offlineQueueStorage) {
151
+ throw new Error("[OfflineClientManager] _offlineQueueStorage non initialisé");
152
+ }
153
153
  const hasToken = this._client.getToken() || this._client.getRefreshToken();
154
- const endpoint = this._client._endpoints.find(e => e.constant === constant);
154
+ const endpoint = this._client._endpoints.find((e: any) => e.constant === constant);
155
155
  const authPolicy = endpoint?.authPolicy || (endpoint?.auth === "none" ? "none" : "required");
156
156
  if (authPolicy === "required" && !hasToken) {
157
157
  this._client._logger.warn(`[Offline] Action ignorée : token requis mais absent (${constant})`);
158
158
  return;
159
159
  }
160
160
 
161
- const action = {
161
+ const action: OfflineAction = {
162
162
  constant,
163
163
  data,
164
164
  options,
@@ -175,17 +175,16 @@ export class OfflineClientManager {
175
175
  this._client._logger.info(`[Offline] Action mise en file : ${constant}`);
176
176
  }
177
177
 
178
- /**
179
- * Rejoue toutes les actions offline.
180
- * Ré-insère celles qui échouent dans la file.
181
- */
182
- async _replayOfflineQueue() {
178
+ async _replayOfflineQueue(): Promise<any> {
179
+ if (!this._offlineQueueStorage) {
180
+ throw new Error("[OfflineClientManager] _offlineQueueStorage non initialisé");
181
+ }
183
182
  const queueCopy = [...this._offlineQueue];
184
183
  this._offlineQueue = [];
185
184
  await this._offlineQueueStorage.saveQueue([]);
186
185
 
187
186
  for (const action of queueCopy) {
188
- const endpoint = this._client._endpoints.find(e => e.constant === action.constant);
187
+ const endpoint = this._client._endpoints.find((e: any) => e.constant === action.constant);
189
188
  const authPolicy = endpoint?.authPolicy || (endpoint?.auth === "none" ? "none" : "required");
190
189
  const hasToken = action.meta.accessToken || action.meta.refreshToken;
191
190
 
@@ -196,9 +195,8 @@ export class OfflineClientManager {
196
195
 
197
196
  try {
198
197
  await this.replayAction(action);
199
-
200
198
  } catch (e) {
201
- this._client._logger.error("[Offline] Relecture échouée :", e.message);
199
+ this._client._logger.error("[Offline] Relecture échouée :", (e as Error).message);
202
200
  this._offlineQueue.push(action); // requeue si erreur
203
201
  }
204
202
  }
@@ -206,12 +204,10 @@ export class OfflineClientManager {
206
204
  await this._offlineQueueStorage.saveQueue(this._offlineQueue);
207
205
  }
208
206
 
209
- /**
210
- * Initialise la stratégie de stockage offline et charge la file d’attente.
211
- *
212
- * @param {OfflineQueueStorageStrategy} storageStrategy
213
- */
214
- async _initOfflineQueue(storageStrategy) {
207
+ async _initOfflineQueue(storageStrategy: OfflineQueueStorageStrategyAction): Promise<any> {
208
+ if(!storageStrategy || !(storageStrategy instanceof OfflineQueueStorageStrategy)) {
209
+ throw new Error("[OfflineClientManager] storageStrategy doit être une instance de OfflineQueueStorageStrategy");
210
+ }
215
211
  this._offlineQueueStorage = storageStrategy;
216
212
  this._offlineQueue = await storageStrategy.loadQueue();
217
213
  }
@@ -0,0 +1,47 @@
1
+ export abstract class OfflineQueueStorageStrategy<T = any> {
2
+ abstract loadQueue(): Promise<T[]>;
3
+ abstract saveQueue(queue: T[]): Promise<void>;
4
+ }
5
+
6
+ export class MemoryOfflineStorage<T = any> extends OfflineQueueStorageStrategy<T> {
7
+ private _queue: T[] = [];
8
+
9
+ constructor() {
10
+ super();
11
+ }
12
+
13
+ async loadQueue(): Promise<T[]> {
14
+ return this._queue;
15
+ }
16
+
17
+ async saveQueue(queue: T[]): Promise<void> {
18
+ this._queue = [...queue];
19
+ }
20
+ }
21
+
22
+ export class LocalStorageOfflineStorage<T = any> extends OfflineQueueStorageStrategy<T> {
23
+ public readonly key: string;
24
+
25
+ constructor(key: string = "cocolight-api-offline-queue") {
26
+ super();
27
+ this.key = key;
28
+ }
29
+
30
+ async loadQueue(): Promise<T[]> {
31
+ try {
32
+ const raw = localStorage.getItem(this.key);
33
+ const parsed: T[] | null = raw ? JSON.parse(raw) : null;
34
+ return parsed ?? [];
35
+ } catch {
36
+ return [];
37
+ }
38
+ }
39
+
40
+ async saveQueue(queue: T[]): Promise<void> {
41
+ try {
42
+ localStorage.setItem(this.key, JSON.stringify(queue));
43
+ } catch (e) {
44
+ console.warn("[Offline] Échec du stockage localStorage", e);
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,77 @@
1
+ export abstract class TokenStorageStrategy {
2
+ abstract getAccessToken(): string | null;
3
+ abstract setAccessToken(token: string | null): void;
4
+ abstract getRefreshToken(): string | null;
5
+ abstract setRefreshToken(token: string | null): void;
6
+ abstract clear(): void;
7
+ }
8
+
9
+ export class MemoryStorageStrategy extends TokenStorageStrategy {
10
+ private _accessToken: string | null = null;
11
+ private _refreshToken: string | null = null;
12
+
13
+ constructor() {
14
+ super();
15
+ }
16
+
17
+ getAccessToken(): string | null {
18
+ return this._accessToken;
19
+ }
20
+
21
+ setAccessToken(token: string | null): void {
22
+ this._accessToken = token;
23
+ }
24
+
25
+ getRefreshToken(): string | null {
26
+ return this._refreshToken;
27
+ }
28
+
29
+ setRefreshToken(token: string | null): void {
30
+ this._refreshToken = token;
31
+ }
32
+
33
+ clear(): void {
34
+ this._accessToken = null;
35
+ this._refreshToken = null;
36
+ }
37
+ }
38
+
39
+ export class LocalStorageStrategy extends TokenStorageStrategy {
40
+ public readonly prefix: string;
41
+
42
+ constructor(prefix: string = "cocolight") {
43
+ super();
44
+ this.prefix = prefix;
45
+ }
46
+
47
+ getAccessToken(): string | null {
48
+ return typeof localStorage !== "undefined"
49
+ ? localStorage.getItem(`${this.prefix}_accessToken`)
50
+ : null;
51
+ }
52
+
53
+ setAccessToken(token: string | null): void {
54
+ if (typeof localStorage !== "undefined") {
55
+ localStorage.setItem(`${this.prefix}_accessToken`, token ?? "");
56
+ }
57
+ }
58
+
59
+ getRefreshToken(): string | null {
60
+ return typeof localStorage !== "undefined"
61
+ ? localStorage.getItem(`${this.prefix}_refreshToken`)
62
+ : null;
63
+ }
64
+
65
+ setRefreshToken(token: string | null): void {
66
+ if (typeof localStorage !== "undefined") {
67
+ localStorage.setItem(`${this.prefix}_refreshToken`, token ?? "");
68
+ }
69
+ }
70
+
71
+ clear(): void {
72
+ if (typeof localStorage !== "undefined") {
73
+ localStorage.removeItem(`${this.prefix}_accessToken`);
74
+ localStorage.removeItem(`${this.prefix}_refreshToken`);
75
+ }
76
+ }
77
+ }
@@ -0,0 +1,12 @@
1
+ // utils/compat.ts - Compatibility layer for default imports
2
+ const _def = <T>(m: T & { default?: any }): any => (m && m.default) ? m.default : m;
3
+
4
+ import * as AjvNS from "ajv";
5
+ import * as addFormatsNS from "ajv-formats";
6
+ import * as EJSONNS from "ejson";
7
+ import * as pinoNS from "pino";
8
+
9
+ export const Ajv = _def(AjvNS); // constructible
10
+ export const addFormats = _def(addFormatsNS); // callable
11
+ export const pino = _def(pinoNS); // callable
12
+ export const EJSON = _def(EJSONNS); // default safe
@@ -0,0 +1,35 @@
1
+ import {
2
+ MultiServerMemoryStorageStrategy,
3
+ MultiServerLocalStorageStrategy,
4
+ type MultiServerTokenStorageStrategy,
5
+ } from "./MultiServerTokenStorageStrategy.js";
6
+
7
+ export async function createDefaultMultiServerTokenStorageStrategy(
8
+ strategyType: "memory" | "localStorage" | "file" | "auto" = "auto"
9
+ ): Promise<MultiServerTokenStorageStrategy> {
10
+ if (strategyType === "memory") {
11
+ return new MultiServerMemoryStorageStrategy();
12
+ }
13
+
14
+ if (strategyType === "localStorage") {
15
+ if (typeof window !== "undefined" && typeof window.localStorage !== "undefined") {
16
+ return new MultiServerLocalStorageStrategy();
17
+ }
18
+ throw new Error("localStorage n'est pas disponible dans cet environnement.");
19
+ }
20
+
21
+ if (strategyType === "file") {
22
+ if (typeof window !== "undefined" && typeof window.localStorage !== "undefined") {
23
+ throw new Error("Le stockage fichier n'est pas disponible côté navigateur.");
24
+ }
25
+ const { MultiServerFileStorageStrategy } = await import("./MultiServerFileStorageStrategy.node.js");
26
+ return new MultiServerFileStorageStrategy();
27
+ }
28
+
29
+ // auto
30
+ if (typeof window !== "undefined" && typeof window.localStorage !== "undefined") {
31
+ return new MultiServerLocalStorageStrategy();
32
+ }
33
+ const { MultiServerFileStorageStrategy } = await import("./MultiServerFileStorageStrategy.node.js");
34
+ return new MultiServerFileStorageStrategy();
35
+ }
@@ -1,6 +1,8 @@
1
- import { LocalStorageOfflineStorage, MemoryOfflineStorage } from "./OfflineQueueStorageStrategy.js";
1
+ import { LocalStorageOfflineStorage, MemoryOfflineStorage, type OfflineQueueStorageStrategy } from "./OfflineQueueStorageStrategy.js";
2
2
 
3
- export async function createDefaultOfflineStrategy(offlineStorageStrategy = "auto") {
3
+ export async function createDefaultOfflineStrategy<T = any>(
4
+ offlineStorageStrategy: "auto" | "memory" | "localStorage" | "file" = "auto"
5
+ ): Promise<OfflineQueueStorageStrategy<T>> {
4
6
  if (offlineStorageStrategy === "memory") {
5
7
  return new MemoryOfflineStorage();
6
8
  }
@@ -26,4 +28,7 @@ export async function createDefaultOfflineStrategy(offlineStorageStrategy = "aut
26
28
  return new FileOfflineStorage();
27
29
  }
28
30
  }
29
- }
31
+
32
+ // Handle unexpected strategy values
33
+ throw new Error(`Unsupported offline storage strategy: ${offlineStorageStrategy}`);
34
+ }
@@ -0,0 +1,33 @@
1
+ import { LocalStorageStrategy, MemoryStorageStrategy } from "./TokenStorage.js";
2
+
3
+ import type { TokenStorageStrategy } from "./TokenStorage.js";
4
+
5
+ export async function createDefaultTokenStorageStrategy(
6
+ tokenStorageStrategy: "memory" | "localStorage" | "file" | "auto" = "auto"
7
+ ): Promise<TokenStorageStrategy> {
8
+ if (tokenStorageStrategy === "memory") {
9
+ return new MemoryStorageStrategy();
10
+ }
11
+
12
+ if (tokenStorageStrategy === "localStorage") {
13
+ if (typeof window !== "undefined" && window.localStorage) {
14
+ return new LocalStorageStrategy();
15
+ }
16
+ throw new Error("localStorage is not available in this environment.");
17
+ }
18
+
19
+ if (tokenStorageStrategy === "file") {
20
+ if (typeof window !== "undefined" && window.localStorage) {
21
+ throw new Error("file storage is not available in this environment.");
22
+ }
23
+ const { FileStorageStrategy } = await import("./FileStorageStrategy.node.js");
24
+ return new FileStorageStrategy();
25
+ }
26
+
27
+ // 'auto'
28
+ if (typeof window !== "undefined" && window.localStorage) {
29
+ return new LocalStorageStrategy();
30
+ }
31
+ const { FileStorageStrategy } = await import("./FileStorageStrategy.node.js");
32
+ return new FileStorageStrategy();
33
+ }