@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.
Files changed (82) hide show
  1. package/README.md +331 -214
  2. package/dist/__tests__/env-config.test.d.ts +2 -0
  3. package/dist/__tests__/env-config.test.d.ts.map +1 -0
  4. package/dist/__tests__/env-config.test.js +23 -0
  5. package/dist/__tests__/env-config.test.js.map +1 -0
  6. package/dist/__tests__/infra-prompts.test.d.ts +2 -0
  7. package/dist/__tests__/infra-prompts.test.d.ts.map +1 -0
  8. package/dist/__tests__/infra-prompts.test.js +43 -0
  9. package/dist/__tests__/infra-prompts.test.js.map +1 -0
  10. package/dist/__tests__/infra.test.d.ts +2 -0
  11. package/dist/__tests__/infra.test.d.ts.map +1 -0
  12. package/dist/__tests__/infra.test.js +14 -0
  13. package/dist/__tests__/infra.test.js.map +1 -0
  14. package/dist/__tests__/nginx.test.d.ts +2 -0
  15. package/dist/__tests__/nginx.test.d.ts.map +1 -0
  16. package/dist/__tests__/nginx.test.js +16 -0
  17. package/dist/__tests__/nginx.test.js.map +1 -0
  18. package/dist/env-config.d.ts +27 -12
  19. package/dist/env-config.d.ts.map +1 -1
  20. package/dist/env-config.js +253 -128
  21. package/dist/env-config.js.map +1 -1
  22. package/dist/index.js +340 -69
  23. package/dist/index.js.map +1 -1
  24. package/dist/infra.d.ts +19 -8
  25. package/dist/infra.d.ts.map +1 -1
  26. package/dist/infra.js +267 -128
  27. package/dist/infra.js.map +1 -1
  28. package/dist/plugins.d.ts +5 -10
  29. package/dist/plugins.d.ts.map +1 -1
  30. package/dist/plugins.js +75 -44
  31. package/dist/plugins.js.map +1 -1
  32. package/dist/services.d.ts +1 -23
  33. package/dist/services.d.ts.map +1 -1
  34. package/dist/services.js +47 -62
  35. package/dist/services.js.map +1 -1
  36. package/dist/templates.d.ts +2 -1
  37. package/dist/templates.d.ts.map +1 -1
  38. package/dist/templates.js +203 -191
  39. package/dist/templates.js.map +1 -1
  40. package/dist/types/domain.d.ts +2 -0
  41. package/dist/types/domain.d.ts.map +1 -1
  42. package/dist/ui.d.ts +45 -0
  43. package/dist/ui.d.ts.map +1 -0
  44. package/dist/ui.js +93 -0
  45. package/dist/ui.js.map +1 -0
  46. package/dist/utils/logger.d.ts +1 -0
  47. package/dist/utils/logger.d.ts.map +1 -1
  48. package/dist/utils/logger.js +32 -7
  49. package/dist/utils/logger.js.map +1 -1
  50. package/dist/utils.d.ts +8 -0
  51. package/dist/utils.d.ts.map +1 -1
  52. package/dist/utils.js +66 -2
  53. package/dist/utils.js.map +1 -1
  54. package/dist/validators.d.ts +1 -52
  55. package/dist/validators.d.ts.map +1 -1
  56. package/dist/validators.js +10 -57
  57. package/dist/validators.js.map +1 -1
  58. package/package.json +3 -5
  59. package/src/__tests__/env-config.test.ts +28 -0
  60. package/src/__tests__/errors.test.ts +187 -187
  61. package/src/__tests__/infra-prompts.test.ts +54 -0
  62. package/src/__tests__/infra.test.ts +15 -0
  63. package/src/__tests__/utils.test.ts +142 -142
  64. package/src/__tests__/validators.test.ts +195 -195
  65. package/src/config/constants.ts +86 -86
  66. package/src/config/index.ts +1 -1
  67. package/src/env-config.ts +455 -311
  68. package/src/index.ts +534 -202
  69. package/src/infra.ts +404 -245
  70. package/src/plugins.ts +221 -190
  71. package/src/services.ts +175 -190
  72. package/src/templates.ts +209 -196
  73. package/src/types/domain.ts +129 -127
  74. package/src/types/errors.ts +173 -173
  75. package/src/types/index.ts +2 -2
  76. package/src/ui.ts +91 -0
  77. package/src/utils/index.ts +1 -1
  78. package/src/utils/logger.ts +144 -118
  79. package/src/utils.ts +183 -105
  80. package/src/validators.ts +145 -192
  81. package/tsconfig.json +18 -18
  82. package/vitest.config.ts +22 -22
