@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,70 @@
1
+ /**
2
+ * Generate nginx config from domains config; optionally install and reload.
3
+ */
4
+ import { spawn } from "node:child_process";
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+ import { parseDomainsYaml } from "../lib/domains.js";
8
+ import { error, info, warn } from "../lib/logger.js";
9
+ import { generateNginxConf } from "../lib/nginx.js";
10
+ const NGINX_CONF_NAME = "n2.conf";
11
+ export async function runNginx(opts) {
12
+ const configPath = path.resolve(process.cwd(), opts.config);
13
+ if (!fs.existsSync(configPath)) {
14
+ error(`Config not found: ${configPath}`);
15
+ process.exit(1);
16
+ }
17
+ const yaml = fs.readFileSync(configPath, "utf8");
18
+ const config = parseDomainsYaml(yaml);
19
+ const nginxConf = generateNginxConf(config);
20
+ const outPath = path.resolve(process.cwd(), opts.output);
21
+ const outDir = path.dirname(outPath);
22
+ fs.mkdirSync(outDir, { recursive: true });
23
+ fs.writeFileSync(outPath, nginxConf);
24
+ info(`Wrote ${outPath}`);
25
+ if (opts.install) {
26
+ const destDir = detectNginxConfDir();
27
+ const destPath = path.join(destDir, NGINX_CONF_NAME);
28
+ try {
29
+ fs.copyFileSync(outPath, destPath);
30
+ info(`Installed to ${destPath}`);
31
+ }
32
+ catch (e) {
33
+ error(`Install failed (try sudo): ${e}`);
34
+ process.exit(1);
35
+ }
36
+ await nginxTestAndReload();
37
+ }
38
+ }
39
+ function detectNginxConfDir() {
40
+ if (fs.existsSync("/etc/nginx/conf.d"))
41
+ return "/etc/nginx/conf.d";
42
+ if (fs.existsSync("/etc/nginx/sites-available"))
43
+ return "/etc/nginx/sites-available";
44
+ return "/etc/nginx/conf.d";
45
+ }
46
+ function nginxTestAndReload() {
47
+ return new Promise((resolve, reject) => {
48
+ const t = spawn("nginx", ["-t"], { stdio: "inherit" });
49
+ t.on("close", code => {
50
+ if (code !== 0) {
51
+ reject(new Error("nginx -t failed"));
52
+ return;
53
+ }
54
+ const r = spawn("systemctl", ["reload", "nginx"], { stdio: "inherit" });
55
+ r.on("close", c => {
56
+ if (c === 0) {
57
+ info("Nginx reloaded.");
58
+ resolve();
59
+ }
60
+ else {
61
+ warn("systemctl reload nginx failed; try: sudo systemctl reload nginx");
62
+ resolve();
63
+ }
64
+ });
65
+ r.on("error", () => resolve());
66
+ });
67
+ t.on("error", () => reject(new Error("nginx not found")));
68
+ });
69
+ }
70
+ //# sourceMappingURL=nginx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nginx.js","sourceRoot":"","sources":["../../src/commands/nginx.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * View SSL log file: tail, lines, follow, optional filter by action/result.
3
+ */
4
+ export interface SslLogsOptions {
5
+ /** Log file path (default: /opt/deploy/logs/ssl.log) */
6
+ logFile?: string;
7
+ /** Show last N lines (default: 50) */
8
+ lines?: number;
9
+ /** Follow (tail -f) */
10
+ follow?: boolean;
11
+ /** Filter: create | renew | success | failure | run */
12
+ action?: string;
13
+ /** Filter: ok | fail */
14
+ result?: string;
15
+ }
16
+ export declare function runSslLogs(opts: SslLogsOptions): Promise<void>;
17
+ //# sourceMappingURL=ssl-logs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssl-logs.d.ts","sourceRoot":"","sources":["../../src/commands/ssl-logs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAwDpE"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * View SSL log file: tail, lines, follow, optional filter by action/result.
3
+ */
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { getLogFilePath } from "../lib/logger.js";
7
+ const DEFAULT_SSL_LOG = "/opt/deploy/logs/ssl.log";
8
+ export async function runSslLogs(opts) {
9
+ const logPath = opts.logFile ?? getLogFilePath() ?? DEFAULT_SSL_LOG;
10
+ const resolved = path.resolve(process.cwd(), logPath);
11
+ if (!fs.existsSync(resolved)) {
12
+ console.error("Log file not found:", resolved);
13
+ process.exit(1);
14
+ }
15
+ const lines = opts.lines ?? 50;
16
+ let content;
17
+ const stat = fs.statSync(resolved);
18
+ const fd = fs.openSync(resolved, "r");
19
+ try {
20
+ const buffer = Buffer.alloc(Math.min(stat.size, 256 * 1024));
21
+ const read = fs.readSync(fd, buffer, 0, buffer.length, Math.max(0, stat.size - buffer.length));
22
+ content = buffer.subarray(0, read).toString("utf8");
23
+ }
24
+ finally {
25
+ fs.closeSync(fd);
26
+ }
27
+ const allLines = content.split(/\n/).filter(l => l.length > 0);
28
+ const lastLines = allLines.slice(-lines);
29
+ const filter = (line) => {
30
+ if (opts.action || opts.result) {
31
+ const parts = line.split("\t");
32
+ if (parts.length >= 5) {
33
+ const [, , action, , result] = parts;
34
+ if (opts.action && action !== opts.action)
35
+ return false;
36
+ if (opts.result && result !== opts.result)
37
+ return false;
38
+ }
39
+ }
40
+ return true;
41
+ };
42
+ const filtered = opts.action || opts.result ? lastLines.filter(filter) : lastLines;
43
+ for (const line of filtered) {
44
+ console.log(line);
45
+ }
46
+ if (opts.follow) {
47
+ const { spawn } = await import("node:child_process");
48
+ const tail = spawn("tail", ["-n", String(lines), "-f", resolved], {
49
+ stdio: "inherit",
50
+ });
51
+ tail.on("close", code => process.exit(code ?? 0));
52
+ }
53
+ }
54
+ //# sourceMappingURL=ssl-logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssl-logs.js","sourceRoot":"","sources":["../../src/commands/ssl-logs.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAenD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAoB;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,cAAc,EAAE,IAAI,eAAe,CAAC;IACpE,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;IAEtD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;IAC/B,IAAI,OAAe,CAAC;IACpB,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CACtB,EAAE,EACF,MAAM,EACN,CAAC,EACD,MAAM,CAAC,MAAM,EACb,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CACvC,CAAC;QACF,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtD,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAW,EAAE;QACvC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;gBACtB,MAAM,CAAC,EAAE,AAAD,EAAG,MAAM,EAAE,AAAD,EAAG,MAAM,CAAC,GAAG,KAAK,CAAC;gBACrC,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM;oBAAE,OAAO,KAAK,CAAC;gBACxD,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM;oBAAE,OAAO,KAAK,CAAC;YAC1D,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,MAAM,QAAQ,GACZ,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEpE,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACrD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE;YAChE,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * SSL certificate setup/renew for all domains from config.
3
+ * Runs check-and-setup-ssl.sh; all output and structured events go to SSL log file.
4
+ */
5
+ export interface SslOptions {
6
+ config: string;
7
+ /** Ali key (or ALIYUN_ACCESS_KEY_ID / Ali_Key env) */
8
+ aliKey?: string;
9
+ /** Ali secret (or ALIYUN_ACCESS_KEY_SECRET / Ali_Secret env) */
10
+ aliSecret?: string;
11
+ logFile?: string;
12
+ /** Path to deploy scripts (default: N2_DEPLOY_SCRIPTS_DIR or cwd/scripts/deploy or assets) */
13
+ scriptsDir?: string;
14
+ }
15
+ export declare function runSsl(opts: SslOptions): Promise<void>;
16
+ //# sourceMappingURL=ssl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssl.d.ts","sourceRoot":"","sources":["../../src/commands/ssl.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiBH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8FAA8F;IAC9F,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA4G5D"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * SSL certificate setup/renew for all domains from config.
3
+ * Runs check-and-setup-ssl.sh; all output and structured events go to SSL log file.
4
+ */
5
+ import { spawn } from "node:child_process";
6
+ import fs from "node:fs";
7
+ import path from "node:path";
8
+ import { getAllDomains, parseDomainsYaml } from "../lib/domains.js";
9
+ import { appendRaw, appendSslLog, error, info, setLogFile, } from "../lib/logger.js";
10
+ import { getScriptsDir } from "../lib/paths.js";
11
+ const DEFAULT_SSL_LOG = "/opt/deploy/logs/ssl.log";
12
+ export async function runSsl(opts) {
13
+ const configPath = path.resolve(process.cwd(), opts.config);
14
+ if (!fs.existsSync(configPath)) {
15
+ error(`Config not found: ${configPath}`);
16
+ process.exit(1);
17
+ }
18
+ const aliKey = opts.aliKey ?? process.env.ALIYUN_ACCESS_KEY_ID ?? process.env.Ali_Key;
19
+ const aliSecret = opts.aliSecret ??
20
+ process.env.ALIYUN_ACCESS_KEY_SECRET ??
21
+ process.env.Ali_Secret;
22
+ if (!aliKey || !aliSecret) {
23
+ error("Aliyun API credentials required. Set --ali-key/--ali-secret or ALIYUN_ACCESS_KEY_ID/ALIYUN_ACCESS_KEY_SECRET (or Ali_Key/Ali_Secret).");
24
+ process.exit(1);
25
+ }
26
+ const yaml = fs.readFileSync(configPath, "utf8");
27
+ const config = parseDomainsYaml(yaml);
28
+ const domains = getAllDomains(config);
29
+ const domainsTxt = domains.join("\n") + "\n";
30
+ const logPath = opts.logFile ?? DEFAULT_SSL_LOG;
31
+ setLogFile(logPath);
32
+ const logDir = path.dirname(logPath);
33
+ fs.mkdirSync(logDir, { recursive: true });
34
+ info("SSL log file: " + logPath);
35
+ info("Domains: " + domains.join(", "));
36
+ const scriptsDir = opts.scriptsDir ||
37
+ process.env.N2_DEPLOY_SCRIPTS_DIR ||
38
+ getScriptsDir(process.cwd());
39
+ let scriptPath;
40
+ let domainsFilePath;
41
+ if (fs.existsSync("/opt/ssl/check-and-setup-ssl.sh")) {
42
+ scriptPath = "/opt/ssl/check-and-setup-ssl.sh";
43
+ domainsFilePath = "/opt/ssl/domains.txt";
44
+ fs.writeFileSync(domainsFilePath, domainsTxt);
45
+ info("Updated /opt/ssl/domains.txt");
46
+ }
47
+ else if (scriptsDir &&
48
+ fs.existsSync(path.join(scriptsDir, "ssl", "check-and-setup-ssl.sh"))) {
49
+ scriptPath = path.join(scriptsDir, "ssl", "check-and-setup-ssl.sh");
50
+ const tmpDomains = path.join(logDir, "domains.txt");
51
+ fs.writeFileSync(tmpDomains, domainsTxt);
52
+ domainsFilePath = tmpDomains;
53
+ }
54
+ else {
55
+ error("SSL scripts not found. Run 'n2-deploy init' first or set N2_DEPLOY_SCRIPTS_DIR.");
56
+ process.exit(1);
57
+ }
58
+ appendSslLog("run", "", "ok", "start");
59
+ await new Promise((resolve, reject) => {
60
+ const child = spawn("bash", [scriptPath, "--ali-key", aliKey, "--ali-secret", aliSecret], {
61
+ env: {
62
+ ...process.env,
63
+ Ali_Key: aliKey,
64
+ Ali_Secret: aliSecret,
65
+ DOMAINS_FILE: domainsFilePath,
66
+ },
67
+ stdio: ["inherit", "pipe", "pipe"],
68
+ });
69
+ const appendOut = (data) => {
70
+ const s = data.toString();
71
+ process.stdout.write(s);
72
+ appendRaw(s.trimEnd());
73
+ };
74
+ child.stdout?.on("data", appendOut);
75
+ child.stderr?.on("data", data => {
76
+ const s = data.toString();
77
+ process.stderr.write(s);
78
+ appendRaw(s.trimEnd());
79
+ });
80
+ child.on("close", (code, signal) => {
81
+ if (code === 0) {
82
+ appendSslLog("run", "", "ok", "done");
83
+ info("SSL certificate setup completed.");
84
+ resolve();
85
+ }
86
+ else {
87
+ appendSslLog("run", "", "fail", `exit ${code} ${signal ?? ""}`);
88
+ error(`SSL script exited with code ${code}`);
89
+ reject(new Error(`SSL script exited with ${code}`));
90
+ }
91
+ });
92
+ child.on("error", err => {
93
+ appendSslLog("run", "", "fail", err.message);
94
+ reject(err);
95
+ });
96
+ });
97
+ }
98
+ //# sourceMappingURL=ssl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssl.js","sourceRoot":"","sources":["../../src/commands/ssl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Parse domains.yaml format (same as scripts/deploy/domains.yaml).
3
+ */
4
+ export interface DomainsConfig {
5
+ api: {
6
+ backend_port: number;
7
+ domains: string[];
8
+ };
9
+ admin: {
10
+ domains: string[];
11
+ };
12
+ tenant: {
13
+ domains: string[];
14
+ };
15
+ client: {
16
+ domains: string[];
17
+ };
18
+ }
19
+ export declare function parseDomainsYaml(content: string): DomainsConfig;
20
+ /** Return all domains (api + admin + tenant + client) in order. */
21
+ export declare function getAllDomains(config: DomainsConfig): string[];
22
+ //# sourceMappingURL=domains.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domains.d.ts","sourceRoot":"","sources":["../../src/lib/domains.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACjD,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC7B,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC9B,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC/B;AASD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAgD/D;AAED,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CAO7D"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Parse domains.yaml format (same as scripts/deploy/domains.yaml).
3
+ */
4
+ const DEFAULT_CONFIG = {
5
+ api: { backend_port: 3000, domains: [] },
6
+ admin: { domains: [] },
7
+ tenant: { domains: [] },
8
+ client: { domains: [] },
9
+ };
10
+ export function parseDomainsYaml(content) {
11
+ const result = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
12
+ const lines = content.split(/\r?\n/);
13
+ let current = null;
14
+ let inDomains = false;
15
+ for (const line of lines) {
16
+ const trimmed = line.trim();
17
+ if (trimmed.startsWith("#") || !trimmed)
18
+ continue;
19
+ if (/^api:\s*$/.test(trimmed)) {
20
+ current = "api";
21
+ inDomains = false;
22
+ continue;
23
+ }
24
+ if (/^admin:\s*$/.test(trimmed)) {
25
+ current = "admin";
26
+ inDomains = false;
27
+ continue;
28
+ }
29
+ if (/^tenant:\s*$/.test(trimmed)) {
30
+ current = "tenant";
31
+ inDomains = false;
32
+ continue;
33
+ }
34
+ if (/^client:\s*$/.test(trimmed)) {
35
+ current = "client";
36
+ inDomains = false;
37
+ continue;
38
+ }
39
+ const backendPortMatch = trimmed.match(/^backend_port:\s*(\d+)\s*$/);
40
+ if (current === "api" && backendPortMatch) {
41
+ result.api.backend_port = parseInt(backendPortMatch[1], 10);
42
+ continue;
43
+ }
44
+ if (current && /^domains:\s*$/.test(trimmed)) {
45
+ inDomains = true;
46
+ continue;
47
+ }
48
+ const domainMatch = trimmed.match(/^-\s*(.+)$/);
49
+ if (current && inDomains && domainMatch) {
50
+ const domain = domainMatch[1].trim();
51
+ if (domain)
52
+ result[current].domains.push(domain);
53
+ }
54
+ }
55
+ return result;
56
+ }
57
+ /** Return all domains (api + admin + tenant + client) in order. */
58
+ export function getAllDomains(config) {
59
+ const list = [];
60
+ for (const d of config.api.domains)
61
+ list.push(d);
62
+ for (const d of config.admin.domains)
63
+ list.push(d);
64
+ for (const d of config.tenant.domains)
65
+ list.push(d);
66
+ for (const d of config.client.domains)
67
+ list.push(d);
68
+ return list;
69
+ }
70
+ //# sourceMappingURL=domains.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domains.js","sourceRoot":"","sources":["../../src/lib/domains.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Unified logger: timestamp, level, optional file output.
3
+ */
4
+ export type LogLevel = "info" | "warn" | "error";
5
+ export declare function setLogFile(filePath: string): void;
6
+ export declare function getLogFilePath(): string | null;
7
+ export declare function info(msg: string): void;
8
+ export declare function warn(msg: string): void;
9
+ export declare function error(msg: string): void;
10
+ /** Append a raw line to the log file (no timestamp/level prefix). */
11
+ export declare function appendRaw(line: string): void;
12
+ /** Append a structured SSL log line (time, action, domain, result, message). */
13
+ export declare function appendSslLog(action: "create" | "renew" | "success" | "failure" | "run", domain: string, result: "ok" | "fail", message?: string): void;
14
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAkBjD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C;AAaD,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAItC;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAItC;AAED,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAIvC;AAED,qEAAqE;AACrE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAC1B,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,KAAK,EAC1D,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,IAAI,GAAG,MAAM,EACrB,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAKN"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Unified logger: timestamp, level, optional file output.
3
+ */
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ const PREFIX = {
7
+ info: "\x1b[32m[INFO]\x1b[0m",
8
+ warn: "\x1b[33m[WARN]\x1b[0m",
9
+ error: "\x1b[31m[ERROR]\x1b[0m",
10
+ };
11
+ function timestamp() {
12
+ return new Date().toISOString().replace("T", " ").slice(0, 19);
13
+ }
14
+ function format(level, msg) {
15
+ return `${timestamp()} ${PREFIX[level]} ${msg}`;
16
+ }
17
+ let logFile = null;
18
+ export function setLogFile(filePath) {
19
+ logFile = filePath;
20
+ }
21
+ export function getLogFilePath() {
22
+ return logFile;
23
+ }
24
+ function writeToLogFileSync(line) {
25
+ if (!logFile)
26
+ return;
27
+ try {
28
+ const dir = path.dirname(logFile);
29
+ fs.mkdirSync(dir, { recursive: true });
30
+ fs.appendFileSync(logFile, line + "\n");
31
+ }
32
+ catch {
33
+ // ignore
34
+ }
35
+ }
36
+ export function info(msg) {
37
+ const line = format("info", msg);
38
+ console.log(line);
39
+ writeToLogFileSync(line);
40
+ }
41
+ export function warn(msg) {
42
+ const line = format("warn", msg);
43
+ console.warn(line);
44
+ writeToLogFileSync(line);
45
+ }
46
+ export function error(msg) {
47
+ const line = format("error", msg);
48
+ console.error(line);
49
+ writeToLogFileSync(line);
50
+ }
51
+ /** Append a raw line to the log file (no timestamp/level prefix). */
52
+ export function appendRaw(line) {
53
+ writeToLogFileSync(line);
54
+ }
55
+ /** Append a structured SSL log line (time, action, domain, result, message). */
56
+ export function appendSslLog(action, domain, result, message) {
57
+ const line = [timestamp(), "ssl", action, domain, result, message ?? ""].join("\t");
58
+ writeToLogFileSync(line);
59
+ }
60
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,MAAM,MAAM,GAA6B;IACvC,IAAI,EAAE,uBAAuB;IAC7B,IAAI,EAAE,uBAAuB;IAC7B,KAAK,EAAE,wBAAwB;CAChC,CAAC;AAEF,SAAS,SAAS;IAChB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,MAAM,CAAC,KAAe,EAAE,GAAW;IAC1C,OAAO,GAAG,SAAS,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC;AAClD,CAAC;AAED,IAAI,OAAO,GAAkB,IAAI,CAAC;AAElC,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,GAAG,QAAQ,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACtC,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAClC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClB,kBAAkB,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,kBAAkB,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,GAAW;IAC/B,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAClC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpB,kBAAkB,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,kBAAkB,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAC1B,MAA0D,EAC1D,MAAc,EACd,MAAqB,EACrB,OAAgB;IAEhB,MAAM,IAAI,GAAG,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAC3E,IAAI,CACL,CAAC;IACF,kBAAkB,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Generate nginx n2.conf from domains config (same output as generate-nginx-conf.js).
3
+ */
4
+ import type { DomainsConfig } from "./domains.js";
5
+ export declare function generateNginxConf(config: DomainsConfig): string;
6
+ //# sourceMappingURL=nginx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nginx.d.ts","sourceRoot":"","sources":["../../src/lib/nginx.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAmFlD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAgC/D"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Generate nginx n2.conf from domains config (same output as generate-nginx-conf.js).
3
+ */
4
+ function apiServerBlock(domain, backendPort) {
5
+ return `# HTTPS - API (${domain})
6
+ server {
7
+ listen 443 ssl http2;
8
+ server_name ${domain};
9
+
10
+ ssl_certificate /etc/nginx/ssl/${domain}.crt;
11
+ ssl_certificate_key /etc/nginx/ssl/${domain}.key;
12
+
13
+ ssl_protocols TLSv1.2 TLSv1.3;
14
+ ssl_ciphers HIGH:!aNULL:!MD5;
15
+ ssl_prefer_server_ciphers on;
16
+ ssl_session_cache shared:SSL:10m;
17
+ ssl_session_timeout 10m;
18
+
19
+ access_log /var/log/nginx/api-access.log;
20
+ error_log /var/log/nginx/api-error.log;
21
+
22
+ location / {
23
+ proxy_pass http://127.0.0.1:${backendPort};
24
+ proxy_http_version 1.1;
25
+ proxy_set_header Host $host;
26
+ proxy_set_header X-Real-IP $remote_addr;
27
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
28
+ proxy_set_header X-Forwarded-Proto $scheme;
29
+ }
30
+
31
+ add_header X-Frame-Options "SAMEORIGIN" always;
32
+ add_header X-Content-Type-Options "nosniff" always;
33
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
34
+ }
35
+
36
+ `;
37
+ }
38
+ function staticAppServerBlock(domain, appName) {
39
+ const root = `/var/www/${appName}`;
40
+ return `# HTTPS - ${appName} (${domain})
41
+ server {
42
+ listen 443 ssl http2;
43
+ server_name ${domain};
44
+
45
+ root ${root};
46
+ index index.html;
47
+
48
+ ssl_certificate /etc/nginx/ssl/${domain}.crt;
49
+ ssl_certificate_key /etc/nginx/ssl/${domain}.key;
50
+
51
+ ssl_protocols TLSv1.2 TLSv1.3;
52
+ ssl_ciphers HIGH:!aNULL:!MD5;
53
+ ssl_prefer_server_ciphers on;
54
+ ssl_session_cache shared:SSL:10m;
55
+ ssl_session_timeout 10m;
56
+
57
+ access_log /var/log/nginx/${appName}-access.log;
58
+ error_log /var/log/nginx/${appName}-error.log;
59
+
60
+ gzip on;
61
+ gzip_vary on;
62
+ gzip_min_length 1024;
63
+ gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
64
+
65
+ location ~* \\.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot|mp3)$ {
66
+ expires 1y;
67
+ add_header Cache-Control "public, immutable";
68
+ access_log off;
69
+ }
70
+
71
+ location / {
72
+ try_files $uri $uri/ /index.html;
73
+ }
74
+
75
+ add_header X-Frame-Options "SAMEORIGIN" always;
76
+ add_header X-Content-Type-Options "nosniff" always;
77
+ add_header X-XSS-Protection "1; mode=block" always;
78
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
79
+ }
80
+
81
+ `;
82
+ }
83
+ export function generateNginxConf(config) {
84
+ const blocks = [];
85
+ const apiPort = config.api.backend_port ?? 3000;
86
+ for (const d of config.api.domains) {
87
+ blocks.push(apiServerBlock(d, apiPort));
88
+ }
89
+ for (const d of config.admin.domains) {
90
+ blocks.push(staticAppServerBlock(d, "admin"));
91
+ }
92
+ for (const d of config.tenant.domains) {
93
+ blocks.push(staticAppServerBlock(d, "tenant"));
94
+ }
95
+ for (const d of config.client.domains) {
96
+ blocks.push(staticAppServerBlock(d, "client"));
97
+ }
98
+ const allDomains = [
99
+ ...config.api.domains,
100
+ ...config.admin.domains,
101
+ ...config.tenant.domains,
102
+ ...config.client.domains,
103
+ ];
104
+ const redirectBlock = `# HTTP to HTTPS redirect
105
+ server {
106
+ listen 80;
107
+ server_name ${allDomains.join(" ")};
108
+ return 301 https://$host$request_uri;
109
+ }
110
+ `;
111
+ return blocks.join("\n") + "\n" + redirectBlock;
112
+ }
113
+ //# sourceMappingURL=nginx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nginx.js","sourceRoot":"","sources":["../../src/lib/nginx.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,SAAS,cAAc,CAAC,MAAc,EAAE,WAAmB;IACzD,OAAO,kBAAkB,MAAM;;;kBAGf,MAAM;;qCAEa,MAAM;yCACF,MAAM;;;;;;;;;;;;sCAYT,WAAW;;;;;;;;;;;;;CAahD,CAAC;AACF,CAAC;AAED,SAAS,oBAAoB,CAAC,MAAc,EAAE,OAAe;IAC3D,MAAM,IAAI,GAAG,YAAY,OAAO,EAAE,CAAC;IACnC,OAAO,aAAa,OAAO,KAAK,MAAM;;;kBAGtB,MAAM;;WAEb,IAAI;;;qCAGsB,MAAM;yCACF,MAAM;;;;;;;;gCAQf,OAAO;+BACR,OAAO;;;;;;;;;;;;;;;;;;;;;;;CAuBrC,CAAC;AACF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAqB;IACrD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC;IAEhD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1C,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,UAAU,GAAG;QACjB,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO;QACrB,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO;QACvB,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO;QACxB,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO;KACzB,CAAC;IACF,MAAM,aAAa,GAAG;;;kBAGN,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;;;CAGrC,CAAC;IAEA,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,aAAa,CAAC;AAClD,CAAC"}
@@ -0,0 +1,8 @@
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
+ export declare function getScriptsDir(cwd?: string): string | null;
8
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/lib/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAgBxE"}
@@ -0,0 +1,28 @@
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
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
+ export function getScriptsDir(cwd = process.cwd()) {
12
+ const envDir = process.env.N2_DEPLOY_SCRIPTS_DIR;
13
+ if (envDir && fs.existsSync(path.join(envDir, "deploy.sh"))) {
14
+ return envDir;
15
+ }
16
+ const monorepo = path.join(cwd, "scripts", "deploy");
17
+ if (fs.existsSync(path.join(monorepo, "deploy.sh"))) {
18
+ return monorepo;
19
+ }
20
+ // From dist/cli.js, package root is ../ and we may have assets/deploy
21
+ const packageRoot = path.join(__dirname, "..", "..");
22
+ const assetsDeploy = path.join(packageRoot, "assets", "deploy");
23
+ if (fs.existsSync(path.join(assetsDeploy, "deploy.sh"))) {
24
+ return assetsDeploy;
25
+ }
26
+ return null;
27
+ }
28
+ //# sourceMappingURL=paths.js.map