@simplens/onboard 1.0.1 → 1.0.2
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 +331 -214
- package/dist/__tests__/env-config.test.d.ts +2 -0
- package/dist/__tests__/env-config.test.d.ts.map +1 -0
- package/dist/__tests__/env-config.test.js +23 -0
- package/dist/__tests__/env-config.test.js.map +1 -0
- package/dist/__tests__/infra-prompts.test.d.ts +2 -0
- package/dist/__tests__/infra-prompts.test.d.ts.map +1 -0
- package/dist/__tests__/infra-prompts.test.js +43 -0
- package/dist/__tests__/infra-prompts.test.js.map +1 -0
- package/dist/__tests__/infra.test.d.ts +2 -0
- package/dist/__tests__/infra.test.d.ts.map +1 -0
- package/dist/__tests__/infra.test.js +14 -0
- package/dist/__tests__/infra.test.js.map +1 -0
- package/dist/__tests__/nginx.test.d.ts +2 -0
- package/dist/__tests__/nginx.test.d.ts.map +1 -0
- package/dist/__tests__/nginx.test.js +16 -0
- package/dist/__tests__/nginx.test.js.map +1 -0
- package/dist/env-config.d.ts +27 -12
- package/dist/env-config.d.ts.map +1 -1
- package/dist/env-config.js +253 -128
- package/dist/env-config.js.map +1 -1
- package/dist/index.js +340 -69
- package/dist/index.js.map +1 -1
- package/dist/infra.d.ts +19 -8
- package/dist/infra.d.ts.map +1 -1
- package/dist/infra.js +267 -128
- package/dist/infra.js.map +1 -1
- package/dist/plugins.d.ts +5 -10
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +75 -44
- package/dist/plugins.js.map +1 -1
- package/dist/services.d.ts +1 -23
- package/dist/services.d.ts.map +1 -1
- package/dist/services.js +47 -62
- package/dist/services.js.map +1 -1
- package/dist/templates.d.ts +2 -1
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js +203 -191
- package/dist/templates.js.map +1 -1
- package/dist/types/domain.d.ts +2 -0
- package/dist/types/domain.d.ts.map +1 -1
- package/dist/ui.d.ts +45 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +93 -0
- package/dist/ui.js.map +1 -0
- package/dist/utils/logger.d.ts +1 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +32 -7
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +66 -2
- package/dist/utils.js.map +1 -1
- package/dist/validators.d.ts +1 -52
- package/dist/validators.d.ts.map +1 -1
- package/dist/validators.js +10 -57
- package/dist/validators.js.map +1 -1
- package/package.json +3 -5
- package/src/__tests__/env-config.test.ts +28 -0
- package/src/__tests__/errors.test.ts +187 -187
- package/src/__tests__/infra-prompts.test.ts +54 -0
- package/src/__tests__/infra.test.ts +15 -0
- package/src/__tests__/utils.test.ts +142 -142
- package/src/__tests__/validators.test.ts +195 -195
- package/src/config/constants.ts +86 -86
- package/src/config/index.ts +1 -1
- package/src/env-config.ts +455 -311
- package/src/index.ts +534 -202
- package/src/infra.ts +404 -245
- package/src/plugins.ts +221 -190
- package/src/services.ts +175 -190
- package/src/templates.ts +209 -196
- package/src/types/domain.ts +129 -127
- package/src/types/errors.ts +173 -173
- package/src/types/index.ts +2 -2
- package/src/ui.ts +91 -0
- package/src/utils/index.ts +1 -1
- package/src/utils/logger.ts +144 -118
- package/src/utils.ts +183 -105
- package/src/validators.ts +145 -192
- package/tsconfig.json +18 -18
- package/vitest.config.ts +22 -22
package/src/validators.ts
CHANGED
|
@@ -1,192 +1,145 @@
|
|
|
1
|
-
import { execa } from 'execa';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
*
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
* @param key - Environment variable name (e.g., 'MONGO_URI', 'PORT', 'API_KEY')
|
|
147
|
-
* @param value - Value to validate
|
|
148
|
-
* @returns `true` if valid, `false` otherwise
|
|
149
|
-
*
|
|
150
|
-
* @remarks
|
|
151
|
-
* Validation rules:
|
|
152
|
-
* - URLs: Must contain protocol (mongodb://, redis://)
|
|
153
|
-
* - Ports: Must be 1-65535
|
|
154
|
-
* - Secrets/Keys/Passwords: Must be at least 8 characters
|
|
155
|
-
*
|
|
156
|
-
* @example
|
|
157
|
-
* ```ts
|
|
158
|
-
* validateEnvValue('MONGO_URI', 'mongodb://localhost:27017'); // true
|
|
159
|
-
* validateEnvValue('PORT', '3000'); // true
|
|
160
|
-
* validateEnvValue('API_KEY', 'short'); // false (too short)
|
|
161
|
-
* ```
|
|
162
|
-
*/
|
|
163
|
-
export function validateEnvValue(key: string, value: string): boolean {
|
|
164
|
-
// URL validation
|
|
165
|
-
if (key.includes('URL') || key.includes('URI')) {
|
|
166
|
-
if (!value) return false;
|
|
167
|
-
// Basic URL format check
|
|
168
|
-
if (key === 'MONGO_URI' && !value.includes('mongodb://')) {
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
if (key === 'REDIS_URL' && !value.includes('redis://')) {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Port validation
|
|
177
|
-
if (key.includes('PORT')) {
|
|
178
|
-
const port = parseInt(value, 10);
|
|
179
|
-
if (isNaN(port) || port < VALIDATION.PORT_MIN || port > VALIDATION.PORT_MAX) {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// API Key validation (should not be empty for security)
|
|
185
|
-
if (key.includes('API_KEY') || key.includes('SECRET') || key.includes('PASSWORD')) {
|
|
186
|
-
if (!value || value.length < VALIDATION.MIN_PASSWORD_LENGTH) {
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return true;
|
|
192
|
-
}
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import { logSuccess, logWarning } from './utils.js';
|
|
3
|
+
import { spinner } from './ui.js';
|
|
4
|
+
import {
|
|
5
|
+
DockerNotInstalledError,
|
|
6
|
+
DockerNotRunningError,
|
|
7
|
+
DockerPermissionError,
|
|
8
|
+
} from './types/errors.js';
|
|
9
|
+
import { VALIDATION } from './config/constants.js';
|
|
10
|
+
|
|
11
|
+
export type OSType = 'windows' | 'linux' | 'darwin';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Checks if Docker is installed on the system by running `docker --version`.
|
|
15
|
+
*
|
|
16
|
+
* @throws {DockerNotInstalledError} When Docker is not found in PATH or not installed
|
|
17
|
+
*/
|
|
18
|
+
export async function checkDockerInstalled(): Promise<void> {
|
|
19
|
+
try {
|
|
20
|
+
await execa('docker', ['--version']);
|
|
21
|
+
} catch (error: unknown) {
|
|
22
|
+
throw new DockerNotInstalledError();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Checks if the Docker daemon is running by executing `docker ps`.
|
|
28
|
+
* Provides specific error types based on the failure reason.
|
|
29
|
+
*
|
|
30
|
+
* @throws {DockerPermissionError} When user lacks permissions to access Docker socket
|
|
31
|
+
* @throws {DockerNotRunningError} When Docker daemon is not running or unreachable
|
|
32
|
+
*/
|
|
33
|
+
export async function checkDockerRunning(): Promise<void> {
|
|
34
|
+
try {
|
|
35
|
+
await execa('docker', ['ps']);
|
|
36
|
+
} catch (error: unknown) {
|
|
37
|
+
const errorMessage = (error as Error).message?.toLowerCase() || '';
|
|
38
|
+
|
|
39
|
+
if (errorMessage.includes('permission denied') || errorMessage.includes('eacces')) {
|
|
40
|
+
throw new DockerPermissionError();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (errorMessage.includes('cannot connect') || errorMessage.includes('is the docker daemon running')) {
|
|
44
|
+
throw new DockerNotRunningError();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Generic docker error
|
|
48
|
+
throw new DockerNotRunningError();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Detects the operating system platform.
|
|
54
|
+
*
|
|
55
|
+
* @returns OS type: 'windows', 'darwin' (macOS), or 'linux'
|
|
56
|
+
* @note Defaults to 'linux' for unknown platforms
|
|
57
|
+
*/
|
|
58
|
+
export function detectOS(): OSType {
|
|
59
|
+
const platform = process.platform;
|
|
60
|
+
if (platform === 'win32') return 'windows';
|
|
61
|
+
if (platform === 'linux') return 'linux';
|
|
62
|
+
if (platform === 'darwin') return 'darwin';
|
|
63
|
+
return 'linux'; // Default fallback
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Validates all system prerequisites before starting the onboarding process.
|
|
68
|
+
* Checks Docker installation, daemon status, and detects the operating system.
|
|
69
|
+
* Uses clack spinners for visual feedback.
|
|
70
|
+
*
|
|
71
|
+
* @throws {DockerNotInstalledError} If Docker is not installed
|
|
72
|
+
* @throws {DockerNotRunningError} If Docker daemon is not running
|
|
73
|
+
* @throws {DockerPermissionError} If user lacks Docker permissions
|
|
74
|
+
*/
|
|
75
|
+
export async function validatePrerequisites(): Promise<void> {
|
|
76
|
+
logSuccess('Running prerequisite checks...');
|
|
77
|
+
|
|
78
|
+
// Check Docker installation
|
|
79
|
+
const s = spinner();
|
|
80
|
+
s.start('Checking Docker installation...');
|
|
81
|
+
try {
|
|
82
|
+
await checkDockerInstalled();
|
|
83
|
+
s.stop('Docker installation detected');
|
|
84
|
+
} catch (error) {
|
|
85
|
+
s.error('Docker installation check failed');
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Check Docker daemon
|
|
90
|
+
s.start('Checking Docker daemon status...');
|
|
91
|
+
try {
|
|
92
|
+
await checkDockerRunning();
|
|
93
|
+
s.stop('Docker daemon is running');
|
|
94
|
+
} catch (error) {
|
|
95
|
+
s.error('Docker daemon check failed');
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Detect OS
|
|
100
|
+
const os = detectOS();
|
|
101
|
+
logSuccess(`Detected OS: ${os}`);
|
|
102
|
+
|
|
103
|
+
if (os === 'linux') {
|
|
104
|
+
logWarning('Linux detected: You may need to provide your machine IP for infra services.');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Validates environment variable values based on the variable name/type.
|
|
110
|
+
* Performs format-specific validation for URLs, ports, and security credentials.
|
|
111
|
+
*
|
|
112
|
+
* @param key - Environment variable name (e.g., 'MONGO_URI', 'PORT', 'API_KEY')
|
|
113
|
+
* @param value - Value to validate
|
|
114
|
+
* @returns `true` if valid, `false` otherwise
|
|
115
|
+
*/
|
|
116
|
+
export function validateEnvValue(key: string, value: string): boolean {
|
|
117
|
+
// URL validation
|
|
118
|
+
if (key.includes('URL') || key.includes('URI')) {
|
|
119
|
+
if (!value) return false;
|
|
120
|
+
// Basic URL format check
|
|
121
|
+
if (key === 'MONGO_URI' && !value.includes('mongodb://')) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
if (key === 'REDIS_URL' && !value.includes('redis://')) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Port validation
|
|
130
|
+
if (key.includes('PORT')) {
|
|
131
|
+
const port = parseInt(value, 10);
|
|
132
|
+
if (isNaN(port) || port < VALIDATION.PORT_MIN || port > VALIDATION.PORT_MAX) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// API Key validation (should not be empty for security)
|
|
138
|
+
if (key.includes('API_KEY') || key.includes('SECRET') || key.includes('PASSWORD')) {
|
|
139
|
+
if (!value || value.length < VALIDATION.MIN_PASSWORD_LENGTH) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return true;
|
|
145
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "
|
|
5
|
-
"moduleResolution": "
|
|
6
|
-
"rootDir": "./src",
|
|
7
|
-
"outDir": "./dist",
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"resolveJsonModule": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"strict": true,
|
|
12
|
-
"skipLibCheck": true,
|
|
13
|
-
"declaration": true,
|
|
14
|
-
"declarationMap": true,
|
|
15
|
-
"sourceMap": true
|
|
16
|
-
},
|
|
17
|
-
"include": ["src/**/*"],
|
|
18
|
-
"exclude": ["node_modules", "dist"]
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "Node16",
|
|
5
|
+
"moduleResolution": "Node16",
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
19
|
}
|
package/vitest.config.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { defineConfig } from 'vitest/config';
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
test: {
|
|
5
|
-
globals: true,
|
|
6
|
-
environment: 'node',
|
|
7
|
-
include: ['src/**/*.{test,spec}.{js,ts}'],
|
|
8
|
-
exclude: ['node_modules/**', 'dist/**'],
|
|
9
|
-
coverage: {
|
|
10
|
-
provider: 'v8',
|
|
11
|
-
reporter: ['text', 'json', 'html'],
|
|
12
|
-
exclude: [
|
|
13
|
-
'node_modules/**',
|
|
14
|
-
'dist/**',
|
|
15
|
-
'**/*.test.ts',
|
|
16
|
-
'**/*.spec.ts',
|
|
17
|
-
'src/templates.ts', // Large constant file
|
|
18
|
-
],
|
|
19
|
-
},
|
|
20
|
-
testTimeout: 10000,
|
|
21
|
-
},
|
|
22
|
-
});
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
environment: 'node',
|
|
7
|
+
include: ['src/**/*.{test,spec}.{js,ts}'],
|
|
8
|
+
exclude: ['node_modules/**', 'dist/**'],
|
|
9
|
+
coverage: {
|
|
10
|
+
provider: 'v8',
|
|
11
|
+
reporter: ['text', 'json', 'html'],
|
|
12
|
+
exclude: [
|
|
13
|
+
'node_modules/**',
|
|
14
|
+
'dist/**',
|
|
15
|
+
'**/*.test.ts',
|
|
16
|
+
'**/*.spec.ts',
|
|
17
|
+
'src/templates.ts', // Large constant file
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
testTimeout: 10000,
|
|
21
|
+
},
|
|
22
|
+
});
|