suthep 0.1.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 (50) hide show
  1. package/.editorconfig +17 -0
  2. package/.prettierignore +6 -0
  3. package/.prettierrc +7 -0
  4. package/.vscode/settings.json +19 -0
  5. package/LICENSE +21 -0
  6. package/README.md +214 -0
  7. package/dist/commands/deploy.js +104 -0
  8. package/dist/commands/deploy.js.map +1 -0
  9. package/dist/commands/init.js +188 -0
  10. package/dist/commands/init.js.map +1 -0
  11. package/dist/commands/setup.js +90 -0
  12. package/dist/commands/setup.js.map +1 -0
  13. package/dist/index.js +12 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/utils/certbot.js +27 -0
  16. package/dist/utils/certbot.js.map +1 -0
  17. package/dist/utils/config-loader.js +65 -0
  18. package/dist/utils/config-loader.js.map +1 -0
  19. package/dist/utils/deployment.js +52 -0
  20. package/dist/utils/deployment.js.map +1 -0
  21. package/dist/utils/docker.js +57 -0
  22. package/dist/utils/docker.js.map +1 -0
  23. package/dist/utils/nginx.js +154 -0
  24. package/dist/utils/nginx.js.map +1 -0
  25. package/docs/README.md +62 -0
  26. package/docs/api-reference.md +545 -0
  27. package/docs/architecture.md +367 -0
  28. package/docs/commands.md +273 -0
  29. package/docs/configuration.md +347 -0
  30. package/docs/examples.md +537 -0
  31. package/docs/getting-started.md +197 -0
  32. package/docs/troubleshooting.md +441 -0
  33. package/example/README.md +81 -0
  34. package/example/docker-compose.yml +72 -0
  35. package/example/suthep.yml +31 -0
  36. package/package.json +45 -0
  37. package/src/commands/deploy.ts +133 -0
  38. package/src/commands/init.ts +214 -0
  39. package/src/commands/setup.ts +112 -0
  40. package/src/index.ts +34 -0
  41. package/src/types/config.ts +51 -0
  42. package/src/utils/certbot.ts +82 -0
  43. package/src/utils/config-loader.ts +81 -0
  44. package/src/utils/deployment.ts +132 -0
  45. package/src/utils/docker.ts +151 -0
  46. package/src/utils/nginx.ts +143 -0
  47. package/suthep.example.yml +69 -0
  48. package/todo.md +6 -0
  49. package/tsconfig.json +26 -0
  50. package/vite.config.ts +46 -0
