ultraenv 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +2058 -0
- package/bin/ultraenv.mjs +3 -0
- package/dist/chunk-2USZPWLZ.js +288 -0
- package/dist/chunk-3UV2QNJL.js +270 -0
- package/dist/chunk-3VYXPTYV.js +179 -0
- package/dist/chunk-4XUYMRK5.js +366 -0
- package/dist/chunk-5G2DU52U.js +189 -0
- package/dist/chunk-6KS56D6E.js +172 -0
- package/dist/chunk-AWN6ADV7.js +328 -0
- package/dist/chunk-CHVO6NWI.js +203 -0
- package/dist/chunk-CIFMBJ4H.js +3975 -0
- package/dist/chunk-GC7RXHLA.js +253 -0
- package/dist/chunk-HFXQGJY3.js +445 -0
- package/dist/chunk-IGFVP24Q.js +91 -0
- package/dist/chunk-IKPTKALB.js +78 -0
- package/dist/chunk-JB7RKV3C.js +66 -0
- package/dist/chunk-MNVFG7H4.js +611 -0
- package/dist/chunk-MSXMESFP.js +1910 -0
- package/dist/chunk-N5PAV4NM.js +127 -0
- package/dist/chunk-NBOABPHM.js +158 -0
- package/dist/chunk-OMAOROL4.js +49 -0
- package/dist/chunk-R7PZRSZ7.js +105 -0
- package/dist/chunk-TE7HPLA6.js +73 -0
- package/dist/chunk-TMT5KCO3.js +101 -0
- package/dist/chunk-UEWYFN6A.js +189 -0
- package/dist/chunk-WMHN5RW2.js +128 -0
- package/dist/chunk-XC65ORJ5.js +70 -0
- package/dist/chunk-YMMP4VQL.js +118 -0
- package/dist/chunk-YN2KGTCB.js +33 -0
- package/dist/chunk-YTICOB5M.js +65 -0
- package/dist/chunk-YVWLXFUT.js +107 -0
- package/dist/ci-check-sync-VBMSVWIV.js +48 -0
- package/dist/ci-scan-24MT5XGS.js +41 -0
- package/dist/ci-setup-C2NKEFRD.js +135 -0
- package/dist/ci-validate-7AW24LSQ.js +57 -0
- package/dist/cli/index.cjs +9217 -0
- package/dist/cli/index.d.cts +9 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.js +339 -0
- package/dist/comparator-RDKX3OI7.js +13 -0
- package/dist/completion-MW35C2XO.js +168 -0
- package/dist/config-O5YRQP5Z.js +13 -0
- package/dist/debug-PTPXAF3K.js +131 -0
- package/dist/declaration-LEME4AFZ.js +10 -0
- package/dist/doctor-FZAUPKHS.js +129 -0
- package/dist/envs-compare-5K3HESX5.js +49 -0
- package/dist/envs-create-2XXHXMGA.js +58 -0
- package/dist/envs-list-NQM5252B.js +59 -0
- package/dist/envs-switch-6L2AQYID.js +50 -0
- package/dist/envs-validate-FL73Q76T.js +89 -0
- package/dist/fs-VH7ATUS3.js +31 -0
- package/dist/generator-LFZBMZZS.js +14 -0
- package/dist/git-BZS4DPAI.js +30 -0
- package/dist/help-3XJBXEHE.js +121 -0
- package/dist/index.cjs +12907 -0
- package/dist/index.d.cts +2562 -0
- package/dist/index.d.ts +2562 -0
- package/dist/index.js +3212 -0
- package/dist/init-Y7JQ2KYJ.js +146 -0
- package/dist/install-hook-SKXIV6NV.js +111 -0
- package/dist/json-schema-I26YNQBH.js +10 -0
- package/dist/key-manager-O3G55WPU.js +25 -0
- package/dist/middleware/express.cjs +103 -0
- package/dist/middleware/express.d.cts +115 -0
- package/dist/middleware/express.d.ts +115 -0
- package/dist/middleware/express.js +8 -0
- package/dist/middleware/fastify.cjs +91 -0
- package/dist/middleware/fastify.d.cts +111 -0
- package/dist/middleware/fastify.d.ts +111 -0
- package/dist/middleware/fastify.js +8 -0
- package/dist/module-IDIZPP4M.js +10 -0
- package/dist/protect-NCWPM6VC.js +161 -0
- package/dist/scan-TRLY36TT.js +58 -0
- package/dist/schema/index.cjs +4074 -0
- package/dist/schema/index.d.cts +1244 -0
- package/dist/schema/index.d.ts +1244 -0
- package/dist/schema/index.js +152 -0
- package/dist/sync-TMHMTLH2.js +186 -0
- package/dist/typegen-SQOSXBWM.js +80 -0
- package/dist/validate-IOAM5HWS.js +100 -0
- package/dist/vault-decrypt-U6HJZNBV.js +111 -0
- package/dist/vault-diff-B3ZOQTWI.js +132 -0
- package/dist/vault-encrypt-GUSLCSKS.js +112 -0
- package/dist/vault-init-GUBOTOUL.js +106 -0
- package/dist/vault-rekey-DAHT7JCN.js +132 -0
- package/dist/vault-status-GDLRU2OK.js +90 -0
- package/dist/vault-verify-CD76FJSF.js +102 -0
- package/package.json +106 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,2562 @@
|
|
|
1
|
+
export { InferSchema, SchemaBuilder, SchemaDefinition, defineEnv, t, tryDefineEnv, validate } from './schema/index.cjs';
|
|
2
|
+
export { healthCheckRoute, ultraenvMiddleware } from './middleware/express.cjs';
|
|
3
|
+
export { createUltraenvPlugin, ultraenvPlugin } from './middleware/fastify.cjs';
|
|
4
|
+
|
|
5
|
+
declare enum EnvFileType {
|
|
6
|
+
/** .env — Default, shared across all environments */
|
|
7
|
+
Env = ".env",
|
|
8
|
+
/** .env.local — Local overrides, gitignored by default */
|
|
9
|
+
EnvLocal = ".env.local",
|
|
10
|
+
/** .env.development — Development-specific */
|
|
11
|
+
EnvDevelopment = ".env.development",
|
|
12
|
+
/** .env.development.local — Local development overrides */
|
|
13
|
+
EnvDevelopmentLocal = ".env.development.local",
|
|
14
|
+
/** .env.test — Test-specific */
|
|
15
|
+
EnvTest = ".env.test",
|
|
16
|
+
/** .env.test.local — Local test overrides */
|
|
17
|
+
EnvTestLocal = ".env.test.local",
|
|
18
|
+
/** .env.production — Production-specific */
|
|
19
|
+
EnvProduction = ".env.production",
|
|
20
|
+
/** .env.production.local — Local production overrides */
|
|
21
|
+
EnvProductionLocal = ".env.production.local",
|
|
22
|
+
/** .env.staging — Staging-specific */
|
|
23
|
+
EnvStaging = ".env.staging",
|
|
24
|
+
/** .env.staging.local — Local staging overrides */
|
|
25
|
+
EnvStagingLocal = ".env.staging.local",
|
|
26
|
+
/** .env.ci — CI/CD-specific */
|
|
27
|
+
EnvCI = ".env.ci"
|
|
28
|
+
}
|
|
29
|
+
type MergeStrategy = 'first-wins' | 'last-wins' | 'error-on-conflict';
|
|
30
|
+
type OutputFormat$1 = 'terminal' | 'json' | 'silent';
|
|
31
|
+
interface UltraenvConfig {
|
|
32
|
+
/** Directory to search for .env files (default: '.') */
|
|
33
|
+
envDir: string;
|
|
34
|
+
/** Which .env file variants to load (default: [EnvFileType.Env]) */
|
|
35
|
+
files: readonly EnvFileType[];
|
|
36
|
+
/** Character encoding for reading files (default: 'utf-8') */
|
|
37
|
+
encoding: BufferEncoding;
|
|
38
|
+
/** Whether to expand $VAR references (default: true) */
|
|
39
|
+
expandVariables: boolean;
|
|
40
|
+
/** Whether to overwrite existing process.env values (default: false) */
|
|
41
|
+
overrideProcessEnv: boolean;
|
|
42
|
+
/** Merge strategy when multiple files define the same key */
|
|
43
|
+
mergeStrategy: MergeStrategy;
|
|
44
|
+
/** Whether to prefix error messages with "ultraenv" */
|
|
45
|
+
prefixErrors: boolean;
|
|
46
|
+
/** Whether to silence all output (equivalent to OutputFormat.silent) */
|
|
47
|
+
silent: boolean;
|
|
48
|
+
/** Custom schema for validation */
|
|
49
|
+
schema?: EnvSchema;
|
|
50
|
+
/** Vault configuration */
|
|
51
|
+
vault?: VaultConfig;
|
|
52
|
+
/** Watch configuration */
|
|
53
|
+
watch?: WatchOptions;
|
|
54
|
+
/** Scan options for secret detection */
|
|
55
|
+
scan?: ScanOptions;
|
|
56
|
+
/** Output format */
|
|
57
|
+
outputFormat: OutputFormat$1;
|
|
58
|
+
/** Whether to log debug information */
|
|
59
|
+
debug: boolean;
|
|
60
|
+
/** Custom reporter for events */
|
|
61
|
+
reporter?: Reporter;
|
|
62
|
+
/** Maximum allowed value length in bytes (default: 1MB) */
|
|
63
|
+
maxValueLength: number;
|
|
64
|
+
/** Maximum variable interpolation depth (default: 10) */
|
|
65
|
+
maxInterpolationDepth: number;
|
|
66
|
+
}
|
|
67
|
+
interface LoadOptions {
|
|
68
|
+
/** Override the env directory */
|
|
69
|
+
envDir?: string;
|
|
70
|
+
/** Override the list of files to load */
|
|
71
|
+
files?: readonly EnvFileType[];
|
|
72
|
+
/** Override the encoding */
|
|
73
|
+
encoding?: BufferEncoding;
|
|
74
|
+
/** Whether to expand variables */
|
|
75
|
+
expandVariables?: boolean;
|
|
76
|
+
/** Whether to override process.env */
|
|
77
|
+
overrideProcessEnv?: boolean;
|
|
78
|
+
/** Merge strategy */
|
|
79
|
+
mergeStrategy?: MergeStrategy;
|
|
80
|
+
/** Schema for validation */
|
|
81
|
+
schema?: EnvSchema;
|
|
82
|
+
/** Whether to silence output */
|
|
83
|
+
silent?: boolean;
|
|
84
|
+
/** Maximum interpolation depth */
|
|
85
|
+
maxInterpolationDepth?: number;
|
|
86
|
+
/** Maximum value length */
|
|
87
|
+
maxValueLength?: number;
|
|
88
|
+
/** Process env to merge with (defaults to process.env) */
|
|
89
|
+
processEnv?: Record<string, string | undefined>;
|
|
90
|
+
}
|
|
91
|
+
interface ParsedEnvVar {
|
|
92
|
+
/** The variable name (key) */
|
|
93
|
+
key: string;
|
|
94
|
+
/** The resolved/interpolated value */
|
|
95
|
+
value: string;
|
|
96
|
+
/** The raw value as-is from the file (before interpolation) */
|
|
97
|
+
raw: string;
|
|
98
|
+
/** Which file this variable came from */
|
|
99
|
+
source: string;
|
|
100
|
+
/** 1-based line number in the source file */
|
|
101
|
+
lineNumber: number;
|
|
102
|
+
/** Any inline comment after the value */
|
|
103
|
+
comment: string;
|
|
104
|
+
}
|
|
105
|
+
interface ParsedEnvFile {
|
|
106
|
+
/** Absolute path to the .env file */
|
|
107
|
+
path: string;
|
|
108
|
+
/** All parsed variables from this file */
|
|
109
|
+
vars: readonly ParsedEnvVar[];
|
|
110
|
+
/** Whether the file exists on disk */
|
|
111
|
+
exists: boolean;
|
|
112
|
+
}
|
|
113
|
+
interface LoadResult {
|
|
114
|
+
/** The final merged env key-value pairs */
|
|
115
|
+
env: Record<string, string>;
|
|
116
|
+
/** Metadata about the load operation */
|
|
117
|
+
metadata: LoadMetadata;
|
|
118
|
+
/** All parsed files with their contents */
|
|
119
|
+
parsed: readonly ParsedEnvFile[];
|
|
120
|
+
/** Validation results, if a schema was provided */
|
|
121
|
+
validation?: ValidationResult;
|
|
122
|
+
}
|
|
123
|
+
interface LoadMetadata {
|
|
124
|
+
/** Total number of variables loaded */
|
|
125
|
+
totalVars: number;
|
|
126
|
+
/** Number of files successfully parsed */
|
|
127
|
+
filesParsed: number;
|
|
128
|
+
/** Number of files that existed */
|
|
129
|
+
filesFound: number;
|
|
130
|
+
/** Wall-clock time for the load operation in ms */
|
|
131
|
+
loadTimeMs: number;
|
|
132
|
+
/** Timestamp when the load was performed */
|
|
133
|
+
timestamp: string;
|
|
134
|
+
/** Environment directory used */
|
|
135
|
+
envDir: string;
|
|
136
|
+
/** Whether any overrides occurred (existing keys overwritten) */
|
|
137
|
+
hadOverrides: boolean;
|
|
138
|
+
}
|
|
139
|
+
type SchemaDefinition = Record<string, StringSchema | NumberSchema | BooleanSchema | EnumSchema<string[]> | ArraySchema | JsonSchema | DateSchema | BigIntSchema>;
|
|
140
|
+
/** Base schema shape shared by all types */
|
|
141
|
+
interface BaseSchema<T> {
|
|
142
|
+
/** Human-readable description for documentation */
|
|
143
|
+
description?: string;
|
|
144
|
+
/** If true, the variable is optional (defaults to false) */
|
|
145
|
+
optional?: boolean;
|
|
146
|
+
/** Default value when the variable is not set */
|
|
147
|
+
default?: T;
|
|
148
|
+
/** Transform function applied after parsing */
|
|
149
|
+
transform?: (value: T) => T;
|
|
150
|
+
/** Custom validation function — return a string for error message, or void/undefined for pass */
|
|
151
|
+
validate?: (value: T) => string | undefined;
|
|
152
|
+
/** Deprecation message, if set this variable is deprecated */
|
|
153
|
+
deprecated?: string;
|
|
154
|
+
}
|
|
155
|
+
interface StringSchema extends BaseSchema<string> {
|
|
156
|
+
type: 'string';
|
|
157
|
+
/** Minimum string length */
|
|
158
|
+
minLength?: number;
|
|
159
|
+
/** Maximum string length */
|
|
160
|
+
maxLength?: number;
|
|
161
|
+
/** Regex pattern the value must match */
|
|
162
|
+
pattern?: RegExp;
|
|
163
|
+
/** Predefined format shortcut (e.g., 'email', 'url', 'uuid') */
|
|
164
|
+
format?: 'email' | 'url' | 'uuid' | 'hostname' | 'ip' | 'ipv4' | 'ipv6';
|
|
165
|
+
/** Allowed values (enum shorthand) */
|
|
166
|
+
enum?: readonly string[];
|
|
167
|
+
/** Trim whitespace before validation */
|
|
168
|
+
trim?: boolean;
|
|
169
|
+
}
|
|
170
|
+
interface NumberSchema extends BaseSchema<number> {
|
|
171
|
+
type: 'number';
|
|
172
|
+
/** Minimum allowed value */
|
|
173
|
+
min?: number;
|
|
174
|
+
/** Maximum allowed value */
|
|
175
|
+
max?: number;
|
|
176
|
+
/** Value must be an integer */
|
|
177
|
+
integer?: boolean;
|
|
178
|
+
/** Value must be positive (> 0) */
|
|
179
|
+
positive?: boolean;
|
|
180
|
+
/** Value must be negative (< 0) */
|
|
181
|
+
negative?: boolean;
|
|
182
|
+
/** Value must be non-negative (>= 0) */
|
|
183
|
+
nonNegative?: boolean;
|
|
184
|
+
/** Value cannot be NaN or Infinity */
|
|
185
|
+
finite?: boolean;
|
|
186
|
+
/** Custom parsing function */
|
|
187
|
+
parse?: (raw: string) => number;
|
|
188
|
+
}
|
|
189
|
+
interface BooleanSchema extends BaseSchema<boolean> {
|
|
190
|
+
type: 'boolean';
|
|
191
|
+
/** Custom truthy values (default: ['true', '1', 'yes']) */
|
|
192
|
+
truthy?: readonly string[];
|
|
193
|
+
/** Custom falsy values (default: ['false', '0', 'no']) */
|
|
194
|
+
falsy?: readonly string[];
|
|
195
|
+
}
|
|
196
|
+
interface EnumSchema<T extends readonly string[]> extends BaseSchema<T[number]> {
|
|
197
|
+
type: 'enum';
|
|
198
|
+
/** Allowed values */
|
|
199
|
+
values: T;
|
|
200
|
+
/** Whether matching is case-insensitive (default: false) */
|
|
201
|
+
caseInsensitive?: boolean;
|
|
202
|
+
}
|
|
203
|
+
interface ArraySchema extends BaseSchema<readonly string[]> {
|
|
204
|
+
type: 'array';
|
|
205
|
+
/** Separator to split the value on (default: ',') */
|
|
206
|
+
separator?: string;
|
|
207
|
+
/** Trim each item after splitting */
|
|
208
|
+
trimItems?: boolean;
|
|
209
|
+
/** Remove empty strings from the result */
|
|
210
|
+
filterEmpty?: boolean;
|
|
211
|
+
/** Minimum number of items */
|
|
212
|
+
minItems?: number;
|
|
213
|
+
/** Maximum number of items */
|
|
214
|
+
maxItems?: number;
|
|
215
|
+
/** Unique items only */
|
|
216
|
+
unique?: boolean;
|
|
217
|
+
/** Schema to validate each item against */
|
|
218
|
+
itemSchema?: BaseSchema<string>;
|
|
219
|
+
}
|
|
220
|
+
interface JsonSchema<T = unknown> extends BaseSchema<T> {
|
|
221
|
+
type: 'json';
|
|
222
|
+
/** Custom reviver for JSON.parse */
|
|
223
|
+
reviver?: (key: string, value: unknown) => unknown;
|
|
224
|
+
}
|
|
225
|
+
interface DateSchema extends BaseSchema<Date> {
|
|
226
|
+
type: 'date';
|
|
227
|
+
/** Custom date format string or parsing function */
|
|
228
|
+
format?: string;
|
|
229
|
+
/** Custom parse function */
|
|
230
|
+
parse?: (raw: string) => Date;
|
|
231
|
+
/** Minimum date */
|
|
232
|
+
min?: Date;
|
|
233
|
+
/** Maximum date */
|
|
234
|
+
max?: Date;
|
|
235
|
+
}
|
|
236
|
+
interface BigIntSchema extends BaseSchema<bigint> {
|
|
237
|
+
type: 'bigint';
|
|
238
|
+
/** Radix for parsing (default: 10) */
|
|
239
|
+
radix?: number;
|
|
240
|
+
/** Custom parse function */
|
|
241
|
+
parse?: (raw: string) => bigint;
|
|
242
|
+
/** Minimum value */
|
|
243
|
+
min?: bigint;
|
|
244
|
+
/** Maximum value */
|
|
245
|
+
max?: bigint;
|
|
246
|
+
}
|
|
247
|
+
interface EnvSchema {
|
|
248
|
+
/** Schema definitions keyed by variable name */
|
|
249
|
+
definitions: SchemaDefinition;
|
|
250
|
+
/** Whether to strip unknown variables (default: false) */
|
|
251
|
+
strict?: boolean;
|
|
252
|
+
/** Whether to allow extra variables not in the schema (inverse of strict) */
|
|
253
|
+
allowExtra?: boolean;
|
|
254
|
+
}
|
|
255
|
+
interface ValidationResult {
|
|
256
|
+
/** Whether all validations passed */
|
|
257
|
+
valid: boolean;
|
|
258
|
+
/** All validation errors */
|
|
259
|
+
errors: readonly ValidationError$1[];
|
|
260
|
+
/** All validation warnings (non-blocking) */
|
|
261
|
+
warnings: readonly ValidationWarning[];
|
|
262
|
+
/** Variables that passed validation */
|
|
263
|
+
validated: Record<string, unknown>;
|
|
264
|
+
/** Unknown variables not in schema (when strict mode) */
|
|
265
|
+
unknown: readonly string[];
|
|
266
|
+
}
|
|
267
|
+
interface ValidationError$1 {
|
|
268
|
+
/** The variable name */
|
|
269
|
+
field: string;
|
|
270
|
+
/** The actual value that failed validation */
|
|
271
|
+
value: string;
|
|
272
|
+
/** Human-readable error message */
|
|
273
|
+
message: string;
|
|
274
|
+
/** Actionable hint for fixing the error */
|
|
275
|
+
hint: string;
|
|
276
|
+
/** The schema that was violated */
|
|
277
|
+
schema: BaseSchema<unknown>;
|
|
278
|
+
/** The expected type or constraint */
|
|
279
|
+
expected: string;
|
|
280
|
+
/** Source file, if applicable */
|
|
281
|
+
source?: string;
|
|
282
|
+
/** Line number, if applicable */
|
|
283
|
+
lineNumber?: number;
|
|
284
|
+
}
|
|
285
|
+
interface ValidationWarning {
|
|
286
|
+
/** The variable name */
|
|
287
|
+
field: string;
|
|
288
|
+
/** The value that triggered the warning */
|
|
289
|
+
value: string;
|
|
290
|
+
/** Warning message */
|
|
291
|
+
message: string;
|
|
292
|
+
/** Warning code for programmatic handling */
|
|
293
|
+
code: string;
|
|
294
|
+
}
|
|
295
|
+
interface VaultConfig {
|
|
296
|
+
/** Path to the vault file (default: '.env.vault') */
|
|
297
|
+
vaultFile: string;
|
|
298
|
+
/** Path to the keys file (default: '.env.keys') */
|
|
299
|
+
keysFile: string;
|
|
300
|
+
/** Current environment name (e.g., 'development', 'production') */
|
|
301
|
+
environment: string;
|
|
302
|
+
/** Master encryption key (if not using keys file) */
|
|
303
|
+
masterKey?: string;
|
|
304
|
+
/** Whether to auto-generate a key if none exists */
|
|
305
|
+
autoGenerateKey: boolean;
|
|
306
|
+
}
|
|
307
|
+
interface VaultEnvironment {
|
|
308
|
+
/** Environment name */
|
|
309
|
+
name: string;
|
|
310
|
+
/** Number of encrypted variables */
|
|
311
|
+
varCount: number;
|
|
312
|
+
/** ISO timestamp of last modification */
|
|
313
|
+
lastModified: string;
|
|
314
|
+
/** Which keys are available for this environment */
|
|
315
|
+
keyIds: readonly string[];
|
|
316
|
+
}
|
|
317
|
+
interface EncryptionResult {
|
|
318
|
+
/** Initialization vector */
|
|
319
|
+
iv: Buffer;
|
|
320
|
+
/** Authentication tag (for AEAD modes like AES-GCM) */
|
|
321
|
+
authTag: Buffer;
|
|
322
|
+
/** Encrypted ciphertext */
|
|
323
|
+
ciphertext: Buffer;
|
|
324
|
+
/** Algorithm used (e.g., 'aes-256-gcm') */
|
|
325
|
+
algorithm: string;
|
|
326
|
+
}
|
|
327
|
+
interface ScanOptions {
|
|
328
|
+
/** Files/patterns to include */
|
|
329
|
+
include: readonly string[];
|
|
330
|
+
/** Files/patterns to exclude */
|
|
331
|
+
exclude: readonly string[];
|
|
332
|
+
/** Whether to scan git history (more thorough but slower) */
|
|
333
|
+
scanGitHistory: boolean;
|
|
334
|
+
/** Maximum file size to scan in bytes (default: 1MB) */
|
|
335
|
+
maxFileSize: number;
|
|
336
|
+
/** Custom secret patterns to match */
|
|
337
|
+
customPatterns?: readonly SecretPattern[];
|
|
338
|
+
/** Whether to include default patterns */
|
|
339
|
+
includeDefaults: boolean;
|
|
340
|
+
/** Whether to stop on first match */
|
|
341
|
+
failFast: boolean;
|
|
342
|
+
}
|
|
343
|
+
interface ScanResult {
|
|
344
|
+
/** Whether any secrets were detected */
|
|
345
|
+
found: boolean;
|
|
346
|
+
/** All detected secrets */
|
|
347
|
+
secrets: readonly DetectedSecret[];
|
|
348
|
+
/** Files that were scanned */
|
|
349
|
+
filesScanned: readonly string[];
|
|
350
|
+
/** Files that were skipped (binary, too large, etc.) */
|
|
351
|
+
filesSkipped: readonly string[];
|
|
352
|
+
/** Wall-clock time for the scan in ms */
|
|
353
|
+
scanTimeMs: number;
|
|
354
|
+
/** Timestamp of the scan */
|
|
355
|
+
timestamp: string;
|
|
356
|
+
}
|
|
357
|
+
interface DetectedSecret {
|
|
358
|
+
/** The type of secret detected */
|
|
359
|
+
type: string;
|
|
360
|
+
/** The full matched string (masked) */
|
|
361
|
+
value: string;
|
|
362
|
+
/** The file where it was detected */
|
|
363
|
+
file: string;
|
|
364
|
+
/** Line number (1-based) */
|
|
365
|
+
line: number;
|
|
366
|
+
/** Column number (1-based) */
|
|
367
|
+
column: number;
|
|
368
|
+
/** The pattern that matched */
|
|
369
|
+
pattern: SecretPattern;
|
|
370
|
+
/** Confidence score (0-1) */
|
|
371
|
+
confidence: number;
|
|
372
|
+
/** The variable name, if the secret is in a .env file */
|
|
373
|
+
varName?: string;
|
|
374
|
+
}
|
|
375
|
+
interface SecretPattern {
|
|
376
|
+
/** Human-readable name (e.g., 'AWS Access Key') */
|
|
377
|
+
name: string;
|
|
378
|
+
/** Unique identifier */
|
|
379
|
+
id: string;
|
|
380
|
+
/** Regex pattern to match */
|
|
381
|
+
pattern: RegExp;
|
|
382
|
+
/** Confidence score (0-1) for this pattern */
|
|
383
|
+
confidence: number;
|
|
384
|
+
/** Description of what this pattern detects */
|
|
385
|
+
description: string;
|
|
386
|
+
/** Recommended remediation */
|
|
387
|
+
remediation: string;
|
|
388
|
+
/** Severity level: critical, high, or medium */
|
|
389
|
+
severity: 'critical' | 'high' | 'medium';
|
|
390
|
+
/** Category for grouping (e.g., 'aws', 'github', 'database') */
|
|
391
|
+
category: string;
|
|
392
|
+
}
|
|
393
|
+
interface SyncResult {
|
|
394
|
+
/** Whether the sync was successful */
|
|
395
|
+
success: boolean;
|
|
396
|
+
/** Differences detected */
|
|
397
|
+
diffs: readonly SyncDiff$1[];
|
|
398
|
+
/** Number of variables added */
|
|
399
|
+
added: number;
|
|
400
|
+
/** Number of variables removed */
|
|
401
|
+
removed: number;
|
|
402
|
+
/** Number of variables changed */
|
|
403
|
+
changed: number;
|
|
404
|
+
/** Number of variables unchanged */
|
|
405
|
+
unchanged: number;
|
|
406
|
+
/** Source environment name */
|
|
407
|
+
source: string;
|
|
408
|
+
/** Target environment name */
|
|
409
|
+
target: string;
|
|
410
|
+
}
|
|
411
|
+
interface SyncDiff$1 {
|
|
412
|
+
/** The variable name */
|
|
413
|
+
key: string;
|
|
414
|
+
/** Type of difference */
|
|
415
|
+
type: 'added' | 'removed' | 'changed';
|
|
416
|
+
/** Value in the source (masked) */
|
|
417
|
+
sourceValue: string;
|
|
418
|
+
/** Value in the target (masked) */
|
|
419
|
+
targetValue: string;
|
|
420
|
+
}
|
|
421
|
+
interface TypegenOptions {
|
|
422
|
+
/** Output file path for generated .d.ts */
|
|
423
|
+
outFile: string;
|
|
424
|
+
/** Interface name (default: 'UltraenvEnv') */
|
|
425
|
+
interfaceName: string;
|
|
426
|
+
/** Whether to export as default */
|
|
427
|
+
exportAsDefault: boolean;
|
|
428
|
+
/** Whether to make it a const assertion */
|
|
429
|
+
constAssertion: boolean;
|
|
430
|
+
/** Custom header comment */
|
|
431
|
+
header?: string;
|
|
432
|
+
/** Whether to generate JSDoc comments from schema descriptions */
|
|
433
|
+
jsdoc: boolean;
|
|
434
|
+
/** Indentation (spaces) */
|
|
435
|
+
indent: number;
|
|
436
|
+
}
|
|
437
|
+
interface WatchOptions {
|
|
438
|
+
/** Files/patterns to watch */
|
|
439
|
+
files: readonly string[];
|
|
440
|
+
/** Whether to watch recursively */
|
|
441
|
+
recursive: boolean;
|
|
442
|
+
/** Debounce interval in ms (default: 100) */
|
|
443
|
+
debounceMs: number;
|
|
444
|
+
/** Whether to trigger on initial load */
|
|
445
|
+
initial: boolean;
|
|
446
|
+
/** Polling interval in ms (0 = use native fs.watch) */
|
|
447
|
+
pollIntervalMs: number;
|
|
448
|
+
/** Ignore patterns */
|
|
449
|
+
ignore: readonly string[];
|
|
450
|
+
}
|
|
451
|
+
interface Watcher {
|
|
452
|
+
/** Start watching */
|
|
453
|
+
start(): void;
|
|
454
|
+
/** Stop watching */
|
|
455
|
+
stop(): void;
|
|
456
|
+
/** Whether the watcher is currently active */
|
|
457
|
+
readonly active: boolean;
|
|
458
|
+
/** Register a callback for file changes */
|
|
459
|
+
on(event: 'change' | 'error' | 'ready', callback: WatcherCallback): Watcher;
|
|
460
|
+
/** Remove a callback */
|
|
461
|
+
off(event: 'change' | 'error' | 'ready', callback: WatcherCallback): Watcher;
|
|
462
|
+
}
|
|
463
|
+
type WatcherCallback = (event: WatcherEvent) => void;
|
|
464
|
+
interface WatcherEvent {
|
|
465
|
+
/** Type of file system event */
|
|
466
|
+
type: 'add' | 'change' | 'unlink' | 'rename';
|
|
467
|
+
/** The file path that triggered the event */
|
|
468
|
+
path: string;
|
|
469
|
+
/** Timestamp of the event */
|
|
470
|
+
timestamp: number;
|
|
471
|
+
}
|
|
472
|
+
interface Preset {
|
|
473
|
+
/** Unique preset identifier */
|
|
474
|
+
id: string;
|
|
475
|
+
/** Human-readable name */
|
|
476
|
+
name: string;
|
|
477
|
+
/** Description of what this preset configures */
|
|
478
|
+
description: string;
|
|
479
|
+
/** Schema definitions for this preset */
|
|
480
|
+
schema: SchemaDefinition;
|
|
481
|
+
/** Recommended .env file variants */
|
|
482
|
+
files: readonly EnvFileType[];
|
|
483
|
+
/** Recommended vault settings */
|
|
484
|
+
vault?: Partial<VaultConfig>;
|
|
485
|
+
/** Tags for categorization */
|
|
486
|
+
tags: readonly string[];
|
|
487
|
+
}
|
|
488
|
+
interface Reporter {
|
|
489
|
+
/** Report a successfully loaded variable */
|
|
490
|
+
varLoaded(key: string, source: string): void;
|
|
491
|
+
/** Report a validation error */
|
|
492
|
+
varError(error: ValidationError$1): void;
|
|
493
|
+
/** Report a validation warning */
|
|
494
|
+
varWarning(warning: ValidationWarning): void;
|
|
495
|
+
/** Report a file being loaded */
|
|
496
|
+
fileLoaded(path: string, varCount: number): void;
|
|
497
|
+
/** Report a file that was not found */
|
|
498
|
+
fileNotFound(path: string): void;
|
|
499
|
+
/** Report the beginning of a load operation */
|
|
500
|
+
loadStart(config: UltraenvConfig): void;
|
|
501
|
+
/** Report the end of a load operation */
|
|
502
|
+
loadEnd(result: LoadResult): void;
|
|
503
|
+
/** Report a secret detection */
|
|
504
|
+
secretDetected(secret: DetectedSecret): void;
|
|
505
|
+
/** Report a sync operation */
|
|
506
|
+
syncResult(result: SyncResult): void;
|
|
507
|
+
/** Report a watch event */
|
|
508
|
+
watchEvent(event: WatcherEvent): void;
|
|
509
|
+
/** Report debug information */
|
|
510
|
+
debug(message: string, metadata?: Record<string, unknown>): void;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Load environment variables from .env files (synchronous).
|
|
515
|
+
*
|
|
516
|
+
* This function:
|
|
517
|
+
* 1. Resolves the file cascade based on environment
|
|
518
|
+
* 2. Reads and parses each .env file
|
|
519
|
+
* 3. Merges according to merge strategy
|
|
520
|
+
* 4. Expands variable references (if enabled)
|
|
521
|
+
* 5. Optionally sets process.env values
|
|
522
|
+
*
|
|
523
|
+
* @param options - Load configuration options
|
|
524
|
+
* @returns Merged env key-value pairs
|
|
525
|
+
*/
|
|
526
|
+
declare function load(options?: LoadOptions): Record<string, string>;
|
|
527
|
+
/**
|
|
528
|
+
* Synchronous version of load (alias for clarity).
|
|
529
|
+
* Identical behavior — uses synchronous file I/O.
|
|
530
|
+
*
|
|
531
|
+
* @param options - Load configuration options
|
|
532
|
+
* @returns Merged env key-value pairs
|
|
533
|
+
*/
|
|
534
|
+
declare function loadSync(options?: LoadOptions): Record<string, string>;
|
|
535
|
+
/**
|
|
536
|
+
* Full load with complete LoadResult (sync).
|
|
537
|
+
*
|
|
538
|
+
* @param options - Load configuration options
|
|
539
|
+
* @returns Complete LoadResult with env, metadata, and parsed files
|
|
540
|
+
*/
|
|
541
|
+
declare function loadWithResult(options?: LoadOptions): LoadResult;
|
|
542
|
+
/**
|
|
543
|
+
* Full load with complete LoadResult (sync, explicit alias).
|
|
544
|
+
*/
|
|
545
|
+
declare function loadWithResultSync(options?: LoadOptions): LoadResult;
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Search for an ultraenv configuration file starting from `cwd`
|
|
549
|
+
* and walking up the directory tree.
|
|
550
|
+
*
|
|
551
|
+
* Searches for (in order):
|
|
552
|
+
* - .ultraenvrc.json
|
|
553
|
+
* - .ultraenvrc.yaml
|
|
554
|
+
* - .ultraenvrc.yml
|
|
555
|
+
* - ultraenv.config.js
|
|
556
|
+
* - ultraenv.config.cjs
|
|
557
|
+
* - "ultraenv" key in package.json
|
|
558
|
+
*
|
|
559
|
+
* @param cwd - Starting directory (default: process.cwd())
|
|
560
|
+
* @returns Absolute path to the config file, or null if none found
|
|
561
|
+
*/
|
|
562
|
+
declare function findConfig(cwd?: string): string | null;
|
|
563
|
+
/**
|
|
564
|
+
* Load and validate ultraenv configuration from a file.
|
|
565
|
+
*
|
|
566
|
+
* @param configPath - Explicit path to a config file. If not provided,
|
|
567
|
+
* auto-discovers using findConfig().
|
|
568
|
+
* @returns The fully resolved and validated UltraenvConfig
|
|
569
|
+
* @throws ConfigError if the config file is invalid or cannot be read
|
|
570
|
+
*/
|
|
571
|
+
declare function loadConfig(configPath?: string): UltraenvConfig;
|
|
572
|
+
|
|
573
|
+
interface CascadeOptions {
|
|
574
|
+
/** Directory to search for .env files (default: process.cwd()) */
|
|
575
|
+
envDir?: string;
|
|
576
|
+
/** Override the detected environment name */
|
|
577
|
+
environment?: string;
|
|
578
|
+
/** Specific file paths to load (takes priority over auto-detection) */
|
|
579
|
+
paths?: readonly string[];
|
|
580
|
+
/** Glob patterns for file matching */
|
|
581
|
+
patterns?: readonly string[];
|
|
582
|
+
/** Specific EnvFileType enum values to load */
|
|
583
|
+
files?: readonly EnvFileType[];
|
|
584
|
+
/** Merge strategy when multiple files define the same key */
|
|
585
|
+
mergeStrategy?: MergeStrategy;
|
|
586
|
+
/** Whether to include system env vars in the cascade (highest priority) */
|
|
587
|
+
includeSystemEnv?: boolean;
|
|
588
|
+
/** Custom system env snapshot (defaults to process.env) */
|
|
589
|
+
systemEnv?: Record<string, string | undefined>;
|
|
590
|
+
}
|
|
591
|
+
interface CascadeFileEntry {
|
|
592
|
+
/** Absolute path to the .env file */
|
|
593
|
+
absolutePath: string;
|
|
594
|
+
/** The file type (if recognized) */
|
|
595
|
+
fileType: EnvFileType | null;
|
|
596
|
+
/** Priority rank (higher = overrides lower) */
|
|
597
|
+
priority: number;
|
|
598
|
+
/** Whether the file exists on disk */
|
|
599
|
+
exists: boolean;
|
|
600
|
+
}
|
|
601
|
+
interface ResolvedCascadeResult {
|
|
602
|
+
/** Ordered list of file entries (lowest priority first) */
|
|
603
|
+
files: readonly CascadeFileEntry[];
|
|
604
|
+
/** The detected or specified environment name */
|
|
605
|
+
environment: string;
|
|
606
|
+
/** The merge strategy used */
|
|
607
|
+
mergeStrategy: MergeStrategy;
|
|
608
|
+
/** Whether system env vars are included */
|
|
609
|
+
includeSystemEnv: boolean;
|
|
610
|
+
/** The resolved env directory (absolute path) */
|
|
611
|
+
envDir: string;
|
|
612
|
+
/** Files that were found to exist */
|
|
613
|
+
existingFiles: readonly CascadeFileEntry[];
|
|
614
|
+
/** Source tracking: which file each key came from */
|
|
615
|
+
sources: Record<string, string>;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Resolve the file cascade based on the given options.
|
|
619
|
+
*
|
|
620
|
+
* This function determines which .env files to load and in what order.
|
|
621
|
+
* It supports:
|
|
622
|
+
* - Standard cascade: .env → .env.local → .env.{ENV} → .env.{ENV}.local
|
|
623
|
+
* - Custom file paths
|
|
624
|
+
* - Custom EnvFileType arrays
|
|
625
|
+
* - .env.local is skipped in test environment
|
|
626
|
+
*
|
|
627
|
+
* @param options - Cascade resolution options
|
|
628
|
+
* @returns ResolvedCascadeResult with ordered file list and metadata
|
|
629
|
+
* @throws ConfigError if options are invalid
|
|
630
|
+
*/
|
|
631
|
+
declare function resolveCascade(options?: CascadeOptions): ResolvedCascadeResult;
|
|
632
|
+
/**
|
|
633
|
+
* Merge parsed env files according to the cascade result and merge strategy.
|
|
634
|
+
*
|
|
635
|
+
* @param parsedFiles - Array of successfully parsed env files (in priority order)
|
|
636
|
+
* @param cascade - The resolved cascade result
|
|
637
|
+
* @returns Merged key-value pairs with source tracking
|
|
638
|
+
* @throws ConfigError on conflict when using 'error-on-conflict' strategy
|
|
639
|
+
*/
|
|
640
|
+
declare function mergeCascade(parsedFiles: readonly ParsedEnvFile[], cascade: ResolvedCascadeResult): Record<string, string>;
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Create a new EnvFileWatcher instance.
|
|
644
|
+
*
|
|
645
|
+
* @param options - Optional watch and cascade configuration
|
|
646
|
+
* @returns A new Watcher instance
|
|
647
|
+
*/
|
|
648
|
+
declare function createWatcher(options?: {
|
|
649
|
+
watchOptions?: WatchOptions;
|
|
650
|
+
cascadeOptions?: CascadeOptions;
|
|
651
|
+
}): Watcher;
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Encrypt an entire environment variable set using AES-256-GCM.
|
|
655
|
+
*
|
|
656
|
+
* The data is serialized to a deterministic string format (sorted keys,
|
|
657
|
+
* KEY=VALUE per line), then encrypted. The result includes the IV, auth tag,
|
|
658
|
+
* ciphertext, and algorithm identifier for later decryption.
|
|
659
|
+
*
|
|
660
|
+
* @param data - Object of environment variable key-value pairs.
|
|
661
|
+
* @param key - 32-byte encryption key.
|
|
662
|
+
* @returns EncryptionResult containing IV, auth tag, ciphertext, and algorithm.
|
|
663
|
+
* @throws EncryptionError if encryption fails.
|
|
664
|
+
*
|
|
665
|
+
* @example
|
|
666
|
+
* const result = encryptEnvironment(
|
|
667
|
+
* { DATABASE_URL: 'postgres://localhost/mydb', API_KEY: 'sk-123' },
|
|
668
|
+
* masterKey,
|
|
669
|
+
* );
|
|
670
|
+
*/
|
|
671
|
+
declare function encryptEnvironment(data: Record<string, string>, key: Buffer): EncryptionResult;
|
|
672
|
+
/**
|
|
673
|
+
* Decrypt environment data that was encrypted with encryptEnvironment.
|
|
674
|
+
*
|
|
675
|
+
* @param encrypted - The EncryptionResult from a previous encryptEnvironment call.
|
|
676
|
+
* @param key - The 32-byte encryption key (must match the encryption key).
|
|
677
|
+
* @returns The original serialized environment data string.
|
|
678
|
+
* @throws EncryptionError if decryption fails, the key is wrong, or data was tampered with.
|
|
679
|
+
*
|
|
680
|
+
* @example
|
|
681
|
+
* const serialized = decryptEnvironment(encryptedResult, masterKey);
|
|
682
|
+
* // serialized = "API_KEY=sk-123\nDATABASE_URL=postgres://localhost/mydb"
|
|
683
|
+
*/
|
|
684
|
+
declare function decryptEnvironment(encrypted: EncryptionResult, key: Buffer): string;
|
|
685
|
+
/**
|
|
686
|
+
* Encrypt a single value using AES-256-GCM and return it as a self-contained
|
|
687
|
+
* encoded string that includes the algorithm version, IV, auth tag, and ciphertext.
|
|
688
|
+
*
|
|
689
|
+
* Output format: `encrypted:v1:aes-256-gcm:{iv_base64}:{authTag_base64}:{ciphertext_base64}`
|
|
690
|
+
*
|
|
691
|
+
* This format is safe to store in .env files and .env.vault files.
|
|
692
|
+
* The IV and auth tag are generated fresh for each encryption.
|
|
693
|
+
*
|
|
694
|
+
* @param value - The plaintext string to encrypt.
|
|
695
|
+
* @param key - 32-byte encryption key.
|
|
696
|
+
* @returns The encrypted value in the standard ultraenv format.
|
|
697
|
+
* @throws EncryptionError if encryption fails.
|
|
698
|
+
*
|
|
699
|
+
* @example
|
|
700
|
+
* const encrypted = encryptValue('my-secret-password', masterKey);
|
|
701
|
+
* // encrypted = "encrypted:v1:aes-256-gcm:aBcDeF...:XyZ123...:QrStUv..."
|
|
702
|
+
*/
|
|
703
|
+
declare function encryptValue(value: string, key: Buffer): string;
|
|
704
|
+
/**
|
|
705
|
+
* Decrypt a single value that was encrypted with encryptValue.
|
|
706
|
+
*
|
|
707
|
+
* Parses the self-contained encrypted format:
|
|
708
|
+
* `encrypted:v1:aes-256-gcm:{iv_base64}:{authTag_base64}:{ciphertext_base64}`
|
|
709
|
+
*
|
|
710
|
+
* @param encrypted - The encrypted string in ultraenv format.
|
|
711
|
+
* @param key - 32-byte encryption key (must match the encryption key).
|
|
712
|
+
* @returns The original plaintext string.
|
|
713
|
+
* @throws EncryptionError if the format is invalid, decryption fails, or the key is wrong.
|
|
714
|
+
*
|
|
715
|
+
* @example
|
|
716
|
+
* const plaintext = decryptValue(
|
|
717
|
+
* 'encrypted:v1:aes-256-gcm:aBcDeF...:XyZ123...:QrStUv...',
|
|
718
|
+
* masterKey,
|
|
719
|
+
* );
|
|
720
|
+
* // plaintext = 'my-secret-password'
|
|
721
|
+
*/
|
|
722
|
+
declare function decryptValue(encrypted: string, key: Buffer): string;
|
|
723
|
+
/**
|
|
724
|
+
* Check if a string is an ultraenv-encrypted value.
|
|
725
|
+
*
|
|
726
|
+
* @param value - The string to check.
|
|
727
|
+
* @returns true if the value matches the encrypted format prefix.
|
|
728
|
+
*/
|
|
729
|
+
declare function isEncryptedValue(value: string): boolean;
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Generate a cryptographically secure 32-byte master key for AES-256 encryption.
|
|
733
|
+
*
|
|
734
|
+
* Uses node:crypto.randomBytes for cryptographically secure pseudo-random
|
|
735
|
+
* number generation (CSPRNG).
|
|
736
|
+
*
|
|
737
|
+
* @returns A 32-byte Buffer containing the master key.
|
|
738
|
+
*
|
|
739
|
+
* @example
|
|
740
|
+
* const masterKey = generateMasterKey();
|
|
741
|
+
* // masterKey is a 32-byte Buffer — keep it secret!
|
|
742
|
+
*/
|
|
743
|
+
declare function generateMasterKey(): Buffer;
|
|
744
|
+
/**
|
|
745
|
+
* Derive a per-environment encryption key from a master key using HKDF-SHA256.
|
|
746
|
+
*
|
|
747
|
+
* Each environment (development, staging, production, etc.) gets a unique key
|
|
748
|
+
* derived from the same master key. This means:
|
|
749
|
+
* - Compromising one environment's key does NOT compromise others.
|
|
750
|
+
* - Rotating an environment key only requires re-encrypting that environment.
|
|
751
|
+
* - The master key alone can derive all environment keys.
|
|
752
|
+
*
|
|
753
|
+
* Uses a fixed salt ("ultraenv") for deterministic derivation — the same
|
|
754
|
+
* master key + environment name always produces the same environment key.
|
|
755
|
+
*
|
|
756
|
+
* @param masterKey - The 32-byte master key.
|
|
757
|
+
* @param environment - The environment name (e.g., 'development', 'production').
|
|
758
|
+
* @returns A 32-byte derived key for the specified environment.
|
|
759
|
+
* @throws EncryptionError if the master key is invalid or derivation fails.
|
|
760
|
+
*
|
|
761
|
+
* @example
|
|
762
|
+
* const devKey = deriveEnvironmentKey(masterKey, 'development');
|
|
763
|
+
* const prodKey = deriveEnvironmentKey(masterKey, 'production');
|
|
764
|
+
* // devKey !== prodKey — each environment has a unique key
|
|
765
|
+
*/
|
|
766
|
+
declare function deriveEnvironmentKey(masterKey: Buffer, environment: string): Buffer;
|
|
767
|
+
/**
|
|
768
|
+
* Format a raw key Buffer into a human-readable string with a version prefix.
|
|
769
|
+
*
|
|
770
|
+
* Output format: `ultraenv_key_v1_{base64}`
|
|
771
|
+
*
|
|
772
|
+
* This format allows:
|
|
773
|
+
* - Easy identification of ultraenv keys
|
|
774
|
+
* - Future algorithm migration (v2, v3, etc.)
|
|
775
|
+
* - Safe storage in .env.keys files
|
|
776
|
+
*
|
|
777
|
+
* @param key - The raw key Buffer.
|
|
778
|
+
* @returns The formatted key string.
|
|
779
|
+
* @throws EncryptionError if the key is too short to encode.
|
|
780
|
+
*
|
|
781
|
+
* @example
|
|
782
|
+
* const formatted = formatKey(masterKey);
|
|
783
|
+
* // formatted = "ultraenv_key_v1_aBcDeF123456..."
|
|
784
|
+
*/
|
|
785
|
+
declare function formatKey(key: Buffer): string;
|
|
786
|
+
/**
|
|
787
|
+
* Parse a formatted key string back into a raw Buffer.
|
|
788
|
+
*
|
|
789
|
+
* Expects format: `ultraenv_key_v1_{base64}`
|
|
790
|
+
*
|
|
791
|
+
* @param formatted - The formatted key string.
|
|
792
|
+
* @returns The raw key Buffer.
|
|
793
|
+
* @throws EncryptionError if the format is invalid or base64 decoding fails.
|
|
794
|
+
*
|
|
795
|
+
* @example
|
|
796
|
+
* const key = parseKey('ultraenv_key_v1_aBcDeF123456...');
|
|
797
|
+
* // key is a 32-byte Buffer
|
|
798
|
+
*/
|
|
799
|
+
declare function parseKey(formatted: string): Buffer;
|
|
800
|
+
/**
|
|
801
|
+
* Check if a string matches the ultraenv key format.
|
|
802
|
+
*
|
|
803
|
+
* Validates the prefix is correct and that the base64 portion is non-empty
|
|
804
|
+
* and decodable to at least 16 bytes.
|
|
805
|
+
*
|
|
806
|
+
* @param formatted - The string to check.
|
|
807
|
+
* @returns true if the string appears to be a valid ultraenv key.
|
|
808
|
+
*
|
|
809
|
+
* @example
|
|
810
|
+
* isValidKeyFormat('ultraenv_key_v1_aBcDeF123=') // true
|
|
811
|
+
* isValidKeyFormat('not-a-key') // false
|
|
812
|
+
* isValidKeyFormat('ultraenv_key_v1_') // false
|
|
813
|
+
*/
|
|
814
|
+
declare function isValidKeyFormat(formatted: string): boolean;
|
|
815
|
+
/**
|
|
816
|
+
* Mask a formatted key for safe display in logs or terminal output.
|
|
817
|
+
*
|
|
818
|
+
* Shows only the first 8 and last 4 characters, replacing everything
|
|
819
|
+
* in between with asterisks.
|
|
820
|
+
*
|
|
821
|
+
* @param formatted - The formatted key string.
|
|
822
|
+
* @returns The masked key string.
|
|
823
|
+
*
|
|
824
|
+
* @example
|
|
825
|
+
* maskKey('ultraenv_key_v1_aBcDeFgHiJkLmNoPqRsTuVwXyZ==')
|
|
826
|
+
* // → "ultraenv********XyZ=="
|
|
827
|
+
*/
|
|
828
|
+
declare function maskKey(formatted: string): string;
|
|
829
|
+
/**
|
|
830
|
+
* Generate the content for a .env.keys file.
|
|
831
|
+
*
|
|
832
|
+
* The keys file stores environment-specific keys in a format that is safe
|
|
833
|
+
* to distribute through secure channels (NOT committed to git).
|
|
834
|
+
*
|
|
835
|
+
* Output format:
|
|
836
|
+
* ```
|
|
837
|
+
* # ultraenv encryption keys — DO NOT COMMIT
|
|
838
|
+
* # Generated: {ISO timestamp}
|
|
839
|
+
*
|
|
840
|
+
* ULTRAENV_KEY_DEVELOPMENT="ultraenv_key_v1_..."
|
|
841
|
+
* ULTRAENV_KEY_STAGING="ultraenv_key_v1_..."
|
|
842
|
+
* ULTRAENV_KEY_PRODUCTION="ultraenv_key_v1_..."
|
|
843
|
+
* ```
|
|
844
|
+
*
|
|
845
|
+
* @param environments - Array of environment names.
|
|
846
|
+
* @returns The complete .env.keys file content as a string.
|
|
847
|
+
*
|
|
848
|
+
* @example
|
|
849
|
+
* const masterKey = generateMasterKey();
|
|
850
|
+
* const keysFile = generateKeysFile(['development', 'staging', 'production'], masterKey);
|
|
851
|
+
*/
|
|
852
|
+
declare function generateKeysFile(environments: string[]): string;
|
|
853
|
+
/**
|
|
854
|
+
* Parse a .env.keys file and extract environment-to-key mappings.
|
|
855
|
+
*
|
|
856
|
+
* Expects lines in the format: `ULTRAENV_KEY_{ENV}="ultraenv_key_v1_..."`
|
|
857
|
+
*
|
|
858
|
+
* @param content - The raw content of the .env.keys file.
|
|
859
|
+
* @returns A Map of environment name → formatted key string.
|
|
860
|
+
* @throws EncryptionError if the file format is invalid.
|
|
861
|
+
*
|
|
862
|
+
* @example
|
|
863
|
+
* const keys = parseKeysFile(fileContent);
|
|
864
|
+
* // keys.get('development') → 'ultraenv_key_v1_...'
|
|
865
|
+
*/
|
|
866
|
+
declare function parseKeysFile(content: string): Map<string, string>;
|
|
867
|
+
/**
|
|
868
|
+
* Rotate encryption for data by decrypting with the old key and re-encrypting
|
|
869
|
+
* with the new key.
|
|
870
|
+
*
|
|
871
|
+
* This is used when you want to change the encryption key for an environment
|
|
872
|
+
* without losing the data. The process is:
|
|
873
|
+
* 1. Decrypt the data using the old key
|
|
874
|
+
* 2. Encrypt the same data using the new key
|
|
875
|
+
*
|
|
876
|
+
* @param oldKey - The current 32-byte encryption key.
|
|
877
|
+
* @param newData - The plaintext data (or previously encrypted data string).
|
|
878
|
+
* @param newKey - The new 32-byte encryption key.
|
|
879
|
+
* @returns The data encrypted with the new key (same format as encryptValue).
|
|
880
|
+
* @throws EncryptionError if either key is invalid or operations fail.
|
|
881
|
+
*
|
|
882
|
+
* @example
|
|
883
|
+
* const newEncrypted = rotateKey(oldEnvironmentKey, 'my-secret', newEnvironmentKey);
|
|
884
|
+
*/
|
|
885
|
+
declare function rotateKey(oldKey: Buffer, newData: string, newKey: Buffer): string;
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Internal vault entry that pairs the encrypted payload with environment metadata.
|
|
889
|
+
* Extends the public VaultEnvironment type with the encrypted data needed for
|
|
890
|
+
* serialization.
|
|
891
|
+
*/
|
|
892
|
+
interface VaultEntry extends VaultEnvironment {
|
|
893
|
+
/** The full encrypted payload string for this environment */
|
|
894
|
+
encrypted: string;
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* Parse the content of a .env.vault file into a Map of environment entries.
|
|
898
|
+
*
|
|
899
|
+
* Expected format:
|
|
900
|
+
* ```
|
|
901
|
+
* # ultraenv encrypted vault — safe to commit
|
|
902
|
+
* # Generated: {ISO timestamp}
|
|
903
|
+
* # Environments: development, staging, production
|
|
904
|
+
*
|
|
905
|
+
* ULTRAENV_VAULT_DEVELOPMENT="encrypted:v1:aes-256-gcm:..."
|
|
906
|
+
* ULTRAENV_VAULT_STAGING="encrypted:v1:aes-256-gcm:..."
|
|
907
|
+
* ```
|
|
908
|
+
*
|
|
909
|
+
* Comments (lines starting with #) and blank lines are ignored.
|
|
910
|
+
* Environment names are normalized to lowercase.
|
|
911
|
+
*
|
|
912
|
+
* @param content - The raw file content.
|
|
913
|
+
* @returns A Map of environment name (lowercase) → VaultEntry.
|
|
914
|
+
* @throws VaultError if the file format is invalid.
|
|
915
|
+
*
|
|
916
|
+
* @example
|
|
917
|
+
* const vault = parseVaultFile(fileContent);
|
|
918
|
+
* const devEntry = vault.get('development');
|
|
919
|
+
* // devEntry?.encrypted = "encrypted:v1:aes-256-gcm:..."
|
|
920
|
+
* // devEntry?.varCount = 5
|
|
921
|
+
*/
|
|
922
|
+
declare function parseVaultFile(content: string): Map<string, VaultEntry>;
|
|
923
|
+
/**
|
|
924
|
+
* Serialize a Map of vault entries into the .env.vault file format.
|
|
925
|
+
*
|
|
926
|
+
* Output format:
|
|
927
|
+
* ```
|
|
928
|
+
* # ultraenv encrypted vault — safe to commit
|
|
929
|
+
* # Generated: {ISO timestamp}
|
|
930
|
+
* # Environments: development, staging, production
|
|
931
|
+
*
|
|
932
|
+
* ULTRAENV_VAULT_DEVELOPMENT="encrypted:v1:aes-256-gcm:..."
|
|
933
|
+
* ULTRAENV_VAULT_STAGING="encrypted:v1:aes-256-gcm:..."
|
|
934
|
+
* ```
|
|
935
|
+
*
|
|
936
|
+
* @param environments - A Map of environment name → VaultEntry.
|
|
937
|
+
* @returns The complete vault file content as a string.
|
|
938
|
+
*
|
|
939
|
+
* @example
|
|
940
|
+
* const content = serializeVaultFile(vaultMap);
|
|
941
|
+
*/
|
|
942
|
+
declare function serializeVaultFile(environments: Map<string, VaultEntry>): string;
|
|
943
|
+
/**
|
|
944
|
+
* Read a .env.vault file from disk and parse it into a Map of entries.
|
|
945
|
+
*
|
|
946
|
+
* @param path - Absolute or relative path to the vault file.
|
|
947
|
+
* @returns A Map of environment name → VaultEntry.
|
|
948
|
+
* @throws VaultError if the file cannot be read or has an invalid format.
|
|
949
|
+
*
|
|
950
|
+
* @example
|
|
951
|
+
* const vault = await readVaultFile('.env.vault');
|
|
952
|
+
*/
|
|
953
|
+
declare function readVaultFile(path: string): Promise<Map<string, VaultEntry>>;
|
|
954
|
+
/**
|
|
955
|
+
* Write vault entries to a .env.vault file on disk.
|
|
956
|
+
*
|
|
957
|
+
* Creates parent directories if needed. The file is overwritten atomically
|
|
958
|
+
* (written in full, not appended).
|
|
959
|
+
*
|
|
960
|
+
* @param path - Absolute or relative path to the vault file.
|
|
961
|
+
* @param environments - A Map of environment name → VaultEntry to write.
|
|
962
|
+
* @throws VaultError if the file cannot be written.
|
|
963
|
+
*
|
|
964
|
+
* @example
|
|
965
|
+
* await writeVaultFile('.env.vault', vaultMap);
|
|
966
|
+
*/
|
|
967
|
+
declare function writeVaultFile(path: string, environments: Map<string, VaultEntry>): Promise<void>;
|
|
968
|
+
/**
|
|
969
|
+
* Get the vault entry for a specific environment from a parsed vault.
|
|
970
|
+
*
|
|
971
|
+
* @param vault - The parsed vault Map.
|
|
972
|
+
* @param env - The environment name (case-insensitive).
|
|
973
|
+
* @returns The VaultEntry if found, undefined otherwise.
|
|
974
|
+
*
|
|
975
|
+
* @example
|
|
976
|
+
* const entry = getEnvironmentData(vault, 'production');
|
|
977
|
+
* if (entry) {
|
|
978
|
+
* console.log(`Found ${entry.varCount} encrypted variables`);
|
|
979
|
+
* }
|
|
980
|
+
*/
|
|
981
|
+
declare function getEnvironmentData(vault: Map<string, VaultEntry>, env: string): VaultEntry | undefined;
|
|
982
|
+
/**
|
|
983
|
+
* Get a list of all environment names stored in the vault.
|
|
984
|
+
*
|
|
985
|
+
* @param vault - The parsed vault Map.
|
|
986
|
+
* @returns Array of environment names sorted alphabetically.
|
|
987
|
+
*/
|
|
988
|
+
declare function getVaultEnvironments(vault: Map<string, VaultEntry>): string[];
|
|
989
|
+
|
|
990
|
+
/**
|
|
991
|
+
* Compute an HMAC-SHA256 integrity hash for data using the given key.
|
|
992
|
+
*
|
|
993
|
+
* The integrity hash authenticates that the data has not been modified
|
|
994
|
+
* since it was created. It is NOT a confidentiality mechanism — the data
|
|
995
|
+
* itself is not encrypted by this function.
|
|
996
|
+
*
|
|
997
|
+
* @param data - The string data to authenticate.
|
|
998
|
+
* @param key - The HMAC key (can be the encryption key or a separate integrity key).
|
|
999
|
+
* @returns The HMAC-SHA256 digest as a lowercase hex string (64 characters).
|
|
1000
|
+
* @throws EncryptionError if the key or data is empty.
|
|
1001
|
+
*
|
|
1002
|
+
* @example
|
|
1003
|
+
* const digest = computeIntegrity(serializedEnvData, encryptionKey);
|
|
1004
|
+
* // digest = "a1b2c3d4e5f6...64 chars..."
|
|
1005
|
+
*/
|
|
1006
|
+
declare function computeIntegrity(data: string, key: Buffer): string;
|
|
1007
|
+
/**
|
|
1008
|
+
* Verify the HMAC-SHA256 integrity of data using constant-time comparison.
|
|
1009
|
+
*
|
|
1010
|
+
* This function is resistant to timing attacks because it uses
|
|
1011
|
+
* `crypto.timingSafeEqual` internally. Even if the data or expected digest
|
|
1012
|
+
* differ, the function takes the same amount of time to complete.
|
|
1013
|
+
*
|
|
1014
|
+
* @param data - The string data to verify.
|
|
1015
|
+
* @param key - The HMAC key (must match the key used to compute the digest).
|
|
1016
|
+
* @param expected - The expected HMAC-SHA256 hex digest.
|
|
1017
|
+
* @returns true if the computed digest matches the expected digest.
|
|
1018
|
+
* @throws EncryptionError if the inputs are invalid.
|
|
1019
|
+
*
|
|
1020
|
+
* @example
|
|
1021
|
+
* const isValid = verifyIntegrity(data, key, storedDigest);
|
|
1022
|
+
* if (!isValid) {
|
|
1023
|
+
* throw new Error('Data has been tampered with!');
|
|
1024
|
+
* }
|
|
1025
|
+
*/
|
|
1026
|
+
declare function verifyIntegrity(data: string, key: Buffer, expected: string): boolean;
|
|
1027
|
+
/**
|
|
1028
|
+
* Compute a checksum over all environments in the vault.
|
|
1029
|
+
*
|
|
1030
|
+
* The checksum is computed by:
|
|
1031
|
+
* 1. Sorting environment names alphabetically
|
|
1032
|
+
* 2. Concatenating all encrypted payloads with their environment names
|
|
1033
|
+
* 3. Computing HMAC-SHA256 over the combined data
|
|
1034
|
+
*
|
|
1035
|
+
* This provides a single integrity check for the entire vault file.
|
|
1036
|
+
* If ANY environment's data changes, the vault checksum will change.
|
|
1037
|
+
*
|
|
1038
|
+
* @param environments - A Map of environment name → VaultEnvironment.
|
|
1039
|
+
* Each VaultEnvironment's `name` and `keyIds` are used to construct
|
|
1040
|
+
* the checksum input. The encrypted data is typically stored in a
|
|
1041
|
+
* VaultEntry (extends VaultEnvironment) — if the `encrypted` property
|
|
1042
|
+
* exists, it will be included.
|
|
1043
|
+
* @param key - The HMAC key for computing the checksum.
|
|
1044
|
+
* @returns The vault checksum as a lowercase hex string.
|
|
1045
|
+
* @throws EncryptionError if the inputs are invalid.
|
|
1046
|
+
*
|
|
1047
|
+
* @example
|
|
1048
|
+
* const checksum = computeVaultChecksum(vaultEntries, integrityKey);
|
|
1049
|
+
*/
|
|
1050
|
+
declare function computeVaultChecksum(environments: Map<string, VaultEnvironment>, key: Buffer): string;
|
|
1051
|
+
/**
|
|
1052
|
+
* Verify the integrity of the entire vault against an expected checksum.
|
|
1053
|
+
*
|
|
1054
|
+
* @param environments - A Map of environment name → VaultEnvironment.
|
|
1055
|
+
* @param key - The HMAC key used to compute the original checksum.
|
|
1056
|
+
* @param expected - The expected vault checksum (64-char hex string).
|
|
1057
|
+
* @returns true if the computed checksum matches the expected checksum.
|
|
1058
|
+
* @throws EncryptionError if the inputs are invalid.
|
|
1059
|
+
*
|
|
1060
|
+
* @example
|
|
1061
|
+
* const isValid = verifyVaultChecksum(vaultEntries, integrityKey, storedChecksum);
|
|
1062
|
+
*/
|
|
1063
|
+
declare function verifyVaultChecksum(environments: Map<string, VaultEnvironment>, key: Buffer, expected: string): boolean;
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* A secure buffer wrapper that automatically zeroes its contents on garbage
|
|
1067
|
+
* collection and provides safe access methods.
|
|
1068
|
+
*
|
|
1069
|
+
* Unlike a regular Buffer, SecureBuffer:
|
|
1070
|
+
* - Zeros its contents when garbage collected (via FinalizationRegistry)
|
|
1071
|
+
* - Does not expose the raw buffer to JSON.stringify or console.log
|
|
1072
|
+
* - Provides explicit zero() and fill() methods for manual cleanup
|
|
1073
|
+
*
|
|
1074
|
+
* **Important**: While SecureBuffer reduces the risk of sensitive data
|
|
1075
|
+
* remaining in memory, it cannot provide absolute guarantees. Node.js V8
|
|
1076
|
+
* engine may create copies of the data during garbage collection or
|
|
1077
|
+
* serialization. Use defense-in-depth practices.
|
|
1078
|
+
*
|
|
1079
|
+
* @example
|
|
1080
|
+
* const buf = new SecureBuffer(32);
|
|
1081
|
+
* buf.fill(0); // Fill with zeros
|
|
1082
|
+
* // ... use buf ...
|
|
1083
|
+
* buf.zero(); // Explicitly zero when done
|
|
1084
|
+
* // buf will also be zeroed automatically when garbage collected
|
|
1085
|
+
*/
|
|
1086
|
+
declare class SecureBuffer {
|
|
1087
|
+
private _buffer;
|
|
1088
|
+
private _length;
|
|
1089
|
+
private _zeroed;
|
|
1090
|
+
/** Track all live SecureBuffers for FinalizationRegistry cleanup */
|
|
1091
|
+
private static readonly registry;
|
|
1092
|
+
/** Counter for generating unique token identifiers */
|
|
1093
|
+
private static _instanceCount;
|
|
1094
|
+
/**
|
|
1095
|
+
* Create a new SecureBuffer.
|
|
1096
|
+
*
|
|
1097
|
+
* @param size - The size of the buffer in bytes.
|
|
1098
|
+
* @throws RangeError if size is not a positive integer.
|
|
1099
|
+
*/
|
|
1100
|
+
constructor(size: number);
|
|
1101
|
+
/**
|
|
1102
|
+
* Create a SecureBuffer from an existing Buffer.
|
|
1103
|
+
* The source buffer is NOT modified — a copy is made.
|
|
1104
|
+
*
|
|
1105
|
+
* @param source - The source buffer to copy.
|
|
1106
|
+
* @returns A new SecureBuffer containing a copy of the source data.
|
|
1107
|
+
*/
|
|
1108
|
+
static from(source: Buffer | Uint8Array): SecureBuffer;
|
|
1109
|
+
/**
|
|
1110
|
+
* Create a SecureBuffer from a string.
|
|
1111
|
+
*
|
|
1112
|
+
* @param str - The string to encode.
|
|
1113
|
+
* @param encoding - The character encoding (default: 'utf-8').
|
|
1114
|
+
* @returns A new SecureBuffer containing the encoded string.
|
|
1115
|
+
*/
|
|
1116
|
+
static fromString(str: string, encoding?: BufferEncoding): SecureBuffer;
|
|
1117
|
+
/**
|
|
1118
|
+
* The size of the buffer in bytes.
|
|
1119
|
+
*/
|
|
1120
|
+
get length(): number;
|
|
1121
|
+
/**
|
|
1122
|
+
* Whether the buffer has been zeroed.
|
|
1123
|
+
*/
|
|
1124
|
+
get isZeroed(): boolean;
|
|
1125
|
+
/**
|
|
1126
|
+
* Fill the buffer with the specified byte value.
|
|
1127
|
+
*
|
|
1128
|
+
* @param value - The byte value to fill with (0-255).
|
|
1129
|
+
* @returns This SecureBuffer for chaining.
|
|
1130
|
+
*/
|
|
1131
|
+
fill(value: number): SecureBuffer;
|
|
1132
|
+
/**
|
|
1133
|
+
* Fill the buffer with random bytes.
|
|
1134
|
+
*
|
|
1135
|
+
* @returns This SecureBuffer for chaining.
|
|
1136
|
+
*/
|
|
1137
|
+
fillRandom(): SecureBuffer;
|
|
1138
|
+
/**
|
|
1139
|
+
* Zero out all bytes in the buffer.
|
|
1140
|
+
*
|
|
1141
|
+
* This should be called as soon as the sensitive data is no longer needed.
|
|
1142
|
+
* The buffer will also be zeroed automatically on garbage collection, but
|
|
1143
|
+
* explicit zeroing provides faster cleanup for time-sensitive operations.
|
|
1144
|
+
*
|
|
1145
|
+
* @returns This SecureBuffer for chaining.
|
|
1146
|
+
*/
|
|
1147
|
+
zero(): SecureBuffer;
|
|
1148
|
+
/**
|
|
1149
|
+
* Get a read-only copy of the underlying buffer.
|
|
1150
|
+
*
|
|
1151
|
+
* **Warning**: This returns a COPY of the buffer contents.
|
|
1152
|
+
* The caller is responsible for zeroing the returned buffer when done.
|
|
1153
|
+
* Use toString() when possible to avoid managing raw buffers.
|
|
1154
|
+
*
|
|
1155
|
+
* @returns A copy of the buffer contents.
|
|
1156
|
+
*/
|
|
1157
|
+
getBuffer(): Buffer;
|
|
1158
|
+
/**
|
|
1159
|
+
* Get a single byte at the specified index.
|
|
1160
|
+
*
|
|
1161
|
+
* @param index - The byte index.
|
|
1162
|
+
* @returns The byte value (0-255).
|
|
1163
|
+
*/
|
|
1164
|
+
getByte(index: number): number;
|
|
1165
|
+
/**
|
|
1166
|
+
* Convert the buffer contents to a string.
|
|
1167
|
+
*
|
|
1168
|
+
* @param encoding - The character encoding (default: 'utf-8').
|
|
1169
|
+
* @returns The decoded string.
|
|
1170
|
+
*/
|
|
1171
|
+
toString(encoding?: BufferEncoding): string;
|
|
1172
|
+
/**
|
|
1173
|
+
* Convert to hex string.
|
|
1174
|
+
*
|
|
1175
|
+
* @returns Lowercase hex string.
|
|
1176
|
+
*/
|
|
1177
|
+
toHex(): string;
|
|
1178
|
+
/**
|
|
1179
|
+
* Convert to base64 string.
|
|
1180
|
+
*
|
|
1181
|
+
* @returns Base64-encoded string.
|
|
1182
|
+
*/
|
|
1183
|
+
toBase64(): string;
|
|
1184
|
+
/**
|
|
1185
|
+
* JSON serialization — never exposes the buffer contents.
|
|
1186
|
+
* Returns a placeholder string to prevent accidental logging of secrets.
|
|
1187
|
+
*
|
|
1188
|
+
* @returns A safe placeholder string.
|
|
1189
|
+
*/
|
|
1190
|
+
toJSON(): string;
|
|
1191
|
+
/**
|
|
1192
|
+
* Manual cleanup — call when the SecureBuffer is no longer needed.
|
|
1193
|
+
* Zeros the buffer and unregisters from the FinalizationRegistry.
|
|
1194
|
+
*
|
|
1195
|
+
* After calling dispose(), the buffer cannot be used.
|
|
1196
|
+
*/
|
|
1197
|
+
dispose(): void;
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* A secure string that stores its backing data in a SecureBuffer.
|
|
1201
|
+
* Provides string-like methods while ensuring the underlying data
|
|
1202
|
+
* can be securely zeroed.
|
|
1203
|
+
*
|
|
1204
|
+
* @example
|
|
1205
|
+
* const secret = createSecureString('my-api-key-12345');
|
|
1206
|
+
* console.log(secret.value); // 'my-api-key-12345'
|
|
1207
|
+
* secret.dispose(); // Zeros the backing buffer
|
|
1208
|
+
* console.log(secret.value); // ''
|
|
1209
|
+
*/
|
|
1210
|
+
declare class SecureString {
|
|
1211
|
+
private _buffer;
|
|
1212
|
+
private _disposed;
|
|
1213
|
+
/**
|
|
1214
|
+
* Create a new SecureString.
|
|
1215
|
+
*
|
|
1216
|
+
* **Internal**: Use the `createSecureString()` factory function instead
|
|
1217
|
+
* of calling this constructor directly.
|
|
1218
|
+
*
|
|
1219
|
+
* @param buffer - The SecureBuffer backing this string.
|
|
1220
|
+
* @internal
|
|
1221
|
+
*/
|
|
1222
|
+
constructor(buffer: SecureBuffer);
|
|
1223
|
+
/**
|
|
1224
|
+
* The string value.
|
|
1225
|
+
* Returns empty string if the backing buffer has been zeroed/disposed.
|
|
1226
|
+
*/
|
|
1227
|
+
get value(): string;
|
|
1228
|
+
/**
|
|
1229
|
+
* The length of the string in characters.
|
|
1230
|
+
*/
|
|
1231
|
+
get length(): number;
|
|
1232
|
+
/**
|
|
1233
|
+
* Whether this SecureString has been disposed.
|
|
1234
|
+
*/
|
|
1235
|
+
get disposed(): boolean;
|
|
1236
|
+
/**
|
|
1237
|
+
* Zero the backing buffer and mark as disposed.
|
|
1238
|
+
* After calling dispose(), value will always return ''.
|
|
1239
|
+
*/
|
|
1240
|
+
dispose(): void;
|
|
1241
|
+
/**
|
|
1242
|
+
* JSON serialization — never exposes the string contents.
|
|
1243
|
+
*/
|
|
1244
|
+
toJSON(): string;
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Create a SecureString from a plain string.
|
|
1248
|
+
*
|
|
1249
|
+
* The plain string's data is copied into a SecureBuffer. Note that the
|
|
1250
|
+
* original string may still exist in V8's string table until GC runs.
|
|
1251
|
+
*
|
|
1252
|
+
* @param value - The string value to wrap securely.
|
|
1253
|
+
* @returns A SecureString instance.
|
|
1254
|
+
*
|
|
1255
|
+
* @example
|
|
1256
|
+
* const apiKey = createSecureString('sk-abc123def456');
|
|
1257
|
+
* console.log(apiKey.value); // 'sk-abc123def456'
|
|
1258
|
+
* apiKey.dispose();
|
|
1259
|
+
*/
|
|
1260
|
+
declare function createSecureString(value: string): SecureString;
|
|
1261
|
+
/**
|
|
1262
|
+
* Create a SecureString from a Buffer.
|
|
1263
|
+
*
|
|
1264
|
+
* @param buffer - The buffer containing the string data.
|
|
1265
|
+
* @param encoding - The character encoding (default: 'utf-8').
|
|
1266
|
+
* @returns A SecureString instance.
|
|
1267
|
+
*/
|
|
1268
|
+
declare function createSecureStringFromBuffer(buffer: Buffer, encoding?: BufferEncoding): SecureString;
|
|
1269
|
+
/**
|
|
1270
|
+
* Attempt to overwrite a string's memory with zeros.
|
|
1271
|
+
*
|
|
1272
|
+
* **Important limitation**: JavaScript strings are immutable in V8. This
|
|
1273
|
+
* function works by creating a modified string that replaces characters,
|
|
1274
|
+
* but V8 may retain copies of the original string in memory. This is a
|
|
1275
|
+
* best-effort mitigation, not a guarantee.
|
|
1276
|
+
*
|
|
1277
|
+
* For truly secure handling, prefer SecureBuffer and SecureString which
|
|
1278
|
+
* use mutable Buffer storage that CAN be reliably zeroed.
|
|
1279
|
+
*
|
|
1280
|
+
* @param str - The string to attempt to wipe.
|
|
1281
|
+
*
|
|
1282
|
+
* @example
|
|
1283
|
+
* let password = 'my-secret-password';
|
|
1284
|
+
* // ... use password ...
|
|
1285
|
+
* wipeString(password);
|
|
1286
|
+
* password = '';
|
|
1287
|
+
*/
|
|
1288
|
+
declare function wipeString(str: string): void;
|
|
1289
|
+
/**
|
|
1290
|
+
* Constant-time comparison of two strings or Buffers.
|
|
1291
|
+
*
|
|
1292
|
+
* This function always takes the same amount of time regardless of where
|
|
1293
|
+
* the first difference occurs, preventing timing attacks that could
|
|
1294
|
+
* reveal information about the expected value.
|
|
1295
|
+
*
|
|
1296
|
+
* For strings: converts to UTF-8 Buffers and compares.
|
|
1297
|
+
* For Buffers: compares directly.
|
|
1298
|
+
* Different-length inputs are safely handled (returns false in constant time).
|
|
1299
|
+
*
|
|
1300
|
+
* @param a - First value (string or Buffer).
|
|
1301
|
+
* @param b - Second value (string or Buffer).
|
|
1302
|
+
* @returns true if the values are identical.
|
|
1303
|
+
*
|
|
1304
|
+
* @example
|
|
1305
|
+
* // Safe for comparing passwords, tokens, API keys, etc.
|
|
1306
|
+
* const isMatch = secureCompare(userInput, storedHash);
|
|
1307
|
+
*
|
|
1308
|
+
* // Also works with Buffers
|
|
1309
|
+
* const isMatch = secureCompare(keyBuffer, expectedKeyBuffer);
|
|
1310
|
+
*/
|
|
1311
|
+
declare function secureCompare(a: string | Buffer, b: string | Buffer): boolean;
|
|
1312
|
+
|
|
1313
|
+
/**
|
|
1314
|
+
* Scan multiple files for secrets.
|
|
1315
|
+
*
|
|
1316
|
+
* Collects files from the given paths, respects include/exclude patterns,
|
|
1317
|
+
* skips binary files and common non-source directories, checks .gitignore,
|
|
1318
|
+
* and runs both pattern matching and entropy analysis on each file.
|
|
1319
|
+
*
|
|
1320
|
+
* @param paths - File or directory paths to scan.
|
|
1321
|
+
* @param options - Scan configuration options.
|
|
1322
|
+
* @returns A ScanResult with all detected secrets and metadata.
|
|
1323
|
+
*/
|
|
1324
|
+
declare function scanFiles(paths: readonly string[], options?: Partial<ScanOptions>): Promise<ScanResult>;
|
|
1325
|
+
|
|
1326
|
+
/**
|
|
1327
|
+
* Scan files staged for commit (in the git index) for secrets.
|
|
1328
|
+
*
|
|
1329
|
+
* Uses `git diff --cached` to get the staged content and scans it
|
|
1330
|
+
* for any detected secrets.
|
|
1331
|
+
*
|
|
1332
|
+
* @param cwd - Working directory (default: process.cwd()).
|
|
1333
|
+
* @returns Array of DetectedSecret objects found in staged files.
|
|
1334
|
+
*/
|
|
1335
|
+
declare function scanStagedFiles(cwd?: string): Promise<DetectedSecret[]>;
|
|
1336
|
+
/**
|
|
1337
|
+
* Scan a git diff between two refs (or between a ref and working tree) for secrets.
|
|
1338
|
+
*
|
|
1339
|
+
* @param from - The base commit ref.
|
|
1340
|
+
* @param to - The target commit ref. If omitted, compares to working tree.
|
|
1341
|
+
* @param cwd - Working directory.
|
|
1342
|
+
* @returns Array of DetectedSecret objects found in the diff.
|
|
1343
|
+
*/
|
|
1344
|
+
declare function scanDiff(from: string, to?: string, cwd?: string): Promise<DetectedSecret[]>;
|
|
1345
|
+
/**
|
|
1346
|
+
* Git history scanning options.
|
|
1347
|
+
*/
|
|
1348
|
+
interface GitScanOptions {
|
|
1349
|
+
/** Starting commit (default: HEAD~100) */
|
|
1350
|
+
from?: string;
|
|
1351
|
+
/** Ending commit (default: HEAD) */
|
|
1352
|
+
to?: string;
|
|
1353
|
+
/** Working directory (default: process.cwd()) */
|
|
1354
|
+
cwd?: string;
|
|
1355
|
+
/** Number of commits to scan (default: 100) */
|
|
1356
|
+
depth?: number;
|
|
1357
|
+
/** Whether to scan all history (overrides depth) */
|
|
1358
|
+
allHistory?: boolean;
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Scan git commit history for secrets.
|
|
1362
|
+
*
|
|
1363
|
+
* Uses `git log -p` to get patch content for each commit and scans
|
|
1364
|
+
* for secrets. Reports each finding with the associated commit hash.
|
|
1365
|
+
*
|
|
1366
|
+
* @param options - Git scanning options.
|
|
1367
|
+
* @returns A ScanResult with secrets found in git history.
|
|
1368
|
+
*/
|
|
1369
|
+
declare function scanGitHistory(options?: GitScanOptions): Promise<ScanResult>;
|
|
1370
|
+
|
|
1371
|
+
/**
|
|
1372
|
+
* Match all registered patterns against the given content.
|
|
1373
|
+
*
|
|
1374
|
+
* Iterates over every pattern in the registry and collects all detections.
|
|
1375
|
+
*
|
|
1376
|
+
* @param content - The text content to scan.
|
|
1377
|
+
* @param filePath - Path to the file being scanned.
|
|
1378
|
+
* @returns Array of DetectedSecret objects for all pattern matches.
|
|
1379
|
+
*/
|
|
1380
|
+
declare function matchPatterns(content: string, filePath: string): DetectedSecret[];
|
|
1381
|
+
/**
|
|
1382
|
+
* Add a custom secret detection pattern to the registry.
|
|
1383
|
+
*
|
|
1384
|
+
* If a pattern with the same ID already exists, it will be replaced.
|
|
1385
|
+
*
|
|
1386
|
+
* @param pattern - The SecretPattern to add.
|
|
1387
|
+
* @throws {Error} If the pattern has an invalid regex.
|
|
1388
|
+
*/
|
|
1389
|
+
declare function addCustomPattern(pattern: SecretPattern): void;
|
|
1390
|
+
/**
|
|
1391
|
+
* Remove a custom (or built-in) pattern from the registry by ID.
|
|
1392
|
+
*
|
|
1393
|
+
* @param id - The unique pattern identifier to remove.
|
|
1394
|
+
* @returns true if a pattern was removed, false if not found.
|
|
1395
|
+
*/
|
|
1396
|
+
declare function removeCustomPattern(id: string): boolean;
|
|
1397
|
+
/**
|
|
1398
|
+
* Remove all custom patterns, restoring the registry to built-in patterns only.
|
|
1399
|
+
*/
|
|
1400
|
+
declare function resetPatterns(): void;
|
|
1401
|
+
|
|
1402
|
+
/**
|
|
1403
|
+
* Supported output formats.
|
|
1404
|
+
*/
|
|
1405
|
+
type OutputFormat = 'terminal' | 'json' | 'sarif';
|
|
1406
|
+
/**
|
|
1407
|
+
* Format a scan result in the specified output format.
|
|
1408
|
+
*
|
|
1409
|
+
* @param result - The scan result to format.
|
|
1410
|
+
* @param format - The output format ('terminal', 'json', or 'sarif').
|
|
1411
|
+
* @returns A formatted string representation of the scan result.
|
|
1412
|
+
*/
|
|
1413
|
+
declare function formatScanResult(result: ScanResult, format: OutputFormat): string;
|
|
1414
|
+
|
|
1415
|
+
/**
|
|
1416
|
+
* Full scan options including git-specific options.
|
|
1417
|
+
*/
|
|
1418
|
+
interface FullScanOptions extends Partial<ScanOptions> {
|
|
1419
|
+
/** Whether to scan staged files (for pre-commit hooks) */
|
|
1420
|
+
scanStaged?: boolean;
|
|
1421
|
+
/** Git ref to diff against (for diff scanning) */
|
|
1422
|
+
diffFrom?: string;
|
|
1423
|
+
/** Git ref to diff to (for diff scanning) */
|
|
1424
|
+
diffTo?: string;
|
|
1425
|
+
/** Number of git history commits to scan */
|
|
1426
|
+
gitDepth?: number;
|
|
1427
|
+
/** Scan all git history (overrides gitDepth) */
|
|
1428
|
+
gitAllHistory?: boolean;
|
|
1429
|
+
/** Output format for the report */
|
|
1430
|
+
outputFormat?: 'terminal' | 'json' | 'sarif';
|
|
1431
|
+
/** Working directory */
|
|
1432
|
+
cwd?: string;
|
|
1433
|
+
/** Paths to scan (files or directories) */
|
|
1434
|
+
paths?: string[];
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Perform a comprehensive secret scan.
|
|
1438
|
+
*
|
|
1439
|
+
* Combines:
|
|
1440
|
+
* 1. File scanning (pattern matching + entropy analysis)
|
|
1441
|
+
* 2. Git history scanning (if enabled)
|
|
1442
|
+
* 3. Staged file scanning (if enabled)
|
|
1443
|
+
* 4. Diff scanning (if refs provided)
|
|
1444
|
+
*
|
|
1445
|
+
* Results are deduplicated and sorted by severity.
|
|
1446
|
+
*
|
|
1447
|
+
* @param options - Scan configuration options.
|
|
1448
|
+
* @returns A ScanResult with all detected secrets and metadata.
|
|
1449
|
+
*
|
|
1450
|
+
* @example
|
|
1451
|
+
* // Scan current directory
|
|
1452
|
+
* const result = await scan();
|
|
1453
|
+
* console.log(formatScanResult(result, 'terminal'));
|
|
1454
|
+
*
|
|
1455
|
+
* // Scan with options
|
|
1456
|
+
* const result = await scan({
|
|
1457
|
+
* include: ['src/', 'config/'],
|
|
1458
|
+
* exclude: ['src/*.test.ts'],
|
|
1459
|
+
* scanGitHistory: true,
|
|
1460
|
+
* });
|
|
1461
|
+
*/
|
|
1462
|
+
declare function scan(options?: FullScanOptions): Promise<ScanResult>;
|
|
1463
|
+
|
|
1464
|
+
interface EntropyOptions {
|
|
1465
|
+
/** Minimum Shannon entropy threshold (default: 3.5) */
|
|
1466
|
+
threshold?: number;
|
|
1467
|
+
/** Minimum string length to consider (default: 20) */
|
|
1468
|
+
minLength?: number;
|
|
1469
|
+
/** Maximum string length to consider (default: 500) */
|
|
1470
|
+
maxLength?: number;
|
|
1471
|
+
/** Whether to include the high-entropy pattern in results (default: true) */
|
|
1472
|
+
includeDefaultPattern?: boolean;
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* Scan a single line for high-entropy strings.
|
|
1476
|
+
*
|
|
1477
|
+
* Extracts candidate strings from the line, computes Shannon entropy,
|
|
1478
|
+
* filters false positives, and returns detections above the threshold.
|
|
1479
|
+
*
|
|
1480
|
+
* @param line - The line of text to scan.
|
|
1481
|
+
* @param lineNumber - The 1-based line number.
|
|
1482
|
+
* @param filePath - The file path being scanned.
|
|
1483
|
+
* @param options - Entropy detection options.
|
|
1484
|
+
* @returns Array of DetectedSecret objects for high-entropy strings found.
|
|
1485
|
+
*/
|
|
1486
|
+
declare function scanLineForEntropy(line: string, lineNumber: number, filePath: string, options?: EntropyOptions): DetectedSecret[];
|
|
1487
|
+
/**
|
|
1488
|
+
* Detect high-entropy strings in file content.
|
|
1489
|
+
*
|
|
1490
|
+
* Processes the content line by line, extracts candidate strings,
|
|
1491
|
+
* computes Shannon entropy, and returns detections above the threshold.
|
|
1492
|
+
*
|
|
1493
|
+
* @param content - The full text content to scan.
|
|
1494
|
+
* @param filePath - The file path being scanned.
|
|
1495
|
+
* @param options - Entropy detection options.
|
|
1496
|
+
* @returns Array of DetectedSecret objects for high-entropy strings found.
|
|
1497
|
+
*/
|
|
1498
|
+
declare function detectHighEntropyStrings(content: string, filePath: string, options?: EntropyOptions): DetectedSecret[];
|
|
1499
|
+
|
|
1500
|
+
interface GenerateExampleOptions {
|
|
1501
|
+
/** Include type hint comments (default: true) */
|
|
1502
|
+
includeDescriptions?: boolean;
|
|
1503
|
+
/** Include type annotation comments (default: true) */
|
|
1504
|
+
includeTypes?: boolean;
|
|
1505
|
+
/** Include default values in comments (default: true) */
|
|
1506
|
+
includeDefaults?: boolean;
|
|
1507
|
+
/** Path to a schema file (TypeScript module exporting schema) for metadata */
|
|
1508
|
+
schemaPath?: string;
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* Generate a .env.example file from a .env file.
|
|
1512
|
+
*
|
|
1513
|
+
* Reads the .env file, strips secret values, preserves comments and variable
|
|
1514
|
+
* ordering, and optionally adds type hints, descriptions, and default values
|
|
1515
|
+
* from a schema definition.
|
|
1516
|
+
*
|
|
1517
|
+
* @param envPath - Path to the source .env file
|
|
1518
|
+
* @param outputPath - Path where the .env.example will be written
|
|
1519
|
+
* @param options - Generation options
|
|
1520
|
+
* @throws FileSystemError if the .env file cannot be read
|
|
1521
|
+
*/
|
|
1522
|
+
declare function generateExampleFile(envPath: string, outputPath: string, options?: GenerateExampleOptions): Promise<void>;
|
|
1523
|
+
/**
|
|
1524
|
+
* Generate the content of a .env.example file from parsed variables.
|
|
1525
|
+
*
|
|
1526
|
+
* @param vars - Parsed environment variables from a .env file
|
|
1527
|
+
* @param schema - Optional schema definition for type/description metadata
|
|
1528
|
+
* @param options - Generation options
|
|
1529
|
+
* @returns The complete .env.example file content as a string
|
|
1530
|
+
*/
|
|
1531
|
+
declare function generateExampleContent(vars: readonly ParsedEnvVar[], schema?: SchemaDefinition, options?: {
|
|
1532
|
+
includeDescriptions?: boolean;
|
|
1533
|
+
includeTypes?: boolean;
|
|
1534
|
+
includeDefaults?: boolean;
|
|
1535
|
+
}): string;
|
|
1536
|
+
/**
|
|
1537
|
+
* Check if a .env.example file needs updating by comparing its content
|
|
1538
|
+
* with what would be generated from the current .env file.
|
|
1539
|
+
*/
|
|
1540
|
+
declare function needsUpdate(envPath: string, examplePath: string, options?: GenerateExampleOptions): Promise<boolean>;
|
|
1541
|
+
|
|
1542
|
+
/**
|
|
1543
|
+
* Result of comparing .env against .env.example.
|
|
1544
|
+
*/
|
|
1545
|
+
interface SyncDiff {
|
|
1546
|
+
/** Whether the two files are perfectly in sync */
|
|
1547
|
+
inSync: boolean;
|
|
1548
|
+
/** Variables present in .env.example but missing from .env */
|
|
1549
|
+
missing: readonly string[];
|
|
1550
|
+
/** Variables present in .env but not in .env.example */
|
|
1551
|
+
extra: readonly string[];
|
|
1552
|
+
/** Variables present in both but with different values (example has placeholder) */
|
|
1553
|
+
different: readonly string[];
|
|
1554
|
+
/** Variables present in both with the same value */
|
|
1555
|
+
same: readonly string[];
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* Compare a .env file against a .env.example file.
|
|
1559
|
+
*
|
|
1560
|
+
* Analyzes both files and categorizes every variable into:
|
|
1561
|
+
* - **missing**: present in .env.example but not in .env (needs to be added)
|
|
1562
|
+
* - **extra**: present in .env but not in .env.example (possibly sensitive)
|
|
1563
|
+
* - **different**: present in both but values differ (example may have placeholder)
|
|
1564
|
+
* - **same**: present in both with matching values
|
|
1565
|
+
*
|
|
1566
|
+
* A file is considered "in sync" when there are no missing or extra variables.
|
|
1567
|
+
* "Different" variables do NOT cause inSync to be false since the .env.example
|
|
1568
|
+
* typically contains placeholder values rather than actual secrets.
|
|
1569
|
+
*
|
|
1570
|
+
* @param envPath - Path to the .env file
|
|
1571
|
+
* @param examplePath - Path to the .env.example file
|
|
1572
|
+
* @returns SyncDiff with categorized differences
|
|
1573
|
+
* @throws FileSystemError if either file cannot be read
|
|
1574
|
+
*/
|
|
1575
|
+
declare function compareSync(envPath: string, examplePath: string): Promise<SyncDiff>;
|
|
1576
|
+
/**
|
|
1577
|
+
* Compare two sets of environment variables.
|
|
1578
|
+
*
|
|
1579
|
+
* This is the core comparison logic, useful when you already have parsed
|
|
1580
|
+
* variables and don't need file I/O.
|
|
1581
|
+
*
|
|
1582
|
+
* @param envVars - The actual environment variables (e.g., from .env)
|
|
1583
|
+
* @param exampleVars - The example/template variables (e.g., from .env.example)
|
|
1584
|
+
* @returns SyncDiff with categorized differences
|
|
1585
|
+
*/
|
|
1586
|
+
declare function compareValues(envVars: Record<string, string>, exampleVars: Record<string, string>): SyncDiff;
|
|
1587
|
+
|
|
1588
|
+
interface CreateSyncWatcherOptions {
|
|
1589
|
+
/** Path to the .env file to watch */
|
|
1590
|
+
envPath: string;
|
|
1591
|
+
/** Path to the .env.example file to update */
|
|
1592
|
+
examplePath: string;
|
|
1593
|
+
/** Schema definition for type hints (if available) */
|
|
1594
|
+
schema?: SchemaDefinition;
|
|
1595
|
+
/** Debounce interval in milliseconds (default: 300) */
|
|
1596
|
+
debounceMs?: number;
|
|
1597
|
+
/** Whether to include descriptions in the generated example */
|
|
1598
|
+
includeDescriptions?: boolean;
|
|
1599
|
+
/** Whether to include type annotations */
|
|
1600
|
+
includeTypes?: boolean;
|
|
1601
|
+
/** Whether to include default values */
|
|
1602
|
+
includeDefaults?: boolean;
|
|
1603
|
+
/** Callback invoked after a successful sync */
|
|
1604
|
+
onSync?: (result: SyncWatcherResult) => void;
|
|
1605
|
+
}
|
|
1606
|
+
interface SyncWatcherResult {
|
|
1607
|
+
/** Whether the sync was successful */
|
|
1608
|
+
success: boolean;
|
|
1609
|
+
/** The env file that triggered the sync */
|
|
1610
|
+
envPath: string;
|
|
1611
|
+
/** The example file that was updated */
|
|
1612
|
+
examplePath: string;
|
|
1613
|
+
/** Error message if sync failed */
|
|
1614
|
+
error?: string;
|
|
1615
|
+
/** Timestamp of the sync */
|
|
1616
|
+
timestamp: string;
|
|
1617
|
+
}
|
|
1618
|
+
/**
|
|
1619
|
+
* Create a new SyncWatcher that monitors a .env file and auto-updates .env.example.
|
|
1620
|
+
*
|
|
1621
|
+
* @param options - Configuration for the watcher
|
|
1622
|
+
* @returns A Watcher instance
|
|
1623
|
+
*
|
|
1624
|
+
* @example
|
|
1625
|
+
* ```ts
|
|
1626
|
+
* import { createSyncWatcher } from 'ultraenv/sync';
|
|
1627
|
+
*
|
|
1628
|
+
* const watcher = createSyncWatcher({
|
|
1629
|
+
* envPath: '.env',
|
|
1630
|
+
* examplePath: '.env.example',
|
|
1631
|
+
* onSync: (result) => {
|
|
1632
|
+
* if (result.success) {
|
|
1633
|
+
* console.log('.env.example updated');
|
|
1634
|
+
* }
|
|
1635
|
+
* },
|
|
1636
|
+
* });
|
|
1637
|
+
*
|
|
1638
|
+
* watcher.start();
|
|
1639
|
+
* process.on('SIGINT', () => watcher.stop());
|
|
1640
|
+
* ```
|
|
1641
|
+
*/
|
|
1642
|
+
declare function createSyncWatcher(options: CreateSyncWatcherOptions): Watcher;
|
|
1643
|
+
|
|
1644
|
+
interface GenerateDeclarationOptions {
|
|
1645
|
+
/** Interface name for the generated env type (default: 'UltraenvEnv') */
|
|
1646
|
+
interfaceName?: string;
|
|
1647
|
+
/** Custom header comment */
|
|
1648
|
+
header?: string;
|
|
1649
|
+
/** Whether to include JSDoc comments from schema descriptions */
|
|
1650
|
+
jsdoc?: boolean;
|
|
1651
|
+
/** Indentation in spaces (default: 4) */
|
|
1652
|
+
indent?: number;
|
|
1653
|
+
}
|
|
1654
|
+
/**
|
|
1655
|
+
* Generate TypeScript declaration content that augments NodeJS.ProcessEnv.
|
|
1656
|
+
*/
|
|
1657
|
+
declare function generateDeclaration(vars: Record<string, string>, schema?: SchemaDefinition, outputPath?: string, options?: GenerateDeclarationOptions): Promise<string>;
|
|
1658
|
+
|
|
1659
|
+
interface GenerateModuleOptions {
|
|
1660
|
+
/** Interface name (default: 'Env') */
|
|
1661
|
+
interfaceName?: string;
|
|
1662
|
+
/** Custom header comment */
|
|
1663
|
+
header?: string;
|
|
1664
|
+
/** Whether to include JSDoc comments from schema descriptions */
|
|
1665
|
+
jsdoc?: boolean;
|
|
1666
|
+
/** Indentation in spaces (default: 2) */
|
|
1667
|
+
indent?: number;
|
|
1668
|
+
/** Whether to export the interface as default */
|
|
1669
|
+
exportAsDefault?: boolean;
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* Generate a TypeScript module with a typed Env interface.
|
|
1673
|
+
*/
|
|
1674
|
+
declare function generateModule(schema: SchemaDefinition, outputPath?: string, options?: GenerateModuleOptions): Promise<string>;
|
|
1675
|
+
|
|
1676
|
+
interface GenerateJsonSchemaOptions {
|
|
1677
|
+
/** Title for the JSON Schema (default: 'Environment Variables') */
|
|
1678
|
+
title?: string;
|
|
1679
|
+
/** Description for the JSON Schema */
|
|
1680
|
+
description?: string;
|
|
1681
|
+
/** Whether to include schema descriptions in the output */
|
|
1682
|
+
includeDescriptions?: boolean;
|
|
1683
|
+
/** Indentation in spaces (default: 2) */
|
|
1684
|
+
indent?: number;
|
|
1685
|
+
}
|
|
1686
|
+
/**
|
|
1687
|
+
* Generate a JSON Schema (draft-07) from a SchemaDefinition.
|
|
1688
|
+
*/
|
|
1689
|
+
declare function generateJsonSchema(schema: SchemaDefinition, outputPath?: string, options?: GenerateJsonSchemaOptions): Promise<string>;
|
|
1690
|
+
|
|
1691
|
+
type TypegenFormat = 'declaration' | 'module' | 'json-schema' | 'all';
|
|
1692
|
+
interface CreateTypegenWatcherOptions {
|
|
1693
|
+
/** Path to the schema file (watched for changes) */
|
|
1694
|
+
schemaPath?: string;
|
|
1695
|
+
/** Path to the .env file (watched for changes) */
|
|
1696
|
+
envPath?: string;
|
|
1697
|
+
/** Output path for the generated type file(s) */
|
|
1698
|
+
outputPath: string;
|
|
1699
|
+
/** The schema definition (used when schemaPath is not provided) */
|
|
1700
|
+
schema?: SchemaDefinition;
|
|
1701
|
+
/** Which formats to generate (default: 'declaration') */
|
|
1702
|
+
format?: TypegenFormat;
|
|
1703
|
+
/** Debounce interval in milliseconds (default: 300) */
|
|
1704
|
+
debounceMs?: number;
|
|
1705
|
+
/** Callback invoked after generation */
|
|
1706
|
+
onGenerate?: (result: TypegenResult) => void;
|
|
1707
|
+
}
|
|
1708
|
+
interface TypegenResult {
|
|
1709
|
+
/** Whether generation was successful */
|
|
1710
|
+
success: boolean;
|
|
1711
|
+
/** The format that was generated */
|
|
1712
|
+
format: TypegenFormat;
|
|
1713
|
+
/** Output path(s) written */
|
|
1714
|
+
outputPaths: readonly string[];
|
|
1715
|
+
/** Error message if generation failed */
|
|
1716
|
+
error?: string;
|
|
1717
|
+
/** Timestamp */
|
|
1718
|
+
timestamp: string;
|
|
1719
|
+
}
|
|
1720
|
+
/**
|
|
1721
|
+
* Create a new TypegenWatcher that monitors schema and env files,
|
|
1722
|
+
* regenerating type declarations whenever changes are detected.
|
|
1723
|
+
*
|
|
1724
|
+
* @param options - Configuration for the watcher
|
|
1725
|
+
* @returns A Watcher instance
|
|
1726
|
+
*
|
|
1727
|
+
* @example
|
|
1728
|
+
* ```ts
|
|
1729
|
+
* import { createTypegenWatcher } from 'ultraenv/typegen';
|
|
1730
|
+
*
|
|
1731
|
+
* const watcher = createTypegenWatcher({
|
|
1732
|
+
* envPath: '.env',
|
|
1733
|
+
* outputPath: 'src/env.d.ts',
|
|
1734
|
+
* schema: mySchema,
|
|
1735
|
+
* format: 'all',
|
|
1736
|
+
* onGenerate: (result) => {
|
|
1737
|
+
* if (result.success) {
|
|
1738
|
+
* console.log(`Generated: ${result.outputPaths.join(', ')}`);
|
|
1739
|
+
* }
|
|
1740
|
+
* },
|
|
1741
|
+
* });
|
|
1742
|
+
*
|
|
1743
|
+
* watcher.start();
|
|
1744
|
+
* process.on('SIGINT', () => watcher.stop());
|
|
1745
|
+
* ```
|
|
1746
|
+
*/
|
|
1747
|
+
declare function createTypegenWatcher(options: CreateTypegenWatcherOptions): Watcher;
|
|
1748
|
+
|
|
1749
|
+
interface EnvironmentInfo {
|
|
1750
|
+
name: string;
|
|
1751
|
+
fileName: string;
|
|
1752
|
+
absolutePath: string;
|
|
1753
|
+
exists: boolean;
|
|
1754
|
+
variableCount: number;
|
|
1755
|
+
fileSize: number;
|
|
1756
|
+
lastModified: string;
|
|
1757
|
+
}
|
|
1758
|
+
type EnvironmentValidationMap = Map<string, {
|
|
1759
|
+
valid: boolean;
|
|
1760
|
+
errors: readonly {
|
|
1761
|
+
field: string;
|
|
1762
|
+
value: string;
|
|
1763
|
+
message: string;
|
|
1764
|
+
hint: string;
|
|
1765
|
+
}[];
|
|
1766
|
+
warnings: readonly {
|
|
1767
|
+
field: string;
|
|
1768
|
+
value: string;
|
|
1769
|
+
message: string;
|
|
1770
|
+
code: string;
|
|
1771
|
+
}[];
|
|
1772
|
+
}>;
|
|
1773
|
+
declare function listEnvironments(cwd?: string): Promise<EnvironmentInfo[]>;
|
|
1774
|
+
declare function validateAllEnvironments(schema: SchemaDefinition, cwd?: string): Promise<EnvironmentValidationMap>;
|
|
1775
|
+
declare function switchEnvironment(envName: string, cwd?: string): Promise<void>;
|
|
1776
|
+
declare function getActiveEnvironment(cwd?: string): Promise<string>;
|
|
1777
|
+
declare function discoverEnvironments(cwd?: string): Promise<string[]>;
|
|
1778
|
+
|
|
1779
|
+
/**
|
|
1780
|
+
* Result of comparing two environments.
|
|
1781
|
+
*/
|
|
1782
|
+
interface EnvironmentComparison {
|
|
1783
|
+
/** The first environment name */
|
|
1784
|
+
env1Name: string;
|
|
1785
|
+
/** The second environment name */
|
|
1786
|
+
env2Name: string;
|
|
1787
|
+
/** Variables only present in env1 */
|
|
1788
|
+
onlyInEnv1: readonly EnvDifference[];
|
|
1789
|
+
/** Variables only present in env2 */
|
|
1790
|
+
onlyInEnv2: readonly EnvDifference[];
|
|
1791
|
+
/** Variables present in both but with different values */
|
|
1792
|
+
different: readonly EnvDifference[];
|
|
1793
|
+
/** Variables present in both with the same value */
|
|
1794
|
+
same: readonly string[];
|
|
1795
|
+
/** Warnings about potentially dangerous differences */
|
|
1796
|
+
warnings: readonly ComparisonWarning[];
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1799
|
+
* A single variable difference between two environments.
|
|
1800
|
+
*/
|
|
1801
|
+
interface EnvDifference {
|
|
1802
|
+
/** The variable name */
|
|
1803
|
+
key: string;
|
|
1804
|
+
/** Value in env1 (masked if secret) */
|
|
1805
|
+
value1: string;
|
|
1806
|
+
/** Value in env2 (masked if secret) */
|
|
1807
|
+
value2: string;
|
|
1808
|
+
/** Whether the value is a secret */
|
|
1809
|
+
isSecret: boolean;
|
|
1810
|
+
}
|
|
1811
|
+
/**
|
|
1812
|
+
* A warning about a potentially dangerous difference.
|
|
1813
|
+
*/
|
|
1814
|
+
interface ComparisonWarning {
|
|
1815
|
+
/** The variable name */
|
|
1816
|
+
key: string;
|
|
1817
|
+
/** Warning message */
|
|
1818
|
+
message: string;
|
|
1819
|
+
/** Severity level */
|
|
1820
|
+
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
1821
|
+
/** Value in env1 (masked) */
|
|
1822
|
+
value1: string;
|
|
1823
|
+
/** Value in env2 (masked) */
|
|
1824
|
+
value2: string;
|
|
1825
|
+
}
|
|
1826
|
+
/**
|
|
1827
|
+
* Compare two .env environment files and report differences.
|
|
1828
|
+
*
|
|
1829
|
+
* This compares the variables between two environments, masks secret values
|
|
1830
|
+
* in the output, and generates warnings for potentially dangerous differences
|
|
1831
|
+
* (e.g., different database URLs, disabled security features, debug mode enabled).
|
|
1832
|
+
*
|
|
1833
|
+
* @param env1 - Name of the first environment (e.g., 'development')
|
|
1834
|
+
* @param env2 - Name of the second environment (e.g., 'production')
|
|
1835
|
+
* @param cwd - The directory containing the .env files
|
|
1836
|
+
* @param schema - Optional schema for identifying secrets and required fields
|
|
1837
|
+
* @returns EnvironmentComparison with detailed difference information
|
|
1838
|
+
* @throws FileSystemError if either environment file cannot be read
|
|
1839
|
+
*/
|
|
1840
|
+
declare function compareEnvironments(env1: string, env2: string, cwd?: string, _schema?: unknown): Promise<EnvironmentComparison>;
|
|
1841
|
+
/**
|
|
1842
|
+
* Format an EnvironmentComparison into a human-readable summary string.
|
|
1843
|
+
*
|
|
1844
|
+
* @param comparison - The comparison result
|
|
1845
|
+
* @returns Formatted string suitable for terminal output
|
|
1846
|
+
*/
|
|
1847
|
+
declare function formatComparison(comparison: EnvironmentComparison): string;
|
|
1848
|
+
|
|
1849
|
+
interface CreateEnvironmentOptions {
|
|
1850
|
+
copyFrom?: string;
|
|
1851
|
+
fromTemplate?: string;
|
|
1852
|
+
interactive?: boolean;
|
|
1853
|
+
schema?: SchemaDefinition;
|
|
1854
|
+
cwd?: string;
|
|
1855
|
+
values?: Record<string, string>;
|
|
1856
|
+
}
|
|
1857
|
+
declare function createEnvironment(name: string, options?: CreateEnvironmentOptions): Promise<void>;
|
|
1858
|
+
declare function removeEnvironment(name: string, cwd?: string): Promise<void>;
|
|
1859
|
+
declare function duplicateEnvironment(sourceName: string, targetName: string, cwd?: string): Promise<void>;
|
|
1860
|
+
|
|
1861
|
+
/**
|
|
1862
|
+
* Register a preset by name.
|
|
1863
|
+
*
|
|
1864
|
+
* If a preset with the same name already exists, it will be replaced
|
|
1865
|
+
* with a warning logged to stderr.
|
|
1866
|
+
*
|
|
1867
|
+
* @param name - Unique identifier for the preset (e.g., 'nextjs', 'vite')
|
|
1868
|
+
* @param preset - The preset definition
|
|
1869
|
+
*
|
|
1870
|
+
* @example
|
|
1871
|
+
* ```typescript
|
|
1872
|
+
* import { registerPreset } from 'ultraenv/presets';
|
|
1873
|
+
* registerPreset('my-framework', { id: 'my-framework', ... });
|
|
1874
|
+
* ```
|
|
1875
|
+
*/
|
|
1876
|
+
declare function registerPreset(name: string, preset: Preset): void;
|
|
1877
|
+
/**
|
|
1878
|
+
* Retrieve a preset by name.
|
|
1879
|
+
*
|
|
1880
|
+
* @param name - The preset identifier
|
|
1881
|
+
* @returns The preset definition, or undefined if not found
|
|
1882
|
+
*
|
|
1883
|
+
* @example
|
|
1884
|
+
* ```typescript
|
|
1885
|
+
* import { getPreset } from 'ultraenv/presets';
|
|
1886
|
+
* const nextjs = getPreset('nextjs');
|
|
1887
|
+
* console.log(nextjs?.schema);
|
|
1888
|
+
* ```
|
|
1889
|
+
*/
|
|
1890
|
+
declare function getPreset(name: string): Preset | undefined;
|
|
1891
|
+
/**
|
|
1892
|
+
* List all registered preset names.
|
|
1893
|
+
*
|
|
1894
|
+
* @returns Array of preset identifier strings
|
|
1895
|
+
*
|
|
1896
|
+
* @example
|
|
1897
|
+
* ```typescript
|
|
1898
|
+
* import { listPresets } from 'ultraenv/presets';
|
|
1899
|
+
* console.log(listPresets());
|
|
1900
|
+
* // ['nextjs', 'vite', 'nuxt', 'remix', 'sveltekit', 'express', 'fastify', 'docker', 'aws-lambda']
|
|
1901
|
+
* ```
|
|
1902
|
+
*/
|
|
1903
|
+
declare function listPresets(): string[];
|
|
1904
|
+
/**
|
|
1905
|
+
* Check if a preset is registered.
|
|
1906
|
+
*
|
|
1907
|
+
* @param name - The preset identifier
|
|
1908
|
+
* @returns Whether the preset exists in the registry
|
|
1909
|
+
*/
|
|
1910
|
+
declare function hasPreset(name: string): boolean;
|
|
1911
|
+
/**
|
|
1912
|
+
* Remove a preset from the registry.
|
|
1913
|
+
*
|
|
1914
|
+
* @param name - The preset identifier to remove
|
|
1915
|
+
* @returns Whether the preset was found and removed
|
|
1916
|
+
*/
|
|
1917
|
+
declare function unregisterPreset(name: string): boolean;
|
|
1918
|
+
/**
|
|
1919
|
+
* Get all registered presets as a readonly record.
|
|
1920
|
+
*
|
|
1921
|
+
* @returns Readonly record of preset name → preset definition
|
|
1922
|
+
*/
|
|
1923
|
+
declare function getAllPresets(): Readonly<Record<string, Preset>>;
|
|
1924
|
+
|
|
1925
|
+
/** Health check configuration options */
|
|
1926
|
+
interface HealthCheckOptions {
|
|
1927
|
+
/**
|
|
1928
|
+
* Custom env source to check.
|
|
1929
|
+
* Defaults to process.env.
|
|
1930
|
+
*/
|
|
1931
|
+
source?: Record<string, string | undefined>;
|
|
1932
|
+
/**
|
|
1933
|
+
* List of loaded .env files (for metadata).
|
|
1934
|
+
*/
|
|
1935
|
+
loadedFiles?: readonly string[];
|
|
1936
|
+
/**
|
|
1937
|
+
* Total number of validated variables (from schema validation).
|
|
1938
|
+
*/
|
|
1939
|
+
validCount?: number;
|
|
1940
|
+
/**
|
|
1941
|
+
* Additional metadata to include in the health response.
|
|
1942
|
+
*/
|
|
1943
|
+
metadata?: Record<string, string | number | boolean>;
|
|
1944
|
+
}
|
|
1945
|
+
/** Health check response structure */
|
|
1946
|
+
interface HealthCheckResult {
|
|
1947
|
+
/** Overall health status: 'ok' or 'error' */
|
|
1948
|
+
status: 'ok' | 'error';
|
|
1949
|
+
/** Total number of environment variables loaded */
|
|
1950
|
+
loaded: number;
|
|
1951
|
+
/** Number of variables that passed validation */
|
|
1952
|
+
valid: number;
|
|
1953
|
+
/** Current environment name */
|
|
1954
|
+
environment: string;
|
|
1955
|
+
/** List of .env files that were loaded */
|
|
1956
|
+
files: readonly string[];
|
|
1957
|
+
/** ISO 8601 timestamp of the check */
|
|
1958
|
+
timestamp: string;
|
|
1959
|
+
/** Any additional metadata */
|
|
1960
|
+
metadata: Record<string, string | number | boolean>;
|
|
1961
|
+
}
|
|
1962
|
+
/**
|
|
1963
|
+
* Perform an environment health check.
|
|
1964
|
+
*
|
|
1965
|
+
* Returns a structured object with health status information
|
|
1966
|
+
* WITHOUT exposing any secret values. This is safe to expose
|
|
1967
|
+
* via HTTP endpoints.
|
|
1968
|
+
*
|
|
1969
|
+
* @param options - Health check configuration
|
|
1970
|
+
* @returns Health check result
|
|
1971
|
+
*
|
|
1972
|
+
* @example
|
|
1973
|
+
* ```typescript
|
|
1974
|
+
* import { healthCheck } from 'ultraenv';
|
|
1975
|
+
* import { loadWithResult } from 'ultraenv';
|
|
1976
|
+
*
|
|
1977
|
+
* const result = loadWithResult();
|
|
1978
|
+
* const health = healthCheck({
|
|
1979
|
+
* source: result.env,
|
|
1980
|
+
* loadedFiles: result.parsed.map(f => f.path),
|
|
1981
|
+
* validCount: result.validation?.errors.length === 0 ? Object.keys(result.env).length : 0,
|
|
1982
|
+
* });
|
|
1983
|
+
*
|
|
1984
|
+
* // Use in Express:
|
|
1985
|
+
* app.get('/health/env', (req, res) => res.json(healthCheck()));
|
|
1986
|
+
*
|
|
1987
|
+
* // Use in Fastify:
|
|
1988
|
+
* fastify.get('/health/env', async () => healthCheck());
|
|
1989
|
+
* ```
|
|
1990
|
+
*/
|
|
1991
|
+
declare function healthCheck(options?: HealthCheckOptions): HealthCheckResult;
|
|
1992
|
+
/**
|
|
1993
|
+
* Returns a minimal liveness check response.
|
|
1994
|
+
* Suitable for Kubernetes liveness probes.
|
|
1995
|
+
*
|
|
1996
|
+
* @returns Simple liveness response
|
|
1997
|
+
*
|
|
1998
|
+
* @example
|
|
1999
|
+
* app.get('/health/live', (req, res) => res.json(liveCheck()));
|
|
2000
|
+
* // → { status: 'ok', timestamp: '2024-01-15T10:30:00.000Z' }
|
|
2001
|
+
*/
|
|
2002
|
+
declare function liveCheck(): {
|
|
2003
|
+
status: 'ok';
|
|
2004
|
+
timestamp: string;
|
|
2005
|
+
};
|
|
2006
|
+
/**
|
|
2007
|
+
* Returns a readiness check that verifies critical env vars are set.
|
|
2008
|
+
*
|
|
2009
|
+
* @param requiredVars - List of env var names that MUST be set
|
|
2010
|
+
* @param source - Custom env source (defaults to process.env)
|
|
2011
|
+
* @returns Readiness check result
|
|
2012
|
+
*
|
|
2013
|
+
* @example
|
|
2014
|
+
* app.get('/health/ready', (req, res) => {
|
|
2015
|
+
* res.json(readinessCheck(['DATABASE_URL', 'JWT_SECRET']));
|
|
2016
|
+
* });
|
|
2017
|
+
* // → { status: 'ok', ready: true, missing: [], timestamp: '...' }
|
|
2018
|
+
* // → { status: 'error', ready: false, missing: ['DATABASE_URL'], timestamp: '...' }
|
|
2019
|
+
*/
|
|
2020
|
+
declare function readinessCheck(requiredVars: readonly string[], source?: Record<string, string | undefined>): {
|
|
2021
|
+
status: 'ok' | 'error';
|
|
2022
|
+
ready: boolean;
|
|
2023
|
+
missing: readonly string[];
|
|
2024
|
+
timestamp: string;
|
|
2025
|
+
};
|
|
2026
|
+
|
|
2027
|
+
/**
|
|
2028
|
+
* Base error class for all ultraenv errors.
|
|
2029
|
+
* Provides a structured `code` field, an optional `hint` for remediation,
|
|
2030
|
+
* and a `cause` wrapper for chaining.
|
|
2031
|
+
*/
|
|
2032
|
+
declare class UltraenvError extends Error {
|
|
2033
|
+
/** Machine-readable error code (e.g., 'PARSE_ERROR', 'ENCRYPTION_ERROR') */
|
|
2034
|
+
readonly code: string;
|
|
2035
|
+
/** Human-readable hint for how to fix this error */
|
|
2036
|
+
readonly hint?: string;
|
|
2037
|
+
/** The original cause of this error, if wrapping another error */
|
|
2038
|
+
readonly cause?: Error;
|
|
2039
|
+
constructor(message: string, options?: {
|
|
2040
|
+
code?: string;
|
|
2041
|
+
hint?: string;
|
|
2042
|
+
cause?: Error;
|
|
2043
|
+
});
|
|
2044
|
+
/** Return a formatted string with code, message, and hint */
|
|
2045
|
+
toString(): string;
|
|
2046
|
+
}
|
|
2047
|
+
/**
|
|
2048
|
+
* Thrown when an environment variable fails schema validation.
|
|
2049
|
+
*/
|
|
2050
|
+
declare class ValidationError extends UltraenvError {
|
|
2051
|
+
/** The variable name that failed validation */
|
|
2052
|
+
readonly field: string;
|
|
2053
|
+
/** The actual value that was provided */
|
|
2054
|
+
readonly value: string;
|
|
2055
|
+
/** The schema definition that was violated */
|
|
2056
|
+
readonly schema: unknown;
|
|
2057
|
+
/** Expected type or constraint description */
|
|
2058
|
+
readonly expected: string;
|
|
2059
|
+
constructor(field: string, value: string, message: string, options?: {
|
|
2060
|
+
hint?: string;
|
|
2061
|
+
schema?: unknown;
|
|
2062
|
+
expected?: string;
|
|
2063
|
+
cause?: Error;
|
|
2064
|
+
});
|
|
2065
|
+
}
|
|
2066
|
+
/**
|
|
2067
|
+
* Thrown when an .env file cannot be parsed due to malformed syntax.
|
|
2068
|
+
*/
|
|
2069
|
+
declare class ParseError extends UltraenvError {
|
|
2070
|
+
/** 1-based line number where the error occurred */
|
|
2071
|
+
readonly line: number;
|
|
2072
|
+
/** 1-based column number where the error occurred */
|
|
2073
|
+
readonly column: number;
|
|
2074
|
+
/** The raw content of the line that caused the error */
|
|
2075
|
+
readonly raw: string;
|
|
2076
|
+
/** Path to the file being parsed */
|
|
2077
|
+
readonly filePath: string;
|
|
2078
|
+
constructor(message: string, options?: {
|
|
2079
|
+
line?: number;
|
|
2080
|
+
column?: number;
|
|
2081
|
+
raw?: string;
|
|
2082
|
+
filePath?: string;
|
|
2083
|
+
hint?: string;
|
|
2084
|
+
cause?: Error;
|
|
2085
|
+
});
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Thrown when variable interpolation (e.g., $VAR or ${VAR}) fails.
|
|
2089
|
+
*/
|
|
2090
|
+
declare class InterpolationError extends UltraenvError {
|
|
2091
|
+
/** The variable reference that caused the error */
|
|
2092
|
+
readonly variable: string;
|
|
2093
|
+
/** Whether this was caused by a circular reference */
|
|
2094
|
+
readonly circular: boolean;
|
|
2095
|
+
constructor(message: string, options?: {
|
|
2096
|
+
variable?: string;
|
|
2097
|
+
circular?: boolean;
|
|
2098
|
+
hint?: string;
|
|
2099
|
+
cause?: Error;
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
/**
|
|
2103
|
+
* Thrown when encryption or decryption operations fail.
|
|
2104
|
+
*/
|
|
2105
|
+
declare class EncryptionError extends UltraenvError {
|
|
2106
|
+
constructor(message: string, options?: {
|
|
2107
|
+
hint?: string;
|
|
2108
|
+
cause?: Error;
|
|
2109
|
+
});
|
|
2110
|
+
}
|
|
2111
|
+
/**
|
|
2112
|
+
* Thrown when vault operations fail (lock/unlock/encrypt/decrypt).
|
|
2113
|
+
*/
|
|
2114
|
+
declare class VaultError extends UltraenvError {
|
|
2115
|
+
/** The environment name involved */
|
|
2116
|
+
readonly environment: string;
|
|
2117
|
+
/** The vault operation that failed */
|
|
2118
|
+
readonly operation: string;
|
|
2119
|
+
constructor(message: string, options?: {
|
|
2120
|
+
environment?: string;
|
|
2121
|
+
operation?: string;
|
|
2122
|
+
hint?: string;
|
|
2123
|
+
cause?: Error;
|
|
2124
|
+
});
|
|
2125
|
+
}
|
|
2126
|
+
/**
|
|
2127
|
+
* Thrown when secret scanning encounters an issue.
|
|
2128
|
+
*/
|
|
2129
|
+
declare class ScanError extends UltraenvError {
|
|
2130
|
+
/** The file being scanned */
|
|
2131
|
+
readonly file: string;
|
|
2132
|
+
/** The line number where the error occurred */
|
|
2133
|
+
readonly line: number;
|
|
2134
|
+
/** The secret pattern that triggered the error */
|
|
2135
|
+
readonly pattern: string;
|
|
2136
|
+
constructor(message: string, options?: {
|
|
2137
|
+
file?: string;
|
|
2138
|
+
line?: number;
|
|
2139
|
+
pattern?: string;
|
|
2140
|
+
hint?: string;
|
|
2141
|
+
cause?: Error;
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
/**
|
|
2145
|
+
* Thrown when the ultraenv configuration is invalid.
|
|
2146
|
+
*/
|
|
2147
|
+
declare class ConfigError extends UltraenvError {
|
|
2148
|
+
/** The configuration field that is invalid */
|
|
2149
|
+
readonly field: string;
|
|
2150
|
+
constructor(message: string, options?: {
|
|
2151
|
+
field?: string;
|
|
2152
|
+
hint?: string;
|
|
2153
|
+
cause?: Error;
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2156
|
+
/**
|
|
2157
|
+
* Thrown when file system operations fail.
|
|
2158
|
+
*/
|
|
2159
|
+
declare class FileSystemError extends UltraenvError {
|
|
2160
|
+
/** The file or directory path involved */
|
|
2161
|
+
readonly path: string;
|
|
2162
|
+
/** The operation that failed (e.g., 'read', 'write', 'mkdir') */
|
|
2163
|
+
readonly operation: string;
|
|
2164
|
+
/** The underlying system error code (e.g., 'ENOENT', 'EACCES') */
|
|
2165
|
+
readonly code: string;
|
|
2166
|
+
constructor(message: string, options?: {
|
|
2167
|
+
path?: string;
|
|
2168
|
+
operation?: string;
|
|
2169
|
+
code?: string;
|
|
2170
|
+
hint?: string;
|
|
2171
|
+
cause?: Error;
|
|
2172
|
+
});
|
|
2173
|
+
}
|
|
2174
|
+
/**
|
|
2175
|
+
* Check if an error is an ultraenv error (or subclass thereof).
|
|
2176
|
+
*/
|
|
2177
|
+
declare function isUltraenvError(error: unknown): error is UltraenvError;
|
|
2178
|
+
|
|
2179
|
+
/** Unicode box drawing characters set */
|
|
2180
|
+
interface BoxChars {
|
|
2181
|
+
/** Top-left corner */
|
|
2182
|
+
topLeft: string;
|
|
2183
|
+
/** Top-right corner */
|
|
2184
|
+
topRight: string;
|
|
2185
|
+
/** Bottom-left corner */
|
|
2186
|
+
bottomLeft: string;
|
|
2187
|
+
/** Bottom-right corner */
|
|
2188
|
+
bottomRight: string;
|
|
2189
|
+
/** Horizontal line */
|
|
2190
|
+
horizontal: string;
|
|
2191
|
+
/** Vertical line */
|
|
2192
|
+
vertical: string;
|
|
2193
|
+
/** Left tee (vertical meets horizontal) */
|
|
2194
|
+
leftTee: string;
|
|
2195
|
+
/** Right tee (vertical meets horizontal) */
|
|
2196
|
+
rightTee: string;
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
/** Options for the terminal reporter */
|
|
2200
|
+
interface TerminalReporterOptions {
|
|
2201
|
+
/** Whether to use colors (auto-detected if not specified) */
|
|
2202
|
+
color?: boolean;
|
|
2203
|
+
/** Box character style */
|
|
2204
|
+
boxStyle?: BoxChars;
|
|
2205
|
+
/** Maximum width of output lines (0 = no limit) */
|
|
2206
|
+
maxWidth?: number;
|
|
2207
|
+
}
|
|
2208
|
+
/**
|
|
2209
|
+
* Report a validation result with rich formatting.
|
|
2210
|
+
*
|
|
2211
|
+
* - Green box for passing validations
|
|
2212
|
+
* - Red box for errors with field details table
|
|
2213
|
+
* - Yellow warnings section
|
|
2214
|
+
*
|
|
2215
|
+
* @param result - The validation result to report
|
|
2216
|
+
* @param options - Reporter options
|
|
2217
|
+
* @returns Formatted terminal string
|
|
2218
|
+
*/
|
|
2219
|
+
declare function reportValidation$1(result: ValidationResult, options?: TerminalReporterOptions): string;
|
|
2220
|
+
/**
|
|
2221
|
+
* Report an UltraenvError with structured formatting.
|
|
2222
|
+
*
|
|
2223
|
+
* @param error - The error to report
|
|
2224
|
+
* @param options - Reporter options
|
|
2225
|
+
* @returns Formatted terminal string
|
|
2226
|
+
*/
|
|
2227
|
+
declare function reportError$1(error: UltraenvError, options?: TerminalReporterOptions): string;
|
|
2228
|
+
/**
|
|
2229
|
+
* Report a success message with a green checkmark.
|
|
2230
|
+
*
|
|
2231
|
+
* @param message - The success message
|
|
2232
|
+
* @param options - Reporter options
|
|
2233
|
+
* @returns Formatted terminal string
|
|
2234
|
+
*/
|
|
2235
|
+
declare function reportSuccess(message: string, options?: TerminalReporterOptions): string;
|
|
2236
|
+
/**
|
|
2237
|
+
* Report a warning with yellow formatting.
|
|
2238
|
+
*
|
|
2239
|
+
* @param warning - The validation warning to report
|
|
2240
|
+
* @param options - Reporter options
|
|
2241
|
+
* @returns Formatted terminal string
|
|
2242
|
+
*/
|
|
2243
|
+
declare function reportWarning(warning: ValidationWarning, options?: TerminalReporterOptions): string;
|
|
2244
|
+
/**
|
|
2245
|
+
* Report an informational message.
|
|
2246
|
+
*
|
|
2247
|
+
* @param message - The info message
|
|
2248
|
+
* @param options - Reporter options
|
|
2249
|
+
* @returns Formatted terminal string
|
|
2250
|
+
*/
|
|
2251
|
+
declare function reportInfo(message: string, options?: TerminalReporterOptions): string;
|
|
2252
|
+
/**
|
|
2253
|
+
* Report a scan result with severity-colored table.
|
|
2254
|
+
*
|
|
2255
|
+
* @param result - The scan result to report
|
|
2256
|
+
* @param options - Reporter options
|
|
2257
|
+
* @returns Formatted terminal string
|
|
2258
|
+
*/
|
|
2259
|
+
declare function reportScanResult$2(result: ScanResult, options?: TerminalReporterOptions): string;
|
|
2260
|
+
|
|
2261
|
+
/** Options for the JSON reporter */
|
|
2262
|
+
interface JsonReporterOptions {
|
|
2263
|
+
/**
|
|
2264
|
+
* Whether to pretty-print the JSON output.
|
|
2265
|
+
* Default: true (2-space indent)
|
|
2266
|
+
*/
|
|
2267
|
+
pretty?: boolean;
|
|
2268
|
+
/**
|
|
2269
|
+
* Number of spaces for indentation when pretty-printing.
|
|
2270
|
+
* Default: 2
|
|
2271
|
+
*/
|
|
2272
|
+
indent?: number;
|
|
2273
|
+
/**
|
|
2274
|
+
* Whether to include stack traces for errors.
|
|
2275
|
+
* Default: false
|
|
2276
|
+
*/
|
|
2277
|
+
includeStack?: boolean;
|
|
2278
|
+
}
|
|
2279
|
+
/**
|
|
2280
|
+
* Report a validation result as a JSON string.
|
|
2281
|
+
*
|
|
2282
|
+
* @param result - The validation result to report
|
|
2283
|
+
* @param options - Reporter options
|
|
2284
|
+
* @returns JSON string
|
|
2285
|
+
*
|
|
2286
|
+
* @example
|
|
2287
|
+
* ```typescript
|
|
2288
|
+
* import { reportValidation } from 'ultraenv/reporters/json';
|
|
2289
|
+
* const json = reportValidation(result);
|
|
2290
|
+
* // → '{"valid":true,"errorCount":0,"warningCount":0,"...}'
|
|
2291
|
+
* ```
|
|
2292
|
+
*/
|
|
2293
|
+
declare function reportValidation(result: ValidationResult, options?: JsonReporterOptions): string;
|
|
2294
|
+
/**
|
|
2295
|
+
* Report an UltraenvError as a JSON string.
|
|
2296
|
+
*
|
|
2297
|
+
* @param error - The error to report
|
|
2298
|
+
* @param options - Reporter options
|
|
2299
|
+
* @returns JSON string
|
|
2300
|
+
*/
|
|
2301
|
+
declare function reportError(error: UltraenvError, options?: JsonReporterOptions): string;
|
|
2302
|
+
/**
|
|
2303
|
+
* Report a scan result as a JSON string.
|
|
2304
|
+
*
|
|
2305
|
+
* @param result - The scan result to report
|
|
2306
|
+
* @param options - Reporter options
|
|
2307
|
+
* @returns JSON string
|
|
2308
|
+
*
|
|
2309
|
+
* @example
|
|
2310
|
+
* ```typescript
|
|
2311
|
+
* import { reportScanResult } from 'ultraenv/reporters/json';
|
|
2312
|
+
* const json = reportScanResult(scanResult);
|
|
2313
|
+
* ```
|
|
2314
|
+
*/
|
|
2315
|
+
declare function reportScanResult$1(result: ScanResult, options?: JsonReporterOptions): string;
|
|
2316
|
+
|
|
2317
|
+
/** SARIF rule object */
|
|
2318
|
+
interface SarifRule {
|
|
2319
|
+
id: string;
|
|
2320
|
+
name: string;
|
|
2321
|
+
shortDescription: {
|
|
2322
|
+
text: string;
|
|
2323
|
+
};
|
|
2324
|
+
fullDescription: {
|
|
2325
|
+
text: string;
|
|
2326
|
+
};
|
|
2327
|
+
helpUri?: string;
|
|
2328
|
+
properties: {
|
|
2329
|
+
'security-severity': string;
|
|
2330
|
+
tags: string[];
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2333
|
+
/**
|
|
2334
|
+
* Report a scan result as a SARIF JSON string.
|
|
2335
|
+
*
|
|
2336
|
+
* Generates a valid SARIF v2.1.0 document compatible with:
|
|
2337
|
+
* - GitHub Code Scanning
|
|
2338
|
+
* - GitHub CodeQL action
|
|
2339
|
+
* - Azure DevOps
|
|
2340
|
+
* - VS Code SARIF Viewer
|
|
2341
|
+
*
|
|
2342
|
+
* @param result - The scan result to report
|
|
2343
|
+
* @param options - Reporter options
|
|
2344
|
+
* @returns SARIF JSON string
|
|
2345
|
+
*
|
|
2346
|
+
* @example
|
|
2347
|
+
* ```typescript
|
|
2348
|
+
* import { reportScanResult } from 'ultraenv/reporters/sarif';
|
|
2349
|
+
* import { writeFileSync } from 'fs';
|
|
2350
|
+
*
|
|
2351
|
+
* const sarif = reportScanResult(scanResult);
|
|
2352
|
+
* writeFileSync('results.sarif', sarif);
|
|
2353
|
+
* ```
|
|
2354
|
+
*/
|
|
2355
|
+
declare function reportScanResult(result: ScanResult, options?: {
|
|
2356
|
+
/** Tool version to report (default: '1.0.0') */
|
|
2357
|
+
toolVersion?: string;
|
|
2358
|
+
/** Custom rules to add to the SARIF output */
|
|
2359
|
+
additionalRules?: readonly SarifRule[];
|
|
2360
|
+
}): string;
|
|
2361
|
+
|
|
2362
|
+
interface MaskOptions {
|
|
2363
|
+
/** Number of characters visible at the start (default: 3) */
|
|
2364
|
+
visibleStart?: number;
|
|
2365
|
+
/** Number of characters visible at the end (default: 4) */
|
|
2366
|
+
visibleEnd?: number;
|
|
2367
|
+
/** Character used for masking (default: '*') */
|
|
2368
|
+
maskChar?: string;
|
|
2369
|
+
/** Minimum value length before masking is applied (default: 8) */
|
|
2370
|
+
minLength?: number;
|
|
2371
|
+
}
|
|
2372
|
+
/**
|
|
2373
|
+
* Mask a secret value for safe display.
|
|
2374
|
+
*
|
|
2375
|
+
* @example
|
|
2376
|
+
* maskValue('sk-abc12345def67890') → 'sk-***********7890'
|
|
2377
|
+
* maskValue('short') → 'short' (below minLength, not masked)
|
|
2378
|
+
* maskValue('') → ''
|
|
2379
|
+
*/
|
|
2380
|
+
declare function maskValue(value: string, options?: MaskOptions): string;
|
|
2381
|
+
|
|
2382
|
+
/**
|
|
2383
|
+
* Calculate the Shannon entropy of a string in bits per character.
|
|
2384
|
+
*
|
|
2385
|
+
* Shannon entropy measures the uncertainty (randomness) in a message.
|
|
2386
|
+
* Higher values indicate more randomness / less predictability.
|
|
2387
|
+
*
|
|
2388
|
+
* - Uniform lowercase English text: ~4.0–4.5 bits
|
|
2389
|
+
* - Mixed case + digits + symbols: ~5.0–6.0 bits
|
|
2390
|
+
* - Random hex strings: ~4.0 bits (per char)
|
|
2391
|
+
* - High-entropy secrets (base64, API keys): typically > 3.5 bits
|
|
2392
|
+
*
|
|
2393
|
+
* @param str - The input string to analyze.
|
|
2394
|
+
* @returns Entropy in bits per character (0.0 for empty strings).
|
|
2395
|
+
*
|
|
2396
|
+
* @example
|
|
2397
|
+
* shannonEntropy('hello') // ~2.85
|
|
2398
|
+
* shannonEntropy('a1b2c3d4') // ~3.0
|
|
2399
|
+
* shannonEntropy('xJ9#kL2$mP') // ~4.12
|
|
2400
|
+
* shannonEntropy('') // 0
|
|
2401
|
+
*/
|
|
2402
|
+
declare function shannonEntropy(str: string): number;
|
|
2403
|
+
/**
|
|
2404
|
+
* Check if a string has high entropy, suggesting it may be a secret or token.
|
|
2405
|
+
*
|
|
2406
|
+
* Uses Shannon entropy with configurable threshold.
|
|
2407
|
+
* Default threshold of 3.5 is calibrated to catch common secret formats
|
|
2408
|
+
* (API keys, tokens, passwords) while minimizing false positives on
|
|
2409
|
+
* regular text.
|
|
2410
|
+
*
|
|
2411
|
+
* @param str - The string to check.
|
|
2412
|
+
* @param threshold - Minimum entropy to consider "high" (default: 3.5).
|
|
2413
|
+
* @returns true if the string's entropy exceeds the threshold.
|
|
2414
|
+
*
|
|
2415
|
+
* @example
|
|
2416
|
+
* isHighEntropy('my-database-password') // false (~3.1)
|
|
2417
|
+
* isHighEntropy('sk_live_4eC39HqLyjWDarjtT1zdp7dc') // true (~4.2)
|
|
2418
|
+
* isHighEntropy('a]c!D@f#G$h%J^k&L*m') // true (~4.0)
|
|
2419
|
+
*/
|
|
2420
|
+
declare function isHighEntropy(str: string, threshold?: number): boolean;
|
|
2421
|
+
|
|
2422
|
+
/** Current ultraenv version */
|
|
2423
|
+
declare const VERSION = "1.0.0";
|
|
2424
|
+
|
|
2425
|
+
/**
|
|
2426
|
+
* Parse a .env file content string into a structured representation.
|
|
2427
|
+
*
|
|
2428
|
+
* Supported syntax:
|
|
2429
|
+
* - KEY=value
|
|
2430
|
+
* - KEY="value with escapes: \\n \\t \\xHH \\uXXXX"
|
|
2431
|
+
* - KEY='literal value (no escaping)'
|
|
2432
|
+
* - KEY=`backtick value`
|
|
2433
|
+
* - KEY= or KEY="" (empty values)
|
|
2434
|
+
* - KEY (no = sign → empty string)
|
|
2435
|
+
* - # comments
|
|
2436
|
+
* - export KEY=value
|
|
2437
|
+
* - Inline comments: KEY=value # this is a comment
|
|
2438
|
+
* - Multiline values in double quotes
|
|
2439
|
+
* - Whitespace trimming around = and quotes
|
|
2440
|
+
*
|
|
2441
|
+
* @param content - The raw file content string
|
|
2442
|
+
* @param filePath - Optional file path for error messages
|
|
2443
|
+
* @returns ParsedEnvFile with all extracted variables
|
|
2444
|
+
* @throws ParseError on malformed syntax
|
|
2445
|
+
*/
|
|
2446
|
+
declare function parseEnvFile(content: string, filePath?: string): ParsedEnvFile;
|
|
2447
|
+
|
|
2448
|
+
interface ExpandOptions {
|
|
2449
|
+
/** Maximum recursion depth for nested variable references (default: 10) */
|
|
2450
|
+
maxDepth?: number;
|
|
2451
|
+
/** Additional environment variables (e.g., system process.env) to resolve from */
|
|
2452
|
+
systemEnv?: Record<string, string | undefined>;
|
|
2453
|
+
}
|
|
2454
|
+
/**
|
|
2455
|
+
* Expand variable references in all values of the given env object.
|
|
2456
|
+
*
|
|
2457
|
+
* Supported expansions:
|
|
2458
|
+
* - $VAR → simple substitution
|
|
2459
|
+
* - ${VAR} → simple substitution (braced)
|
|
2460
|
+
* - ${VAR:-def} → default if unset or empty
|
|
2461
|
+
* - ${VAR-def} → default if unset
|
|
2462
|
+
* - ${VAR:+alt} → replacement if set and non-empty
|
|
2463
|
+
* - ${VAR+alt} → replacement if set
|
|
2464
|
+
* - ${VAR:?err} → error if unset or empty
|
|
2465
|
+
* - ${VAR?err} → error if unset
|
|
2466
|
+
* - ${VAR^^} → uppercase
|
|
2467
|
+
* - ${VAR,,} → lowercase
|
|
2468
|
+
* - ${VAR:0:5} → substring
|
|
2469
|
+
* - ${#VAR} → string length
|
|
2470
|
+
* - \${VAR} → escaped literal (no expansion)
|
|
2471
|
+
*
|
|
2472
|
+
* @param vars - The env variables to expand (key-value pairs)
|
|
2473
|
+
* @param env - The full env map for resolving references (usually the same as vars)
|
|
2474
|
+
* @param options - Expansion options
|
|
2475
|
+
* @returns A new Record with all variable references expanded
|
|
2476
|
+
* @throws InterpolationError on circular references or maximum depth exceeded
|
|
2477
|
+
*/
|
|
2478
|
+
declare function expandVariables(vars: Record<string, string>, env: Record<string, string>, options?: ExpandOptions): Record<string, string>;
|
|
2479
|
+
|
|
2480
|
+
/**
|
|
2481
|
+
* Read a file and return its contents as a string.
|
|
2482
|
+
* @throws FileSystemError if the file cannot be read.
|
|
2483
|
+
*/
|
|
2484
|
+
declare function readFile(filePath: string, encoding?: BufferEncoding): Promise<string>;
|
|
2485
|
+
/**
|
|
2486
|
+
* Synchronously read a file and return its contents as a string.
|
|
2487
|
+
* Use sparingly — prefer the async version.
|
|
2488
|
+
*/
|
|
2489
|
+
declare function readFileSync(filePath: string, encoding?: BufferEncoding): string;
|
|
2490
|
+
/**
|
|
2491
|
+
* Write content to a file, creating parent directories if needed.
|
|
2492
|
+
* @throws FileSystemError if the write fails.
|
|
2493
|
+
*/
|
|
2494
|
+
declare function writeFile(filePath: string, content: string, encoding?: BufferEncoding): Promise<void>;
|
|
2495
|
+
/**
|
|
2496
|
+
* Check if a path exists on the filesystem.
|
|
2497
|
+
*/
|
|
2498
|
+
declare function exists(filePath: string): Promise<boolean>;
|
|
2499
|
+
/**
|
|
2500
|
+
* Check if the given path points to a regular file.
|
|
2501
|
+
*/
|
|
2502
|
+
declare function isFile(filePath: string): Promise<boolean>;
|
|
2503
|
+
/**
|
|
2504
|
+
* Check if the given path points to a directory.
|
|
2505
|
+
*/
|
|
2506
|
+
declare function isDirectory(dirPath: string): Promise<boolean>;
|
|
2507
|
+
/**
|
|
2508
|
+
* Ensure a directory exists, creating it recursively if necessary (mkdir -p).
|
|
2509
|
+
*/
|
|
2510
|
+
declare function ensureDir(dirPath: string): Promise<void>;
|
|
2511
|
+
/**
|
|
2512
|
+
* Remove a file. Does nothing if the file does not exist.
|
|
2513
|
+
*/
|
|
2514
|
+
declare function removeFile(filePath: string): Promise<void>;
|
|
2515
|
+
/**
|
|
2516
|
+
* Copy a file from src to dest, creating parent directories if needed.
|
|
2517
|
+
*/
|
|
2518
|
+
declare function copyFile(src: string, dest: string): Promise<void>;
|
|
2519
|
+
/**
|
|
2520
|
+
* List files in a directory.
|
|
2521
|
+
* @param dirPath - Directory to scan.
|
|
2522
|
+
* @param recursive - Whether to recurse into subdirectories (default: false).
|
|
2523
|
+
* @returns Array of file paths relative to dirPath.
|
|
2524
|
+
*/
|
|
2525
|
+
declare function listFiles(dirPath: string, recursive?: boolean): Promise<string[]>;
|
|
2526
|
+
/**
|
|
2527
|
+
* Walk up the directory tree looking for a file with the given name.
|
|
2528
|
+
* @param name - File name to search for (e.g., '.env').
|
|
2529
|
+
* @param cwd - Starting directory (default: process.cwd()).
|
|
2530
|
+
* @returns Absolute path to the found file, or null if not found.
|
|
2531
|
+
*/
|
|
2532
|
+
declare function findUp(name: string, cwd?: string): Promise<string | null>;
|
|
2533
|
+
|
|
2534
|
+
/**
|
|
2535
|
+
* ultraenv — The Ultimate Environment Variable Manager
|
|
2536
|
+
*
|
|
2537
|
+
* @example
|
|
2538
|
+
* ```typescript
|
|
2539
|
+
* // Simple loading (dotenv-compatible)
|
|
2540
|
+
* import { load } from 'ultraenv';
|
|
2541
|
+
* load();
|
|
2542
|
+
*
|
|
2543
|
+
* // Schema-based validation with full type inference
|
|
2544
|
+
* import { defineEnv, t } from 'ultraenv';
|
|
2545
|
+
* const env = defineEnv({
|
|
2546
|
+
* PORT: t.number().port().default(3000),
|
|
2547
|
+
* DATABASE_URL: t.string().url().required(),
|
|
2548
|
+
* NODE_ENV: t.enum(['development', 'staging', 'production'] as const).required(),
|
|
2549
|
+
* DEBUG: t.boolean().default(false),
|
|
2550
|
+
* });
|
|
2551
|
+
* // env.PORT → number (not string!)
|
|
2552
|
+
* // env.NODE_ENV → 'development' | 'staging' | 'production'
|
|
2553
|
+
* ```
|
|
2554
|
+
*
|
|
2555
|
+
* @module ultraenv
|
|
2556
|
+
*/
|
|
2557
|
+
|
|
2558
|
+
declare const _default: {
|
|
2559
|
+
version: string;
|
|
2560
|
+
};
|
|
2561
|
+
|
|
2562
|
+
export { ConfigError, type DetectedSecret, EncryptionError, type EncryptionResult, FileSystemError, InterpolationError, type LoadMetadata, type LoadOptions, type LoadResult, ParseError, type ParsedEnvFile, type ParsedEnvVar, type Preset, ScanError, type ScanOptions, type ScanResult, type SecretPattern, SecureBuffer, SecureString, type SyncDiff$1 as SyncDiff, type SyncResult, type TypegenOptions, type UltraenvConfig, UltraenvError, ValidationError as UltraenvValidationError, VERSION, VaultError, type WatchOptions, type Watcher, type WatcherEvent, addCustomPattern, compareEnvironments, compareSync, compareValues, computeIntegrity, computeVaultChecksum, copyFile, createEnvironment, createSecureString, createSecureStringFromBuffer, createSyncWatcher, createTypegenWatcher, createWatcher, decryptEnvironment, decryptValue, _default as default, deriveEnvironmentKey, detectHighEntropyStrings, discoverEnvironments, duplicateEnvironment, encryptEnvironment, encryptValue, ensureDir, exists, expandVariables, findConfig, findUp, formatComparison, formatKey, formatScanResult, generateDeclaration, generateExampleContent, generateExampleFile, generateJsonSchema, generateKeysFile, generateMasterKey, generateModule, getActiveEnvironment, getAllPresets, getEnvironmentData, getPreset, getVaultEnvironments, hasPreset, healthCheck, isDirectory, isEncryptedValue, isFile, isHighEntropy, isUltraenvError, isValidKeyFormat, listEnvironments, listFiles, listPresets, liveCheck, load, loadConfig, loadSync, loadWithResult, loadWithResultSync, maskKey, maskValue as maskSecretValue, matchPatterns, mergeCascade, needsUpdate, parseEnvFile, parseKey, parseKeysFile, parseVaultFile, readFile, readFileSync, readVaultFile, readinessCheck, registerPreset, removeCustomPattern, removeEnvironment, removeFile, reportError$1 as reportError, reportError as reportErrorJson, reportInfo, reportScanResult$1 as reportScanResultJson, reportScanResult as reportScanResultSarif, reportScanResult$2 as reportScanResultTerminal, reportSuccess, reportValidation$1 as reportValidation, reportValidation as reportValidationJson, reportWarning, resetPatterns, resolveCascade, rotateKey, scan, scanDiff, scanFiles, scanGitHistory, scanLineForEntropy, scanStagedFiles, secureCompare, serializeVaultFile, shannonEntropy, switchEnvironment, unregisterPreset, validateAllEnvironments, verifyIntegrity, verifyVaultChecksum, wipeString, writeFile, writeVaultFile };
|