@arc-js/cp-request 0.0.1

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 ADDED
@@ -0,0 +1,700 @@
1
+ # @arc-js/cp-request
2
+
3
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4
+ ![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-007ACC)
5
+ ![Browser](https://img.shields.io/badge/browser-compatible-green)
6
+ ![Node.js](https://img.shields.io/badge/Node.js-18+-339933)
7
+
8
+ **@arc-js/cp-request** est une bibliothèque TypeScript complète pour gérer les requêtes HTTP et WebSocket avec une API unifiée et type-safe. Elle offre une solution robuste pour les communications client-serveur avec gestion automatique des erreurs, validation des schémas et support multi-langue.
9
+
10
+ ## ✨ Fonctionnalités Principales
11
+
12
+ ### 🌐 HTTP Request (HttpRequest)
13
+ - **Méthodes HTTP complètes** : GET, POST, PUT, DELETE
14
+ - **Gestion intelligente des erreurs** : mapping automatique des codes HTTP vers des types de notification
15
+ - **Validation de schéma** : intégration avec JON pour la validation des données
16
+ - **Support multi-langue** : messages d'erreur en français et anglais
17
+ - **Authentification** : support Basic Auth
18
+ - **Types de réponse** : JSON, text, arraybuffer, blob
19
+ - **Intercepteurs** : actions personnalisées pour succès/erreur
20
+
21
+ ### 🔌 WebSocket Request (WsRequest)
22
+ - **Connexion WebSocket managée** : avec reconnexion automatique
23
+ - **File d'attente de messages** : messages stockés si non connecté
24
+ - **API unifiée** : même interface que HttpRequest pour la cohérence
25
+ - **Gestion d'état** : suivi de la connexion et tentatives de reconnexion
26
+ - **Validation des messages** : schémas JON pour les données entrantes
27
+
28
+ ### 🛡️ Sécurité & Fiabilité
29
+ - **Validation stricte** : des paramètres d'entrée
30
+ - **Gestion des timeouts** : configuration flexible
31
+ - **Protection contre les erreurs** : fallbacks et valeurs par défaut
32
+ - **Logs détaillés** : en mode développement seulement
33
+
34
+ ## 📦 Installation
35
+
36
+ ### Via npm/yarn/pnpm
37
+
38
+ ```bash
39
+ npm install @arc-js/cp-request
40
+ # ou
41
+ yarn add @arc-js/cp-request
42
+ # ou
43
+ pnpm add @arc-js/cp-request
44
+ ```
45
+
46
+ ### Importation directe (CDN)
47
+
48
+ ```html
49
+ <script src="@arc-js/cp-request/cp-request.all.js"></script>
50
+ ```
51
+
52
+ ## 🚀 Démarrage Rapide
53
+
54
+ ### TypeScript/ES Modules
55
+
56
+ ```typescript
57
+ import { HttpRequest, WsRequest } from '@arc-js/cp-request';
58
+ // ou
59
+ import CPRequest from '@arc-js/cp-request';
60
+ ```
61
+
62
+ ### CommonJS
63
+
64
+ ```javascript
65
+ const { HttpRequest, WsRequest } = require('@arc-js/cp-request');
66
+ ```
67
+
68
+ ### Navigateur (global)
69
+
70
+ ```html
71
+ <script src="@arc-js/cp-request/cp-request.all.js"></script>
72
+ <script>
73
+ // Disponible globalement
74
+ const httpRequest = new HttpRequest();
75
+ const wsRequest = new WsRequest();
76
+ </script>
77
+ ```
78
+
79
+ ## 📚 Documentation API
80
+
81
+ ### Configuration Initiale
82
+
83
+ ```typescript
84
+ // Configuration de base
85
+ const httpRequest = new HttpRequest()
86
+ .initConfig('http://api.example.com', 'fr');
87
+
88
+ const wsRequest = new WsRequest()
89
+ .initConfig('wss://ws.example.com', 'en');
90
+ ```
91
+
92
+ ### Interface HTTPRequestParams
93
+
94
+ ```typescript
95
+ interface HTTPRequestParams {
96
+ method: "GET" | "POST" | "PUT" | "DELETE";
97
+ path: string;
98
+ headers?: Record<string, string>;
99
+ params?: Record<string, any>;
100
+ body?: any;
101
+ responseType?: "json" | "arraybuffer" | "blob" | "text";
102
+ auth?: {
103
+ username: string;
104
+ password: string;
105
+ };
106
+ }
107
+ ```
108
+
109
+ ### Interface WSRequestParams
110
+
111
+ ```typescript
112
+ interface WSRequestParams {
113
+ path: string;
114
+ headers?: Record<string, string>;
115
+ auth?: {
116
+ username: string;
117
+ password: string;
118
+ };
119
+ autoReconnect?: boolean;
120
+ reconnectDelay?: number;
121
+ maxReconnectAttempts?: number;
122
+ }
123
+ ```
124
+
125
+ ### Réponse Standardisée
126
+
127
+ ```typescript
128
+ interface HTTPRequestResponse {
129
+ response: {
130
+ code: number;
131
+ type: string; // "success", "error", "warning", "info", "error_auth", "error_auth_required"
132
+ message: any;
133
+ };
134
+ data: any;
135
+ error?: any;
136
+ errors?: any[];
137
+ }
138
+ ```
139
+
140
+ ## 🔧 Utilisation Détaillée
141
+
142
+ ### Requêtes HTTP
143
+
144
+ #### Récupérer plusieurs éléments (findAllRequests)
145
+
146
+ ```typescript
147
+ const httpRequest = new HttpRequest()
148
+ .initConfig('http://api.example.com', 'fr');
149
+
150
+ httpRequest.findAllRequests(
151
+ {
152
+ method: 'GET',
153
+ path: '/users',
154
+ headers: {
155
+ 'Content-Type': 'application/json',
156
+ 'Authorization': 'Bearer token'
157
+ },
158
+ params: {
159
+ page: 1,
160
+ limit: 20,
161
+ sort: 'name'
162
+ }
163
+ },
164
+ {}, // otherParams
165
+ (response) => {
166
+ console.log('Succès:', response.data); // Tableau d'utilisateurs
167
+ },
168
+ (response) => {
169
+ console.error('Erreur:', response.error);
170
+ }
171
+ );
172
+ ```
173
+
174
+ #### Récupérer un seul élément (findOneRequest)
175
+
176
+ ```typescript
177
+ httpRequest.findOneRequest(
178
+ {
179
+ method: 'GET',
180
+ path: '/users/123'
181
+ },
182
+ {},
183
+ (response) => {
184
+ console.log('Utilisateur:', response.data);
185
+ },
186
+ (response) => {
187
+ console.error('Erreur:', response.errors);
188
+ }
189
+ );
190
+ ```
191
+
192
+ #### Créer une ressource (POST)
193
+
194
+ ```typescript
195
+ httpRequest.findOneRequest(
196
+ {
197
+ method: 'POST',
198
+ path: '/users',
199
+ body: {
200
+ name: 'John Doe',
201
+ email: 'john@example.com'
202
+ }
203
+ },
204
+ {},
205
+ (response) => {
206
+ console.log('Créé avec succès:', response.data);
207
+ }
208
+ );
209
+ ```
210
+
211
+ #### Authentification Basic
212
+
213
+ ```typescript
214
+ httpRequest.findAllRequests(
215
+ {
216
+ method: 'GET',
217
+ path: '/secure-data',
218
+ auth: {
219
+ username: 'admin',
220
+ password: 'secret123'
221
+ }
222
+ }
223
+ );
224
+ ```
225
+
226
+ ### WebSocket
227
+
228
+ #### Connexion WebSocket
229
+
230
+ ```typescript
231
+ const wsRequest = new WsRequest()
232
+ .initConfig('wss://ws.example.com', 'fr');
233
+
234
+ wsRequest.connect({
235
+ path: '/socket',
236
+ autoReconnect: true,
237
+ reconnectDelay: 3000,
238
+ maxReconnectAttempts: 5
239
+ });
240
+ ```
241
+
242
+ #### Envoyer et recevoir des messages
243
+
244
+ ```typescript
245
+ // Récupérer plusieurs éléments via WebSocket
246
+ wsRequest.findAllMessages(
247
+ {
248
+ action: 'GET_USERS',
249
+ filters: { active: true }
250
+ },
251
+ (response) => {
252
+ console.log('Utilisateurs actifs:', response.data);
253
+ },
254
+ (response) => {
255
+ console.error('Erreur WebSocket:', response.error);
256
+ }
257
+ );
258
+
259
+ // Récupérer un élément spécifique
260
+ wsRequest.findOneMessage(
261
+ {
262
+ action: 'GET_USER',
263
+ id: 456
264
+ },
265
+ (response) => {
266
+ console.log('Utilisateur:', response.data);
267
+ }
268
+ );
269
+ ```
270
+
271
+ #### Gestion de la file d'attente
272
+
273
+ Les messages sont automatiquement mis en file d'attente si la connexion WebSocket n'est pas encore établie et envoyés une fois la connexion rétablie.
274
+
275
+ ### Actions Personnalisées
276
+
277
+ #### Custom Map Actions
278
+
279
+ ```typescript
280
+ const customMapAction: HttpRequestMapAction = (
281
+ code,
282
+ type,
283
+ message,
284
+ data,
285
+ cleanedData,
286
+ error,
287
+ errors
288
+ ) => {
289
+ // Logique personnalisée de transformation
290
+ return {
291
+ response: { code, type, message },
292
+ data: cleanedData ? cleanedData.processed : null,
293
+ metadata: { timestamp: new Date().toISOString() },
294
+ error,
295
+ errors
296
+ };
297
+ };
298
+
299
+ httpRequest.findAllRequests(
300
+ { method: 'GET', path: '/data' },
301
+ {},
302
+ new JON.Object('fr'), // schéma
303
+ customMapAction, // mapAction personnalisée
304
+ undefined, // errMapAction (par défaut)
305
+ undefined, // successAction (par défaut)
306
+ undefined // errorAction (par défaut)
307
+ );
308
+ ```
309
+
310
+ #### Custom Success/Error Actions
311
+
312
+ ```typescript
313
+ const successAction: HttpRequestReponseAction = async (response) => {
314
+ // Enregistrer dans l'historique
315
+ await logToDatabase({
316
+ type: 'request_success',
317
+ code: response.response.code,
318
+ data: response.data
319
+ });
320
+
321
+ // Afficher une notification
322
+ showNotification('Succès', response.response.message);
323
+ };
324
+
325
+ const errorAction: HttpRequestReponseAction = (response) => {
326
+ // Journaliser l'erreur
327
+ console.error('Request failed:', response);
328
+
329
+ // Afficher un message d'erreur
330
+ alert(`Erreur \${response.response.code}: \${response.response.message}`);
331
+ };
332
+ ```
333
+
334
+ ## 🎯 Exemples Complets
335
+
336
+ ### Exemple 1 : Application avec Authentification
337
+
338
+ ```typescript
339
+ class ApiService {
340
+ private http: HttpRequest;
341
+
342
+ constructor(baseUrl: string, lang: 'fr' | 'en' = 'fr') {
343
+ this.http = new HttpRequest().initConfig(baseUrl, lang);
344
+ }
345
+
346
+ async login(email: string, password: string) {
347
+ return this.http.findOneRequest(
348
+ {
349
+ method: 'POST',
350
+ path: '/auth/login',
351
+ body: { email, password }
352
+ },
353
+ {},
354
+ (response) => {
355
+ // Stocker le token
356
+ localStorage.setItem('token', response.data.token);
357
+
358
+ // Rediriger
359
+ window.location.href = '/dashboard';
360
+ },
361
+ (response) => {
362
+ // Afficher l'erreur
363
+ alert(`Échec de connexion: \${response.response.message}`);
364
+ }
365
+ );
366
+ }
367
+
368
+ async getProfile() {
369
+ const token = localStorage.getItem('token');
370
+
371
+ return this.http.findOneRequest(
372
+ {
373
+ method: 'GET',
374
+ path: '/profile',
375
+ headers: {
376
+ 'Authorization': `Bearer \${token}`
377
+ }
378
+ }
379
+ );
380
+ }
381
+ }
382
+ ```
383
+
384
+ ### Exemple 2 : Chat en Temps Réel
385
+
386
+ ```typescript
387
+ class ChatService {
388
+ private ws: WsRequest;
389
+ private messageHandlers: ((message: any) => void)[] = [];
390
+
391
+ constructor(wsUrl: string) {
392
+ this.ws = new WsRequest().initConfig(wsUrl, 'fr');
393
+
394
+ this.ws.connect({
395
+ path: '/chat',
396
+ autoReconnect: true,
397
+ reconnectDelay: 2000
398
+ });
399
+ }
400
+
401
+ async sendMessage(roomId: string, content: string) {
402
+ return this.ws.findOneMessage(
403
+ {
404
+ action: 'SEND_MESSAGE',
405
+ roomId,
406
+ content,
407
+ timestamp: Date.now()
408
+ },
409
+ (response) => {
410
+ console.log('Message envoyé:', response.data);
411
+ },
412
+ (response) => {
413
+ console.error('Erreur d\'envoi:', response.error);
414
+ }
415
+ );
416
+ }
417
+
418
+ async getMessages(roomId: string, limit = 50) {
419
+ return this.ws.findAllMessages(
420
+ {
421
+ action: 'GET_MESSAGES',
422
+ roomId,
423
+ limit
424
+ },
425
+ (response) => {
426
+ // Traiter les messages
427
+ response.data.forEach(message => {
428
+ this.messageHandlers.forEach(handler => handler(message));
429
+ });
430
+ }
431
+ );
432
+ }
433
+
434
+ onMessage(handler: (message: any) => void) {
435
+ this.messageHandlers.push(handler);
436
+ }
437
+ }
438
+ ```
439
+
440
+ ### Exemple 3 : Upload de Fichiers
441
+
442
+ ```typescript
443
+ async uploadFile(file: File, onProgress?: (progress: number) => void) {
444
+ const formData = new FormData();
445
+ formData.append('file', file);
446
+ formData.append('metadata', JSON.stringify({
447
+ name: file.name,
448
+ type: file.type,
449
+ size: file.size
450
+ }));
451
+
452
+ return this.http.findOneRequest(
453
+ {
454
+ method: 'POST',
455
+ path: '/upload',
456
+ body: formData,
457
+ // Pas de Content-Type pour FormData, le navigateur le définit automatiquement
458
+ },
459
+ {
460
+ // Configuration fetch supplémentaire
461
+ onUploadProgress: (progressEvent) => {
462
+ if (onProgress) {
463
+ const percent = (progressEvent.loaded / progressEvent.total) * 100;
464
+ onProgress(percent);
465
+ }
466
+ }
467
+ },
468
+ (response) => {
469
+ console.log('Fichier uploadé:', response.data);
470
+ showNotification('Succès', 'Fichier uploadé avec succès');
471
+ },
472
+ (response) => {
473
+ console.error('Échec upload:', response.error);
474
+ showNotification('Erreur', 'Échec de l\'upload du fichier');
475
+ }
476
+ );
477
+ }
478
+ ```
479
+
480
+ ## 🔧 Configuration Avancée
481
+
482
+ ### Types de Notification Personnalisés
483
+
484
+ ```typescript
485
+ import { getNotifRequestType } from '@arc-js/cp-request';
486
+
487
+ // Étendre les types de notification
488
+ function customGetNotifRequestType(status: number): string {
489
+ const baseType = getNotifRequestType(status);
490
+
491
+ // Ajouter des types personnalisés
492
+ if (status === 429) {
493
+ return 'rate_limit';
494
+ }
495
+ if (status === 503) {
496
+ return 'maintenance';
497
+ }
498
+
499
+ return baseType;
500
+ }
501
+ ```
502
+
503
+ ### Schémas de Validation Personnalisés
504
+
505
+ ```typescript
506
+ import JON from '@arc-js/jon';
507
+
508
+ // Créer un schéma de validation personnalisé
509
+ const userSchema = new JON.Object('fr').struct({
510
+ id: new JON.Number('fr').required(),
511
+ name: new JON.String('fr').min(2).max(100).required(),
512
+ email: new JON.String('fr').email().required(),
513
+ age: new JON.Number('fr').min(0).max(150),
514
+ roles: new JON.Array('fr').types(
515
+ new JON.Enum('fr').choices('admin', 'user', 'guest')
516
+ ).default(['user'])
517
+ });
518
+
519
+ // Utiliser le schéma dans une requête
520
+ httpRequest.findOneRequest(
521
+ { method: 'GET', path: '/user/123' },
522
+ {},
523
+ userSchema, // Schéma personnalisé
524
+ // ... autres paramètres
525
+ );
526
+ ```
527
+
528
+ ### Middleware et Intercepteurs
529
+
530
+ ```typescript
531
+ class RequestLogger {
532
+ static async logRequest(urlParams: HTTPRequestParams) {
533
+ console.log('[REQUEST]', {
534
+ timestamp: new Date().toISOString(),
535
+ method: urlParams.method,
536
+ path: urlParams.path,
537
+ hasBody: !!urlParams.body
538
+ });
539
+ }
540
+
541
+ static async logResponse(response: HTTPRequestResponse) {
542
+ console.log('[RESPONSE]', {
543
+ timestamp: new Date().toISOString(),
544
+ code: response.response.code,
545
+ type: response.response.type,
546
+ hasData: !!response.data
547
+ });
548
+ }
549
+ }
550
+
551
+ // Envelopper les méthodes existantes
552
+ const originalFindAllRequests = HttpRequest.prototype.findAllRequests;
553
+ HttpRequest.prototype.findAllRequests = async function(...args) {
554
+ await RequestLogger.logRequest(args[0]);
555
+ const result = await originalFindAllRequests.apply(this, args);
556
+ await RequestLogger.logResponse(result);
557
+ return result;
558
+ };
559
+ ```
560
+
561
+ ## 📋 Table des Codes de Notification
562
+
563
+ | Code HTTP | Type | Description | Action Recommandée |
564
+ |-----------|------|-------------|-------------------|
565
+ | 200 | success | Requête réussie | Traiter les données |
566
+ | 201 | success | Ressource créée | Mettre à jour l'UI |
567
+ | 204 | success | Pas de contenu | Rafraîchir si nécessaire |
568
+ | 400 | error | Mauvaise requête | Corriger les données envoyées |
569
+ | 401 | error_auth_required | Non authentifié | Rediriger vers login |
570
+ | 403 | error_auth | Non autorisé | Vérifier les permissions |
571
+ | 404 | error | Non trouvé | Afficher message d'erreur |
572
+ | 409 | error_auth | Conflit | Résoudre le conflit de données |
573
+ | 419 | error_auth_required | Session expirée | Renouveler la session |
574
+ | 422 | warning | Données invalides | Corriger la validation |
575
+ | 429 | warning | Trop de requêtes | Attendre avant de réessayer |
576
+ | 500 | error | Erreur serveur | Signaler l'administrateur |
577
+ | 503 | error | Service indisponible | Réessayer plus tard |
578
+
579
+ ## 🚨 Gestion des Erreurs
580
+
581
+ ### Erreurs de Réseau
582
+
583
+ ```typescript
584
+ try {
585
+ await httpRequest.findAllRequests({
586
+ method: 'GET',
587
+ path: '/data'
588
+ });
589
+ } catch (error) {
590
+ if (error.message.includes('Failed to fetch')) {
591
+ // Pas de connexion internet
592
+ showOfflineMessage();
593
+ } else if (error.response?.code === 500) {
594
+ // Erreur serveur
595
+ showServerError();
596
+ } else {
597
+ // Erreur inconnue
598
+ console.error('Erreur inattendue:', error);
599
+ }
600
+ }
601
+ ```
602
+
603
+ ### Retry Automatique
604
+
605
+ ```typescript
606
+ async function fetchWithRetry(urlParams, maxRetries = 3) {
607
+ let lastError;
608
+
609
+ for (let i = 0; i < maxRetries; i++) {
610
+ try {
611
+ return await httpRequest.findOneRequest(urlParams);
612
+ } catch (error) {
613
+ lastError = error;
614
+
615
+ // Attendre avant de réessayer (backoff exponentiel)
616
+ await new Promise(resolve =>
617
+ setTimeout(resolve, 1000 * Math.pow(2, i))
618
+ );
619
+ }
620
+ }
621
+
622
+ throw lastError;
623
+ }
624
+ ```
625
+
626
+ ## 🔧 Build et Développement
627
+
628
+ ### Structure du Projet
629
+
630
+ ```
631
+ @arc-js/cp-request/
632
+ ├── cp-request.all.js
633
+ ├── cp-request.all.min.js
634
+ ├── index.d.ts
635
+ ├── index.js
636
+ ├── index.min.d.ts
637
+ ├── index.min.js
638
+ ├── package.json
639
+ ├── tsconfig.json
640
+ └── README.md
641
+ ```
642
+
643
+ ## 📋 Compatibilité
644
+
645
+ ### Navigateurs Supportés
646
+ - Chrome 60+
647
+ - Firefox 55+
648
+ - Safari 12+
649
+ - Edge 79+
650
+ - Opera 47+
651
+
652
+ ### Environnements
653
+ - Node.js 18+
654
+ - Deno 1.30+
655
+ - Bun 1.0+
656
+ - React Native (avec polyfill fetch)
657
+ - Electron
658
+
659
+ ### Dépendances
660
+ - @arc-js/jon (pour la validation)
661
+ - @arc-js/pajo (pour la manipulation de chemins)
662
+ - @arc-js/qust (pour la manipulation de query strings)
663
+ - @arc-js/timez (pour la gestion du temps)
664
+
665
+ ## 🛡️ Meilleures Pratiques
666
+
667
+ ### Sécurité
668
+ 1. **Toujours valider les entrées** : utiliser les schémas JON
669
+ 2. **Ne pas exposer les tokens** : dans les logs de développement
670
+ 3. **Utiliser HTTPS/SSL** : toujours en production
671
+ 4. **Sanitizer les headers** : éviter l'injection de headers
672
+
673
+ ### Performance
674
+ 1. **Réutiliser les instances** : créer une instance par base URL
675
+ 2. **Limiter les requêtes parallèles** : utiliser une file d'attente si nécessaire
676
+ 3. **Mettre en cache** : les réponses statiques
677
+ 4. **Compresser les données** : gzip/brotli pour les bodies volumineux
678
+
679
+ ### Maintenance
680
+ 1. **Centraliser la configuration** : dans un service dédié
681
+ 2. **Logger proprement** : différents niveaux selon l'environnement
682
+ 3. **Versionner les APIs** : dans le path (/api/v1/)
683
+ 4. **Documenter les endpoints** : avec des exemples
684
+
685
+ ## 📄 Licence
686
+
687
+ MIT License - Voir le fichier [LICENSE](LICENSE) pour plus de détails.
688
+
689
+ ## 🐛 Signaler un Bug
690
+
691
+ Envoyez nous un mail à l'adresse `contact.inicode@gmail.com` pour :
692
+ - Signaler un bug
693
+ - Proposer une amélioration
694
+ - Poser une question
695
+
696
+ ---
697
+
698
+ **@arc-js/cp-request** - Une solution complète pour les communications client-serveur.
699
+
700
+ *Développé par l'équipe INICODE*