@arc-js/config-manager 0.0.96 → 0.0.98
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 +445 -237
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,50 +3,51 @@
|
|
|
3
3
|
[](LICENSE)
|
|
4
4
|

|
|
5
5
|

|
|
6
|
-

|
|
7
6
|
|
|
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
|
|
7
|
+
**@arc-js/config-manager** est un système de gestion de configuration modulaire et performant pour les applications React avec TypeScript/JavaScript. Il fournit une gestion avancée des configurations, un chargement dynamique par scope et module, et une intégration transparente avec l'écosystème Arc.
|
|
9
8
|
|
|
10
9
|
## ✨ Fonctionnalités Principales
|
|
11
10
|
|
|
12
|
-
###
|
|
13
|
-
- **
|
|
14
|
-
- **Chargement dynamique** des
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
|
|
18
|
-
###
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
22
|
-
- **
|
|
23
|
-
|
|
24
|
-
###
|
|
25
|
-
- **Chargement paresseux** des
|
|
26
|
-
- **
|
|
11
|
+
### 🌍 Gestion Multi-Scope Avancée
|
|
12
|
+
- **Support de plusieurs scopes** avec persistance automatique
|
|
13
|
+
- **Chargement dynamique** des configurations par scope
|
|
14
|
+
- **Isolation des configurations** entre environnements
|
|
15
|
+
- **Changement à chaud** de scope sans rechargement
|
|
16
|
+
|
|
17
|
+
### 📦 Architecture Modulaire
|
|
18
|
+
- **Configurations par module** avec isolation complète
|
|
19
|
+
- **Chargement à la demande** des configurations de modules
|
|
20
|
+
- **Fusion intelligente** des configurations hiérarchiques
|
|
21
|
+
- **Support des namespaces** pour une organisation claire
|
|
22
|
+
|
|
23
|
+
### ⚡ Performance Optimisée
|
|
24
|
+
- **Chargement paresseux** des fichiers de configuration
|
|
25
|
+
- **Mémoire cache** des configurations chargées
|
|
26
|
+
- **Minimal bundle size** grâce au code splitting
|
|
27
27
|
- **Hot reload** pendant le développement
|
|
28
|
-
- **Minimal bundle size**
|
|
29
28
|
|
|
30
|
-
###
|
|
31
|
-
- **
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
34
|
-
- **
|
|
29
|
+
### 🔧 Intégration Facile
|
|
30
|
+
- **Provider React** simple à configurer
|
|
31
|
+
- **Hooks personnalisés** pour une utilisation intuitive
|
|
32
|
+
- **Compatibilité totale** avec TypeScript
|
|
33
|
+
- **Intégration avec @arc-js/cooks** pour la persistance
|
|
35
34
|
|
|
36
35
|
## 📦 Installation
|
|
37
36
|
|
|
37
|
+
### Via npm/yarn/pnpm
|
|
38
|
+
|
|
38
39
|
```bash
|
|
39
|
-
npm install @arc-js/config-manager
|
|
40
|
+
npm install @arc-js/config-manager @arc-js/cooks react
|
|
40
41
|
# ou
|
|
41
|
-
yarn add @arc-js/config-manager
|
|
42
|
+
yarn add @arc-js/config-manager @arc-js/cooks react
|
|
42
43
|
# ou
|
|
43
|
-
pnpm add @arc-js/config-manager
|
|
44
|
+
pnpm add @arc-js/config-manager @arc-js/cooks react
|
|
44
45
|
```
|
|
45
46
|
|
|
46
47
|
### Dépendances requises
|
|
47
48
|
- React 19+
|
|
49
|
+
- @arc-js/cooks 1.0.0+
|
|
48
50
|
- TypeScript 5.0+ (recommandé)
|
|
49
|
-
- Vite (pour le chargement dynamique)
|
|
50
51
|
|
|
51
52
|
## 🚀 Démarrage Rapide
|
|
52
53
|
|
|
@@ -54,85 +55,91 @@ pnpm add @arc-js/config-manager
|
|
|
54
55
|
|
|
55
56
|
```
|
|
56
57
|
src/
|
|
57
|
-
├──
|
|
58
|
-
├──
|
|
59
|
-
│ ├──
|
|
60
|
-
│ │
|
|
61
|
-
│
|
|
62
|
-
│
|
|
63
|
-
│
|
|
64
|
-
│
|
|
58
|
+
├── configs/
|
|
59
|
+
│ ├── app/
|
|
60
|
+
│ │ ├── development.ts # Config scope development
|
|
61
|
+
│ │ ├── staging.ts # Config scope staging
|
|
62
|
+
│ │ └── production.ts # Config scope production
|
|
63
|
+
│ ├── modules/
|
|
64
|
+
│ │ ├── admin/
|
|
65
|
+
│ │ │ └── config.ts # Configuration du module admin
|
|
66
|
+
│ │ └── dashboard/
|
|
67
|
+
│ │ └── config.ts # Configuration du module dashboard
|
|
65
68
|
└── main.tsx
|
|
66
69
|
```
|
|
67
70
|
|
|
68
71
|
### Configuration de base
|
|
69
72
|
|
|
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
73
|
```typescript
|
|
114
74
|
// main.tsx
|
|
115
75
|
import React from 'react';
|
|
116
76
|
import ReactDOM from 'react-dom/client';
|
|
117
|
-
import {
|
|
77
|
+
import { ArcConfigProvider } from '@arc-js/config-manager';
|
|
118
78
|
|
|
119
79
|
const App = () => {
|
|
120
80
|
return (
|
|
121
81
|
<div>
|
|
122
|
-
<h1>Mon Application
|
|
82
|
+
<h1>Mon Application Configurable</h1>
|
|
83
|
+
{/* Votre contenu ici */}
|
|
123
84
|
</div>
|
|
124
85
|
);
|
|
125
86
|
};
|
|
126
87
|
|
|
127
88
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
128
89
|
<React.StrictMode>
|
|
129
|
-
<
|
|
90
|
+
<ArcConfigProvider
|
|
91
|
+
config={{
|
|
92
|
+
base: {
|
|
93
|
+
development: async () => (await import('./configs/app/development.ts')).default,
|
|
94
|
+
staging: async () => (await import('./configs/app/staging.ts')).default,
|
|
95
|
+
production: async () => (await import('./configs/app/production.ts')).default
|
|
96
|
+
},
|
|
97
|
+
modules: {
|
|
98
|
+
admin: async () => (await import('./configs/modules/admin/config.ts')).default,
|
|
99
|
+
dashboard: async () => (await import('./configs/modules/dashboard/config.ts')).default
|
|
100
|
+
}
|
|
101
|
+
}}
|
|
102
|
+
supportedScopes={['development', 'staging', 'production']}
|
|
103
|
+
>
|
|
130
104
|
<App />
|
|
131
|
-
</
|
|
105
|
+
</ArcConfigProvider>
|
|
132
106
|
</React.StrictMode>
|
|
133
107
|
);
|
|
134
108
|
```
|
|
135
109
|
|
|
110
|
+
### Fichiers de configuration
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// configs/app/development.ts
|
|
114
|
+
export default {
|
|
115
|
+
api: {
|
|
116
|
+
baseUrl: 'https://dev-api.example.com',
|
|
117
|
+
timeout: 5000
|
|
118
|
+
},
|
|
119
|
+
features: {
|
|
120
|
+
analytics: true,
|
|
121
|
+
debug: true
|
|
122
|
+
},
|
|
123
|
+
ui: {
|
|
124
|
+
theme: 'light',
|
|
125
|
+
language: 'en'
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// configs/modules/admin/config.ts
|
|
130
|
+
export default {
|
|
131
|
+
permissions: {
|
|
132
|
+
canEdit: true,
|
|
133
|
+
canDelete: false,
|
|
134
|
+
canCreate: true
|
|
135
|
+
},
|
|
136
|
+
settings: {
|
|
137
|
+
pagination: 20,
|
|
138
|
+
exportFormats: ['csv', 'pdf', 'excel']
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
```
|
|
142
|
+
|
|
136
143
|
## 📚 Documentation API
|
|
137
144
|
|
|
138
145
|
### Hook useConfig
|
|
@@ -141,203 +148,321 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
141
148
|
import { useConfig } from '@arc-js/config-manager';
|
|
142
149
|
|
|
143
150
|
const MyComponent = () => {
|
|
144
|
-
const
|
|
151
|
+
const {
|
|
152
|
+
cf, // Fonction d'accès aux configurations
|
|
153
|
+
changeScope, // Changer le scope actuel
|
|
154
|
+
currentScope, // Scope actuel
|
|
155
|
+
isLoading, // État de chargement
|
|
156
|
+
loadModule // Charger un module spécifique
|
|
157
|
+
} = useConfig('admin'); // Optionnel: nom du module
|
|
158
|
+
|
|
159
|
+
// Exemple d'utilisation
|
|
160
|
+
const handleChangeScope = () => {
|
|
161
|
+
changeScope(currentScope === 'development' ? 'staging' : 'development');
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Accès aux valeurs de configuration
|
|
165
|
+
const apiUrl = cf('api.baseUrl');
|
|
166
|
+
const canEdit = cf('permissions.canEdit', { moduleName: 'admin' });
|
|
145
167
|
|
|
146
|
-
// Récupérer une valeur avec chemin pointé
|
|
147
|
-
const appName = config.cf('app.name');
|
|
148
|
-
const apiTimeout = config.cf('api.timeout');
|
|
149
|
-
|
|
150
|
-
// Récupérer avec valeur par défaut
|
|
151
|
-
const debugMode = config.cf('app.debug', { defaultValue: false });
|
|
152
|
-
|
|
153
|
-
// Récupérer toute la configuration du module
|
|
154
|
-
const adminConfig = config.getConfig('admin');
|
|
155
|
-
|
|
156
|
-
// Vérifier si le module est chargé
|
|
157
|
-
const isModuleLoaded = config.isModuleLoaded;
|
|
158
|
-
|
|
159
|
-
// Recharger les configurations
|
|
160
|
-
const handleReload = () => config.reloadConfig();
|
|
161
|
-
|
|
162
168
|
return (
|
|
163
169
|
<div>
|
|
164
|
-
<h1>
|
|
165
|
-
<p>
|
|
166
|
-
<p>
|
|
167
|
-
<
|
|
170
|
+
<h1>Configuration du module Admin</h1>
|
|
171
|
+
<p>Scope actuel: {currentScope}</p>
|
|
172
|
+
<p>URL API: {apiUrl}</p>
|
|
173
|
+
<p>Permission d'édition: {canEdit ? 'Oui' : 'Non'}</p>
|
|
174
|
+
<button onClick={handleChangeScope}>
|
|
175
|
+
Passer à {currentScope === 'development' ? 'Staging' : 'Development'}
|
|
176
|
+
</button>
|
|
168
177
|
</div>
|
|
169
178
|
);
|
|
170
179
|
};
|
|
171
180
|
```
|
|
172
181
|
|
|
173
|
-
|
|
182
|
+
### ArcConfigProvider
|
|
174
183
|
|
|
175
184
|
```typescript
|
|
176
|
-
|
|
177
|
-
|
|
185
|
+
import { ArcConfigProvider } from '@arc-js/config-manager';
|
|
186
|
+
|
|
187
|
+
// Configuration complète avec modules
|
|
188
|
+
<ArcConfigProvider
|
|
189
|
+
config={{
|
|
190
|
+
base: {
|
|
191
|
+
development: async () => (await import('./configs/app/development.ts')).default,
|
|
192
|
+
staging: async () => (await import('./configs/app/staging.ts')).default,
|
|
193
|
+
production: async () => (await import('./configs/app/production.ts')).default
|
|
194
|
+
},
|
|
195
|
+
modules: {
|
|
196
|
+
admin: {
|
|
197
|
+
development: async () => (await import('./configs/modules/admin/development.ts')).default,
|
|
198
|
+
staging: async () => (await import('./configs/modules/admin/staging.ts')).default,
|
|
199
|
+
production: async () => (await import('./configs/modules/admin/production.ts')).default
|
|
200
|
+
},
|
|
201
|
+
dashboard: {
|
|
202
|
+
development: async () => (await import('./configs/modules/dashboard/development.ts')).default,
|
|
203
|
+
staging: async () => (await import('./configs/modules/dashboard/staging.ts')).default,
|
|
204
|
+
production: async () => (await import('./configs/modules/dashboard/production.ts')).default
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}}
|
|
208
|
+
supportedScopes={['development', 'staging', 'production']}
|
|
209
|
+
>
|
|
210
|
+
{children}
|
|
211
|
+
</ArcConfigProvider>
|
|
212
|
+
```
|
|
178
213
|
|
|
179
|
-
|
|
180
|
-
const configs = {
|
|
181
|
-
base: {
|
|
182
|
-
main: async () => (await import('./config.json')).default,
|
|
183
|
-
env: async () => ({
|
|
184
|
-
apiUrl: import.meta.env.VITE_API_URL,
|
|
185
|
-
nodeEnv: import.meta.env.NODE_ENV
|
|
186
|
-
})
|
|
187
|
-
},
|
|
188
|
-
modules: {
|
|
189
|
-
admin: async () => (await import('./modules/admin/config.json')).default,
|
|
190
|
-
dashboard: async () => (await import('./modules/dashboard/config.json')).default
|
|
191
|
-
}
|
|
192
|
-
};
|
|
214
|
+
## 🔧 Utilisation Avancée
|
|
193
215
|
|
|
194
|
-
|
|
216
|
+
### Accès aux configurations avec chemins imbriqués
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
const ConfigComponent = () => {
|
|
220
|
+
const { cf } = useConfig();
|
|
221
|
+
|
|
222
|
+
// Accès à des valeurs imbriquées
|
|
223
|
+
const apiConfig = cf('api');
|
|
224
|
+
const baseUrl = cf('api.baseUrl');
|
|
225
|
+
const debugMode = cf('features.debug');
|
|
226
|
+
|
|
195
227
|
return (
|
|
196
|
-
<
|
|
197
|
-
|
|
198
|
-
|
|
228
|
+
<div>
|
|
229
|
+
<p>URL de base: {baseUrl}</p>
|
|
230
|
+
<p>Mode debug: {debugMode ? 'Activé' : 'Désactivé'}</p>
|
|
231
|
+
<pre>{JSON.stringify(apiConfig, null, 2)}</pre>
|
|
232
|
+
</div>
|
|
199
233
|
);
|
|
200
234
|
};
|
|
201
235
|
```
|
|
202
236
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
### Accès aux variables d'environnement
|
|
237
|
+
### Valeurs par défaut et fallback
|
|
206
238
|
|
|
207
239
|
```typescript
|
|
208
|
-
const
|
|
209
|
-
const
|
|
240
|
+
const SafeConfigComponent = () => {
|
|
241
|
+
const { cf } = useConfig();
|
|
210
242
|
|
|
211
|
-
//
|
|
212
|
-
const
|
|
213
|
-
|
|
243
|
+
// Avec valeur par défaut
|
|
244
|
+
const timeout = cf('api.timeout', { defaultValue: 3000 });
|
|
245
|
+
|
|
246
|
+
// Accès avec chemin inexistant
|
|
247
|
+
const missingValue = cf('non.existent.key', { defaultValue: 'valeur par défaut' });
|
|
214
248
|
|
|
215
249
|
return (
|
|
216
250
|
<div>
|
|
217
|
-
<
|
|
218
|
-
<p>
|
|
219
|
-
<p>Node Environment: {nodeEnv}</p>
|
|
251
|
+
<p>Timeout: {timeout}ms</p>
|
|
252
|
+
<p>Valeur manquante: {missingValue}</p>
|
|
220
253
|
</div>
|
|
221
254
|
);
|
|
222
255
|
};
|
|
223
256
|
```
|
|
224
257
|
|
|
225
|
-
### Chargement
|
|
258
|
+
### Chargement dynamique de modules
|
|
226
259
|
|
|
227
260
|
```typescript
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const [moduleConfig, setModuleConfig] = useState(null);
|
|
261
|
+
import { useEffect } from 'react';
|
|
262
|
+
import { useConfig } from '@arc-js/config-manager';
|
|
231
263
|
|
|
264
|
+
const AdminModule = () => {
|
|
265
|
+
const { cf, loadModule, isLoading } = useConfig('admin');
|
|
266
|
+
|
|
232
267
|
useEffect(() => {
|
|
233
|
-
// Charger
|
|
234
|
-
|
|
235
|
-
const analyticsConfig = config.getConfig('analytics');
|
|
236
|
-
setModuleConfig(analyticsConfig);
|
|
237
|
-
});
|
|
268
|
+
// Charger les configurations du module admin à la demande
|
|
269
|
+
loadModule('admin');
|
|
238
270
|
}, []);
|
|
239
|
-
|
|
240
|
-
if (
|
|
271
|
+
|
|
272
|
+
if (isLoading) return <div>Chargement des configurations...</div>;
|
|
241
273
|
|
|
242
274
|
return (
|
|
243
275
|
<div>
|
|
244
|
-
<
|
|
245
|
-
<
|
|
276
|
+
<h1>Dashboard Admin</h1>
|
|
277
|
+
<p>Pagination: {cf('settings.pagination')} éléments</p>
|
|
278
|
+
<p>Formats d'export: {cf('settings.exportFormats').join(', ')}</p>
|
|
246
279
|
</div>
|
|
247
280
|
);
|
|
248
281
|
};
|
|
249
282
|
```
|
|
250
283
|
|
|
284
|
+
### Configuration multi-scope par module
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// configs/modules/admin/development.ts
|
|
288
|
+
export default {
|
|
289
|
+
permissions: {
|
|
290
|
+
canEdit: true,
|
|
291
|
+
canDelete: true,
|
|
292
|
+
canCreate: true
|
|
293
|
+
},
|
|
294
|
+
limits: {
|
|
295
|
+
maxUsers: 100,
|
|
296
|
+
maxStorage: '10GB'
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
// configs/modules/admin/production.ts
|
|
301
|
+
export default {
|
|
302
|
+
permissions: {
|
|
303
|
+
canEdit: true,
|
|
304
|
+
canDelete: false,
|
|
305
|
+
canCreate: true
|
|
306
|
+
},
|
|
307
|
+
limits: {
|
|
308
|
+
maxUsers: 1000,
|
|
309
|
+
maxStorage: '100GB'
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
```
|
|
313
|
+
|
|
251
314
|
## 🎯 Exemples Complets
|
|
252
315
|
|
|
253
|
-
### Exemple 1 :
|
|
316
|
+
### Exemple 1 : Sélecteur de scope
|
|
254
317
|
|
|
255
318
|
```typescript
|
|
256
319
|
import { useConfig } from '@arc-js/config-manager';
|
|
257
320
|
|
|
258
|
-
const
|
|
259
|
-
const
|
|
321
|
+
const ScopeSwitcher = () => {
|
|
322
|
+
const { currentScope, changeScope, cf } = useConfig();
|
|
260
323
|
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const timeout = config.cf('api.timeout', { defaultValue: 30000 });
|
|
267
|
-
const retryAttempts = config.cf('api.retryAttempts', { defaultValue: 3 });
|
|
268
|
-
|
|
269
|
-
return { baseUrl, timeout, retryAttempts };
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
const fetchData = async () => {
|
|
273
|
-
const { baseUrl, timeout } = getApiConfig();
|
|
274
|
-
|
|
275
|
-
try {
|
|
276
|
-
const controller = new AbortController();
|
|
277
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
278
|
-
|
|
279
|
-
const response = await fetch(`\${baseUrl}/data`, {
|
|
280
|
-
signal: controller.signal,
|
|
281
|
-
headers: {
|
|
282
|
-
'Content-Type': 'application/json'
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
clearTimeout(timeoutId);
|
|
287
|
-
return await response.json();
|
|
288
|
-
} catch (error) {
|
|
289
|
-
console.error('API Error:', error);
|
|
290
|
-
throw error;
|
|
291
|
-
}
|
|
292
|
-
};
|
|
324
|
+
const scopes = [
|
|
325
|
+
{ code: 'development', name: 'Développement', description: 'Environnement de développement' },
|
|
326
|
+
{ code: 'staging', name: 'Staging', description: 'Environnement de pré-production' },
|
|
327
|
+
{ code: 'production', name: 'Production', description: 'Environnement de production' }
|
|
328
|
+
];
|
|
293
329
|
|
|
294
330
|
return (
|
|
295
|
-
<div>
|
|
296
|
-
<
|
|
297
|
-
|
|
298
|
-
|
|
331
|
+
<div className="scope-switcher">
|
|
332
|
+
<h3>Sélecteur d'environnement</h3>
|
|
333
|
+
<div className="scope-buttons">
|
|
334
|
+
{scopes.map(scope => (
|
|
335
|
+
<button
|
|
336
|
+
key={scope.code}
|
|
337
|
+
className={currentScope === scope.code ? 'active' : ''}
|
|
338
|
+
onClick={() => changeScope(scope.code)}
|
|
339
|
+
title={scope.description}
|
|
340
|
+
>
|
|
341
|
+
{scope.name}
|
|
342
|
+
</button>
|
|
343
|
+
))}
|
|
344
|
+
</div>
|
|
345
|
+
<p className="current-scope-info">
|
|
346
|
+
Environnement actuel: <strong>{currentScope}</strong>
|
|
347
|
+
</p>
|
|
299
348
|
</div>
|
|
300
349
|
);
|
|
301
350
|
};
|
|
302
351
|
```
|
|
303
352
|
|
|
304
|
-
### Exemple 2 :
|
|
353
|
+
### Exemple 2 : Configuration dynamique d'API
|
|
305
354
|
|
|
306
355
|
```typescript
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
moduleName?: string
|
|
310
|
-
}) => {
|
|
311
|
-
const config = useConfig(moduleName);
|
|
312
|
-
const [isEnabled, setIsEnabled] = useState(false);
|
|
313
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
356
|
+
import { useConfig } from '@arc-js/config-manager';
|
|
357
|
+
import { useState, useEffect } from 'react';
|
|
314
358
|
|
|
359
|
+
const ApiDashboard = () => {
|
|
360
|
+
const { cf, currentScope } = useConfig();
|
|
361
|
+
const [apiStatus, setApiStatus] = useState('checking');
|
|
362
|
+
|
|
315
363
|
useEffect(() => {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
364
|
+
const checkApiStatus = async () => {
|
|
365
|
+
try {
|
|
366
|
+
const baseUrl = cf('api.baseUrl');
|
|
367
|
+
const timeout = cf('api.timeout', { defaultValue: 5000 });
|
|
368
|
+
|
|
369
|
+
const controller = new AbortController();
|
|
370
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
371
|
+
|
|
372
|
+
const response = await fetch(`\${baseUrl}/health`, {
|
|
373
|
+
signal: controller.signal
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
clearTimeout(timeoutId);
|
|
377
|
+
|
|
378
|
+
if (response.ok) {
|
|
379
|
+
setApiStatus('healthy');
|
|
380
|
+
} else {
|
|
381
|
+
setApiStatus('unhealthy');
|
|
382
|
+
}
|
|
383
|
+
} catch (error) {
|
|
384
|
+
setApiStatus('unreachable');
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
checkApiStatus();
|
|
389
|
+
}, [cf, currentScope]);
|
|
325
390
|
|
|
326
391
|
return (
|
|
327
|
-
<div className=
|
|
328
|
-
<
|
|
329
|
-
|
|
392
|
+
<div className="api-dashboard">
|
|
393
|
+
<h2>Statut de l'API</h2>
|
|
394
|
+
<div className="api-info">
|
|
395
|
+
<p><strong>Environnement:</strong> {currentScope}</p>
|
|
396
|
+
<p><strong>URL de base:</strong> {cf('api.baseUrl')}</p>
|
|
397
|
+
<p><strong>Timeout:</strong> {cf('api.timeout')}ms</p>
|
|
398
|
+
<p><strong>Statut:</strong>
|
|
399
|
+
<span className={`status-\${apiStatus}`}>
|
|
400
|
+
{apiStatus === 'healthy' ? '✅ En ligne' :
|
|
401
|
+
apiStatus === 'unhealthy' ? '⚠️ Problèmes' :
|
|
402
|
+
'❌ Hors ligne'}
|
|
403
|
+
</span>
|
|
404
|
+
</p>
|
|
405
|
+
</div>
|
|
330
406
|
</div>
|
|
331
407
|
);
|
|
332
408
|
};
|
|
409
|
+
```
|
|
333
410
|
|
|
334
|
-
|
|
335
|
-
|
|
411
|
+
### Exemple 3 : Dashboard avec modules multiples
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
import { useConfig } from '@arc-js/config-manager';
|
|
415
|
+
import { useEffect } from 'react';
|
|
416
|
+
|
|
417
|
+
const Dashboard = () => {
|
|
418
|
+
const { cf, loadModule, currentScope, isLoading } = useConfig('admin');
|
|
419
|
+
|
|
420
|
+
// Charger les configurations de plusieurs modules
|
|
421
|
+
useEffect(() => {
|
|
422
|
+
const loadModules = async () => {
|
|
423
|
+
await loadModule('admin');
|
|
424
|
+
await loadModule('analytics');
|
|
425
|
+
await loadModule('reports');
|
|
426
|
+
};
|
|
427
|
+
loadModules();
|
|
428
|
+
}, [currentScope]);
|
|
429
|
+
|
|
430
|
+
if (isLoading) return <div>Chargement des configurations...</div>;
|
|
431
|
+
|
|
336
432
|
return (
|
|
337
|
-
<div>
|
|
338
|
-
<
|
|
339
|
-
|
|
340
|
-
|
|
433
|
+
<div className="dashboard">
|
|
434
|
+
<header>
|
|
435
|
+
<h1>Tableau de bord de configuration</h1>
|
|
436
|
+
<p>Environnement: {currentScope}</p>
|
|
437
|
+
</header>
|
|
438
|
+
|
|
439
|
+
<section className="config-cards">
|
|
440
|
+
<div className="config-card">
|
|
441
|
+
<h3>Configuration Admin</h3>
|
|
442
|
+
<ul>
|
|
443
|
+
<li>Édition: {cf('permissions.canEdit', { moduleName: 'admin' }) ? '✅' : '❌'}</li>
|
|
444
|
+
<li>Suppression: {cf('permissions.canDelete', { moduleName: 'admin' }) ? '✅' : '❌'}</li>
|
|
445
|
+
<li>Pagination: {cf('settings.pagination', { moduleName: 'admin' })} éléments</li>
|
|
446
|
+
</ul>
|
|
447
|
+
</div>
|
|
448
|
+
|
|
449
|
+
<div className="config-card">
|
|
450
|
+
<h3>Configuration Analytics</h3>
|
|
451
|
+
<ul>
|
|
452
|
+
<li>Tracking: {cf('features.enabled', { moduleName: 'analytics' }) ? 'Activé' : 'Désactivé'}</li>
|
|
453
|
+
<li>Rétention: {cf('data.retentionDays', { moduleName: 'analytics' })} jours</li>
|
|
454
|
+
</ul>
|
|
455
|
+
</div>
|
|
456
|
+
|
|
457
|
+
<div className="config-card">
|
|
458
|
+
<h3>Configuration API</h3>
|
|
459
|
+
<ul>
|
|
460
|
+
<li>URL: {cf('api.baseUrl')}</li>
|
|
461
|
+
<li>Version: {cf('api.version', { defaultValue: 'v1' })}</li>
|
|
462
|
+
<li>Debug: {cf('features.debug') ? 'Activé' : 'Désactivé'}</li>
|
|
463
|
+
</ul>
|
|
464
|
+
</div>
|
|
465
|
+
</section>
|
|
341
466
|
</div>
|
|
342
467
|
);
|
|
343
468
|
};
|
|
@@ -345,52 +470,83 @@ const AppFeatures = () => {
|
|
|
345
470
|
|
|
346
471
|
## 📋 API Reference
|
|
347
472
|
|
|
348
|
-
###
|
|
349
|
-
| Prop | Type | Description |
|
|
350
|
-
|
|
351
|
-
| `
|
|
352
|
-
| `
|
|
473
|
+
### ArcConfigProvider
|
|
474
|
+
| Prop | Type | Description | Required |
|
|
475
|
+
|------|------|-------------|----------|
|
|
476
|
+
| `config` | `ConfigManagerConfig` | Configuration des chargeurs de configuration | Oui |
|
|
477
|
+
| `supportedScopes` | `string[]` | Scopes supportés (défaut: ['app']) | Non |
|
|
478
|
+
| `children` | `React.ReactNode` | Composants enfants | Oui |
|
|
353
479
|
|
|
354
480
|
### Hook useConfig
|
|
355
481
|
Retourne un objet avec:
|
|
356
|
-
- `cf(key: string, options?: ConfigOptions)`:
|
|
357
|
-
- `
|
|
358
|
-
- `
|
|
482
|
+
- `cf(key: string, options?: ConfigOptions)`: Fonction d'accès aux configurations
|
|
483
|
+
- `changeScope(scope: string)`: Changer le scope actuel
|
|
484
|
+
- `currentScope`: Scope actuel
|
|
359
485
|
- `isLoading`: État de chargement global
|
|
360
486
|
- `isModuleLoaded`: Indique si le module demandé est chargé
|
|
361
|
-
- `
|
|
487
|
+
- `loadModule(moduleName: string)`: Charge un module spécifique
|
|
362
488
|
|
|
363
489
|
### Options de Configuration
|
|
364
490
|
```typescript
|
|
365
491
|
interface ConfigOptions {
|
|
366
|
-
moduleName?: string; // Nom du module (défaut: '
|
|
367
|
-
defaultValue?: any; // Valeur par défaut si non
|
|
368
|
-
|
|
492
|
+
moduleName?: string; // Nom du module (défaut: 'app')
|
|
493
|
+
defaultValue?: any; // Valeur par défaut si clé non trouvée
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Structure de configuration
|
|
498
|
+
```typescript
|
|
499
|
+
interface ConfigManagerConfig {
|
|
500
|
+
base: {
|
|
501
|
+
[scope: string]: () => Promise<Record<string, any>>;
|
|
502
|
+
};
|
|
503
|
+
modules?: {
|
|
504
|
+
[moduleName: string]: () => Promise<Record<string, any>>;
|
|
505
|
+
};
|
|
369
506
|
}
|
|
370
507
|
```
|
|
371
508
|
|
|
509
|
+
### Types principaux
|
|
510
|
+
```typescript
|
|
511
|
+
export type ConfigScope = string;
|
|
512
|
+
export type ConfigMap = { [scope: string]: () => Promise<Record<string, any>> };
|
|
513
|
+
export type ModuleConfigs = { [moduleName: string]: () => Promise<Record<string, any>> };
|
|
514
|
+
```
|
|
515
|
+
|
|
372
516
|
## 🛡️ Gestion des Erreurs
|
|
373
517
|
|
|
374
518
|
### Fallback sécurisé
|
|
375
519
|
```typescript
|
|
376
520
|
const SafeComponent = () => {
|
|
377
|
-
const
|
|
521
|
+
const { cf } = useConfig();
|
|
378
522
|
|
|
379
523
|
// Utilisation sécurisée avec valeur par défaut
|
|
380
|
-
const
|
|
381
|
-
defaultValue: '
|
|
382
|
-
moduleName: 'admin'
|
|
524
|
+
const apiUrl = cf('api.baseUrl', {
|
|
525
|
+
defaultValue: 'https://default-api.example.com'
|
|
383
526
|
});
|
|
384
527
|
|
|
385
|
-
//
|
|
386
|
-
const
|
|
387
|
-
const hasRequiredConfig = 'requiredKey' in adminConfig;
|
|
528
|
+
// Accès imbriqué sécurisé
|
|
529
|
+
const theme = cf('ui.theme', { defaultValue: 'light' });
|
|
388
530
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
531
|
+
return (
|
|
532
|
+
<div>
|
|
533
|
+
<p>API: {apiUrl}</p>
|
|
534
|
+
<p>Theme: {theme}</p>
|
|
535
|
+
</div>
|
|
536
|
+
);
|
|
537
|
+
};
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Logs en développement
|
|
541
|
+
```typescript
|
|
542
|
+
// En mode développement, les clés manquantes sont automatiquement loggées
|
|
543
|
+
const MissingConfigs = () => {
|
|
544
|
+
const { cf } = useConfig();
|
|
545
|
+
|
|
546
|
+
// Ceci loggue un avertissement en développement
|
|
547
|
+
const missingKey = cf('non.existent.key');
|
|
392
548
|
|
|
393
|
-
return <div>
|
|
549
|
+
return <div>{missingKey || 'Configuration manquante'}</div>;
|
|
394
550
|
};
|
|
395
551
|
```
|
|
396
552
|
|
|
@@ -415,6 +571,58 @@ const SafeComponent = () => {
|
|
|
415
571
|
}
|
|
416
572
|
```
|
|
417
573
|
|
|
574
|
+
## 📋 Table des Conventions
|
|
575
|
+
|
|
576
|
+
### Structure des fichiers de configuration
|
|
577
|
+
|
|
578
|
+
| Chemin | Description | Exemple |
|
|
579
|
+
|--------|-------------|---------|
|
|
580
|
+
| `configs/app/{scope}.ts` | Configuration de base par scope | `configs/app/development.ts` |
|
|
581
|
+
| `configs/modules/{module}/config.ts` | Configuration du module | `configs/modules/admin/config.ts` |
|
|
582
|
+
| `configs/modules/{module}/{scope}.ts` | Configuration du module par scope | `configs/modules/admin/production.ts` |
|
|
583
|
+
|
|
584
|
+
### Clés de configuration
|
|
585
|
+
|
|
586
|
+
| Format | Description | Exemple |
|
|
587
|
+
|--------|-------------|---------|
|
|
588
|
+
| `namespace.key` | Clé simple | `api.baseUrl` |
|
|
589
|
+
| `namespace.nested.key` | Clé imbriquée | `features.analytics.enabled` |
|
|
590
|
+
| `moduleName:key` | Avec module spécifique | `admin:permissions.canEdit` |
|
|
591
|
+
|
|
592
|
+
## 🔧 Build et Développement
|
|
593
|
+
|
|
594
|
+
### Scripts recommandés
|
|
595
|
+
|
|
596
|
+
```json
|
|
597
|
+
{
|
|
598
|
+
"scripts": {
|
|
599
|
+
"dev": "vite",
|
|
600
|
+
"build": "tsc && vite build",
|
|
601
|
+
"preview": "vite preview",
|
|
602
|
+
"type-check": "tsc --noEmit",
|
|
603
|
+
"validate-configs": "node scripts/validate-configs.js",
|
|
604
|
+
"generate-config-schema": "node scripts/generate-schema.js"
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Configuration Vite
|
|
610
|
+
|
|
611
|
+
```typescript
|
|
612
|
+
// vite.config.ts
|
|
613
|
+
import { defineConfig } from 'vite';
|
|
614
|
+
import react from '@vitejs/plugin-react';
|
|
615
|
+
|
|
616
|
+
export default defineConfig({
|
|
617
|
+
plugins: [react()],
|
|
618
|
+
resolve: {
|
|
619
|
+
alias: {
|
|
620
|
+
'@arc-js/config-manager': '@arc-js/config-manager/index.js'
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
```
|
|
625
|
+
|
|
418
626
|
## 📄 Licence
|
|
419
627
|
|
|
420
628
|
MIT License - Voir le fichier [LICENSE](LICENSE) pour plus de détails.
|
|
@@ -429,6 +637,6 @@ Envoyez-nous un mail à l'adresse `contact.inicode@gmail.com` pour :
|
|
|
429
637
|
|
|
430
638
|
---
|
|
431
639
|
|
|
432
|
-
**@arc-js/config-manager** -
|
|
640
|
+
**@arc-js/config-manager** - La solution de gestion de configuration modulaire pour React et TypeScript.
|
|
433
641
|
|
|
434
642
|
*Développé par l'équipe INICODE*
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.0.
|
|
6
|
+
"version": "0.0.98",
|
|
7
7
|
"description": "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.",
|
|
8
8
|
"main": "index.js",
|
|
9
9
|
"keywords": [],
|