canvasframework 0.3.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/README.md +554 -0
- package/components/Accordion.js +252 -0
- package/components/AndroidDatePickerDialog.js +398 -0
- package/components/AppBar.js +225 -0
- package/components/Avatar.js +202 -0
- package/components/BottomNavigationBar.js +205 -0
- package/components/BottomSheet.js +374 -0
- package/components/Button.js +225 -0
- package/components/Card.js +193 -0
- package/components/Checkbox.js +180 -0
- package/components/Chip.js +212 -0
- package/components/CircularProgress.js +143 -0
- package/components/ContextMenu.js +116 -0
- package/components/DatePicker.js +257 -0
- package/components/Dialog.js +367 -0
- package/components/Divider.js +125 -0
- package/components/Drawer.js +261 -0
- package/components/FAB.js +270 -0
- package/components/FileUpload.js +315 -0
- package/components/IOSDatePickerWheel.js +268 -0
- package/components/ImageCarousel.js +193 -0
- package/components/ImageComponent.js +223 -0
- package/components/Input.js +309 -0
- package/components/List.js +94 -0
- package/components/ListItem.js +223 -0
- package/components/Modal.js +364 -0
- package/components/MultiSelectDialog.js +206 -0
- package/components/NumberInput.js +271 -0
- package/components/ProgressBar.js +88 -0
- package/components/RadioButton.js +142 -0
- package/components/SearchInput.js +315 -0
- package/components/SegmentedControl.js +202 -0
- package/components/Select.js +199 -0
- package/components/SelectDialog.js +255 -0
- package/components/Slider.js +113 -0
- package/components/Snackbar.js +243 -0
- package/components/Stepper.js +281 -0
- package/components/SwipeableListItem.js +179 -0
- package/components/Switch.js +147 -0
- package/components/Table.js +492 -0
- package/components/Tabs.js +125 -0
- package/components/Text.js +141 -0
- package/components/TextField.js +331 -0
- package/components/Toast.js +236 -0
- package/components/TreeView.js +420 -0
- package/components/Video.js +397 -0
- package/components/View.js +140 -0
- package/components/VirtualList.js +120 -0
- package/core/CanvasFramework.js +1271 -0
- package/core/CanvasWork.js +32 -0
- package/core/Component.js +153 -0
- package/core/LogicWorker.js +25 -0
- package/core/WebGLCanvasAdapter.js +1369 -0
- package/features/Column.js +43 -0
- package/features/Grid.js +47 -0
- package/features/LayoutComponent.js +43 -0
- package/features/OpenStreetMap.js +310 -0
- package/features/Positioned.js +33 -0
- package/features/PullToRefresh.js +328 -0
- package/features/Row.js +40 -0
- package/features/SignaturePad.js +257 -0
- package/features/Skeleton.js +84 -0
- package/features/Stack.js +21 -0
- package/index.js +101 -0
- package/manager/AccessibilityManager.js +107 -0
- package/manager/ErrorHandler.js +59 -0
- package/manager/FeatureFlags.js +60 -0
- package/manager/MemoryManager.js +107 -0
- package/manager/PerformanceMonitor.js +84 -0
- package/manager/SecurityManager.js +54 -0
- package/package.json +28 -0
- package/utils/AnimationEngine.js +428 -0
- package/utils/DataStore.js +403 -0
- package/utils/EventBus.js +407 -0
- package/utils/FetchClient.js +74 -0
- package/utils/FormValidator.js +355 -0
- package/utils/GeoLocationService.js +62 -0
- package/utils/I18n.js +207 -0
- package/utils/IndexedDBManager.js +273 -0
- package/utils/OfflineSyncManager.js +342 -0
- package/utils/QueryBuilder.js +478 -0
- package/utils/SafeArea.js +64 -0
- package/utils/SecureStorage.js +289 -0
- package/utils/StateManager.js +207 -0
- package/utils/WebSocketClient.js +66 -0
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bus d'événements pour communication entre composants
|
|
3
|
+
* Pattern: Publish/Subscribe (Pub/Sub)
|
|
4
|
+
* @class
|
|
5
|
+
* @property {Map} events - Événements enregistrés
|
|
6
|
+
* @property {Array} history - Historique des événements
|
|
7
|
+
* @property {boolean} enableHistory - Activer l'historique
|
|
8
|
+
* @property {number} maxHistory - Taille max de l'historique
|
|
9
|
+
*/
|
|
10
|
+
class EventBus {
|
|
11
|
+
/**
|
|
12
|
+
* Crée une instance de EventBus
|
|
13
|
+
* @param {Object} [options={}] - Options
|
|
14
|
+
* @param {boolean} [options.enableHistory=false] - Activer l'historique
|
|
15
|
+
* @param {number} [options.maxHistory=100] - Taille max historique
|
|
16
|
+
* @param {boolean} [options.enableWildcard=true] - Activer wildcards
|
|
17
|
+
*/
|
|
18
|
+
constructor(options = {}) {
|
|
19
|
+
this.events = new Map();
|
|
20
|
+
this.history = [];
|
|
21
|
+
this.enableHistory = options.enableHistory || false;
|
|
22
|
+
this.maxHistory = options.maxHistory || 100;
|
|
23
|
+
this.enableWildcard = options.enableWildcard !== false;
|
|
24
|
+
this.middlewares = [];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Souscrit à un événement
|
|
29
|
+
* @param {string} event - Nom de l'événement
|
|
30
|
+
* @param {Function} callback - Fonction callback
|
|
31
|
+
* @param {Object} [options={}] - Options
|
|
32
|
+
* @param {boolean} [options.once=false] - Exécuter une seule fois
|
|
33
|
+
* @param {number} [options.priority=0] - Priorité (plus haut = exécuté avant)
|
|
34
|
+
* @returns {Function} Fonction de désinscription
|
|
35
|
+
*/
|
|
36
|
+
on(event, callback, options = {}) {
|
|
37
|
+
if (typeof callback !== 'function') {
|
|
38
|
+
throw new Error('Callback must be a function');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!this.events.has(event)) {
|
|
42
|
+
this.events.set(event, []);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const listener = {
|
|
46
|
+
callback,
|
|
47
|
+
once: options.once || false,
|
|
48
|
+
priority: options.priority || 0,
|
|
49
|
+
id: this.generateId()
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const listeners = this.events.get(event);
|
|
53
|
+
listeners.push(listener);
|
|
54
|
+
|
|
55
|
+
// Trier par priorité (descendant)
|
|
56
|
+
listeners.sort((a, b) => b.priority - a.priority);
|
|
57
|
+
|
|
58
|
+
// Retourner une fonction de désinscription
|
|
59
|
+
return () => this.off(event, listener.id);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Souscrit à un événement (une seule fois)
|
|
64
|
+
* @param {string} event - Nom de l'événement
|
|
65
|
+
* @param {Function} callback - Fonction callback
|
|
66
|
+
* @param {Object} [options={}] - Options
|
|
67
|
+
* @returns {Function} Fonction de désinscription
|
|
68
|
+
*/
|
|
69
|
+
once(event, callback, options = {}) {
|
|
70
|
+
return this.on(event, callback, { ...options, once: true });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Se désinscrit d'un événement
|
|
75
|
+
* @param {string} event - Nom de l'événement
|
|
76
|
+
* @param {string|Function} [callbackOrId] - Callback ou ID du listener
|
|
77
|
+
* @returns {boolean} True si désabonné
|
|
78
|
+
*/
|
|
79
|
+
off(event, callbackOrId) {
|
|
80
|
+
const listeners = this.events.get(event);
|
|
81
|
+
|
|
82
|
+
if (!listeners) return false;
|
|
83
|
+
|
|
84
|
+
if (!callbackOrId) {
|
|
85
|
+
// Supprimer tous les listeners de cet événement
|
|
86
|
+
this.events.delete(event);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const index = listeners.findIndex(listener =>
|
|
91
|
+
listener.callback === callbackOrId || listener.id === callbackOrId
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
if (index > -1) {
|
|
95
|
+
listeners.splice(index, 1);
|
|
96
|
+
|
|
97
|
+
// Supprimer l'événement s'il n'y a plus de listeners
|
|
98
|
+
if (listeners.length === 0) {
|
|
99
|
+
this.events.delete(event);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Émet un événement
|
|
110
|
+
* @param {string} event - Nom de l'événement
|
|
111
|
+
* @param {...*} args - Arguments à passer
|
|
112
|
+
* @returns {number} Nombre de listeners exécutés
|
|
113
|
+
*/
|
|
114
|
+
emit(event, ...args) {
|
|
115
|
+
// Historique
|
|
116
|
+
if (this.enableHistory) {
|
|
117
|
+
this.addToHistory(event, args);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Middlewares
|
|
121
|
+
let shouldContinue = true;
|
|
122
|
+
for (let middleware of this.middlewares) {
|
|
123
|
+
const result = middleware(event, args);
|
|
124
|
+
if (result === false) {
|
|
125
|
+
shouldContinue = false;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!shouldContinue) return 0;
|
|
131
|
+
|
|
132
|
+
let count = 0;
|
|
133
|
+
|
|
134
|
+
// Listeners exacts
|
|
135
|
+
const listeners = this.events.get(event);
|
|
136
|
+
if (listeners) {
|
|
137
|
+
count += this.executeListeners(listeners, event, args);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Wildcards (si activé)
|
|
141
|
+
if (this.enableWildcard) {
|
|
142
|
+
count += this.emitWildcard(event, args);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return count;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Émet un événement avec wildcard
|
|
150
|
+
* @param {string} event - Nom de l'événement
|
|
151
|
+
* @param {Array} args - Arguments
|
|
152
|
+
* @returns {number} Nombre de listeners exécutés
|
|
153
|
+
* @private
|
|
154
|
+
*/
|
|
155
|
+
emitWildcard(event, args) {
|
|
156
|
+
let count = 0;
|
|
157
|
+
|
|
158
|
+
for (let [eventPattern, listeners] of this.events.entries()) {
|
|
159
|
+
if (eventPattern.includes('*')) {
|
|
160
|
+
if (this.matchWildcard(event, eventPattern)) {
|
|
161
|
+
count += this.executeListeners(listeners, event, args);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return count;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Vérifie si un événement match un pattern wildcard
|
|
171
|
+
* @param {string} event - Événement
|
|
172
|
+
* @param {string} pattern - Pattern avec *
|
|
173
|
+
* @returns {boolean} True si match
|
|
174
|
+
* @private
|
|
175
|
+
*/
|
|
176
|
+
matchWildcard(event, pattern) {
|
|
177
|
+
const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
|
|
178
|
+
return regex.test(event);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Exécute les listeners
|
|
183
|
+
* @param {Array} listeners - Liste des listeners
|
|
184
|
+
* @param {string} event - Nom de l'événement
|
|
185
|
+
* @param {Array} args - Arguments
|
|
186
|
+
* @returns {number} Nombre de listeners exécutés
|
|
187
|
+
* @private
|
|
188
|
+
*/
|
|
189
|
+
executeListeners(listeners, event, args) {
|
|
190
|
+
let count = 0;
|
|
191
|
+
const toRemove = [];
|
|
192
|
+
|
|
193
|
+
for (let listener of listeners) {
|
|
194
|
+
try {
|
|
195
|
+
listener.callback(...args);
|
|
196
|
+
count++;
|
|
197
|
+
|
|
198
|
+
if (listener.once) {
|
|
199
|
+
toRemove.push(listener.id);
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error(`Error in event listener for "${event}":`, error);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Supprimer les listeners "once"
|
|
207
|
+
for (let id of toRemove) {
|
|
208
|
+
this.off(event, id);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return count;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Émet un événement de manière asynchrone
|
|
216
|
+
* @param {string} event - Nom de l'événement
|
|
217
|
+
* @param {...*} args - Arguments
|
|
218
|
+
* @returns {Promise<number>} Nombre de listeners exécutés
|
|
219
|
+
*/
|
|
220
|
+
async emitAsync(event, ...args) {
|
|
221
|
+
if (this.enableHistory) {
|
|
222
|
+
this.addToHistory(event, args);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
let count = 0;
|
|
226
|
+
const listeners = this.events.get(event);
|
|
227
|
+
|
|
228
|
+
if (listeners) {
|
|
229
|
+
for (let listener of listeners) {
|
|
230
|
+
try {
|
|
231
|
+
await listener.callback(...args);
|
|
232
|
+
count++;
|
|
233
|
+
|
|
234
|
+
if (listener.once) {
|
|
235
|
+
this.off(event, listener.id);
|
|
236
|
+
}
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.error(`Error in async event listener for "${event}":`, error);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return count;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Attend qu'un événement soit émis
|
|
248
|
+
* @param {string} event - Nom de l'événement
|
|
249
|
+
* @param {number} [timeout=0] - Timeout en ms (0 = infini)
|
|
250
|
+
* @returns {Promise} Promise qui se résout avec les args
|
|
251
|
+
*/
|
|
252
|
+
waitFor(event, timeout = 0) {
|
|
253
|
+
return new Promise((resolve, reject) => {
|
|
254
|
+
let timeoutId;
|
|
255
|
+
|
|
256
|
+
const unsubscribe = this.once(event, (...args) => {
|
|
257
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
258
|
+
resolve(args);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
if (timeout > 0) {
|
|
262
|
+
timeoutId = setTimeout(() => {
|
|
263
|
+
unsubscribe();
|
|
264
|
+
reject(new Error(`Timeout waiting for event "${event}"`));
|
|
265
|
+
}, timeout);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Ajoute un middleware
|
|
272
|
+
* @param {Function} middleware - Fonction middleware (event, args) => boolean
|
|
273
|
+
*/
|
|
274
|
+
use(middleware) {
|
|
275
|
+
if (typeof middleware !== 'function') {
|
|
276
|
+
throw new Error('Middleware must be a function');
|
|
277
|
+
}
|
|
278
|
+
this.middlewares.push(middleware);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Supprime un middleware
|
|
283
|
+
* @param {Function} middleware - Middleware à supprimer
|
|
284
|
+
*/
|
|
285
|
+
removeMiddleware(middleware) {
|
|
286
|
+
const index = this.middlewares.indexOf(middleware);
|
|
287
|
+
if (index > -1) {
|
|
288
|
+
this.middlewares.splice(index, 1);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Obtient tous les événements enregistrés
|
|
294
|
+
* @returns {Array<string>} Liste des événements
|
|
295
|
+
*/
|
|
296
|
+
eventNames() {
|
|
297
|
+
return Array.from(this.events.keys());
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Obtient le nombre de listeners pour un événement
|
|
302
|
+
* @param {string} event - Nom de l'événement
|
|
303
|
+
* @returns {number} Nombre de listeners
|
|
304
|
+
*/
|
|
305
|
+
listenerCount(event) {
|
|
306
|
+
const listeners = this.events.get(event);
|
|
307
|
+
return listeners ? listeners.length : 0;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Supprime tous les listeners
|
|
312
|
+
*/
|
|
313
|
+
clear() {
|
|
314
|
+
this.events.clear();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Ajoute à l'historique
|
|
319
|
+
* @param {string} event - Événement
|
|
320
|
+
* @param {Array} args - Arguments
|
|
321
|
+
* @private
|
|
322
|
+
*/
|
|
323
|
+
addToHistory(event, args) {
|
|
324
|
+
this.history.push({
|
|
325
|
+
event,
|
|
326
|
+
args,
|
|
327
|
+
timestamp: Date.now()
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// Limiter la taille de l'historique
|
|
331
|
+
if (this.history.length > this.maxHistory) {
|
|
332
|
+
this.history.shift();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Obtient l'historique
|
|
338
|
+
* @param {string} [event] - Filtrer par événement
|
|
339
|
+
* @returns {Array} Historique
|
|
340
|
+
*/
|
|
341
|
+
getHistory(event) {
|
|
342
|
+
if (event) {
|
|
343
|
+
return this.history.filter(item => item.event === event);
|
|
344
|
+
}
|
|
345
|
+
return this.history;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Vide l'historique
|
|
350
|
+
*/
|
|
351
|
+
clearHistory() {
|
|
352
|
+
this.history = [];
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Rejoue l'historique
|
|
357
|
+
* @param {string} [event] - Filtrer par événement
|
|
358
|
+
*/
|
|
359
|
+
replay(event) {
|
|
360
|
+
const items = this.getHistory(event);
|
|
361
|
+
|
|
362
|
+
for (let item of items) {
|
|
363
|
+
this.emit(item.event, ...item.args);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Génère un ID unique
|
|
369
|
+
* @returns {string} ID
|
|
370
|
+
* @private
|
|
371
|
+
*/
|
|
372
|
+
generateId() {
|
|
373
|
+
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Debug: affiche tous les listeners
|
|
378
|
+
*/
|
|
379
|
+
debug() {
|
|
380
|
+
console.log('EventBus Debug:');
|
|
381
|
+
console.log('Events:', this.eventNames());
|
|
382
|
+
|
|
383
|
+
for (let [event, listeners] of this.events.entries()) {
|
|
384
|
+
console.log(` ${event}: ${listeners.length} listener(s)`);
|
|
385
|
+
listeners.forEach((listener, i) => {
|
|
386
|
+
console.log(` [${i}] Priority: ${listener.priority}, Once: ${listener.once}`);
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (this.enableHistory) {
|
|
391
|
+
console.log('History:', this.history.length, 'events');
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Instance globale par défaut
|
|
397
|
+
EventBus.global = new EventBus();
|
|
398
|
+
|
|
399
|
+
// Raccourcis globaux
|
|
400
|
+
EventBus.on = (...args) => EventBus.global.on(...args);
|
|
401
|
+
EventBus.once = (...args) => EventBus.global.once(...args);
|
|
402
|
+
EventBus.off = (...args) => EventBus.global.off(...args);
|
|
403
|
+
EventBus.emit = (...args) => EventBus.global.emit(...args);
|
|
404
|
+
EventBus.emitAsync = (...args) => EventBus.global.emitAsync(...args);
|
|
405
|
+
EventBus.waitFor = (...args) => EventBus.global.waitFor(...args);
|
|
406
|
+
|
|
407
|
+
export default EventBus;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client HTTP avec cache interne TTL
|
|
3
|
+
* @class
|
|
4
|
+
* @property {Map<string, {data:any, expiresAt:number}>} cache - Cache interne
|
|
5
|
+
* @property {Object} defaultHeaders - Headers par défaut
|
|
6
|
+
* @property {number} defaultTTL - TTL par défaut pour le cache (ms)
|
|
7
|
+
*/
|
|
8
|
+
class FetchClient {
|
|
9
|
+
/**
|
|
10
|
+
* Crée une instance de FetchClient
|
|
11
|
+
* @param {Object} [options={}]
|
|
12
|
+
* @param {Object} [options.defaultHeaders] - Headers par défaut
|
|
13
|
+
* @param {number} [options.defaultTTL=0] - TTL par défaut en ms (0 = pas de cache)
|
|
14
|
+
*/
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
this.defaultHeaders = options.defaultHeaders || { 'Content-Type': 'application/json' };
|
|
17
|
+
this.defaultTTL = options.defaultTTL || 0;
|
|
18
|
+
this.cache = new Map();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* GET avec cache TTL optionnel
|
|
23
|
+
* @param {string} url - URL de la requête
|
|
24
|
+
* @param {Object} [options] - Options supplémentaires
|
|
25
|
+
* @param {number} [options.ttl] - TTL pour cette requête (ms)
|
|
26
|
+
* @returns {Promise<any>} - Données JSON
|
|
27
|
+
*/
|
|
28
|
+
async get(url, options = {}) {
|
|
29
|
+
const ttl = options.ttl ?? this.defaultTTL;
|
|
30
|
+
|
|
31
|
+
const cached = this.cache.get(url);
|
|
32
|
+
if (cached && (ttl === 0 || cached.expiresAt > Date.now())) {
|
|
33
|
+
return cached.data;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const res = await fetch(url, { method: 'GET', headers: this.defaultHeaders });
|
|
37
|
+
if (!res.ok) throw new Error(`Fetch error ${res.status}: ${res.statusText}`);
|
|
38
|
+
|
|
39
|
+
const data = await res.json();
|
|
40
|
+
|
|
41
|
+
if (ttl > 0) {
|
|
42
|
+
this.cache.set(url, { data, expiresAt: Date.now() + ttl });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return data;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* POST
|
|
50
|
+
* @param {string} url - URL
|
|
51
|
+
* @param {Object} body - Corps de la requête
|
|
52
|
+
* @param {Object} [options] - Options supplémentaires
|
|
53
|
+
* @param {Object} [options.headers] - Headers supplémentaires
|
|
54
|
+
* @returns {Promise<any>} - Données JSON
|
|
55
|
+
*/
|
|
56
|
+
async post(url, body, options = {}) {
|
|
57
|
+
const res = await fetch(url, {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: { ...this.defaultHeaders, ...(options.headers || {}) },
|
|
60
|
+
body: JSON.stringify(body)
|
|
61
|
+
});
|
|
62
|
+
if (!res.ok) throw new Error(`Fetch error ${res.status}: ${res.statusText}`);
|
|
63
|
+
return res.json();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Vide le cache
|
|
68
|
+
*/
|
|
69
|
+
clearCache() {
|
|
70
|
+
this.cache.clear();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default FetchClient;
|