@@ -0,0 +1,545 @@
1
+ # API Reference
2
+
3
+ This document provides detailed reference for Suthep's internal APIs and utility functions.
4
+
5
+ ## Configuration Loader
6
+
7
+ **File**: `src/utils/config-loader.ts`
8
+
9
+ ### `loadConfig(filePath: string): Promise<DeployConfig>`
10
+
11
+ Loads and parses a YAML configuration file.
12
+
13
+ **Parameters**:
14
+ - `filePath`: Path to the configuration file
15
+
16
+ **Returns**: Promise resolving to `DeployConfig` object
17
+
18
+ **Throws**: Error if file doesn't exist or is invalid
19
+
20
+ **Example**:
21
+ ```typescript
22
+ const config = await loadConfig('suthep.yml');
23
+ ```
24
+
25
+ ### `saveConfig(filePath: string, config: DeployConfig): Promise<void>`
26
+
27
+ Saves a configuration object to a YAML file.
28
+
29
+ **Parameters**:
30
+ - `filePath`: Path where to save the configuration
31
+ - `config`: Configuration object to save
32
+
33
+ **Returns**: Promise that resolves when file is saved
34
+
35
+ **Example**:
36
+ ```typescript
37
+ await saveConfig('suthep.yml', config);
38
+ ```
39
+
40
+ ## Docker Utilities
41
+
42
+ **File**: `src/utils/docker.ts`
43
+
44
+ ### `startDockerContainer(service: ServiceConfig): Promise<void>`
45
+
46
+ Starts or connects to a Docker container for a service.
47
+
48
+ **Parameters**:
49
+ - `service`: Service configuration with Docker settings
50
+
51
+ **Returns**: Promise that resolves when container is running
52
+
53
+ **Throws**: Error if container can't be started
54
+
55
+ **Behavior**:
56
+ - If container exists and is running: Does nothing
57
+ - If container exists but is stopped: Starts it
58
+ - If container doesn't exist and image provided: Creates and runs new container
59
+ - If container doesn't exist and no image: Throws error
60
+
61
+ **Example**:
62
+ ```typescript
63
+ await startDockerContainer(service);
64
+ ```
65
+
66
+ ### `stopDockerContainer(containerName: string): Promise<void>`
67
+
68
+ Stops a running Docker container.
69
+
70
+ **Parameters**:
71
+ - `containerName`: Name of the container to stop
72
+
73
+ **Returns**: Promise that resolves when container is stopped
74
+
75
+ **Throws**: Error if container can't be stopped
76
+
77
+ **Example**:
78
+ ```typescript
79
+ await stopDockerContainer('my-container');
80
+ ```
81
+
82
+ ### `removeDockerContainer(containerName: string): Promise<void>`
83
+
84
+ Removes a Docker container (force stop and remove).
85
+
86
+ **Parameters**:
87
+ - `containerName`: Name of the container to remove
88
+
89
+ **Returns**: Promise that resolves when container is removed
90
+
91
+ **Throws**: Error if container can't be removed
92
+
93
+ **Example**:
94
+ ```typescript
95
+ await removeDockerContainer('my-container');
96
+ ```
97
+
98
+ ### `isContainerRunning(containerName: string): Promise<boolean>`
99
+
100
+ Checks if a Docker container is currently running.
101
+
102
+ **Parameters**:
103
+ - `containerName`: Name of the container to check
104
+
105
+ **Returns**: Promise resolving to `true` if running, `false` otherwise
106
+
107
+ **Example**:
108
+ ```typescript
109
+ const running = await isContainerRunning('my-container');
110
+ ```
111
+
112
+ ### `getContainerLogs(containerName: string, lines?: number): Promise<string>`
113
+
114
+ Retrieves logs from a Docker container.
115
+
116
+ **Parameters**:
117
+ - `containerName`: Name of the container
118
+ - `lines`: Number of log lines to retrieve (default: 100)
119
+
120
+ **Returns**: Promise resolving to log output as string
121
+
122
+ **Throws**: Error if logs can't be retrieved
123
+
124
+ **Example**:
125
+ ```typescript
126
+ const logs = await getContainerLogs('my-container', 50);
127
+ ```
128
+
129
+ ### `inspectContainer(containerName: string): Promise<any>`
130
+
131
+ Inspects a Docker container and returns its configuration.
132
+
133
+ **Parameters**:
134
+ - `containerName`: Name of the container to inspect
135
+
136
+ **Returns**: Promise resolving to container inspection object
137
+
138
+ **Throws**: Error if container can't be inspected
139
+
140
+ **Example**:
141
+ ```typescript
142
+ const info = await inspectContainer('my-container');
143
+ ```
144
+
145
+ ## Nginx Utilities
146
+
147
+ **File**: `src/utils/nginx.ts`
148
+
149
+ ### `generateNginxConfig(service: ServiceConfig, withHttps: boolean): string`
150
+
151
+ Generates Nginx server block configuration for a service.
152
+
153
+ **Parameters**:
154
+ - `service`: Service configuration
155
+ - `withHttps`: Whether to include HTTPS configuration
156
+
157
+ **Returns**: Nginx configuration as string
158
+
159
+ **Example**:
160
+ ```typescript
161
+ const config = generateNginxConfig(service, true);
162
+ ```
163
+
164
+ **Generated Configuration Includes**:
165
+ - Upstream definition
166
+ - HTTP server (with HTTPS redirect if enabled)
167
+ - HTTPS server (if enabled)
168
+ - SSL configuration (if enabled)
169
+ - Proxy settings
170
+ - Health check endpoint (if configured)
171
+ - Logging configuration
172
+
173
+ ### `enableSite(siteName: string, configPath: string): Promise<void>`
174
+
175
+ Enables an Nginx site by creating a symbolic link in `sites-enabled`.
176
+
177
+ **Parameters**:
178
+ - `siteName`: Name of the site (without .conf extension)
179
+ - `configPath`: Path to sites-available directory
180
+
181
+ **Returns**: Promise that resolves when site is enabled
182
+
183
+ **Example**:
184
+ ```typescript
185
+ await enableSite('my-service', '/etc/nginx/sites-available');
186
+ ```
187
+
188
+ ### `disableSite(siteName: string, configPath: string): Promise<void>`
189
+
190
+ Disables an Nginx site by removing the symbolic link.
191
+
192
+ **Parameters**:
193
+ - `siteName`: Name of the site
194
+ - `configPath`: Path to sites-available directory
195
+
196
+ **Returns**: Promise that resolves when site is disabled
197
+
198
+ **Example**:
199
+ ```typescript
200
+ await disableSite('my-service', '/etc/nginx/sites-available');
201
+ ```
202
+
203
+ ### `reloadNginx(reloadCommand: string): Promise<void>`
204
+
205
+ Tests and reloads Nginx configuration.
206
+
207
+ **Parameters**:
208
+ - `reloadCommand`: Command to execute for reloading
209
+
210
+ **Returns**: Promise that resolves when Nginx is reloaded
211
+
212
+ **Throws**: Error if Nginx configuration test fails or reload fails
213
+
214
+ **Example**:
215
+ ```typescript
216
+ await reloadNginx('sudo nginx -t && sudo systemctl reload nginx');
217
+ ```
218
+
219
+ ## Certbot Utilities
220
+
221
+ **File**: `src/utils/certbot.ts`
222
+
223
+ ### `requestCertificate(domain: string, email: string, staging?: boolean): Promise<void>`
224
+
225
+ Requests an SSL certificate from Let's Encrypt using Certbot.
226
+
227
+ **Parameters**:
228
+ - `domain`: Domain name for the certificate
229
+ - `email`: Email address for certificate notifications
230
+ - `staging`: Use staging environment (default: false)
231
+
232
+ **Returns**: Promise that resolves when certificate is obtained
233
+
234
+ **Throws**: Error if certificate request fails
235
+
236
+ **Example**:
237
+ ```typescript
238
+ await requestCertificate('example.com', 'admin@example.com', false);
239
+ ```
240
+
241
+ ### `renewCertificates(): Promise<void>`
242
+
243
+ Renews all SSL certificates that are due for renewal.
244
+
245
+ **Returns**: Promise that resolves when renewal is complete
246
+
247
+ **Throws**: Error if renewal fails
248
+
249
+ **Example**:
250
+ ```typescript
251
+ await renewCertificates();
252
+ ```
253
+
254
+ ### `checkCertificateExpiration(domain: string): Promise<Date | null>`
255
+
256
+ Checks the expiration date of a certificate for a domain.
257
+
258
+ **Parameters**:
259
+ - `domain`: Domain name to check
260
+
261
+ **Returns**: Promise resolving to expiration date or `null` if not found
262
+
263
+ **Example**:
264
+ ```typescript
265
+ const expiry = await checkCertificateExpiration('example.com');
266
+ if (expiry) {
267
+ console.log(`Certificate expires on: ${expiry}`);
268
+ }
269
+ ```
270
+
271
+ ### `revokeCertificate(domain: string): Promise<void>`
272
+
273
+ Revokes an SSL certificate for a domain.
274
+
275
+ **Parameters**:
276
+ - `domain`: Domain name whose certificate to revoke
277
+
278
+ **Returns**: Promise that resolves when certificate is revoked
279
+
280
+ **Throws**: Error if revocation fails
281
+
282
+ **Example**:
283
+ ```typescript
284
+ await revokeCertificate('example.com');
285
+ ```
286
+
287
+ ## Deployment Utilities
288
+
289
+ **File**: `src/utils/deployment.ts`
290
+
291
+ ### `deployService(service: ServiceConfig, deploymentConfig: DeploymentConfig): Promise<void>`
292
+
293
+ Deploys a service using the configured deployment strategy.
294
+
295
+ **Parameters**:
296
+ - `service`: Service configuration
297
+ - `deploymentConfig`: Deployment strategy configuration
298
+
299
+ **Returns**: Promise that resolves when service is deployed
300
+
301
+ **Throws**: Error if deployment fails
302
+
303
+ **Example**:
304
+ ```typescript
305
+ await deployService(service, deploymentConfig);
306
+ ```
307
+
308
+ ### `performHealthCheck(url: string, timeout?: number): Promise<boolean>`
309
+
310
+ Performs a health check on a service endpoint.
311
+
312
+ **Parameters**:
313
+ - `url`: Health check endpoint URL
314
+ - `timeout`: Maximum time to wait in milliseconds (default: 30000)
315
+
316
+ **Returns**: Promise resolving to `true` if healthy, `false` if timeout
317
+
318
+ **Behavior**:
319
+ - Polls endpoint every 2 seconds
320
+ - Returns `true` on first successful (200 OK) response
321
+ - Returns `false` if timeout is exceeded
322
+
323
+ **Example**:
324
+ ```typescript
325
+ const isHealthy = await performHealthCheck('http://localhost:3000/health', 30000);
326
+ ```
327
+
328
+ ### `waitForService(service: ServiceConfig, timeout?: number): Promise<boolean>`
329
+
330
+ Waits for a service to become healthy.
331
+
332
+ **Parameters**:
333
+ - `service`: Service configuration
334
+ - `timeout`: Maximum time to wait in milliseconds (default: 60000)
335
+
336
+ **Returns**: Promise resolving to `true` if service becomes healthy
337
+
338
+ **Example**:
339
+ ```typescript
340
+ const ready = await waitForService(service, 60000);
341
+ ```
342
+
343
+ ### `gracefulShutdown(service: ServiceConfig, timeout?: number): Promise<void>`
344
+
345
+ Gracefully shuts down a service.
346
+
347
+ **Parameters**:
348
+ - `service`: Service configuration
349
+ - `timeout`: Maximum time to wait for shutdown (default: 30000)
350
+
351
+ **Returns**: Promise that resolves when shutdown is complete
352
+
353
+ **Note**: This is a placeholder implementation. Actual implementation depends on service management.
354
+
355
+ **Example**:
356
+ ```typescript
357
+ await gracefulShutdown(service, 30000);
358
+ ```
359
+
360
+ ## Type Definitions
361
+
362
+ **File**: `src/types/config.ts`
363
+
364
+ ### `DeployConfig`
365
+
366
+ Root configuration interface.
367
+
368
+ ```typescript
369
+ interface DeployConfig {
370
+ project: ProjectConfig;
371
+ services: ServiceConfig[];
372
+ nginx: NginxConfig;
373
+ certbot: CertbotConfig;
374
+ deployment: DeploymentConfig;
375
+ }
376
+ ```
377
+
378
+ ### `ProjectConfig`
379
+
380
+ Project metadata.
381
+
382
+ ```typescript
383
+ interface ProjectConfig {
384
+ name: string;
385
+ version: string;
386
+ }
387
+ ```
388
+
389
+ ### `ServiceConfig`
390
+
391
+ Service configuration.
392
+
393
+ ```typescript
394
+ interface ServiceConfig {
395
+ name: string;
396
+ port: number;
397
+ domains: string[];
398
+ docker?: DockerConfig;
399
+ healthCheck?: HealthCheckConfig;
400
+ environment?: Record<string, string>;
401
+ }
402
+ ```
403
+
404
+ ### `DockerConfig`
405
+
406
+ Docker container configuration.
407
+
408
+ ```typescript
409
+ interface DockerConfig {
410
+ image?: string;
411
+ container: string;
412
+ port: number;
413
+ }
414
+ ```
415
+
416
+ ### `HealthCheckConfig`
417
+
418
+ Health check configuration.
419
+
420
+ ```typescript
421
+ interface HealthCheckConfig {
422
+ path: string;
423
+ interval: number;
424
+ }
425
+ ```
426
+
427
+ ### `NginxConfig`
428
+
429
+ Nginx configuration.
430
+
431
+ ```typescript
432
+ interface NginxConfig {
433
+ configPath: string;
434
+ reloadCommand: string;
435
+ }
436
+ ```
437
+
438
+ ### `CertbotConfig`
439
+
440
+ Certbot/SSL configuration.
441
+
442
+ ```typescript
443
+ interface CertbotConfig {
444
+ email: string;
445
+ staging: boolean;
446
+ }
447
+ ```
448
+
449
+ ### `DeploymentConfig`
450
+
451
+ Deployment strategy configuration.
452
+
453
+ ```typescript
454
+ interface DeploymentConfig {
455
+ strategy: 'rolling' | 'blue-green';
456
+ healthCheckTimeout: number;
457
+ }
458
+ ```
459
+
460
+ ## Command Handlers
461
+
462
+ ### `initCommand(options: InitOptions): Promise<void>`
463
+
464
+ **File**: `src/commands/init.ts`
465
+
466
+ Interactive configuration file creation.
467
+
468
+ **Parameters**:
469
+ - `options.file`: Configuration file path (default: 'suthep.yml')
470
+
471
+ ### `setupCommand(options: SetupOptions): Promise<void>`
472
+
473
+ **File**: `src/commands/setup.ts`
474
+
475
+ Install and configure prerequisites.
476
+
477
+ **Parameters**:
478
+ - `options.nginxOnly`: Only setup Nginx
479
+ - `options.certbotOnly`: Only setup Certbot
480
+
481
+ ### `deployCommand(options: DeployOptions): Promise<void>`
482
+
483
+ **File**: `src/commands/deploy.ts`
484
+
485
+ Deploy services using configuration.
486
+
487
+ **Parameters**:
488
+ - `options.file`: Configuration file path (default: 'suthep.yml')
489
+ - `options.https`: Enable HTTPS (default: true)
490
+ - `options.nginx`: Configure Nginx (default: true)
491
+
492
+ ## Error Handling
493
+
494
+ All functions throw errors with descriptive messages. Common error patterns:
495
+
496
+ - **File operations**: `Error: Configuration file not found: ...`
497
+ - **Docker operations**: `Error: Failed to start Docker container: ...`
498
+ - **Nginx operations**: `Error: Failed to reload Nginx: ...`
499
+ - **Certbot operations**: `Error: Failed to obtain SSL certificate for ...: ...`
500
+ - **Health checks**: `Error: Service ... failed health check ...`
501
+
502
+ ## Usage Examples
503
+
504
+ ### Custom Deployment Script
505
+
506
+ ```typescript
507
+ import { loadConfig } from './utils/config-loader';
508
+ import { startDockerContainer } from './utils/docker';
509
+ import { generateNginxConfig, enableSite, reloadNginx } from './utils/nginx';
510
+ import { requestCertificate } from './utils/certbot';
511
+ import { performHealthCheck } from './utils/deployment';
512
+
513
+ async function customDeploy() {
514
+ const config = await loadConfig('suthep.yml');
515
+
516
+ for (const service of config.services) {
517
+ // Start Docker container
518
+ if (service.docker) {
519
+ await startDockerContainer(service);
520
+ }
521
+
522
+ // Generate and enable Nginx config
523
+ const nginxConfig = generateNginxConfig(service, false);
524
+ // ... write config file ...
525
+ await enableSite(service.name, config.nginx.configPath);
526
+
527
+ // Request certificate
528
+ for (const domain of service.domains) {
529
+ await requestCertificate(domain, config.certbot.email, config.certbot.staging);
530
+ }
531
+
532
+ // Health check
533
+ if (service.healthCheck) {
534
+ const url = `http://localhost:${service.port}${service.healthCheck.path}`;
535
+ const healthy = await performHealthCheck(url, 30000);
536
+ if (!healthy) {
537
+ throw new Error(`Service ${service.name} is not healthy`);
538
+ }
539
+ }
540
+
541
+ // Reload Nginx
542
+ await reloadNginx(config.nginx.reloadCommand);
543
+ }
544
+ }
545
+ ```