safelaunch 1.0.5 → 1.0.7

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
@@ -2,50 +2,79 @@
2
2
 
3
3
  > Catch what breaks production before it breaks.
4
4
 
5
- safelaunch validates your local environment against a required environment contract before you push to production. No more missing variables. No more runtime mismatches. No more production surprises.
5
+ safelaunch is a comprehensive environment validator for JavaScript projects. Run it before every push to catch everything that will break production.
6
+
7
+ Works with Node.js, Next.js, Vite, and Create React App projects. Automatically detects your project type and runs the right checks.
6
8
 
7
9
  ## Install
8
10
 
9
11
  npm install -g safelaunch
10
12
 
11
- ## Quick Start
12
-
13
- **Step 1: Generate your environment manifest automatically**
13
+ ## Two commands. That is it.
14
14
 
15
- Run this in your project folder:
15
+ **Step 1: Generate your environment manifest**
16
16
 
17
17
  safelaunch init
18
18
 
19
- safelaunch scans your entire codebase, finds every environment variable your app uses, and generates env.manifest.json automatically.
19
+ Scans your entire codebase, finds every environment variable your app uses, and generates env.manifest.json automatically. Works with process.env and import.meta.env.
20
20
 
21
- **Step 2: Validate before you push**
21
+ **Step 2: Validate before every push**
22
22
 
23
23
  safelaunch validate
24
24
 
25
- **Step 3: See exactly what will break**
25
+ ## What safelaunch checks
26
+
27
+ safelaunch validate runs 7 checks:
28
+
29
+ 1. Missing required environment variables
30
+ 2. Empty required environment variables
31
+ 3. Runtime version mismatch (Node version)
32
+ 4. Duplicate variables in .env
33
+ 5. Dependencies not installed
34
+ 6. Dependency drift (in package.json but not installed)
35
+ 7. Variables in .env.example but missing from .env
36
+
37
+ ## Example output
38
+
39
+ Running safelaunch...
40
+
41
+ project type: Node.js
26
42
 
27
- Running safelaunch validate gives you:
43
+ ⚠️ RUNTIME MISMATCH
28
44
 
29
- MISSING VARIABLES (2 found)
45
+ Node required: 18
46
+ Node actual: 20
30
47
 
31
- DATABASE_URL required but missing from .env
32
- REDIS_URL required but missing from .env
48
+ ⚠️ DEPENDENCY DRIFT (1 found)
49
+
50
+ express in package.json but not installed
51
+
52
+ ❌ EMPTY VARIABLES (1 found)
53
+
54
+ DATABASE_URL required but empty in .env
55
+
56
+ ❌ MISSING VARIABLES (1 found)
57
+
58
+ REDIS_URL required but missing from .env
33
59
 
34
60
  ✅ PASSING (1)
35
61
 
36
62
  API_KEY present
37
63
 
38
64
  Your environment is not ready for production.
39
- Fix the issues above and run safelaunch again.
40
65
 
41
- ## Commands
66
+ ## Supported project types
67
+
68
+ safelaunch automatically detects your project type.
42
69
 
43
- safelaunch init scan project and generate env.manifest.json automatically
44
- safelaunch validate validate your .env against the manifest
70
+ - Node.js scans process.env
71
+ - Next.js scans process.env
72
+ - Vite scans import.meta.env
73
+ - React CRA scans process.env REACT_APP_ variables
45
74
 
46
75
  ## CI Integration
47
76
 
48
- Add this to your GitHub Actions workflow to block deployments automatically:
77
+ Add this to your GitHub Actions workflow:
49
78
 
50
79
  - name: Install safelaunch
51
80
  run: npm install -g safelaunch
@@ -53,6 +82,10 @@ Add this to your GitHub Actions workflow to block deployments automatically:
53
82
  - name: Validate environment
54
83
  run: safelaunch validate
55
84
 
85
+ Blocks deployments automatically if any check fails.
86
+
56
87
  ## Built by Orches
57
88
 
58
- Backend Reliability Infrastructure.
89
+ Deployment Reliability Infrastructure.
90
+ GitHub: https://github.com/karthicedric7-cloud/safelaunch
91
+ VS Code: https://marketplace.visualstudio.com/items?itemName=Orches.deploycheck-vscode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "safelaunch",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Backend Reliability Infrastructure - catch what breaks production before it breaks",
5
5
  "main": "index.js",
