@utilarium/cardigantime 0.0.24-dev.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 (89) hide show
  1. package/LICENSE +65 -0
  2. package/README.md +398 -0
  3. package/dist/cardigantime.cjs +2169 -0
  4. package/dist/cardigantime.cjs.map +1 -0
  5. package/dist/cardigantime.d.ts +92 -0
  6. package/dist/cardigantime.js +198 -0
  7. package/dist/cardigantime.js.map +1 -0
  8. package/dist/config/executable-security.d.ts +32 -0
  9. package/dist/config/format-detector.d.ts +59 -0
  10. package/dist/configure.d.ts +55 -0
  11. package/dist/configure.js +125 -0
  12. package/dist/configure.js.map +1 -0
  13. package/dist/constants.d.ts +25 -0
  14. package/dist/constants.js +38 -0
  15. package/dist/constants.js.map +1 -0
  16. package/dist/discovery/discoverer.d.ts +62 -0
  17. package/dist/discovery/hierarchical-modes.d.ts +64 -0
  18. package/dist/discovery/index.d.ts +15 -0
  19. package/dist/discovery/patterns.d.ts +77 -0
  20. package/dist/discovery/root-detection.d.ts +100 -0
  21. package/dist/discovery/traversal-security.d.ts +106 -0
  22. package/dist/env/errors.d.ts +18 -0
  23. package/dist/env/index.d.ts +7 -0
  24. package/dist/env/naming.d.ts +38 -0
  25. package/dist/env/parser.d.ts +61 -0
  26. package/dist/env/reader.d.ts +45 -0
  27. package/dist/env/resolver.d.ts +25 -0
  28. package/dist/env/schema-utils.d.ts +33 -0
  29. package/dist/env/types.d.ts +43 -0
  30. package/dist/error/ArgumentError.d.ts +31 -0
  31. package/dist/error/ArgumentError.js +48 -0
  32. package/dist/error/ArgumentError.js.map +1 -0
  33. package/dist/error/ConfigParseError.d.ts +26 -0
  34. package/dist/error/ConfigurationError.d.ts +21 -0
  35. package/dist/error/ConfigurationError.js +46 -0
  36. package/dist/error/ConfigurationError.js.map +1 -0
  37. package/dist/error/FileSystemError.d.ts +30 -0
  38. package/dist/error/FileSystemError.js +58 -0
  39. package/dist/error/FileSystemError.js.map +1 -0
  40. package/dist/error/index.d.ts +4 -0
  41. package/dist/mcp/discovery.d.ts +105 -0
  42. package/dist/mcp/errors.d.ts +75 -0
  43. package/dist/mcp/index.d.ts +22 -0
  44. package/dist/mcp/integration.d.ts +184 -0
  45. package/dist/mcp/parser.d.ts +141 -0
  46. package/dist/mcp/resolver.d.ts +165 -0
  47. package/dist/mcp/tools/check-config-types.d.ts +208 -0
  48. package/dist/mcp/tools/check-config.d.ts +85 -0
  49. package/dist/mcp/tools/index.d.ts +12 -0
  50. package/dist/mcp/types.d.ts +210 -0
  51. package/dist/parsers/index.d.ts +25 -0
  52. package/dist/parsers/javascript-parser.d.ts +12 -0
  53. package/dist/parsers/json-parser.d.ts +6 -0
  54. package/dist/parsers/typescript-parser.d.ts +15 -0
  55. package/dist/parsers/yaml-parser.d.ts +6 -0
  56. package/dist/read.d.ts +56 -0
  57. package/dist/read.js +653 -0
  58. package/dist/read.js.map +1 -0
  59. package/dist/security/audit-logger.d.ts +135 -0
  60. package/dist/security/cli-validator.d.ts +73 -0
  61. package/dist/security/config-validator.d.ts +95 -0
  62. package/dist/security/defaults.d.ts +17 -0
  63. package/dist/security/index.d.ts +14 -0
  64. package/dist/security/numeric-guard.d.ts +111 -0
  65. package/dist/security/path-guard.d.ts +53 -0
  66. package/dist/security/profiles.d.ts +127 -0
  67. package/dist/security/security-validator.d.ts +109 -0
  68. package/dist/security/string-guard.d.ts +92 -0
  69. package/dist/security/types.d.ts +126 -0
  70. package/dist/security/zod-secure-enum.d.ts +20 -0
  71. package/dist/security/zod-secure-number.d.ts +39 -0
  72. package/dist/security/zod-secure-path.d.ts +24 -0
  73. package/dist/security/zod-secure-string.d.ts +38 -0
  74. package/dist/types.d.ts +584 -0
  75. package/dist/types.js +56 -0
  76. package/dist/types.js.map +1 -0
  77. package/dist/util/hierarchical.d.ts +136 -0
  78. package/dist/util/hierarchical.js +436 -0
  79. package/dist/util/hierarchical.js.map +1 -0
  80. package/dist/util/schema-defaults.d.ts +80 -0
  81. package/dist/util/schema-defaults.js +118 -0
  82. package/dist/util/schema-defaults.js.map +1 -0
  83. package/dist/util/storage.d.ts +31 -0
  84. package/dist/util/storage.js +154 -0
  85. package/dist/util/storage.js.map +1 -0
  86. package/dist/validate.d.ts +113 -0
  87. package/dist/validate.js +260 -0
  88. package/dist/validate.js.map +1 -0
  89. package/package.json +84 -0
