tina4-nodejs 3.13.83 → 3.13.85

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.
@@ -45,21 +45,77 @@ function readCliVersion(): string {
45
45
 
46
46
  // ── Port-kill helper ────────────────────────────────────────────────
47
47
 
48
+ /**
49
+ * Whether this process is running inside a container.
50
+ *
51
+ * Reclaiming a port makes sense on a dev machine, where a previous serve may
52
+ * still hold it. Inside a container the server IS the container, so there is no
53
+ * stale sibling to reclaim from -- and trying is dangerous (see below).
54
+ */
55
+ function inContainer(): boolean {
56
+ if (existsSync("/.dockerenv") || existsSync("/run/.containerenv")) return true;
57
+ try {
58
+ const blob = readFileSync("/proc/1/cgroup", "utf-8");
59
+ return blob.includes("docker") || blob.includes("containerd") || blob.includes("kubepods");
60
+ } catch {
61
+ return false;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Kill any process listening on `port`. Returns true if anything was killed.
67
+ *
68
+ * Every PID is validated first. `parseInt` on a non-numeric lsof field yields
69
+ * 1, and SIGTERM to PID 1 is the container's own init -- which is exactly how a
70
+ * production container logged "Killed existing process on port 7148 (PID: 1
71
+ * ...)" and then exited 143, killing itself on startup.
72
+ */
73
+ /**
74
+ * The PIDs from `lsof -ti` output that are safe to signal.
75
+ *
76
+ * Pure so the safety rule can be tested directly. An unvalidated parse is a
77
+ * footgun with real teeth: where lsof prints a different shape than -ti
78
+ * implies, a non-numeric field becomes 0, and signalling PID 0 hits EVERY
79
+ * process in the caller's own process group -- the server kills itself. That
80
+ * is what produced "Killed existing process on port 7148 (PID: 1 ...)" in a
81
+ * real image, where the container then exited 143.
82
+ *
83
+ * Accepts only all-digit tokens; never PID 0 (our group), PID 1 (init),
84
+ * ourselves, or our own process group.
85
+ */
86
+ export function selectablePids(lsofOutput: string, me: number, myGroup?: number): number[] {
87
+ const pids: number[] = [];
88
+ for (const token of lsofOutput.split(/\s+/)) {
89
+ if (!/^\d+$/.test(token)) continue; // never coerce junk into a PID
90
+ const pid = Number(token);
91
+ if (pid <= 1 || pid === me) continue; // 0 = our group, 1 = init, me = suicide
92
+ if (myGroup !== undefined && pid === myGroup) continue;
93
+ if (!pids.includes(pid)) pids.push(pid);
94
+ }
95
+ return pids;
96
+ }
97
+
48
98
  function killProcessOnPort(port: number): boolean {
99
+ if (inContainer()) return false;
49
100
  try {
50
101
  const result = execSync(`lsof -ti :${port}`, { encoding: "utf-8", timeout: 5000 }).trim();
51
- if (result) {
52
- const pids = result.split("\n");
53
- for (const pid of pids) {
54
- try {
55
- process.kill(parseInt(pid, 10), "SIGTERM");
56
- } catch {
57
- // ignore ProcessLookupError / PermissionError
58
- }
102
+ if (!result) return false;
103
+
104
+ const killed: string[] = [];
105
+ // Node core exposes no getpgrp(), so myGroup stays unset here. The pid <= 1
106
+ // guard already covers the dangerous case (a junk field coercing to 0);
107
+ // Python and Ruby pass their real process group in addition.
108
+ for (const pid of selectablePids(result, process.pid)) {
109
+ try {
110
+ process.kill(pid, "SIGTERM");
111
+ killed.push(String(pid));
112
+ } catch {
113
+ // ignore ProcessLookupError / PermissionError
59
114
  }
60
- console.log(` Killed existing process on port ${port} (PID: ${pids.join(", ")})`);
61
- return true;
62
115
  }
116
+ if (killed.length === 0) return false;
117
+ console.log(` Killed existing process on port ${port} (PID: ${killed.join(", ")})`);
118
+ return true;
63
119
  } catch {
64
120
  // lsof not found or no process on port — that's fine
65
121
  }
@@ -133,7 +133,7 @@ COPY --from=build /app .
133
133
  ENV HOST=0.0.0.0
134
134
  ENV PORT=7148
135
135
  EXPOSE 7148
136
- CMD ["npx", "tsx", "app.ts"]
136
+ CMD ["npx", "tina4nodejs", "serve", "--production"]
137
137
  `
138
138
  );
139
139
  }