@@ -1,195 +1,195 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import {
3
- checkDockerInstalled,
4
- checkDockerRunning,
5
- detectOS,
6
- validatePrerequisites,
7
- validateEnvValue
8
- } from '../validators.js';
9
- import {
10
- DockerNotInstalledError,
11
- DockerNotRunningError,
12
- DockerPermissionError
13
- } from '../types/errors.js';
14
-
15
- // Mock execa
16
- vi.mock('execa', () => ({
17
- execa: vi.fn(),
18
- }));
19
-
20
- // Mock utils
21
- vi.mock('../utils.js', () => ({
22
- logError: vi.fn(),
23
- logSuccess: vi.fn(),
24
- logWarning: vi.fn(),
25
- }));
26
-
27
- import { execa } from 'execa';
28
-
29
- describe('validators', () => {
30
- beforeEach(() => {
31
- vi.clearAllMocks();
32
- });
33
-
34
- describe('checkDockerInstalled', () => {
35
- it('should not throw when docker is installed', async () => {
36
- vi.mocked(execa).mockResolvedValueOnce({
37
- stdout: 'Docker version 24.0.0',
38
- stderr: '',
39
- } as any);
40
-
41
- await expect(checkDockerInstalled()).resolves.not.toThrow();
42
- });
43
-
44
- it('should throw DockerNotInstalledError when docker is not installed', async () => {
45
- vi.mocked(execa).mockRejectedValueOnce(new Error('Command not found'));
46
-
47
- await expect(checkDockerInstalled()).rejects.toThrow(DockerNotInstalledError);
48
- });
49
- });
50
-
51
- describe('checkDockerRunning', () => {
52
- it('should not throw when docker daemon is running', async () => {
53
- vi.mocked(execa).mockResolvedValueOnce({
54
- stdout: 'CONTAINER ID IMAGE',
55
- stderr: '',
56
- } as any);
57
-
58
- await expect(checkDockerRunning()).resolves.not.toThrow();
59
- });
60
-
61
- it('should throw DockerPermissionError on permission denied', async () => {
62
- const error = new Error('permission denied while trying to connect');
63
- vi.mocked(execa).mockRejectedValueOnce(error);
64
-
65
- await expect(checkDockerRunning()).rejects.toThrow(DockerPermissionError);
66
- });
67
-
68
- it('should throw DockerNotRunningError when daemon is not running', async () => {
69
- const error = new Error('Cannot connect to the Docker daemon');
70
- vi.mocked(execa).mockRejectedValueOnce(error);
71
-
72
- await expect(checkDockerRunning()).rejects.toThrow(DockerNotRunningError);
73
- });
74
-
75
- it('should throw DockerNotRunningError on generic docker error', async () => {
76
- const error = new Error('Some other docker error');
77
- vi.mocked(execa).mockRejectedValueOnce(error);
78
-
79
- await expect(checkDockerRunning()).rejects.toThrow(DockerNotRunningError);
80
- });
81
- });
82
-
83
- describe('detectOS', () => {
84
- const originalPlatform = process.platform;
85
-
86
- afterEach(() => {
87
- Object.defineProperty(process, 'platform', {
88
- value: originalPlatform
89
- });
90
- });
91
-
92
- it('should detect Windows', () => {
93
- Object.defineProperty(process, 'platform', {
94
- value: 'win32'
95
- });
96
- expect(detectOS()).toBe('windows');
97
- });
98
-
99
- it('should detect macOS', () => {
100
- Object.defineProperty(process, 'platform', {
101
- value: 'darwin'
102
- });
103
- expect(detectOS()).toBe('darwin');
104
- });
105
-
106
- it('should detect Linux', () => {
107
- Object.defineProperty(process, 'platform', {
108
- value: 'linux'
109
- });
110
- expect(detectOS()).toBe('linux');
111
- });
112
-
113
- it('should default to Linux for unknown platforms', () => {
114
- Object.defineProperty(process, 'platform', {
115
- value: 'freebsd'
116
- });
117
- expect(detectOS()).toBe('linux');
118
- });
119
- });
120
-
121
- describe('validateEnvValue', () => {
122
- describe('URL validation', () => {
123
- it('should reject empty MongoDB URI', () => {
124
- expect(validateEnvValue('MONGO_URI', '')).toBe(false);
125
- });
126
-
127
- it('should reject MongoDB URI without proper format', () => {
128
- expect(validateEnvValue('MONGO_URI', 'localhost:27017')).toBe(false);
129
- });
130
-
131
- it('should accept valid MongoDB URI', () => {
132
- expect(validateEnvValue('MONGO_URI', 'mongodb://localhost:27017')).toBe(true);
133
- });
134
-
135
- it('should reject Redis URL without proper format', () => {
136
- expect(validateEnvValue('REDIS_URL', 'localhost:6379')).toBe(false);
137
- });
138
-
139
- it('should accept valid Redis URL', () => {
140
- expect(validateEnvValue('REDIS_URL', 'redis://localhost:6379')).toBe(true);
141
- });
142
- });
143
-
144
- describe('Port validation', () => {
145
- it('should reject negative ports', () => {
146
- expect(validateEnvValue('PORT', '-1')).toBe(false);
147
- });
148
-
149
- it('should reject zero port', () => {
150
- expect(validateEnvValue('PORT', '0')).toBe(false);
151
- });
152
-
153
- it('should reject ports > 65535', () => {
154
- expect(validateEnvValue('PORT', '65536')).toBe(false);
155
- });
156
-
157
- it('should accept valid ports', () => {
158
- expect(validateEnvValue('PORT', '3000')).toBe(true);
159
- expect(validateEnvValue('API_PORT', '8080')).toBe(true);
160
- });
161
-
162
- it('should reject non-numeric ports', () => {
163
- expect(validateEnvValue('PORT', 'abc')).toBe(false);
164
- });
165
- });
166
-
167
- describe('Security fields validation', () => {
168
- it('should reject short API keys', () => {
169
- expect(validateEnvValue('API_KEY', 'short')).toBe(false);
170
- });
171
-
172
- it('should reject short passwords', () => {
173
- expect(validateEnvValue('PASSWORD', '1234567')).toBe(false);
174
- });
175
-
176
- it('should reject short secrets', () => {
177
- expect(validateEnvValue('AUTH_SECRET', 'abc')).toBe(false);
178
- });
179
-
180
- it('should accept API keys with 8+ characters', () => {
181
- expect(validateEnvValue('API_KEY', 'verylongapikey123')).toBe(true);
182
- });
183
-
184
- it('should accept passwords with 8+ characters', () => {
185
- expect(validateEnvValue('PASSWORD', 'password123')).toBe(true);
186
- });
187
- });
188
-
189
- describe('General validation', () => {
190
- it('should accept valid non-special values', () => {
191
- expect(validateEnvValue('SOME_VAR', 'some-value')).toBe(true);
192
- });
193
- });
194
- });
195
- });
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import {
3
+ checkDockerInstalled,
4
+ checkDockerRunning,
5
+ detectOS,
6
+ validatePrerequisites,
7
+ validateEnvValue
8
+ } from '../validators.js';
9
+ import {
10
+ DockerNotInstalledError,
11
+ DockerNotRunningError,
12
+ DockerPermissionError
13
+ } from '../types/errors.js';
14
+
15
+ // Mock execa
16
+ vi.mock('execa', () => ({
17
+ execa: vi.fn(),
18
+ }));
19
+
20
+ // Mock utils
21
+ vi.mock('../utils.js', () => ({
22
+ logError: vi.fn(),
23
+ logSuccess: vi.fn(),
24
+ logWarning: vi.fn(),
25
+ }));
26
+
27
+ import { execa } from 'execa';
28
+
29
+ describe('validators', () => {
30
+ beforeEach(() => {
31
+ vi.clearAllMocks();
32
+ });
33
+
34
+ describe('checkDockerInstalled', () => {
35
+ it('should not throw when docker is installed', async () => {
36
+ vi.mocked(execa).mockResolvedValueOnce({
37
+ stdout: 'Docker version 24.0.0',
38
+ stderr: '',
39
+ } as any);
40
+
41
+ await expect(checkDockerInstalled()).resolves.not.toThrow();
42
+ });
43
+
44
+ it('should throw DockerNotInstalledError when docker is not installed', async () => {
45
+ vi.mocked(execa).mockRejectedValueOnce(new Error('Command not found'));
46
+
47
+ await expect(checkDockerInstalled()).rejects.toThrow(DockerNotInstalledError);
48
+ });
49
+ });
50
+
51
+ describe('checkDockerRunning', () => {
52
+ it('should not throw when docker daemon is running', async () => {
53
+ vi.mocked(execa).mockResolvedValueOnce({
54
+ stdout: 'CONTAINER ID IMAGE',
55
+ stderr: '',
56
+ } as any);
57
+
58
+ await expect(checkDockerRunning()).resolves.not.toThrow();
59
+ });
60
+
61
+ it('should throw DockerPermissionError on permission denied', async () => {
62
+ const error = new Error('permission denied while trying to connect');
63
+ vi.mocked(execa).mockRejectedValueOnce(error);
64
+
65
+ await expect(checkDockerRunning()).rejects.toThrow(DockerPermissionError);
66
+ });
67
+
68
+ it('should throw DockerNotRunningError when daemon is not running', async () => {
69
+ const error = new Error('Cannot connect to the Docker daemon');
70
+ vi.mocked(execa).mockRejectedValueOnce(error);
71
+
72
+ await expect(checkDockerRunning()).rejects.toThrow(DockerNotRunningError);
73
+ });
74
+
75
+ it('should throw DockerNotRunningError on generic docker error', async () => {
76
+ const error = new Error('Some other docker error');
77
+ vi.mocked(execa).mockRejectedValueOnce(error);
78
+
79
+ await expect(checkDockerRunning()).rejects.toThrow(DockerNotRunningError);
80
+ });
81
+ });
82
+
83
+ describe('detectOS', () => {
84
+ const originalPlatform = process.platform;
85
+
86
+ afterEach(() => {
87
+ Object.defineProperty(process, 'platform', {
88
+ value: originalPlatform
89
+ });
90
+ });
91
+
92
+ it('should detect Windows', () => {
93
+ Object.defineProperty(process, 'platform', {
94
+ value: 'win32'
95
+ });
96
+ expect(detectOS()).toBe('windows');
97
+ });
98
+
99
+ it('should detect macOS', () => {
100
+ Object.defineProperty(process, 'platform', {
101
+ value: 'darwin'
102
+ });
103
+ expect(detectOS()).toBe('darwin');
104
+ });
105
+
106
+ it('should detect Linux', () => {
107
+ Object.defineProperty(process, 'platform', {
108
+ value: 'linux'
109
+ });
110
+ expect(detectOS()).toBe('linux');
111
+ });
112
+
113
+ it('should default to Linux for unknown platforms', () => {
114
+ Object.defineProperty(process, 'platform', {
115
+ value: 'freebsd'
116
+ });
117
+ expect(detectOS()).toBe('linux');
118
+ });
119
+ });
120
+
121
+ describe('validateEnvValue', () => {
122
+ describe('URL validation', () => {
123
+ it('should reject empty MongoDB URI', () => {
124
+ expect(validateEnvValue('MONGO_URI', '')).toBe(false);
125
+ });
126
+
127
+ it('should reject MongoDB URI without proper format', () => {
128
+ expect(validateEnvValue('MONGO_URI', 'localhost:27017')).toBe(false);
129
+ });
130
+
131
+ it('should accept valid MongoDB URI', () => {
132
+ expect(validateEnvValue('MONGO_URI', 'mongodb://localhost:27017')).toBe(true);
133
+ });
134
+
135
+ it('should reject Redis URL without proper format', () => {
136
+ expect(validateEnvValue('REDIS_URL', 'localhost:6379')).toBe(false);
137
+ });
138
+
139
+ it('should accept valid Redis URL', () => {
140
+ expect(validateEnvValue('REDIS_URL', 'redis://localhost:6379')).toBe(true);
141
+ });
142
+ });
143
+
144
+ describe('Port validation', () => {
145
+ it('should reject negative ports', () => {
146
+ expect(validateEnvValue('PORT', '-1')).toBe(false);
147
+ });
148
+
149
+ it('should reject zero port', () => {
150
+ expect(validateEnvValue('PORT', '0')).toBe(false);
151
+ });
152
+
153
+ it('should reject ports > 65535', () => {
154
+ expect(validateEnvValue('PORT', '65536')).toBe(false);
155
+ });
156
+
157
+ it('should accept valid ports', () => {
158
+ expect(validateEnvValue('PORT', '3000')).toBe(true);
159
+ expect(validateEnvValue('API_PORT', '8080')).toBe(true);
160
+ });
161
+
162
+ it('should reject non-numeric ports', () => {
163
+ expect(validateEnvValue('PORT', 'abc')).toBe(false);
164
+ });
165
+ });
166
+
167
+ describe('Security fields validation', () => {
168
+ it('should reject short API keys', () => {
169
+ expect(validateEnvValue('API_KEY', 'short')).toBe(false);
170
+ });
171
+
172
+ it('should reject short passwords', () => {
173
+ expect(validateEnvValue('PASSWORD', '1234567')).toBe(false);
174
+ });
175
+
176
+ it('should reject short secrets', () => {
177
+ expect(validateEnvValue('AUTH_SECRET', 'abc')).toBe(false);
178
+ });
179
+
180
+ it('should accept API keys with 8+ characters', () => {
181
+ expect(validateEnvValue('API_KEY', 'verylongapikey123')).toBe(true);
182
+ });
183
+
184
+ it('should accept passwords with 8+ characters', () => {
185
+ expect(validateEnvValue('PASSWORD', 'password123')).toBe(true);
186
+ });
187
+ });
188
+
189
+ describe('General validation', () => {
190
+ it('should accept valid non-special values', () => {
191
+ expect(validateEnvValue('SOME_VAR', 'some-value')).toBe(true);
192
+ });
193
+ });
194
+ });
195
+ });
@@ -1,86 +1,86 @@
1
- /**
2
- * Application configuration constants
3
- */
4
-
5
- /**
6
- * Service port mappings
7
- */
8
- export const SERVICE_PORTS = {
9
- API: 3000,
10
- DASHBOARD: 3002,
11
- GRAFANA: 3001,
12
- KAFKA_UI: 8080,
13
- MONGO: 27017,
14
- KAFKA: 9092,
15
- REDIS: 6379,
16
- LOKI: 3100,
17
- } as const;
18
-
19
- /**
20
- * Health check configuration
21
- */
22
- export const HEALTH_CHECK = {
23
- MAX_RETRIES: 30,
24
- RETRY_DELAY_MS: 2000,
25
- TIMEOUT_MS: 60000,
26
- } as const;
27
-
28
- /**
29
- * Docker command timeouts
30
- */
31
- export const DOCKER_TIMEOUTS = {
32
- START_MS: 30000,
33
- STOP_MS: 15000,
34
- BUILD_MS: 300000,
35
- } as const;
36
-
37
- /**
38
- * Critical environment variables that always need user input
39
- */
40
- export const CRITICAL_ENV_KEYS = [
41
- 'NS_API_KEY',
42
- 'MONGO_URI',
43
- 'BROKERS',
44
- 'REDIS_URL',
45
- 'AUTH_SECRET',
46
- 'ADMIN_PASSWORD',
47
- 'LOKI_URL',
48
- ];
49
-
50
- /**
51
- * Validation constraints
52
- */
53
- export const VALIDATION = {
54
- MIN_PASSWORD_LENGTH: 8,
55
- MIN_API_KEY_LENGTH: 8,
56
- PORT_MIN: 1,
57
- PORT_MAX: 65535,
58
- } as const;
59
-
60
- /**
61
- * File paths
62
- */
63
- export const FILES = {
64
- DOCKER_COMPOSE_INFRA: 'docker-compose.infra.yaml',
65
- DOCKER_COMPOSE_APP: 'docker-compose.yaml',
66
- ENV_FILE: '.env',
67
- CONFIG_FILE: 'simplens.config.yaml',
68
- ERROR_LOG: 'onboard-error.log',
69
- } as const;
70
-
71
- /**
72
- * URL templates for service access
73
- */
74
- export function getServiceURL(service: keyof typeof SERVICE_PORTS, host: string = 'localhost'): string {
75
- return `http://${host}:${SERVICE_PORTS[service]}`;
76
- }
77
-
78
- /**
79
- * Docker compose file paths
80
- */
81
- export const DOCKER_COMPOSE_COMMANDS = {
82
- UP: ['up', '-d'],
83
- DOWN: ['down'],
84
- LOGS: ['logs', '-f'],
85
- PS: ['ps'],
86
- } as const;
1
+ /**
2
+ * Application configuration constants
3
+ */
4
+
5
+ /**
6
+ * Service port mappings
7
+ */
8
+ export const SERVICE_PORTS = {
9
+ API: 3000,
10
+ DASHBOARD: 3002,
11
+ GRAFANA: 3001,
12
+ KAFKA_UI: 8080,
13
+ MONGO: 27017,
14
+ KAFKA: 9092,
15
+ REDIS: 6379,
16
+ LOKI: 3100,
17
+ } as const;
18
+
19
+ /**
20
+ * Health check configuration
21
+ */
22
+ export const HEALTH_CHECK = {
23
+ MAX_RETRIES: 30,
24
+ RETRY_DELAY_MS: 2000,
25
+ TIMEOUT_MS: 60000,
26
+ } as const;
27
+
28
+ /**
29
+ * Docker command timeouts
30
+ */
31
+ export const DOCKER_TIMEOUTS = {
32
+ START_MS: 30000,
33
+ STOP_MS: 15000,
34
+ BUILD_MS: 300000,
35
+ } as const;
36
+
37
+ /**
38
+ * Critical environment variables that always need user input
39
+ */
40
+ export const CRITICAL_ENV_KEYS = [
41
+ 'NS_API_KEY',
42
+ 'MONGO_URI',
43
+ 'BROKERS',
44
+ 'REDIS_URL',
45
+ 'AUTH_SECRET',
46
+ 'ADMIN_PASSWORD',
47
+ 'LOKI_URL',
48
+ ];
49
+
50
+ /**
51
+ * Validation constraints
52
+ */
53
+ export const VALIDATION = {
54
+ MIN_PASSWORD_LENGTH: 8,
55
+ MIN_API_KEY_LENGTH: 8,
56
+ PORT_MIN: 1,
57
+ PORT_MAX: 65535,
58
+ } as const;
59
+
60
+ /**
61
+ * File paths
62
+ */
63
+ export const FILES = {
64
+ DOCKER_COMPOSE_INFRA: 'docker-compose.infra.yaml',
65
+ DOCKER_COMPOSE_APP: 'docker-compose.yaml',
66
+ ENV_FILE: '.env',
67
+ CONFIG_FILE: 'simplens.config.yaml',
68
+ ERROR_LOG: 'onboard-error.log',
69
+ } as const;
70
+
71
+ /**
72
+ * URL templates for service access
73
+ */
74
+ export function getServiceURL(service: keyof typeof SERVICE_PORTS, host: string = 'localhost'): string {
75
+ return `http://${host}:${SERVICE_PORTS[service]}`;
76
+ }
77
+
78
+ /**
79
+ * Docker compose file paths
80
+ */
81
+ export const DOCKER_COMPOSE_COMMANDS = {
82
+ UP: ['up', '-d'],
83
+ DOWN: ['down'],
84
+ LOGS: ['logs', '-f'],
85
+ PS: ['ps'],
86
+ } as const;
@@ -1 +1 @@
1
- export * from './constants.js';
1
+ export * from './constants.js';