shyp 0.1.0 → 0.1.5

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 (124) hide show
  1. package/README.md +46 -3
  2. package/dist/cli.d.ts +0 -1
  3. package/dist/cli.js +2 -3
  4. package/dist/commands/add.d.ts +0 -1
  5. package/dist/commands/add.js +140 -8
  6. package/dist/commands/deploy.d.ts +0 -1
  7. package/dist/commands/deploy.js +0 -1
  8. package/dist/commands/doctor.d.ts +0 -1
  9. package/dist/commands/doctor.js +0 -1
  10. package/dist/commands/index.d.ts +0 -1
  11. package/dist/commands/index.js +0 -1
  12. package/dist/commands/init.d.ts +0 -1
  13. package/dist/commands/init.js +0 -1
  14. package/dist/commands/logs.d.ts +0 -1
  15. package/dist/commands/logs.js +0 -1
  16. package/dist/commands/ports.d.ts +0 -1
  17. package/dist/commands/ports.js +0 -1
  18. package/dist/commands/start.d.ts +0 -1
  19. package/dist/commands/start.js +0 -1
  20. package/dist/commands/status.d.ts +0 -1
  21. package/dist/commands/status.js +38 -9
  22. package/dist/commands/sync.d.ts +0 -1
  23. package/dist/commands/sync.js +44 -3
  24. package/dist/index.d.ts +0 -1
  25. package/dist/index.js +0 -1
  26. package/dist/lib/config.d.ts +0 -1
  27. package/dist/lib/config.js +0 -1
  28. package/dist/lib/deploy.d.ts +0 -1
  29. package/dist/lib/deploy.js +0 -1
  30. package/dist/lib/git.d.ts +0 -1
  31. package/dist/lib/git.js +0 -1
  32. package/dist/lib/index.d.ts +1 -1
  33. package/dist/lib/index.js +1 -1
  34. package/dist/lib/nginx.d.ts +0 -1
  35. package/dist/lib/nginx.js +0 -1
  36. package/dist/lib/pm2.d.ts +0 -1
  37. package/dist/lib/pm2.js +0 -1
  38. package/dist/lib/ssl.d.ts +22 -0
  39. package/dist/lib/ssl.js +115 -0
  40. package/dist/lib/state.d.ts +0 -1
  41. package/dist/lib/state.js +0 -1
  42. package/dist/schemas/app.d.ts +0 -1
  43. package/dist/schemas/app.js +0 -1
  44. package/dist/schemas/config.d.ts +15 -16
  45. package/dist/schemas/config.js +1 -2
  46. package/dist/schemas/engine.d.ts +0 -1
  47. package/dist/schemas/engine.js +0 -1
  48. package/dist/schemas/index.d.ts +0 -1
  49. package/dist/schemas/index.js +0 -1
  50. package/dist/schemas/state.d.ts +0 -1
  51. package/dist/schemas/state.js +0 -1
  52. package/dist/server/index.d.ts +0 -1
  53. package/dist/server/index.js +0 -1
  54. package/dist/server/webhook.d.ts +0 -1
  55. package/dist/server/webhook.js +0 -1
  56. package/dist/utils/index.d.ts +0 -1
  57. package/dist/utils/index.js +0 -1
  58. package/dist/utils/logger.d.ts +0 -1
  59. package/dist/utils/logger.js +0 -1
  60. package/dist/utils/paths.d.ts +0 -1
  61. package/dist/utils/paths.js +0 -1
  62. package/dist/utils/spinner.d.ts +0 -1
  63. package/dist/utils/spinner.js +0 -1
  64. package/package.json +2 -1
  65. package/dist/cli.d.ts.map +0 -1
  66. package/dist/cli.js.map +0 -1
  67. package/dist/commands/add.d.ts.map +0 -1
  68. package/dist/commands/add.js.map +0 -1
  69. package/dist/commands/deploy.d.ts.map +0 -1
  70. package/dist/commands/deploy.js.map +0 -1
  71. package/dist/commands/doctor.d.ts.map +0 -1
  72. package/dist/commands/doctor.js.map +0 -1
  73. package/dist/commands/index.d.ts.map +0 -1
  74. package/dist/commands/index.js.map +0 -1
  75. package/dist/commands/init.d.ts.map +0 -1
  76. package/dist/commands/init.js.map +0 -1
  77. package/dist/commands/logs.d.ts.map +0 -1
  78. package/dist/commands/logs.js.map +0 -1
  79. package/dist/commands/ports.d.ts.map +0 -1
  80. package/dist/commands/ports.js.map +0 -1
  81. package/dist/commands/start.d.ts.map +0 -1
  82. package/dist/commands/start.js.map +0 -1
  83. package/dist/commands/status.d.ts.map +0 -1
  84. package/dist/commands/status.js.map +0 -1
  85. package/dist/commands/sync.d.ts.map +0 -1
  86. package/dist/commands/sync.js.map +0 -1
  87. package/dist/index.d.ts.map +0 -1
  88. package/dist/index.js.map +0 -1
  89. package/dist/lib/config.d.ts.map +0 -1
  90. package/dist/lib/config.js.map +0 -1
  91. package/dist/lib/deploy.d.ts.map +0 -1
  92. package/dist/lib/deploy.js.map +0 -1
  93. package/dist/lib/git.d.ts.map +0 -1
  94. package/dist/lib/git.js.map +0 -1
  95. package/dist/lib/index.d.ts.map +0 -1
  96. package/dist/lib/index.js.map +0 -1
  97. package/dist/lib/nginx.d.ts.map +0 -1
  98. package/dist/lib/nginx.js.map +0 -1
  99. package/dist/lib/pm2.d.ts.map +0 -1
  100. package/dist/lib/pm2.js.map +0 -1
  101. package/dist/lib/state.d.ts.map +0 -1
  102. package/dist/lib/state.js.map +0 -1
  103. package/dist/schemas/app.d.ts.map +0 -1
  104. package/dist/schemas/app.js.map +0 -1
  105. package/dist/schemas/config.d.ts.map +0 -1
  106. package/dist/schemas/config.js.map +0 -1
  107. package/dist/schemas/engine.d.ts.map +0 -1
  108. package/dist/schemas/engine.js.map +0 -1
  109. package/dist/schemas/index.d.ts.map +0 -1
  110. package/dist/schemas/index.js.map +0 -1
  111. package/dist/schemas/state.d.ts.map +0 -1
  112. package/dist/schemas/state.js.map +0 -1
  113. package/dist/server/index.d.ts.map +0 -1
  114. package/dist/server/index.js.map +0 -1
  115. package/dist/server/webhook.d.ts.map +0 -1
  116. package/dist/server/webhook.js.map +0 -1
  117. package/dist/utils/index.d.ts.map +0 -1
  118. package/dist/utils/index.js.map +0 -1
  119. package/dist/utils/logger.d.ts.map +0 -1
  120. package/dist/utils/logger.js.map +0 -1
  121. package/dist/utils/paths.d.ts.map +0 -1
  122. package/dist/utils/paths.js.map +0 -1
  123. package/dist/utils/spinner.d.ts.map +0 -1
  124. package/dist/utils/spinner.js.map +0 -1
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  <p align="center">
12
12
  From code to production. Shyp now.<br>
