@lindorm/config 0.2.0 → 0.2.2

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 (3) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +407 -0
  3. package/package.json +6 -6
package/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.2.2](https://github.com/lindorm-io/monorepo/compare/@lindorm/config@0.2.1...@lindorm/config@0.2.2) (2025-07-12)
7
+
8
+ **Note:** Version bump only for package @lindorm/config
9
+
10
+ ## [0.2.1](https://github.com/lindorm-io/monorepo/compare/@lindorm/config@0.2.0...@lindorm/config@0.2.1) (2025-07-10)
11
+
12
+ **Note:** Version bump only for package @lindorm/config
13
+
6
14
  # [0.2.0](https://github.com/lindorm-io/monorepo/compare/@lindorm/config@0.1.2...@lindorm/config@0.2.0) (2025-06-17)
7
15
 
8
16
  ### Bug Fixes
package/README.md CHANGED
@@ -1 +1,408 @@
1
1
  # @lindorm/config
2
+
3
+ Type-safe configuration management with environment variable overrides, YAML file support, and Zod schema validation.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @lindorm/config
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **Type-Safe Configuration**: Full TypeScript support with Zod schema validation
14
+ - **Multiple Configuration Sources**: YAML files, environment variables, and NODE_CONFIG
15
+ - **Automatic Type Coercion**: Converts string values to correct types (numbers, booleans, arrays, objects)
16
+ - **Environment Variable Overrides**: Override any config value with environment variables
17
+ - **Case Conversion**: Automatic conversion between snake_case (files/env) and camelCase (code)
18
+ - **Environment-Specific Config**: Load different configurations based on NODE_ENV
19
+ - **CLI Tool**: Convert local config files to NODE_CONFIG environment variable
20
+ - **NPM Package Info**: Automatically includes package name and version
21
+
22
+ ## Quick Start
23
+
24
+ ```typescript
25
+ import { configuration } from "@lindorm/config";
26
+ import { z } from "zod";
27
+
28
+ // Define your configuration schema
29
+ const config = configuration({
30
+ server: z.object({
31
+ port: z.number().default(3000),
32
+ host: z.string().default("localhost"),
33
+ }),
34
+ database: z.object({
35
+ url: z.string(),
36
+ poolSize: z.number().default(10),
37
+ }),
38
+ features: z.array(z.string()).default([]),
39
+ isProduction: z.boolean().default(false),
40
+ });
41
+
42
+ // Use your typed configuration
43
+ console.log(config.server.port); // number
44
+ console.log(config.database.url); // string
45
+ console.log(config.npm.package.name); // automatically added
46
+ ```
47
+
48
+ ## Configuration Sources
49
+
50
+ Configuration is loaded and merged from multiple sources in this order:
51
+
52
+ 1. **YAML Configuration Files** (`config/` directory)
53
+ 2. **Environment Variables** (automatic override)
54
+ 3. **NODE_CONFIG** environment variable (JSON object)
55
+ 4. **NPM Package Information** (name and version)
56
+
57
+ ### 1. YAML Configuration Files
58
+
59
+ Create a `config/` directory in your project root with environment-specific YAML files:
60
+
61
+ ```yaml
62
+ # config/default.yml
63
+ server:
64
+ port: 3000
65
+ host: localhost
66
+
67
+ database:
68
+ url: postgresql://localhost/myapp
69
+ pool_size: 10
70
+
71
+ features:
72
+ - feature1
73
+ - feature2
74
+
75
+ is_production: false
76
+ ```
77
+
78
+ ```yaml
79
+ # config/production.yml
80
+ server:
81
+ port: 8080
82
+ host: 0.0.0.0
83
+
84
+ database:
85
+ pool_size: 50
86
+
87
+ is_production: true
88
+ ```
89
+
90
+ Files are loaded based on NODE_ENV:
91
+ - `default.yml` - Always loaded first
92
+ - `{NODE_ENV}.yml` - Environment-specific overrides (e.g., `production.yml`)
93
+
94
+ ### 2. Environment Variables
95
+
96
+ Override any configuration value using environment variables. The package automatically converts between naming conventions:
97
+
98
+ ```bash
99
+ # Override server.port
100
+ SERVER_PORT=8080
101
+
102
+ # Override database.url
103
+ DATABASE_URL=postgresql://prod-server/myapp
104
+
105
+ # Override nested values
106
+ DATABASE_POOL_SIZE=50
107
+
108
+ # Arrays (JSON format)
109
+ FEATURES='["feature1", "feature2", "feature3"]'
110
+
111
+ # Booleans
112
+ IS_PRODUCTION=true
113
+ ```
114
+
115
+ **Naming Convention**:
116
+ - Nested keys are flattened with underscores
117
+ - camelCase becomes snake_case
118
+ - All uppercase for environment variables
119
+
120
+ Examples:
121
+ - `server.port` → `SERVER_PORT`
122
+ - `database.poolSize` → `DATABASE_POOL_SIZE`
123
+ - `nested.some.deepValue` → `NESTED_SOME_DEEP_VALUE`
124
+
125
+ ### 3. NODE_CONFIG
126
+
127
+ Pass configuration as a JSON string via NODE_CONFIG environment variable:
128
+
129
+ ```bash
130
+ NODE_CONFIG='{"server":{"port":9000},"features":["feat1","feat2"]}'
131
+ ```
132
+
133
+ ### 4. .env Files
134
+
135
+ The package automatically loads `.env` files using `@dotenvx/dotenvx`:
136
+
137
+ ```bash
138
+ # .env
139
+ DATABASE_URL=postgresql://localhost/myapp
140
+ SERVER_PORT=3000
141
+
142
+ # .env.production
143
+ DATABASE_URL=postgresql://prod-server/myapp
144
+ SERVER_PORT=8080
145
+ ```
146
+
147
+ Environment-specific `.env` files are loaded based on NODE_ENV:
148
+ - `.env` - Always loaded
149
+ - `.env.{NODE_ENV}` - Environment-specific overrides
150
+
151
+ ## Advanced Usage
152
+
153
+ ### Complex Schema with Defaults
154
+
155
+ ```typescript
156
+ import { configuration } from "@lindorm/config";
157
+ import { z } from "zod";
158
+
159
+ const config = configuration({
160
+ app: z.object({
161
+ name: z.string(),
162
+ version: z.string().optional(),
163
+ environment: z.enum(["development", "staging", "production"]),
164
+ }),
165
+
166
+ server: z.object({
167
+ port: z.number().min(1).max(65535),
168
+ host: z.string().ip(), // IP address validation
169
+ cors: z.object({
170
+ enabled: z.boolean().default(true),
171
+ origins: z.array(z.string().url()).default([]),
172
+ }),
173
+ }),
174
+
175
+ database: z.object({
176
+ primary: z.object({
177
+ host: z.string(),
178
+ port: z.number().default(5432),
179
+ name: z.string(),
180
+ user: z.string(),
181
+ password: z.string(),
182
+ ssl: z.boolean().default(false),
183
+ }),
184
+ replica: z.object({
185
+ host: z.string(),
186
+ port: z.number(),
187
+ }).optional(),
188
+ }),
189
+
190
+ redis: z.object({
191
+ url: z.string().url(),
192
+ ttl: z.number().default(3600),
193
+ }),
194
+
195
+ logging: z.object({
196
+ level: z.enum(["debug", "info", "warn", "error"]).default("info"),
197
+ format: z.enum(["json", "pretty"]).default("json"),
198
+ }),
199
+
200
+ features: z.record(z.boolean()).default({}),
201
+ });
202
+ ```
203
+
204
+ ### Using the Config Object
205
+
206
+ ```typescript
207
+ // Type-safe access to configuration
208
+ if (config.server.cors.enabled) {
209
+ app.use(cors({ origins: config.server.cors.origins }));
210
+ }
211
+
212
+ // Database connection
213
+ const dbConfig = {
214
+ host: config.database.primary.host,
215
+ port: config.database.primary.port,
216
+ database: config.database.primary.name,
217
+ user: config.database.primary.user,
218
+ password: config.database.primary.password,
219
+ ssl: config.database.primary.ssl,
220
+ };
221
+
222
+ // Feature flags
223
+ if (config.features.newDashboard) {
224
+ app.use("/dashboard", newDashboardRouter);
225
+ }
226
+
227
+ // Logging configuration
228
+ logger.setLevel(config.logging.level);
229
+ ```
230
+
231
+ ### Working with Arrays and Objects
232
+
233
+ Environment variables support JSON format for complex types:
234
+
235
+ ```bash
236
+ # Array of strings
237
+ CORS_ORIGINS='["https://app.example.com", "https://admin.example.com"]'
238
+
239
+ # Object
240
+ FEATURES='{"newDashboard": true, "betaApi": false}'
241
+
242
+ # Array of objects
243
+ SERVERS='[{"host": "server1.com", "port": 8080}, {"host": "server2.com", "port": 8081}]'
244
+ ```
245
+
246
+ ## CLI Tool
247
+
248
+ The package includes a CLI tool for working with configuration:
249
+
250
+ ### Convert Config to NODE_CONFIG
251
+
252
+ ```bash
253
+ # Create a .node_config file (JSON, YAML, or YML)
254
+ echo '{"server": {"port": 9000}}' > .node_config
255
+
256
+ # Generate NODE_CONFIG environment variable
257
+ npx config node_config
258
+ # Output: NODE_CONFIG={"server":{"port":9000}}
259
+
260
+ # Use in scripts
261
+ export $(npx config node_config)
262
+ ```
263
+
264
+ This is useful for:
265
+ - Docker containers
266
+ - CI/CD pipelines
267
+ - Deployment scripts
268
+
269
+ ## Best Practices
270
+
271
+ ### 1. Schema Definition
272
+
273
+ Define your schema in a separate file for reusability:
274
+
275
+ ```typescript
276
+ // config/schema.ts
277
+ import { z } from "zod";
278
+
279
+ export const configSchema = {
280
+ server: z.object({
281
+ port: z.number().default(3000),
282
+ host: z.string().default("localhost"),
283
+ }),
284
+ // ... rest of schema
285
+ };
286
+
287
+ // config/index.ts
288
+ import { configuration } from "@lindorm/config";
289
+ import { configSchema } from "./schema";
290
+
291
+ export const config = configuration(configSchema);
292
+ ```
293
+
294
+ ### 2. Environment-Specific Defaults
295
+
296
+ Use YAML files for environment-specific defaults:
297
+
298
+ ```yaml
299
+ # config/default.yml
300
+ logging:
301
+ level: debug
302
+ format: pretty
303
+
304
+ # config/production.yml
305
+ logging:
306
+ level: info
307
+ format: json
308
+ ```
309
+
310
+ ### 3. Secret Management
311
+
312
+ Never commit secrets to config files. Use environment variables:
313
+
314
+ ```yaml
315
+ # config/default.yml
316
+ database:
317
+ host: localhost
318
+ port: 5432
319
+ name: myapp
320
+ # DON'T put passwords here
321
+ ```
322
+
323
+ ```bash
324
+ # .env (add to .gitignore)
325
+ DATABASE_USER=myuser
326
+ DATABASE_PASSWORD=secret123
327
+ ```
328
+
329
+ ### 4. Validation
330
+
331
+ Use Zod's features for comprehensive validation:
332
+
333
+ ```typescript
334
+ const config = configuration({
335
+ email: z.string().email(),
336
+ port: z.number().min(1).max(65535),
337
+ url: z.string().url(),
338
+ apiKey: z.string().min(32),
339
+ retryAttempts: z.number().int().positive().max(10),
340
+ });
341
+ ```
342
+
343
+ ## Automatic Type Coercion
344
+
345
+ The package automatically converts string values to the correct types:
346
+
347
+ | Zod Type | Input | Output |
348
+ |----------|-------|--------|
349
+ | z.number() | "123" | 123 |
350
+ | z.boolean() | "true" | true |
351
+ | z.array() | '["a","b"]' | ["a", "b"] |
352
+ | z.object() | '{"a":1}' | { a: 1 } |
353
+ | z.bigint() | "9007199254740991" | 9007199254740991n |
354
+ | z.date() | "2023-01-01" | Date object |
355
+
356
+ ## NPM Package Information
357
+
358
+ The configuration automatically includes package information:
359
+
360
+ ```typescript
361
+ const config = configuration({ /* your schema */ });
362
+
363
+ console.log(config.npm.package.name); // from package.json
364
+ console.log(config.npm.package.version); // from package.json
365
+ ```
366
+
367
+ ## Error Handling
368
+
369
+ Configuration errors are thrown during initialization:
370
+
371
+ ```typescript
372
+ try {
373
+ const config = configuration({
374
+ required: z.string(), // No default
375
+ });
376
+ } catch (error) {
377
+ console.error("Configuration error:", error);
378
+ // Error will include details about missing required fields
379
+ }
380
+ ```
381
+
382
+ ## Testing
383
+
384
+ For testing, you can override configuration using NODE_ENV and environment variables:
385
+
386
+ ```typescript
387
+ // test/setup.ts
388
+ process.env.NODE_ENV = "test";
389
+ process.env.DATABASE_URL = "postgresql://localhost/test";
390
+ process.env.REDIS_URL = "redis://localhost:6379/1";
391
+ ```
392
+
393
+ Or create a `config/test.yml`:
394
+
395
+ ```yaml
396
+ database:
397
+ url: postgresql://localhost/test
398
+
399
+ redis:
400
+ url: redis://localhost:6379/1
401
+
402
+ logging:
403
+ level: error # Reduce noise in tests
404
+ ```
405
+
406
+ ## License
407
+
408
+ AGPL-3.0-or-later
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lindorm/config",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "license": "AGPL-3.0-or-later",
5
5
  "author": "Jonn Nilsson",
6
6
  "repository": {
@@ -33,9 +33,9 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@dotenvx/dotenvx": "^1.10.3",
36
- "@lindorm/case": "^0.1.8",
37
- "@lindorm/is": "^0.1.8",
38
- "@lindorm/utils": "^0.5.0",
36
+ "@lindorm/case": "^0.1.9",
37
+ "@lindorm/is": "^0.1.9",
38
+ "@lindorm/utils": "^0.5.2",
39
39
  "commander": "^13.1.0",
40
40
  "config": "^3.3.12",
41
41
  "dotenv": "^16.4.5",
@@ -43,9 +43,9 @@
43
43
  "zod": "^3.24.3"
44
44
  },
45
45
  "devDependencies": {
46
- "@lindorm/types": "^0.3.0",
46
+ "@lindorm/types": "^0.3.1",
47
47
  "@types/config": "^3.3.4",
48
48
  "@types/js-yaml": "^4.0.9"
49
49
  },
50
- "gitHead": "c1800f039a816f7ebce30379f8dce9c53ea9f5d1"
50
+ "gitHead": "9f254e41792b2ccc34c733c070f0686fb9a64209"
51
51
  }