hostfn 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/dist/__tests__/core/backup.test.d.ts +2 -0
  2. package/dist/__tests__/core/backup.test.d.ts.map +1 -0
  3. package/dist/__tests__/core/backup.test.js +108 -0
  4. package/dist/__tests__/core/backup.test.js.map +1 -0
  5. package/dist/__tests__/core/health.test.d.ts +2 -0
  6. package/dist/__tests__/core/health.test.d.ts.map +1 -0
  7. package/dist/__tests__/core/health.test.js +97 -0
  8. package/dist/__tests__/core/health.test.js.map +1 -0
  9. package/dist/__tests__/core/lock.test.d.ts +2 -0
  10. package/dist/__tests__/core/lock.test.d.ts.map +1 -0
  11. package/dist/__tests__/core/lock.test.js +136 -0
  12. package/dist/__tests__/core/lock.test.js.map +1 -0
  13. package/dist/__tests__/core/nginx-multi-domain.test.d.ts +2 -0
  14. package/dist/__tests__/core/nginx-multi-domain.test.d.ts.map +1 -0
  15. package/dist/__tests__/core/nginx-multi-domain.test.js +158 -0
  16. package/dist/__tests__/core/nginx-multi-domain.test.js.map +1 -0
  17. package/dist/__tests__/runtimes/pm2.test.d.ts +2 -0
  18. package/dist/__tests__/runtimes/pm2.test.d.ts.map +1 -0
  19. package/dist/__tests__/runtimes/pm2.test.js +111 -0
  20. package/dist/__tests__/runtimes/pm2.test.js.map +1 -0
  21. package/dist/__tests__/utils/validation.test.d.ts +2 -0
  22. package/dist/__tests__/utils/validation.test.d.ts.map +1 -0
  23. package/dist/__tests__/utils/validation.test.js +136 -0
  24. package/dist/__tests__/utils/validation.test.js.map +1 -0
  25. package/dist/commands/deploy.d.ts +11 -0
  26. package/dist/commands/deploy.d.ts.map +1 -0
  27. package/dist/commands/deploy.js +636 -0
  28. package/dist/commands/deploy.js.map +1 -0
  29. package/dist/commands/env.d.ts +21 -0
  30. package/dist/commands/env.d.ts.map +1 -0
  31. package/dist/commands/env.js +317 -0
  32. package/dist/commands/env.js.map +1 -0
  33. package/dist/commands/expose.d.ts +6 -0
  34. package/dist/commands/expose.d.ts.map +1 -0
  35. package/dist/commands/expose.js +379 -0
  36. package/dist/commands/expose.js.map +1 -0
  37. package/dist/commands/init.d.ts +2 -0
  38. package/dist/commands/init.d.ts.map +1 -0
  39. package/dist/commands/init.js +175 -0
  40. package/dist/commands/init.js.map +1 -0
  41. package/dist/commands/logs.d.ts +10 -0
  42. package/dist/commands/logs.d.ts.map +1 -0
  43. package/dist/commands/logs.js +75 -0
  44. package/dist/commands/logs.js.map +1 -0
  45. package/dist/commands/rollback.d.ts +6 -0
  46. package/dist/commands/rollback.d.ts.map +1 -0
  47. package/dist/commands/rollback.js +113 -0
  48. package/dist/commands/rollback.js.map +1 -0
  49. package/dist/commands/server/info.d.ts +2 -0
  50. package/dist/commands/server/info.d.ts.map +1 -0
  51. package/dist/commands/server/info.js +104 -0
  52. package/dist/commands/server/info.js.map +1 -0
  53. package/dist/commands/server/setup.d.ts +11 -0
  54. package/dist/commands/server/setup.d.ts.map +1 -0
  55. package/dist/commands/server/setup.js +161 -0
  56. package/dist/commands/server/setup.js.map +1 -0
  57. package/dist/commands/status.d.ts +6 -0
  58. package/dist/commands/status.d.ts.map +1 -0
  59. package/dist/commands/status.js +120 -0
  60. package/dist/commands/status.js.map +1 -0
  61. package/dist/config/loader.d.ts +21 -0
  62. package/dist/config/loader.d.ts.map +1 -0
  63. package/dist/config/loader.js +54 -0
  64. package/dist/config/loader.js.map +1 -0
  65. package/dist/config/schema.d.ts +323 -0
  66. package/dist/config/schema.d.ts.map +1 -0
  67. package/dist/config/schema.js +108 -0
  68. package/dist/config/schema.js.map +1 -0
  69. package/dist/core/backup.d.ts +34 -0
  70. package/dist/core/backup.d.ts.map +1 -0
  71. package/dist/core/backup.js +95 -0
  72. package/dist/core/backup.js.map +1 -0
  73. package/dist/core/health.d.ts +31 -0
  74. package/dist/core/health.d.ts.map +1 -0
  75. package/dist/core/health.js +78 -0
  76. package/dist/core/health.js.map +1 -0
  77. package/dist/core/local.d.ts +19 -0
  78. package/dist/core/local.d.ts.map +1 -0
  79. package/dist/core/local.js +50 -0
  80. package/dist/core/local.js.map +1 -0
  81. package/dist/core/lock.d.ts +28 -0
  82. package/dist/core/lock.d.ts.map +1 -0
  83. package/dist/core/lock.js +89 -0
  84. package/dist/core/lock.js.map +1 -0
  85. package/dist/core/nginx.d.ts +43 -0
  86. package/dist/core/nginx.d.ts.map +1 -0
  87. package/dist/core/nginx.js +131 -0
  88. package/dist/core/nginx.js.map +1 -0
  89. package/dist/core/ssh.d.ts +79 -0
  90. package/dist/core/ssh.d.ts.map +1 -0
  91. package/dist/core/ssh.js +264 -0
  92. package/dist/core/ssh.js.map +1 -0
  93. package/dist/core/sync.d.ts +25 -0
  94. package/dist/core/sync.d.ts.map +1 -0
  95. package/dist/core/sync.js +117 -0
  96. package/dist/core/sync.js.map +1 -0
  97. package/dist/core/workspace.d.ts +13 -0
  98. package/dist/core/workspace.d.ts.map +1 -0
  99. package/dist/core/workspace.js +141 -0
  100. package/dist/core/workspace.js.map +1 -0
  101. package/dist/index.d.ts +3 -0
  102. package/dist/index.d.ts.map +1 -0
  103. package/dist/index.js +232 -0
  104. package/dist/index.js.map +1 -0
  105. package/dist/runtimes/base.d.ts +115 -0
  106. package/dist/runtimes/base.d.ts.map +1 -0
  107. package/dist/runtimes/base.js +16 -0
  108. package/dist/runtimes/base.js.map +1 -0
  109. package/dist/runtimes/nodejs/detector.d.ts +47 -0
  110. package/dist/runtimes/nodejs/detector.d.ts.map +1 -0
  111. package/dist/runtimes/nodejs/detector.js +143 -0
  112. package/dist/runtimes/nodejs/detector.js.map +1 -0
  113. package/dist/runtimes/nodejs/index.d.ts +14 -0
  114. package/dist/runtimes/nodejs/index.d.ts.map +1 -0
  115. package/dist/runtimes/nodejs/index.js +213 -0
  116. package/dist/runtimes/nodejs/index.js.map +1 -0
  117. package/dist/runtimes/nodejs/pm2.d.ts +17 -0
  118. package/dist/runtimes/nodejs/pm2.d.ts.map +1 -0
  119. package/dist/runtimes/nodejs/pm2.js +60 -0
  120. package/dist/runtimes/nodejs/pm2.js.map +1 -0
  121. package/dist/runtimes/registry.d.ts +34 -0
  122. package/dist/runtimes/registry.d.ts.map +1 -0
  123. package/dist/runtimes/registry.js +58 -0
  124. package/dist/runtimes/registry.js.map +1 -0
  125. package/dist/utils/logger.d.ts +47 -0
  126. package/dist/utils/logger.d.ts.map +1 -0
  127. package/dist/utils/logger.js +76 -0
  128. package/dist/utils/logger.js.map +1 -0
  129. package/dist/utils/validation.d.ts +32 -0
  130. package/dist/utils/validation.d.ts.map +1 -0
  131. package/dist/utils/validation.js +125 -0
  132. package/dist/utils/validation.js.map +1 -0
  133. package/package.json +33 -16
  134. package/LICENSE +0 -21
  135. package/README.md +0 -1136
  136. package/_conduct/specs/1.v0.spec.md +0 -1041
  137. package/examples/express-api/package.json +0 -22
  138. package/examples/express-api/src/index.ts +0 -16
  139. package/examples/express-api/tsconfig.json +0 -11
  140. package/examples/github-actions-deploy.yml +0 -40
  141. package/examples/monorepo-config.json +0 -76
  142. package/examples/monorepo-multi-server-config.json +0 -74
  143. package/packages/cli/package.json +0 -40
  144. package/turbo.json +0 -24
  145. /package/{packages/cli/src → src}/__tests__/core/backup.test.ts +0 -0
  146. /package/{packages/cli/src → src}/__tests__/core/health.test.ts +0 -0
  147. /package/{packages/cli/src → src}/__tests__/core/lock.test.ts +0 -0
  148. /package/{packages/cli/src → src}/__tests__/core/nginx-multi-domain.test.ts +0 -0
  149. /package/{packages/cli/src → src}/__tests__/runtimes/pm2.test.ts +0 -0
  150. /package/{packages/cli/src → src}/__tests__/utils/validation.test.ts +0 -0
  151. /package/{packages/cli/src → src}/commands/deploy.ts +0 -0
  152. /package/{packages/cli/src → src}/commands/env.ts +0 -0
  153. /package/{packages/cli/src → src}/commands/expose.ts +0 -0
  154. /package/{packages/cli/src → src}/commands/init.ts +0 -0
  155. /package/{packages/cli/src → src}/commands/logs.ts +0 -0
  156. /package/{packages/cli/src → src}/commands/rollback.ts +0 -0
  157. /package/{packages/cli/src → src}/commands/server/info.ts +0 -0
  158. /package/{packages/cli/src → src}/commands/server/setup.ts +0 -0
  159. /package/{packages/cli/src → src}/commands/status.ts +0 -0
  160. /package/{packages/cli/src → src}/config/loader.ts +0 -0
  161. /package/{packages/cli/src → src}/config/schema.ts +0 -0
  162. /package/{packages/cli/src → src}/core/backup.ts +0 -0
  163. /package/{packages/cli/src → src}/core/health.ts +0 -0
  164. /package/{packages/cli/src → src}/core/local.ts +0 -0
  165. /package/{packages/cli/src → src}/core/lock.ts +0 -0
  166. /package/{packages/cli/src → src}/core/nginx.ts +0 -0
  167. /package/{packages/cli/src → src}/core/ssh.ts +0 -0
  168. /package/{packages/cli/src → src}/core/sync.ts +0 -0
  169. /package/{packages/cli/src → src}/core/workspace.ts +0 -0
  170. /package/{packages/cli/src → src}/index.ts +0 -0
  171. /package/{packages/cli/src → src}/runtimes/base.ts +0 -0
  172. /package/{packages/cli/src → src}/runtimes/nodejs/detector.ts +0 -0
  173. /package/{packages/cli/src → src}/runtimes/nodejs/index.ts +0 -0
  174. /package/{packages/cli/src → src}/runtimes/nodejs/pm2.ts +0 -0
  175. /package/{packages/cli/src → src}/runtimes/registry.ts +0 -0
  176. /package/{packages/cli/src → src}/utils/logger.ts +0 -0
  177. /package/{packages/cli/src → src}/utils/validation.ts +0 -0
  178. /package/{packages/cli/tsconfig.json → tsconfig.json} +0 -0
  179. /package/{packages/cli/vitest.config.ts → vitest.config.ts} +0 -0
