@arc-js/config-manager 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,608 @@
1
+ # @arc-js/config-manager
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
+ ![React](https://img.shields.io/badge/React-19+-61DAFB)
6
+ ![Vite](https://img.shields.io/badge/Vite-6+-646CFF)
7
+
8
+ **@arc-js/config-manager** est un système de gestion de configuration modulaire pour les applications React avec TypeScript/JavaScript. Il fournit une gestion centralisée des configurations, un chargement dynamique des modules, et une intégration transparente avec les variables d'environnement.
9
+
10
+ ## ✨ Fonctionnalités Principales
11
+
12
+ ### ⚙️ Gestion Modulaire des Configurations
13
+ - **Configurations hiérarchiques** avec fusion intelligente
14
+ - **Chargement dynamique** des fichiers de configuration
15
+ - **Support des modules indépendants** avec isolation
16
+ - **Héritage automatique** de la configuration globale
17
+
18
+ ### 🔌 Intégration Environnement
19
+ - **Variables d'environnement** automatiquement chargées (module `ENV`)
20
+ - **Support Vite et Node.js** (process.env)
21
+ - **Typage fort** pour les configurations
22
+ - **Validation des chemins** avec fallback sécurisé
23
+
24
+ ### 🚀 Performance Optimisée
25
+ - **Chargement paresseux** des configurations
26
+ - **Cache mémoire** pour les accès répétés
27
+ - **Hot reload** pendant le développement
28
+ - **Minimal bundle size**
29
+
30
+ ### 🛡️ Sécurité et Fiabilité
31
+ - **Gestion des erreurs** avec valeurs par défaut
32
+ - **Validation des chemins** avant accès
33
+ - **Logs en mode développement** uniquement
34
+ - **Types TypeScript complets**
35
+
36
+ ## 📦 Installation
37
+
38
+ ```bash
39
+ npm install @arc-js/config-manager
40
+ # ou
41
+ yarn add @arc-js/config-manager
42
+ # ou
43
+ pnpm add @arc-js/config-manager
44
+ ```
45
+
46
+ ### Dépendances requises
47
+ - React 19+
48
+ - TypeScript 5.0+ (recommandé)
49
+ - Vite (pour le chargement dynamique)
50
+
51
+ ## 🚀 Démarrage Rapide
52
+
53
+ ### Structure de projet recommandée
54
+
55
+ ```
56
+ src/
57
+ ├── config.json # Configuration globale
58
+ ├── modules/
59
+ │ ├── admin/
60
+ │ │ └── config.json # Configuration du module admin
61
+ │ ├── dashboard/
62
+ │ │ └── config.json # Configuration du module dashboard
63
+ │ └── api/
64
+ │ └── config.json # Configuration du module API
65
+ └── main.tsx
66
+ ```
67
+
68
+ ### Configuration de base
69
+
70
+ ```json
71
+ // src/config.json (Configuration globale)
72
+ {
73
+ "app": {
74
+ "name": "Mon Application",
75
+ "version": "1.0.0",
76
+ "debug": false,
77
+ "features": {
78
+ "analytics": true,
79
+ "notifications": false
80
+ }
81
+ },
82
+ "api": {
83
+ "baseUrl": "https://api.example.com",
84
+ "timeout": 30000,
85
+ "retryAttempts": 3
86
+ },
87
+ "ui": {
88
+ "theme": "light",
89
+ "language": "fr"
90
+ }
91
+ }
92
+ ```
93
+
94
+ ```json
95
+ // src/modules/admin/config.json (Module admin)
96
+ {
97
+ "app": {
98
+ "name": "Admin Panel", // Écrase le nom global pour ce module
99
+ "debug": true // Surcharge le debug global
100
+ },
101
+ "admin": {
102
+ "permissions": ["users:read", "users:write", "settings:manage"],
103
+ "dashboard": {
104
+ "refreshInterval": 5000,
105
+ "maxItems": 100
106
+ }
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### Utilisation de base
112
+
113
+ ```typescript
114
+ // main.tsx
115
+ import React from 'react';
116
+ import ReactDOM from 'react-dom/client';
117
+ import { ConfigProvider } from '@arc-js/config-manager';
118
+
119
+ const App = () => {
120
+ return (
121
+ <div>
122
+ <h1>Mon Application Configurée</h1>
123
+ </div>
124
+ );
125
+ };
126
+
127
+ ReactDOM.createRoot(document.getElementById('root')!).render(
128
+ <React.StrictMode>
129
+ <ConfigProvider preloadModules={['admin', 'dashboard']}>
130
+ <App />
131
+ </ConfigProvider>
132
+ </React.StrictMode>
133
+ );
134
+ ```
135
+
136
+ ## 📚 Documentation API
137
+
138
+ ### Hook useConfig
139
+
140
+ ```typescript
141
+ import { useConfig } from '@arc-js/config-manager';
142
+
143
+ const MyComponent = () => {
144
+ const config = useConfig('admin'); // Optionnel: nom du module
145
+
146
+ // Récupérer une valeur avec chemin pointé
147
+ const appName = config.get('app.name');
148
+ const apiTimeout = config.get('api.timeout');
149
+
150
+ // Récupérer avec valeur par défaut
151
+ const debugMode = config.get('app.debug', { defaultValue: false });
152
+
153
+ // Récupérer ou lancer une exception si non trouvé
154
+ const baseUrl = config.getOrThrow('api.baseUrl');
155
+
156
+ // Vérifier l'existence d'un chemin
157
+ const hasAnalytics = config.has('app.features.analytics');
158
+
159
+ // Récupérer toutes les configurations
160
+ const allConfigs = config.getAll();
161
+
162
+ // Accès aux variables d'environnement
163
+ const nodeEnv = config.getEnv('NODE_ENV');
164
+ const apiUrl = config.getEnv('apiUrl'); // VITE_API_URL
165
+
166
+ return (
167
+ <div>
168
+ <h1>{appName}</h1>
169
+ <p>API Timeout: {apiTimeout}ms</p>
170
+ <p>Environment: {nodeEnv}</p>
171
+ </div>
172
+ );
173
+ };
174
+ ```
175
+
176
+ ### Hook useConfigValue (Typé)
177
+
178
+ ```typescript
179
+ import { useConfigValue } from '@arc-js/config-manager';
180
+
181
+ const FeatureToggle = () => {
182
+ const { value: isEnabled, isLoading, exists } =
183
+ useConfigValue<boolean>('app.features.analytics', {
184
+ moduleName: 'admin',
185
+ defaultValue: false
186
+ });
187
+
188
+ if (isLoading) return <div>Chargement...</div>;
189
+
190
+ return (
191
+ <div>
192
+ <p>Analytics: {isEnabled ? 'Activé' : 'Désactivé'}</p>
193
+ <p>Configuration existante: {exists ? 'Oui' : 'Non'}</p>
194
+ </div>
195
+ );
196
+ };
197
+ ```
198
+
199
+ ### Modifier une configuration
200
+
201
+ ```typescript
202
+ const SettingsPanel = () => {
203
+ const config = useConfig();
204
+
205
+ const toggleDebug = () => {
206
+ const currentDebug = config.get('app.debug', { defaultValue: false });
207
+ config.set('app.debug', !currentDebug);
208
+ };
209
+
210
+ const updateApiConfig = () => {
211
+ config.merge({
212
+ api: {
213
+ timeout: 60000,
214
+ retryAttempts: 5
215
+ }
216
+ }, 'admin'); // Appliquer uniquement au module admin
217
+ };
218
+
219
+ return (
220
+ <div>
221
+ <button onClick={toggleDebug}>
222
+ Toggle Debug Mode
223
+ </button>
224
+ <button onClick={updateApiConfig}>
225
+ Update API Settings
226
+ </button>
227
+ </div>
228
+ );
229
+ };
230
+ ```
231
+
232
+ ## 🔧 Utilisation Avancée
233
+
234
+ ### Variables d'environnement
235
+
236
+ ```bash
237
+ # .env
238
+ VITE_API_URL=https://api.example.com
239
+ VITE_APP_NAME="My App"
240
+ VITE_DEBUG=true
241
+ NODE_ENV=development
242
+ ```
243
+
244
+ ```typescript
245
+ const EnvironmentInfo = () => {
246
+ const config = useConfig();
247
+
248
+ // Accès aux variables VITE_*
249
+ const apiUrl = config.getEnv('apiUrl'); // VITE_API_URL
250
+ const appName = config.getEnv('appName'); // VITE_APP_NAME
251
+
252
+ // Ou via le module ENV
253
+ const viteApiUrl = config.get('apiUrl', { moduleName: 'ENV' });
254
+
255
+ // Vérifier l'environnement
256
+ const isProd = config.isProduction();
257
+ const isDev = config.isDevelopment();
258
+ const isTest = config.isTest();
259
+
260
+ return (
261
+ <div>
262
+ <h2>Environment Configuration</h2>
263
+ <p>API URL: {apiUrl}</p>
264
+ <p>App Name: {appName}</p>
265
+ <p>Mode: {isProd ? 'Production' : isDev ? 'Development' : 'Test'}</p>
266
+ </div>
267
+ );
268
+ };
269
+ ```
270
+
271
+ ### Configuration hiérarchique complexe
272
+
273
+ ```json
274
+ // src/modules/complex/config.json
275
+ {
276
+ "database": {
277
+ "connections": {
278
+ "primary": {
279
+ "host": "localhost",
280
+ "port": 5432,
281
+ "credentials": {
282
+ "username": "admin",
283
+ "password": "secret"
284
+ },
285
+ "options": {
286
+ "ssl": true,
287
+ "pool": {
288
+ "max": 20,
289
+ "min": 5,
290
+ "idleTimeout": 30000
291
+ }
292
+ }
293
+ },
294
+ "replica": {
295
+ "host": "replica.local",
296
+ "port": 5432
297
+ }
298
+ }
299
+ }
300
+ }
301
+ ```
302
+
303
+ ```typescript
304
+ const DatabaseConfig = () => {
305
+ const config = useConfig('complex');
306
+
307
+ // Accès aux chemins profonds
308
+ const primaryHost = config.get('database.connections.primary.host');
309
+ const poolMax = config.get('database.connections.primary.options.pool.max');
310
+ const sslEnabled = config.get('database.connections.primary.options.ssl');
311
+
312
+ // Utilisation avec tableau de chemin
313
+ const credentials = config.get(['database', 'connections', 'primary', 'credentials']);
314
+
315
+ return (
316
+ <div>
317
+ <h3>Database Configuration</h3>
318
+ <p>Primary Host: {primaryHost}</p>
319
+ <p>Max Pool Connections: {poolMax}</p>
320
+ <p>SSL: {sslEnabled ? 'Enabled' : 'Disabled'}</p>
321
+ <pre>{JSON.stringify(credentials, null, 2)}</pre>
322
+ </div>
323
+ );
324
+ };
325
+ ```
326
+
327
+ ## 🎯 Exemples Complets
328
+
329
+ ### Exemple 1 : Configuration d'API avec fallback
330
+
331
+ ```typescript
332
+ import { useConfig } from '@arc-js/config-manager';
333
+
334
+ const ApiClient = () => {
335
+ const config = useConfig();
336
+
337
+ const getApiConfig = () => {
338
+ // Utiliser l'URL de l'ENV si disponible, sinon la config globale
339
+ const baseUrl = config.getEnv('apiUrl') ||
340
+ config.get('api.baseUrl', {
341
+ defaultValue: 'http://localhost:3000'
342
+ });
343
+
344
+ const timeout = config.get('api.timeout', { defaultValue: 30000 });
345
+ const retryAttempts = config.get('api.retryAttempts', { defaultValue: 3 });
346
+
347
+ return { baseUrl, timeout, retryAttempts };
348
+ };
349
+
350
+ const fetchData = async () => {
351
+ const { baseUrl, timeout } = getApiConfig();
352
+
353
+ try {
354
+ const response = await fetch(`\${baseUrl}/data`, {
355
+ timeout,
356
+ headers: {
357
+ 'Content-Type': 'application/json'
358
+ }
359
+ });
360
+
361
+ return await response.json();
362
+ } catch (error) {
363
+ console.error('API Error:', error);
364
+ throw error;
365
+ }
366
+ };
367
+
368
+ return (
369
+ <div>
370
+ <button onClick={fetchData}>
371
+ Fetch Data
372
+ </button>
373
+ </div>
374
+ );
375
+ };
376
+ ```
377
+
378
+ ### Exemple 2 : Feature flags modulaires
379
+
380
+ ```typescript
381
+ import { useConfigValue } from '@arc-js/config-manager';
382
+
383
+ const FeatureComponent = ({ featureName, moduleName }: {
384
+ featureName: string,
385
+ moduleName?: string
386
+ }) => {
387
+ const { value: isEnabled, isLoading } = useConfigValue<boolean>(
388
+ `features.\${featureName}`,
389
+ {
390
+ moduleName,
391
+ defaultValue: false
392
+ }
393
+ );
394
+
395
+ if (isLoading) return <div>Loading feature...</div>;
396
+ if (!isEnabled) return null;
397
+
398
+ return (
399
+ <div className={`feature \${featureName}`}>
400
+ <h3>Feature: {featureName}</h3>
401
+ {/* Contenu de la feature */}
402
+ </div>
403
+ );
404
+ };
405
+
406
+ // Utilisation
407
+ const AppFeatures = () => {
408
+ return (
409
+ <div>
410
+ <FeatureComponent featureName="analytics" moduleName="admin" />
411
+ <FeatureComponent featureName="darkMode" />
412
+ <FeatureComponent featureName="experimental" moduleName="dashboard" />
413
+ </div>
414
+ );
415
+ };
416
+ ```
417
+
418
+ ### Exemple 3 : Configuration dynamique avec React Query
419
+
420
+ ```typescript
421
+ import { useQuery } from '@tanstack/react-query';
422
+ import { useConfig } from '@arc-js/config-manager';
423
+
424
+ const ConfigBasedQuery = () => {
425
+ const config = useConfig('admin');
426
+
427
+ const { data, isLoading, error } = useQuery({
428
+ queryKey: ['users', 'list'],
429
+ queryFn: async () => {
430
+ const baseUrl = config.getOrThrow('api.baseUrl');
431
+ const pageSize = config.get('pagination.pageSize', { defaultValue: 20 });
432
+
433
+ const response = await fetch(
434
+ `\${baseUrl}/users?limit=\${pageSize}`
435
+ );
436
+
437
+ if (!response.ok) throw new Error('Failed to fetch');
438
+ return response.json();
439
+ },
440
+ // Utiliser la config pour les options de requête
441
+ retry: config.get('api.retryAttempts', { defaultValue: 3 }),
442
+ retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
443
+ enabled: config.get('features.dataFetching', { defaultValue: true })
444
+ });
445
+
446
+ if (isLoading) return <div>Loading...</div>;
447
+ if (error) return <div>Error: {error.message}</div>;
448
+
449
+ return (
450
+ <div>
451
+ <h2>Users</h2>
452
+ <ul>
453
+ {data?.users?.map(user => (
454
+ <li key={user.id}>{user.name}</li>
455
+ ))}
456
+ </ul>
457
+ </div>
458
+ );
459
+ };
460
+ ```
461
+
462
+ ## 🔧 Configuration Avancée
463
+
464
+ ### Configuration Vite
465
+
466
+ ```typescript
467
+ // vite.config.ts
468
+ import { defineConfig } from 'vite';
469
+ import react from '@vitejs/plugin-react';
470
+
471
+ export default defineConfig({
472
+ plugins: [react()],
473
+ define: {
474
+ // Exposer les variables d'environnement
475
+ 'import.meta.env': process.env
476
+ }
477
+ });
478
+ ```
479
+
480
+ ### Configuration TypeScript
481
+
482
+ ```json
483
+ {
484
+ "compilerOptions": {
485
+ "target": "ES2020",
486
+ "lib": ["DOM", "DOM.Iterable", "ES2020"],
487
+ "module": "ESNext",
488
+ "moduleResolution": "bundler",
489
+ "allowImportingTsExtensions": true,
490
+ "resolveJsonModule": true,
491
+ "isolatedModules": true,
492
+ "noEmit": true,
493
+ "jsx": "react-jsx",
494
+ "strict": true,
495
+ "types": ["vite/client"]
496
+ },
497
+ "include": ["src", "node_modules/@arc-js/config-manager/**/*"]
498
+ }
499
+ ```
500
+
501
+ ### Scripts de validation
502
+
503
+ ```json
504
+ {
505
+ "scripts": {
506
+ "validate-config": "node scripts/validate-config.js",
507
+ "generate-config-schema": "node scripts/generate-schema.js",
508
+ "check-env": "node scripts/check-environment.js"
509
+ }
510
+ }
511
+ ```
512
+
513
+ ## 📋 Table des Conventions
514
+
515
+ ### Chemins de configuration
516
+
517
+ | Type | Format | Exemple |
518
+ |------|--------|---------|
519
+ | Pointé | `parent.child.grandchild` | `app.features.analytics` |
520
+ | Tableau | `['parent', 'child', 'grandchild']` | `['api', 'baseUrl']` |
521
+ | Mixte | Supporté | `app.features[0].name` |
522
+
523
+ ### Fichiers de configuration
524
+
525
+ | Chemin | Portée | Priorité |
526
+ |--------|--------|----------|
527
+ | `src/config.json` | Globale | Base |
528
+ | `src/modules/*/config.json` | Module | Écrase la globale |
529
+ | `.env` / Variables | Environnement | Écrase tout |
530
+
531
+ ### Variables d'environnement
532
+
533
+ | Variable | Conversion | Accès |
534
+ |----------|------------|-------|
535
+ | `VITE_API_URL` | `apiUrl` | `config.getEnv('apiUrl')` |
536
+ | `VITE_APP_NAME` | `appName` | `config.get('appName', {moduleName: 'ENV'})` |
537
+ | `NODE_ENV` | `nodeEnv` | `config.getEnv('NODE_ENV')` |
538
+
539
+ ## 🛡️ Gestion des Erreurs
540
+
541
+ ### Fallback et validation
542
+
543
+ ```typescript
544
+ const SafeConfigAccess = () => {
545
+ const config = useConfig();
546
+
547
+ try {
548
+ // Cette méthode lève une exception si le chemin n'existe pas
549
+ const requiredValue = config.getOrThrow('required.path', 'admin');
550
+
551
+ return (
552
+ <div>
553
+ <p>Value: {requiredValue}</p>
554
+ </div>
555
+ );
556
+ } catch (error) {
557
+ return (
558
+ <div className="error">
559
+ <p>Configuration error: {(error as Error).message}</p>
560
+ <p>Using fallback configuration...</p>
561
+ </div>
562
+ );
563
+ }
564
+ };
565
+ ```
566
+
567
+ ### Logs en développement
568
+
569
+ ```typescript
570
+ // Le service loggue automatiquement en mode développement
571
+ const DebugConfig = () => {
572
+ const config = useConfig();
573
+ const isDev = config.isDevelopment();
574
+
575
+ if (isDev) {
576
+ // Afficher toute la configuration en dev
577
+ console.log('Current Configuration:', config.getAll());
578
+
579
+ // Vérifier les chemins manquants
580
+ const missingPaths = ['app.name', 'api.baseUrl', 'unknown.path'];
581
+ missingPaths.forEach(path => {
582
+ if (!config.has(path)) {
583
+ console.warn(`Missing config path: \${path}`);
584
+ }
585
+ });
586
+ }
587
+
588
+ return null;
589
+ };
590
+ ```
591
+
592
+ ## 📄 Licence
593
+
594
+ MIT License - Voir le fichier [LICENSE](LICENSE) pour plus de détails.
595
+
596
+ ## 🐛 Signaler un Bug
597
+
598
+ Envoyez-nous un mail à l'adresse `contact.inicode@gmail.com` pour :
599
+ - Signaler un bug
600
+ - Proposer une amélioration
601
+ - Poser une question sur l'utilisation
602
+ - Demander une nouvelle fonctionnalité
603
+
604
+ ---
605
+
606
+ **@arc-js/config-manager** - Le système de configuration modulaire pour React et TypeScript.
607
+
608
+ *Développé par l'équipe INICODE*
package/config.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ declare const DEFAULT_LOCALE = "en";
2
+ declare const SUPPORTED_LOCALES: string[];
3
+ declare const COOKIE_NAME = "app_locale";
4
+ type Locale = typeof SUPPORTED_LOCALES[number];
5
+ declare const getSavedLocale: (supportedLocales?: string[]) => string;
6
+ declare const saveLocale: (locale: string) => void;
7
+ declare const PATH_CONFIG: {
8
+ SRC_DIR: string;
9
+ };
10
+ declare const SRC_DIR: string;
11
+
12
+ export { COOKIE_NAME, DEFAULT_LOCALE, PATH_CONFIG, SRC_DIR, SUPPORTED_LOCALES, getSavedLocale, saveLocale };
13
+ export type { Locale };