@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/dist/index.js CHANGED
@@ -1,193 +1,35 @@
1
- // src/environment.ts
2
- var VALID_ENVIRONMENTS = new Set([
3
- "development",
4
- "production",
5
- "test"
6
- ]);
7
- var ENVIRONMENT_DEFAULTS = {
8
- development: {
9
- logLevel: "debug",
10
- verbose: true,
11
- errorDetail: "full"
12
- },
13
- production: {
14
- logLevel: null,
15
- verbose: false,
16
- errorDetail: "message"
17
- },
18
- test: {
19
- logLevel: null,
20
- verbose: false,
21
- errorDetail: "full"
22
- }
23
- };
24
- function getEnvironment() {
25
- const value = process.env["OUTFITTER_ENV"];
26
- if (value !== undefined && VALID_ENVIRONMENTS.has(value)) {
27
- return value;
28
- }
29
- return "production";
30
- }
31
- function getEnvironmentDefaults(env) {
32
- return { ...ENVIRONMENT_DEFAULTS[env] };
33
- }
34
- // src/env.ts
35
- import { z } from "zod";
36
- var portSchema = z.string().regex(/^\d+$/).transform(Number).pipe(z.number().int().positive().max(65535));
37
- var booleanSchema = z.enum(["true", "false", "1", "0", ""]).transform((val) => val === "true" || val === "1");
38
- var optionalBooleanSchema = z.string().optional().transform((val) => {
39
- if (val === undefined || val === "")
40
- return;
41
- return val === "true" || val === "1";
42
- });
43
- function parseEnv(schema, envObj = process.env) {
44
- return schema.parse(envObj);
45
- }
46
- var appEnvSchema = z.object({
47
- NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
48
- NO_COLOR: optionalBooleanSchema,
49
- FORCE_COLOR: optionalBooleanSchema,
50
- CI: optionalBooleanSchema,
51
- TERM: z.string().optional(),
52
- XDG_CONFIG_HOME: z.string().optional(),
53
- XDG_DATA_HOME: z.string().optional(),
54
- XDG_STATE_HOME: z.string().optional(),
55
- XDG_CACHE_HOME: z.string().optional(),
56
- HOME: z.string().optional()
57
- });
58
- var env = parseEnv(appEnvSchema);
59
- function getEnvBoolean(key) {
60
- const value = process.env[key];
61
- if (value === undefined || value === "")
62
- return;
63
- return value === "true" || value === "1";
64
- }
65
-
66
- // src/index.ts
67
- import { existsSync, readFileSync } from "node:fs";
68
- import { dirname, isAbsolute, join, resolve } from "node:path";
1
+ // @bun
69
2
  import {
70
- NotFoundError,
71
- Result,
72
- TaggedError,
73
- ValidationError
74
- } from "@outfitter/contracts";
75
- import { parse as parseToml } from "smol-toml";
76
- import { parse as parseYaml } from "yaml";
77
- var ParseErrorBase = TaggedError("ParseError")();
78
-
79
- class ParseError extends ParseErrorBase {
80
- category = "validation";
81
- }
82
- var CircularExtendsErrorBase = TaggedError("CircularExtendsError")();
3
+ booleanSchema,
4
+ env,
5
+ getEnvBoolean,
6
+ optionalBooleanSchema,
7
+ parseEnv,
8
+ portSchema
9
+ } from "./shared/@outfitter/config-443pb6p2.js";
10
+ import {
11
+ getEnvironment,
12
+ getEnvironmentDefaults
13
+ } from "./shared/@outfitter/config-w3pwcpr2.js";
14
+ import {
15
+ getCacheDir,
16
+ getConfigDir,
17
+ getDataDir,
18
+ getStateDir
19
+ } from "./shared/@outfitter/config-pf9xp78h.js";
20
+ import {
21
+ loadConfig
22
+ } from "./shared/@outfitter/config-br341dr7.js";
23
+ import"./shared/@outfitter/config-aje2en96.js";
24
+ import {
25
+ CircularExtendsError,
26
+ ParseError,
27
+ deepMerge,
28
+ parseConfigFile
29
+ } from "./shared/@outfitter/config-s4swz8m3.js";
83
30
 