@@ -0,0 +1,34 @@
1
+ import { SSHConnection } from './ssh.js';
2
+ export interface BackupOptions {
3
+ keep?: number;
4
+ }
5
+ /**
6
+ * Backup manager for deployments
7
+ */
8
+ export declare class BackupManager {
9
+ private ssh;
10
+ private appDir;
11
+ private backupDir;
12
+ constructor(ssh: SSHConnection, appDir: string);
13
+ /**
14
+ * Create backup of current deployment
15
+ */
16
+ create(): Promise<string>;
17
+ /**
18
+ * List all backups
19
+ */
20
+ list(): Promise<string[]>;
21
+ /**
22
+ * Restore from backup
23
+ */
24
+ restore(backupName: string): Promise<void>;
25
+ /**
26
+ * Clean up old backups (keep only last N)
27
+ */
28
+ cleanup(keep?: number): Promise<void>;
29
+ /**
30
+ * Get most recent backup
31
+ */
32
+ getLatest(): Promise<string | null>;
33
+ }
34
+ //# sourceMappingURL=backup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../../src/core/backup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAAgB;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;gBAEd,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM;IAM9C;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IA6B/B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAqB/B;;OAEG;IACG,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBhD;;OAEG;IACG,OAAO,CAAC,IAAI,GAAE,MAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB9C;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAI1C"}
@@ -0,0 +1,95 @@
1
+ import { Logger } from '../utils/logger.js';
2
+ /**
3
+ * Backup manager for deployments
4
+ */
5
+ export class BackupManager {
6
+ ssh;
7
+ appDir;
8
+ backupDir;
9
+ constructor(ssh, appDir) {
10
+ this.ssh = ssh;
11
+ this.appDir = appDir;
12
+ this.backupDir = `${appDir}/backups`;
13
+ }
14
+ /**
15
+ * Create backup of current deployment
16
+ */
17
+ async create() {
18
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
19
+ const backupPath = `${this.backupDir}/${timestamp}`;
20
+ // Create backup directory if it doesn't exist
21
+ await this.ssh.mkdir(this.backupDir, true);
22
+ // Check if there's anything to backup
23
+ const distExists = await this.ssh.exists(`${this.appDir}/dist`);
24
+ if (!distExists) {
25
+ Logger.warn('No existing deployment to backup');
26
+ return backupPath;
27
+ }
28
+ // Create backup
29
+ const result = await this.ssh.exec(`mkdir -p ${backupPath} && ` +
30
+ `cp -r ${this.appDir}/dist ${backupPath}/ && ` +
31
+ `cp ${this.appDir}/package.json ${backupPath}/ 2>/dev/null || true`);
32
+ if (result.exitCode !== 0) {
33
+ throw new Error(`Failed to create backup: ${result.stderr}`);
34
+ }
35
+ return backupPath;
36
+ }
37
+ /**
38
+ * List all backups
39
+ */
40
+ async list() {
41
+ const exists = await this.ssh.exists(this.backupDir);
42
+ if (!exists) {
43
+ return [];
44
+ }
45
+ const result = await this.ssh.exec(`ls -1 ${this.backupDir}`);
46
+ if (result.exitCode !== 0) {
47
+ return [];
48
+ }
49
+ return result.stdout
50
+ .trim()
51
+ .split('\n')
52
+ .filter(line => line.length > 0)
53
+ .sort()
54
+ .reverse(); // Most recent first
55
+ }
56
+ /**
57
+ * Restore from backup
58
+ */
59
+ async restore(backupName) {
60
+ const backupPath = `${this.backupDir}/${backupName}`;
61
+ // Check if backup exists
62
+ const exists = await this.ssh.exists(backupPath);
63
+ if (!exists) {
64
+ throw new Error(`Backup not found: ${backupName}`);
65
+ }
66
+ // Restore
67
+ const result = await this.ssh.exec(`rm -rf ${this.appDir}/dist && ` +
68
+ `cp -r ${backupPath}/dist ${this.appDir}/`);
69
+ if (result.exitCode !== 0) {
70
+ throw new Error(`Failed to restore backup: ${result.stderr}`);
71
+ }
72
+ }
73
+ /**
74
+ * Clean up old backups (keep only last N)
75
+ */
76
+ async cleanup(keep = 5) {
77
+ const backups = await this.list();
78
+ if (backups.length <= keep) {
79
+ return; // Nothing to clean up
80
+ }
81
+ const toDelete = backups.slice(keep);
82
+ for (const backup of toDelete) {
83
+ await this.ssh.exec(`rm -rf ${this.backupDir}/${backup}`);
84
+ }
85
+ Logger.info(`Cleaned up ${toDelete.length} old backup(s)`);
86
+ }
87
+ /**
88
+ * Get most recent backup
89
+ */
90
+ async getLatest() {
91
+ const backups = await this.list();
92
+ return backups.length > 0 ? backups[0] : null;
93
+ }
94
+ }
95
+ //# sourceMappingURL=backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.js","sourceRoot":"","sources":["../../src/core/backup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export interface HealthCheckOptions {
2
+ url: string;
3
+ timeout?: number;
4
+ retries?: number;
5
+ interval?: number;
6
+ }
7
+ export interface HealthCheckResult {
8
+ healthy: boolean;
9
+ statusCode?: number;
10
+ responseTime?: number;
11
+ error?: string;
12
+ }
13
+ /**
14
+ * Health check utility
15
+ */
16
+ export declare class HealthCheck {
17
+ /**
18
+ * Check if service is healthy
19
+ */
20
+ static check(options: HealthCheckOptions): Promise<HealthCheckResult>;
21
+ /**
22
+ * Poll health endpoint until healthy or max retries reached
23
+ */
24
+ static poll(options: HealthCheckOptions): Promise<boolean>;
25
+ /**
26
+ * Wait for service to be ready
27
+ */
28
+ static waitForReady(options: HealthCheckOptions, onProgress?: (attempt: number) => void): Promise<boolean>;
29
+ private static sleep;
30
+ }
31
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/core/health.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB;;OAEG;WACU,KAAK,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAiC3E;;OAEG;WACU,IAAI,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BhE;;OAEG;WACU,YAAY,CACvB,OAAO,EAAE,kBAAkB,EAC3B,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GACrC,OAAO,CAAC,OAAO,CAAC;IAqBnB,OAAO,CAAC,MAAM,CAAC,KAAK;CAGrB"}
@@ -0,0 +1,78 @@
1
+ import { Logger } from '../utils/logger.js';
2
+ /**
3
+ * Health check utility
4
+ */
5
+ export class HealthCheck {
6
+ /**
7
+ * Check if service is healthy
8
+ */
9
+ static async check(options) {
10
+ const timeout = options.timeout || 5000;
11
+ try {
12
+ const startTime = Date.now();
13
+ const controller = new AbortController();
14
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
15
+ const response = await fetch(options.url, {
16
+ signal: controller.signal,
17
+ headers: {
18
+ 'User-Agent': 'hostfn-health-check',
19
+ },
20
+ });
21
+ clearTimeout(timeoutId);
22
+ const responseTime = Date.now() - startTime;
23
+ return {
24
+ healthy: response.ok,
25
+ statusCode: response.status,
26
+ responseTime,
27
+ };
28
+ }
29
+ catch (error) {
30
+ return {
31
+ healthy: false,
32
+ error: error instanceof Error ? error.message : String(error),
33
+ };
34
+ }
35
+ }
36
+ /**
37
+ * Poll health endpoint until healthy or max retries reached
38
+ */
39
+ static async poll(options) {
40
+ const retries = options.retries || 10;
41
+ const interval = options.interval || 3000;
42
+ for (let i = 0; i < retries; i++) {
43
+ const result = await this.check(options);
44
+ if (result.healthy) {
45
+ Logger.success(`Health check passed (${result.statusCode}, ${result.responseTime}ms)`);
46
+ return true;
47
+ }
48
+ if (i < retries - 1) {
49
+ Logger.warn(`Health check failed (attempt ${i + 1}/${retries}), retrying in ${interval / 1000}s...`);
50
+ await this.sleep(interval);
51
+ }
52
+ }
53
+ Logger.error(`Health check failed after ${retries} attempts`);
54
+ return false;
55
+ }
56
+ /**
57
+ * Wait for service to be ready
58
+ */
59
+ static async waitForReady(options, onProgress) {
60
+ const retries = options.retries || 10;
61
+ const interval = options.interval || 3000;
62
+ for (let i = 0; i < retries; i++) {
63
+ onProgress?.(i + 1);
64
+ const result = await this.check(options);
65
+ if (result.healthy) {
66
+ return true;
67
+ }
68
+ if (i < retries - 1) {
69
+ await this.sleep(interval);
70
+ }
71
+ }
72
+ return false;
73
+ }
74
+ static sleep(ms) {
75
+ return new Promise(resolve => setTimeout(resolve, ms));
76
+ }
77
+ }
78
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/core/health.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export interface LocalCommandResult {
2
+ stdout: string;
3
+ stderr: string;
4
+ exitCode: number;
5
+ }
6
+ export declare class LocalExecutor {
7
+ connect(): Promise<void>;
8
+ exec(command: string, options?: {
9
+ streaming?: boolean;
10
+ cwd?: string;
11
+ }): Promise<LocalCommandResult>;
12
+ uploadFile(localPath: string, remotePath: string): Promise<void>;
13
+ downloadFile(remotePath: string, localPath: string): Promise<void>;
14
+ exists(path: string): Promise<boolean>;
15
+ mkdir(path: string, recursive?: boolean): Promise<void>;
16
+ isConnected(): boolean;
17
+ disconnect(): void;
18
+ }
19
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/core/local.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,aAAa;IAClB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QACpC,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAqBzB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhE,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAItC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,OAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAInE,WAAW,IAAI,OAAO;IAItB,UAAU,IAAI,IAAI;CAEnB"}
@@ -0,0 +1,50 @@
1
+ import { exec } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import { existsSync } from 'fs';
4
+ import { mkdir } from 'fs/promises';
5
+ const execAsync = promisify(exec);
6
+ export class LocalExecutor {
7
+ async connect() {
8
+ return Promise.resolve();
9
+ }
10
+ async exec(command, options) {
11
+ try {
12
+ const { stdout, stderr } = await execAsync(command, {
13
+ cwd: options?.cwd,
14
+ shell: '/bin/bash',
15
+ });
16
+ return {
17
+ stdout,
18
+ stderr,
19
+ exitCode: 0,
20
+ };
21
+ }
22
+ catch (error) {
23
+ return {
24
+ stdout: error.stdout || '',
25
+ stderr: error.stderr || '',
26
+ exitCode: error.code || 1,
27
+ };
28
+ }
29
+ }
30
+ async uploadFile(localPath, remotePath) {
31
+ const { copyFileSync } = await import('fs');
32
+ copyFileSync(localPath, remotePath);
33
+ }
34
+ async downloadFile(remotePath, localPath) {
35
+ const { copyFileSync } = await import('fs');
36
+ copyFileSync(remotePath, localPath);
37
+ }
38
+ async exists(path) {
39
+ return existsSync(path);
40
+ }
41
+ async mkdir(path, recursive = true) {
42
+ await mkdir(path, { recursive });
43
+ }
44
+ isConnected() {
45
+ return true;
46
+ }
47
+ disconnect() {
48
+ }
49
+ }
50
+ //# sourceMappingURL=local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/core/local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAQlC,MAAM,OAAO,aAAa;IACxB,KAAK,CAAC,OAAO;QACX,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAe,EAAE,OAG3B;QACC,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE;gBAClD,GAAG,EAAE,OAAO,EAAE,GAAG;gBACjB,KAAK,EAAE,WAAW;aACnB,CAAC,CAAC;YAEH,OAAO;gBACL,MAAM;gBACN,MAAM;gBACN,QAAQ,EAAE,CAAC;aACZ,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO;gBACL,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;gBAC1B,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;gBAC1B,QAAQ,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC;aAC1B,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,SAAiB,EAAE,UAAkB;QACpD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5C,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,UAAkB,EAAE,SAAiB;QACtD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5C,YAAY,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAY,EAAE,YAAqB,IAAI;QACjD,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IAED,UAAU;IACV,CAAC;CACF"}
@@ -0,0 +1,28 @@
1
+ import { SSHConnection } from './ssh.js';
2
+ export interface DeploymentLock {
3
+ pid: number;
4
+ user: string;
5
+ timestamp: number;
6
+ hostname: string;
7
+ }
8
+ /**
9
+ * Deployment lock manager to prevent concurrent deployments
10
+ */
11
+ export declare class LockManager {
12
+ private ssh;
13
+ private lockFile;
14
+ constructor(ssh: SSHConnection, remoteDir: string);
15
+ /**
16
+ * Acquire deployment lock
17
+ */
18
+ acquire(timeout?: number): Promise<boolean>;
19
+ /**
20
+ * Release deployment lock
21
+ */
22
+ release(): Promise<void>;
23
+ /**
24
+ * Check if deployment is locked
25
+ */
26
+ isLocked(): Promise<boolean>;
27
+ }
28
+ //# sourceMappingURL=lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/core/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,GAAG,CAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAS;gBAEb,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM;IAKjD;;OAEG;IACG,OAAO,CAAC,OAAO,GAAE,MAAY,GAAG,OAAO,CAAC,OAAO,CAAC;IAiDtD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;CAqBnC"}
@@ -0,0 +1,89 @@
1
+ import { Logger } from '../utils/logger.js';
2
+ /**
3
+ * Deployment lock manager to prevent concurrent deployments
4
+ */
5
+ export class LockManager {
6
+ ssh;
7
+ lockFile;
8
+ constructor(ssh, remoteDir) {
9
+ this.ssh = ssh;
10
+ this.lockFile = `${remoteDir}/.hostfn-deploy.lock`;
11
+ }
12
+ /**
13
+ * Acquire deployment lock
14
+ */
15
+ async acquire(timeout = 300) {
16
+ // Check if lock exists
17
+ const exists = await this.ssh.exists(this.lockFile);
18
+ if (exists) {
19
+ // Read lock info
20
+ const result = await this.ssh.exec(`cat ${this.lockFile}`);
21
+ try {
22
+ const lock = JSON.parse(result.stdout);
23
+ const age = Date.now() - lock.timestamp;
24
+ // Check if lock is stale (older than timeout)
25
+ if (age > timeout * 1000) {
26
+ Logger.warn('Found stale lock file, removing...');
27
+ await this.release();
28
+ }
29
+ else {
30
+ const ageMinutes = Math.round(age / 1000 / 60);
31
+ Logger.error('Deployment is already in progress');
32
+ Logger.info(`Started by: ${lock.user}`);
33
+ Logger.info(`Started at: ${new Date(lock.timestamp).toLocaleString()}`);
34
+ Logger.info(`Age: ${ageMinutes} minute(s)`);
35
+ Logger.br();
36
+ Logger.warn('Wait for the current deployment to finish or:');
37
+ Logger.log(' 1. Wait for lock to expire (5 minutes)');
38
+ Logger.log(' 2. Manually remove: ssh <host> rm ' + this.lockFile);
39
+ return false;
40
+ }
41
+ }
42
+ catch {
43
+ // Invalid lock file, remove it
44
+ await this.release();
45
+ }
46
+ }
47
+ // Create lock
48
+ const lock = {
49
+ pid: process.pid,
50
+ user: process.env.USER || 'unknown',
51
+ timestamp: Date.now(),
52
+ hostname: process.env.HOSTNAME || 'unknown',
53
+ };
54
+ await this.ssh.exec(`cat > ${this.lockFile} << 'LOCKEOF'
55
+ ${JSON.stringify(lock, null, 2)}
56
+ LOCKEOF`);
57
+ return true;
58
+ }
59
+ /**
60
+ * Release deployment lock
61
+ */
62
+ async release() {
63
+ await this.ssh.exec(`rm -f ${this.lockFile}`).catch(() => {
64
+ // Ignore errors on cleanup
65
+ });
66
+ }
67
+ /**
68
+ * Check if deployment is locked
69
+ */
70
+ async isLocked() {
71
+ const exists = await this.ssh.exists(this.lockFile);
72
+ if (!exists) {
73
+ return false;
74
+ }
75
+ // Check if lock is stale
76
+ const result = await this.ssh.exec(`cat ${this.lockFile}`);
77
+ try {
78
+ const lock = JSON.parse(result.stdout);
79
+ const age = Date.now() - lock.timestamp;
80
+ // Lock is stale if older than 5 minutes
81
+ return age < 300 * 1000;
82
+ }
83
+ catch {
84
+ // Invalid lock file = not locked
85
+ return false;
86
+ }
87
+ }
88
+ }
89
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/core/lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ export interface NginxServiceConfig {
2
+ name: string;
3
+ port: number;
4
+ exposePath?: string;
5
+ isDefault?: boolean;
6
+ }
7
+ export interface NginxConfig {
8
+ domain?: string | string[];
9
+ ssl: boolean;
10
+ services: NginxServiceConfig[];
11
+ environment: string;
12
+ }
13
+ export declare class NginxConfigGenerator {
14
+ /**
15
+ * Generate nginx configuration for services
16
+ */
17
+ static generate(config: NginxConfig): string;
18
+ /**
19
+ * Generate HTTPS server block
20
+ */
21
+ private static generateHttpsBlock;
22
+ /**
23
+ * Generate HTTP server block
24
+ */
25
+ private static generateHttpBlock;
26
+ /**
27
+ * Generate HTTP to HTTPS redirect block
28
+ */
29
+ private static generateHttpRedirectBlock;
30
+ /**
31
+ * Generate location block for a service
32
+ */
33
+ private static generateLocationBlock;
34
+ /**
35
+ * Get nginx config file path based on the system
36
+ */
37
+ static getConfigPath(environment: string, useSitesAvailable: boolean): string;
38
+ /**
39
+ * Get command to enable site (for sites-available/sites-enabled systems)
40
+ */
41
+ static getEnableCommand(environment: string, useSitesAvailable: boolean): string | null;
42
+ }
43
+ //# sourceMappingURL=nginx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nginx.d.ts","sourceRoot":"","sources":["../../src/core/nginx.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,oBAAoB;IAC/B;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM;IA0B5C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAgCjC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAyBhC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAYxC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAuBpC;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAG,MAAM;IAO7E;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI;CAMxF"}
@@ -0,0 +1,131 @@
1
+ export class NginxConfigGenerator {
2
+ /**
3
+ * Generate nginx configuration for services
4
+ */
5
+ static generate(config) {
6
+ const { domain, ssl, services, environment } = config;
7
+ // Handle both single domain string and array of domains
8
+ const domains = domain ? (Array.isArray(domain) ? domain : [domain]) : [];
9
+ const serverName = domains.length > 0 ? domains.join(' ') : '_';
10
+ // Separate default and path-based services
11
+ const defaultService = services.find(s => s.isDefault);
12
+ const pathServices = services.filter(s => !s.isDefault && s.exposePath);
13
+ let nginxConfig = '';
14
+ if (ssl) {
15
+ // HTTPS server block
16
+ nginxConfig += this.generateHttpsBlock(serverName, defaultService, pathServices);
17
+ nginxConfig += '\n\n';
18
+ // HTTP redirect block
19
+ nginxConfig += this.generateHttpRedirectBlock(serverName);
20
+ }
21
+ else {
22
+ // HTTP only server block
23
+ nginxConfig += this.generateHttpBlock(serverName, defaultService, pathServices);
24
+ }
25
+ return nginxConfig;
26
+ }
27
+ /**
28
+ * Generate HTTPS server block
29
+ */
30
+ static generateHttpsBlock(serverName, defaultService, pathServices) {
31
+ // Extract primary domain for certificate path (first domain in the list)
32
+ const primaryDomain = serverName.split(' ')[0];
33
+ let config = `server {
34
+ listen 443 ssl http2;
35
+ listen [::]:443 ssl http2;
36
+ server_name ${serverName};
37
+
38
+ ssl_certificate /etc/letsencrypt/live/${primaryDomain}/fullchain.pem; # managed by Certbot
39
+ ssl_certificate_key /etc/letsencrypt/live/${primaryDomain}/privkey.pem; # managed by Certbot
40
+ include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
41
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
42
+ `;
43
+ // Add path-based services first (higher priority)
44
+ for (const service of pathServices) {
45
+ config += this.generateLocationBlock(service);
46
+ }
47
+ // Add default service
48
+ if (defaultService) {
49
+ config += this.generateLocationBlock(defaultService);
50
+ }
51
+ config += '}\n';
52
+ return config;
53
+ }
54
+ /**
55
+ * Generate HTTP server block
56
+ */
57
+ static generateHttpBlock(serverName, defaultService, pathServices) {
58
+ let config = `server {
59
+ listen 80;
60
+ listen [::]:80;
61
+ server_name ${serverName};
62
+ `;
63
+ // Add path-based services first (higher priority)
64
+ for (const service of pathServices) {
65
+ config += this.generateLocationBlock(service);
66
+ }
67
+ // Add default service
68
+ if (defaultService) {
69
+ config += this.generateLocationBlock(defaultService);
70
+ }
71
+ config += '}\n';
72
+ return config;
73
+ }
74
+ /**
75
+ * Generate HTTP to HTTPS redirect block
76
+ */
77
+ static generateHttpRedirectBlock(serverName) {
78
+ return `server {
79
+ listen 80;
80
+ listen [::]:80;
81
+ server_name ${serverName};
82
+
83
+ location / {
84
+ return 301 https://$host$request_uri;
85
+ }
86
+ }`;
87
+ }
88
+ /**
89
+ * Generate location block for a service
90
+ */
91
+ static generateLocationBlock(service) {
92
+ const path = service.exposePath || '/';
93
+ const hasTrailingSlash = path !== '/' && path.endsWith('/');
94
+ const proxyPassPath = hasTrailingSlash ? '/' : '';
95
+ return `
96
+ # ${service.name}
97
+ location ${path} {
98
+ proxy_pass http://localhost:${service.port}${proxyPassPath};
99
+ proxy_http_version 1.1;
100
+ proxy_set_header Upgrade $http_upgrade;
101
+ proxy_set_header Connection 'upgrade';
102
+ proxy_set_header Host $host;
103
+ proxy_set_header X-Real-IP $remote_addr;
104
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
105
+ proxy_set_header X-Forwarded-Proto $scheme;
106
+ proxy_cache_bypass $http_upgrade;
107
+ proxy_read_timeout 60s;
108
+ proxy_connect_timeout 60s;
109
+ }
110
+ `;
111
+ }
112
+ /**
113
+ * Get nginx config file path based on the system
114
+ */
115
+ static getConfigPath(environment, useSitesAvailable) {
116
+ if (useSitesAvailable) {
117
+ return `/etc/nginx/sites-available/hostfn-${environment}`;
118
+ }
119
+ return `/etc/nginx/conf.d/hostfn-${environment}.conf`;
120
+ }
121
+ /**
122
+ * Get command to enable site (for sites-available/sites-enabled systems)
123
+ */
124
+ static getEnableCommand(environment, useSitesAvailable) {
125
+ if (useSitesAvailable) {
126
+ return `ln -sf /etc/nginx/sites-available/hostfn-${environment} /etc/nginx/sites-enabled/hostfn-${environment}`;
127
+ }
128
+ return null;
129
+ }
130
+ }
131
+ //# sourceMappingURL=nginx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nginx.js","sourceRoot":"","sources":["../../src/core/nginx.ts"],"names":[],"mappings":"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"}