@teamscala/service-boot 0.23.295 → 0.23.297
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/package.json
CHANGED
|
@@ -97,7 +97,10 @@ async function scalaToolsCurrencyWatch(_ctx: { config: ScheduledJobConfig }): Pr
|
|
|
97
97
|
);
|
|
98
98
|
const install = await spawn({
|
|
99
99
|
name: "scala-tools-currency-watch:deps-install",
|
|
100
|
-
|
|
100
|
+
// A plain install fetches the current version, which is the whole point
|
|
101
|
+
// of this watch. Re-resolving the entire tree is an emergency hatch, not
|
|
102
|
+
// a currency step (operator ruling 2026-07-31).
|
|
103
|
+
command: ["scala-tools", "deps", "install"],
|
|
101
104
|
cwd: SENTINEL_DIR,
|
|
102
105
|
timeoutMs: 300_000,
|
|
103
106
|
});
|
|
@@ -14,6 +14,8 @@ import { join } from "node:path";
|
|
|
14
14
|
import type { Hono } from "hono";
|
|
15
15
|
import { etag } from "hono/etag";
|
|
16
16
|
import { buildErrorReport } from "@teamscala/os/errors/error-report";
|
|
17
|
+
import { collectHeapReport } from "@teamscala/os/observability/heap-report";
|
|
18
|
+
import { isLoopbackHost } from "@teamscala/os/observability/loopback-host";
|
|
17
19
|
import { handleAssetProxy } from "./asset-proxy";
|
|
18
20
|
import { resolveBrandFaviconPath, warmBrandFaviconCache } from "./resolve-brand-favicon";
|
|
19
21
|
|
|
@@ -37,41 +39,20 @@ export async function registerStaticAssets(
|
|
|
37
39
|
}),
|
|
38
40
|
);
|
|
39
41
|
|
|
40
|
-
// Localhost-gated heap-attribution probe —
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
42
|
+
// Localhost-gated heap-attribution probe — the heapSize-vs-RSS split (JS heap
|
|
43
|
+
// vs native: OTel/Prisma-engine/buffers/compiled code) plus the top object
|
|
44
|
+
// types by count. Read-only, no secrets; gated to a localhost Host so it never
|
|
45
|
+
// answers over the public domain. Registered here (before auth + page routes)
|
|
46
|
+
// so it is reachable on every service kind, like /health
|
|
47
|
+
// (`verify-via-127.0.0.1`, sibling of `runtime-metrics-via-railway-cli`).
|
|
48
|
+
//
|
|
49
|
+
// The payload shape lives in @teamscala/os so standalone `Bun.serve` daemons
|
|
50
|
+
// (scala-guard) answer this probe identically — `scala-tools heap <slug>` must
|
|
51
|
+
// not mean different things depending on which process replied.
|
|
47
52
|
app.get("/_heap", async (c) => {
|
|
48
|
-
|
|
49
|
-
const isLocal =
|
|
50
|
-
host.startsWith("127.0.0.1") || host.startsWith("localhost") || host.startsWith("[::1]");
|
|
51
|
-
if (!isLocal) return c.json({ error: "localhost only" }, 403);
|
|
53
|
+
if (!isLoopbackHost(c.req.header("host"))) return c.json({ error: "localhost only" }, 403);
|
|
52
54
|
try {
|
|
53
|
-
|
|
54
|
-
const s = heapStats() as unknown as {
|
|
55
|
-
heapSize: number;
|
|
56
|
-
heapCapacity: number;
|
|
57
|
-
objectCount: number;
|
|
58
|
-
objectTypeCounts?: Record<string, number>;
|
|
59
|
-
};
|
|
60
|
-
const rss = process.memoryUsage.rss();
|
|
61
|
-
const topObjectTypes = Object.fromEntries(
|
|
62
|
-
Object.entries(s.objectTypeCounts ?? {})
|
|
63
|
-
.sort((a, b) => b[1] - a[1])
|
|
64
|
-
.slice(0, 40),
|
|
65
|
-
);
|
|
66
|
-
return c.json({
|
|
67
|
-
service: serviceSlug,
|
|
68
|
-
rss,
|
|
69
|
-
heapSize: s.heapSize,
|
|
70
|
-
heapCapacity: s.heapCapacity,
|
|
71
|
-
objectCount: s.objectCount,
|
|
72
|
-
nativeApprox: Math.max(0, rss - s.heapSize),
|
|
73
|
-
topObjectTypes,
|
|
74
|
-
});
|
|
55
|
+
return c.json(await collectHeapReport(serviceSlug));
|
|
75
56
|
} catch (err) {
|
|
76
57
|
const report = buildErrorReport(err, { service: serviceSlug, url: c.req.url });
|
|
77
58
|
return new Response(JSON.stringify(report.http.body), {
|
|
@@ -113,7 +113,11 @@ async function checkCurrency(): Promise<{ healthy: boolean; details?: Record<str
|
|
|
113
113
|
});
|
|
114
114
|
const result = await spawn({
|
|
115
115
|
name: "scala-tools-currency-repair",
|
|
116
|
-
|
|
116
|
+
// A stale installed version needs the current one fetched, which a plain
|
|
117
|
+
// install does. Re-resolving the whole tree to achieve that is an emergency
|
|
118
|
+
// escape hatch, not a currency step, and running it automatically burns host
|
|
119
|
+
// resources for no gain (operator ruling 2026-07-31).
|
|
120
|
+
command: ["node_modules/.bin/scala-tools", "deps", "install", "--dir", cwd],
|
|
117
121
|
cwd,
|
|
118
122
|
timeoutMs: cfg.command_timeout_ms,
|
|
119
123
|
captureStderr: true,
|