@vibes.diy/api-svc 13.1.12 → 13.1.13
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/create-handler.js +2 -0
- package/create-handler.js.map +1 -1
- package/evento-handler-manifest.js +2 -0
- package/evento-handler-manifest.js.map +1 -1
- package/intern/backend-egress.d.ts +1 -0
- package/intern/backend-egress.js +24 -10
- package/intern/backend-egress.js.map +1 -1
- package/intern/components/vibe-page.js +29 -1
- package/intern/components/vibe-page.js.map +1 -1
- package/intern/egress-read-lane.js.map +1 -1
- package/intern/egress-request-log.d.ts +14 -0
- package/intern/egress-request-log.js +16 -0
- package/intern/egress-request-log.js.map +1 -0
- package/intern/render-vibe.js +2 -0
- package/intern/render-vibe.js.map +1 -1
- package/intern/ssr-theme-css.d.ts +1 -0
- package/intern/ssr-theme-css.js +12 -0
- package/intern/ssr-theme-css.js.map +1 -1
- package/package.json +12 -11
- package/public/report-egress.d.ts +19 -0
- package/public/report-egress.js +168 -0
- package/public/report-egress.js.map +1 -0
- package/usage-report/egress-abuse-alert-util.d.ts +100 -0
- package/usage-report/egress-abuse-alert-util.js +246 -0
- package/usage-report/egress-abuse-alert-util.js.map +1 -0
- package/usage-report/egress-abuse-alert.d.ts +1 -0
- package/usage-report/egress-abuse-alert.js +94 -0
- package/usage-report/egress-abuse-alert.js.map +1 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Pool } from "@neondatabase/serverless";
|
|
2
|
+
import { Result, exception2Result } from "@adviser/cement";
|
|
3
|
+
import { arg, flag, formatError, loadDevVars } from "./usage-report-util.js";
|
|
4
|
+
import { buildEgressAlertEmbed, buildMissingTablesEmbed, isUndefinedTableError, resolveThresholds, summarizeEgress, } from "./egress-abuse-alert-util.js";
|
|
5
|
+
const DEFAULT_SINCE_HOURS = 24;
|
|
6
|
+
const ROW_CAP = 50000;
|
|
7
|
+
function asString(v) {
|
|
8
|
+
return typeof v === "string" ? v : "";
|
|
9
|
+
}
|
|
10
|
+
async function postMissingTables(webhookUrl, dryRun, sinceHours) {
|
|
11
|
+
const body = buildMissingTablesEmbed(sinceHours);
|
|
12
|
+
if (dryRun) {
|
|
13
|
+
console.log(JSON.stringify(body, null, 2));
|
|
14
|
+
return Result.Ok(undefined);
|
|
15
|
+
}
|
|
16
|
+
return exception2Result(async () => {
|
|
17
|
+
const res = await fetch(webhookUrl, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: { "Content-Type": "application/json" },
|
|
20
|
+
body: JSON.stringify(body),
|
|
21
|
+
});
|
|
22
|
+
if (res.status !== 204)
|
|
23
|
+
throw new Error(`discord post returned ${res.status}`);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
async function run() {
|
|
27
|
+
loadDevVars();
|
|
28
|
+
const sinceHours = Number(arg("--since-hours") ?? DEFAULT_SINCE_HOURS);
|
|
29
|
+
if (!Number.isFinite(sinceHours) || sinceHours <= 0) {
|
|
30
|
+
return Result.Err("usage: pnpm --dir vibes.diy/api/svc run egress-abuse-alert [--since-hours 24] [--dry-run]");
|
|
31
|
+
}
|
|
32
|
+
const connectionString = process.env["NEON_DATABASE_URL"];
|
|
33
|
+
if (connectionString === undefined)
|
|
34
|
+
return Result.Err("NEON_DATABASE_URL is required (prod Neon)");
|
|
35
|
+
const webhookUrl = process.env["DISCORD_WEBHOOK_URL"];
|
|
36
|
+
const thresholds = resolveThresholds({
|
|
37
|
+
EGRESS_ALERT_HOST_REQUESTS: process.env["EGRESS_ALERT_HOST_REQUESTS"],
|
|
38
|
+
EGRESS_ALERT_HOST_VIBES: process.env["EGRESS_ALERT_HOST_VIBES"],
|
|
39
|
+
EGRESS_ALERT_VIBE_HOSTS: process.env["EGRESS_ALERT_VIBE_HOSTS"],
|
|
40
|
+
EGRESS_ALERT_TRANSPORT_REQUESTS: process.env["EGRESS_ALERT_TRANSPORT_REQUESTS"],
|
|
41
|
+
EGRESS_ALERT_TRANSPORT_SHARE: process.env["EGRESS_ALERT_TRANSPORT_SHARE"],
|
|
42
|
+
EGRESS_ALERT_SUSPECT_EVENTS: process.env["EGRESS_ALERT_SUSPECT_EVENTS"],
|
|
43
|
+
});
|
|
44
|
+
const dryRun = flag("--dry-run") || webhookUrl === undefined || webhookUrl === "";
|
|
45
|
+
const sinceIso = new Date(Date.now() - sinceHours * 3600_000).toISOString();
|
|
46
|
+
const pool = new Pool({ connectionString });
|
|
47
|
+
const result = await exception2Result(async () => {
|
|
48
|
+
const eventsRes = await pool.query(`select outcome, host, "finalHost", "ownerHandle", "appSlug"
|
|
49
|
+
from "EgressEvents" where ts >= $1 order by ts desc limit ${ROW_CAP}`, [sinceIso]);
|
|
50
|
+
const events = eventsRes.rows.map((r) => ({
|
|
51
|
+
outcome: asString(r.outcome),
|
|
52
|
+
host: asString(r.host),
|
|
53
|
+
finalHost: asString(r.finalHost),
|
|
54
|
+
ownerHandle: asString(r.ownerHandle),
|
|
55
|
+
appSlug: asString(r.appSlug),
|
|
56
|
+
}));
|
|
57
|
+
const suspectRes = await pool.query(`select host, "ownerHandle", "appSlug", reasons
|
|
58
|
+
from "EgressSuspectEvents" where ts >= $1 order by ts desc limit ${ROW_CAP}`, [sinceIso]);
|
|
59
|
+
const suspects = suspectRes.rows.map((r) => ({
|
|
60
|
+
host: asString(r.host),
|
|
61
|
+
ownerHandle: asString(r.ownerHandle),
|
|
62
|
+
appSlug: asString(r.appSlug),
|
|
63
|
+
reasons: asString(r.reasons),
|
|
64
|
+
}));
|
|
65
|
+
const summary = summarizeEgress(events, suspects, thresholds);
|
|
66
|
+
const sampled = events.length === ROW_CAP || suspects.length === ROW_CAP;
|
|
67
|
+
const body = buildEgressAlertEmbed({ summary, sinceHours, sampled });
|
|
68
|
+
console.log(`[egress-abuse-alert] window=${sinceHours}h requests=${summary.requests} hosts=${summary.distinctHosts} vibes=${summary.distinctVibes} suspects=${summary.suspectEvents} signals=${summary.tripped.length} posted=${!dryRun}`);
|
|
69
|
+
if (dryRun) {
|
|
70
|
+
console.log(JSON.stringify(body, null, 2));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const res = await fetch(webhookUrl, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: { "Content-Type": "application/json" },
|
|
76
|
+
body: JSON.stringify(body),
|
|
77
|
+
});
|
|
78
|
+
if (res.status !== 204)
|
|
79
|
+
throw new Error(`discord post returned ${res.status}`);
|
|
80
|
+
});
|
|
81
|
+
await pool.end();
|
|
82
|
+
if (result.isErr() && isUndefinedTableError(result.Err())) {
|
|
83
|
+
console.log("[egress-abuse-alert] EgressEvents/EgressSuspectEvents missing — reporting, not suppressing.");
|
|
84
|
+
return await postMissingTables(webhookUrl, dryRun, sinceHours);
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
run().then((result) => {
|
|
89
|
+
if (result.isErr()) {
|
|
90
|
+
console.error(formatError(result.Err()));
|
|
91
|
+
process.exitCode = 1;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=egress-abuse-alert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"egress-abuse-alert.js","sourceRoot":"","sources":["../../jsr/usage-report/egress-abuse-alert.ts"],"names":[],"mappings":"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"}
|