@simplens/onboard 1.0.0

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 (94) hide show
  1. package/README.md +214 -0
  2. package/dist/__tests__/errors.test.d.ts +2 -0
  3. package/dist/__tests__/errors.test.d.ts.map +1 -0
  4. package/dist/__tests__/errors.test.js +125 -0
  5. package/dist/__tests__/errors.test.js.map +1 -0
  6. package/dist/__tests__/utils.test.d.ts +2 -0
  7. package/dist/__tests__/utils.test.d.ts.map +1 -0
  8. package/dist/__tests__/utils.test.js +105 -0
  9. package/dist/__tests__/utils.test.js.map +1 -0
  10. package/dist/__tests__/validators.test.d.ts +2 -0
  11. package/dist/__tests__/validators.test.d.ts.map +1 -0
  12. package/dist/__tests__/validators.test.js +148 -0
  13. package/dist/__tests__/validators.test.js.map +1 -0
  14. package/dist/config/constants.d.ts +69 -0
  15. package/dist/config/constants.d.ts.map +1 -0
  16. package/dist/config/constants.js +79 -0
  17. package/dist/config/constants.js.map +1 -0
  18. package/dist/config/index.d.ts +2 -0
  19. package/dist/config/index.d.ts.map +1 -0
  20. package/dist/config/index.js +2 -0
  21. package/dist/config/index.js.map +1 -0
  22. package/dist/env-config.d.ts +33 -0
  23. package/dist/env-config.d.ts.map +1 -0
  24. package/dist/env-config.js +285 -0
  25. package/dist/env-config.js.map +1 -0
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +153 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/infra.d.ts +31 -0
  31. package/dist/infra.d.ts.map +1 -0
  32. package/dist/infra.js +267 -0
  33. package/dist/infra.js.map +1 -0
  34. package/dist/plugins.d.ts +35 -0
  35. package/dist/plugins.d.ts.map +1 -0
  36. package/dist/plugins.js +164 -0
  37. package/dist/plugins.js.map +1 -0
  38. package/dist/services.d.ts +52 -0
  39. package/dist/services.d.ts.map +1 -0
  40. package/dist/services.js +158 -0
  41. package/dist/services.js.map +1 -0
  42. package/dist/templates.d.ts +3 -0
  43. package/dist/templates.d.ts.map +1 -0
  44. package/dist/templates.js +202 -0
  45. package/dist/templates.js.map +1 -0
  46. package/dist/types/domain.d.ts +119 -0
  47. package/dist/types/domain.d.ts.map +1 -0
  48. package/dist/types/domain.js +5 -0
  49. package/dist/types/domain.js.map +1 -0
  50. package/dist/types/errors.d.ts +69 -0
  51. package/dist/types/errors.d.ts.map +1 -0
  52. package/dist/types/errors.js +129 -0
  53. package/dist/types/errors.js.map +1 -0
  54. package/dist/types/index.d.ts +3 -0
  55. package/dist/types/index.d.ts.map +1 -0
  56. package/dist/types/index.js +3 -0
  57. package/dist/types/index.js.map +1 -0
  58. package/dist/utils/index.d.ts +2 -0
  59. package/dist/utils/index.d.ts.map +1 -0
  60. package/dist/utils/index.js +2 -0
  61. package/dist/utils/index.js.map +1 -0
  62. package/dist/utils/logger.d.ts +54 -0
  63. package/dist/utils/logger.d.ts.map +1 -0
  64. package/dist/utils/logger.js +92 -0
  65. package/dist/utils/logger.js.map +1 -0
  66. package/dist/utils.d.ts +32 -0
  67. package/dist/utils.d.ts.map +1 -0
  68. package/dist/utils.js +79 -0
  69. package/dist/utils.js.map +1 -0
  70. package/dist/validators.d.ts +93 -0
  71. package/dist/validators.d.ts.map +1 -0
  72. package/dist/validators.js +180 -0
  73. package/dist/validators.js.map +1 -0
  74. package/package.json +45 -0
  75. package/src/__tests__/errors.test.ts +187 -0
  76. package/src/__tests__/utils.test.ts +142 -0
  77. package/src/__tests__/validators.test.ts +195 -0
  78. package/src/config/constants.ts +86 -0
  79. package/src/config/index.ts +1 -0
  80. package/src/env-config.ts +320 -0
  81. package/src/index.ts +203 -0
  82. package/src/infra.ts +300 -0
  83. package/src/plugins.ts +190 -0
  84. package/src/services.ts +190 -0
  85. package/src/templates.ts +203 -0
  86. package/src/types/domain.ts +127 -0
  87. package/src/types/errors.ts +173 -0
  88. package/src/types/index.ts +2 -0
  89. package/src/utils/index.ts +1 -0
  90. package/src/utils/logger.ts +118 -0
  91. package/src/utils.ts +105 -0
  92. package/src/validators.ts +192 -0
  93. package/tsconfig.json +19 -0
  94. package/vitest.config.ts +20 -0
