@abdokouta/react-config 1.0.0

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 (42) hide show
  1. package/.examples/01-basic-usage.ts +289 -0
  2. package/.examples/02-env-helper.ts +282 -0
  3. package/.examples/README.md +285 -0
  4. package/.prettierrc.js +1 -0
  5. package/README.md +261 -0
  6. package/__tests__/config.module.test.ts +244 -0
  7. package/__tests__/drivers/env.driver.test.ts +259 -0
  8. package/__tests__/services/config.service.test.ts +328 -0
  9. package/__tests__/setup.d.ts +11 -0
  10. package/__tests__/vitest.setup.ts +30 -0
  11. package/config/config.config.ts +62 -0
  12. package/dist/index.d.mts +474 -0
  13. package/dist/index.d.ts +474 -0
  14. package/dist/index.js +516 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/index.mjs +501 -0
  17. package/dist/index.mjs.map +1 -0
  18. package/eslint.config.js +13 -0
  19. package/package.json +77 -0
  20. package/src/config.module.ts +154 -0
  21. package/src/constants/index.ts +5 -0
  22. package/src/constants/tokens.constant.ts +38 -0
  23. package/src/drivers/env.driver.ts +194 -0
  24. package/src/drivers/file.driver.ts +81 -0
  25. package/src/drivers/index.ts +6 -0
  26. package/src/index.ts +92 -0
  27. package/src/interfaces/config-driver.interface.ts +30 -0
  28. package/src/interfaces/config-module-options.interface.ts +84 -0
  29. package/src/interfaces/config-service.interface.ts +71 -0
  30. package/src/interfaces/index.ts +8 -0
  31. package/src/interfaces/vite-config-plugin-options.interface.ts +56 -0
  32. package/src/plugins/index.ts +5 -0
  33. package/src/plugins/vite.plugin.ts +115 -0
  34. package/src/services/config.service.ts +172 -0
  35. package/src/services/index.ts +5 -0
  36. package/src/utils/get-nested-value.util.ts +56 -0
  37. package/src/utils/index.ts +6 -0
  38. package/src/utils/load-config-file.util.ts +37 -0
  39. package/src/utils/scan-config-files.util.ts +40 -0
  40. package/tsconfig.json +28 -0
  41. package/tsup.config.ts +105 -0
  42. package/vitest.config.ts +66 -0
