@stacksjs/buddy 0.70.111 → 0.70.113
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/dist/commands/dev.js +21 -11
- package/dist/commands/doctor.js +85 -0
- package/package.json +2 -2
package/dist/commands/dev.js
CHANGED
|
@@ -208,25 +208,34 @@ export async function startDevelopmentServer(_options, _startTime) {
|
|
|
208
208
|
return;
|
|
209
209
|
isExiting = !0;
|
|
210
210
|
closeNativeApp?.();
|
|
211
|
-
|
|
212
|
-
activeRpxRegistryIds.length = 0;
|
|
213
|
-
try {
|
|
214
|
-
process.kill(-process.pid, "SIGTERM");
|
|
215
|
-
} catch {
|
|
211
|
+
const rpxTeardown = (async () => {
|
|
216
212
|
try {
|
|
217
|
-
|
|
213
|
+
await unregisterRpxProxies(activeRpxRegistryIds);
|
|
214
|
+
activeRpxRegistryIds.length = 0;
|
|
215
|
+
if (hasCustomDomain && domain)
|
|
216
|
+
await removeStalePublicDomainOverrides(domain, includeDashboard, options.verbose ?? !1);
|
|
218
217
|
} catch {}
|
|
219
|
-
}
|
|
220
|
-
|
|
218
|
+
})(), teardownDeadline = new Promise((resolve) => setTimeout(resolve, SHUTDOWN_GRACE_MS));
|
|
219
|
+
Promise.race([rpxTeardown, teardownDeadline]).finally(() => {
|
|
221
220
|
try {
|
|
222
|
-
process.kill(
|
|
221
|
+
process.kill(-process.pid, "SIGTERM");
|
|
223
222
|
} catch {
|
|
224
|
-
|
|
223
|
+
try {
|
|
224
|
+
process.kill(0, "SIGTERM");
|
|
225
|
+
} catch {}
|
|
225
226
|
}
|
|
226
|
-
|
|
227
|
+
setTimeout(() => {
|
|
228
|
+
try {
|
|
229
|
+
process.kill(0, "SIGKILL");
|
|
230
|
+
} catch {
|
|
231
|
+
process.exit(1);
|
|
232
|
+
}
|
|
233
|
+
}, SHUTDOWN_GRACE_MS).unref();
|
|
234
|
+
});
|
|
227
235
|
};
|
|
228
236
|
process.on("SIGINT", cleanup);
|
|
229
237
|
process.on("SIGTERM", cleanup);
|
|
238
|
+
process.on("SIGHUP", cleanup);
|
|
230
239
|
const quietOpts = { ...options, quiet: !0 }, a = await actions(), ports = [
|
|
231
240
|
{ name: "Frontend", port: frontendPort },
|
|
232
241
|
{ name: "API", port: apiPort }
|
|
@@ -922,6 +931,7 @@ async function registerRpxProxiesForDomain(input) {
|
|
|
922
931
|
to: proxy.to,
|
|
923
932
|
cwd: process.cwd(),
|
|
924
933
|
createdAt,
|
|
934
|
+
pid: process.pid,
|
|
925
935
|
pathRewrites: proxy.pathRewrites
|
|
926
936
|
}, void 0, verbose);
|
|
927
937
|
if (!activeRpxRegistryIds.includes(proxy.id))
|
package/dist/commands/doctor.js
CHANGED
|
@@ -218,6 +218,91 @@ export function doctor(buddy) {
|
|
|
218
218
|
message: `Could not audit storage config: ${err instanceof Error ? err.message : String(err)}`
|
|
219
219
|
});
|
|
220
220
|
}
|
|
221
|
+
try {
|
|
222
|
+
if (process.platform !== "darwin")
|
|
223
|
+
checks.push({ name: "Dev domains (rpx)", status: "pass", message: "Not macOS (skipped)" });
|
|
224
|
+
else {
|
|
225
|
+
const fs = await import("node:fs"), os = await import("node:os"), path = await import("node:path"), isAlive = (pid) => {
|
|
226
|
+
try {
|
|
227
|
+
process.kill(pid, 0);
|
|
228
|
+
return !0;
|
|
229
|
+
} catch (err) {
|
|
230
|
+
return err.code === "EPERM";
|
|
231
|
+
}
|
|
232
|
+
}, registryDir = path.join(os.homedir(), ".stacks", "rpx", "registry.d"), registered = new Set, deadRegistryFiles = [];
|
|
233
|
+
if (fs.existsSync(registryDir))
|
|
234
|
+
for (const file of fs.readdirSync(registryDir)) {
|
|
235
|
+
if (!file.endsWith(".json"))
|
|
236
|
+
continue;
|
|
237
|
+
try {
|
|
238
|
+
const entry = JSON.parse(fs.readFileSync(path.join(registryDir, file), "utf8"));
|
|
239
|
+
if (entry.to && (entry.pid === void 0 || isAlive(entry.pid)))
|
|
240
|
+
registered.add(entry.to.toLowerCase());
|
|
241
|
+
if (typeof entry.pid === "number" && !isAlive(entry.pid))
|
|
242
|
+
deadRegistryFiles.push(file);
|
|
243
|
+
} catch {}
|
|
244
|
+
}
|
|
245
|
+
const staleHosts = new Set, staleResolvers = [], hostsPath = "/etc/hosts", hostsLines = fs.existsSync(hostsPath) ? fs.readFileSync(hostsPath, "utf8").split(`
|
|
246
|
+
`) : [];
|
|
247
|
+
for (let i = 0;i < hostsLines.length; i++) {
|
|
248
|
+
const line = hostsLines[i];
|
|
249
|
+
if (line.trim() === "# Added by rpx") {
|
|
250
|
+
for (let j = i + 1;j < hostsLines.length; j++) {
|
|
251
|
+
const blockLine = hostsLines[j].trim();
|
|
252
|
+
if (blockLine === "" || blockLine.startsWith("#"))
|
|
253
|
+
break;
|
|
254
|
+
const names = blockLine.split("#")[0]?.trim().split(/\s+/).slice(1) ?? [];
|
|
255
|
+
for (const name of names)
|
|
256
|
+
if (!registered.has(name.toLowerCase()))
|
|
257
|
+
staleHosts.add(name);
|
|
258
|
+
}
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const hash = line.indexOf("#");
|
|
262
|
+
if (hash === -1)
|
|
263
|
+
continue;
|
|
264
|
+
const marker = /^rpx(?::pid=(\d+))?$/.exec(line.slice(hash + 1).trim());
|
|
265
|
+
if (!marker)
|
|
266
|
+
continue;
|
|
267
|
+
const names = line.slice(0, hash).trim().split(/\s+/).slice(1), pid = marker[1] ? Number.parseInt(marker[1], 10) : null;
|
|
268
|
+
if (pid !== null ? !isAlive(pid) : names.every((n) => !registered.has(n.toLowerCase())))
|
|
269
|
+
for (const name of names)
|
|
270
|
+
staleHosts.add(name);
|
|
271
|
+
}
|
|
272
|
+
const resolverDir = "/etc/resolver";
|
|
273
|
+
if (fs.existsSync(resolverDir))
|
|
274
|
+
for (const file of fs.readdirSync(resolverDir))
|
|
275
|
+
try {
|
|
276
|
+
const content = fs.readFileSync(path.join(resolverDir, file), "utf8");
|
|
277
|
+
if (!content.includes("127.0.0.1") || !content.includes("15353"))
|
|
278
|
+
continue;
|
|
279
|
+
const domain = file.toLowerCase();
|
|
280
|
+
if (![...registered].some((host) => host === domain || host.endsWith(`.${domain}`)))
|
|
281
|
+
staleResolvers.push(file);
|
|
282
|
+
} catch {}
|
|
283
|
+
if (staleHosts.size > 0 || staleResolvers.length > 0 || deadRegistryFiles.length > 0) {
|
|
284
|
+
const parts = [];
|
|
285
|
+
if (staleHosts.size > 0)
|
|
286
|
+
parts.push(`hosts(${[...staleHosts].join(", ")})`);
|
|
287
|
+
if (staleResolvers.length > 0)
|
|
288
|
+
parts.push(`resolver(${staleResolvers.join(", ")})`);
|
|
289
|
+
if (deadRegistryFiles.length > 0)
|
|
290
|
+
parts.push(`registry(${deadRegistryFiles.join(", ")})`);
|
|
291
|
+
checks.push({
|
|
292
|
+
name: "Dev domains (rpx)",
|
|
293
|
+
status: "warn",
|
|
294
|
+
message: `Stale loopback overrides from dead dev sessions: ${parts.join(" ")}. These keep pointing the domain at 127.0.0.1. Remove with: sudo nano /etc/hosts; sudo rm /etc/resolver/<name>; rm ~/.stacks/rpx/registry.d/<file>. Updating @stacksjs/rpx lets the daemon sweep pid-stamped entries automatically.`
|
|
295
|
+
});
|
|
296
|
+
} else
|
|
297
|
+
checks.push({ name: "Dev domains (rpx)", status: "pass", message: "No stale dev-domain overrides" });
|
|
298
|
+
}
|
|
299
|
+
} catch (err) {
|
|
300
|
+
checks.push({
|
|
301
|
+
name: "Dev domains (rpx)",
|
|
302
|
+
status: "warn",
|
|
303
|
+
message: `Could not audit dev-domain overrides: ${err instanceof Error ? err.message : String(err)}`
|
|
304
|
+
});
|
|
305
|
+
}
|
|
221
306
|
try {
|
|
222
307
|
const orphans = [];
|
|
223
308
|
for (const name of FEATURE_NAMES) {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/buddy",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.70.
|
|
5
|
+
"version": "0.70.113",
|
|
6
6
|
"description": "Meet Buddy. The Stacks runtime.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
"@stacksjs/payments": "^0.70.23",
|
|
125
125
|
"@stacksjs/realtime": "^0.70.23",
|
|
126
126
|
"@stacksjs/router": "^0.70.23",
|
|
127
|
-
"@stacksjs/rpx": "^0.11.
|
|
127
|
+
"@stacksjs/rpx": "^0.11.29",
|
|
128
128
|
"@stacksjs/search-engine": "^0.70.23",
|
|
129
129
|
"@stacksjs/security": "^0.70.23",
|
|
130
130
|
"@stacksjs/server": "^0.70.23",
|