@simplens/onboard 1.0.8 → 1.0.10

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/src/templates.ts DELETED
@@ -1,278 +0,0 @@
1
- // Docker Compose templates as constants
2
-
3
- export const INFRA_COMPOSE_TEMPLATE = `
4
- services:
5
- # ============================================
6
- # Infrastructure Services
7
- # ============================================
8
- mongo:
9
- image: mongo:7.0
10
- container_name: mongo
11
- command: [ "--replSet", "rs0", "--bind_ip_all", "--port", "27017" ]
12
- ports:
13
- - 27017:27017
14
- healthcheck:
15
- test: echo "try { rs.status() } catch (err) { rs.initiate({_id:'rs0',members:[{_id:0,host:'mongo:27017'}]}) }" | mongosh --port 27017 --quiet
16
- interval: 5s
17
- timeout: 30s
18
- start_period: 0s
19
- start_interval: 1s
20
- retries: 30
21
- volumes:
22
- - "mongo_data:/data/db"
23
- - "mongo_config:/data/configdb"
24
-
25
- kafka:
26
- image: apache/kafka-native
27
- container_name: kafka
28
- ports:
29
- - "9092:9092"
30
- environment:
31
- # Configure listeners for both docker and host communication
32
- KAFKA_LISTENERS: CONTROLLER://localhost:9091,HOST://0.0.0.0:9092,DOCKER://0.0.0.0:9093
33
- KAFKA_ADVERTISED_LISTENERS: HOST://kafka:9092,DOCKER://kafka:9093
34
- KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,DOCKER:PLAINTEXT,HOST:PLAINTEXT
35
-
36
- # Settings required for KRaft mode
37
- KAFKA_NODE_ID: 1
38
- KAFKA_PROCESS_ROLES: broker,controller
39
- KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
40
- KAFKA_CONTROLLER_QUORUM_VOTERS: 1@localhost:9091
41
-
42
- # Listener to use for broker-to-broker communication
43
- KAFKA_INTER_BROKER_LISTENER_NAME: DOCKER
44
-
45
- # Required for a single node cluster
46
- KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
47
-
48
- # Disable auto-topic creation - API server will create topics with correct partitions
49
- KAFKA_AUTO_CREATE_TOPICS_ENABLE: "false"
50
- volumes:
51
- - "kafka_data:/var/lib/kafka/data"
52
-
53
- kafka-ui:
54
- image: kafbat/kafka-ui:main
55
- container_name: kafka-ui
56
- ports:
57
- - 8080:8080
58
- environment:
59
- DYNAMIC_CONFIG_ENABLED: "true"
60
- KAFKA_CLUSTERS_0_NAME: local
61
- KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9093
62
- depends_on:
63
- - kafka
64
-
65
- redis:
66
- image: redis:7-alpine
67
- container_name: redis
68
- ports:
69
- - "6379:6379"
70
- command: redis-server --appendonly yes
71
- volumes:
72
- - "redis_data:/data"
73
- healthcheck:
74
- test: [ "CMD", "redis-cli", "ping" ]
75
- interval: 5s
76
- timeout: 3s
77
- retries: 5
78
-
79
- # ============================================
80
- # Observability Services
81
- # ============================================
82
-
83
- loki:
84
- image: grafana/loki:2.9.0
85
- container_name: loki
86
- ports:
87
- - "3100:3100"
88
- command: -config.file=/etc/loki/local-config.yaml
89
- volumes:
90
- - "loki_data:/loki"
91
- healthcheck:
92
- test: [ "CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3100/ready || exit 1" ]
93
- interval: 10s
94
- timeout: 5s
95
- retries: 5
96
-
97
- grafana:
98
- image: grafana/grafana:10.2.0
99
- container_name: grafana
100
- ports:
101
- - "3001:3000"
102
- environment:
103
- - GF_PATHS_PROVISIONING=/etc/grafana/provisioning
104
- - GF_AUTH_ANONYMOUS_ENABLED=true
105
- - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
106
- - GF_SECURITY_ADMIN_PASSWORD=admin
107
- volumes:
108
- - "grafana_data:/var/lib/grafana"
109
- depends_on:
110
- loki:
111
- condition: service_healthy
112
-
113
- volumes:
114
- mongo_data:
115
- mongo_config:
116
- kafka_data:
117
- redis_data:
118
- loki_data:
119
- grafana_data:
120
- `;
121
-
122
- export const APP_COMPOSE_TEMPLATE = `services:
123
- api:
124
- image: ghcr.io/simplenotificationsystem/simplens-core:\${CORE_VERSION:-latest}
125
- container_name: api
126
- ports:
127
- - 3000:3000
128
- env_file:
129
- - .env
130
- environment:
131
- SIMPLENS_CONFIG_PATH: \${SIMPLENS_CONFIG_PATH:-/app/simplens.config.yaml}
132
- volumes:
133
- - plugin-data:/app/.plugins
134
- - logs-data:/app/logs
135
- - ./simplens.config.yaml:/app/simplens.config.yaml:ro
136
- command: [ "node", "dist/api/server.js" ]
137
- restart: unless-stopped
138
- healthcheck:
139
- test: [ "CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))" ]
140
- interval: 30s
141
- timeout: 10s
142
- retries: 3
143
- start_period: 10s
144
-
145
- worker:
146
- image: ghcr.io/simplenotificationsystem/simplens-core:\${CORE_VERSION:-latest}
147
- env_file:
148
- - .env
149
- volumes:
150
- - logs-data:/app/logs
151
- command: [ "node", "dist/workers/worker.js" ]
152
- restart: unless-stopped
153
-
154
- notification_processor:
155
- image: ghcr.io/simplenotificationsystem/simplens-core:\${CORE_VERSION:-latest}
156
- env_file:
157
- - .env
158
- environment:
159
- SIMPLENS_CONFIG_PATH: \${SIMPLENS_CONFIG_PATH:-/app/simplens.config.yaml}
160
- volumes:
161
- - plugin-data:/app/.plugins
162
- - logs-data:/app/logs
163
- - ./simplens.config.yaml:/app/simplens.config.yaml:ro
164
- command: [ "node", "dist/processors/unified/unified.processor.js" ]
165
- depends_on:
166
- api:
167
- condition: service_healthy
168
- restart: unless-stopped
169
-
170
- delayed_processor:
171
- image: ghcr.io/simplenotificationsystem/simplens-core:\${CORE_VERSION:-latest}
172
- env_file:
173
- - .env
174
- volumes:
175
- - logs-data:/app/logs
176
- command: [ "node", "dist/processors/delayed/delayed.processor.js" ]
177
- restart: unless-stopped
178
-
179
- recovery:
180
- image: ghcr.io/simplenotificationsystem/simplens-core:\${CORE_VERSION:-latest}
181
- env_file:
182
- - .env
183
- volumes:
184
- - logs-data:/app/logs
185
- command: [ "node", "dist/workers/recovery/recovery.service.js" ]
186
- restart: unless-stopped
187
-
188
- dashboard:
189
- image: ghcr.io/simplenotificationsystem/simplens-dashboard:\${DASHBOARD_VERSION:-latest}
190
- ports:
191
- - 3002:3002
192
- container_name: dashboard
193
- env_file:
194
- - .env
195
- environment:
196
- PORT: \${DASHBOARD_PORT:-3002}
197
- API_BASE_URL: http://api:\${PORT:-3000}
198
- WEBHOOK_HOST: dashboard
199
- WEBHOOK_PORT: \${DASHBOARD_PORT:-3002}
200
- restart: unless-stopped
201
-
202
- volumes:
203
- plugin-data:
204
- logs-data:
205
-
206
- networks:
207
- default:
208
- name: simplens
209
- `;
210
-
211
- export const APP_NGINX_SERVICE_TEMPLATE = ` nginx:
212
- image: nginx:alpine
213
- container_name: nginx
214
- ports:
215
- - "80:80"
216
- volumes:
217
- - "./nginx.conf:/etc/nginx/conf.d/default.conf:ro"
218
- depends_on:
219
- - api
220
- - dashboard
221
- restart: unless-stopped`;
222
-
223
- export const APP_NGINX_SSL_SERVICE_TEMPLATE = ` nginx:
224
- image: nginx:alpine
225
- container_name: nginx
226
- ports:
227
- - "80:80"
228
- - "443:443"
229
- volumes:
230
- - "./nginx.conf:/etc/nginx/conf.d/default.conf:ro"
231
- - certbot-etc:/etc/letsencrypt
232
- - certbot-www:/var/www/certbot
233
- depends_on:
234
- - api
235
- - dashboard
236
- restart: unless-stopped`;
237
-
238
- export const APP_CERTBOT_SERVICES_TEMPLATE = ` certbot:
239
- image: certbot/certbot:latest
240
- container_name: certbot
241
- volumes:
242
- - certbot-etc:/etc/letsencrypt
243
- - certbot-www:/var/www/certbot
244
- command: sh -c "trap exit TERM; while :; do sleep 86400; done"
245
- restart: unless-stopped
246
-
247
- certbot-renew:
248
- image: docker:cli
249
- container_name: certbot-renew
250
- volumes:
251
- - /var/run/docker.sock:/var/run/docker.sock
252
- depends_on:
253
- - certbot
254
- - nginx
255
- command: sh -c "while :; do sleep 12h; docker exec certbot certbot renew --webroot -w /var/www/certbot --quiet && docker exec nginx nginx -s reload || true; done"
256
- restart: unless-stopped`;
257
-
258
- export const INFRA_CERTBOT_SERVICES_TEMPLATE = ` certbot:
259
- image: certbot/certbot:latest
260
- container_name: certbot
261
- volumes:
262
- - certbot-etc:/etc/letsencrypt
263
- - certbot-www:/var/www/certbot
264
- command: sh -c "trap exit TERM; while :; do sleep 86400; done"
265
- restart: unless-stopped
266
-
267
- certbot-renew:
268
- image: docker:cli
269
- container_name: certbot-renew
270
- volumes:
271
- - /var/run/docker.sock:/var/run/docker.sock
272
- depends_on:
273
- - certbot
274
- - nginx
275
- command: sh -c "while :; do sleep 12h; docker exec certbot certbot renew --webroot -w /var/www/certbot --quiet && docker exec nginx nginx -s reload || true; done"
276
- restart: unless-stopped`;
277
-
278
- export const INFRA_CERTBOT_VOLUMES = ['certbot-etc', 'certbot-www'] as const;
@@ -1,135 +0,0 @@
1
- /**
2
- * Domain type definitions for the onboarding system
3
- */
4
-
5
- /**
6
- * Plugin information returned by config-gen
7
- */
8
- export interface PluginInfo {
9
- /** Package name (e.g., '@simplens/nodemailer-gmail') */
10
- package: string;
11
- /** Display name */
12
- name: string;
13
- /** Description of what the plugin does */
14
- description: string;
15
- }
16
-
17
- /**
18
- * Infrastructure service option
19
- */
20
- export interface InfraService {
21
- /** Display name (e.g., 'MongoDB (Database)') */
22
- name: string;
23
- /** Service identifier (e.g., 'mongo') */
24
- value: string;
25
- /** Whether checked by default */
26
- checked: boolean;
27
- }
28
-
29
- /**
30
- * Environment variable definition
31
- */
32
- export interface EnvVariable {
33
- /** Environment variable key */
34
- key: string;
35
- /** Current or default value */
36
- value: string;
37
- /** Optional description/comment */
38
- description?: string;
39
- /** Whether this variable is required */
40
- required: boolean;
41
- }
42
-
43
- /**
44
- * Setup options provided via CLI or prompts
45
- */
46
- export interface SetupOptions {
47
- /** Whether to setup infrastructure services */
48
- infra: boolean;
49
- /** Environment configuration mode */
50
- envMode: 'default' | 'interactive';
51
- /** Target directory for setup */
52
- targetDir: string;
53
- /** Dashboard base path (empty string means root) */
54
- basePath: string;
55
- /** Whether SSL automation with Certbot is enabled */
56
- enableSsl?: boolean;
57
- /** Public domain for SSL certificate */
58
- sslDomain?: string;
59
- /** Registration email for Let's Encrypt */
60
- sslEmail?: string;
61
- }
62
-
63
- /**
64
- * Service definition for docker-compose generation
65
- */
66
- export interface ServiceDefinition {
67
- /** Service identifier */
68
- id: string;
69
- /** Display name */
70
- name: string;
71
- /** Docker compose YAML block */
72
- dockerCompose: string;
73
- /** Required volumes */
74
- volumes: string[];
75
- /** Service dependencies */
76
- dependencies?: string[];
77
- /** Whether service has health check */
78
- healthCheck?: boolean;
79
- }
80
-
81
- /**
82
- * SimplensConfig YAML structure
83
- */
84
- export interface SimplensConfig {
85
- providers: ProviderConfig[];
86
- }
87
-
88
- /**
89
- * Provider configuration in simplens.config.yaml
90
- */
91
- export interface ProviderConfig {
92
- /** Package name */
93
- package: string;
94
- /** Provider ID */
95
- id: string;
96
- /** Required credentials as key-value pairs */
97
- credentials: Record<string, string>;
98
- /** Optional configuration */
99
- optionalConfig?: Record<string, string | number | boolean>;
100
- }
101
-
102
- /**
103
- * Docker compose file structure (simplified)
104
- */
105
- export interface DockerComposeFile {
106
- services: Record<string, DockerService>;
107
- volumes?: Record<string, DockerVolume>;
108
- networks?: Record<string, DockerNetwork>;
109
- }
110
-
111
- export interface DockerService {
112
- image: string;
113
- container_name?: string;
114
- ports?: string[];
115
- environment?: Record<string, string> | string[];
116
- volumes?: string[];
117
- command?: string | string[];
118
- depends_on?: string[] | Record<string, { condition: string }>;
119
- healthcheck?: {
120
- test: string | string[];
121
- interval?: string;
122
- timeout?: string;
123
- retries?: number;
124
- start_period?: string;
125
- };
126
- }
127
-
128
- export interface DockerVolume {
129
- driver?: string;
130
- driver_opts?: Record<string, string>;
131
- }
132
-
133
- export interface DockerNetwork {
134
- driver?: string;
135
- }
@@ -1,173 +0,0 @@
1
- /**
2
- * Custom error types for better error handling and troubleshooting
3
- */
4
-
5
- /**
6
- * Base error class for all onboarding errors
7
- */
8
- export class OnboardingError extends Error {
9
- constructor(
10
- public readonly code: string,
11
- message: string,
12
- public readonly troubleshooting?: string
13
- ) {
14
- super(message);
15
- this.name = 'OnboardingError';
16
- Error.captureStackTrace(this, this.constructor);
17
- }
18
- }
19
-
20
- /**
21
- * Docker-related errors
22
- */
23
- export class DockerError extends OnboardingError {
24
- constructor(message: string, troubleshooting?: string) {
25
- super('DOCKER_ERROR', message, troubleshooting);
26
- this.name = 'DockerError';
27
- }
28
- }
29
-
30
- export class DockerNotInstalledError extends DockerError {
31
- constructor() {
32
- super(
33
- 'Docker is not installed on this system',
34
- 'Please install Docker from: https://docs.docker.com/get-docker/'
35
- );
36
- this.name = 'DockerNotInstalledError';
37
- }
38
- }
39
-
40
- export class DockerNotRunningError extends DockerError {
41
- constructor() {
42
- super(
43
- 'Docker daemon is not running',
44
- 'Please start Docker Desktop or Docker daemon, then try again'
45
- );
46
- this.name = 'DockerNotRunningError';
47
- }
48
- }
49
-
50
- export class DockerPermissionError extends DockerError {
51
- constructor() {
52
- super(
53
- 'Permission denied when accessing Docker',
54
- 'Try running with sudo or add your user to the docker group:\n' +
55
- ' sudo usermod -aG docker $USER\n' +
56
- ' Then log out and log back in'
57
- );
58
- this.name = 'DockerPermissionError';
59
- }
60
- }
61
-
62
- export class DockerComposeError extends DockerError {
63
- constructor(operation: string, details?: string) {
64
- super(
65
- `Failed to ${operation} with docker compose (fallback: docker-compose)`,
66
- details || 'Check service logs for more details:\n docker compose logs\n (fallback: docker-compose logs)'
67
- );
68
- this.name = 'DockerComposeError';
69
- }
70
- }
71
-
72
- /**
73
- * File system errors
74
- */
75
- export class FileSystemError extends OnboardingError {
76
- constructor(message: string, public readonly path: string, troubleshooting?: string) {
77
- super('FILESYSTEM_ERROR', message, troubleshooting);
78
- this.name = 'FileSystemError';
79
- }
80
- }
81
-
82
- export class DirectoryNotWritableError extends FileSystemError {
83
- constructor(path: string) {
84
- super(
85
- `Directory is not writable: ${path}`,
86
- path,
87
- 'Check directory permissions or choose a different directory'
88
- );
89
- this.name = 'DirectoryNotWritableError';
90
- }
91
- }
92
-
93
- export class FileNotFoundError extends FileSystemError {
94
- constructor(path: string) {
95
- super(
96
- `File not found: ${path}`,
97
- path,
98
- 'Ensure the file exists or check the path'
99
- );
100
- this.name = 'FileNotFoundError';
101
- }
102
- }
103
-
104
- /**
105
- * Configuration errors
106
- */
107
- export class ConfigurationError extends OnboardingError {
108
- constructor(message: string, troubleshooting?: string) {
109
- super('CONFIG_ERROR', message, troubleshooting);
110
- this.name = 'ConfigurationError';
111
- }
112
- }
113
-
114
- export class InvalidEnvironmentValueError extends ConfigurationError {
115
- constructor(key: string, value: string, expectedFormat: string) {
116
- super(
117
- `Invalid value for ${key}: ${value}`,
118
- `Expected format: ${expectedFormat}`
119
- );
120
- this.name = 'InvalidEnvironmentValueError';
121
- }
122
- }
123
-
124
- export class PluginConfigurationError extends ConfigurationError {
125
- constructor(pluginName: string, details: string) {
126
- super(
127
- `Failed to configure plugin ${pluginName}`,
128
- details
129
- );
130
- this.name = 'PluginConfigurationError';
131
- }
132
- }
133
-
134
- /**
135
- * Service health errors
136
- */
137
- export class ServiceHealthError extends OnboardingError {
138
- constructor(serviceName: string, timeout: number) {
139
- super(
140
- 'SERVICE_HEALTH_ERROR',
141
- `Service '${serviceName}' did not become healthy within ${timeout}ms`,
142
- `Check service logs:\n docker compose logs ${serviceName}\n (fallback: docker-compose logs ${serviceName})\n\n` +
143
- 'Or check container status:\n docker ps -a'
144
- );
145
- this.name = 'ServiceHealthError';
146
- }
147
- }
148
-
149
- /**
150
- * Type guard to check if an error is an OnboardingError
151
- */
152
- export function isOnboardingError(error: unknown): error is OnboardingError {
153
- return error instanceof OnboardingError;
154
- }
155
-
156
- /**
157
- * Format error for user display
158
- */
159
- export function formatErrorForUser(error: unknown): string {
160
- if (isOnboardingError(error)) {
161
- let message = `āŒ ${error.message}`;
162
- if (error.troubleshooting) {
163
- message += `\n\nšŸ’” Troubleshooting:\n${error.troubleshooting}`;
164
- }
165
- return message;
166
- }
167
-
168
- if (error instanceof Error) {
169
- return `āŒ Unexpected error: ${error.message}`;
170
- }
171
-
172
- return `āŒ An unknown error occurred`;
173
- }
@@ -1,2 +0,0 @@
1
- export * from './errors.js';
2
- export * from './domain.js';
package/src/ui.ts DELETED
@@ -1,91 +0,0 @@
1
- /**
2
- * Centralized UI helpers — themed intro/outro and cancellation handling.
3
- *
4
- * NOTE: Individual @clack/prompts functions (text, confirm, select, etc.)
5
- * should be imported directly from '@clack/prompts' in each consumer file.
6
- * Re-exporting from here causes TypeScript resolution issues with .d.mts types.
7
- */
8
-
9
- import { intro as clackIntro, outro as clackOutro, cancel as clackCancel, isCancel, log as clackLog, note as clackNote, spinner as clackSpinner } from '@clack/prompts';
10
- import chalk from 'chalk';
11
- import { getLoggerConfig } from './utils/logger.js';
12
-
13
- /**
14
- * Themed intro — blue bar
15
- */
16
- export function intro(title?: string): void {
17
- if (getLoggerConfig().silent) return;
18
- clackIntro(chalk.bgBlueBright.black(` ${title ?? ''} `));
19
- }
20
-
21
- /**
22
- * Themed outro — blue text
23
- */
24
- export function outro(message?: string): void {
25
- if (getLoggerConfig().silent) return;
26
- clackOutro(chalk.blueBright(message ?? 'Done'));
27
- }
28
-
29
- /**
30
- * Wrapped log functions that respect silent mode
31
- */
32
- export const log = {
33
- step: (message: string) => {
34
- if (getLoggerConfig().silent) return;
35
- clackLog.step(message);
36
- },
37
- info: (message: string) => {
38
- if (getLoggerConfig().silent) return;
39
- clackLog.info(message);
40
- },
41
- warning: (message: string) => {
42
- if (getLoggerConfig().silent) return;
43
- clackLog.warning(message);
44
- },
45
- error: (message: string) => {
46
- if (getLoggerConfig().silent) return;
47
- clackLog.error(message);
48
- },
49
- success: (message: string) => {
50
- if (getLoggerConfig().silent) return;
51
- clackLog.success(message);
52
- },
53
- };
54
-
55
- /**
56
- * Wrapped note function that respects silent mode
57
- */
58
- export function note(message: string, title?: string): void {
59
- if (getLoggerConfig().silent) return;
60
- clackNote(message, title);
61
- }
62
-
63
- /**
64
- * Wrapped spinner that respects silent mode
65
- * Returns a no-op spinner in silent mode
66
- */
67
- export function spinner() {
68
- if (getLoggerConfig().silent) {
69
- // Return a no-op spinner with all required methods
70
- return {
71
- start: () => {},
72
- stop: () => {},
73
- message: () => {},
74
- error: () => {},
75
- };
76
- }
77
- return clackSpinner();
78
- }
79
-
80
- /**
81
- * Handle user cancellation (Ctrl-C) for any prompt value.
82
- * Exits the process with code 0 after printing a message.
83
- */
84
- export function handleCancel(value: unknown, message = 'Setup cancelled.'): void {
85
- if (isCancel(value)) {
86
- if (!getLoggerConfig().silent) {
87
- clackCancel(chalk.blueBright(message));
88
- }
89
- process.exit(0);
90
- }
91
- }
@@ -1 +0,0 @@
1
- export * from './logger.js';