@@ -0,0 +1,62 @@
1
+ import { ConfigDiscoveryOptions, DiscoveryResult, Logger } from '../types';
2
+ /**
3
+ * Discovers configuration files in a directory using multiple naming patterns.
4
+ *
5
+ * Checks patterns in priority order and returns the first match.
6
+ * If `warnOnMultipleConfigs` is enabled (default), continues scanning after
7
+ * the first match to detect and warn about additional config files.
8
+ *
9
+ * @param directory - Directory to search for configuration files
10
+ * @param options - Discovery options including app name and patterns
11
+ * @param logger - Optional logger for debug/info/warn messages
12
+ * @returns Discovery result containing the found config and any warnings
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const result = await discoverConfig('/path/to/project', {
17
+ * appName: 'myapp',
18
+ * extensions: ['yaml', 'json'],
19
+ * });
20
+ *
21
+ * if (result.config) {
22
+ * console.log(`Found config: ${result.config.absolutePath}`);
23
+ * }
24
+ *
25
+ * if (result.multipleConfigWarning) {
26
+ * console.warn(`Multiple configs found. Using ${result.multipleConfigWarning.used.path}`);
27
+ * }
28
+ * ```
29
+ */
30
+ export declare function discoverConfig(directory: string, options: ConfigDiscoveryOptions, logger?: Logger): Promise<DiscoveryResult>;
31
+ /**
32
+ * Discovers configuration files across multiple directories.
33
+ * Useful for hierarchical configuration where multiple directories may contain config files.
34
+ *
35
+ * @param directories - Directories to search, in order of precedence (first = highest)
36
+ * @param options - Discovery options
37
+ * @param logger - Optional logger
38
+ * @returns Array of discovery results, one per directory that had a config
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const results = await discoverConfigsInHierarchy(
43
+ * ['/project/subdir', '/project', '/home/user'],
44
+ * { appName: 'myapp' }
45
+ * );
46
+ *
47
+ * // results[0] = config from /project/subdir (if exists)
48
+ * // results[1] = config from /project (if exists)
49
+ * // etc.
50
+ * ```
51
+ */
52
+ export declare function discoverConfigsInHierarchy(directories: string[], options: ConfigDiscoveryOptions, logger?: Logger): Promise<DiscoveryResult[]>;
53
+ /**
54
+ * Quickly checks if any config file exists in a directory.
55
+ * More efficient than `discoverConfig` when you only need to know if a config exists,
56
+ * not which one it is.
57
+ *
58
+ * @param directory - Directory to check
59
+ * @param options - Discovery options
60
+ * @returns True if any config file exists
61
+ */
62
+ export declare function hasConfigFile(directory: string, options: ConfigDiscoveryOptions): Promise<boolean>;
@@ -0,0 +1,64 @@
1
+ import { HierarchicalMode, HierarchicalOptions, ConfigDiscoveryOptions, DiscoveredConfig, Logger } from '../types';
2
+ /**
3
+ * Result of hierarchical config discovery with mode awareness.
4
+ */
5
+ export interface HierarchicalDiscoveryResult {
6
+ /** The mode that was used for discovery */
7
+ mode: HierarchicalMode;
8
+ /** Primary config (if found) */
9
+ primaryConfig: DiscoveredConfig | null;
10
+ /** All configs found during traversal (for 'enabled' mode) */
11
+ configs: DiscoveredConfig[];
12
+ /** Directories that were searched */
13
+ searchedDirectories: string[];
14
+ /** Whether hierarchical loading should occur */
15
+ shouldMerge: boolean;
16
+ }
17
+ /**
18
+ * Resolves hierarchical options with defaults.
19
+ *
20
+ * @param options - User-provided options
21
+ * @returns Resolved options with defaults applied
22
+ */
23
+ export declare function resolveHierarchicalOptions(options?: Partial<HierarchicalOptions>): Required<HierarchicalOptions>;
24
+ /**
25
+ * Discovers configuration files using the specified hierarchical mode.
26
+ *
27
+ * @param startPath - Starting directory for discovery
28
+ * @param discoveryOptions - Config discovery options (app name, patterns, etc.)
29
+ * @param hierarchicalOptions - Hierarchical mode options
30
+ * @param logger - Optional logger
31
+ * @returns Hierarchical discovery result
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * // Disabled mode - only check starting directory
36
+ * const result = await discoverWithMode('/project/src',
37
+ * { appName: 'myapp' },
38
+ * { mode: 'disabled' }
39
+ * );
40
+ *
41
+ * // Enabled mode - full hierarchical traversal
42
+ * const result = await discoverWithMode('/project/src',
43
+ * { appName: 'myapp' },
44
+ * { mode: 'enabled', maxDepth: 5 }
45
+ * );
46
+ * ```
47
+ */
48
+ export declare function discoverWithMode(startPath: string, discoveryOptions: ConfigDiscoveryOptions, hierarchicalOptions?: Partial<HierarchicalOptions>, logger?: Logger): Promise<HierarchicalDiscoveryResult>;
49
+ /**
50
+ * Checks if a config content specifies a hierarchical mode override.
51
+ * Configs can set `hierarchical.mode: disabled` to prevent parent merging.
52
+ *
53
+ * @param configContent - Parsed config content
54
+ * @returns The override mode if specified, undefined otherwise
55
+ */
56
+ export declare function getHierarchicalModeOverride(configContent: unknown): HierarchicalMode | undefined;
57
+ /**
58
+ * Gets hierarchical options from a config content.
59
+ * Extracts any hierarchical settings from the config.
60
+ *
61
+ * @param configContent - Parsed config content
62
+ * @returns Partial hierarchical options, or undefined if none
63
+ */
64
+ export declare function getHierarchicalOptionsFromConfig(configContent: unknown): Partial<HierarchicalOptions> | undefined;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Configuration Discovery Module
3
+ *
4
+ * Provides functionality for discovering configuration files in various
5
+ * standard locations using customizable naming patterns.
6
+ *
7
+ * @module discovery
8
+ */
9
+ export { STANDARD_PATTERNS, DEFAULT_EXTENSIONS, expandPattern, getDiscoveryPaths, } from './patterns';
10
+ export { discoverConfig, discoverConfigsInHierarchy, hasConfigFile, } from './discoverer';
11
+ export { isProjectRoot, findProjectRoot, shouldStopAt, walkUpToRoot, getDirectoriesToRoot, } from './root-detection';
12
+ export type { RootDetectionResult } from './root-detection';
13
+ export { discoverWithMode, resolveHierarchicalOptions, getHierarchicalModeOverride, getHierarchicalOptionsFromConfig, } from './hierarchical-modes';
14
+ export type { HierarchicalDiscoveryResult } from './hierarchical-modes';
15
+ export { DEFAULT_TRAVERSAL_BOUNDARY, expandEnvironmentVariables, normalizePath, getPathDepth, isPathWithin, isPathAtOrAbove, checkTraversalBoundary, resolveTraversalBoundary, createBoundaryChecker, filterAllowedPaths, } from './traversal-security';
@@ -0,0 +1,77 @@
1
+ import { ConfigNamingPattern } from '../types';
2
+ /**
3
+ * Standard configuration file naming patterns.
4
+ *
5
+ * These patterns cover the most common conventions used by modern JavaScript tools:
6
+ *
7
+ * 1. **Modern explicit pattern** (`{app}.config.{ext}`) - Used by Vite, Next.js, etc.
8
+ * 2. **Short explicit pattern** (`{app}.conf.{ext}`) - Unix-style configuration
9
+ * 3. **Hidden directory pattern** (`.{app}/config.{ext}`) - Current CardiganTime default
10
+ * 4. **RC file with extension** (`.{app}rc.{ext}`) - ESLint legacy, Babel
11
+ * 5. **RC file without extension** (`.{app}rc`) - Prettier, npm
12
+ *
13
+ * Patterns are ordered by priority (lower = checked first). This order prefers:
14
+ * - Visible files over hidden files (easier to discover)
15
+ * - Explicit naming over implicit (clearer intent)
16
+ * - Modern conventions over legacy conventions
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * import { STANDARD_PATTERNS, expandPattern } from './patterns';
21
+ *
22
+ * // List all patterns for 'protokoll' app with YAML extension
23
+ * const files = STANDARD_PATTERNS.map(p =>
24
+ * expandPattern(p.pattern, 'protokoll', 'yaml')
25
+ * );
26
+ * // ['protokoll.config.yaml', 'protokoll.conf.yaml', '.protokoll/config.yaml', ...]
27
+ * ```
28
+ */
29
+ export declare const STANDARD_PATTERNS: ConfigNamingPattern[];
30
+ /**
31
+ * Expands a naming pattern into an actual file path segment.
32
+ *
33
+ * @param pattern - The pattern template with placeholders
34
+ * @param appName - The application name to substitute for `{app}`
35
+ * @param extension - The file extension to substitute for `{ext}` (optional)
36
+ * @returns The expanded file path segment
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * expandPattern('{app}.config.{ext}', 'myapp', 'yaml');
41
+ * // Returns: 'myapp.config.yaml'
42
+ *
43
+ * expandPattern('.{app}rc', 'myapp');
44
+ * // Returns: '.myapprc'
45
+ *
46
+ * expandPattern('.{app}/config.{ext}', 'protokoll', 'json');
47
+ * // Returns: '.protokoll/config.json'
48
+ * ```
49
+ */
50
+ export declare function expandPattern(pattern: string, appName: string, extension?: string): string;
51
+ /**
52
+ * Gets all file paths to check for a given app name and extensions.
53
+ * Expands all standard patterns with the provided extensions.
54
+ *
55
+ * @param appName - The application name
56
+ * @param extensions - Array of file extensions to search for
57
+ * @param options - Optional configuration
58
+ * @param options.includeHidden - Whether to include hidden file patterns (default: true)
59
+ * @param options.patterns - Custom patterns to use instead of STANDARD_PATTERNS
60
+ * @returns Array of file paths to check, ordered by priority
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const paths = getDiscoveryPaths('myapp', ['yaml', 'json']);
65
+ * // Returns (in priority order):
66
+ * // ['myapp.config.yaml', 'myapp.config.json', 'myapp.conf.yaml', ...]
67
+ * ```
68
+ */
69
+ export declare function getDiscoveryPaths(appName: string, extensions: string[], options?: {
70
+ includeHidden?: boolean;
71
+ patterns?: ConfigNamingPattern[];
72
+ }): string[];
73
+ /**
74
+ * Default file extensions supported for configuration discovery.
75
+ * Ordered by priority (TypeScript > JavaScript > JSON > YAML).
76
+ */
77
+ export declare const DEFAULT_EXTENSIONS: string[];
@@ -0,0 +1,100 @@
1
+ import { RootMarker, Logger } from '../types';
2
+ /**
3
+ * Result of root detection operation.
4
+ */
5
+ export interface RootDetectionResult {
6
+ /** Whether a root was found */
7
+ found: boolean;
8
+ /** Path to the detected root directory (if found) */
9
+ rootPath?: string;
10
+ /** The marker that triggered root detection (if found) */
11
+ matchedMarker?: RootMarker;
12
+ }
13
+ /**
14
+ * Checks if a directory is a project root based on the presence of root markers.
15
+ *
16
+ * @param directory - Directory to check
17
+ * @param markers - Root markers to look for (defaults to DEFAULT_ROOT_MARKERS)
18
+ * @param logger - Optional logger for debug output
19
+ * @returns True if the directory contains any of the root markers
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const isRoot = await isProjectRoot('/path/to/dir');
24
+ * // Returns true if directory contains package.json, .git, etc.
25
+ * ```
26
+ */
27
+ export declare function isProjectRoot(directory: string, markers?: RootMarker[], logger?: Logger): Promise<boolean>;
28
+ /**
29
+ * Finds the project root by walking up from the starting directory.
30
+ *
31
+ * @param startPath - Starting directory for the search
32
+ * @param markers - Root markers to look for (defaults to DEFAULT_ROOT_MARKERS)
33
+ * @param maxDepth - Maximum number of directories to traverse (default: 20)
34
+ * @param logger - Optional logger for debug output
35
+ * @returns Detection result with the root path if found
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const result = await findProjectRoot('/path/to/deep/nested/dir');
40
+ * if (result.found) {
41
+ * console.log(`Project root: ${result.rootPath}`);
42
+ * console.log(`Detected by: ${result.matchedMarker?.name}`);
43
+ * }
44
+ * ```
45
+ */
46
+ export declare function findProjectRoot(startPath: string, markers?: RootMarker[], maxDepth?: number, logger?: Logger): Promise<RootDetectionResult>;
47
+ /**
48
+ * Checks if a directory name is in the stop-at list.
49
+ *
50
+ * @param directory - Directory path to check
51
+ * @param stopAtNames - List of directory names to stop at
52
+ * @returns True if the directory should stop traversal
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * const shouldStop = shouldStopAt('/path/to/node_modules/pkg', ['node_modules', 'vendor']);
57
+ * // Returns false (parent 'node_modules' triggers stop, but current dir is 'pkg')
58
+ *
59
+ * const shouldStop2 = shouldStopAt('/path/to/node_modules', ['node_modules', 'vendor']);
60
+ * // Returns true (current directory is 'node_modules')
61
+ * ```
62
+ */
63
+ export declare function shouldStopAt(directory: string, stopAtNames: string[]): boolean;
64
+ /**
65
+ * Walks up the directory tree, checking each directory against root markers and stop conditions.
66
+ * Yields each directory until a stop condition is met.
67
+ *
68
+ * @param startPath - Starting directory
69
+ * @param options - Walk options
70
+ * @param logger - Optional logger
71
+ * @yields Directory paths from start to root/stop condition
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * for await (const dir of walkUpToRoot('/path/to/start', { maxDepth: 5 })) {
76
+ * console.log(`Processing: ${dir}`);
77
+ * }
78
+ * ```
79
+ */
80
+ export declare function walkUpToRoot(startPath: string, options?: {
81
+ maxDepth?: number;
82
+ rootMarkers?: RootMarker[];
83
+ stopAt?: string[];
84
+ stopAtRoot?: boolean;
85
+ }, logger?: Logger): AsyncGenerator<string, void, undefined>;
86
+ /**
87
+ * Gets all directories from start to root (or stop condition) as an array.
88
+ * Convenience wrapper around walkUpToRoot for when you need all directories at once.
89
+ *
90
+ * @param startPath - Starting directory
91
+ * @param options - Walk options
92
+ * @param logger - Optional logger
93
+ * @returns Array of directory paths
94
+ */
95
+ export declare function getDirectoriesToRoot(startPath: string, options?: {
96
+ maxDepth?: number;
97
+ rootMarkers?: RootMarker[];
98
+ stopAt?: string[];
99
+ stopAtRoot?: boolean;
100
+ }, logger?: Logger): Promise<string[]>;
@@ -0,0 +1,106 @@
1
+ import { TraversalBoundary, TraversalCheckResult, TraversalSecurityOptions, Logger } from '../types';
2
+ /**
3
+ * Default traversal boundaries.
4
+ * These provide safe defaults for most use cases.
5
+ */
6
+ export declare const DEFAULT_TRAVERSAL_BOUNDARY: TraversalBoundary;
7
+ /**
8
+ * Expands environment variable placeholders in a path.
9
+ * Supports $HOME, $USER, and $TMPDIR.
10
+ *
11
+ * @param pathStr - Path string with potential variable placeholders
12
+ * @returns Expanded path string
13
+ */
14
+ export declare function expandEnvironmentVariables(pathStr: string): string;
15
+ /**
16
+ * Normalizes a path for comparison.
17
+ * Resolves to absolute path and normalizes separators.
18
+ *
19
+ * @param pathStr - Path to normalize
20
+ * @returns Normalized absolute path
21
+ */
22
+ export declare function normalizePath(pathStr: string): string;
23
+ /**
24
+ * Calculates the depth of a path (number of segments from root).
25
+ *
26
+ * @param pathStr - Absolute path
27
+ * @returns Number of path segments
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * getPathDepth('/'); // 0
32
+ * getPathDepth('/home'); // 1
33
+ * getPathDepth('/home/user/project'); // 3
34
+ * ```
35
+ */
36
+ export declare function getPathDepth(pathStr: string): number;
37
+ /**
38
+ * Checks if a path is at or within a boundary path.
39
+ *
40
+ * @param checkPath - Path to check
41
+ * @param boundaryPath - Boundary path
42
+ * @returns True if checkPath is at or within boundaryPath
43
+ */
44
+ export declare function isPathWithin(checkPath: string, boundaryPath: string): boolean;
45
+ /**
46
+ * Checks if a path is at or above a boundary path.
47
+ * Used to check if traversal would go beyond soft boundaries.
48
+ *
49
+ * @param checkPath - Path to check
50
+ * @param boundaryPath - Boundary path
51
+ * @returns True if checkPath is at or above (parent of) boundaryPath
52
+ */
53
+ export declare function isPathAtOrAbove(checkPath: string, boundaryPath: string): boolean;
54
+ /**
55
+ * Checks if a path is allowed according to traversal boundaries.
56
+ *
57
+ * @param pathToCheck - Path to check
58
+ * @param boundary - Traversal boundaries to enforce
59
+ * @param startPath - Optional starting path for relative depth calculation
60
+ * @returns Check result with allowed status and reason
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const result = checkTraversalBoundary('/etc/passwd', DEFAULT_TRAVERSAL_BOUNDARY);
65
+ * if (!result.allowed) {
66
+ * console.error(`Access denied: ${result.reason}`);
67
+ * }
68
+ * ```
69
+ */
70
+ export declare function checkTraversalBoundary(pathToCheck: string, boundary: TraversalBoundary, startPath?: string): TraversalCheckResult;
71
+ /**
72
+ * Resolves traversal boundaries with defaults.
73
+ *
74
+ * @param options - User-provided options
75
+ * @returns Complete traversal boundary configuration
76
+ */
77
+ export declare function resolveTraversalBoundary(options?: Partial<TraversalBoundary>): TraversalBoundary;
78
+ /**
79
+ * Creates a boundary checker function with the specified options.
80
+ * Useful for repeated checks with the same configuration.
81
+ *
82
+ * @param options - Security options
83
+ * @param logger - Optional logger
84
+ * @returns Boundary checker function
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const checker = createBoundaryChecker({ allowUnsafeTraversal: false });
89
+ *
90
+ * const result = checker('/path/to/check', '/start/path');
91
+ * if (!result.allowed) {
92
+ * console.error(result.reason);
93
+ * }
94
+ * ```
95
+ */
96
+ export declare function createBoundaryChecker(options?: TraversalSecurityOptions, logger?: Logger): (pathToCheck: string, startPath?: string) => TraversalCheckResult;
97
+ /**
98
+ * Filters an array of paths to only include those within traversal boundaries.
99
+ *
100
+ * @param paths - Paths to filter
101
+ * @param options - Security options
102
+ * @param startPath - Starting path for relative depth calculation
103
+ * @param logger - Optional logger
104
+ * @returns Filtered array of allowed paths
105
+ */
106
+ export declare function filterAllowedPaths(paths: string[], options?: TraversalSecurityOptions, startPath?: string, logger?: Logger): string[];
@@ -0,0 +1,18 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Error thrown when env var parsing fails
4
+ */
5
+ export declare class EnvVarParseError extends Error {
6
+ readonly value: string;
7
+ readonly expectedType: string;
8
+ envVarName?: string | undefined;
9
+ constructor(message: string, value: string, expectedType: string, envVarName?: string | undefined);
10
+ }
11
+ /**
12
+ * Error thrown when env var validation fails
13
+ */
14
+ export declare class EnvVarValidationError extends Error {
15
+ readonly envVarName: string;
16
+ readonly zodError: z.ZodError;
17
+ constructor(message: string, envVarName: string, zodError: z.ZodError);
18
+ }
@@ -0,0 +1,7 @@
1
+ export { toScreamingSnakeCase, generateEnvVarName, flattenFieldPath } from './naming';
2
+ export { parseEnvVar, parseBoolean, parseNumber, parseArray } from './parser';
3
+ export { readEnvVar, readEnvVarForField, readEnvVarsForSchema } from './reader';
4
+ export { extractSchemaFields, getSchemaForField } from './schema-utils';
5
+ export { resolveEnvVarConfig } from './resolver';
6
+ export { EnvVarParseError, EnvVarValidationError } from './errors';
7
+ export type { EnvVarNamingConfig, EnvVarName, EnvVarReadResult, EnvVarConfigSource } from './types';
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Convert camelCase to SCREAMING_SNAKE_CASE
3
+ *
4
+ * Examples:
5
+ * planDirectory -> PLAN_DIRECTORY
6
+ * apiKey -> API_KEY
7
+ * maxRetryCount -> MAX_RETRY_COUNT
8
+ * openaiAPIKey -> OPENAI_API_KEY
9
+ * api.key -> API_KEY (dots converted to underscores)
10
+ *
11
+ * @param camelCase - The camelCase string to convert
12
+ * @returns The SCREAMING_SNAKE_CASE version
13
+ */
14
+ export declare function toScreamingSnakeCase(camelCase: string): string;
15
+ /**
16
+ * Flatten nested field path to single-underscore format
17
+ *
18
+ * Examples:
19
+ * ['api', 'key'] -> 'api.key'
20
+ * ['config', 'server', 'port'] -> 'config.server.port'
21
+ *
22
+ * @param path - Array of field path segments
23
+ * @returns Dot-notation string
24
+ */
25
+ export declare function flattenFieldPath(path: string[]): string;
26
+ /**
27
+ * Generate full env var name with prefix
28
+ *
29
+ * Examples:
30
+ * ('riotplan', 'planDirectory') -> 'RIOTPLAN_PLAN_DIRECTORY'
31
+ * ('protokoll', ['api', 'key']) -> 'PROTOKOLL_API_KEY'
32
+ * ('MyApp', 'setting') -> 'MYAPP_SETTING'
33
+ *
34
+ * @param appName - Application name to use as prefix
35
+ * @param fieldPath - Field path as string or array
36
+ * @returns Full environment variable name
37
+ */
38
+ export declare function generateEnvVarName(appName: string, fieldPath: string | string[]): string;
@@ -0,0 +1,61 @@
1
+ import { ZodTypeAny } from 'zod';
2
+ /**
3
+ * Parse environment variable value based on Zod schema type
4
+ *
5
+ * This function inspects the Zod schema type and delegates to the appropriate
6
+ * parser function. It supports boolean, number, array, and string types.
7
+ *
8
+ * @param value - Raw string value from process.env
9
+ * @param zodType - Zod schema type to parse into
10
+ * @returns Parsed value of appropriate type
11
+ * @throws EnvVarParseError if parsing fails
12
+ */
13
+ export declare function parseEnvVar(value: string | undefined, zodType: ZodTypeAny): unknown;
14
+ /**
15
+ * Parse boolean from various string formats
16
+ *
17
+ * Uses the 'yn' library (https://github.com/sindresorhus/yn) which is
18
+ * well-maintained with 7.1M weekly downloads. Supports case-insensitive:
19
+ * - true/false
20
+ * - yes/no
21
+ * - y/n
22
+ * - 1/0
23
+ * - on/off
24
+ *
25
+ * Empty string is treated as false.
26
+ *
27
+ * @param value - String value to parse
28
+ * @returns Boolean value
29
+ * @throws EnvVarParseError if value cannot be parsed as boolean
30
+ */
31
+ export declare function parseBoolean(value: string): boolean;
32
+ /**
33
+ * Parse number from string
34
+ *
35
+ * Supports:
36
+ * - Integers: 42, -10, 0
37
+ * - Floats: 3.14, -2.7, 0.5
38
+ * - Scientific notation: 1e6, 1.5e3, 2e-3
39
+ * - Hexadecimal: 0xFF, 0x10
40
+ *
41
+ * @param value - String value to parse
42
+ * @returns Number value
43
+ * @throws EnvVarParseError if value cannot be parsed as number
44
+ */
45
+ export declare function parseNumber(value: string): number;
46
+ /**
47
+ * Parse array from space-separated string
48
+ *
49
+ * Example: "tag1 tag2 tag3" -> ['tag1', 'tag2', 'tag3']
50
+ *
51
+ * Each item is parsed according to the element type of the array schema.
52
+ * Multiple spaces are treated as a single separator.
53
+ * Leading and trailing whitespace is trimmed.
54
+ *
55
+ * Note: Items with spaces are not supported in this version.
56
+ *
57
+ * @param value - Space-separated string value
58
+ * @param elementType - Zod schema type for array elements
59
+ * @returns Array of parsed values
60
+ */
61
+ export declare function parseArray(value: string, elementType: ZodTypeAny): unknown[];
@@ -0,0 +1,45 @@
1
+ import { EnvVarNamingConfig, EnvVarReadResult } from './types';
2
+ /**
3
+ * Read environment variable value
4
+ *
5
+ * This is a simple wrapper around process.env access for testability
6
+ * and consistency. It does not throw errors for missing variables.
7
+ *
8
+ * @param envVarName - Full env var name (e.g., 'RIOTPLAN_PLAN_DIRECTORY')
9
+ * @returns Value from process.env or undefined if not set
10
+ */
11
+ export declare function readEnvVar(envVarName: string): string | undefined;
12
+ /**
13
+ * Read environment variable for a config field
14
+ *
15
+ * Checks custom mapping first (from envVarMap), then falls back to
16
+ * auto-generated name. This allows users to override the default
17
+ * naming convention for specific fields.
18
+ *
19
+ * Example:
20
+ * readEnvVarForField('openaiApiKey', {
21
+ * appName: 'riotplan',
22
+ * envVarMap: { openaiApiKey: 'OPENAI_API_KEY' }
23
+ * })
24
+ * // Reads from OPENAI_API_KEY instead of RIOTPLAN_OPENAI_API_KEY
25
+ *
26
+ * @param fieldPath - Field path in config (e.g., 'planDirectory' or ['api', 'key'])
27
+ * @param config - Naming configuration with appName and envVarMap
28
+ * @returns Object with env var name and value
29
+ */
30
+ export declare function readEnvVarForField(fieldPath: string | string[], config: EnvVarNamingConfig): EnvVarReadResult;
31
+ /**
32
+ * Read all environment variables for a schema
33
+ *
34
+ * Returns a map of field paths to env var values. Only includes
35
+ * fields that have corresponding environment variables set.
36
+ * Missing env vars are not included in the result.
37
+ *
38
+ * This is useful for batch reading all env vars for a config schema
39
+ * at once, which can then be merged with other config sources.
40
+ *
41
+ * @param fieldPaths - All field paths from schema
42
+ * @param config - Naming configuration
43
+ * @returns Map of field paths to read results (only includes set vars)
44
+ */
45
+ export declare function readEnvVarsForSchema(fieldPaths: string[], config: EnvVarNamingConfig): Map<string, EnvVarReadResult>;
@@ -0,0 +1,25 @@
1
+ import { ZodObject, ZodRawShape, z } from 'zod';
2
+ import { EnvVarNamingConfig, EnvVarConfigSource } from './types';
3
+ /**
4
+ * Resolve configuration from environment variables
5
+ *
6
+ * This is the main entry point for the env module. It orchestrates:
7
+ * 1. Extracting field paths from the schema
8
+ * 2. Reading environment variables
9
+ * 3. Parsing values according to schema types
10
+ * 4. Validating the final config with Zod
11
+ *
12
+ * Returns null if no environment variables are found, allowing
13
+ * the caller to fall back to other config sources.
14
+ *
15
+ * Throws EnvVarParseError if a value cannot be parsed.
16
+ * Throws EnvVarValidationError if the parsed config fails Zod validation.
17
+ *
18
+ * @param schema - Zod schema defining config structure
19
+ * @param config - Naming configuration (appName, envVarMap)
20
+ * @returns Parsed config object and source information, or null if no env vars found
21
+ */
22
+ export declare function resolveEnvVarConfig<T extends ZodRawShape>(schema: ZodObject<T>, config: EnvVarNamingConfig): Promise<{
23
+ config: z.infer<ZodObject<T>>;
24
+ source: EnvVarConfigSource;
25
+ } | null>;
@@ -0,0 +1,33 @@
1
+ import { ZodObject, ZodTypeAny } from 'zod';
2
+ /**
3
+ * Extract all field paths from a Zod schema
4
+ *
5
+ * Handles nested objects by flattening to dot notation.
6
+ * This allows us to generate environment variable names for all
7
+ * fields in a schema, including nested ones.
8
+ *
9
+ * Example:
10
+ * schema = z.object({ api: z.object({ key: z.string() }) })
11
+ * extractSchemaFields(schema) => ['api', 'api.key']
12
+ *
13
+ * @param schema - Zod object schema
14
+ * @returns Array of field paths in dot notation
15
+ */
16
+ export declare function extractSchemaFields(schema: ZodObject<any>): string[];
17
+ /**
18
+ * Get Zod schema for a specific field path
19
+ *
20
+ * Navigates through nested objects using dot notation to find
21
+ * the schema for a specific field. This is used to determine
22
+ * the correct parser for each field.
23
+ *
24
+ * Example:
25
+ * schema = z.object({ api: z.object({ key: z.string() }) })
26
+ * getSchemaForField(schema, 'api.key') => z.string()
27
+ *
28
+ * @param schema - Zod object schema
29
+ * @param fieldPath - Field path in dot notation
30
+ * @returns Zod schema for the field
31
+ * @throws Error if field path is invalid
32
+ */
33
+ export declare function getSchemaForField(schema: ZodObject<any>, fieldPath: string): ZodTypeAny;