envilder 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +83 -34
  2. package/lib/{cli/cli.d.ts → Cli.d.ts} +1 -1
  3. package/lib/Cli.d.ts.map +1 -0
  4. package/lib/{cli/cli.js → Cli.js} +7 -3
  5. package/lib/Cli.js.map +1 -0
  6. package/lib/cli/application/EnvilderHandler.d.ts +18 -0
  7. package/lib/cli/application/EnvilderHandler.d.ts.map +1 -0
  8. package/lib/cli/application/EnvilderHandler.js +64 -0
  9. package/lib/cli/application/EnvilderHandler.js.map +1 -0
  10. package/lib/cli/domain/EnvilderBuilder.d.ts +14 -0
  11. package/lib/cli/domain/EnvilderBuilder.d.ts.map +1 -0
  12. package/lib/cli/domain/EnvilderBuilder.js +41 -0
  13. package/lib/cli/domain/EnvilderBuilder.js.map +1 -0
  14. package/lib/cli/domain/ports/IEnvFileManager.d.ts +6 -0
  15. package/lib/cli/domain/ports/IEnvFileManager.d.ts.map +1 -0
  16. package/lib/cli/domain/ports/IEnvFileManager.js +2 -0
  17. package/lib/cli/domain/ports/IEnvFileManager.js.map +1 -0
  18. package/lib/cli/domain/ports/ISecretProvider.d.ts +4 -0
  19. package/lib/cli/domain/ports/ISecretProvider.d.ts.map +1 -0
  20. package/lib/cli/domain/ports/ISecretProvider.js +2 -0
  21. package/lib/cli/domain/ports/ISecretProvider.js.map +1 -0
  22. package/lib/cli/infrastructure/AwsSsmStoreSecrets.d.ts +8 -0
  23. package/lib/cli/infrastructure/AwsSsmStoreSecrets.d.ts.map +1 -0
  24. package/lib/cli/infrastructure/AwsSsmStoreSecrets.js +26 -0
  25. package/lib/cli/infrastructure/AwsSsmStoreSecrets.js.map +1 -0
  26. package/lib/cli/infrastructure/EnvFileManager.d.ts +7 -0
  27. package/lib/cli/infrastructure/EnvFileManager.d.ts.map +1 -0
  28. package/lib/cli/infrastructure/EnvFileManager.js +37 -0
  29. package/lib/cli/infrastructure/EnvFileManager.js.map +1 -0
  30. package/package.json +38 -27
  31. package/lib/cli/cli.d.ts.map +0 -1
  32. package/lib/cli/cli.js.map +0 -1
  33. package/lib/index.d.ts +0 -11
  34. package/lib/index.d.ts.map +0 -1
  35. package/lib/index.js +0 -116
  36. package/lib/index.js.map +0 -1
package/README.md CHANGED
@@ -1,12 +1,9 @@
1
1
  <h1 align="center">
2
2
  <br>
3
3
  <img src="https://github.com/user-attachments/assets/96bf1efa-7d21-440a-a414-3a20e7f9a1f1" alt="Envilder">
4
- <br>
5
- Envilder
6
- <br>
7
4
  </h1>
8
5
 
9
- <h4 align="center">Secure Your Environment Variables with AWS SSM Parameter Store</h4>
6
+ <h4 align="center">A CLI that securely centralizes your environment variables from AWS SSM as a single source of truth</h4>
10
7
 
11
8
  <p align="center">
12
9
  <a href="https://www.npmjs.com/package/envilder">
@@ -20,11 +17,17 @@
20
17
  </a>
21
18
  </p>
22
19
 
23
- <p align="center">
24
- <b>Stop committing secrets to your repo! Start using AWS SSM Parameter Store to secure your credentials.</b>
25
- </p>
20
+ ## 🌟 Key benefits
21
+
22
+ - **🔒 Strict access control** - AWS IAM policies control who accesses which secrets (dev vs prod)
23
+ - **📊 Full audit trail** - All parameter access is logged in CloudTrail for compliance requirements
24
+ - **🧩 Single source of truth** - No more copying .env files from Notion or emails - SSM is your only source
25
+ - **🔁 Idempotent operations** - Overwrites values in your `.env` file *only* for variables defined in your mapping
26
+ file, using the latest from SSM. Variables not in the mapping file are preserved. Safe for automation.
27
+ - **⚙️ Environment-aware** - Use templates like `/project/${ENV}/DB_PASSWORD` to dynamically fetch the right secrets
28
+ - **🧱 No extra infrastructure** - Uses AWS SSM's existing reliability instead of additional secret managers
26
29
 
27
- ## ⚡ Quick Start
30
+ ## ⚡ Quick start
28
31
 
29
32
  ```bash
30
33
  # Install globally
@@ -37,7 +40,7 @@ echo '{"DB_PASSWORD": "/my-app/db/password"}' > param-map.json
37
40
  envilder --map=param-map.json --envfile=.env
38
41
  ```
39
42
 
40
- ## 🤔 What Problem Does Envilder Solve?
43
+ ## 🤔 What problem does Envilder solve?
41
44
 
42
45
  <table>
43
46
  <tr>
@@ -72,23 +75,23 @@ envilder --map=param-map.json --envfile=.env
72
75
 
73
76
  ## 💡 Why Envilder?
74
77
 
75
- - 🔐 **No More Secrets in Git** - Store credentials in AWS SSM Parameter Store instead of version control
76
- - 🤖 **Automate Everything** - One command to generate your `.env` files across all environments
77
- - 🔄 **Always in Sync** - Keep your local, dev, and production environments consistent
78
- - 🏎️ **Fast to Set Up** - Configure once, then generate `.env` files with a single command
79
- - 🪶 **Simple but Powerful** - Easy interface with support for encrypted parameters and multiple AWS profiles
78
+ - 🔐 **No more secrets in git** - Store credentials in AWS SSM Parameter Store instead of version control
79
+ - 🤖 **Automate everything** - One command to generate your `.env` files across all environments
80
+ - 🔄 **Always in sync** - Keep your local, dev, and production environments consistent
81
+ - 🏎️ **Fast to set up** - Configure once, then generate `.env` files with a single command
82
+ - 🪶 **Simple but powerful** - Easy interface with support for encrypted parameters and multiple AWS profiles
80
83
 
