@outfitter/config 0.3.3 → 0.4.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.
package/README.md CHANGED
@@ -59,11 +59,13 @@ if (result.isOk()) {
59
59
  ```
60
60
 
61
61
  **Parameters:**
62
+
62
63
  - `appName` - Application name for XDG directory lookup
63
64
  - `schema` - Zod schema for validation
64
65
  - `options.searchPaths` - Custom search paths (overrides XDG defaults)
65
66
 
66
67
  **Search Order:**
68
+
67
69
  1. Custom `searchPaths` if provided
68
70
  2. `$XDG_CONFIG_HOME/{appName}/config.{ext}`
69
71
  3. `~/.config/{appName}/config.{ext}`
@@ -88,6 +90,7 @@ const result = resolveConfig(AppSchema, {
88
90
  ```
89
91
 
90
92
  **Parameters:**
93
+
91
94
  - `schema` - Zod schema for validation
92
95
  - `sources` - Configuration sources to merge
93
96
 
@@ -113,6 +116,7 @@ if (result.isOk()) {
113
116
  ```
114
117
 
115
118
  **Parameters:**
119
+
116
120
  - `content` - Raw file content
117
121
  - `filename` - Filename (extension determines parser)
118
122
 
@@ -179,6 +183,7 @@ const merged = deepMerge(defaults, overrides);
179
183
  ```
180
184
 
181
185
  **Merge Behavior:**
186
+
182
187
  - Recursively merges nested plain objects
183
188
  - Arrays are replaced (not concatenated)
184
189
  - `null` explicitly replaces the target value
@@ -194,10 +199,10 @@ Configuration sources for multi-layer resolution.
194
199
 
195
200
  ```typescript
196
201
  interface ConfigSources<T> {
197
- defaults?: Partial<T>; // Lowest precedence
198
- file?: Partial<T>; // From config file
199
- env?: Partial<T>; // Environment variables
200
- flags?: Partial<T>; // CLI flags (highest)
202
+ defaults?: Partial<T>; // Lowest precedence
203
+ file?: Partial<T>; // From config file
204
+ env?: Partial<T>; // Environment variables
205
+ flags?: Partial<T>; // CLI flags (highest)
201
206
  }
202
207
  ```
203
208
 
@@ -207,7 +212,7 @@ Options for `loadConfig()`.
207
212
 
208
213
  ```typescript
209
214
  interface LoadConfigOptions {
210
- searchPaths?: string[]; // Custom search paths
215
+ searchPaths?: string[]; // Custom search paths
211
216
  }
212
217
  ```
213
218
 
@@ -256,11 +261,11 @@ const prodDefaults = getEnvironmentDefaults("production");
256
261
  // { logLevel: null, verbose: false, errorDetail: "message" }
257
262
  ```
258
263
 
259
- | Setting | `development` | `production` | `test` |
260
- |---------|--------------|-------------|--------|
261
- | logLevel | `"debug"` | `null` | `null` |
262
- | verbose | `true` | `false` | `false` |
263
- | errorDetail | `"full"` | `"message"` | `"full"` |
264
+ | Setting | `development` | `production` | `test` |
265
+ | ----------- | ------------- | ------------ | -------- |
266
+ | logLevel | `"debug"` | `null` | `null` |
267
+ | verbose | `true` | `false` | `false` |
268
+ | errorDetail | `"full"` | `"message"` | `"full"` |
264
269
 
265
270
  ### Types
266
271
 
@@ -286,12 +291,12 @@ interface EnvironmentDefaults {
286
291
 
287
292
  This package follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) for locating configuration files.
288
293
 
289
- | Variable | macOS/Linux Default | Purpose |
290
- |----------|---------------------|---------|
291
- | `XDG_CONFIG_HOME` | `~/.config` | User-specific configuration |
292
- | `XDG_DATA_HOME` | `~/.local/share` | User-specific data files |
293
- | `XDG_CACHE_HOME` | `~/.cache` | Non-essential cached data |
294
- | `XDG_STATE_HOME` | `~/.local/state` | Persistent state (logs, history) |
294
+ | Variable | macOS/Linux Default | Purpose |
295
+ | ----------------- | ------------------- | -------------------------------- |
296
+ | `XDG_CONFIG_HOME` | `~/.config` | User-specific configuration |
297
+ | `XDG_DATA_HOME` | `~/.local/share` | User-specific data files |
298
+ | `XDG_CACHE_HOME` | `~/.cache` | Non-essential cached data |
299
+ | `XDG_STATE_HOME` | `~/.local/state` | Persistent state (logs, history) |
295
300
 
296
301
  ---
297
302
 
@@ -317,13 +322,13 @@ Higher precedence sources override lower ones. Nested objects are deep-merged.
317
322
 
318
323
  ## Supported File Formats
319
324
 
320
- | Extension | Parser | Notes |
321
- |-----------|--------|-------|
322
- | `.toml` | smol-toml | Preferred for configuration |
323
- | `.yaml`, `.yml` | yaml | YAML anchors/aliases supported |
324
- | `.json` | JSON.parse | Strict parsing |
325
- | `.jsonc` | json5 | JSON with comments and trailing commas |
326
- | `.json5` | json5 | Comments and trailing commas allowed |
325
+ | Extension | Parser | Notes |
326
+ | --------------- | ---------- | -------------------------------------- |
327
+ | `.toml` | smol-toml | Preferred for configuration |
328
+ | `.yaml`, `.yml` | yaml | YAML anchors/aliases supported |
329
+ | `.json` | JSON.parse | Strict parsing |
330
+ | `.jsonc` | json5 | JSON with comments and trailing commas |
331
+ | `.json5` | json5 | Comments and trailing commas allowed |
327
332
 
328
333
  ---
329
334
 
package/dist/index.d.ts CHANGED
@@ -1,443 +1,10 @@
1
- /**
2
- * Unified environment profiles for Outfitter packages.
3
- *
4
- * Provides a shared "environment" concept that cascades defaults
5
- * across all Outfitter packages. The environment is determined by
6
- * the `OUTFITTER_ENV` environment variable, falling back to
7
- * `"production"` when unset or invalid.
8
- *
9
- * @example
10
- * ```typescript
11
- * import { getEnvironment, getEnvironmentDefaults } from "@outfitter/config";
12
- *
13
- * const env = getEnvironment(); // "development" | "production" | "test"
14
- * const defaults = getEnvironmentDefaults(env);
15
- *
16
- * if (defaults.verbose) {
17
- * console.log("Verbose mode enabled");
18
- * }
19
- * ```
20
- *
21
- * @module
22
- */
23
- /**
24
- * Valid Outfitter environment names.
25
- *
26
- * - `"development"` — Local development with verbose output and debug logging
27
- * - `"production"` — Production deployments with minimal output
28
- * - `"test"` — Test runs with full error detail but no logging
29
- */
30
- type OutfitterEnv = "development" | "production" | "test";
31
- /**
32
- * Profile-specific defaults for an environment.
33
- *
34
- * These defaults provide sensible starting values that individual
35
- * packages can override or extend.
36
- */
37
- interface EnvironmentDefaults {
38
- /** How much error detail to include in output. */
39
- errorDetail: "full" | "message";
40
- /** Default log level. `null` means logging is disabled by default. */
41
- logLevel: "debug" | "info" | "warn" | "error" | null;
42
- /** Whether verbose output is enabled by default. */
43
- verbose: boolean;
44
- }
45
- /**
46
- * Determine the current Outfitter environment.
47
- *
48
- * Reads the `OUTFITTER_ENV` environment variable. If set to a valid
49
- * value (`"development"`, `"production"`, or `"test"`), returns that
50
- * value. Otherwise falls back to `"production"`.
51
- *
52
- * @returns The current environment
53
- *
54
- * @example
55
- * ```typescript
56
- * // With OUTFITTER_ENV=development
57
- * getEnvironment(); // "development"
58
- *
59
- * // With OUTFITTER_ENV unset or invalid
60
- * getEnvironment(); // "production"
61
- * ```
62
- */
63
- declare function getEnvironment(): OutfitterEnv;
64
- /**
65
- * Get the default settings for an environment profile.
66
- *
67
- * Returns a shallow copy of the defaults for the given environment.
68
- * These defaults are intended as starting values that individual
69
- * packages can override via their own configuration.
70
- *
71
- * | Setting | `development` | `production` | `test` |
72
- * |---------|--------------|-------------|--------|
73
- * | logLevel | `"debug"` | `null` | `null` |
74
- * | verbose | `true` | `false` | `false` |
75
- * | errorDetail | `"full"` | `"message"` | `"full"` |
76
- *
77
- * @param env - The environment to get defaults for
78
- * @returns Profile-specific default settings
79
- *
80
- * @example
81
- * ```typescript
82
- * const defaults = getEnvironmentDefaults("development");
83
- * // { logLevel: "debug", verbose: true, errorDetail: "full" }
84
- *
85
- * const prodDefaults = getEnvironmentDefaults("production");
86
- * // { logLevel: null, verbose: false, errorDetail: "message" }
87
- * ```
88
- */
89
- declare function getEnvironmentDefaults(env: OutfitterEnv): EnvironmentDefaults;
90
- import { z } from "zod";
91
- /**
92
- * Port number schema (1-65535) with string-to-number coercion.
93
- *
94
- * Validates that a string contains only digits, then transforms
95
- * to a number and validates the port range.
96
- *
97
- * @example
98
- * ```typescript
99
- * const schema = z.object({ PORT: portSchema });
100
- * schema.parse({ PORT: "3000" }); // { PORT: 3000 }
101
- * schema.parse({ PORT: "invalid" }); // throws
102
- * schema.parse({ PORT: "99999" }); // throws (out of range)
103
- * ```
104
- */
105
- declare const portSchema: z.ZodType<number, string>;
106
- /**
107
- * Boolean schema with proper string coercion.
108
- *
109
- * Accepts: "true", "false", "1", "0", ""
110
- * - "true" or "1" -> true
111
- * - "false", "0", or "" -> false
112
- *
113
- * @example
114
- * ```typescript
115
- * const schema = z.object({ DEBUG: booleanSchema });
116
- * schema.parse({ DEBUG: "true" }); // { DEBUG: true }
117
- * schema.parse({ DEBUG: "1" }); // { DEBUG: true }
118
- * schema.parse({ DEBUG: "false" }); // { DEBUG: false }
119
- * schema.parse({ DEBUG: "" }); // { DEBUG: false }
120
- * ```
121
- */
122
- declare const booleanSchema: z.ZodType<boolean, string>;
123
- /**
124
- * Optional boolean schema - returns undefined if not set.
125
- *
126
- * Unlike `booleanSchema`, this returns `undefined` for missing
127
- * or empty values, allowing callers to distinguish between
128
- * "explicitly set to false" and "not set".
129
- *
130
- * @example
131
- * ```typescript
132
- * const schema = z.object({ NO_COLOR: optionalBooleanSchema });
133
- * schema.parse({ NO_COLOR: "true" }); // { NO_COLOR: true }
134
- * schema.parse({ NO_COLOR: "" }); // { NO_COLOR: undefined }
135
- * schema.parse({ NO_COLOR: undefined }); // { NO_COLOR: undefined }
136
- * ```
137
- */
138
- declare const optionalBooleanSchema: z.ZodType<boolean | undefined, string | undefined>;
139
- /**
140
- * Parse and validate environment variables against a Zod schema.
141
- *
142
- * By default reads from `process.env`, but accepts a custom env
143
- * object for testing.
144
- *
145
- * @typeParam T - The Zod schema shape
146
- * @param schema - Zod object schema to validate against
147
- * @param envObj - Environment object (defaults to process.env)
148
- * @returns Validated and transformed environment object
149
- * @throws {z.ZodError} When validation fails
150
- *
151
- * @example
152
- * ```typescript
153
- * const AppEnv = z.object({
154
- * PORT: portSchema,
155
- * DEBUG: booleanSchema,
156
- * });
157
- *
158
- * const env = parseEnv(AppEnv);
159
- * console.log(env.PORT); // number
160
- * console.log(env.DEBUG); // boolean
161
- * ```
162
- */
163
- declare function parseEnv<T extends z.ZodRawShape>(schema: z.ZodObject<T>, envObj?: Record<string, string | undefined>): z.infer<z.ZodObject<T>>;
164
- type AppEnvShape = {
165
- NODE_ENV: z.ZodDefault<z.ZodEnum<{
166
- development: "development";
167
- test: "test";
168
- production: "production";
169
- }>>;
170
- NO_COLOR: typeof optionalBooleanSchema;
171
- FORCE_COLOR: typeof optionalBooleanSchema;
172
- CI: typeof optionalBooleanSchema;
173
- TERM: z.ZodOptional<z.ZodString>;
174
- XDG_CONFIG_HOME: z.ZodOptional<z.ZodString>;
175
- XDG_DATA_HOME: z.ZodOptional<z.ZodString>;
176
- XDG_STATE_HOME: z.ZodOptional<z.ZodString>;
177
- XDG_CACHE_HOME: z.ZodOptional<z.ZodString>;
178
- HOME: z.ZodOptional<z.ZodString>;
179
- };
180
- /**
181
- * Schema for common application environment variables.
182
- */
183
- declare const appEnvSchema: z.ZodObject<AppEnvShape>;
184
- /**
185
- * Type for the pre-parsed application environment.
186
- */
187
- type Env = z.infer<typeof appEnvSchema>;
188
- /**
189
- * Pre-parsed application environment.
190
- *
191
- * Access common environment variables with proper typing:
192
- * - `env.NODE_ENV`: "development" | "test" | "production"
193
- * - `env.NO_COLOR`: boolean | undefined
194
- * - `env.FORCE_COLOR`: boolean | undefined
195
- * - `env.CI`: boolean | undefined
196
- * - `env.TERM`: string | undefined
197
- * - `env.XDG_*`: string | undefined
198
- * - `env.HOME`: string | undefined
199
- *
200
- * @example
201
- * ```typescript
202
- * import { env } from "@outfitter/config";
203
- *
204
- * if (env.CI) {
205
- * console.log("Running in CI environment");
206
- * }
207
- *
208
- * if (env.NO_COLOR) {
209
- * // Disable color output
210
- * }
211
- * ```
212
- */
213
- declare const env: Env;
214
- /**
215
- * Reads an optional boolean from process.env at call time.
216
- *
217
- * Unlike `env.NO_COLOR` (which is static), this reads dynamically
218
- * for use cases where env vars may change at runtime (e.g., tests).
219
- *
220
- * @param key - The environment variable name to read
221
- * @returns `true` if "true"/"1", `false` if "false"/"0", `undefined` otherwise
222
- *
223
- * @example
224
- * ```typescript
225
- * // For terminal detection that needs dynamic behavior
226
- * if (getEnvBoolean("NO_COLOR")) {
227
- * // colors disabled
228
- * }
229
- * ```
230
- */
231
- declare function getEnvBoolean(key: "NO_COLOR" | "FORCE_COLOR" | "CI"): boolean | undefined;
232
- import { TaggedErrorClass } from "@outfitter/contracts";
233
- import { NotFoundError, Result, ValidationError } from "@outfitter/contracts";
1
+ import { Env, booleanSchema, env, getEnvBoolean, optionalBooleanSchema, parseEnv, portSchema } from "./shared/@outfitter/config-veqxf02x.js";
2
+ import { EnvironmentDefaults, OutfitterEnv, getEnvironment, getEnvironmentDefaults } from "./shared/@outfitter/config-wawavx3r.js";
3
+ import { getCacheDir, getConfigDir, getDataDir, getStateDir } from "./shared/@outfitter/config-6449x3br.js";
4
+ import { LoadConfigOptions, loadConfig } from "./shared/@outfitter/config-7dyshh4r.js";
5
+ import { CircularExtendsError, ParseError, deepMerge, parseConfigFile } from "./shared/@outfitter/config-sp6gradd.js";
6
+ import { Result, ValidationError } from "@outfitter/contracts";
234
7
  import { ZodSchema } from "zod";
235
- type ParseErrorFields = {
236
- /** Human-readable error message describing the parse failure */
237
- message: string;
238
- /** Name of the file that failed to parse */
239
- filename: string;
240
- /** Line number where the error occurred (if available) */
241
- line?: number;
242
- /** Column number where the error occurred (if available) */
243
- column?: number;
244
- };
245
- declare const ParseErrorBase: TaggedErrorClass<"ParseError", ParseErrorFields>;
246
- /**
247
- * Error thrown when a configuration file cannot be parsed.
248
- *
249
- * Contains details about the parse failure including the filename
250
- * and optionally the line/column where the error occurred.
251
- *
252
- * @example
253
- * ```typescript
254
- * const result = parseConfigFile("invalid toml [", "config.toml");
255
- * if (result.isErr() && result.error._tag === "ParseError") {
256
- * console.error(`Parse error in ${result.error.filename}: ${result.error.message}`);
257
- * }
258
- * ```
259
- */
260
- declare class ParseError extends ParseErrorBase {
261
- readonly category: "validation";
262
- }
263
- type CircularExtendsErrorFields = {
264
- /** Human-readable error message */
265
- message: string;
266
- /** The config file paths that form the circular reference */
267
- chain: string[];
268
- };
269
- declare const CircularExtendsErrorBase: TaggedErrorClass<"CircularExtendsError", CircularExtendsErrorFields>;
270
- /**
271
- * Error thrown when a circular extends reference is detected.
272
- */
273
- declare class CircularExtendsError extends CircularExtendsErrorBase {
274
- readonly category: "validation";
275
- }
276
- /**
277
- * Get the XDG config directory for an application.
278
- *
279
- * Uses `XDG_CONFIG_HOME` if set, otherwise defaults to `~/.config`.
280
- * This follows the XDG Base Directory Specification for storing
281
- * user-specific configuration files.
282
- *
283
- * @param appName - Application name used as subdirectory
284
- * @returns Absolute path to the application's config directory
285
- *
286
- * @example
287
- * ```typescript
288
- * // With XDG_CONFIG_HOME="/custom/config"
289
- * getConfigDir("myapp"); // "/custom/config/myapp"
290
- *
291
- * // Without XDG_CONFIG_HOME (uses default)
292
- * getConfigDir("myapp"); // "/home/user/.config/myapp"
293
- * ```
294
- */
295
- declare function getConfigDir(appName: string): string;
296
- /**
297
- * Get the XDG data directory for an application.
298
- *
299
- * Uses `XDG_DATA_HOME` if set, otherwise defaults to `~/.local/share`.
300
- * This follows the XDG Base Directory Specification for storing
301
- * user-specific data files (databases, generated content, etc.).
302
- *
303
- * @param appName - Application name used as subdirectory
304
- * @returns Absolute path to the application's data directory
305
- *
306
- * @example
307
- * ```typescript
308
- * // With XDG_DATA_HOME="/custom/data"
309
- * getDataDir("myapp"); // "/custom/data/myapp"
310
- *
311
- * // Without XDG_DATA_HOME (uses default)
312
- * getDataDir("myapp"); // "/home/user/.local/share/myapp"
313
- * ```
314
- */
315
- declare function getDataDir(appName: string): string;
316
- /**
317
- * Get the XDG cache directory for an application.
318
- *
319
- * Uses `XDG_CACHE_HOME` if set, otherwise defaults to `~/.cache`.
320
- * This follows the XDG Base Directory Specification for storing
321
- * non-essential cached data that can be regenerated.
322
- *
323
- * @param appName - Application name used as subdirectory
324
- * @returns Absolute path to the application's cache directory
325
- *
326
- * @example
327
- * ```typescript
328
- * // With XDG_CACHE_HOME="/custom/cache"
329
- * getCacheDir("myapp"); // "/custom/cache/myapp"
330
- *
331
- * // Without XDG_CACHE_HOME (uses default)
332
- * getCacheDir("myapp"); // "/home/user/.cache/myapp"
333
- * ```
334
- */
335
- declare function getCacheDir(appName: string): string;
336
- /**
337
- * Get the XDG state directory for an application.
338
- *
339
- * Uses `XDG_STATE_HOME` if set, otherwise defaults to `~/.local/state`.
340
- * This follows the XDG Base Directory Specification for storing
341
- * state data that should persist between restarts (logs, history, etc.).
342
- *
343
- * @param appName - Application name used as subdirectory
344
- * @returns Absolute path to the application's state directory
345
- *
346
- * @example
347
- * ```typescript
348
- * // With XDG_STATE_HOME="/custom/state"
349
- * getStateDir("myapp"); // "/custom/state/myapp"
350
- *
351
- * // Without XDG_STATE_HOME (uses default)
352
- * getStateDir("myapp"); // "/home/user/.local/state/myapp"
353
- * ```
354
- */
355
- declare function getStateDir(appName: string): string;
356
- /**
357
- * Deep merge two objects with configurable merge semantics.
358
- *
359
- * Merge behavior:
360
- * - Recursively merges nested plain objects
361
- * - Arrays are replaced (not concatenated)
362
- * - `null` explicitly replaces the target value
363
- * - `undefined` is skipped (does not override)
364
- *
365
- * @typeParam T - The type of the target object
366
- * @param target - Base object to merge into (not mutated)
367
- * @param source - Object with values to merge
368
- * @returns New object with merged values
369
- *
370
- * @example
371
- * ```typescript
372
- * const defaults = { server: { port: 3000, host: "localhost" } };
373
- * const overrides = { server: { port: 8080 } };
374
- *
375
- * const merged = deepMerge(defaults, overrides);
376
- * // { server: { port: 8080, host: "localhost" } }
377
- * ```
378
- *
379
- * @example
380
- * ```typescript
381
- * // Arrays replace, not merge
382
- * const target = { tags: ["a", "b"] };
383
- * const source = { tags: ["c"] };
384
- * deepMerge(target, source); // { tags: ["c"] }
385
- *
386
- * // undefined is skipped
387
- * const base = { a: 1, b: 2 };
388
- * deepMerge(base, { a: undefined, b: 3 }); // { a: 1, b: 3 }
389
- *
390
- * // null explicitly replaces
391
- * deepMerge(base, { a: null }); // { a: null, b: 2 }
392
- * ```
393
- */
394
- declare function deepMerge<T extends object>(target: T, source: Partial<T>): T;
395
- /**
396
- * Parse configuration file content based on filename extension.
397
- *
398
- * Supports multiple formats:
399
- * - `.toml` - Parsed with smol-toml (preferred for config)
400
- * - `.yaml`, `.yml` - Parsed with yaml (merge key support enabled)
401
- * - `.json` - Parsed with strict JSON.parse
402
- * - `.jsonc` - Parsed with json5 compatibility (comments/trailing commas)
403
- * - `.json5` - Parsed with json5 (comments and trailing commas allowed)
404
- *
405
- * @param content - Raw file content to parse
406
- * @param filename - Filename used to determine format (by extension)
407
- * @returns Result containing parsed object or ParseError
408
- *
409
- * @example
410
- * ```typescript
411
- * const toml = `
412
- * [server]
413
- * port = 3000
414
- * host = "localhost"
415
- * `;
416
- *
417
- * const result = parseConfigFile(toml, "config.toml");
418
- * if (result.isOk()) {
419
- * console.log(result.value.server.port); // 3000
420
- * }
421
- * ```
422
- *
423
- * @example
424
- * ```typescript
425
- * // YAML with anchors/aliases
426
- * const yaml = `
427
- * defaults: &defaults
428
- * timeout: 5000
429
- * server:
430
- * <<: *defaults
431
- * port: 3000
432
- * `;
433
- *
434
- * const result = parseConfigFile(yaml, "config.yaml");
435
- * if (result.isOk()) {
436
- * console.log(result.value.server.timeout); // 5000
437
- * }
438
- * ```
439
- */
440
- declare function parseConfigFile(content: string, filename: string): Result<Record<string, unknown>, InstanceType<typeof ParseError>>;
441
8
  /**
442
9
  * Configuration sources for multi-layer resolution.
443
10
  *
@@ -503,73 +70,6 @@ interface ConfigSources<T> {
503
70
  */
504
71
  declare function resolveConfig<T>(schema: ZodSchema<T>, sources: ConfigSources<T>): Result<T, InstanceType<typeof ValidationError> | InstanceType<typeof ParseError>>;
505
72
  /**
506
- * Options for the {@link loadConfig} function.
507
- *
508
- * @example
509
- * ```typescript
510
- * const options: LoadConfigOptions = {
511
- * searchPaths: ["/etc/myapp", "/opt/myapp/config"],
512
- * };
513
- * ```
514
- */
515
- interface LoadConfigOptions {
516
- /**
517
- * Custom search paths to check for config files.
518
- * When provided, overrides the default XDG-based search paths.
519
- * Paths are searched in order; first match wins.
520
- */
521
- searchPaths?: string[];
522
- }
523
- /**
524
- * Load configuration for an application from XDG-compliant paths.
525
- *
526
- * Search order (first found wins):
527
- * 1. Custom `searchPaths` if provided in options
528
- * 2. `$XDG_CONFIG_HOME/{appName}/config.{ext}`
529
- * 3. `~/.config/{appName}/config.{ext}`
530
- *
531
- * File format preference: `.toml` > `.yaml` > `.yml` > `.json` > `.jsonc` > `.json5`
532
- *
533
- * @typeParam T - The configuration type (inferred from schema)
534
- * @param appName - Application name for XDG directory lookup
535
- * @param schema - Zod schema for validation
536
- * @param options - Optional configuration (custom search paths)
537
- * @returns Result containing validated config or NotFoundError/ValidationError/ParseError
538
- *
539
- * @example
540
- * ```typescript
541
- * import { loadConfig } from "@outfitter/config";
542
- * import { z } from "zod";
543
- *
544
- * const AppConfigSchema = z.object({
545
- * apiKey: z.string(),
546
- * timeout: z.number().default(5000),
547
- * features: z.object({
548
- * darkMode: z.boolean().default(false),
549
- * }),
550
- * });
551
- *
552
- * // Searches ~/.config/myapp/config.{toml,yaml,json,...}
553
- * const result = await loadConfig("myapp", AppConfigSchema);
554
- *
555
- * if (result.isOk()) {
556
- * console.log("API Key:", result.value.apiKey);
557
- * console.log("Timeout:", result.value.timeout);
558
- * } else {
559
- * console.error("Failed to load config:", result.error.message);
560
- * }
561
- * ```
562
- *
563
- * @example
564
- * ```typescript
565
- * // With custom search paths
566
- * const result = await loadConfig("myapp", AppConfigSchema, {
567
- * searchPaths: ["/etc/myapp", "/opt/myapp/config"],
568
- * });
569
- * ```
570
- */
571
- declare function loadConfig<T>(appName: string, schema: ZodSchema<T>, options?: LoadConfigOptions): Result<T, InstanceType<typeof NotFoundError> | InstanceType<typeof ValidationError> | InstanceType<typeof ParseError> | InstanceType<typeof CircularExtendsError>>;
572
- /**
573
73
  * Map environment variables to config object based on prefix.
574
74
  *
575
75
  * Environment variables are mapped as follows: