@dotenvage/node 0.1.5

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.
@@ -0,0 +1,129 @@
1
+ /**
2
+ * TypeScript example: Type-safe application configuration
3
+ *
4
+ * This shows how to use dotenvage with TypeScript for type-safe
5
+ * configuration management.
6
+ */
7
+
8
+ import * as dotenvage from "../index.js";
9
+
10
+ // Define your application configuration schema
11
+ interface AppConfig {
12
+ readonly apiKey: string;
13
+ readonly databaseUrl: string;
14
+ readonly port: number;
15
+ readonly nodeEnv: "development" | "production" | "test";
16
+ readonly logLevel: "debug" | "info" | "warn" | "error";
17
+ }
18
+
19
+ // Type-safe config loader
20
+ class ConfigLoader {
21
+ private loader: dotenvage.JsEnvLoader;
22
+
23
+ constructor() {
24
+ this.loader = dotenvage.JsEnvLoaderNew();
25
+ this.loader.load(); // Load into process.env
26
+ }
27
+
28
+ /**
29
+ * Load and validate configuration
30
+ */
31
+ loadConfig(): AppConfig {
32
+ const raw = this.loader.getAllVariables();
33
+
34
+ // Validate and transform
35
+ const apiKey = this.getRequired("API_KEY", raw);
36
+ const databaseUrl = this.getRequired("DATABASE_URL", raw);
37
+ const port = this.getNumber("PORT", raw, 8080);
38
+ const nodeEnv = this.getEnum(
39
+ "NODE_ENV",
40
+ raw,
41
+ ["development", "production", "test"],
42
+ "development"
43
+ ) as AppConfig["nodeEnv"];
44
+ const logLevel = this.getEnum(
45
+ "LOG_LEVEL",
46
+ raw,
47
+ ["debug", "info", "warn", "error"],
48
+ "info"
49
+ ) as AppConfig["logLevel"];
50
+
51
+ return {
52
+ apiKey,
53
+ databaseUrl,
54
+ port,
55
+ nodeEnv,
56
+ logLevel,
57
+ };
58
+ }
59
+
60
+ private getRequired(key: string, env: Record<string, string>): string {
61
+ const value = env[key] || process.env[key];
62
+ if (!value) {
63
+ throw new Error(`Missing required environment variable: ${key}`);
64
+ }
65
+ return value;
66
+ }
67
+
68
+ private getNumber(
69
+ key: string,
70
+ env: Record<string, string>,
71
+ defaultValue: number
72
+ ): number {
73
+ const value = env[key] || process.env[key];
74
+ if (!value) {
75
+ return defaultValue;
76
+ }
77
+ const parsed = parseInt(value, 10);
78
+ if (isNaN(parsed)) {
79
+ console.warn(`Invalid number for ${key}, using default: ${defaultValue}`);
80
+ return defaultValue;
81
+ }
82
+ return parsed;
83
+ }
84
+
85
+ private getEnum<T extends string>(
86
+ key: string,
87
+ env: Record<string, string>,
88
+ validValues: readonly T[],
89
+ defaultValue: T
90
+ ): T {
91
+ const value = (env[key] || process.env[key] || defaultValue).toLowerCase();
92
+ if (validValues.includes(value as T)) {
93
+ return value as T;
94
+ }
95
+ console.warn(
96
+ `Invalid value for ${key}: ${value}, using default: ${defaultValue}`
97
+ );
98
+ return defaultValue;
99
+ }
100
+ }
101
+
102
+ // Usage in your application
103
+ function main() {
104
+ try {
105
+ const loader = new ConfigLoader();
106
+ const config: AppConfig = loader.loadConfig();
107
+
108
+ console.log("Application Configuration:");
109
+ console.log(` API Key: ${config.apiKey.substring(0, 10)}...`);
110
+ console.log(` Database: ${config.databaseUrl}`);
111
+ console.log(` Port: ${config.port}`);
112
+ console.log(` Environment: ${config.nodeEnv}`);
113
+ console.log(` Log Level: ${config.logLevel}`);
114
+ } catch (error) {
115
+ if (error instanceof Error) {
116
+ console.error(`Configuration error: ${error.message}`);
117
+ } else {
118
+ console.error("Unknown configuration error");
119
+ }
120
+ process.exit(1);
121
+ }
122
+ }
123
+
124
+ // Run if this is the main module
125
+ if (import.meta.url === `file://${process.argv[1]}`) {
126
+ main();
127
+ }
128
+
129
+ export { ConfigLoader, type AppConfig };
@@ -0,0 +1,132 @@
1
+ /**
2
+ * TypeScript example: Auto-detection patterns
3
+ *
4
+ * Shows how to use pattern matching to determine which
5
+ * environment variables should be encrypted.
6
+ */
7
+
8
+ import * as dotenvage from "../index.js";
9
+
10
+ // Test various key names
11
+ const testKeys = [
12
+ "API_KEY",
13
+ "FLY_API_TOKEN",
14
+ "SECRET_TOKEN",
15
+ "DATABASE_PASSWORD",
16
+ "AWS_SECRET_ACCESS_KEY",
17
+ "STRIPE_SECRET_KEY",
18
+ "NODE_ENV",
19
+ "PORT",
20
+ "DATABASE_URL",
21
+ "LOG_LEVEL",
22
+ "PUBLIC_API_URL",
23
+ ] as const;
24
+
25
+ // Type-safe function to check if a key should be encrypted
26
+ function shouldEncryptKey(key: string): boolean {
27
+ return dotenvage.shouldEncrypt(key);
28
+ }
29
+
30
+ // Group keys by whether they should be encrypted
31
+ const encryptedKeys: string[] = [];
32
+ const plainKeys: string[] = [];
33
+
34
+ testKeys.forEach((key) => {
35
+ if (shouldEncryptKey(key)) {
36
+ encryptedKeys.push(key);
37
+ } else {
38
+ plainKeys.push(key);
39
+ }
40
+ });
41
+
42
+ console.log("Auto-detection Results:");
43
+ console.log(`\n🔒 Should encrypt (${encryptedKeys.length}):`);
44
+ encryptedKeys.forEach((key) => {
45
+ console.log(` - ${key}`);
46
+ });
47
+
48
+ console.log(`\n✅ Plain text (${plainKeys.length}):`);
49
+ plainKeys.forEach((key) => {
50
+ console.log(` - ${key}`);
51
+ });
52
+
53
+ // Example: Type-safe helper to encrypt secrets automatically
54
+ class SecretManager {
55
+ private manager: dotenvage.JsSecretManager;
56
+
57
+ constructor() {
58
+ this.manager = dotenvage.JsSecretManagerNew();
59
+ }
60
+
61
+ /**
62
+ * Set an environment variable, auto-encrypting if the key matches patterns
63
+ */
64
+ setEnvVar(key: string, value: string): string {
65
+ if (dotenvage.shouldEncrypt(key)) {
66
+ // Auto-encrypt sensitive keys
67
+ const encrypted = this.manager.encryptValue(value);
68
+ console.log(`🔒 Auto-encrypted ${key}`);
69
+ return encrypted;
70
+ } else {
71
+ // Keep plain text for non-sensitive keys
72
+ console.log(`✅ Kept ${key} as plain text`);
73
+ return value;
74
+ }
75
+ }
76
+ }
77
+
78
+ // Usage example
79
+ const secretMgr = new SecretManager();
80
+ const apiKey = secretMgr.setEnvVar("API_KEY", "sk_live_abc123");
81
+ const port = secretMgr.setEnvVar("PORT", "8080");
82
+
83
+ console.log(`\nAPI_KEY (encrypted): ${apiKey.substring(0, 30)}...`);
84
+ console.log(`PORT (plain): ${port}`);
85
+
86
+ // Type-safe configuration with auto-encryption
87
+ type ConfigEntry<T> = {
88
+ key: string;
89
+ value: T;
90
+ encrypt: boolean;
91
+ };
92
+
93
+ function createConfig<T>(
94
+ entries: Array<{ key: string; value: T; encrypt?: boolean }>
95
+ ): ConfigEntry<T>[] {
96
+ const manager = dotenvage.JsSecretManagerGenerate();
97
+
98
+ return entries.map((entry) => {
99
+ const shouldEncrypt =
100
+ entry.encrypt !== undefined
101
+ ? entry.encrypt
102
+ : dotenvage.shouldEncrypt(entry.key);
103
+
104
+ let processedValue: T = entry.value;
105
+
106
+ if (shouldEncrypt && typeof entry.value === "string") {
107
+ processedValue = manager.encryptValue(entry.value) as T;
108
+ }
109
+
110
+ return {
111
+ key: entry.key,
112
+ value: processedValue,
113
+ encrypt: shouldEncrypt,
114
+ };
115
+ });
116
+ }
117
+
118
+ const configEntries = createConfig([
119
+ { key: "API_KEY", value: "sk_live_123" },
120
+ { key: "PORT", value: "8080" },
121
+ { key: "DATABASE_URL", value: "postgres://localhost/db" },
122
+ { key: "SECRET_TOKEN", value: "secret-value" },
123
+ ]);
124
+
125
+ console.log("\nConfig entries:");
126
+ configEntries.forEach((entry) => {
127
+ const displayValue =
128
+ entry.encrypt && typeof entry.value === "string"
129
+ ? `${entry.value.substring(0, 30)}...`
130
+ : entry.value;
131
+ console.log(` ${entry.key}: ${displayValue} ${entry.encrypt ? "🔒" : "✅"}`);
132
+ });
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Basic example of using dotenvage in Node.js
3
+ *
4
+ * This is the most common pattern: load encrypted .env files into process.env
5
+ * (similar to how dotenv works with require('dotenv').config())
6
+ */
7
+
8
+ const dotenvage = require("../index.js");
9
+
10
+ // Example 1: Load environment files (MOST COMMON - like dotenv.config())
11
+ // This loads and decrypts .env files, setting variables into process.env
12
+ // Yes, this is how dotenv packages work - they mutate process.env
13
+ console.log(
14
+ "=== Example 1: Load Environment Files (Most Common) ==="
15
+ );
16
+ try {
17
+ const loader = dotenvage.JsEnvLoaderNew();
18
+ loader.load(); // Loads into process.env (mutates environment, like dotenv)
19
+
20
+ // Now variables are available in process.env
21
+ console.log("Loaded variables into process.env");
22
+ const variableNames = loader.getAllVariableNames();
23
+ console.log("Total variables:", variableNames.length);
24
+
25
+ if (variableNames.length > 0) {
26
+ console.log(
27
+ "Sample variables:",
28
+ variableNames.slice(0, 5).join(", ")
29
+ );
30
+ // Example: access a variable (if it exists)
31
+ const sampleKey = variableNames[0];
32
+ if (process.env[sampleKey]) {
33
+ console.log(
34
+ `Example: process.env.${sampleKey} = ${process.env[
35
+ sampleKey
36
+ ].substring(0, 20)}...`
37
+ );
38
+ }
39
+ }
40
+ } catch (error) {
41
+ console.log(
42
+ "Note: Environment loading requires a valid encryption key."
43
+ );
44
+ console.log(
45
+ "Set DOTENVAGE_AGE_KEY, AGE_KEY, or EKG_AGE_KEY environment variable."
46
+ );
47
+ console.log("Error:", error.message);
48
+ }
49
+
50
+ // Example 1b: Load without mutating process.env (alternative pattern)
51
+ // Get variables as an object instead of setting process.env
52
+ console.log(
53
+ "\n=== Example 1b: Get Variables as Object (Non-mutating) ==="
54
+ );
55
+ try {
56
+ const loader = dotenvage.JsEnvLoaderNew();
57
+ const variables = loader.getAllVariables(); // Returns object without modifying process.env
58
+ const keys = Object.keys(variables);
59
+ console.log(
60
+ "Got",
61
+ keys.length,
62
+ "variables as object (not in process.env)"
63
+ );
64
+ if (keys.length > 0) {
65
+ const sampleKey = keys[0];
66
+ console.log(
67
+ `Example: variables.${sampleKey} = ${variables[
68
+ sampleKey
69
+ ].substring(0, 20)}...`
70
+ );
71
+ }
72
+ } catch (error) {
73
+ console.log(
74
+ "Note: Requires valid encryption key. Error:",
75
+ error.message
76
+ );
77
+ }
78
+
79
+ // Example 2: Generate a new encryption key
80
+ console.log("\n=== Example 2: Generate Key ===");
81
+ try {
82
+ const manager = dotenvage.JsSecretManagerGenerate();
83
+ const publicKey = manager.publicKeyString();
84
+ console.log("Generated public key:", publicKey);
85
+ console.log("Save this key - you'll need it to decrypt values!");
86
+ console.log(
87
+ 'Set it as: export DOTENVAGE_AGE_KEY="<private-key-string>"'
88
+ );
89
+ } catch (error) {
90
+ console.error("Error generating key:", error.message);
91
+ console.log(
92
+ 'Note: Make sure you have built the native bindings with "npm run build"'
93
+ );
94
+ }
95
+
96
+ // Example 3: Encrypt and decrypt a value
97
+ console.log("\n=== Example 3: Encrypt/Decrypt ===");
98
+ try {
99
+ const manager = dotenvage.JsSecretManagerGenerate();
100
+ const secret = "my-super-secret-api-key-12345";
101
+
102
+ const encrypted = manager.encryptValue(secret);
103
+ console.log("Original:", secret);
104
+ console.log("Encrypted:", encrypted);
105
+
106
+ const decrypted = manager.decryptValue(encrypted);
107
+ console.log("Decrypted:", decrypted);
108
+ console.log("Match:", secret === decrypted ? "✅" : "❌");
109
+ } catch (error) {
110
+ console.error("Error:", error.message);
111
+ }
112
+
113
+ // Example 4: Check if key should be encrypted (auto-detection patterns)
114
+ console.log("\n=== Example 4: Auto-detection Patterns ===");
115
+ const keys = [
116
+ "API_KEY",
117
+ "FLY_API_TOKEN",
118
+ "NODE_ENV",
119
+ "PORT",
120
+ "DATABASE_URL",
121
+ ];
122
+ for (const key of keys) {
123
+ const shouldEncrypt = dotenvage.shouldEncrypt(key);
124
+ console.log(
125
+ `${key}: ${shouldEncrypt ? "🔒 Should encrypt" : "✅ Plain text"}`
126
+ );
127
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * TypeScript example: Encryption and decryption
3
+ */
4
+
5
+ import * as dotenvage from "../index.js";
6
+
7
+ // Generate a new key pair
8
+ const manager = dotenvage.JsSecretManagerGenerate();
9
+
10
+ // Get the public key (can be shared)
11
+ const publicKey: string = manager.publicKeyString();
12
+ console.log(`Public key: ${publicKey}`);
13
+
14
+ // Encrypt a secret value
15
+ const secret = "sk_live_abc123xyz";
16
+ const encrypted: string = manager.encryptValue(secret);
17
+ console.log(`\nEncrypted: ${encrypted}`);
18
+
19
+ // Decrypt it back
20
+ const decrypted: string = manager.decryptValue(encrypted);
21
+ console.log(`Decrypted: ${decrypted}`);
22
+ console.log(`Match: ${secret === decrypted ? "✅" : "❌"}`);
23
+
24
+ // Check if a value is encrypted
25
+ const isEncrypted: boolean = manager.isEncrypted(encrypted);
26
+ console.log(`\nIs encrypted: ${isEncrypted}`);
27
+
28
+ // Pass through unencrypted values
29
+ const plaintext = "not-encrypted";
30
+ const result: string = manager.decryptValue(plaintext);
31
+ console.log(`Plaintext passthrough: ${result}`);
32
+
33
+ // Type-safe wrapper function
34
+ function encryptSecret(
35
+ manager: dotenvage.JsSecretManager,
36
+ value: string
37
+ ): string {
38
+ return manager.encryptValue(value);
39
+ }
40
+
41
+ function decryptSecret(
42
+ manager: dotenvage.JsSecretManager,
43
+ value: string
44
+ ): string {
45
+ return manager.decryptValue(value);
46
+ }
47
+
48
+ // Usage with type safety
49
+ const apiToken = "my-api-token-123";
50
+ const encryptedToken = encryptSecret(manager, apiToken);
51
+ const decryptedToken = decryptSecret(manager, encryptedToken);
52
+
53
+ console.log(`\nType-safe encryption:`);
54
+ console.log(`Original: ${apiToken}`);
55
+ console.log(`Encrypted: ${encryptedToken.substring(0, 30)}...`);
56
+ console.log(`Decrypted: ${decryptedToken}`);
@@ -0,0 +1,51 @@
1
+ /**
2
+ * TypeScript example: Loading environment variables
3
+ *
4
+ * This is the most common pattern - loading encrypted .env files
5
+ * into process.env (like dotenv.config())
6
+ */
7
+
8
+ import * as dotenvage from "../index.js";
9
+
10
+ // Pattern 1: Load into process.env (most common, mutates environment)
11
+ // This matches how dotenv works - variables become available in process.env
12
+ const loader = dotenvage.JsEnvLoaderNew();
13
+ loader.load(); // Sets variables in process.env
14
+
15
+ // Now access via process.env
16
+ const apiKey = process.env.API_KEY;
17
+ const databaseUrl = process.env.DATABASE_URL;
18
+
19
+ console.log("Loaded variables into process.env");
20
+ console.log(`API_KEY exists: ${!!apiKey}`);
21
+ console.log(`DATABASE_URL exists: ${!!databaseUrl}`);
22
+
23
+ // Pattern 2: Get as object (non-mutating, functional style)
24
+ // Use this when you don't want to modify process.env
25
+ const loader2 = dotenvage.JsEnvLoaderNew();
26
+ const env = loader2.getAllVariables(); // Returns Record<string, string>
27
+
28
+ // Type-safe access
29
+ type EnvConfig = {
30
+ API_KEY?: string;
31
+ DATABASE_URL?: string;
32
+ PORT?: string;
33
+ };
34
+
35
+ const config: EnvConfig = env as EnvConfig;
36
+ console.log("\nGot variables as object:");
37
+ console.log(`API_KEY: ${config.API_KEY ? "✅" : "❌"}`);
38
+ console.log(`DATABASE_URL: ${config.DATABASE_URL ? "✅" : "❌"}`);
39
+ console.log(`PORT: ${config.PORT || "default (8080)"}`);
40
+
41
+ // Pattern 3: Load from specific directory
42
+ const loader3 = dotenvage.JsEnvLoaderNew();
43
+ loader3.loadFromDir("./config"); // Load .env files from ./config directory
44
+
45
+ // Pattern 4: Get variable names only (without loading into environment)
46
+ const loader4 = dotenvage.JsEnvLoaderNew();
47
+ const variableNames: string[] = loader4.getAllVariableNames();
48
+ console.log(`\nFound ${variableNames.length} variables in .env files:`);
49
+ variableNames.slice(0, 5).forEach((name) => {
50
+ console.log(` - ${name}`);
51
+ });
@@ -0,0 +1,132 @@
1
+ /**
2
+ * TypeScript example: Next.js integration
3
+ *
4
+ * Shows how to integrate dotenvage with Next.js for
5
+ * server-side configuration.
6
+ */
7
+
8
+ import * as dotenvage from "../index.js";
9
+
10
+ // Load environment variables (do this early in your app)
11
+ // In Next.js, you'd typically do this in next.config.js or in your API routes
12
+ const loader = dotenvage.JsEnvLoaderNew();
13
+ loader.load();
14
+
15
+ // Type-safe Next.js environment configuration
16
+ interface NextjsEnv {
17
+ readonly NEXT_PUBLIC_APP_URL: string;
18
+ readonly DATABASE_URL: string;
19
+ readonly API_KEY: string;
20
+ readonly NEXT_PUBLIC_API_URL?: string;
21
+ readonly NODE_ENV: "development" | "production" | "test";
22
+ }
23
+
24
+ // Get environment variables with type safety
25
+ function getNextjsEnv(): NextjsEnv {
26
+ const required = (key: keyof NextjsEnv): string => {
27
+ const value = process.env[key];
28
+ if (!value) {
29
+ throw new Error(`Missing required environment variable: ${key}`);
30
+ }
31
+ return value;
32
+ };
33
+
34
+ const optional = (key: string): string | undefined => {
35
+ return process.env[key];
36
+ };
37
+
38
+ return {
39
+ NEXT_PUBLIC_APP_URL: required("NEXT_PUBLIC_APP_URL"),
40
+ DATABASE_URL: required("DATABASE_URL"),
41
+ API_KEY: required("API_KEY"),
42
+ NEXT_PUBLIC_API_URL: optional("NEXT_PUBLIC_API_URL"),
43
+ NODE_ENV: (process.env.NODE_ENV || "development") as NextjsEnv["NODE_ENV"],
44
+ };
45
+ }
46
+
47
+ // Example: Next.js API route handler
48
+ export function createApiHandler<T extends Record<string, unknown>>(
49
+ handler: (env: NextjsEnv, req: T) => Promise<Response>
50
+ ) {
51
+ return async (req: T): Promise<Response> => {
52
+ try {
53
+ const env = getNextjsEnv();
54
+ return await handler(env, req);
55
+ } catch (error) {
56
+ console.error("API error:", error);
57
+ return new Response(
58
+ JSON.stringify({ error: "Internal server error" }),
59
+ {
60
+ status: 500,
61
+ headers: { "Content-Type": "application/json" },
62
+ }
63
+ );
64
+ }
65
+ };
66
+ }
67
+
68
+ // Example: Next.js API route
69
+ async function exampleApiRoute(
70
+ env: NextjsEnv,
71
+ req: { method: string }
72
+ ): Promise<Response> {
73
+ if (req.method !== "GET") {
74
+ return new Response("Method not allowed", { status: 405 });
75
+ }
76
+
77
+ return new Response(
78
+ JSON.stringify({
79
+ message: "API is working",
80
+ environment: env.NODE_ENV,
81
+ // Don't expose secrets in API responses!
82
+ hasApiKey: !!env.API_KEY,
83
+ }),
84
+ {
85
+ status: 200,
86
+ headers: { "Content-Type": "application/json" },
87
+ }
88
+ );
89
+ }
90
+
91
+ // Export the handler (Next.js pattern)
92
+ export const handler = createApiHandler(exampleApiRoute);
93
+
94
+ // Example: Server-side component data fetching
95
+ export async function getServerSideData() {
96
+ const env = getNextjsEnv();
97
+
98
+ // Use the decrypted environment variables
99
+ const response = await fetch(`${env.NEXT_PUBLIC_API_URL}/api/data`, {
100
+ headers: {
101
+ Authorization: `Bearer ${env.API_KEY}`,
102
+ },
103
+ });
104
+
105
+ if (!response.ok) {
106
+ throw new Error("Failed to fetch data");
107
+ }
108
+
109
+ return response.json();
110
+ }
111
+
112
+ // Example: Environment validation at startup
113
+ export function validateNextjsEnv(): void {
114
+ try {
115
+ const env = getNextjsEnv();
116
+ console.log("✅ All required environment variables are set");
117
+ console.log(` Environment: ${env.NODE_ENV}`);
118
+ console.log(` App URL: ${env.NEXT_PUBLIC_APP_URL}`);
119
+ } catch (error) {
120
+ if (error instanceof Error) {
121
+ console.error(`❌ Environment validation failed: ${error.message}`);
122
+ }
123
+ process.exit(1);
124
+ }
125
+ }
126
+
127
+ // Run validation if this is the main module
128
+ if (import.meta.url === `file://${process.argv[1]}`) {
129
+ validateNextjsEnv();
130
+ }
131
+
132
+ export { getNextjsEnv, type NextjsEnv };
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "lib": ["ES2022"],
6
+ "moduleResolution": "node",
7
+ "types": ["node"],
8
+ "esModuleInterop": true,
9
+ "allowSyntheticDefaultImports": true,
10
+ "strict": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "isolatedModules": true,
15
+ "noEmit": true,
16
+ "declaration": true,
17
+ "declarationMap": true,
18
+ "sourceMap": true
19
+ },
20
+ "include": ["*.ts", "**/*.ts"],
21
+ "exclude": ["node_modules"]
22
+ }