@aaricchen1991/deploy 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 (49) hide show
  1. package/PUBLISHING.md +131 -0
  2. package/README.md +256 -0
  3. package/dist/cli.d.ts +6 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +95 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/init.d.ts +10 -0
  8. package/dist/commands/init.d.ts.map +1 -0
  9. package/dist/commands/init.js +104 -0
  10. package/dist/commands/init.js.map +1 -0
  11. package/dist/commands/nginx.d.ts +10 -0
  12. package/dist/commands/nginx.d.ts.map +1 -0
  13. package/dist/commands/nginx.js +70 -0
  14. package/dist/commands/nginx.js.map +1 -0
  15. package/dist/commands/ssl-logs.d.ts +17 -0
  16. package/dist/commands/ssl-logs.d.ts.map +1 -0
  17. package/dist/commands/ssl-logs.js +54 -0
  18. package/dist/commands/ssl-logs.js.map +1 -0
  19. package/dist/commands/ssl.d.ts +16 -0
  20. package/dist/commands/ssl.d.ts.map +1 -0
  21. package/dist/commands/ssl.js +98 -0
  22. package/dist/commands/ssl.js.map +1 -0
  23. package/dist/lib/domains.d.ts +22 -0
  24. package/dist/lib/domains.d.ts.map +1 -0
  25. package/dist/lib/domains.js +70 -0
  26. package/dist/lib/domains.js.map +1 -0
  27. package/dist/lib/logger.d.ts +14 -0
  28. package/dist/lib/logger.d.ts.map +1 -0
  29. package/dist/lib/logger.js +60 -0
  30. package/dist/lib/logger.js.map +1 -0
  31. package/dist/lib/nginx.d.ts +6 -0
  32. package/dist/lib/nginx.d.ts.map +1 -0
  33. package/dist/lib/nginx.js +113 -0
  34. package/dist/lib/nginx.js.map +1 -0
  35. package/dist/lib/paths.d.ts +8 -0
  36. package/dist/lib/paths.d.ts.map +1 -0
  37. package/dist/lib/paths.js +28 -0
  38. package/dist/lib/paths.js.map +1 -0
  39. package/package.json +24 -0
  40. package/src/cli.ts +122 -0
  41. package/src/commands/init.ts +127 -0
  42. package/src/commands/nginx.ts +82 -0
  43. package/src/commands/ssl-logs.ts +80 -0
  44. package/src/commands/ssl.ts +140 -0
  45. package/src/lib/domains.ts +77 -0
  46. package/src/lib/logger.ts +79 -0
  47. package/src/lib/nginx.ts +120 -0
  48. package/src/lib/paths.ts +30 -0
  49. package/tsconfig.json +19 -0
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Unified logger: timestamp, level, optional file output.
3
+ */
4
+
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+
8
+ export type LogLevel = "info" | "warn" | "error";
9
+
10
+ const PREFIX: Record<LogLevel, string> = {
11
+ info: "\x1b[32m[INFO]\x1b[0m",
12
+ warn: "\x1b[33m[WARN]\x1b[0m",
13
+ error: "\x1b[31m[ERROR]\x1b[0m",
14
+ };
15
+
16
+ function timestamp(): string {
17
+ return new Date().toISOString().replace("T", " ").slice(0, 19);
18
+ }
19
+
20
+ function format(level: LogLevel, msg: string): string {
21
+ return `${timestamp()} ${PREFIX[level]} ${msg}`;
22
+ }
23
+
24
+ let logFile: string | null = null;
25
+
26
+ export function setLogFile(filePath: string): void {
27
+ logFile = filePath;
28
+ }
29
+
30
+ export function getLogFilePath(): string | null {
31
+ return logFile;
32
+ }
33
+
34
+ function writeToLogFileSync(line: string): void {
35
+ if (!logFile) return;
36
+ try {
37
+ const dir = path.dirname(logFile);
38
+ fs.mkdirSync(dir, { recursive: true });
39
+ fs.appendFileSync(logFile, line + "\n");
40
+ } catch {
41
+ // ignore
42
+ }
43
+ }
44
+
45
+ export function info(msg: string): void {
46
+ const line = format("info", msg);
47
+ console.log(line);
48
+ writeToLogFileSync(line);
49
+ }
50
+
51
+ export function warn(msg: string): void {
52
+ const line = format("warn", msg);
53
+ console.warn(line);
54
+ writeToLogFileSync(line);
55
+ }
56
+
57
+ export function error(msg: string): void {
58
+ const line = format("error", msg);
59
+ console.error(line);
60
+ writeToLogFileSync(line);
61
+ }
62
+
63
+ /** Append a raw line to the log file (no timestamp/level prefix). */
64
+ export function appendRaw(line: string): void {
65
+ writeToLogFileSync(line);
66
+ }
67
+
68
+ /** Append a structured SSL log line (time, action, domain, result, message). */
69
+ export function appendSslLog(
70
+ action: "create" | "renew" | "success" | "failure" | "run",
71
+ domain: string,
72
+ result: "ok" | "fail",
73
+ message?: string
74
+ ): void {
75
+ const line = [timestamp(), "ssl", action, domain, result, message ?? ""].join(
76
+ "\t"
77
+ );
78
+ writeToLogFileSync(line);
79
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Generate nginx n2.conf from domains config (same output as generate-nginx-conf.js).
3
+ */
4
+
5
+ import type { DomainsConfig } from "./domains.js";
6
+
7
+ function apiServerBlock(domain: string, backendPort: number): string {
8
+ return `# HTTPS - API (${domain})
9
+ server {
10
+ listen 443 ssl http2;
11
+ server_name ${domain};
12
+
13
+ ssl_certificate /etc/nginx/ssl/${domain}.crt;
14
+ ssl_certificate_key /etc/nginx/ssl/${domain}.key;
15
+
16
+ ssl_protocols TLSv1.2 TLSv1.3;
17
+ ssl_ciphers HIGH:!aNULL:!MD5;
18
+ ssl_prefer_server_ciphers on;
19
+ ssl_session_cache shared:SSL:10m;
20
+ ssl_session_timeout 10m;
21
+
22
+ access_log /var/log/nginx/api-access.log;
23
+ error_log /var/log/nginx/api-error.log;
24
+
25
+ location / {
26
+ proxy_pass http://127.0.0.1:${backendPort};
27
+ proxy_http_version 1.1;
28
+ proxy_set_header Host $host;
29
+ proxy_set_header X-Real-IP $remote_addr;
30
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
31
+ proxy_set_header X-Forwarded-Proto $scheme;
32
+ }
33
+
34
+ add_header X-Frame-Options "SAMEORIGIN" always;
35
+ add_header X-Content-Type-Options "nosniff" always;
36
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
37
+ }
38
+
39
+ `;
40
+ }
41
+
42
+ function staticAppServerBlock(domain: string, appName: string): string {
43
+ const root = `/var/www/${appName}`;
44
+ return `# HTTPS - ${appName} (${domain})
45
+ server {
46
+ listen 443 ssl http2;
47
+ server_name ${domain};
48
+
49
+ root ${root};
50
+ index index.html;
51
+
52
+ ssl_certificate /etc/nginx/ssl/${domain}.crt;
53
+ ssl_certificate_key /etc/nginx/ssl/${domain}.key;
54
+
55
+ ssl_protocols TLSv1.2 TLSv1.3;
56
+ ssl_ciphers HIGH:!aNULL:!MD5;
57
+ ssl_prefer_server_ciphers on;
58
+ ssl_session_cache shared:SSL:10m;
59
+ ssl_session_timeout 10m;
60
+
61
+ access_log /var/log/nginx/${appName}-access.log;
62
+ error_log /var/log/nginx/${appName}-error.log;
63
+
64
+ gzip on;
65
+ gzip_vary on;
66
+ gzip_min_length 1024;
67
+ gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
68
+
69
+ location ~* \\.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot|mp3)$ {
70
+ expires 1y;
71
+ add_header Cache-Control "public, immutable";
72
+ access_log off;
73
+ }
74
+
75
+ location / {
76
+ try_files $uri $uri/ /index.html;
77
+ }
78
+
79
+ add_header X-Frame-Options "SAMEORIGIN" always;
80
+ add_header X-Content-Type-Options "nosniff" always;
81
+ add_header X-XSS-Protection "1; mode=block" always;
82
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
83
+ }
84
+
85
+ `;
86
+ }
87
+
88
+ export function generateNginxConf(config: DomainsConfig): string {
89
+ const blocks: string[] = [];
90
+ const apiPort = config.api.backend_port ?? 3000;
91
+
92
+ for (const d of config.api.domains) {
93
+ blocks.push(apiServerBlock(d, apiPort));
94
+ }
95
+ for (const d of config.admin.domains) {
96
+ blocks.push(staticAppServerBlock(d, "admin"));
97
+ }
98
+ for (const d of config.tenant.domains) {
99
+ blocks.push(staticAppServerBlock(d, "tenant"));
100
+ }
101
+ for (const d of config.client.domains) {
102
+ blocks.push(staticAppServerBlock(d, "client"));
103
+ }
104
+
105
+ const allDomains = [
106
+ ...config.api.domains,
107
+ ...config.admin.domains,
108
+ ...config.tenant.domains,
109
+ ...config.client.domains,
110
+ ];
111
+ const redirectBlock = `# HTTP to HTTPS redirect
112
+ server {
113
+ listen 80;
114
+ server_name ${allDomains.join(" ")};
115
+ return 301 https://$host$request_uri;
116
+ }
117
+ `;
118
+
119
+ return blocks.join("\n") + "\n" + redirectBlock;
120
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Resolve deploy scripts directory: for init/ssl we need deploy.sh, server-setup.sh, ssl/*, lib/*.
3
+ * 1) N2_DEPLOY_SCRIPTS_DIR env
4
+ * 2) cwd/scripts/deploy (monorepo)
5
+ * 3) package assets (when published)
6
+ */
7
+
8
+ import fs from "node:fs";
9
+ import path from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+
12
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
+
14
+ export function getScriptsDir(cwd: string = process.cwd()): string | null {
15
+ const envDir = process.env.N2_DEPLOY_SCRIPTS_DIR;
16
+ if (envDir && fs.existsSync(path.join(envDir, "deploy.sh"))) {
17
+ return envDir;
18
+ }
19
+ const monorepo = path.join(cwd, "scripts", "deploy");
20
+ if (fs.existsSync(path.join(monorepo, "deploy.sh"))) {
21
+ return monorepo;
22
+ }
23
+ // From dist/cli.js, package root is ../ and we may have assets/deploy
24
+ const packageRoot = path.join(__dirname, "..", "..");
25
+ const assetsDeploy = path.join(packageRoot, "assets", "deploy");
26
+ if (fs.existsSync(path.join(assetsDeploy, "deploy.sh"))) {
27
+ return assetsDeploy;
28
+ }
29
+ return null;
30
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "declaration": true,
9
+ "declarationMap": true,
10
+ "sourceMap": true,
11
+ "noEmit": false,
12
+ "strict": true,
13
+ "esModuleInterop": true,
14
+ "skipLibCheck": true,
15
+ "resolveJsonModule": true
16
+ },
17
+ "include": ["src/**/*"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }