dotenv-gad 1.4.2 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -11
- package/dist/cli/commands/check.js +10 -2
- package/dist/cli/commands/decrypt.js +126 -0
- package/dist/cli/commands/docs.js +2 -2
- package/dist/cli/commands/encrypt.js +100 -0
- package/dist/cli/commands/fix.js +16 -12
- package/dist/cli/commands/init.js +17 -12
- package/dist/cli/commands/keygen.js +97 -0
- package/dist/cli/commands/rotate.js +160 -0
- package/dist/cli/commands/status.js +116 -0
- package/dist/cli/commands/sync.js +15 -17
- package/dist/cli/commands/utils.js +40 -28
- package/dist/cli/commands/verify.js +101 -0
- package/dist/cli/index.js +12 -0
- package/dist/crypto.js +165 -0
- package/dist/errors.js +92 -4
- package/dist/index.cjs +408 -26
- package/dist/index.js +6 -4
- package/dist/runtime.js +43 -0
- package/dist/schema-loader.js +12 -3
- package/dist/types/cli/commands/check.d.ts +1 -1
- package/dist/types/cli/commands/decrypt.d.ts +2 -0
- package/dist/types/cli/commands/docs.d.ts +1 -1
- package/dist/types/cli/commands/encrypt.d.ts +2 -0
- package/dist/types/cli/commands/fix.d.ts +1 -1
- package/dist/types/cli/commands/init.d.ts +1 -1
- package/dist/types/cli/commands/keygen.d.ts +2 -0
- package/dist/types/cli/commands/rotate.d.ts +2 -0
- package/dist/types/cli/commands/status.d.ts +2 -0
- package/dist/types/cli/commands/sync.d.ts +1 -1
- package/dist/types/cli/commands/verify.d.ts +2 -0
- package/dist/types/crypto.d.ts +58 -0
- package/dist/types/errors.d.ts +35 -12
- package/dist/types/index.d.ts +8 -3
- package/dist/types/runtime.d.ts +29 -0
- package/dist/types/schema-loader.d.ts +5 -2
- package/dist/types/schema.d.ts +7 -0
- package/dist/types/utils.d.ts +21 -10
- package/dist/types/validator.d.ts +40 -0
- package/dist/utils.js +50 -13
- package/dist/validator.js +164 -19
- package/package.json +6 -4
package/dist/schema-loader.js
CHANGED
|
@@ -4,14 +4,17 @@
|
|
|
4
4
|
* Deliberately free of CLI-only dependencies (chalk, inquirer) so it can be
|
|
5
5
|
* imported by the Vite plugin without pulling in heavy Node packages.
|
|
6
6
|
*
|
|
7
|
-
* esbuild is required only when loading `.ts` schemas and is imported
|
|
7
|
+
* esbuild is required only when loading `.ts` schemas in Node.js and is imported
|
|
8
8
|
* lazily via `await import("esbuild")` so the module itself has no
|
|
9
9
|
* top-level dependency on it.
|
|
10
|
+
*
|
|
11
|
+
* In Bun, TypeScript files are loaded directly without transpilation.
|
|
10
12
|
*/
|
|
11
13
|
import { readFileSync, writeFileSync, unlinkSync, existsSync } from "fs";
|
|
12
14
|
import { dirname, join, resolve } from "path";
|
|
13
15
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
14
16
|
import { randomBytes } from "crypto";
|
|
17
|
+
import { isBun } from "./runtime.js";
|
|
15
18
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
19
|
async function importModule(filePath) {
|
|
17
20
|
const fileUrl = pathToFileURL(filePath).href;
|
|
@@ -23,6 +26,11 @@ async function importModule(filePath) {
|
|
|
23
26
|
return schema;
|
|
24
27
|
}
|
|
25
28
|
async function loadTsModule(tsFilePath) {
|
|
29
|
+
// Bun can import TypeScript files directly without transpilation
|
|
30
|
+
if (isBun()) {
|
|
31
|
+
return await importModule(tsFilePath);
|
|
32
|
+
}
|
|
33
|
+
// Node.js requires transpilation via esbuild
|
|
26
34
|
const tempFile = join(__dirname, `../temp-schema-${randomBytes(8).toString("hex")}.mjs`);
|
|
27
35
|
try {
|
|
28
36
|
const { transformSync } = await import("esbuild");
|
|
@@ -32,7 +40,7 @@ async function loadTsModule(tsFilePath) {
|
|
|
32
40
|
loader: "ts",
|
|
33
41
|
target: "esnext",
|
|
34
42
|
});
|
|
35
|
-
writeFileSync(tempFile, code);
|
|
43
|
+
writeFileSync(tempFile, code, { mode: 0o600 });
|
|
36
44
|
return await importModule(tempFile);
|
|
37
45
|
}
|
|
38
46
|
finally {
|
|
@@ -45,7 +53,8 @@ async function loadTsModule(tsFilePath) {
|
|
|
45
53
|
* Loads a schema from a file.
|
|
46
54
|
*
|
|
47
55
|
* Supports `.ts`, `.js`, `.mjs`, `.cjs`, and `.json` formats.
|
|
48
|
-
* TypeScript files are transpiled on-the-fly
|
|
56
|
+
* TypeScript files are loaded natively in Bun, or transpiled on-the-fly
|
|
57
|
+
* via esbuild in Node.js (loaded lazily).
|
|
49
58
|
*/
|
|
50
59
|
export async function loadSchema(schemaPath) {
|
|
51
60
|
const absPath = resolve(schemaPath);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
export default function (
|
|
2
|
+
export default function (_program: Command): Command;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
export default function (
|
|
2
|
+
export default function (_program: Command): Command;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
export default function (
|
|
2
|
+
export default function (_program: Command): Command;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
export default function (
|
|
2
|
+
export default function (_program: Command): Command;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
export default function (
|
|
2
|
+
export default function (_program: Command): Command;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface KeyPair {
|
|
2
|
+
/** Hex-encoded 44-byte SPKI DER. Store as ENVGAD_PUBLIC_KEY in .env (safe to commit). */
|
|
3
|
+
publicKeyHex: string;
|
|
4
|
+
/** Hex-encoded 48-byte PKCS8 DER. Store as ENVGAD_PRIVATE_KEY in .env.keys (never commit). */
|
|
5
|
+
privateKeyHex: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Generates a new key pair using the X25519 curve.
|
|
9
|
+
*
|
|
10
|
+
* @returns An object containing the hex-encoded public and private keys.
|
|
11
|
+
* The public key is safe to commit to version control (e.g. .env), while the private key
|
|
12
|
+
* should be kept secret and stored securely (e.g. .env.keys).
|
|
13
|
+
*/
|
|
14
|
+
export declare function generateKeyPair(): KeyPair;
|
|
15
|
+
/**
|
|
16
|
+
* Encrypts a plaintext string using ChaCha20-Poly1305 authenticated encryption.
|
|
17
|
+
* The encryption key is derived from the shared secret of the ephemeral key pair
|
|
18
|
+
* and the recipient's public key using HKDF-SHA256.
|
|
19
|
+
*
|
|
20
|
+
* @param plaintext - The plaintext string to encrypt.
|
|
21
|
+
* @param recipientPublicKeyHex - Hex-encoded 44-byte SPKI DER of the recipient's public key.
|
|
22
|
+
* @param varName - The name of the environment variable being encrypted.
|
|
23
|
+
* @returns A wire-format string containing the encrypted ciphertext and
|
|
24
|
+
* ephemeral public key information: `encrypted:v1:<base64>`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function encryptEnvValue(plaintext: string, recipientPublicKeyHex: string, varName: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Decrypt a wire-format ciphertext produced by {@link encryptEnvValue}.
|
|
29
|
+
*
|
|
30
|
+
* @param token - Wire-format string: `encrypted:v1:<base64>`.
|
|
31
|
+
* @param privateKeyHex - Hex-encoded PKCS8 DER of the recipient's private key (from ENVGAD_PRIVATE_KEY).
|
|
32
|
+
* @param varName - Schema variable name, must match the one used during encryption (AAD check).
|
|
33
|
+
* @returns Decrypted plaintext string.
|
|
34
|
+
* @throws {@link DecryptionFailedError} if the key is wrong, ciphertext is tampered, or AAD mismatches.
|
|
35
|
+
*/
|
|
36
|
+
export declare function decryptEnvValue(token: string, privateKeyHex: string, varName: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Returns true if the given value starts with the encrypted value
|
|
39
|
+
* prefix, and false otherwise.
|
|
40
|
+
*
|
|
41
|
+
* The encrypted value prefix is in the format of
|
|
42
|
+
* `encrypted:v1:<base64-encoded-payload>`.
|
|
43
|
+
*
|
|
44
|
+
* @param {string} value the value to check
|
|
45
|
+
* @returns {boolean} true if the value is an encrypted value, false otherwise
|
|
46
|
+
*/
|
|
47
|
+
export declare function isEncryptedValue(value: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Loads the ENVGAD_PRIVATE_KEY value from the given path (default: `.env.keys`)
|
|
50
|
+
* or the ENVGAD_PRIVATE_KEY environment variable if present.
|
|
51
|
+
* Returns the hex-encoded DER value of the private key if found, or null otherwise.
|
|
52
|
+
* @param {Object} [options] Optional options.
|
|
53
|
+
* @param {string} [options.keysPath] Path to the `.env.keys` file (default: `.env.keys`).
|
|
54
|
+
* @returns {string | null} Hex-encoded DER value of the private key if found, or null otherwise.
|
|
55
|
+
*/
|
|
56
|
+
export declare function loadPrivateKey(options?: {
|
|
57
|
+
keysPath?: string;
|
|
58
|
+
}): string | null;
|
package/dist/types/errors.d.ts
CHANGED
|
@@ -4,21 +4,44 @@ export declare class EnvValidationError extends Error {
|
|
|
4
4
|
message: string;
|
|
5
5
|
receiveValue?: unknown | undefined;
|
|
6
6
|
constructor(key: string, message: string, receiveValue?: unknown | undefined);
|
|
7
|
+
static [Symbol.hasInstance](instance: unknown): boolean;
|
|
7
8
|
}
|
|
9
|
+
type ErrorItem = {
|
|
10
|
+
key: string;
|
|
11
|
+
message: string;
|
|
12
|
+
value?: any;
|
|
13
|
+
rule?: SchemaRule;
|
|
14
|
+
};
|
|
8
15
|
export declare class EnvAggregateError extends Error {
|
|
9
|
-
errors:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
value?: any;
|
|
13
|
-
rule?: SchemaRule;
|
|
14
|
-
}[];
|
|
15
|
-
constructor(errors: {
|
|
16
|
-
key: string;
|
|
17
|
-
message: string;
|
|
18
|
-
value?: any;
|
|
19
|
-
rule?: SchemaRule;
|
|
20
|
-
}[], message: string);
|
|
16
|
+
get errors(): ErrorItem[];
|
|
17
|
+
constructor(errors: ErrorItem[], message: string);
|
|
18
|
+
static [Symbol.hasInstance](instance: unknown): boolean;
|
|
21
19
|
toString(): string;
|
|
22
20
|
}
|
|
23
21
|
/** @deprecated Use `EnvAggregateError` instead — avoids shadowing the built-in `AggregateError`. */
|
|
24
22
|
export declare const AggregateError: typeof EnvAggregateError;
|
|
23
|
+
/**
|
|
24
|
+
* Thrown when a required encryption or decryption key is not available.
|
|
25
|
+
* For encryption: ENVGAD_PUBLIC_KEY missing from .env.
|
|
26
|
+
* For decryption: ENVGAD_PRIVATE_KEY missing from .env.keys and environment.
|
|
27
|
+
*/
|
|
28
|
+
export declare class EncryptionKeyMissingError extends Error {
|
|
29
|
+
constructor(context: "encryption" | "decryption");
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Thrown when ChaCha20-Poly1305 authenticated decryption fails.
|
|
33
|
+
* Common causes: wrong private key, corrupted ciphertext, or AAD mismatch
|
|
34
|
+
* (ciphertext copied from a different variable).
|
|
35
|
+
*/
|
|
36
|
+
export declare class DecryptionFailedError extends Error {
|
|
37
|
+
constructor(varName: string);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Thrown when an encrypted/plaintext value is found but the schema says otherwise.
|
|
41
|
+
* When `shouldBeEncrypted = true`: schema has `encrypted: true` but value is plaintext.
|
|
42
|
+
* When `shouldBeEncrypted = false`: value starts with `encrypted:v1:` but schema lacks `encrypted: true`.
|
|
43
|
+
*/
|
|
44
|
+
export declare class EncryptedFieldMismatchError extends Error {
|
|
45
|
+
constructor(varName: string, shouldBeEncrypted: boolean);
|
|
46
|
+
}
|
|
47
|
+
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { EnvValidator } from "./validator.js";
|
|
2
2
|
import { defineSchema, SchemaDefinition, SchemaRule } from "./schema.js";
|
|
3
|
-
import { EnvAggregateError, AggregateError, EnvValidationError } from "./errors.js";
|
|
3
|
+
import { EnvAggregateError, AggregateError, EnvValidationError, EncryptionKeyMissingError, DecryptionFailedError, EncryptedFieldMismatchError } from "./errors.js";
|
|
4
4
|
import { loadEnv, createEnvProxy } from "./utils.js";
|
|
5
5
|
import { composeSchema } from "./compose.js";
|
|
6
6
|
import { ExtractEnv, InferEnv } from "./types.js";
|
|
7
|
+
import { generateKeyPair, encryptEnvValue, decryptEnvValue, isEncryptedValue, loadPrivateKey } from "./crypto.js";
|
|
8
|
+
import type { KeyPair } from "./crypto.js";
|
|
9
|
+
import { isBun, getEnv, getRuntimeName, getRuntimeVersion } from "./runtime.js";
|
|
7
10
|
export { defineSchema, EnvAggregateError,
|
|
8
11
|
/** @deprecated Use `EnvAggregateError` instead. */
|
|
9
|
-
AggregateError, EnvValidationError, EnvValidator, loadEnv, createEnvProxy, composeSchema, };
|
|
10
|
-
export type { SchemaDefinition, SchemaRule, ExtractEnv, InferEnv };
|
|
12
|
+
AggregateError, EnvValidationError, EncryptionKeyMissingError, DecryptionFailedError, EncryptedFieldMismatchError, EnvValidator, loadEnv, createEnvProxy, composeSchema, generateKeyPair, encryptEnvValue, decryptEnvValue, isEncryptedValue, loadPrivateKey, isBun, getEnv, getRuntimeName, getRuntimeVersion, };
|
|
13
|
+
export type { SchemaDefinition, SchemaRule, ExtractEnv, InferEnv, KeyPair };
|
|
11
14
|
export declare function validateEnv(schema: SchemaDefinition, options?: {
|
|
12
15
|
strict?: boolean;
|
|
13
16
|
path?: string;
|
|
17
|
+
allowPlaintext?: boolean;
|
|
18
|
+
keysPath?: string;
|
|
14
19
|
}): Record<string, any>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime detection and compatibility utilities for Node.js and Bun.
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities to detect the current runtime environment
|
|
5
|
+
* and offers optimized implementations based on the runtime.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Checks if the current runtime is Bun.
|
|
9
|
+
* @returns true if running in Bun, false otherwise
|
|
10
|
+
*/
|
|
11
|
+
export declare function isBun(): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Gets the appropriate environment object for the current runtime.
|
|
14
|
+
* In Bun, this returns Bun.env, in Node.js it returns process.env.
|
|
15
|
+
* Both are compatible, but Bun.env may have better performance in Bun.
|
|
16
|
+
*
|
|
17
|
+
* @returns The environment variables object
|
|
18
|
+
*/
|
|
19
|
+
export declare function getEnv(): Record<string, string | undefined>;
|
|
20
|
+
/**
|
|
21
|
+
* Gets the current runtime name for logging/debugging purposes.
|
|
22
|
+
* @returns "Bun" or "Node.js"
|
|
23
|
+
*/
|
|
24
|
+
export declare function getRuntimeName(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Gets the runtime version string.
|
|
27
|
+
* @returns The version of the current runtime
|
|
28
|
+
*/
|
|
29
|
+
export declare function getRuntimeVersion(): string;
|
|
@@ -4,15 +4,18 @@
|
|
|
4
4
|
* Deliberately free of CLI-only dependencies (chalk, inquirer) so it can be
|
|
5
5
|
* imported by the Vite plugin without pulling in heavy Node packages.
|
|
6
6
|
*
|
|
7
|
-
* esbuild is required only when loading `.ts` schemas and is imported
|
|
7
|
+
* esbuild is required only when loading `.ts` schemas in Node.js and is imported
|
|
8
8
|
* lazily via `await import("esbuild")` so the module itself has no
|
|
9
9
|
* top-level dependency on it.
|
|
10
|
+
*
|
|
11
|
+
* In Bun, TypeScript files are loaded directly without transpilation.
|
|
10
12
|
*/
|
|
11
13
|
import type { SchemaDefinition } from "./schema.js";
|
|
12
14
|
/**
|
|
13
15
|
* Loads a schema from a file.
|
|
14
16
|
*
|
|
15
17
|
* Supports `.ts`, `.js`, `.mjs`, `.cjs`, and `.json` formats.
|
|
16
|
-
* TypeScript files are transpiled on-the-fly
|
|
18
|
+
* TypeScript files are loaded natively in Bun, or transpiled on-the-fly
|
|
19
|
+
* via esbuild in Node.js (loaded lazily).
|
|
17
20
|
*/
|
|
18
21
|
export declare function loadSchema(schemaPath: string): Promise<SchemaDefinition>;
|
package/dist/types/schema.d.ts
CHANGED
|
@@ -12,6 +12,13 @@ export interface SchemaRule {
|
|
|
12
12
|
validate?: (value: any) => boolean;
|
|
13
13
|
transform?: (value: any) => any;
|
|
14
14
|
sensitive?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* When true, the value must be stored encrypted in the .env file using the
|
|
17
|
+
* dotenv-gad ECIES scheme. The validator will automatically decrypt the value
|
|
18
|
+
* before type-checking and returning it to the application.
|
|
19
|
+
* Use `npx dotenv-gad keygen` and `npx dotenv-gad encrypt` to manage keys.
|
|
20
|
+
*/
|
|
21
|
+
encrypted?: boolean;
|
|
15
22
|
docs?: string;
|
|
16
23
|
enum?: any[];
|
|
17
24
|
regex?: RegExp;
|
package/dist/types/utils.d.ts
CHANGED
|
@@ -1,23 +1,34 @@
|
|
|
1
1
|
import { SchemaDefinition } from "./schema.js";
|
|
2
2
|
import type { InferEnv } from "./types.js";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
4
|
+
* Silently reads and parses a .env file without injecting into process.env.
|
|
5
|
+
* Returns an empty object when the file does not exist (e.g. Vercel, Railway,
|
|
6
|
+
* Docker — where env vars are already present in process.env).
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @
|
|
8
|
+
* In Bun, this uses Bun's optimized file reading when available.
|
|
9
|
+
*/
|
|
10
|
+
export declare function readEnvFile(path?: string): Record<string, string>;
|
|
11
|
+
/**
|
|
12
|
+
* Loads environment variables from a `.env` file (if present) and validates them
|
|
13
|
+
* against the provided schema.
|
|
14
|
+
*
|
|
15
|
+
* @param schema The schema definition for the environment variables.
|
|
16
|
+
* @param options Optional options for the validation process.
|
|
17
|
+
* @param options.strict When true, environment variables not present in the schema will be rejected.
|
|
18
|
+
* @param options.includeRaw When true, include raw values in error reports (non-sensitive by default).
|
|
19
|
+
* @param options.includeSensitive When true, include values marked sensitive in error reports (use only for local debugging).
|
|
20
|
+
* @param options.path Path to the `.env` file (defaults to `.env` in cwd).
|
|
21
|
+
* @param options.allowPlaintext When true, fields with `encrypted: true` that have plaintext values emit a warning instead of an error.
|
|
22
|
+
* @param options.keysPath Path to the `.env.keys` file containing ENVGAD_PRIVATE_KEY (default: `.env.keys`).
|
|
23
|
+
* @returns The validated environment variables, typed according to the schema.
|
|
15
24
|
*/
|
|
16
25
|
export declare function loadEnv<S extends SchemaDefinition>(schema: S, options?: {
|
|
17
26
|
strict?: boolean;
|
|
18
27
|
includeRaw?: boolean;
|
|
19
28
|
includeSensitive?: boolean;
|
|
20
29
|
path?: string;
|
|
30
|
+
allowPlaintext?: boolean;
|
|
31
|
+
keysPath?: string;
|
|
21
32
|
}): InferEnv<S>;
|
|
22
33
|
/**
|
|
23
34
|
* Create a proxy around the validated environment variables. The proxy will
|
|
@@ -2,21 +2,61 @@ import { SchemaDefinition } from "./schema.js";
|
|
|
2
2
|
export declare class EnvValidator {
|
|
3
3
|
private schema;
|
|
4
4
|
private options?;
|
|
5
|
+
private static readonly EMAIL_REGEX;
|
|
6
|
+
private static readonly LOCAL_MAX;
|
|
7
|
+
private static readonly DOMAIN_MAX;
|
|
8
|
+
private static readonly DOMAIN_PART_MAX;
|
|
5
9
|
private errors;
|
|
6
10
|
/**
|
|
7
11
|
* Constructs a new EnvValidator instance.
|
|
8
12
|
* @param {SchemaDefinition} schema The schema definition for the environment variables.
|
|
9
13
|
* @param {Object} [options] Optional options for the validation process.
|
|
10
14
|
* @param {boolean} [options.strict] When true, environment variables not present in the schema will be rejected.
|
|
15
|
+
* @param {boolean} [options.allowPlaintext] When true, fields with `encrypted: true` that have plaintext values emit a warning instead of an error. Useful for gradual migration.
|
|
16
|
+
* @param {string} [options.keysPath] Path to the `.env.keys` file (default: `.env.keys`).
|
|
11
17
|
*/
|
|
12
18
|
constructor(schema: SchemaDefinition, options?: {
|
|
13
19
|
strict?: boolean;
|
|
14
20
|
includeRaw?: boolean;
|
|
15
21
|
includeSensitive?: boolean;
|
|
22
|
+
allowPlaintext?: boolean;
|
|
23
|
+
keysPath?: string;
|
|
16
24
|
} | undefined);
|
|
25
|
+
/** Bundler-safe instanceof — checks the symbol marker, not the class name. */
|
|
26
|
+
static [Symbol.hasInstance](instance: unknown): boolean;
|
|
17
27
|
validate(env: Record<string, string | undefined>): Record<string, any>;
|
|
28
|
+
/**
|
|
29
|
+
* Redacts a value to hide its contents, following these rules:
|
|
30
|
+
* - If `value` is undefined, returns undefined.
|
|
31
|
+
* - If `sensitive` is true, returns `"****"`.
|
|
32
|
+
* - If `value` is not a string, returns the original value.
|
|
33
|
+
* - If `value` is a string longer than 64 characters, truncates it to 4 characters
|
|
34
|
+
* at the start and end, and replaces the middle with `"..."`.
|
|
35
|
+
* - Otherwise, returns the original string.
|
|
36
|
+
* @param value The value to redact.
|
|
37
|
+
* @param sensitive If true, redacts the value to `"****"`.
|
|
38
|
+
*/
|
|
18
39
|
private redactValue;
|
|
40
|
+
/**
|
|
41
|
+
* Tries to parse the given value as a JSON object.
|
|
42
|
+
* Returns `{ ok: true, value: JSON.parse(s) }` if successful,
|
|
43
|
+
* or `{ ok: false }` if not.
|
|
44
|
+
* The following conditions will cause the function to return `{ ok: false }`:
|
|
45
|
+
* - `value` is not a string
|
|
46
|
+
* - `value` is an empty string
|
|
47
|
+
* - `value` does not start with one of the following characters: `{`, `[`, `"`, `t`, `f`, `n`, or a digit
|
|
48
|
+
* - `value` cannot be parsed as a JSON object
|
|
49
|
+
*/
|
|
19
50
|
private tryParseJSON;
|
|
20
51
|
private validateKey;
|
|
21
52
|
private getEffectiveRule;
|
|
53
|
+
/**
|
|
54
|
+
* Preprocesses environment variables to detect and handle encrypted values.
|
|
55
|
+
* 1. Decrypts any encrypted values using the private key.
|
|
56
|
+
* 2. Checks if any plaintext values are present for fields that should be encrypted.
|
|
57
|
+
* 3. Flags any env value that looks encrypted but the schema doesn't declare encrypted: true.
|
|
58
|
+
* @returns An object containing the processed environment variables and a set of keys that were skipped due to errors.
|
|
59
|
+
*/
|
|
60
|
+
private preprocessEncryption;
|
|
61
|
+
private validateEmail;
|
|
22
62
|
}
|
package/dist/utils.js
CHANGED
|
@@ -1,21 +1,58 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { parse as parseEnv } from "dotenv";
|
|
2
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
2
3
|
import { EnvValidator } from "./validator.js";
|
|
4
|
+
import { isBun, getEnv } from "./runtime.js";
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
6
|
+
* Silently reads and parses a .env file without injecting into process.env.
|
|
7
|
+
* Returns an empty object when the file does not exist (e.g. Vercel, Railway,
|
|
8
|
+
* Docker — where env vars are already present in process.env).
|
|
6
9
|
*
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
* In Bun, this uses Bun's optimized file reading when available.
|
|
11
|
+
*/
|
|
12
|
+
export function readEnvFile(path) {
|
|
13
|
+
const filePath = path ?? ".env";
|
|
14
|
+
if (!existsSync(filePath))
|
|
15
|
+
return {};
|
|
16
|
+
try {
|
|
17
|
+
// Use Bun's file reading when available for better performance
|
|
18
|
+
let content;
|
|
19
|
+
if (isBun() && typeof globalThis.Bun?.file === 'function') {
|
|
20
|
+
// Bun's synchronous text reading
|
|
21
|
+
const file = globalThis.Bun.file(filePath);
|
|
22
|
+
content = file.text ? (typeof file.text === 'function' ? file.text() : file.text) : readFileSync(filePath, "utf-8");
|
|
23
|
+
// Note: Bun.file().text() is async, so fallback to readFileSync for sync operation
|
|
24
|
+
content = readFileSync(filePath, "utf-8");
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
content = readFileSync(filePath, "utf-8");
|
|
28
|
+
}
|
|
29
|
+
return parseEnv(content);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
33
|
+
console.warn(`[dotenv-gad] Failed to parse ${filePath}: ${message}`);
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Loads environment variables from a `.env` file (if present) and validates them
|
|
39
|
+
* against the provided schema.
|
|
40
|
+
*
|
|
41
|
+
* @param schema The schema definition for the environment variables.
|
|
42
|
+
* @param options Optional options for the validation process.
|
|
43
|
+
* @param options.strict When true, environment variables not present in the schema will be rejected.
|
|
44
|
+
* @param options.includeRaw When true, include raw values in error reports (non-sensitive by default).
|
|
45
|
+
* @param options.includeSensitive When true, include values marked sensitive in error reports (use only for local debugging).
|
|
46
|
+
* @param options.path Path to the `.env` file (defaults to `.env` in cwd).
|
|
47
|
+
* @param options.allowPlaintext When true, fields with `encrypted: true` that have plaintext values emit a warning instead of an error.
|
|
48
|
+
* @param options.keysPath Path to the `.env.keys` file containing ENVGAD_PRIVATE_KEY (default: `.env.keys`).
|
|
49
|
+
* @returns The validated environment variables, typed according to the schema.
|
|
15
50
|
*/
|
|
16
51
|
export function loadEnv(schema, options) {
|
|
17
|
-
const fileEnv =
|
|
18
|
-
|
|
52
|
+
const fileEnv = readEnvFile(options?.path);
|
|
53
|
+
// Use runtime-aware environment getter (process.env or Bun.env)
|
|
54
|
+
const runtimeEnv = getEnv();
|
|
55
|
+
const env = { ...runtimeEnv, ...fileEnv };
|
|
19
56
|
const validator = new EnvValidator(schema, options);
|
|
20
57
|
return validator.validate(env);
|
|
21
58
|
}
|