84
- class CircularExtendsError extends CircularExtendsErrorBase {
85
- category = "validation";
86
- }
87
- function getConfigDir(appName) {
88
- const xdgConfigHome = process.env["XDG_CONFIG_HOME"];
89
- const home = process.env["HOME"] ?? "";
90
- const baseDir = xdgConfigHome ?? join(home, ".config");
91
- return join(baseDir, appName);
92
- }
93
- function getDataDir(appName) {
94
- const xdgDataHome = process.env["XDG_DATA_HOME"];
95
- const home = process.env["HOME"] ?? "";
96
- const baseDir = xdgDataHome ?? join(home, ".local", "share");
97
- return join(baseDir, appName);
98
- }
99
- function getCacheDir(appName) {
100
- const xdgCacheHome = process.env["XDG_CACHE_HOME"];
101
- const home = process.env["HOME"] ?? "";
102
- const baseDir = xdgCacheHome ?? join(home, ".cache");
103
- return join(baseDir, appName);
104
- }
105
- function getStateDir(appName) {
106
- const xdgStateHome = process.env["XDG_STATE_HOME"];
107
- const home = process.env["HOME"] ?? "";
108
- const baseDir = xdgStateHome ?? join(home, ".local", "state");
109
- return join(baseDir, appName);
110
- }
111
- function isPlainObject(value) {
112
- if (value === null || typeof value !== "object") {
113
- return false;
114
- }
115
- if (Array.isArray(value)) {
116
- return false;
117
- }
118
- return true;
119
- }
120
- function deepMerge(target, source) {
121
- const result = { ...target };
122
- for (const key of Object.keys(source)) {
123
- const sourceValue = source[key];
124
- const targetValue = result[key];
125
- if (sourceValue === undefined) {
126
- continue;
127
- }
128
- if (sourceValue === null) {
129
- result[key] = null;
130
- continue;
131
- }
132
- if (Array.isArray(sourceValue)) {
133
- result[key] = sourceValue;
134
- continue;
135
- }
136
- if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {
137
- result[key] = deepMerge(targetValue, sourceValue);
138
- continue;
139
- }
140
- result[key] = sourceValue;
141
- }
142
- return result;
143
- }
144
- function getExtension(filename) {
145
- const lastDot = filename.lastIndexOf(".");
146
- if (lastDot === -1) {
147
- return "";
148
- }
149
- return filename.slice(lastDot + 1).toLowerCase();
150
- }
151
- function parseConfigFile(content, filename) {
152
- const ext = getExtension(filename);
153
- try {
154
- switch (ext) {
155
- case "toml": {
156
- const parsed = parseToml(content);
157
- return Result.ok(parsed);
158
- }
159
- case "yaml":
160
- case "yml": {
161
- const parsed = parseYaml(content, { merge: true });
162
- if (parsed === null || typeof parsed !== "object") {
163
- return Result.ok({});
164
- }
165
- return Result.ok(parsed);
166
- }
167
- case "json": {
168
- const parsed = JSON.parse(content);
169
- return Result.ok(parsed);
170
- }
171
- case "jsonc":
172
- case "json5": {
173
- const parsed = Bun.JSON5.parse(content);
174
- return Result.ok(parsed);
175
- }
176
- default: {
177
- return Result.err(new ParseError({
178
- message: `Unsupported config file extension: .${ext}`,
179
- filename
180
- }));
181
- }
182
- }
183
- } catch (error) {
184
- const message = error instanceof Error ? error.message : "Unknown parse error";
185
- return Result.err(new ParseError({
186
- message: `Failed to parse ${filename}: ${message}`,
187
- filename
188
- }));
189
- }
190
- }
31
+ // packages/config/src/index.ts
32
+ import { formatZodIssues, Result, ValidationError } from "@outfitter/contracts";
191
33
  function resolveConfig(schema, sources) {
192
34
  let merged = {};
193
35
  if (sources.defaults) {
@@ -204,133 +46,15 @@ function resolveConfig(schema, sources) {
204
46
  }
205
47
  const parseResult = schema.safeParse(merged);
206
48
  if (!parseResult.success) {
207
- const issues = parseResult.error.issues;
208
- const firstIssue = issues[0];
209
- const path = firstIssue?.path?.join(".") ?? "";
210
- const message = firstIssue?.message ?? "Validation failed";
211
- const fullMessage = path ? `${path}: ${message}` : message;
49
+ const fullMessage = formatZodIssues(parseResult.error.issues);
50
+ const firstPath = parseResult.error.issues[0]?.path?.join(".");
212
51
  return Result.err(new ValidationError({
213
52
  message: fullMessage,
214
- ...path ? { field: path } : {}
53
+ ...firstPath ? { field: firstPath } : {}
215
54
  }));
216
55
  }
217
56
  return Result.ok(parseResult.data);
218
57
  }
219
- var CONFIG_EXTENSIONS = ["toml", "yaml", "yml", "json", "jsonc", "json5"];
220
- function findConfigFile(dir) {
221
- for (const ext of CONFIG_EXTENSIONS) {
222
- const filePath = join(dir, `config.${ext}`);
223
- if (existsSync(filePath)) {
224
- return filePath;
225
- }
226
- }
227
- return;
228
- }
229
- function getDefaultSearchPaths(appName) {
230
- const xdgConfigHome = process.env["XDG_CONFIG_HOME"];
231
- const home = process.env["HOME"] ?? "";
232
- const defaultConfigPath = join(home, ".config", appName);
233
- if (xdgConfigHome) {
234
- const xdgPath = join(xdgConfigHome, appName);
235
- if (xdgPath !== defaultConfigPath) {
236
- return [xdgPath, defaultConfigPath];
237
- }
238
- }
239
- return [defaultConfigPath];
240
- }
241
- function loadConfig(appName, schema, options) {
242
- const searchPaths = options?.searchPaths ? options.searchPaths.map((p) => join(p, appName)) : getDefaultSearchPaths(appName);
243
- let configFilePath;
244
- for (const searchPath of searchPaths) {
245
- const found = findConfigFile(searchPath);
246
- if (found) {
247
- configFilePath = found;
248
- break;
249
- }
250
- }
251
- if (!configFilePath) {
252
- return Result.err(new NotFoundError({
253
- message: `Configuration file not found for ${appName}`,
254
- resourceType: "config",
255
- resourceId: appName
256
- }));
257
- }
258
- const loadResult = loadConfigFileWithExtends(configFilePath);
259
- if (loadResult.isErr()) {
260
- return Result.err(loadResult.error);
261
- }
262
- const parsed = loadResult.unwrap();
263
- const validateResult = schema.safeParse(parsed);
264
- if (!validateResult.success) {
265
- const issues = validateResult.error.issues;
266
- const firstIssue = issues[0];
267
- const path = firstIssue?.path?.join(".") ?? "";
268
- const message = firstIssue?.message ?? "Validation failed";
269
- const fullMessage = path ? `${path}: ${message}` : message;
270
- return Result.err(new ValidationError({
271
- message: fullMessage,
272
- ...path ? { field: path } : {}
273
- }));
274
- }
275
- return Result.ok(validateResult.data);
276
- }
277
- function resolveExtendsPath(extendsValue, fromFile) {
278
- if (isAbsolute(extendsValue)) {
279
- return extendsValue;
280
- }
281
- return resolve(dirname(fromFile), extendsValue);
282
- }
283
- function loadConfigFileWithExtends(filePath, visited = new Set) {
284
- const normalizedPath = resolve(filePath);
285
- if (visited.has(normalizedPath)) {
286
- return Result.err(new CircularExtendsError({
287
- message: `Circular extends detected: ${[...visited, normalizedPath].join(" -> ")}`,
288
- chain: [...visited, normalizedPath]
289
- }));
290
- }
291
- if (!existsSync(filePath)) {
292
- return Result.err(new NotFoundError({
293
- message: `Config file not found: ${filePath}`,
294
- resourceType: "config",
295
- resourceId: filePath
296
- }));
297
- }
298
- let content;
299
- try {
300
- content = readFileSync(filePath, "utf-8");
301
- } catch {
302
- return Result.err(new NotFoundError({
303
- message: `Failed to read config file: ${filePath}`,
304
- resourceType: "config",
305
- resourceId: filePath
306
- }));
307
- }
308
- const filename = filePath.split("/").pop() ?? "config";
309
- const parseResult = parseConfigFile(content, filename);
310
- if (parseResult.isErr()) {
311
- return Result.err(parseResult.error);
312
- }
313
- const parsed = parseResult.unwrap();
314
- const extendsValue = parsed["extends"];
315
- if (extendsValue === undefined) {
316
- return Result.ok(parsed);
317
- }
318
- if (typeof extendsValue !== "string") {
319
- return Result.err(new ParseError({
320
- message: `Invalid "extends" value in ${filePath}: expected string, got ${typeof extendsValue}`,
321
- filename: filePath
322
- }));
323
- }
324
- visited.add(normalizedPath);
325
- const extendsPath = resolveExtendsPath(extendsValue, filePath);
326
- const baseResult = loadConfigFileWithExtends(extendsPath, visited);
327
- if (baseResult.isErr()) {
328
- return Result.err(baseResult.error);
329
- }
330
- const baseConfig = baseResult.unwrap();
331
- const { extends: __, ...currentConfig } = parsed;
332
- return Result.ok(deepMerge(baseConfig, currentConfig));
333
- }
334
58
  function mapEnvToConfig(prefix, _schema) {
335
59
  const result = {};
336
60
  const prefixWithUnderscore = `${prefix}_`;
@@ -0,0 +1,13 @@
1
+ import { CircularExtendsError, ParseError } from "../shared/@outfitter/config-sp6gradd.js";
2
+ import { NotFoundError, Result } from "@outfitter/contracts";
3
+ /**
4
+ * Resolve an extends path relative to the config file that contains it.
5
+ * @internal
6
+ */
7
+ declare function resolveExtendsPath(extendsValue: string, fromFile: string): string;
8
+ /**
9
+ * Load a config file and recursively resolve any extends references.
10
+ * @internal
11
+ */
12
+ declare function loadConfigFileWithExtends(filePath: string, visited?: Set<string>): Result<Record<string, unknown>, InstanceType<typeof NotFoundError> | InstanceType<typeof ParseError> | InstanceType<typeof CircularExtendsError>>;
13
+ export { resolveExtendsPath, loadConfigFileWithExtends };
@@ -0,0 +1,10 @@
1
+ // @bun
2
+ import {
3
+ loadConfigFileWithExtends,
4
+ resolveExtendsPath
5
+ } from "../shared/@outfitter/config-aje2en96.js";
6
+ import"../shared/@outfitter/config-s4swz8m3.js";
7
+ export {
8
+ resolveExtendsPath,
9
+ loadConfigFileWithExtends
10
+ };
@@ -0,0 +1,3 @@
1
+ import { LoadConfigOptions, loadConfig } from "../shared/@outfitter/config-7dyshh4r.js";
2
+ import "../shared/@outfitter/config-sp6gradd.js";
3
+ export { loadConfig, LoadConfigOptions };
@@ -0,0 +1,9 @@
1
+ // @bun
2
+ import {
3
+ loadConfig
4
+ } from "../shared/@outfitter/config-br341dr7.js";
5
+ import"../shared/@outfitter/config-aje2en96.js";
6
+ import"../shared/@outfitter/config-s4swz8m3.js";
7
+ export {
8
+ loadConfig
9
+ };
@@ -0,0 +1,2 @@
1
+ import { CircularExtendsError, ParseError, deepMerge, parseConfigFile } from "../shared/@outfitter/config-sp6gradd.js";
2
+ export { parseConfigFile, deepMerge, ParseError, CircularExtendsError };
@@ -0,0 +1,13 @@
1
+ // @bun
2
+ import {
3
+ CircularExtendsError,
4
+ ParseError,
5
+ deepMerge,
6
+ parseConfigFile
7
+ } from "../shared/@outfitter/config-s4swz8m3.js";
8
+ export {
9
+ parseConfigFile,
10
+ deepMerge,
11
+ ParseError,
12
+ CircularExtendsError
13
+ };
@@ -0,0 +1,2 @@
1
+ import { getCacheDir, getConfigDir, getDataDir, getStateDir } from "../shared/@outfitter/config-6449x3br.js";
2
+ export { getStateDir, getDataDir, getConfigDir, getCacheDir };
@@ -0,0 +1,13 @@
1
+ // @bun
2
+ import {
3
+ getCacheDir,
4
+ getConfigDir,
5
+ getDataDir,
6
+ getStateDir
7
+ } from "../shared/@outfitter/config-pf9xp78h.js";
8
+ export {
9
+ getStateDir,
10
+ getDataDir,
11
+ getConfigDir,
12
+ getCacheDir
13
+ };
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Get the XDG config directory for an application.
3
+ *
4
+ * Uses `XDG_CONFIG_HOME` if set, otherwise defaults to `~/.config`.
5
+ * This follows the XDG Base Directory Specification for storing
6
+ * user-specific configuration files.
7
+ *
8
+ * @param appName - Application name used as subdirectory
9
+ * @returns Absolute path to the application's config directory
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * // With XDG_CONFIG_HOME="/custom/config"
14
+ * getConfigDir("myapp"); // "/custom/config/myapp"
15
+ *
16
+ * // Without XDG_CONFIG_HOME (uses default)
17
+ * getConfigDir("myapp"); // "/home/user/.config/myapp"
18
+ * ```
19
+ */
20
+ declare function getConfigDir(appName: string): string;
21
+ /**
22
+ * Get the XDG data directory for an application.
23
+ *
24
+ * Uses `XDG_DATA_HOME` if set, otherwise defaults to `~/.local/share`.
25
+ * This follows the XDG Base Directory Specification for storing
26
+ * user-specific data files (databases, generated content, etc.).
27
+ *
28
+ * @param appName - Application name used as subdirectory
29
+ * @returns Absolute path to the application's data directory
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * // With XDG_DATA_HOME="/custom/data"
34
+ * getDataDir("myapp"); // "/custom/data/myapp"
35
+ *
36
+ * // Without XDG_DATA_HOME (uses default)
37
+ * getDataDir("myapp"); // "/home/user/.local/share/myapp"
38
+ * ```
39
+ */
40
+ declare function getDataDir(appName: string): string;
41
+ /**
42
+ * Get the XDG cache directory for an application.
43
+ *
44
+ * Uses `XDG_CACHE_HOME` if set, otherwise defaults to `~/.cache`.
45
+ * This follows the XDG Base Directory Specification for storing
46
+ * non-essential cached data that can be regenerated.
47
+ *
48
+ * @param appName - Application name used as subdirectory
49
+ * @returns Absolute path to the application's cache directory
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * // With XDG_CACHE_HOME="/custom/cache"
54
+ * getCacheDir("myapp"); // "/custom/cache/myapp"
55
+ *
56
+ * // Without XDG_CACHE_HOME (uses default)
57
+ * getCacheDir("myapp"); // "/home/user/.cache/myapp"
58
+ * ```
59
+ */
60
+ declare function getCacheDir(appName: string): string;
61
+ /**
62
+ * Get the XDG state directory for an application.
63
+ *
64
+ * Uses `XDG_STATE_HOME` if set, otherwise defaults to `~/.local/state`.
65
+ * This follows the XDG Base Directory Specification for storing
66
+ * state data that should persist between restarts (logs, history, etc.).
67
+ *
68
+ * @param appName - Application name used as subdirectory
69
+ * @returns Absolute path to the application's state directory
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * // With XDG_STATE_HOME="/custom/state"
74
+ * getStateDir("myapp"); // "/custom/state/myapp"
75
+ *
76
+ * // Without XDG_STATE_HOME (uses default)
77
+ * getStateDir("myapp"); // "/home/user/.local/state/myapp"
78
+ * ```
79
+ */
80
+ declare function getStateDir(appName: string): string;
81
+ export { getConfigDir, getDataDir, getCacheDir, getStateDir };
@@ -0,0 +1,105 @@
1
+ import { CircularExtendsError, ParseError } from "./config-sp6gradd.js";
2
+ import { NotFoundError, Result, ValidationError } from "@outfitter/contracts";
3
+ import { ZodSchema } from "zod";
4
+ /**
5
+ * Options for the {@link loadConfig} function.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const options: LoadConfigOptions = {
10
+ * searchPaths: ["/etc/myapp", "/opt/myapp/config"],
11
+ * };
12
+ * ```
13
+ */
14
+ interface LoadConfigOptions {
15
+ /**
16
+ * Custom search paths to check for config files.
17
+ * When provided, overrides the default XDG-based search paths.
18
+ * Note: `appName` is appended to each path (e.g., `"/etc/myapp"` becomes `"/etc/myapp/{appName}"`).
19
+ * Paths are searched in order; first match wins.
20
+ */
21
+ searchPaths?: string[];
22
+ }
23
+ /**
24
+ * Load configuration for an application from XDG-compliant paths.
25
+ *
26
+ * Search order (first found wins):
27
+ * 1. Custom `searchPaths` if provided in options
28
+ * 2. `$XDG_CONFIG_HOME/{appName}/config.{ext}`
29
+ * 3. `~/.config/{appName}/config.{ext}`
30
+ *
31
+ * File format preference: `.toml` > `.yaml` > `.yml` > `.json` > `.jsonc` > `.json5`
32
+ *
33
+ * When called without a schema, returns the raw parsed config as `unknown`.
34
+ * When called with a schema, returns the validated typed config.
35
+ *
36
+ * @param appName - Application name for XDG directory lookup
37
+ * @returns Result containing raw config or NotFoundError/ParseError/CircularExtendsError
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * // Without schema — returns raw parsed config
42
+ * const result = loadConfig("myapp");
43
+ * if (result.isOk()) {
44
+ * const config = result.value; // type: unknown
45
+ * }
46
+ * ```
47
+ */
48
+ declare function loadConfig(appName: string): Result<unknown, InstanceType<typeof NotFoundError> | InstanceType<typeof ParseError> | InstanceType<typeof CircularExtendsError>>;
49
+ /**
50
+ * Load configuration for an application from XDG-compliant paths.
51
+ *
52
+ * @param appName - Application name for XDG directory lookup
53
+ * @param options - Configuration options (custom search paths)
54
+ * @returns Result containing raw config or NotFoundError/ParseError/CircularExtendsError
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * // Without schema, with custom search paths
59
+ * const result = loadConfig("myapp", { searchPaths: ["/etc/myapp"] });
60
+ * ```
61
+ */
62
+ declare function loadConfig(appName: string, options: LoadConfigOptions): Result<unknown, InstanceType<typeof NotFoundError> | InstanceType<typeof ParseError> | InstanceType<typeof CircularExtendsError>>;
63
+ /**
64
+ * Load configuration for an application from XDG-compliant paths.
65
+ *
66
+ * @typeParam T - The configuration type (inferred from schema)
67
+ * @param appName - Application name for XDG directory lookup
68
+ * @param schema - Zod schema for validation
69
+ * @returns Result containing validated config or NotFoundError/ValidationError/ParseError/CircularExtendsError
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * import { loadConfig } from "@outfitter/config";
74
+ * import { z } from "zod";
75
+ *
76
+ * const AppConfigSchema = z.object({
77
+ * apiKey: z.string(),
78
+ * timeout: z.number().default(5000),
79
+ * });
80
+ *
81
+ * const result = loadConfig("myapp", AppConfigSchema);
82
+ * if (result.isOk()) {
83
+ * console.log(result.value.apiKey); // typed!
84
+ * }
85
+ * ```
86
+ */
87
+ declare function loadConfig<T>(appName: string, schema: ZodSchema<T>): Result<T, InstanceType<typeof NotFoundError> | InstanceType<typeof ValidationError> | InstanceType<typeof ParseError> | InstanceType<typeof CircularExtendsError>>;
88
+ /**
89
+ * Load configuration for an application from XDG-compliant paths.
90
+ *
91
+ * @typeParam T - The configuration type (inferred from schema)
92
+ * @param appName - Application name for XDG directory lookup
93
+ * @param schema - Zod schema for validation
94
+ * @param options - Configuration options (custom search paths)
95
+ * @returns Result containing validated config or NotFoundError/ValidationError/ParseError/CircularExtendsError
96
+ *
97
+ * @example
98
+ * ```typescript
99
+ * const result = loadConfig("myapp", AppConfigSchema, {
100
+ * searchPaths: ["/etc/myapp", "/opt/myapp/config"],
101
+ * });
102
+ * ```
103
+ */
104
+ 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>>;
105
+ export { LoadConfigOptions, loadConfig };