81
- ## 🎯 Perfect for Teams
84
+ ## 🎯 Perfect for teams
82
85
 
83
86
  Envilder is the tool you need if you:
84
87
 
85
- - 👥 **Work in a Development Team** - Ensure everyone has the same environment without sharing raw secrets
86
- - 🔑 **Deal with API Keys & Tokens** - Securely store and retrieve sensitive credentials
87
- - ⚙️ **Run CI/CD Pipelines** - Automatically generate environment files during deployments
88
- - ☁️ **Use AWS Already** - Leverage your existing AWS infrastructure more effectively
89
- - 🌐 **Manage Multiple Environments** - Switch easily between dev, staging, and production
88
+ - 👥 **Work in a development team** - Ensure everyone has the same environment without sharing raw secrets
89
+ - 🔑 **Deal with API keys & tokens** - Securely store and retrieve sensitive credentials
90
+ - ⚙️ **Run CI/CD pipelines** - Automatically generate environment files during deployments
91
+ - ☁️ **Use AWS already** - Leverage your existing AWS infrastructure more effectively
92
+ - 🌐 **Manage multiple environments** - Switch easily between dev, staging, and production
90
93
 
91
- ## 🔍 How It Works (Simple!)
94
+ ## 🔍 How it works (simple!)
92
95
 
93
96
  ```mermaid
94
97
  graph LR
@@ -98,19 +101,19 @@ graph LR
98
101
  E[SSM Parameters] --> B
99
102
  ```
100
103
 
101
- 1. 📖 **Define Your Mapping** - Simple JSON mapping env vars to SSM paths
104
+ 1. 📖 **Define your mapping** - Simple JSON mapping env vars to SSM paths
102
105
  2. 🚀 **Run Envilder** - One command with your mapping file
103
- 3. 🔄 **Auto-Fetch from AWS** - Retrieves values using your AWS credentials
104
- 4. 💾 **Get Your .env File** - Ready to use in your project
106
+ 3. 🔄 **Auto-fetch from AWS** - Retrieves values using your AWS credentials
107
+ 4. 💾 **Get your .env file** - Ready to use in your project
105
108
 
106
109
  ## ⚙️ Prerequisites
107
110
 
108
111
  You'll need:
109
112
 
110
113
  - ✅ **AWS CLI** - Installed and configured with proper permissions to access SSM Parameter Store
111
- - ✅ **Node.js** - Version 14 or higher
114
+ - ✅ **Node.js** - Version 20.0.0 or higher (as specified in `package.json`)
112
115
 
113
- ### AWS CLI Setup
116
+ ### AWS CLI setup
114
117
 
115
118
  1. Install the AWS CLI by following the [official instructions](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html).
116
119
  2. After installation, configure the AWS CLI:
@@ -132,9 +135,6 @@ You'll need:
132
135
  ```bash
133
136
  # Using npm
134
137
  npm install -g envilder
135
-
136
- # Using yarn
137
- yarn global add envilder
138
138
  ```
139
139
 
140
140
  ## 🚀 Usage
@@ -149,7 +149,7 @@ envilder --map=<mapping-file> --envfile=<output-file> [--profile=<aws-profile>]
149
149
  | `--envfile` | Path to output .env file (required) |
150
150
  | `--profile` | AWS CLI profile to use (optional) |
151
151
 
152
- ## 🔧 Quick Example
152
+ ## 🔧 Quick example
153
153
 
154
154
  1. Create a mapping file `param-map.json`:
155
155
 
@@ -172,7 +172,7 @@ envilder --map=<mapping-file> --envfile=<output-file> [--profile=<aws-profile>]
172
172
  envilder --map=param-map.json --envfile=.env --profile=dev-account
173
173
  ```
174
174
 
175
- ## 🌐 Working with Multiple AWS Profiles
175
+ ## 🌐 Working with multiple AWS profiles
176
176
 
177
177
  For multiple AWS accounts or environments, configure different profiles in your AWS credentials file:
178
178
 
@@ -203,17 +203,66 @@ or `%USERPROFILE%\.aws\credentials` on Windows):
203
203
  envilder --map=param-map.json --envfile=.env.production --profile=prod-account
204
204
  ```
205
205
 
206
- ## 📂 Sample `.env` Output
206
+ ## 🛠️ Advanced usage: environment-specific parameters
207
+
208
+ Envilder works brilliantly with environment variables for dynamic parameter paths:
209
+
210
+ 1. Set up your SSM parameters with environment-specific paths:
211
+
212
+ ```text
213
+ /project/dev/DB_PASSWORD
214
+ /project/stage/DB_PASSWORD
215
+ /project/prod/DB_PASSWORD
216
+ ```
217
+
218
+ 2. Create a template-based mapping file `env-map.json`:
219
+
220
+ ```json
221
+ {
222
+ "DB_PASSWORD": "/project/${ENV}/DB_PASSWORD"
223
+ }
224
+ ```
225
+
226
+ 3. Generate environment-specific .env files:
227
+
228
+ ```powershell
229
+ # Development
230
+ $env:ENV = "dev"
231
+ envilder --map=env-map.json --envfile=.env.dev
232
+
233
+ # Staging
234
+ $env:ENV = "stage"
235
+ envilder --map=env-map.json --envfile=.env.stage
236
+
237
+ # Production
238
+ $env:ENV = "prod"
239
+ envilder --map=env-map.json --envfile=.env.prod --profile=prod-account
240
+ ```
241
+
242
+ This approach ensures the right variables are pulled for each environment with minimal configuration.
243
+
244
+ ## 📂 Sample `.env` output
207
245
 