6
6
  "bin": {
package/src/init.js CHANGED
@@ -1,17 +1,35 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
 
4
- function scanFiles(dir, extensions, found = new Set()) {
4
+ function detectProjectType(cwd) {
5
+ if (fs.existsSync(path.join(cwd, 'vite.config.js')) ||
6
+ fs.existsSync(path.join(cwd, 'vite.config.ts'))) {
7
+ return 'vite';
8
+ }
9
+ if (fs.existsSync(path.join(cwd, 'next.config.js')) ||
10
+ fs.existsSync(path.join(cwd, 'next.config.ts'))) {
11
+ return 'next';
12
+ }
13
+ const packagePath = path.join(cwd, 'package.json');
14
+ if (fs.existsSync(packagePath)) {
15
+ const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
16
+ const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies);
17
+ if (deps['react-scripts']) return 'cra';
18
+ }
19
+ return 'node';
20
+ }
21
+
22
+ function scanFiles(dir, extensions, pattern, found = new Set()) {
5
23
  const items = fs.readdirSync(dir);
6
24
  for (const item of items) {
7
25
  if (item === 'node_modules' || item === '.git') continue;
8
26
  const full = path.join(dir, item);
9
27
  const stat = fs.statSync(full);
10
28
  if (stat.isDirectory()) {
11
- scanFiles(full, extensions, found);
29
+ scanFiles(full, extensions, pattern, found);
12
30
  } else if (extensions.some(ext => item.endsWith(ext))) {
13
31
  const content = fs.readFileSync(full, 'utf8');
14
- const matches = content.matchAll(/process\.env\.([A-Z_][A-Z0-9_]*)/g);
32
+ const matches = content.matchAll(pattern);
15
33
  for (const match of matches) {
16
34
  found.add(match[1]);
17
35
  }
@@ -22,28 +40,58 @@ function scanFiles(dir, extensions, found = new Set()) {
22
40
 
23
41
  function init() {
24
42
  console.log('\nscanning project for environment variables...\n');
43
+
25
44
  const cwd = process.cwd();
26
- const extensions = ['.js', '.ts', '.jsx', '.tsx'];
27
- const found = scanFiles(cwd, extensions);
45
+ const manifestPath = path.join(cwd, 'env.manifest.json');
46
+
47
+ if (fs.existsSync(manifestPath)) {
48
+ console.log('env.manifest.json already exists. delete it first.\n');
49
+ return;
50
+ }
51
+
52
+ const projectType = detectProjectType(cwd);
53
+ const extensions = ['.js', '.ts', '.jsx', '.tsx', '.vue', '.svelte'];
54
+
55
+ let pattern;
56
+ let typeLabel;
57
+
58
+ if (projectType === 'vite') {
59
+ pattern = /import\.meta\.env\.([A-Z_][A-Z0-9_]*)/g;
60
+ typeLabel = 'Vite';
61
+ } else if (projectType === 'cra') {
62
+ pattern = /process\.env\.(REACT_APP_[A-Z0-9_]*)/g;
63
+ typeLabel = 'Create React App';
64
+ } else if (projectType === 'next') {
65
+ pattern = /process\.env\.([A-Z_][A-Z0-9_]*)/g;
66
+ typeLabel = 'Next.js';
67
+ } else {
68
+ pattern = /process\.env\.([A-Z_][A-Z0-9_]*)/g;
69
+ typeLabel = 'Node.js';
70
+ }
71
+
72
+ console.log('detected project type: ' + typeLabel + '\n');
73
+
74
+ const found = scanFiles(cwd, extensions, pattern);
75
+
28
76
  if (found.size === 0) {
29
- console.log('no process.env references found.\n');
77
+ console.log('no environment variables found in your project.\n');
30
78
  return;
31
79
  }
80
+
32
81
  const variables = {};
33
82
  for (const key of [...found].sort()) {
34
83
  variables[key] = { required: true, description: '' };
35
84
  }
85
+
36
86
  const manifest = {
37
87
  version: '1',
88
+ projectType: projectType,
38
89
  runtime: { node: process.version.replace('v', '').split('.')[0] },
39
90
  variables
40
91
  };
41
- const manifestPath = path.join(cwd, 'env.manifest.json');
42
- if (fs.existsSync(manifestPath)) {
43
- console.log('env.manifest.json already exists. delete it first.\n');
44
- return;
45
- }
92
+
46
93
  fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
94
+
47
95
  console.log('found ' + found.size + ' environment variables:\n');
48
96
  for (const key of [...found].sort()) {
49
97
  console.log(' ' + key);
package/src/validate.js CHANGED
@@ -1,6 +1,24 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
 
4
+ function detectProjectType(cwd) {
5
+ if (fs.existsSync(path.join(cwd, 'vite.config.js')) ||
6
+ fs.existsSync(path.join(cwd, 'vite.config.ts'))) {
7
+ return 'vite';
8
+ }
9
+ if (fs.existsSync(path.join(cwd, 'next.config.js')) ||
10
+ fs.existsSync(path.join(cwd, 'next.config.ts'))) {
11
+ return 'next';
12
+ }
13
+ const packagePath = path.join(cwd, 'package.json');
14
+ if (fs.existsSync(packagePath)) {
15
+ const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
16
+ const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies);
17
+ if (deps['react-scripts']) return 'cra';
18
+ }
19
+ return 'node';
20
+ }
21
+
4
22
  function readManifest() {
5
23
  const manifestPath = path.join(process.cwd(), 'env.manifest.json');
6
24
  if (!fs.existsSync(manifestPath)) {
@@ -80,9 +98,14 @@ function checkDependencyDrift() {
80
98
  function validate() {
81
99
  console.log('\nRunning safelaunch...\n');
82
100
 
101
+ const cwd = process.cwd();
83
102
  const manifest = readManifest();
84
103
  const { envVars, duplicates } = readEnv();
85
104
 
105
+ const projectType = manifest.projectType || detectProjectType(cwd);
106
+ const typeLabels = { vite: 'Vite', next: 'Next.js', cra: 'Create React App', node: 'Node.js' };
107
+ console.log('project type: ' + (typeLabels[projectType] || 'Node.js') + '\n');
108
+
86
109
  const missing = [];
87
110
  const empty = [];
88
111
  const passing = [];