@jait/gateway 0.1.396 → 0.1.397
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.
- package/bin/jait.mjs +111 -29
- package/package.json +1 -1
package/bin/jait.mjs
CHANGED
|
@@ -44,6 +44,7 @@ const ENV_PATH = join(JAIT_DIR, ".env");
|
|
|
44
44
|
const LOG_PATH = join(JAIT_DIR, "gateway.log");
|
|
45
45
|
const ERR_LOG_PATH = join(JAIT_DIR, "gateway.err.log");
|
|
46
46
|
const PID_PATH = join(JAIT_DIR, "jait.pid");
|
|
47
|
+
const LEGACY_PID_PATH = join(JAIT_DIR, "gateway.pid");
|
|
47
48
|
|
|
48
49
|
function systemdUnitDir() {
|
|
49
50
|
return join(homedir(), ".config", "systemd", "user");
|
|
@@ -122,6 +123,30 @@ function runSilent(cmd) {
|
|
|
122
123
|
return run(cmd, { silent: true }).trim();
|
|
123
124
|
}
|
|
124
125
|
|
|
126
|
+
function cleanupPidFile(pidPath) {
|
|
127
|
+
try { unlinkSync(pidPath); } catch {}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function getTrackedProcess() {
|
|
131
|
+
for (const pidPath of [PID_PATH, LEGACY_PID_PATH]) {
|
|
132
|
+
if (!existsSync(pidPath)) continue;
|
|
133
|
+
|
|
134
|
+
const pid = readFileSync(pidPath, "utf8").trim();
|
|
135
|
+
if (!pid) {
|
|
136
|
+
cleanupPidFile(pidPath);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (isProcessRunning(pid)) {
|
|
141
|
+
return { pid, pidPath };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
cleanupPidFile(pidPath);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
125
150
|
// ── Cross-platform commands ─────────────────────────────────────────
|
|
126
151
|
|
|
127
152
|
function healthCheck(port) {
|
|
@@ -146,21 +171,53 @@ function healthCheck(port) {
|
|
|
146
171
|
});
|
|
147
172
|
}
|
|
148
173
|
|
|
174
|
+
function isPortReachable(port) {
|
|
175
|
+
return new Promise((resolveP) => {
|
|
176
|
+
const socket = createConnection({ host: "127.0.0.1", port: Number(port) }, () => {
|
|
177
|
+
socket.destroy();
|
|
178
|
+
resolveP(true);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
socket.on("error", () => resolveP(false));
|
|
182
|
+
socket.setTimeout(1000, () => {
|
|
183
|
+
socket.destroy();
|
|
184
|
+
resolveP(false);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function sleep(ms) {
|
|
190
|
+
return new Promise((resolveP) => setTimeout(resolveP, ms));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function waitForBackgroundStart(pid, port, { timeoutMs = 5000, pollMs = 250 } = {}) {
|
|
194
|
+
const deadline = Date.now() + timeoutMs;
|
|
195
|
+
while (Date.now() < deadline) {
|
|
196
|
+
if (!isProcessRunning(pid)) {
|
|
197
|
+
return { ok: false, reason: "exit" };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const health = await healthCheck(port);
|
|
201
|
+
if (health) {
|
|
202
|
+
return { ok: true, health };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
await sleep(pollMs);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!isProcessRunning(pid)) {
|
|
209
|
+
return { ok: false, reason: "exit" };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return { ok: false, reason: "timeout" };
|
|
213
|
+
}
|
|
214
|
+
|
|
149
215
|
async function cmdStatus(port) {
|
|
150
216
|
printBanner();
|
|
151
217
|
port = port || process.env.PORT || "8000";
|
|
152
218
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (existsSync(PID_PATH)) {
|
|
156
|
-
pid = readFileSync(PID_PATH, "utf8").trim();
|
|
157
|
-
const alive = isProcessRunning(pid);
|
|
158
|
-
if (!alive) {
|
|
159
|
-
// Stale PID file
|
|
160
|
-
try { unlinkSync(PID_PATH); } catch {}
|
|
161
|
-
pid = null;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
219
|
+
const tracked = getTrackedProcess();
|
|
220
|
+
const pid = tracked?.pid ?? null;
|
|
164
221
|
|
|
165
222
|
const health = await healthCheck(port);
|
|
166
223
|
if (health) {
|
|
@@ -171,10 +228,14 @@ async function cmdStatus(port) {
|
|
|
171
228
|
console.log(` Healthy: ${health.healthy ? "yes" : "no"}`);
|
|
172
229
|
console.log(` Uptime: ${health.uptime}s`);
|
|
173
230
|
} else {
|
|
231
|
+
const reachable = await isPortReachable(port);
|
|
174
232
|
console.log(` Status: not running`);
|
|
175
233
|
console.log(` Port: ${port} (checked)`);
|
|
176
234
|
if (pid) {
|
|
177
235
|
console.log(` PID: ${pid} (process exists but not responding)`);
|
|
236
|
+
} else if (reachable) {
|
|
237
|
+
console.log(` Health: timed out on /health`);
|
|
238
|
+
console.log(` Note: another process is listening on port ${port}`);
|
|
178
239
|
}
|
|
179
240
|
}
|
|
180
241
|
console.log("");
|
|
@@ -237,19 +298,32 @@ function isProcessRunning(pid) {
|
|
|
237
298
|
}
|
|
238
299
|
}
|
|
239
300
|
|
|
240
|
-
function cmdStart(cliFlags) {
|
|
301
|
+
async function cmdStart(cliFlags) {
|
|
241
302
|
printBanner();
|
|
303
|
+
const port = cliFlags.port || process.env.PORT || "8000";
|
|
304
|
+
|
|
242
305
|
// Check if already running
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (
|
|
246
|
-
console.log(` Jait is already running (PID ${pid}).`);
|
|
306
|
+
const tracked = getTrackedProcess();
|
|
307
|
+
if (tracked) {
|
|
308
|
+
if (await healthCheck(port)) {
|
|
309
|
+
console.log(` Jait is already running (PID ${tracked.pid}).`);
|
|
247
310
|
console.log(` Run 'jait stop' first, or 'jait status' for details.`);
|
|
248
311
|
console.log("");
|
|
249
312
|
process.exit(1);
|
|
250
313
|
}
|
|
251
|
-
|
|
252
|
-
|
|
314
|
+
|
|
315
|
+
console.error(` A tracked Jait process already exists (PID ${tracked.pid}) but is not healthy.`);
|
|
316
|
+
console.error(` Run 'jait stop' or inspect ${LOG_PATH} before starting a new instance.`);
|
|
317
|
+
console.log("");
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (await isPortReachable(port)) {
|
|
322
|
+
console.error(` Port ${port} is already in use.`);
|
|
323
|
+
console.error(` A gateway or another process is listening but not responding to /health.`);
|
|
324
|
+
console.error(` Stop the existing process or start Jait on a different port with 'jait start --port <port>'.`);
|
|
325
|
+
console.log("");
|
|
326
|
+
process.exit(1);
|
|
253
327
|
}
|
|
254
328
|
|
|
255
329
|
mkdirSync(JAIT_DIR, { recursive: true });
|
|
@@ -273,6 +347,20 @@ function cmdStart(cliFlags) {
|
|
|
273
347
|
writeFileSync(PID_PATH, String(child.pid), "utf8");
|
|
274
348
|
child.unref();
|
|
275
349
|
|
|
350
|
+
const started = await waitForBackgroundStart(child.pid, port);
|
|
351
|
+
if (!started.ok) {
|
|
352
|
+
cleanupPidFile(PID_PATH);
|
|
353
|
+
console.error(` Jait failed to become healthy on port ${port}.`);
|
|
354
|
+
if (started.reason === "exit") {
|
|
355
|
+
console.error(` The background process exited during startup.`);
|
|
356
|
+
} else {
|
|
357
|
+
console.error(` The background process did not answer /health within 5 seconds.`);
|
|
358
|
+
}
|
|
359
|
+
console.error(` Logs: ${LOG_PATH}`);
|
|
360
|
+
console.log("");
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
|
|
276
364
|
console.log(` Jait started in background (PID ${child.pid}).`);
|
|
277
365
|
console.log(` Logs: ${LOG_PATH}`);
|
|
278
366
|
console.log(` Run 'jait status' to check health.`);
|
|
@@ -282,20 +370,14 @@ function cmdStart(cliFlags) {
|
|
|
282
370
|
|
|
283
371
|
function cmdStop() {
|
|
284
372
|
printBanner();
|
|
285
|
-
|
|
373
|
+
const tracked = getTrackedProcess();
|
|
374
|
+
if (!tracked) {
|
|
286
375
|
console.log(" Jait is not running (no PID file found).");
|
|
287
376
|
console.log("");
|
|
288
377
|
process.exit(1);
|
|
289
378
|
}
|
|
290
379
|
|
|
291
|
-
const pid =
|
|
292
|
-
|
|
293
|
-
if (!isProcessRunning(pid)) {
|
|
294
|
-
console.log(` Process ${pid} is not running (stale PID file).`);
|
|
295
|
-
try { unlinkSync(PID_PATH); } catch {}
|
|
296
|
-
console.log("");
|
|
297
|
-
process.exit(0);
|
|
298
|
-
}
|
|
380
|
+
const { pid, pidPath } = tracked;
|
|
299
381
|
|
|
300
382
|
try {
|
|
301
383
|
if (platform() === "win32") {
|
|
@@ -308,7 +390,7 @@ function cmdStop() {
|
|
|
308
390
|
console.error(` Failed to stop process ${pid}: ${err.message}`);
|
|
309
391
|
}
|
|
310
392
|
|
|
311
|
-
|
|
393
|
+
cleanupPidFile(pidPath);
|
|
312
394
|
console.log("");
|
|
313
395
|
}
|
|
314
396
|
|
|
@@ -596,7 +678,7 @@ if (args[0] === "status") {
|
|
|
596
678
|
|
|
597
679
|
if (args[0] === "start") {
|
|
598
680
|
parseSubcommandFlags(1);
|
|
599
|
-
cmdStart(flags);
|
|
681
|
+
await cmdStart(flags);
|
|
600
682
|
process.exit(0);
|
|
601
683
|
}
|
|
602
684
|
|