208
246
  ```ini
209
247
  SECRET_TOKEN=mockedEmail@example.com
210
248
  SECRET_KEY=mockedPassword
211
249
  ```
212
250
 
213
- ## 🧪 Running Tests
251
+ ## 🎯 Why use Envilder in practice?
252
+
253
+ Envilder eliminates common problems in development teams:
254
+
255
+ - **🛑 No more "it works on my machine"** - Everyone uses the exact same environment variables from the same source
256
+ - **🔄 Always fresh credentials** - Update a secret in SSM and everyone gets it automatically on next run
257
+ - **🛡️ Access control built-in** - Developers only see dev secrets, CI/CD systems see what they need
258
+ - **🧠 Zero mental overhead** - No need to remember which variables are needed - the mapping defines everything
259
+ - **🚫 No more sharing secrets** - Stop pasting credentials in Slack, email, or Notion documents
260
+ - **📋 Compliance ready** - All accesses are logged in AWS CloudTrail for auditing
261
+
262
+ ## 🧪 Running tests
214
263
 
215
264
  ```bash
216
- yarn test
265
+ npm test
217
266
  ```
218
267
 
219
268
  Check the current coverage report: [Coverage Report](https://macalbert.github.io/envilder/)
@@ -7,4 +7,4 @@
7
7
  * @throws {Error} If either `--map` or `--envfile` arguments are missing.
8
8
  */
9
9
  export declare function main(): Promise<void>;
10
- //# sourceMappingURL=cli.d.ts.map
10
+ //# sourceMappingURL=Cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Cli.d.ts","sourceRoot":"","sources":["../src/Cli.ts"],"names":[],"mappings":";AA6CA;;;;;;GAMG;AACH,wBAAsB,IAAI,kBA0BzB"}
@@ -12,7 +12,7 @@ import { existsSync, readFileSync } from 'node:fs';
12
12
  import { dirname, join } from 'node:path';
13
13
  import { fileURLToPath } from 'node:url';
14
14
  import { Command } from 'commander';
15
- import { run } from '../index.js';
15
+ import { EnvilderBuilder } from './cli/domain/EnvilderBuilder.js';
16
16
  const __filename = fileURLToPath(import.meta.url);
17
17
  const __dirname = dirname(__filename);
18
18
  /**
@@ -65,7 +65,11 @@ export function main() {
65
65
  if (!options.map || !options.envfile) {
66
66
  throw new Error('Missing required arguments: --map and --envfile');
67
67
  }
68
- yield run(options.map, options.envfile, options.profile);
68
+ const envilder = EnvilderBuilder.build()
69
+ .withDefaultFileManager()
70
+ .withAwsProvider(options.profile)
71
+ .create();
72
+ yield envilder.run(options.map, options.envfile);
69
73
  });
70
74
  }
71
75
  // Execute the CLI
@@ -73,4 +77,4 @@ main().catch((error) => {
73
77
  console.error('🚨 Uh-oh! Looks like Mario fell into the wrong pipe! 🍄💥');
74
78
  console.error(error);
75
79
  });
76
- //# sourceMappingURL=cli.js.map
80
+ //# sourceMappingURL=Cli.js.map
package/lib/Cli.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Cli.js","sourceRoot":"","sources":["../src/Cli.ts"],"names":[],"mappings":";;;;;;;;;;AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAElE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;;;;GAKG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAE,QAAQ,GAAG,CAAC;IACrD,IAAI,UAAU,GAAG,QAAQ,CAAC;IAC1B,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,OAAO,KAAK,GAAG,QAAQ,EAAE,CAAC;QACxB,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QACrD,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,sBAAsB;QACtB,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QACtC,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YAC7B,yBAAyB;YACzB,MAAM;QACR,CAAC;QAED,UAAU,GAAG,SAAS,CAAC;QACvB,KAAK,EAAE,CAAC;IACV,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,0DAA0D;AAC1D,MAAM,eAAe,GACnB,eAAe,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;AAC5E,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;AAEtE;;;;;;GAMG;AACH,MAAM,UAAgB,IAAI;;QACxB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;QAC9B,OAAO;aACJ,IAAI,CAAC,UAAU,CAAC;aAChB,WAAW,CAAC,2DAA2D,CAAC;aACxE,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;aAC5B,cAAc,CACb,cAAc,EACd,yDAAyD,CAC1D;aACA,cAAc,CAAC,kBAAkB,EAAE,uCAAuC,CAAC;aAC3E,MAAM,CAAC,kBAAkB,EAAE,wBAAwB,CAAC,CAAC;QAExD,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAE/B,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,EAAE;aACrC,sBAAsB,EAAE;aACxB,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;aAChC,MAAM,EAAE,CAAC;QAEZ,MAAM,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC;CAAA;AAED,kBAAkB;AAClB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC3E,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { IEnvFileManager } from '../domain/ports/IEnvFileManager';
2
+ import type { ISecretProvider } from '../domain/ports/ISecretProvider';
3
+ export declare class Envilder {
4
+ private keyVault;
5
+ private envFileManager;
6
+ constructor(keyVault: ISecretProvider, envFileManager: IEnvFileManager);
7
+ /**
8
+ * Orchestrates the process of fetching environment variable values from a key vault and writing them to a local environment file.
9
+ *
10
+ * Loads a parameter mapping from a JSON file, retrieves existing environment variables, fetches updated values from the key vault, merges them, and writes the result to the specified environment file.
11
+ *
12
+ * @param mapPath - Path to the JSON file mapping environment variable names to key vault parameter names.
13
+ * @param envFilePath - Path to the local environment file to read and update.
14
+ */
15
+ run(mapPath: string, envFilePath: string): Promise<void>;
16
+ private fetchAndUpdateEnvVariables;
17
+ }
18
+ //# sourceMappingURL=EnvilderHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvilderHandler.d.ts","sourceRoot":"","sources":["../../../src/cli/application/EnvilderHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEvE,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,cAAc,CAAkB;gBAE5B,QAAQ,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe;IAKtE;;;;;;;OAOG;IACG,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;YAYhC,0BAA0B;CAoCzC"}
@@ -0,0 +1,64 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ export class Envilder {
11
+ constructor(keyVault, envFileManager) {
12
+ this.keyVault = keyVault;
13
+ this.envFileManager = envFileManager;
14
+ }
15
+ /**
16
+ * Orchestrates the process of fetching environment variable values from a key vault and writing them to a local environment file.
17
+ *
18
+ * Loads a parameter mapping from a JSON file, retrieves existing environment variables, fetches updated values from the key vault, merges them, and writes the result to the specified environment file.
19
+ *
20
+ * @param mapPath - Path to the JSON file mapping environment variable names to key vault parameter names.
21
+ * @param envFilePath - Path to the local environment file to read and update.
22
+ */
23
+ run(mapPath, envFilePath) {
24
+ return __awaiter(this, void 0, void 0, function* () {
25
+ const paramMap = this.envFileManager.loadParamMap(mapPath);
26
+ const existingEnvVariables = this.envFileManager.loadExistingEnvVariables(envFilePath);
27
+ const updatedEnvVariables = yield this.fetchAndUpdateEnvVariables(paramMap, existingEnvVariables);
28
+ this.envFileManager.writeEnvFile(envFilePath, updatedEnvVariables);
29
+ console.log(`Environment File generated at '${envFilePath}'`);
30
+ });
31
+ }
32
+ fetchAndUpdateEnvVariables(paramMap, existingEnvVariables) {
33
+ return __awaiter(this, void 0, void 0, function* () {
34
+ try {
35
+ const errors = [];
36
+ for (const [envVar, secretName] of Object.entries(paramMap)) {
37
+ try {
38
+ const value = yield this.keyVault.getSecret(secretName);
39
+ if (!value) {
40
+ console.error(`Warning: No value found for: '${secretName}'`);
41
+ continue;
42
+ }
43
+ existingEnvVariables[envVar] = value;
44
+ console.log(`${envVar}=${value.length > 10 ? '*'.repeat(value.length - 3) + value.slice(-3) : '*'.repeat(value.length)}`);
45
+ }
46
+ catch (error) {
47
+ console.error(`Error fetching parameter: '${secretName}'`);
48
+ errors.push(`ParameterNotFound: ${secretName}`);
49
+ }
50
+ }
51
+ if (errors.length > 0) {
52
+ throw new Error(`Some parameters could not be fetched:\n${errors.join('\n')}`);
53
+ }
54
+ return existingEnvVariables;
55
+ }
56
+ catch (error) {
57
+ const errorMessage = error instanceof Error ? error.message : String(error);
58
+ console.error(`Failed to generate environment file: ${errorMessage}`);
59
+ throw error;
60
+ }
61
+ });
62
+ }
63
+ }
64
+ //# sourceMappingURL=EnvilderHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvilderHandler.js","sourceRoot":"","sources":["../../../src/cli/application/EnvilderHandler.ts"],"names":[],"mappings":";;;;;;;;;AAGA,MAAM,OAAO,QAAQ;IAInB,YAAY,QAAyB,EAAE,cAA+B;QACpE,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACvC,CAAC;IAED;;;;;;;OAOG;IACG,GAAG,CAAC,OAAe,EAAE,WAAmB;;YAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAC3D,MAAM,oBAAoB,GACxB,IAAI,CAAC,cAAc,CAAC,wBAAwB,CAAC,WAAW,CAAC,CAAC;YAC5D,MAAM,mBAAmB,GAAG,MAAM,IAAI,CAAC,0BAA0B,CAC/D,QAAQ,EACR,oBAAoB,CACrB,CAAC;YACF,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;YACnE,OAAO,CAAC,GAAG,CAAC,kCAAkC,WAAW,GAAG,CAAC,CAAC;QAChE,CAAC;KAAA;IAEa,0BAA0B,CACtC,QAAgC,EAChC,oBAA4C;;YAE5C,IAAI,CAAC;gBACH,MAAM,MAAM,GAAa,EAAE,CAAC;gBAC5B,KAAK,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC5D,IAAI,CAAC;wBACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;wBACxD,IAAI,CAAC,KAAK,EAAE,CAAC;4BACX,OAAO,CAAC,KAAK,CAAC,iCAAiC,UAAU,GAAG,CAAC,CAAC;4BAC9D,SAAS;wBACX,CAAC;wBACD,oBAAoB,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;wBACrC,OAAO,CAAC,GAAG,CACT,GAAG,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAC7G,CAAC;oBACJ,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,OAAO,CAAC,KAAK,CAAC,8BAA8B,UAAU,GAAG,CAAC,CAAC;wBAC3D,MAAM,CAAC,IAAI,CAAC,sBAAsB,UAAU,EAAE,CAAC,CAAC;oBAClD,CAAC;gBACH,CAAC;gBACD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtB,MAAM,IAAI,KAAK,CACb,0CAA0C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC9D,CAAC;gBACJ,CAAC;gBAED,OAAO,oBAAoB,CAAC;YAC9B,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACzD,OAAO,CAAC,KAAK,CAAC,wCAAwC,YAAY,EAAE,CAAC,CAAC;gBACtE,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;KAAA;CACF"}
@@ -0,0 +1,14 @@
1
+ import { Envilder } from '../application/EnvilderHandler.js';
2
+ import type { IEnvFileManager } from './ports/IEnvFileManager.js';
3
+ import type { ISecretProvider } from './ports/ISecretProvider.js';
4
+ export declare class EnvilderBuilder {
5
+ private provider?;
6
+ private fileManager?;
7
+ static build(): EnvilderBuilder;
8
+ withDefaultFileManager(): this;
9
+ withEnvFileManager(fileManager: IEnvFileManager): this;
10
+ withProvider(provider: ISecretProvider): this;
11
+ withAwsProvider(profile?: string): this;
12
+ create(): Envilder;
13
+ }
14
+ //# sourceMappingURL=EnvilderBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvilderBuilder.d.ts","sourceRoot":"","sources":["../../../src/cli/domain/EnvilderBuilder.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAG7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,CAAkB;IACnC,OAAO,CAAC,WAAW,CAAC,CAAkB;IAEtC,MAAM,CAAC,KAAK,IAAI,eAAe;IAI/B,sBAAsB,IAAI,IAAI;IAK9B,kBAAkB,CAAC,WAAW,EAAE,eAAe,GAAG,IAAI;IAKtD,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAK7C,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAYvC,MAAM,IAAI,QAAQ;CAWnB"}
@@ -0,0 +1,41 @@
1
+ import { SSM } from '@aws-sdk/client-ssm';
2
+ import { fromIni } from '@aws-sdk/credential-providers';
3
+ import { Envilder } from '../application/EnvilderHandler.js';
4
+ import { AwsSsmSecretProvider } from '../infrastructure/AwsSsmStoreSecrets.js';
5
+ import { EnvFileManager } from '../infrastructure/EnvFileManager.js';
6
+ export class EnvilderBuilder {
7
+ static build() {
8
+ return new EnvilderBuilder();
9
+ }
10
+ withDefaultFileManager() {
11
+ this.fileManager = new EnvFileManager();
12
+ return this;
13
+ }
14
+ withEnvFileManager(fileManager) {
15
+ this.fileManager = fileManager;
16
+ return this;
17
+ }
18
+ withProvider(provider) {
19
+ this.provider = provider;
20
+ return this;
21
+ }
22
+ withAwsProvider(profile) {
23
+ const ssm = profile == null
24
+ ? new SSM()
25
+ : new SSM({
26
+ credentials: fromIni({ profile: profile }),
27
+ });
28
+ this.provider = new AwsSsmSecretProvider(ssm);
29
+ return this;
30
+ }
31
+ create() {
32
+ if (!this.provider) {
33
+ throw new Error('Secret provider must be specified');
34
+ }
35
+ if (!this.fileManager) {
36
+ throw new Error('Env file manager must be specified');
37
+ }
38
+ return new Envilder(this.provider, this.fileManager);
39
+ }
40
+ }
41
+ //# sourceMappingURL=EnvilderBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvilderBuilder.js","sourceRoot":"","sources":["../../../src/cli/domain/EnvilderBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAE1C,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAIrE,MAAM,OAAO,eAAe;IAI1B,MAAM,CAAC,KAAK;QACV,OAAO,IAAI,eAAe,EAAE,CAAC;IAC/B,CAAC;IAED,sBAAsB;QACpB,IAAI,CAAC,WAAW,GAAG,IAAI,cAAc,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,kBAAkB,CAAC,WAA4B;QAC7C,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,YAAY,CAAC,QAAyB;QACpC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,eAAe,CAAC,OAAgB;QAC9B,MAAM,GAAG,GACP,OAAO,IAAI,IAAI;YACb,CAAC,CAAC,IAAI,GAAG,EAAE;YACX,CAAC,CAAC,IAAI,GAAG,CAAC;gBACN,WAAW,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;aACxB,CAAC,CAAC;QAE5B,IAAI,CAAC,QAAQ,GAAG,IAAI,oBAAoB,CAAC,GAAG,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM;QACJ,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACvD,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ export interface IEnvFileManager {
2
+ loadParamMap(mapPath: string): Record<string, string>;
3
+ loadExistingEnvVariables(envFilePath: string): Record<string, string>;
4
+ writeEnvFile(envFilePath: string, envVariables: Record<string, string>): void;
5
+ }
6
+ //# sourceMappingURL=IEnvFileManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IEnvFileManager.d.ts","sourceRoot":"","sources":["../../../../src/cli/domain/ports/IEnvFileManager.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtD,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtE,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;CAC/E"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=IEnvFileManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IEnvFileManager.js","sourceRoot":"","sources":["../../../../src/cli/domain/ports/IEnvFileManager.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ export interface ISecretProvider {
2
+ getSecret(name: string): Promise<string | undefined>;
3
+ }
4
+ //# sourceMappingURL=ISecretProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ISecretProvider.d.ts","sourceRoot":"","sources":["../../../../src/cli/domain/ports/ISecretProvider.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACtD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ISecretProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ISecretProvider.js","sourceRoot":"","sources":["../../../../src/cli/domain/ports/ISecretProvider.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ import { type SSM } from '@aws-sdk/client-ssm';
2
+ import type { ISecretProvider } from '../domain/ports/ISecretProvider';
3
+ export declare class AwsSsmSecretProvider implements ISecretProvider {
4
+ private ssm;
5
+ constructor(ssm: SSM);
6
+ getSecret(name: string): Promise<string | undefined>;
7
+ }
8
+ //# sourceMappingURL=AwsSsmStoreSecrets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AwsSsmStoreSecrets.d.ts","sourceRoot":"","sources":["../../../src/cli/infrastructure/AwsSsmStoreSecrets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,GAAG,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEvE,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,OAAO,CAAC,GAAG,CAAM;gBAEL,GAAG,EAAE,GAAG;IAId,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAQ3D"}
@@ -0,0 +1,26 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { GetParameterCommand } from '@aws-sdk/client-ssm';
11
+ export class AwsSsmSecretProvider {
12
+ constructor(ssm) {
13
+ this.ssm = ssm;
14
+ }
15
+ getSecret(name) {
16
+ return __awaiter(this, void 0, void 0, function* () {
17
+ const command = new GetParameterCommand({
18
+ Name: name,
19
+ WithDecryption: true,
20
+ });
21
+ const { Parameter } = yield this.ssm.send(command);
22
+ return Parameter === null || Parameter === void 0 ? void 0 : Parameter.Value;
23
+ });
24
+ }
25
+ }
26
+ //# sourceMappingURL=AwsSsmStoreSecrets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AwsSsmStoreSecrets.js","sourceRoot":"","sources":["../../../src/cli/infrastructure/AwsSsmStoreSecrets.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,mBAAmB,EAAY,MAAM,qBAAqB,CAAC;AAGpE,MAAM,OAAO,oBAAoB;IAG/B,YAAY,GAAQ;QAClB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAEK,SAAS,CAAC,IAAY;;YAC1B,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC;gBACtC,IAAI,EAAE,IAAI;gBACV,cAAc,EAAE,IAAI;aACrB,CAAC,CAAC;YACH,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACnD,OAAO,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,KAAK,CAAC;QAC1B,CAAC;KAAA;CACF"}
@@ -0,0 +1,7 @@
1
+ import type { IEnvFileManager } from '../domain/ports/IEnvFileManager';
2
+ export declare class EnvFileManager implements IEnvFileManager {
3
+ loadParamMap(mapPath: string): Record<string, string>;
4
+ loadExistingEnvVariables(envFilePath: string): Record<string, string>;
5
+ writeEnvFile(envFilePath: string, envVariables: Record<string, string>): void;
6
+ }
7
+ //# sourceMappingURL=EnvFileManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvFileManager.d.ts","sourceRoot":"","sources":["../../../src/cli/infrastructure/EnvFileManager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEvE,qBAAa,cAAe,YAAW,eAAe;IACpD,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAUrD,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAWrE,YAAY,CACV,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,IAAI;CAYR"}
@@ -0,0 +1,37 @@
1
+ import * as fs from 'node:fs';
2
+ import * as dotenv from 'dotenv';
3
+ export class EnvFileManager {
4
+ loadParamMap(mapPath) {
5
+ const content = fs.readFileSync(mapPath, 'utf-8');
6
+ try {
7
+ return JSON.parse(content);
8
+ }
9
+ catch (error) {
10
+ console.error(`Error parsing JSON from ${mapPath}`);
11
+ throw new Error(`Invalid JSON in parameter map file: ${mapPath}`);
12
+ }
13
+ }
14
+ loadExistingEnvVariables(envFilePath) {
15
+ const envVariables = {};
16
+ if (!fs.existsSync(envFilePath)) {
17
+ return envVariables;
18
+ }
19
+ const existingEnvContent = fs.readFileSync(envFilePath, 'utf-8');
20
+ const parsedEnv = dotenv.parse(existingEnvContent);
21
+ Object.assign(envVariables, parsedEnv);
22
+ return envVariables;
23
+ }
24
+ writeEnvFile(envFilePath, envVariables) {
25
+ const envContent = Object.entries(envVariables)
26
+ .map(([key, value]) => {
27
+ const escapedValue = value
28
+ .replace(/\\/g, '\\\\')
29
+ .replace(/(\r\n|\n|\r)/g, '\\n')
30
+ .replace(/"/g, '\\"');
31
+ return `${key}=${escapedValue}`;
32
+ })
33
+ .join('\n');
34
+ fs.writeFileSync(envFilePath, envContent);
35
+ }
36
+ }
37
+ //# sourceMappingURL=EnvFileManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnvFileManager.js","sourceRoot":"","sources":["../../../src/cli/infrastructure/EnvFileManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAGjC,MAAM,OAAO,cAAc;IACzB,YAAY,CAAC,OAAe;QAC1B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,2BAA2B,OAAO,EAAE,CAAC,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,uCAAuC,OAAO,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IAED,wBAAwB,CAAC,WAAmB;QAC1C,MAAM,YAAY,GAA2B,EAAE,CAAC;QAChD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAChC,OAAO,YAAY,CAAC;QACtB,CAAC;QACD,MAAM,kBAAkB,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACjE,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;QACvC,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,YAAY,CACV,WAAmB,EACnB,YAAoC;QAEpC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC;aAC5C,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;YACpB,MAAM,YAAY,GAAG,KAAK;iBACvB,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;iBACtB,OAAO,CAAC,eAAe,EAAE,KAAK,CAAC;iBAC/B,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACxB,OAAO,GAAG,GAAG,IAAI,YAAY,EAAE,CAAC;QAClC,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IAC5C,CAAC;CACF"}
package/package.json CHANGED
@@ -1,34 +1,43 @@
1
1
  {
2
2
  "name": "envilder",
3
- "version": "0.5.1",
4
- "description": "A CLI tool to generate .env files from AWS SSM parameters",
5
- "exports": {
6
- ".": {
7
- "import": "./lib/index.js",
8
- "types": "./lib/index.d.ts"
9
- }
10
- },
11
- "main": "./lib/index.js",
3
+ "version": "0.5.3",
4
+ "description": "A CLI that securely centralizes your environment variables from AWS SSM as a single source of truth",
5
+ "main": "./lib/Cli.js",
12
6
  "bin": {
13
- "envilder": "lib/cli/cli.js"
7
+ "envilder": "lib/Cli.js"
14
8
  },
15
9
  "scripts": {
16
- "clean": "npx jest --clearCache && yarn cache clean --force && npx rimraf lib && npx rimraf node_modules && npx rimraf coverage && npx rimraf yarn.lock",
17
- "test-run": "yarn build && node lib/cli/cli.js --map=tests/sample/param-map.json --envfile=tests/sample/autogenerated.env",
18
- "build": "tsc -p tsconfig.build.json --sourceMap --declaration && node --no-warnings scripts/chmod-cli.js",
19
- "validate-cli": "node --no-warnings --loader ts-node/esm scripts/validate-cli.ts",
20
- "format": "npx biome format",
21
- "format:write": "npx biome format --write",
22
- "lint": "npx secretlint \"**/*\" && biome lint --write && biome format --write && biome check --write && tsc --noEmit",
23
- "lint:fix": "npx biome lint --fix",
10
+ "clean": "jest --clearCache && npm cache clean --force && rimraf lib && rimraf coverage && rimraf node_modules",
11
+ "build": "tsc",
12
+ "local:install": "npm run build && node --loader ts-node/esm scripts/pack-and-install.ts",
13
+ "local:test-run": "npm run build && node lib/cli/cli.js --map=tests/cli/sample/param-map.json --envfile=tests/cli/sample/autogenerated.env",
14
+ "format": "biome format",
15
+ "format:write": "biome format --write",
16
+ "lint": "secretlint \"**/*\" && biome check --write && tsc --noEmit",
17
+ "lint:fix": "biome lint --fix",
24
18
  "test": "vitest run --reporter verbose --coverage",
25
- "cli-run": "yarn build && node --trace-warnings lib",
26
- "npm-publish": "yarn lint && yarn build && yarn test && npm pack --dry-run && yarn publish",
27
- "npm-release-patch": "yarn version --new-version patch",
28
- "npm-release-minor": "yarn version --new-version minor",
29
- "npm-release-prerelease": "yarn version --new-version prerelease"
19
+ "npm-publish": "npm run lint && npm run build && npm run test && npm pack --dry-run && npm publish",
20
+ "npm-release-patch": "npm version patch",
21
+ "npm-release-minor": "npm version minor",
22
+ "npm-release-prerelease": "npm version prerelease"
30
23
  },
31
- "keywords": [],
24
+ "keywords": [
25
+ "env",
26
+ "dotenv",
27
+ "aws",
28
+ "ssm",
29
+ "parameter-store",
30
+ "cli",
31
+ "environment",
32
+ "secrets",
33
+ "automation",
34
+ "config",
35
+ "aws-cli",
36
+ "devops",
37
+ "ci-cd",
38
+ "secure",
39
+ "envfile"
40
+ ],
32
41
  "repository": {
33
42
  "type": "git",
34
43
  "url": "git://github.com/macalbert/envilder.git"
@@ -52,22 +61,24 @@
52
61
  "@aws-sdk/client-ssm": "^3.806.0",
53
62
  "@aws-sdk/credential-providers": "^3.806.0",
54
63
  "@types/node": "^22.5.5",
55
- "commander": "^13.1.0",
64
+ "commander": "^14.0.0",
56
65
  "dotenv": "^16.4.5",
57
66
  "picocolors": "^1.1.0"
58
67
  },
59
68
  "devDependencies": {
60
69
  "@biomejs/biome": "^1.9.1",
61
70
  "@secretlint/secretlint-rule-preset-recommend": "^9.3.2",
71
+ "@testcontainers/localstack": "^11.0.1",
62
72
  "@vitest/coverage-v8": "^3.1.1",
73
+ "jest": "^29.7.0",
63
74
  "rimraf": "^6.0.1",
64
75
  "secretlint": "^9.3.2",
76
+ "testcontainers": "^11.0.1",
65
77
  "ts-node": "^10.9.2",
66
78
  "typescript": "^5.6.2",
67
79
  "vitest": "^3.1.1"
68
80
  },
69
81
  "engines": {
70
- "node": ">=20.0.0",
71
- "yarn": ">=1.22"
82
+ "node": ">=20.0.0"
72
83
  }
73
84
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":";AA4CA;;;;;;GAMG;AACH,wBAAsB,IAAI,kBAkBzB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":";;;;;;;;;;AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC;;;;;GAKG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAE,QAAQ,GAAG,CAAC;IACrD,IAAI,UAAU,GAAG,QAAQ,CAAC;IAC1B,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,OAAO,KAAK,GAAG,QAAQ,EAAE,CAAC;QACxB,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QACrD,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,sBAAsB;QACtB,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QACtC,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YAC7B,yBAAyB;YACzB,MAAM;QACR,CAAC;QAED,UAAU,GAAG,SAAS,CAAC;QACvB,KAAK,EAAE,CAAC;IACV,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,0DAA0D;AAC1D,MAAM,eAAe,GAAG,eAAe,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;AAClG,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;AAEtE;;;;;;GAMG;AACH,MAAM,UAAgB,IAAI;;QACxB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;QAC9B,OAAO;aACJ,IAAI,CAAC,UAAU,CAAC;aAChB,WAAW,CAAC,2DAA2D,CAAC;aACxE,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;aAC5B,cAAc,CAAC,cAAc,EAAE,yDAAyD,CAAC;aACzF,cAAc,CAAC,kBAAkB,EAAE,uCAAuC,CAAC;aAC3E,MAAM,CAAC,kBAAkB,EAAE,wBAAwB,CAAC,CAAC;QAExD,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAE/B,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,CAAC;CAAA;AAED,kBAAkB;AAClB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC3E,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
package/lib/index.d.ts DELETED
@@ -1,11 +0,0 @@
1
- /**
2
- * Orchestrates the process of fetching environment variable values from AWS SSM Parameter Store and writing them to a local environment file.
3
- *
4
- * Loads a parameter mapping from a JSON file, retrieves existing environment variables, fetches updated values from SSM (optionally using a specified AWS profile), merges them, and writes the result to the specified environment file.
5
- *
6
- * @param mapPath - Path to the JSON file mapping environment variable names to SSM parameter names.
7
- * @param envFilePath - Path to the local environment file to read and update.
8
- * @param profile - Optional AWS profile name to use for credentials.
9
- */
10
- export declare function run(mapPath: string, envFilePath: string, profile?: string): Promise<void>;
11
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,iBAY/E"}
package/lib/index.js DELETED
@@ -1,116 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import * as fs from 'node:fs';
11
- import { GetParameterCommand, SSM } from '@aws-sdk/client-ssm';
12
- import { fromIni } from '@aws-sdk/credential-providers';
13
- import * as dotenv from 'dotenv';
14
- /**
15
- * Orchestrates the process of fetching environment variable values from AWS SSM Parameter Store and writing them to a local environment file.
16
- *
17
- * Loads a parameter mapping from a JSON file, retrieves existing environment variables, fetches updated values from SSM (optionally using a specified AWS profile), merges them, and writes the result to the specified environment file.
18
- *
19
- * @param mapPath - Path to the JSON file mapping environment variable names to SSM parameter names.
20
- * @param envFilePath - Path to the local environment file to read and update.
21
- * @param profile - Optional AWS profile name to use for credentials.
22
- */
23
- export function run(mapPath, envFilePath, profile) {
24
- return __awaiter(this, void 0, void 0, function* () {
25
- const defaultAwsConfig = {};
26
- const ssmClientConfig = profile ? { credentials: fromIni({ profile }) } : defaultAwsConfig;
27
- const ssm = new SSM(ssmClientConfig);
28
- const paramMap = loadParamMap(mapPath);
29
- const existingEnvVariables = loadExistingEnvVariables(envFilePath);
30
- const updatedEnvVariables = yield fetchAndUpdateEnvVariables(paramMap, existingEnvVariables, ssm);
31
- writeEnvFile(envFilePath, updatedEnvVariables);
32
- console.log(`Environment File generated at '${envFilePath}'`);
33
- });
34
- }
35
- function loadParamMap(mapPath) {
36
- const content = fs.readFileSync(mapPath, 'utf-8');
37
- try {
38
- return JSON.parse(content);
39
- }
40
- catch (error) {
41
- console.error(`Error parsing JSON from ${mapPath}`);
42
- throw new Error(`Invalid JSON in parameter map file: ${mapPath}`);
43
- }
44
- }
45
- function loadExistingEnvVariables(envFilePath) {
46
- const envVariables = {};
47
- if (!fs.existsSync(envFilePath))
48
- return envVariables;
49
- const existingEnvContent = fs.readFileSync(envFilePath, 'utf-8');
50
- const parsedEnv = dotenv.parse(existingEnvContent);
51
- Object.assign(envVariables, parsedEnv);
52
- return envVariables;
53
- }
54
- /**
55
- * Fetches parameter values from AWS SSM for each environment variable in the map and updates the existing environment variables record.
56
- *
57
- * For each mapping, retrieves the corresponding SSM parameter value and updates the environment variable if found. Logs masked values and warnings for missing parameters. Throws an error if any parameters fail to fetch.
58
- *
59
- * @param paramMap - Mapping of environment variable names to SSM parameter names.
60
- * @param existingEnvVariables - Current environment variables to be updated.
61
- * @param ssm - AWS SSM client instance used for fetching parameters.
62
- * @returns The updated environment variables record.
63
- *
64
- * @throws {Error} If any SSM parameters cannot be fetched.
65
- */
66
- function fetchAndUpdateEnvVariables(paramMap, existingEnvVariables, ssm) {
67
- return __awaiter(this, void 0, void 0, function* () {
68
- const errors = [];
69
- for (const [envVar, ssmName] of Object.entries(paramMap)) {
70
- try {
71
- const value = yield fetchSSMParameter(ssmName, ssm);
72
- if (value) {
73
- existingEnvVariables[envVar] = value;
74
- console.log(`${envVar}=${value.length > 3 ? '*'.repeat(value.length - 3) + value.slice(-3) : '*'.repeat(value.length)}`);
75
- }
76
- else {
77
- console.error(`Warning: No value found for: '${ssmName}'`);
78
- }
79
- }
80
- catch (error) {
81
- console.error(`Error fetching parameter: '${ssmName}'`);
82
- errors.push(`ParameterNotFound: ${ssmName}`);
83
- }
84
- }
85
- if (errors.length > 0) {
86
- throw new Error(`Some parameters could not be fetched:\n${errors.join('\n')}`);
87
- }
88
- return existingEnvVariables;
89
- });
90
- }
91
- /**
92
- * Retrieves the value of a parameter from AWS SSM Parameter Store with decryption enabled.
93
- *
94
- * @param ssmName - The name of the SSM parameter to retrieve.
95
- * @returns The decrypted parameter value if found, or undefined if the parameter does not exist.
96
- */
97
- function fetchSSMParameter(ssmName, ssm) {
98
- return __awaiter(this, void 0, void 0, function* () {
99
- const command = new GetParameterCommand({
100
- Name: ssmName,
101
- WithDecryption: true,
102
- });
103
- const { Parameter } = yield ssm.send(command);
104
- return Parameter === null || Parameter === void 0 ? void 0 : Parameter.Value;
105
- });
106
- }
107
- function writeEnvFile(envFilePath, envVariables) {
108
- const envContent = Object.entries(envVariables)
109
- .map(([key, value]) => {
110
- const escapedValue = value.replace(/(\n|\r|\n\r)/g, '\\n').replace(/"/g, '\\"');
111
- return `${key}=${escapedValue}`;
112
- })
113
- .join('\n');
114
- fs.writeFileSync(envFilePath, envContent);
115
- }
116
- //# sourceMappingURL=index.js.map
package/lib/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}