env-drift-check 0.1.7 → 0.1.9

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 CHANGED
@@ -1,71 +1,126 @@
1
- # env-drift-check: Interactive .env Sync & Validation for Teams
1
+ # env-drift-check
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/env-drift-check.svg)](https://www.npmjs.com/package/env-drift-check)
4
- [![npm downloads](https://img.shields.io/npm/dm/env-drift-check.svg)](https://www.npmjs.com/package/env-drift-check)
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
3
+ <div align="center">
6
4
 
7
- > **Eliminate "It works on my machine" issues.** Synchronize `.env` files across your team with interactive prompts, smart schema validation, and real-time drift detection.
5
+ **A combined environment drift detector + schema validator for multi-environment setups.**
8
6
 
9
- **env-drift-check** is a powerful CLI utility designed to manage environment variables in Node.js applications. It ensures your local `.env` remains in perfect sync with `.env.example`, preventing runtime crashes and streamlining developer onboarding.
7
+ [![npm version](https://img.shields.io/npm/v/env-drift-check.svg?style=flat-square)](https://npmjs.org/package/env-drift-check)
8
+ [![npm downloads](https://img.shields.io/npm/dm/env-drift-check.svg?style=flat-square)](https://npm-stat.com/charts.html?package=env-drift-check)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
10
+ [![CI Status](https://img.shields.io/badge/build-passing-brightgreen?style=flat-square)](#)
10
11
 
11
- ![env-drift-check demo](https://github.com/shashi089/env-drift-check/raw/main/assets/env-drift-check.png)
12
+ *Say goodbye to "It works on my machine" and hello to bulletproof environment variables.*
12
13
 
13
- ## 🚀 Why Use env-drift-check?
14
+ [Installation](#installation) [Features](#features) [Quick Start](#quick-start) • [Configuration](#configuration) • [Usage](#usage) • [Roadmap](#roadmap)
14
15
 
15
- Manually managing environment variables is error-prone. **env-drift-check** automates the process:
16
+ </div>
16
17
 
17
- | Pain Point | Standard Approach | **env-drift-check** |
18
- | :--- | :--- | :--- |
19
- | **Missing Keys** | Application crashes at runtime | **Interactive Setup Wizard** fills them |
20
- | **Type Safety** | String-only values, no validation | **Rich Validation** (Email, URL, Regex) |
21
- | **Team Onboarding** | "Copy this file from Slack/Docs" | `npx env-drift-check init` & sync |
22
- | **Configuration Drift** | Desync between dev/stage/prod | **Real-time Detection** against template |
18
+ <div align="center">
19
+ <img src="https://github.com/shashi089/env-drift-check/raw/main/assets/env-drift-check.png" alt="env-drift-check demo" />
20
+ </div>
23
21
 
24
- ### Key Features
22
+ ---
23
+
24
+ ## 💡 The Problem It Solves
25
+
26
+ Managing `.env` files across a team of developers or multiple deployment environments (development, staging, production) is notoriously error-prone.
27
+
28
+ - **Missing variables** lead to unexpected runtime crashes.
29
+ - **Incorrect data types** (e.g., passing a string `"false"` instead of a proper boolean) cause silent logical bugs.
30
+ - **Onboarding new developers** often involves insecurely sharing `.env` files over Slack, or fighting with an outdated `.env.example`.
31
+
32
+ **env-drift-check** bridges this gap. It provides real-time drift detection to ensure your local environments match the blueprint, an interactive CLI to fix missing variables instantly, and a robust schema validator to enforce types and formats.
33
+
34
+ ---
35
+
36
+ ## 🏗 Architecture & Flow
37
+
38
+ ```mermaid
39
+ graph TD
40
+ A[Developers / CI] -->|Run env-drift-check| B(Engine)
41
+
42
+ subgraph Validation Process
43
+ B -->|1. Parse| C{.env.example}
44
+ B -->|2. Parse| D[Target .env]
45
+ B -->|3. Load Rules| E[envwise.config.json]
46
+
47
+ C --> F{Drift Detector}
48
+ D --> F
49
+
50
+ F -->|Detect Mismatches| G{Compare Keys & Values}
51
+ E -->|Schema Validation| G
52
+ end
53
+
54
+ G -->|Interactive Mode| H[Prompt UI: Auto-fix]
55
+ H -->|Update| D
56
+
57
+ G -->|Strict Mode| I[CI/CD Exit Code 1]
58
+ G -->|Report| J[Terminal Output]
59
+ ```
60
+
61
+ ---
62
+
63
+ ## 🚀 Features
25
64
 
26
- - **Interactive Mode**: Automatically detects missing keys and prompts you to fill them in directly via the CLI.
27
- - **Smart Schema Validation**: Enforce strict types including `email`, `url`, `number`, `boolean`, `enum`, and custom `regex`.
28
- - **Zero Config Setup**: Works out of the box. Add an optional `envwise.config.json` for advanced rules.
29
- - **CI/CD Ready**: Use `--strict` mode in your build pipeline to prevent deployments with missing variables.
65
+ - 🔍 **Environment Drift Detection**: Compares your local `.env` against the base `.env.example` to find missing or extra keys.
66
+ - 🛡️ **Extensive Schema Validation**: Enforce `string`, `number`, `boolean`, `enum`, `email`, `url`, and custom `regex` validations via `envwise.config.json`.
67
+ - 🪄 **Interactive Auto-fix**: A beautiful CLI wizard that prompts you for missing variables and writes them back to your `.env` file automatically.
68
+ - **Formatting Preservation**: Inherently preserves your original inline comments, empty lines, bespoke spacing, and absolute key ordering when writing updates to your target `.env` file.
69
+ - �🔄 **Multi-Environment Support**: Validate all `.env*` files in your project with the `--all` flag.
70
+ - 🚦 **CI/CD Ready**: Use `--strict` mode to fail the build if variables are missing or invalid, ensuring safe deployments.
30
71
 
31
- ## 📖 Documentation
72
+ ### How Does It Compare?
73
+
74
+ | Feature | `dotenv-safe` | `envalid` | **`env-drift-check`** |
75
+ | :--- | :---: | :---: | :---: |
76
+ | **Missing Keys Detection** | ✅ | ✅ | ✅ |
77
+ | **CLI Interactive Mode** | ❌ | ❌ | ✅ |
78
+ | **Schema Validation (Config)** | ❌ | ✅ (Code) | ✅ (JSON) |
79
+ | **Cross-Env File Check** | ❌ | ❌ | ✅ |
80
+ | **No Code Integration Needed**| ❌ | ❌ | ✅ |
81
+
82
+ *(env-drift-check works purely as a CLI tooling step, meaning you don't need to change your application's actual code to validate environment variables!)*
83
+
84
+ ---
32
85
 
33
- - [CLI Usage](./docs/CLI-Usage.md) - Detailed flags and command examples.
34
- - [Configuration](./docs/Configuration.md) - Advanced types and `envwise.config.json` schema.
35
- - [Programmatic API](./docs/API-Reference.md) - Integrating the validation engine into your code.
86
+ ## 📦 Installation
36
87
 
37
- ## Installation
88
+ Install `env-drift-check` as a development dependency:
38
89
 
39
90
  ```bash
40
- # Install as a dev dependency (Recommended)
41
91
  npm install --save-dev env-drift-check
42
-
43
- # OR install globally
44
- npm install -g env-drift-check
45
92
  ```
46
93
 
47
- ## Usage
94
+ Or run it directly using `npx` without installing:
48
95
 
49
- ### 1. Initialize (New Setup)
50
- Bootstrap your project by creating a configuration and an example environment file.
51
96
  ```bash
52
97
  npx env-drift-check init
53
98
  ```
54
99
 
55
- ### 2. Basic Check
56
- Compare your `.env` against the reference (default: `.env.example`).
100
+ ---
101
+
102
+ ## ⚡ Quick Start
103
+
104
+ ### 1. Initialize the Project
105
+
106
+ Bootstrap your repository with a default configuration and `.env.example`:
107
+
57
108
  ```bash
58
- npx env-drift-check
59
- # Specify a custom reference file
60
- npx env-drift-check --base .env.production
109
+ npx env-drift-check init
61
110
  ```
111
+ *Output:*
112
+ ```text
113
+ ✅ Created envwise.config.json
114
+ ✅ Created .env.example
62
115
 
63
- ### 3. Interactive Sync (The "Magic" Feature)
64
- If missing variables are found, launch the interactive wizard to fill them in without leaving your IDE.
116
+ Setup complete! Run 'npx env-drift-check -i' to sync your .env file.
117
+ ```
118
+
119
+ ### 2. Run an Interactive Check
120
+
121
+ If you just cloned a repo, check for missing environment variables and fill them in right from the terminal:
65
122
 
66
123
  ```bash
67
- npx env-drift-check --interactive
68
- # OR
69
124
  npx env-drift-check -i
70
125
  ```
71
126
 
@@ -75,39 +130,43 @@ Once completed, your `.env` file is automatically updated!
75
130
 
76
131
  ![Interactive success](https://github.com/shashi089/env-drift-check/raw/main/assets/env-drift-check-i-final.png)
77
132
 
78
- ### 4. CI/CD & Strict Mode
79
- Fail your build or test suite if environment variables are out of sync.
80
- ```bash
81
- npx env-drift-check --strict
82
- ```
83
-
84
133
  ---
85
134
 
86
- ## 🛠 Advanced Configuration
135
+ ## ⚙️ Configuration (`envwise.config.json`)
87
136
 
88
- Define validation rules in `envwise.config.json` to ensure data integrity across environments.
137
+ To unlock the full power of the schema validator, define rules in an `envwise.config.json` file at the root of your project.
138
+
139
+ ### Sample Configuration
89
140
 
90
141
  ```json
91
142
  {
92
143
  "baseEnv": ".env.example",
93
144
  "rules": {
94
- "PORT": {
95
- "type": "number",
96
- "min": 3000,
97
- "max": 9000,
98
- "description": "Port the server should listen on"
145
+ "PORT": {
146
+ "type": "number",
147
+ "min": 1024,
148
+ "max": 65535,
149
+ "description": "The port the HTTP server binds to"
150
+ },
151
+ "NODE_ENV": {
152
+ "type": "enum",
153
+ "values": ["development", "production", "test", "staging"]
99
154
  },
100
- "DATABASE_URL": {
155
+ "DEBUG_MODE": {
156
+ "type": "boolean",
157
+ "mustBeFalseIn": "production"
158
+ },
159
+ "DATABASE_URL": {
101
160
  "type": "url",
102
- "description": "Connection string for MongoDB/PostgreSQL"
161
+ "required": true
103
162
  },
104
163
  "ADMIN_EMAIL": {
105
- "type": "email",
106
- "required": true
164
+ "type": "email"
107
165
  },
108
- "ENVIRONMENT": {
109
- "type": "enum",
110
- "values": ["development", "production", "test"]
166
+ "API_KEY": {
167
+ "type": "regex",
168
+ "regex": "^sk_(test|live)_[0-9a-zA-Z]{24}$",
169
+ "description": "Stripe API Key format"
111
170
  }
112
171
  }
113
172
  }
@@ -115,26 +174,104 @@ Define validation rules in `envwise.config.json` to ensure data integrity across
115
174
 
116
175
  ### Supported Validation Types
117
176
 
118
- | Type | Description | Example Rule |
119
- | :--- | :--- | :--- |
120
- | `string` | Length validation | `{ "min": 5, "max": 20 }` |
121
- | `number` | Range validation | `{ "min": 1, "max": 100 }` |
122
- | `boolean` | Flag checks | `{ "mustBeFalseIn": ["production"] }` |
123
- | `enum` | Restricted values | `{ "values": ["v1", "v2"] }` |
124
- | `email` | Standard email format | `type: "email"` |
125
- | `url` | Valid URL/URI structure | `type: "url"` |
126
- | `regex` | Custom pattern matching | `{ "regex": "^sk_live_.*" }` |
177
+ | Type | Options | Description |
178
+ |---|---|---|
179
+ | `string` | `min`, `max` | Enforce string length bounds. |
180
+ | `number` | `min`, `max` | Enforce numeric value limits. |
181
+ | `boolean` | `mustBeFalseIn` | Ensure value is "true" or "false". Can conditionally reject "true" in specific environments (e.g. production safety). |
182
+ | `enum` | `values: []` | Restrict the variable to a specific set of allowed strings. |
183
+ | `email` | - | Validates against a standard email regex. |
184
+ | `url` | - | Validates standard URI formats. |
185
+ | `regex` | `regex` | Custom regular expression validation. |
186
+
187
+ *(All variables are `required: true` by default unless explicitly specified as `required: false` in their rule).*
188
+
189
+ ---
190
+
191
+ ## 💻 CLI Usage Examples
192
+
193
+ ### Drift Detection Example
194
+ Check the default `.env` file against the default `.env.example`:
195
+
196
+ ```bash
197
+ npx env-drift-check
198
+ ```
199
+ *Output Detail:*
200
+ ```text
201
+ 🚨 1 Mismatched Keys
202
+ PORT: Expected 3000, got 8080
203
+
204
+ ❌ 2 Validation Errors
205
+ DATABASE_URL: DATABASE_URL must be a valid URL
206
+ NODE_ENV: NODE_ENV must be one of: development, production
207
+ ```
208
+
209
+ ### Multi-Environment Verification
210
+ Check all `.env.development`, `.env.test`, `.env.production` files in parallel:
211
+
212
+ ```bash
213
+ npx env-drift-check --all
214
+ ```
215
+
216
+ ### CI/CD Pipeline Integration (Strict Mode)
217
+ Run the check in your GitHub Actions, GitLab CI, or pre-commit hook. Using `--strict` ensures the process exits with `code 1` on any error.
218
+
219
+ ```yaml
220
+ # .github/workflows/ci.yml
221
+ name: CI
222
+ on: [push, pull_request]
223
+
224
+ jobs:
225
+ validate-env:
226
+ runs-on: ubuntu-latest
227
+ steps:
228
+ - uses: actions/checkout@v3
229
+ # Assuming you have a .env.test you want to validate
230
+ - run: npx env-drift-check .env.test --strict
231
+ ```
232
+
233
+ ---
234
+
235
+ ## 🌟 Best Practices
236
+
237
+ 1. **Never commit `.env` or `.env.*` files!** Ensure they are in your `.gitignore`.
238
+ 2. **Always commit `.env.example`** and `envwise.config.json` as the source of truth for your team.
239
+ 3. **Use the Interactive Mode** (`-i`) locally during development and onboarding.
240
+ 4. **Use Strict Mode** (`--strict`) in your CI/CD pipeline to catch missing production variables early.
241
+ 5. **Add it to your `postinstall` or `prepare` script** in `package.json` to auto-prompt new developers:
242
+ ```json
243
+ "scripts": {
244
+ "prepare": "env-drift-check -i"
245
+ }
246
+ ```
247
+
248
+ ---
249
+
250
+ ## 🗺 Roadmap
251
+
252
+ - [x] Boolean conditional checks (`mustBeFalseIn`)
253
+ - [x] Interactive CLI prompts
254
+ - [x] Multi-file parsing (`--all`)
255
+ - [ ] **JSON Output Mode**: Provide `--format json` for reporting to integrate with other tooling pipelines.
256
+ - [ ] **Secret Scanning**: Add basic entropy checks to prevent weak local passwords from entering production variables.
257
+ - [ ] **Variable Deprecation**: Support marking keys as deprecated to gracefully remove them across teams.
258
+
259
+ ---
260
+
261
+ ## 🤝 Contributing
127
262
 
128
- ## Contributing
263
+ Contributions are always welcome!
129
264
 
130
- We welcome contributions! See the [issues](https://github.com/shashi089/env-drift-check/issues) for planned features or bug reports.
265
+ 1. Fork the project
266
+ 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
267
+ 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
268
+ 4. Push to the Branch (`git push origin feature/AmazingFeature`)
269
+ 5. Open a Pull Request
270
+
271
+ ---
131
272
 
132
- 1. Fork the repository.
133
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`).
134
- 3. Commit your changes (`git commit -m 'Add some amazing feature'`).
135
- 4. Push to the branch (`git push origin feature/amazing-feature`).
136
- 5. Open a Pull Request.
273
+ ## 📄 License
137
274
 
138
- ## License
275
+ Distributed under the MIT License. See `LICENSE` for more information.
139
276
 
140
- MIT © [Shashidhar Naik](https://github.com/shashi089)
277
+ > Built with ❤️ for better Developer Experience by [Shashidhar Naik](https://github.com/shashi089)
package/dist/cli.js CHANGED
@@ -46,10 +46,57 @@ program
46
46
  const newValues = await (0, interactive_1.interactiveSetup)(result.missing, baseEnv, config);
47
47
  // Merge new values into targetEnv
48
48
  const updatedEnv = { ...targetEnv, ...newValues };
49
- // Write back to file
50
- const newContent = Object.entries(updatedEnv)
51
- .map(([k, v]) => `${k}=${v}`)
52
- .join("\n");
49
+ // Write back to file preserving formatting
50
+ const rawContent = fs_1.default.readFileSync(targetPath, "utf-8");
51
+ const lines = rawContent.split(/\r?\n/);
52
+ const eol = rawContent.includes("\r\n") ? "\r\n" : "\n";
53
+ const updatedLines = [];
54
+ const keysToUpdate = { ...newValues };
55
+ for (const line of lines) {
56
+ const trimmed = line.trim();
57
+ if (!trimmed || trimmed.startsWith("#")) {
58
+ updatedLines.push(line);
59
+ continue;
60
+ }
61
+ const firstEq = line.indexOf("=");
62
+ if (firstEq !== -1) {
63
+ const key = line.slice(0, firstEq).trim();
64
+ if (key in keysToUpdate) {
65
+ const prefix = line.slice(0, firstEq + 1);
66
+ const rawValue = line.slice(firstEq + 1);
67
+ let suffix = "";
68
+ let inQuote = false;
69
+ let quoteChar = "";
70
+ for (let i = 0; i < rawValue.length; i++) {
71
+ const c = rawValue[i];
72
+ if ((c === '"' || c === "'") && !inQuote) {
73
+ inQuote = true;
74
+ quoteChar = c;
75
+ }
76
+ else if (c === quoteChar && inQuote) {
77
+ inQuote = false;
78
+ }
79
+ else if (c === '#' && !inQuote) {
80
+ // Keep spacing before the comment if possible
81
+ const spaceMatch = rawValue.slice(0, i).match(/\s+$/);
82
+ const spaces = spaceMatch ? spaceMatch[0] : " ";
83
+ suffix = spaces + rawValue.slice(i);
84
+ break;
85
+ }
86
+ }
87
+ updatedLines.push(`${prefix}${keysToUpdate[key]}${suffix}`);
88
+ delete keysToUpdate[key];
89
+ continue;
90
+ }
91
+ }
92
+ updatedLines.push(line);
93
+ }
94
+ if (Object.keys(keysToUpdate).length > 0) {
95
+ for (const [k, v] of Object.entries(keysToUpdate)) {
96
+ updatedLines.push(`${k}=${v}`);
97
+ }
98
+ }
99
+ const newContent = updatedLines.join(eol);
53
100
  fs_1.default.writeFileSync(targetPath, newContent);
54
101
  console.log(`\n ✅ Updated ${path_1.default.basename(targetPath)} with new values.`);
55
102
  // Re-check drift
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "env-drift-check",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Interactive .env synchronizer and validator. Detect environment drift, sync missing variables, and enforce schema validation for seamless developer onboarding.",
5
5
  "keywords": [
6
6
  "env",
@@ -1,2 +0,0 @@
1
- import { DriftResult } from "../types";
2
- export declare function applyFixes(base: Record<string, string>, target: Record<string, string>, result: DriftResult): Record<string, string>;
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.applyFixes = applyFixes;
4
- function applyFixes(base, target, result) {
5
- const fixedEnv = { ...target };
6
- // Add missing keys
7
- for (const key of result.missing) {
8
- if (base[key]) {
9
- fixedEnv[key] = base[key];
10
- }
11
- }
12
- // Fix mismatched values (base → target)
13
- for (const mismatch of result.mismatches) {
14
- if (mismatch.expected) {
15
- fixedEnv[mismatch.key] = mismatch.expected;
16
- }
17
- }
18
- return fixedEnv;
19
- }