13
- AI-native deployment for Node.js apps on Linux VPS.
13
+ AI-native deployment for Node.js apps on Linux.
14
14
  </p>
15
15
 
16
16
  <p align="center">
@@ -37,7 +37,7 @@
37
37
  - Nginx (optional, for domains)
38
38
  - Git
39
39
 
40
- > ⚠️ **Windows is not supported.** Shyp is designed for Linux VPS deployment.
40
+ > ⚠️ **Windows is not supported.** Shyp is designed for Linux deployment.
41
41
 
42
42
  ## Installation
43
43
 
@@ -45,6 +45,48 @@
45
45
  npm install -g shyp
46
46
  ```
47
47
 
48
+ ## Before You Deploy
49
+
50
+ Before adding your first app, complete this checklist:
51
+
52
+ ### 1. DNS Configuration
53
+ Point your domain to your server:
54
+ - Create an **A record** pointing `yourdomain.com` → `your-server-ip`
55
+ - Optional: Add a **www** subdomain if needed
56
+
57
+ ### 2. Email Forwarding
58
+ Set up email forwarding for SSL certificate notifications:
59
+ - Create `contact@yourdomain.com` forwarding to your real email
60
+ - This is used by Let's Encrypt for certificate expiry warnings
61
+
62
+ ### 3. GitHub SSH Key
63
+ Ensure your server can pull from GitHub:
64
+ ```bash
65
+ # Generate a deploy key (if you haven't already)
66
+ ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_myapp -N ""
67
+
68
+ # Add the public key to your repo
69
+ cat ~/.ssh/id_ed25519_myapp.pub
70
+ # → GitHub repo → Settings → Deploy keys → Add deploy key
71
+ ```
72
+
73
+ ### 4. Webhook Secret (for auto-deploy)
74
+ Generate a shared secret for GitHub webhooks:
75
+ ```bash
76
+ # Generate a random secret
77
+ openssl rand -hex 32
78
+
79
+ # Set it on your server
80
+ export SHYP_WEBHOOK_SECRET=your-generated-secret
81
+ ```
82
+
83
+ Then configure the webhook in GitHub:
84
+ 1. Go to your repo → **Settings** → **Webhooks** → **Add webhook**
85
+ 2. **Payload URL:** `http://your-server-ip:9000/`
86
+ 3. **Content type:** `application/json`
87
+ 4. **Secret:** Your `SHYP_WEBHOOK_SECRET`
88
+ 5. **Events:** Just the push event
89
+
48
90
  ## Quick Start
49
91
 