@@ -0,0 +1,474 @@
1
+ import { DynamicModule } from '@abdokouta/react-di';
2
+
3
+ /**
4
+ * Configuration Module Options
5
+ */
6
+ interface ConfigModuleOptions {
7
+ /**
8
+ * Configuration driver to use
9
+ * @default 'env'
10
+ */
11
+ driver?: 'env' | 'file' | 'firebase' | string;
12
+ /**
13
+ * Path to .env file (for env driver)
14
+ * @default '.env'
15
+ */
16
+ envFilePath?: string | string[];
17
+ /**
18
+ * Path pattern to scan for config files (for file driver)
19
+ * @example 'config/**\/*.config.ts'
20
+ */
21
+ filePattern?: string | string[];
22
+ /**
23
+ * Whether to ignore .env file
24
+ * @default false
25
+ */
26
+ ignoreEnvFile?: boolean;
27
+ /**
28
+ * Whether to expand environment variables
29
+ * @default false
30
+ */
31
+ expandVariables?: boolean;
32
+ /**
33
+ * Custom configuration object to merge
34
+ */
35
+ load?: Record<string, any> | (() => Record<string, any> | Promise<Record<string, any>>);
36
+ /**
37
+ * Whether configuration is global
38
+ * @default false
39
+ */
40
+ isGlobal?: boolean;
41
+ /**
42
+ * Cache configuration values
43
+ * @default true
44
+ */
45
+ cache?: boolean;
46
+ /**
47
+ * Validate configuration on load
48
+ */
49
+ validate?: (config: Record<string, any>) => void | Promise<void>;
50
+ /**
51
+ * Firebase configuration (for firebase driver)
52
+ */
53
+ firebase?: {
54
+ projectId: string;
55
+ configPath?: string;
56
+ };
57
+ /**
58
+ * Environment variable prefix to strip
59
+ * Set to 'auto' to auto-detect (VITE_ for Vite, NEXT_PUBLIC_ for Next.js)
60
+ * Set to 'VITE_' or 'NEXT_PUBLIC_' for specific framework
61
+ * Set to a custom string to strip that prefix
62
+ * Set to false to disable prefix stripping
63
+ * @default 'auto'
64
+ * @example 'VITE_' - strips VITE_ prefix, so VITE_APP_NAME becomes APP_NAME
65
+ * @example 'NEXT_PUBLIC_' - strips NEXT_PUBLIC_ prefix, so NEXT_PUBLIC_API_URL becomes API_URL
66
+ * @example 'auto' - auto-detects framework and strips appropriate prefix
67
+ */
68
+ envPrefix?: 'auto' | 'VITE_' | 'NEXT_PUBLIC_' | string | false;
69
+ /**
70
+ * Global variable name to read config from in browser
71
+ * @default '__APP_CONFIG__'
72
+ * @example '__APP_CONFIG__' - reads from window.__APP_CONFIG__
73
+ */
74
+ globalName?: string;
75
+ }
76
+
77
+ /**
78
+ * Configuration Module
79
+ *
80
+ * Provides configuration management with multiple drivers.
81
+ * Similar to NestJS ConfigModule.
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * // Using environment variables (default)
86
+ * @Module({
87
+ * imports: [
88
+ * ConfigModule.forRoot({
89
+ * envFilePath: '.env',
90
+ * isGlobal: true,
91
+ * }),
92
+ * ],
93
+ * })
94
+ * export class AppModule {}
95
+ * ```
96
+ *
97
+ * @example
98
+ * ```typescript
99
+ * // Using file-based configuration
100
+ * @Module({
101
+ * imports: [
102
+ * ConfigModule.forRoot({
103
+ * driver: 'file',
104
+ * filePattern: 'config/**\/*.config.ts',
105
+ * isGlobal: true,
106
+ * }),
107
+ * ],
108
+ * })
109
+ * export class AppModule {}
110
+ * ```
111
+ */
112
+ declare class ConfigModule {
113
+ /**
114
+ * Register configuration module with options
115
+ *
116
+ * @param options - Configuration options
117
+ * @returns Dynamic module
118
+ */
119
+ static forRoot(options?: ConfigModuleOptions): DynamicModule;
120
+ /**
121
+ * Register configuration module asynchronously
122
+ *
123
+ * @param options - Async configuration options
124
+ * @returns Dynamic module
125
+ */
126
+ static forRootAsync(options: ConfigModuleOptions & {
127
+ useFactory?: () => Promise<ConfigModuleOptions> | ConfigModuleOptions;
128
+ }): Promise<DynamicModule>;
129
+ /**
130
+ * Create configuration driver based on options
131
+ */
132
+ private static createDriver;
133
+ /**
134
+ * Merge custom configuration into driver
135
+ */
136
+ private static mergeCustomConfig;
137
+ }
138
+
139
+ /**
140
+ * Configuration Driver Interface
141
+ *
142
+ * Defines the contract for configuration drivers (env, file, firebase, etc.)
143
+ */
144
+ interface ConfigDriver {
145
+ /**
146
+ * Load configuration from the driver source
147
+ * @returns Configuration object
148
+ */
149
+ load(): Promise<Record<string, any>> | Record<string, any>;
150
+ /**
151
+ * Get a configuration value by key
152
+ * @param key - Configuration key (supports dot notation)
153
+ * @param defaultValue - Default value if key not found
154
+ */
155
+ get<T = any>(key: string, defaultValue?: T): T | undefined;
156
+ /**
157
+ * Check if a configuration key exists
158
+ * @param key - Configuration key
159
+ */
160
+ has(key: string): boolean;
161
+ /**
162
+ * Get all configuration values
163
+ */
164
+ all(): Record<string, any>;
165
+ }
166
+
167
+ /**
168
+ * Configuration Service Interface
169
+ *
170
+ * Defines the contract for configuration service implementations.
171
+ */
172
+ interface ConfigServiceInterface {
173
+ /**
174
+ * Get configuration value
175
+ */
176
+ get<T = any>(key: string, defaultValue?: T): T | undefined;
177
+ /**
178
+ * Get configuration value or throw if not found
179
+ */
180
+ getOrThrow<T = any>(key: string): T;
181
+ /**
182
+ * Get string value
183
+ */
184
+ getString(key: string, defaultValue?: string): string | undefined;
185
+ /**
186
+ * Get string value or throw
187
+ */
188
+ getStringOrThrow(key: string): string;
189
+ /**
190
+ * Get number value
191
+ */
192
+ getNumber(key: string, defaultValue?: number): number | undefined;
193
+ /**
194
+ * Get number value or throw
195
+ */
196
+ getNumberOrThrow(key: string): number;
197
+ /**
198
+ * Get boolean value
199
+ */
200
+ getBool(key: string, defaultValue?: boolean): boolean | undefined;
201
+ /**
202
+ * Get boolean value or throw
203
+ */
204
+ getBoolOrThrow(key: string): boolean;
205
+ /**
206
+ * Get array value
207
+ */
208
+ getArray(key: string, defaultValue?: string[]): string[] | undefined;
209
+ /**
210
+ * Get JSON value
211
+ */
212
+ getJson<T = any>(key: string, defaultValue?: T): T | undefined;
213
+ /**
214
+ * Check if configuration key exists
215
+ */
216
+ has(key: string): boolean;
217
+ /**
218
+ * Get all configuration values
219
+ */
220
+ all(): Record<string, any>;
221
+ /**
222
+ * Clear cache
223
+ */
224
+ clearCache(): void;
225
+ }
226
+
227
+ /**
228
+ * Configuration Service
229
+ *
230
+ * Provides type-safe access to configuration values with various getter methods.
231
+ * Similar to NestJS ConfigService.
232
+ *
233
+ * @example
234
+ * ```typescript
235
+ * class MyService {
236
+ * constructor(private config: ConfigService) {}
237
+ *
238
+ * getDbConfig() {
239
+ * return {
240
+ * host: this.config.getString('DB_HOST', 'localhost'),
241
+ * port: this.config.getNumber('DB_PORT', 5432),
242
+ * ssl: this.config.getBool('DB_SSL', false),
243
+ * };
244
+ * }
245
+ * }
246
+ * ```
247
+ */
248
+ declare class ConfigService implements ConfigServiceInterface {
249
+ private driver;
250
+ constructor(driver: ConfigDriver);
251
+ /**
252
+ * Get configuration value
253
+ */
254
+ get<T = any>(key: string, defaultValue?: T): T | undefined;
255
+ /**
256
+ * Get configuration value or throw if not found
257
+ */
258
+ getOrThrow<T = any>(key: string): T;
259
+ /**
260
+ * Get string value
261
+ */
262
+ getString(key: string, defaultValue?: string): string | undefined;
263
+ /**
264
+ * Get string value or throw
265
+ */
266
+ getStringOrThrow(key: string): string;
267
+ /**
268
+ * Get number value
269
+ */
270
+ getNumber(key: string, defaultValue?: number): number | undefined;
271
+ /**
272
+ * Get number value or throw
273
+ */
274
+ getNumberOrThrow(key: string): number;
275
+ /**
276
+ * Get boolean value
277
+ * Treats 'true', '1', 'yes', 'on' as true
278
+ */
279
+ getBool(key: string, defaultValue?: boolean): boolean | undefined;
280
+ /**
281
+ * Get boolean value or throw
282
+ */
283
+ getBoolOrThrow(key: string): boolean;
284
+ /**
285
+ * Get array value (comma-separated string or actual array)
286
+ */
287
+ getArray(key: string, defaultValue?: string[]): string[] | undefined;
288
+ /**
289
+ * Get JSON value
290
+ */
291
+ getJson<T = any>(key: string, defaultValue?: T): T | undefined;
292
+ /**
293
+ * Check if configuration key exists
294
+ */
295
+ has(key: string): boolean;
296
+ /**
297
+ * Get all configuration values
298
+ */
299
+ all(): Record<string, any>;
300
+ /**
301
+ * Clear cache (no-op since we don't cache in ConfigService)
302
+ */
303
+ clearCache(): void;
304
+ }
305
+
306
+ /**
307
+ * Environment Variable Configuration Driver
308
+ *
309
+ * Loads configuration from environment variables (process.env).
310
+ * Supports .env files via dotenv.
311
+ */
312
+ declare class EnvDriver implements ConfigDriver {
313
+ private options;
314
+ private config;
315
+ private loaded;
316
+ constructor(options?: {
317
+ envFilePath?: string | string[];
318
+ ignoreEnvFile?: boolean;
319
+ expandVariables?: boolean;
320
+ envPrefix?: string | false;
321
+ globalName?: string;
322
+ });
323
+ /**
324
+ * Load environment variables
325
+ */
326
+ load(): Record<string, any>;
327
+ /**
328
+ * Get configuration value
329
+ */
330
+ get<T = any>(key: string, defaultValue?: T): T | undefined;
331
+ /**
332
+ * Check if key exists
333
+ */
334
+ has(key: string): boolean;
335
+ /**
336
+ * Get all configuration
337
+ */
338
+ all(): Record<string, any>;
339
+ /**
340
+ * Load .env file using dotenv
341
+ */
342
+ private loadDotEnv;
343
+ /**
344
+ * Expand environment variables (e.g., ${VAR_NAME})
345
+ */
346
+ private expandEnvVariables;
347
+ /**
348
+ * Strip environment variable prefix
349
+ * Auto-detects framework (Vite, Next.js) or uses custom prefix
350
+ */
351
+ private stripPrefix;
352
+ }
353
+
354
+ /**
355
+ * File-based Configuration Driver
356
+ *
357
+ * Loads configuration from TypeScript/JavaScript files.
358
+ * This is a server-side only driver. For client-side, use the Vite plugin.
359
+ *
360
+ * @see packages/pixielity/config/src/plugins/vite-config.plugin.ts
361
+ */
362
+ declare class FileDriver implements ConfigDriver {
363
+ private config;
364
+ private loaded;
365
+ constructor(options?: {
366
+ config?: Record<string, any>;
367
+ });
368
+ /**
369
+ * Load configuration
370
+ * Config should be pre-loaded via Vite plugin or passed in constructor
371
+ */
372
+ load(): Promise<Record<string, any>>;
373
+ /**
374
+ * Get configuration value
375
+ */
376
+ get<T = any>(key: string, defaultValue?: T): T | undefined;
377
+ /**
378
+ * Check if key exists
379
+ */
380
+ has(key: string): boolean;
381
+ /**
382
+ * Get all configuration
383
+ */
384
+ all(): Record<string, any>;
385
+ }
386
+
387
+ /**
388
+ * Vite Config Plugin Options Interface
389
+ *
390
+ * Configuration options for the Vite config plugin that injects
391
+ * environment variables into the browser.
392
+ */
393
+ interface ViteConfigPluginOptions {
394
+ /**
395
+ * Environment variables loaded by Vite's loadEnv
396
+ * Pass the result of loadEnv(mode, envDir, '') here
397
+ */
398
+ env?: Record<string, string>;
399
+ /**
400
+ * Scan and collect .config.ts files
401
+ * @default false (disabled by default to avoid Node.js module issues)
402
+ */
403
+ scanConfigFiles?: boolean;
404
+ /**
405
+ * Pattern to match config files
406
+ * @default 'src/**\/*.config.ts'
407
+ */
408
+ configFilePattern?: string | string[];
409
+ /**
410
+ * Directories to exclude from config file scanning
411
+ * @default ['node_modules', 'dist', 'build', '.git']
412
+ */
413
+ excludeDirs?: string[];
414
+ /**
415
+ * Root directory for scanning config files
416
+ * @default process.cwd()
417
+ */
418
+ root?: string;
419
+ /**
420
+ * Include all environment variables
421
+ * @default true
422
+ */
423
+ includeAll?: boolean;
424
+ /**
425
+ * Specific environment variables to include
426
+ * Only used if includeAll is false
427
+ */
428
+ include?: string[];
429
+ /**
430
+ * Global variable name to inject config into
431
+ * @default '__APP_CONFIG__'
432
+ */
433
+ globalName?: string;
434
+ }
435
+
436
+ /**
437
+ * Get nested value from object using dot notation
438
+ *
439
+ * @param obj - Source object
440
+ * @param path - Dot-notated path (e.g., 'database.host')
441
+ * @param defaultValue - Default value if path not found
442
+ * @returns Value at path or default value
443
+ *
444
+ * @example
445
+ * ```typescript
446
+ * const config = { database: { host: 'localhost' } };
447
+ * getNestedValue(config, 'database.host'); // 'localhost'
448
+ * getNestedValue(config, 'database.port', 5432); // 5432
449
+ * ```
450
+ */
451
+ declare function getNestedValue<T = any>(obj: Record<string, any>, path: string, defaultValue?: T): T | undefined;
452
+ /**
453
+ * Check if nested path exists in object
454
+ *
455
+ * @param obj - Source object
456
+ * @param path - Dot-notated path
457
+ * @returns True if path exists
458
+ */
459
+ declare function hasNestedValue(obj: Record<string, any>, path: string): boolean;
460
+
461
+ /**
462
+ * Load Config File Utility
463
+ *
464
+ * Dynamically loads and parses a config file.
465
+ */
466
+ /**
467
+ * Load and parse config file
468
+ *
469
+ * @param filePath - Absolute path to the config file
470
+ * @returns Parsed config object
471
+ */
472
+ declare function loadConfigFile(filePath: string): Promise<Record<string, any>>;
473
+
474
+ export { type ConfigDriver, ConfigModule, type ConfigModuleOptions, ConfigService, type ConfigServiceInterface, EnvDriver, FileDriver, type ViteConfigPluginOptions, getNestedValue, hasNestedValue, loadConfigFile };