package/README.md ADDED
@@ -0,0 +1,214 @@
1
+ # @simplens/onboard
2
+
3
+ > CLI tool to setup SimpleNS instances on any linux/amd64 and windows machine
4
+
5
+ ## Overview
6
+
7
+ `@simplens/onboard` is an interactive CLI tool that guides you through setting up a complete SimpleNS (Simple Notification System) instance on your local machine or server. It handles infrastructure provisioning, environment configuration, plugin installation, and service orchestration.
8
+
9
+ ## Features
10
+
11
+ - ✅ **Prerequisite Validation** - Checks Docker installation and availability
12
+ - 🏗️ **Infrastructure Setup** - Deploy MongoDB, Kafka, Redis, Loki, Grafana with one command
13
+ - 🐧 **OS-Aware Configuration** - Automatically detects and configures for Windows, Linux, or macOS
14
+ - ⚙️ **Smart Environment Config** - Default or interactive mode for environment variables
15
+ - 🔌 **Plugin Management** - Browse and install official SimpleNS plugins
16
+ - 🚀 **Service Orchestration** - Automatic health checks and sequential service startup
17
+ - 📊 **Service Dashboard** - View all running services and their access URLs
18
+
19
+ ## Prerequisites
20
+
21
+ - **Docker** - Docker Desktop (Windows/Mac) or Docker Engine (Linux)
22
+ - **Node.js** - Version 18 or higher
23
+ - **NPX** - Comes with npm 5.2+
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ # Run directly with npx (recommended)
29
+ npx @simplens/onboard
30
+
31
+ # Or install globally
32
+ npm install -g @simplens/onboard
33
+ simplens-onboard
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ### Basic Setup (Application Services Only)
39
+
40
+ ```bash
41
+ npx @simplens/onboard
42
+ ```
43
+
44
+ This will:
45
+ - Validate prerequisites
46
+ - Generate `docker-compose.yaml` for app services
47
+ - Configure environment variables (default mode)
48
+ - Prompt for plugin selection
49
+ - Optionally start services
50
+
51
+ ### Full Setup (Infrastructure + Application)
52
+
53
+ ```bash
54
+ npx @simplens/onboard --infra
55
+ ```
56
+
57
+ Includes everything from basic setup plus:
58
+ - Interactive infrastructure service selection (MongoDB, Kafka, Redis, etc.)
59
+ - Generate `docker-compose.infra.yaml`
60
+ - OS-specific host configuration (handles Linux compatibility)
61
+ - Auto-configured connection URLs for infra services
62
+
63
+ ### Interactive Environment Configuration
64
+
65
+ ```bash
66
+ npx @simplens/onboard --env interactive
67
+ ```
68
+
69
+ Prompts for every environment variable instead of using defaults.
70
+
71
+ ### Custom Target Directory
72
+
73
+ ```bash
74
+ npx @simplens/onboard --infra --dir /path/to/setup
75
+ ```
76
+
77
+ ## Command Options
78
+
79
+ | Option | Description | Default |
80
+ |--------|-------------|---------|
81
+ | `--infra` | Setup infrastructure services (MongoDB, Kafka, Redis, Loki, Grafana) | `false` |
82
+ | `--env <mode>` | Environment setup mode: `default` or `interactive` | `default` |
83
+ | `--dir <path>` | Target directory for setup files | Current directory |
84
+
85
+ ## Workflow
86
+
87
+ 1. **Prerequisites Check**
88
+ - Validates Docker installation
89
+ - Checks Docker daemon status
90
+ - Detects operating system
91
+
92
+ 2. **Infrastructure Setup** (if `--infra` flag is used)
93
+ - Select infrastructure services
94
+ - Auto-detect host configuration (Linux-aware)
95
+ - Generate `docker-compose.infra.yaml`
96
+
97
+ 3. **Environment Configuration**
98
+ - Load defaults from `.env.example`
99
+ - Auto-fill infra connection URLs
100
+ - Prompt for critical values (API keys, passwords)
101
+ - Generate `.env` file
102
+
103
+ 4. **Plugin Installation**
104
+ - Fetch official plugins from registry
105
+ - Interactive multi-select
106
+ - Generate `simplens.config.yaml`
107
+ - Extract and prompt for plugin credentials
108
+ - Append credentials to `.env`
109
+
110
+ 5. **Service Orchestration**
111
+ - Optionally start infrastructure services
112
+ - Wait for health checks
113
+ - Start application services
114
+ - Display service URLs and status
115
+
116
+ ## Generated Files
117
+
118
+ - `docker-compose.infra.yaml` - Infrastructure services (if `--infra` used)
119
+ - `docker-compose.yaml` - Application services
120
+ - `.env` - Environment variables and credentials
121
+ - `simplens.config.yaml` - Plugin configuration
122
+
123
+ ## Service URLs
124
+
125
+ After successful setup, access these URLs:
126
+
127
+ - **API Server**: http://localhost:3000
128
+ - **API Health**: http://localhost:3000/health
129
+ - **Dashboard**: http://localhost:3002
130
+ - **Kafka UI**: http://localhost:8080 (if Kafka selected)
131
+ - **Grafana**: http://localhost:3001 (if Grafana selected)
132
+
133
+ ## Examples
134
+
135
+ ### Minimal Setup
136
+
137
+ ```bash
138
+ # Basic setup with defaults
139
+ npx @simplens/onboard
140
+
141
+ # Select plugins when prompted
142
+ # Choose "Start services" at the end
143
+ ```
144
+
145
+ ### Full Production Setup
146
+
147
+ ```bash
148
+ # Infrastructure + interactive env config
149
+ npx @simplens/onboard --infra --env interactive
150
+
151
+ # Select all infrastructure services
152
+ # Provide production credentials
153
+ # Start services immediately
154
+ ```
155
+
156
+ ### Development Setup in Custom Directory
157
+
158
+ ```bash
159
+ # Setup in specific directory
160
+ npx @simplens/onboard --infra --dir ~/simplens-dev
161
+
162
+ # Select only MongoDB, Kafka, Redis
163
+ # Use default env values
164
+ # Start services for testing
165
+ ```
166
+
167
+ ## Troubleshooting
168
+
169
+ ### Docker Not Running
170
+
171
+ ```
172
+ ❌ Docker daemon is not running.
173
+ Please start Docker Desktop or Docker daemon.
174
+ ```
175
+
176
+ **Solution**: Start Docker Desktop (Windows/Mac) or `sudo systemctl start docker` (Linux)
177
+
178
+ ### Plugin Installation Failed
179
+
180
+ ```
181
+ ❌ Failed to generate plugin configuration
182
+ ```
183
+
184
+ **Solution**:
185
+ - Check internet connection
186
+ - Verify plugin package name
187
+ - Try installing plugins manually with `@simplens/config-gen`
188
+
189
+ ## Development
190
+
191
+ ```bash
192
+ # Clone repository
193
+ cd packages/onboard
194
+
195
+ # Install dependencies
196
+ npm install
197
+
198
+ # Build TypeScript
199
+ npm run build
200
+
201
+ # Test locally
202
+ npm link
203
+ simplens-onboard --help
204
+ ```
205
+
206
+ ## License
207
+
208
+ ISC
209
+
210
+ ## Support
211
+
212
+ For issues and questions:
213
+ - GitHub Issues: [SimpleNS Core Issues](https://github.com/SimpleNotificationSystem/simplens-core/issues)
214
+ - Documentation: [SimpleNS Docs](https://simplens.vercel.app)
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=errors.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/errors.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,125 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { OnboardingError, DockerNotInstalledError, DockerNotRunningError, DockerPermissionError, DockerComposeError, FileSystemError, DirectoryNotWritableError, isOnboardingError, formatErrorForUser, } from '../types/errors.js';
3
+ describe('error types', () => {
4
+ describe('OnboardingError', () => {
5
+ it('should create error with code and message', () => {
6
+ const error = new OnboardingError('TEST_CODE', 'Test message');
7
+ expect(error.code).toBe('TEST_CODE');
8
+ expect(error.message).toBe('Test message');
9
+ expect(error.name).toBe('OnboardingError');
10
+ });
11
+ it('should include troubleshooting when provided', () => {
12
+ const error = new OnboardingError('TEST_CODE', 'Test message', 'Try this fix');
13
+ expect(error.troubleshooting).toBe('Try this fix');
14
+ });
15
+ it('should have proper stack trace', () => {
16
+ const error = new OnboardingError('TEST', 'message');
17
+ expect(error.stack).toBeDefined();
18
+ expect(error.stack).toContain('OnboardingError');
19
+ });
20
+ });
21
+ describe('DockerNotInstalledError', () => {
22
+ it('should have correct message and troubleshooting', () => {
23
+ const error = new DockerNotInstalledError();
24
+ expect(error.message).toContain('not installed');
25
+ expect(error.troubleshooting).toContain('https://docs.docker.com/get-docker/');
26
+ expect(error.name).toBe('DockerNotInstalledError');
27
+ });
28
+ });
29
+ describe('DockerNotRunningError', () => {
30
+ it('should have correct message and troubleshooting', () => {
31
+ const error = new DockerNotRunningError();
32
+ expect(error.message).toContain('not running');
33
+ expect(error.troubleshooting).toContain('Docker daemon');
34
+ expect(error.name).toBe('DockerNotRunningError');
35
+ });
36
+ });
37
+ describe('DockerPermissionError', () => {
38
+ it('should have correct message and troubleshooting', () => {
39
+ const error = new DockerPermissionError();
40
+ expect(error.message).toContain('Permission denied');
41
+ expect(error.troubleshooting).toContain('usermod');
42
+ expect(error.name).toBe('DockerPermissionError');
43
+ });
44
+ });
45
+ describe('DockerComposeError', () => {
46
+ it('should include operation in message', () => {
47
+ const error = new DockerComposeError('start services');
48
+ expect(error.message).toContain('start services');
49
+ expect(error.name).toBe('DockerComposeError');
50
+ });
51
+ it('should use custom troubleshooting when provided', () => {
52
+ const error = new DockerComposeError('pull images', 'Check network connection');
53
+ expect(error.troubleshooting).toBe('Check network connection');
54
+ });
55
+ it('should have default troubleshooting', () => {
56
+ const error = new DockerComposeError('operation');
57
+ expect(error.troubleshooting).toContain('docker-compose logs');
58
+ });
59
+ });
60
+ describe('FileSystemError', () => {
61
+ it('should include path in error', () => {
62
+ const error = new FileSystemError('Cannot write', '/path/to/file', 'Check permissions');
63
+ expect(error.path).toBe('/path/to/file');
64
+ expect(error.troubleshooting).toBe('Check permissions');
65
+ });
66
+ });
67
+ describe('DirectoryNotWritableError', () => {
68
+ it('should include path in message and error', () => {
69
+ const error = new DirectoryNotWritableError('/opt/app');
70
+ expect(error.message).toContain('/opt/app');
71
+ expect(error.path).toBe('/opt/app');
72
+ expect(error.troubleshooting).toContain('permissions');
73
+ });
74
+ });
75
+ describe('isOnboardingError', () => {
76
+ it('should return true for OnboardingError instances', () => {
77
+ const error = new OnboardingError('CODE', 'message');
78
+ expect(isOnboardingError(error)).toBe(true);
79
+ });
80
+ it('should return true for subclasses of OnboardingError', () => {
81
+ const error = new DockerNotInstalledError();
82
+ expect(isOnboardingError(error)).toBe(true);
83
+ });
84
+ it('should return false for regular Error', () => {
85
+ const error = new Error('regular error');
86
+ expect(isOnboardingError(error)).toBe(false);
87
+ });
88
+ it('should return false for non-error values', () => {
89
+ expect(isOnboardingError('string')).toBe(false);
90
+ expect(isOnboardingError(null)).toBe(false);
91
+ expect(isOnboardingError(undefined)).toBe(false);
92
+ expect(isOnboardingError({})).toBe(false);
93
+ });
94
+ });
95
+ describe('formatErrorForUser', () => {
96
+ it('should format OnboardingError with troubleshooting', () => {
97
+ const error = new OnboardingError('TEST', 'Something went wrong', 'Try this fix');
98
+ const formatted = formatErrorForUser(error);
99
+ expect(formatted).toContain('❌ Something went wrong');
100
+ expect(formatted).toContain('💡 Troubleshooting:');
101
+ expect(formatted).toContain('Try this fix');
102
+ });
103
+ it('should format OnboardingError without troubleshooting', () => {
104
+ const error = new OnboardingError('TEST', 'Something went wrong');
105
+ const formatted = formatErrorForUser(error);
106
+ expect(formatted).toBe('❌ Something went wrong');
107
+ expect(formatted).not.toContain('Troubleshooting');
108
+ });
109
+ it('should format regular Error', () => {
110
+ const error = new Error('Regular error message');
111
+ const formatted = formatErrorForUser(error);
112
+ expect(formatted).toContain('Unexpected error');
113
+ expect(formatted).toContain('Regular error message');
114
+ });
115
+ it('should handle non-Error values', () => {
116
+ const formatted = formatErrorForUser('some string');
117
+ expect(formatted).toBe('❌ An unknown error occurred');
118
+ });
119
+ it('should handle null/undefined', () => {
120
+ expect(formatErrorForUser(null)).toBe('❌ An unknown error occurred');
121
+ expect(formatErrorForUser(undefined)).toBe('❌ An unknown error occurred');
122
+ });
123
+ });
124
+ });
125
+ //# sourceMappingURL=errors.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.test.js","sourceRoot":"","sources":["../../src/__tests__/errors.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/utils.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,105 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { promises as fs } from 'fs';
3
+ import os from 'os';
4
+ import path from 'path';
5
+ import { fileExists, writeFile, readFile, appendFile, } from '../utils.js';
6
+ describe('utils - file operations', () => {
7
+ let tempDir;
8
+ beforeEach(async () => {
9
+ // Create a temporary directory for tests
10
+ tempDir = path.join(os.tmpdir(), `onboard-test-${Date.now()}`);
11
+ await fs.mkdir(tempDir, { recursive: true });
12
+ });
13
+ afterEach(async () => {
14
+ // Clean up temporary directory
15
+ try {
16
+ await fs.rm(tempDir, { recursive: true, force: true });
17
+ }
18
+ catch (error) {
19
+ // Ignore cleanup errors
20
+ }
21
+ });
22
+ describe('fileExists', () => {
23
+ it('should return true for existing file', async () => {
24
+ const filePath = path.join(tempDir, 'test.txt');
25
+ await fs.writeFile(filePath, 'content');
26
+ expect(await fileExists(filePath)).toBe(true);
27
+ });
28
+ it('should return false for non-existing file', async () => {
29
+ const filePath = path.join(tempDir, 'nonexistent.txt');
30
+ expect(await fileExists(filePath)).toBe(false);
31
+ });
32
+ it('should return true for existing directory', async () => {
33
+ expect(await fileExists(tempDir)).toBe(true);
34
+ });
35
+ });
36
+ describe('writeFile', () => {
37
+ it('should write content to file', async () => {
38
+ const filePath = path.join(tempDir, 'write-test.txt');
39
+ const content = 'Hello, World!';
40
+ await writeFile(filePath, content);
41
+ const written = await fs.readFile(filePath, 'utf-8');
42
+ expect(written).toBe(content);
43
+ });
44
+ it('should create parent directories if they do not exist', async () => {
45
+ const filePath = path.join(tempDir, 'nested', 'dir', 'file.txt');
46
+ const content = 'Nested content';
47
+ await writeFile(filePath, content);
48
+ expect(await fileExists(filePath)).toBe(true);
49
+ const written = await fs.readFile(filePath, 'utf-8');
50
+ expect(written).toBe(content);
51
+ });
52
+ it('should overwrite existing file', async () => {
53
+ const filePath = path.join(tempDir, 'overwrite.txt');
54
+ await fs.writeFile(filePath, 'original');
55
+ await writeFile(filePath, 'new content');
56
+ const written = await fs.readFile(filePath, 'utf-8');
57
+ expect(written).toBe('new content');
58
+ });
59
+ });
60
+ describe('readFile', () => {
61
+ it('should read file content', async () => {
62
+ const filePath = path.join(tempDir, 'read-test.txt');
63
+ const content = 'File content to read';
64
+ await fs.writeFile(filePath, content);
65
+ const read = await readFile(filePath);
66
+ expect(read).toBe(content);
67
+ });
68
+ it('should throw error for non-existing file', async () => {
69
+ const filePath = path.join(tempDir, 'nonexistent.txt');
70
+ await expect(readFile(filePath)).rejects.toThrow();
71
+ });
72
+ it('should handle UTF-8 content', async () => {
73
+ const filePath = path.join(tempDir, 'utf8.txt');
74
+ const content = 'Hello 世界 🌍';
75
+ await fs.writeFile(filePath, content);
76
+ const read = await readFile(filePath);
77
+ expect(read).toBe(content);
78
+ });
79
+ });
80
+ describe('appendFile', () => {
81
+ it('should append content to existing file', async () => {
82
+ const filePath = path.join(tempDir, 'append-test.txt');
83
+ await fs.writeFile(filePath, 'Line 1\n');
84
+ await appendFile(filePath, 'Line 2\n');
85
+ const content = await fs.readFile(filePath, 'utf-8');
86
+ expect(content).toBe('Line 1\nLine 2\n');
87
+ });
88
+ it('should create file if it does not exist', async () => {
89
+ const filePath = path.join(tempDir, 'new-append.txt');
90
+ await appendFile(filePath, 'First line\n');
91
+ expect(await fileExists(filePath)).toBe(true);
92
+ const content = await fs.readFile(filePath, 'utf-8');
93
+ expect(content).toBe('First line\n');
94
+ });
95
+ it('should handle multiple appends', async () => {
96
+ const filePath = path.join(tempDir, 'multi-append.txt');
97
+ await appendFile(filePath, 'Line 1\n');
98
+ await appendFile(filePath, 'Line 2\n');
99
+ await appendFile(filePath, 'Line 3\n');
100
+ const content = await fs.readFile(filePath, 'utf-8');
101
+ expect(content).toBe('Line 1\nLine 2\nLine 3\n');
102
+ });
103
+ });
104
+ });
105
+ //# sourceMappingURL=utils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../src/__tests__/utils.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=validators.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validators.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/validators.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,148 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { checkDockerInstalled, checkDockerRunning, detectOS, validateEnvValue } from '../validators.js';
3
+ import { DockerNotInstalledError, DockerNotRunningError, DockerPermissionError } from '../types/errors.js';
4
+ // Mock execa
5
+ vi.mock('execa', () => ({
6
+ execa: vi.fn(),
7
+ }));
8
+ // Mock utils
9
+ vi.mock('../utils.js', () => ({
10
+ logError: vi.fn(),
11
+ logSuccess: vi.fn(),
12
+ logWarning: vi.fn(),
13
+ }));
14
+ import { execa } from 'execa';
15
+ describe('validators', () => {
16
+ beforeEach(() => {
17
+ vi.clearAllMocks();
18
+ });
19
+ describe('checkDockerInstalled', () => {
20
+ it('should not throw when docker is installed', async () => {
21
+ vi.mocked(execa).mockResolvedValueOnce({
22
+ stdout: 'Docker version 24.0.0',
23
+ stderr: '',
24
+ });
25
+ await expect(checkDockerInstalled()).resolves.not.toThrow();
26
+ });
27
+ it('should throw DockerNotInstalledError when docker is not installed', async () => {
28
+ vi.mocked(execa).mockRejectedValueOnce(new Error('Command not found'));
29
+ await expect(checkDockerInstalled()).rejects.toThrow(DockerNotInstalledError);
30
+ });
31
+ });
32
+ describe('checkDockerRunning', () => {
33
+ it('should not throw when docker daemon is running', async () => {
34
+ vi.mocked(execa).mockResolvedValueOnce({
35
+ stdout: 'CONTAINER ID IMAGE',
36
+ stderr: '',
37
+ });
38
+ await expect(checkDockerRunning()).resolves.not.toThrow();
39
+ });
40
+ it('should throw DockerPermissionError on permission denied', async () => {
41
+ const error = new Error('permission denied while trying to connect');
42
+ vi.mocked(execa).mockRejectedValueOnce(error);
43
+ await expect(checkDockerRunning()).rejects.toThrow(DockerPermissionError);
44
+ });
45
+ it('should throw DockerNotRunningError when daemon is not running', async () => {
46
+ const error = new Error('Cannot connect to the Docker daemon');
47
+ vi.mocked(execa).mockRejectedValueOnce(error);
48
+ await expect(checkDockerRunning()).rejects.toThrow(DockerNotRunningError);
49
+ });
50
+ it('should throw DockerNotRunningError on generic docker error', async () => {
51
+ const error = new Error('Some other docker error');
52
+ vi.mocked(execa).mockRejectedValueOnce(error);
53
+ await expect(checkDockerRunning()).rejects.toThrow(DockerNotRunningError);
54
+ });
55
+ });
56
+ describe('detectOS', () => {
57
+ const originalPlatform = process.platform;
58
+ afterEach(() => {
59
+ Object.defineProperty(process, 'platform', {
60
+ value: originalPlatform
61
+ });
62
+ });
63
+ it('should detect Windows', () => {
64
+ Object.defineProperty(process, 'platform', {
65
+ value: 'win32'
66
+ });
67
+ expect(detectOS()).toBe('windows');
68
+ });
69
+ it('should detect macOS', () => {
70
+ Object.defineProperty(process, 'platform', {
71
+ value: 'darwin'
72
+ });
73
+ expect(detectOS()).toBe('darwin');
74
+ });
75
+ it('should detect Linux', () => {
76
+ Object.defineProperty(process, 'platform', {
77
+ value: 'linux'
78
+ });
79
+ expect(detectOS()).toBe('linux');
80
+ });
81
+ it('should default to Linux for unknown platforms', () => {
82
+ Object.defineProperty(process, 'platform', {
83
+ value: 'freebsd'
84
+ });
85
+ expect(detectOS()).toBe('linux');
86
+ });
87
+ });
88
+ describe('validateEnvValue', () => {
89
+ describe('URL validation', () => {
90
+ it('should reject empty MongoDB URI', () => {
91
+ expect(validateEnvValue('MONGO_URI', '')).toBe(false);
92
+ });
93
+ it('should reject MongoDB URI without proper format', () => {
94
+ expect(validateEnvValue('MONGO_URI', 'localhost:27017')).toBe(false);
95
+ });
96
+ it('should accept valid MongoDB URI', () => {
97
+ expect(validateEnvValue('MONGO_URI', 'mongodb://localhost:27017')).toBe(true);
98
+ });
99
+ it('should reject Redis URL without proper format', () => {
100
+ expect(validateEnvValue('REDIS_URL', 'localhost:6379')).toBe(false);
101
+ });
102
+ it('should accept valid Redis URL', () => {
103
+ expect(validateEnvValue('REDIS_URL', 'redis://localhost:6379')).toBe(true);
104
+ });
105
+ });
106
+ describe('Port validation', () => {
107
+ it('should reject negative ports', () => {
108
+ expect(validateEnvValue('PORT', '-1')).toBe(false);
109
+ });
110
+ it('should reject zero port', () => {
111
+ expect(validateEnvValue('PORT', '0')).toBe(false);
112
+ });
113
+ it('should reject ports > 65535', () => {
114
+ expect(validateEnvValue('PORT', '65536')).toBe(false);
115
+ });
116
+ it('should accept valid ports', () => {
117
+ expect(validateEnvValue('PORT', '3000')).toBe(true);
118
+ expect(validateEnvValue('API_PORT', '8080')).toBe(true);
119
+ });
120
+ it('should reject non-numeric ports', () => {
121
+ expect(validateEnvValue('PORT', 'abc')).toBe(false);
122
+ });
123
+ });
124
+ describe('Security fields validation', () => {
125
+ it('should reject short API keys', () => {
126
+ expect(validateEnvValue('API_KEY', 'short')).toBe(false);
127
+ });
128
+ it('should reject short passwords', () => {
129
+ expect(validateEnvValue('PASSWORD', '1234567')).toBe(false);
130
+ });
131
+ it('should reject short secrets', () => {
132
+ expect(validateEnvValue('AUTH_SECRET', 'abc')).toBe(false);
133
+ });
134
+ it('should accept API keys with 8+ characters', () => {
135
+ expect(validateEnvValue('API_KEY', 'verylongapikey123')).toBe(true);
136
+ });
137
+ it('should accept passwords with 8+ characters', () => {
138
+ expect(validateEnvValue('PASSWORD', 'password123')).toBe(true);
139
+ });
140
+ });
141
+ describe('General validation', () => {
142
+ it('should accept valid non-special values', () => {
143
+ expect(validateEnvValue('SOME_VAR', 'some-value')).toBe(true);
144
+ });
145
+ });
146
+ });
147
+ });
148
+ //# sourceMappingURL=validators.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validators.test.js","sourceRoot":"","sources":["../../src/__tests__/validators.test.ts"],"names":[],"mappings":"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"}