50
92
  ```bash
@@ -93,7 +135,7 @@ landing-page ● online 3003 45MB 12d 3h example.com
93
135
  | `shyp status` | Show status of all apps |
94
136
  | `shyp deploy <name>` | Deploy an app |
95
137
  | `shyp add <name>` | Add a new app configuration |
96
- | `shyp sync` | Apply configs to PM2 + Nginx |
138
+ | `shyp sync` | Sync configs, provision SSL certs, reload Nginx |
97
139
  | `shyp ports` | Show port allocations |
98
140
  | `shyp logs <name>` | View deployment logs |
99
141
  | `shyp doctor` | Check system health |
@@ -209,6 +251,7 @@ shyp deploy new-project
209
251
  ## Links
210
252
 
211
253
  - **Website:** [shyp.now](https://shyp.now)
254
+ - **Documentation:** [shyp.now/docs](https://shyp.now/docs)
212
255
  - **GitHub:** [github.com/shypd/shyp](https://github.com/shypd/shyp)
213
256
  - **Issues:** [github.com/shypd/shyp/issues](https://github.com/shypd/shyp/issues)
214
257
  - **npm:** [npmjs.com/package/shyp](https://www.npmjs.com/package/shyp)
package/dist/cli.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  #!/usr/bin/env node
2
2
  export {};
3
- //# sourceMappingURL=cli.d.ts.map
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { statusCommand, deployCommand, portsCommand, doctorCommand, initCommand,
4
4
  program
5
5
  .name('shyp')
6
6
  .description('Zero friction deployment for Node.js apps')
7
- .version('0.1.0');
7
+ .version('0.1.4');
8
8
  // shyp status
9
9
  program
10
10
  .command('status')
@@ -40,7 +40,7 @@ program
40
40
  // shyp sync
41
41
  program
42
42
  .command('sync')
43
- .description('Apply all configs to PM2 and Nginx')
43
+ .description('Sync configs, provision SSL certs, reload Nginx')
44
44
  .option('-n, --dry-run', 'Show what would be done without making changes')
45
45
  .action(syncCommand);
46
46
  // shyp logs <name>
@@ -61,4 +61,3 @@ program
61
61
  .action(addCommand);
62
62
  // Parse arguments
63
63
  program.parse();
64
- //# sourceMappingURL=cli.js.map
@@ -6,4 +6,3 @@ interface AddOptions {
6
6
  }
7
7
  export declare function addCommand(name: string, options: AddOptions): Promise<void>;
8
8
  export {};
9
- //# sourceMappingURL=add.d.ts.map
@@ -2,9 +2,124 @@ import { writeFile } from 'fs/promises';
2
2
  import { existsSync } from 'fs';
3
3
  import { stringify as yamlStringify } from 'yaml';
4
4
  import chalk from 'chalk';
5
+ import { input, select, confirm } from '@inquirer/prompts';
5
6
  import { isInitialized, getAppConfigPath } from '../lib/config.js';
6
7
  import { allocatePort } from '../lib/state.js';
7
8
  import { log } from '../utils/logger.js';
9
+ function showPrerequisites() {
10
+ console.log();
11
+ console.log(chalk.bold.cyan('Before You Deploy'));
12
+ console.log(chalk.dim('─'.repeat(60)));
13
+ console.log();
14
+ console.log(chalk.yellow('Complete this checklist before adding your app:'));
15
+ console.log();
16
+ // 1. DNS
17
+ console.log(chalk.bold('1. DNS Configuration'));
18
+ console.log(chalk.dim(' Point your domain to your server\'s IP address:'));
19
+ console.log();
20
+ console.log(chalk.dim(' Go to your domain registrar (Namecheap, Cloudflare, etc.)'));
21
+ console.log(chalk.dim(' → DNS settings → Add record:'));
22
+ console.log(chalk.white(' Type: A'));
23
+ console.log(chalk.white(' Host: @ (or leave blank for root domain)'));
24
+ console.log(chalk.white(' Value: YOUR_SERVER_IP'));
25
+ console.log(chalk.white(' TTL: Automatic'));
26
+ console.log();
27
+ // 2. Email
28
+ console.log(chalk.bold('2. Email Forwarding (for SSL notifications)'));
29
+ console.log(chalk.dim(' Let\'s Encrypt sends certificate expiry warnings to contact@yourdomain.com'));
30
+ console.log();
31
+ console.log(chalk.dim(' Option A: Domain registrar email forwarding'));
32
+ console.log(chalk.dim(' → Email settings → Add forwarder:'));
33
+ console.log(chalk.white(' contact@yourdomain.com → your-real-email@gmail.com'));
34
+ console.log();
35
+ console.log(chalk.dim(' Option B: Use a different email in the wizard below'));
36
+ console.log();
37
+ // 3. SSH Key
38
+ console.log(chalk.bold('3. GitHub Deploy Key'));
39
+ console.log(chalk.dim(' Your server needs permission to pull from your GitHub repo.'));
40
+ console.log();
41
+ console.log(chalk.dim(' On your server, run:'));
42
+ console.log(chalk.white(' ssh-keygen -t ed25519 -f ~/.ssh/deploy_key -N ""'));
43
+ console.log(chalk.white(' cat ~/.ssh/deploy_key.pub'));
44
+ console.log();
45
+ console.log(chalk.dim(' Copy the public key, then in GitHub:'));
46
+ console.log(chalk.dim(' → Your repo → Settings → Deploy keys → Add deploy key'));
47
+ console.log(chalk.white(' Title: "My Server"'));
48
+ console.log(chalk.white(' Key: (paste the public key)'));
49
+ console.log(chalk.white(' Allow write access: No (leave unchecked)'));
50
+ console.log();
51
+ // 4. Webhook
52
+ console.log(chalk.bold('4. GitHub Webhook (optional - for auto-deploy on push)'));
53
+ console.log(chalk.dim(' Automatically deploy when you push to GitHub.'));
54
+ console.log();
55
+ console.log(chalk.dim(' First, generate a secret on your server:'));
56
+ console.log(chalk.white(' openssl rand -hex 32'));
57
+ console.log(chalk.dim(' Save this secret! Add it to your server environment:'));
58
+ console.log(chalk.white(' export SHYP_WEBHOOK_SECRET=your-generated-secret'));
59
+ console.log();
60
+ console.log(chalk.dim(' Then in GitHub:'));
61
+ console.log(chalk.dim(' → Your repo → Settings → Webhooks → Add webhook'));
62
+ console.log(chalk.white(' Payload URL: http://YOUR_SERVER_IP:9000/'));
63
+ console.log(chalk.white(' Content type: application/json'));
64
+ console.log(chalk.white(' Secret: (paste your SHYP_WEBHOOK_SECRET)'));
65
+ console.log(chalk.white(' Events: Just the push event'));
66
+ console.log(chalk.white(' Active: Yes'));
67
+ console.log();
68
+ console.log(chalk.dim(' After setup, run: shyp start'));
69
+ console.log();
70
+ }
71
+ async function runWizard(name) {
72
+ showPrerequisites();
73
+ const proceed = await confirm({
74
+ message: 'Have you completed the prerequisites above?',
75
+ default: true
76
+ });
77
+ if (!proceed) {
78
+ console.log();
79
+ log.info('Complete the prerequisites first, then run shyp add again');
80
+ process.exit(0);
81
+ }
82
+ console.log();
83
+ console.log(chalk.bold.cyan(`Adding new app: ${name}`));
84
+ console.log(chalk.dim('─'.repeat(50)));
85
+ console.log();
86
+ // Repository URL
87
+ const repo = await input({
88
+ message: 'GitHub repository URL:',
89
+ default: `git@github.com:YOUR_ORG/${name}.git`,
90
+ validate: (value) => {
91
+ if (!value.includes('github.com') && !value.startsWith('git@')) {
92
+ return 'Please enter a valid GitHub repository URL';
93
+ }
94
+ return true;
95
+ }
96
+ });
97
+ // Domain
98
+ const domain = await input({
99
+ message: 'Domain name (leave empty for no domain):',
100
+ default: ''
101
+ });
102
+ // Email for SSL (only if domain provided)
103
+ let email;
104
+ if (domain) {
105
+ email = await input({
106
+ message: 'Email for SSL certificates:',
107
+ default: `contact@${domain}`
108
+ });
109
+ }
110
+ // App type
111
+ const type = await select({
112
+ message: 'Application type:',
113
+ choices: [
114
+ { name: 'Next.js', value: 'nextjs', description: 'Next.js application with npm start' },
115
+ { name: 'Node.js', value: 'node', description: 'Standard Node.js application' },
116
+ { name: 'Static', value: 'static', description: 'Static files served by Nginx' },
117
+ { name: 'Script', value: 'script', description: 'Custom deploy script' }
118
+ ],
119
+ default: 'nextjs'
120
+ });
121
+ return { repo, domain: domain || undefined, email, type };
122
+ }
8
123
  export async function addCommand(name, options) {
9
124
  log.banner();
10
125
  if (!isInitialized()) {
@@ -17,20 +132,37 @@ export async function addCommand(name, options) {
17
132
  log.dim(`Config: ${configPath}`);
18
133
  process.exit(1);
19
134
  }
135
+ // Check if we should run the wizard (no options provided)
136
+ const hasOptions = options.repo || options.domain || options.type || options.port;
137
+ let repo = options.repo;
138
+ let domain = options.domain;
139
+ let type = options.type || 'nextjs';
140
+ let email;
141
+ if (!hasOptions) {
142
+ // Run interactive wizard
143
+ const wizardResult = await runWizard(name);
144
+ repo = wizardResult.repo;
145
+ domain = wizardResult.domain;
146
+ type = wizardResult.type;
147
+ email = wizardResult.email;
148
+ }
20
149
  // Allocate port if not specified
21
150
  const port = options.port || await allocatePort(name, 'standard');
22
151
  // Build config
23
152
  const config = {
24
153
  name,
25
154
  description: `${name} application`,
26
- repo: options.repo || `git@github.com:YOUR_ORG/${name}.git`,
155
+ repo: repo || `git@github.com:YOUR_ORG/${name}.git`,
27
156
  branch: 'main',
28
157
  path: `/var/www/${name}`,
29
- type: options.type || 'nextjs',
158
+ type,
30
159
  port,
31
160
  };
32
- if (options.domain) {
33
- config.domain = options.domain;
161
+ if (domain) {
162
+ config.domain = domain;
163
+ }
164
+ if (email) {
165
+ config.ssl = { email };
34
166
  }
35
167
  config.build = {
36
168
  command: 'npm ci && npm run build',
@@ -52,6 +184,7 @@ export async function addCommand(name, options) {
52
184
  // Write config file
53
185
  const yaml = yamlStringify(config);
54
186
  await writeFile(configPath, yaml);
187
+ console.log();
55
188
  log.success(`Created app config: ${name}`);
56
189
  console.log();
57
190
  console.log(chalk.dim('Config file:'));
@@ -61,9 +194,8 @@ export async function addCommand(name, options) {
61
194
  console.log(chalk.cyan(yaml));
62
195
  console.log();
63
196
  log.info('Next steps:');
64
- console.log(chalk.dim(` 1. Edit the config: nano ${configPath}`));
65
- console.log(chalk.dim(` 2. Apply changes: shyp sync`));
66
- console.log(chalk.dim(` 3. Deploy: shyp deploy ${name}`));
197
+ console.log(chalk.dim(` 1. Review the config: nano ${configPath}`));
198
+ console.log(chalk.dim(` 2. Apply changes: shyp sync`));
199
+ console.log(chalk.dim(` 3. Deploy: shyp deploy ${name}`));
67
200
  console.log();
68
201
  }
69
- //# sourceMappingURL=add.js.map
@@ -1,4 +1,3 @@
1
1
  export declare function deployCommand(name: string, options: {
2
2
  module?: string;
3
3
  }): Promise<void>;
4
- //# sourceMappingURL=deploy.d.ts.map
@@ -101,4 +101,3 @@ async function deployEngineModule(engineName, moduleName) {
101
101
  process.exit(1);
102
102
  }
103
103
  }
104
- //# sourceMappingURL=deploy.js.map
@@ -1,2 +1 @@
1
1
  export declare function doctorCommand(): Promise<void>;
2
- //# sourceMappingURL=doctor.d.ts.map
@@ -94,4 +94,3 @@ export async function doctorCommand() {
94
94
  log.success('All checks passed!');
95
95
  }
96
96
  }
97
- //# sourceMappingURL=doctor.js.map
@@ -7,4 +7,3 @@ export { startCommand } from './start.js';
7
7
  export { syncCommand } from './sync.js';
8
8
  export { logsCommand } from './logs.js';
9
9
  export { addCommand } from './add.js';
10
- //# sourceMappingURL=index.d.ts.map
@@ -7,4 +7,3 @@ export { startCommand } from './start.js';
7
7
  export { syncCommand } from './sync.js';
8
8
  export { logsCommand } from './logs.js';
9
9
  export { addCommand } from './add.js';
10
- //# sourceMappingURL=index.js.map
@@ -1,4 +1,3 @@
1
1
  export declare function initCommand(options: {
2
2
  force?: boolean;
3
3
  }): Promise<void>;
4
- //# sourceMappingURL=init.d.ts.map
@@ -147,4 +147,3 @@ export async function initCommand(options) {
147
147
  throw error;
148
148
  }
149
149
  }
150
- //# sourceMappingURL=init.js.map
@@ -2,4 +2,3 @@ export declare function logsCommand(name: string, options: {
2
2
  follow?: boolean;
3
3
  lines?: number;
4
4
  }): Promise<void>;
5
- //# sourceMappingURL=logs.d.ts.map
@@ -53,4 +53,3 @@ export async function logsCommand(name, options) {
53
53
  log.dim(`${logFiles.length} deployment logs available in ${logDir}`);
54
54
  }
55
55
  }
56
- //# sourceMappingURL=logs.js.map
@@ -1,2 +1 @@
1
1
  export declare function portsCommand(): Promise<void>;
2
- //# sourceMappingURL=ports.d.ts.map
@@ -70,4 +70,3 @@ export async function portsCommand() {
70
70
  }
71
71
  console.log();
72
72
  }
73
- //# sourceMappingURL=ports.js.map
@@ -1,2 +1 @@
1
1
  export declare function startCommand(): Promise<void>;
2
- //# sourceMappingURL=start.d.ts.map
@@ -8,4 +8,3 @@ export async function startCommand() {
8
8
  }
9
9
  await startServer();
10
10
  }
11
- //# sourceMappingURL=start.js.map
@@ -1,2 +1 @@
1
1
  export declare function statusCommand(): Promise<void>;
2
- //# sourceMappingURL=status.d.ts.map
@@ -2,6 +2,7 @@ import chalk from 'chalk';
2
2
  import { loadAppConfigs, loadEngineConfigs, isInitialized } from '../lib/config.js';
3
3
  import { listProcesses, formatMemory, formatUptime } from '../lib/pm2.js';
4
4
  import { loadPortAllocations, loadDeployments } from '../lib/state.js';
5
+ import { getCertInfo, formatCertStatus } from '../lib/ssl.js';
5
6
  import { log } from '../utils/logger.js';
6
7
  export async function statusCommand() {
7
8
  log.banner();
@@ -22,11 +23,29 @@ export async function statusCommand() {
22
23
  for (const p of processes) {
23
24
  processMap.set(p.name, p);
24
25
  }
26
+ // Collect all domains for cert checking
27
+ const domains = [];
28
+ for (const [, config] of apps) {
29
+ if (config.domain)
30
+ domains.push(config.domain);
31
+ }
32
+ for (const [, config] of engines) {
33
+ for (const [, mod] of Object.entries(config.modules)) {
34
+ if (mod.domain)
35
+ domains.push(mod.domain);
36
+ }
37
+ }
38
+ // Get cert info for all domains
39
+ const certMap = new Map();
40
+ for (const domain of domains) {
41
+ const info = await getCertInfo(domain);
42
+ certMap.set(domain, info);
43
+ }
25
44
  // Display apps
26
45
  if (apps.size > 0) {
27
46
  console.log(chalk.bold.white('\nApps'));
28
- console.log(chalk.dim('─'.repeat(70)));
29
- console.log(chalk.dim('NAME'.padEnd(20)), chalk.dim('STATUS'.padEnd(12)), chalk.dim('PORT'.padEnd(8)), chalk.dim('MEMORY'.padEnd(10)), chalk.dim('UPTIME'.padEnd(12)), chalk.dim('DOMAIN'));
47
+ console.log(chalk.dim('─'.repeat(80)));
48
+ console.log(chalk.dim('NAME'.padEnd(18)), chalk.dim('STATUS'.padEnd(12)), chalk.dim('PORT'.padEnd(6)), chalk.dim('MEM'.padEnd(8)), chalk.dim('UPTIME'.padEnd(10)), chalk.dim('SSL'.padEnd(6)), chalk.dim('DOMAIN'));
30
49
  for (const [name, config] of apps) {
31
50
  const pm2Name = config.pm2?.name || name;
32
51
  const proc = processMap.get(pm2Name);
@@ -34,20 +53,26 @@ export async function statusCommand() {
34
53
  const status = proc?.status || 'stopped';
35
54
  const statusColor = status === 'online' ? chalk.green : chalk.red;
36
55
  const statusIcon = status === 'online' ? '●' : '○';
37
- console.log(chalk.white(name.padEnd(20)), statusColor(`${statusIcon} ${status}`.padEnd(12)), chalk.cyan(String(port).padEnd(8)), chalk.dim((proc ? formatMemory(proc.memory) : '-').padEnd(10)), chalk.dim((proc ? formatUptime(proc.uptime) : '-').padEnd(12)), chalk.yellow(config.domain || '-'));
56
+ // Get cert status
57
+ const certInfo = config.domain ? certMap.get(config.domain) : null;
58
+ const cert = certInfo ? formatCertStatus(certInfo) : { text: '-', color: 'dim' };
59
+ const certColor = cert.color === 'green' ? chalk.green :
60
+ cert.color === 'yellow' ? chalk.yellow :
61
+ cert.color === 'red' ? chalk.red : chalk.dim;
62
+ console.log(chalk.white(name.padEnd(18)), statusColor(`${statusIcon} ${status}`.padEnd(12)), chalk.cyan(String(port).padEnd(6)), chalk.dim((proc ? formatMemory(proc.memory) : '-').padEnd(8)), chalk.dim((proc ? formatUptime(proc.uptime) : '-').padEnd(10)), certColor(cert.text.padEnd(6)), chalk.yellow(config.domain || '-'));
38
63
  }
39
64
  }
40
65
  // Display engines
41
66
  if (engines.size > 0) {
42
67
  console.log(chalk.bold.white('\nEngines'));
43
- console.log(chalk.dim('─'.repeat(70)));
68
+ console.log(chalk.dim('─'.repeat(80)));
44
69
  for (const [name, config] of engines) {
45
70
  const pm2Name = config.server.pm2?.name || name;
46
71
  const proc = processMap.get(pm2Name);
47
72
  const status = proc?.status || 'stopped';
48
73
  const statusColor = status === 'online' ? chalk.green : chalk.red;
49
74
  const statusIcon = status === 'online' ? '●' : '○';
50
- console.log(chalk.white(name.padEnd(20)), statusColor(`${statusIcon} ${status}`.padEnd(12)), chalk.dim('Engine'), chalk.dim(proc ? formatMemory(proc.memory) : ''));
75
+ console.log(chalk.white(name.padEnd(18)), statusColor(`${statusIcon} ${status}`.padEnd(12)), chalk.dim('Engine'), chalk.dim(proc ? formatMemory(proc.memory) : ''));
51
76
  // Display modules
52
77
  const modules = Object.entries(config.modules);
53
78
  if (modules.length > 0) {
@@ -58,16 +83,20 @@ export async function statusCommand() {
58
83
  const moduleStatus = moduleProc?.status || (status === 'online' ? 'managed' : 'stopped');
59
84
  const moduleStatusColor = moduleStatus === 'online' || moduleStatus === 'managed' ? chalk.green : chalk.red;
60
85
  const moduleIcon = moduleStatus === 'online' || moduleStatus === 'managed' ? '●' : '○';
61
- console.log(chalk.dim(' └─'), chalk.white(moduleName.padEnd(16)), moduleStatusColor(`${moduleIcon} ${moduleStatus}`.padEnd(12)), chalk.cyan(String(moduleConfig.port).padEnd(8)), chalk.yellow(moduleConfig.domain || '-'));
86
+ // Get cert status for module
87
+ const modCertInfo = moduleConfig.domain ? certMap.get(moduleConfig.domain) : null;
88
+ const modCert = modCertInfo ? formatCertStatus(modCertInfo) : { text: '-', color: 'dim' };
89
+ const modCertColor = modCert.color === 'green' ? chalk.green :
90
+ modCert.color === 'yellow' ? chalk.yellow :
91
+ modCert.color === 'red' ? chalk.red : chalk.dim;
92
+ console.log(chalk.dim(' └─'), chalk.white(moduleName.padEnd(14)), moduleStatusColor(`${moduleIcon} ${moduleStatus}`.padEnd(12)), chalk.cyan(String(moduleConfig.port).padEnd(6)), modCertColor(modCert.text.padEnd(6)), chalk.yellow(moduleConfig.domain || '-'));
62
93
  }
63
94
  }
64
95
  }
65
96
  }
66
97
  if (apps.size === 0 && engines.size === 0) {
67
98
  log.dim('\nNo apps or engines configured.');
68
- log.dim('Add an app: shyp add <name>');
69
- log.dim('Import apps: shyp import');
99
+ log.dim('Add an app: shyp add <name>');
70
100
  }
71
101
  console.log();
72
102
  }
73
- //# sourceMappingURL=status.js.map
@@ -1,4 +1,3 @@
1
1
  export declare function syncCommand(options: {
2
2
  dryRun?: boolean;
3
3
  }): Promise<void>;
4
- //# sourceMappingURL=sync.d.ts.map
@@ -1,6 +1,7 @@
1
- import { loadAppConfigs, loadEngineConfigs, isInitialized } from '../lib/config.js';
1
+ import { loadAppConfigs, loadEngineConfigs, loadGlobalConfig, isInitialized } from '../lib/config.js';
2
2
  import { allocatePort } from '../lib/state.js';
3
3
  import { generateNginxConfig, generateModuleConfig, writeNginxConfig, enableNginxConfig, testNginxConfig, reloadNginx, } from '../lib/nginx.js';
4
+ import { getCertInfo, obtainCert, isCertbotAvailable } from '../lib/ssl.js';
4
5
  import { log } from '../utils/logger.js';
5
6
  import { createSpinner } from '../utils/spinner.js';
6
7
  export async function syncCommand(options) {
@@ -14,12 +15,17 @@ export async function syncCommand(options) {
14
15
  log.info('Dry run mode - no changes will be made');
15
16
  console.log();
16
17
  }
17
- const [apps, engines] = await Promise.all([
18
+ const [apps, engines, globalConfig] = await Promise.all([
18
19
  loadAppConfigs(),
19
20
  loadEngineConfigs(),
21
+ loadGlobalConfig(),
20
22
  ]);
23
+ // Get SSL email from config (fallback to contact@domain per-domain)
24
+ const sslEmail = globalConfig?.server?.ssl?.email;
21
25
  // Track what we're doing
22
26
  const actions = [];
27
+ // Collect all domains for SSL
28
+ const domains = [];
23
29
  // Allocate ports for apps that don't have them
24
30
  log.info('Checking port allocations...');
25
31
  for (const [name, config] of apps) {
@@ -28,6 +34,42 @@ export async function syncCommand(options) {
28
34
  config.port = port;
29
35
  actions.push(`Allocated port ${port} for ${name}`);
30
36
  }
37
+ if (config.domain) {
38
+ domains.push(config.domain);
39
+ }
40
+ }
41
+ // Collect engine module domains
42
+ for (const [, engine] of engines) {
43
+ for (const [, moduleConfig] of Object.entries(engine.modules)) {
44
+ if (moduleConfig.domain) {
45
+ domains.push(moduleConfig.domain);
46
+ }
47
+ }
48
+ }
49
+ // Provision SSL certs for domains that need them
50
+ if (domains.length > 0 && !dryRun) {
51
+ log.info('Checking SSL certificates...');
52
+ const hasCertbot = await isCertbotAvailable();
53
+ if (hasCertbot) {
54
+ for (const domain of domains) {
55
+ const certInfo = await getCertInfo(domain);
56
+ if (!certInfo.exists) {
57
+ const spinner = createSpinner(`Obtaining cert for ${domain}...`).start();
58
+ const result = await obtainCert(domain, sslEmail);
59
+ if (result.success) {
60
+ spinner.succeed(`Obtained cert for ${domain}`);
61
+ actions.push(`Obtained SSL cert for ${domain}`);
62
+ }
63
+ else {
64
+ spinner.fail(`Failed to obtain cert for ${domain}`);
65
+ log.dim(` ${result.error}`);
66
+ }
67
+ }
68
+ }
69
+ }
70
+ else {
71
+ log.dim(' certbot not installed - skipping SSL provisioning');
72
+ }
31
73
  }
32
74
  // Generate nginx configs for apps with domains
33
75
  log.info('Generating nginx configs...');
@@ -92,4 +134,3 @@ export async function syncCommand(options) {
92
134
  console.log();
93
135
  log.success(`Sync complete. Applied ${actions.length} changes.`);
94
136
  }
95
- //# sourceMappingURL=sync.js.map
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export * from './schemas/index.js';
2
2
  export * from './lib/index.js';
3
3
  export { startServer } from './server/index.js';
4
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -3,4 +3,3 @@
3
3
  export * from './schemas/index.js';
4
4
  export * from './lib/index.js';
5
5
  export { startServer } from './server/index.js';
6
- //# sourceMappingURL=index.js.map
@@ -7,4 +7,3 @@ export declare function loadEngineConfig(name: string): Promise<EngineConfig | n
7
7
  export declare function isInitialized(): boolean;
8
8
  export declare function getAppConfigPath(name: string): string;
9
9
  export declare function getEngineConfigPath(name: string): string;
10
- //# sourceMappingURL=config.d.ts.map
@@ -113,4 +113,3 @@ export function getAppConfigPath(name) {
113
113
  export function getEngineConfigPath(name) {
114
114
  return join(ENGINES_DIR, `${name}.yaml`);
115
115
  }
116
- //# sourceMappingURL=config.js.map
@@ -9,4 +9,3 @@ export interface DeployResult {
9
9
  export declare function deployApp(config: AppConfig): Promise<DeployResult>;
10
10
  export declare function deployModule(engine: EngineConfig, moduleName: string, moduleConfig: ModuleConfig): Promise<DeployResult>;
11
11
  export declare function deployEngine(engine: EngineConfig): Promise<DeployResult>;
12
- //# sourceMappingURL=deploy.d.ts.map
@@ -285,4 +285,3 @@ export async function deployEngine(engine) {
285
285
  };
286
286
  }
287
287
  }
288
- //# sourceMappingURL=deploy.js.map
package/dist/lib/git.d.ts CHANGED
@@ -21,4 +21,3 @@ export declare function ensureCloned(repo: string, path: string, options?: {
21
21
  branch?: string;
22
22
  sshKey?: string;
23
23
  }): Promise<void>;
24
- //# sourceMappingURL=git.d.ts.map
package/dist/lib/git.js CHANGED
@@ -79,4 +79,3 @@ export async function ensureCloned(repo, path, options = {}) {
79
79
  await clone(repo, path, options);
80
80
  }
81
81
  }
82
- //# sourceMappingURL=git.js.map
@@ -4,4 +4,4 @@ export * from './pm2.js';
4
4
  export * from './git.js';
5
5
  export * from './deploy.js';
6
6
  export * from './nginx.js';
7
- //# sourceMappingURL=index.d.ts.map
7
+ export * from './ssl.js';
package/dist/lib/index.js CHANGED
@@ -4,4 +4,4 @@ export * from './pm2.js';
4
4
  export * from './git.js';
5
5
  export * from './deploy.js';
6
6
  export * from './nginx.js';
7
- //# sourceMappingURL=index.js.map
7
+ export * from './ssl.js';
@@ -13,4 +13,3 @@ export declare function testNginxConfig(): Promise<{
13
13
  }>;
14
14
  export declare function reloadNginx(): Promise<void>;
15
15
  export declare function isNginxAvailable(): Promise<boolean>;
16
- //# sourceMappingURL=nginx.d.ts.map
package/dist/lib/nginx.js CHANGED
@@ -309,4 +309,3 @@ export async function isNginxAvailable() {
309
309
  return false;
310
310
  }
311
311
  }
312
- //# sourceMappingURL=nginx.js.map
package/dist/lib/pm2.d.ts CHANGED
@@ -22,4 +22,3 @@ export declare function saveProcessList(): Promise<void>;
22
22
  export declare function isPM2Available(): Promise<boolean>;
23
23
  export declare function formatMemory(bytes: number): string;
24
24
  export declare function formatUptime(startTime: number): string;
25
- //# sourceMappingURL=pm2.d.ts.map