@wizeworks/lens-hub 0.3.0-alpha.3 → 0.3.0-alpha.4

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.
Files changed (190) hide show
  1. package/dist/alerts/api.d.ts +5 -0
  2. package/dist/alerts/api.d.ts.map +1 -0
  3. package/dist/alerts/api.js +87 -0
  4. package/dist/alerts/api.js.map +1 -0
  5. package/dist/alerts/deliver.d.ts +54 -0
  6. package/dist/alerts/deliver.d.ts.map +1 -0
  7. package/dist/alerts/deliver.js +66 -0
  8. package/dist/alerts/deliver.js.map +1 -0
  9. package/dist/alerts/evaluate.d.ts +16 -0
  10. package/dist/alerts/evaluate.d.ts.map +1 -0
  11. package/dist/alerts/evaluate.js +76 -0
  12. package/dist/alerts/evaluate.js.map +1 -0
  13. package/dist/alerts/loop.d.ts +10 -0
  14. package/dist/alerts/loop.d.ts.map +1 -0
  15. package/dist/alerts/loop.js +27 -0
  16. package/dist/alerts/loop.js.map +1 -0
  17. package/dist/alerts/store.d.ts +32 -0
  18. package/dist/alerts/store.d.ts.map +1 -0
  19. package/dist/alerts/store.js +38 -0
  20. package/dist/alerts/store.js.map +1 -0
  21. package/dist/alerts/target.d.ts +3 -0
  22. package/dist/alerts/target.d.ts.map +1 -0
  23. package/dist/alerts/target.js +23 -0
  24. package/dist/alerts/target.js.map +1 -0
  25. package/dist/api.d.ts +5 -0
  26. package/dist/api.d.ts.map +1 -1
  27. package/dist/api.js +38 -4
  28. package/dist/api.js.map +1 -1
  29. package/dist/body.d.ts +2 -2
  30. package/dist/body.d.ts.map +1 -1
  31. package/dist/body.js +4 -4
  32. package/dist/body.js.map +1 -1
  33. package/dist/cli-args.d.ts +1 -1
  34. package/dist/cli-args.d.ts.map +1 -1
  35. package/dist/cli-args.js +32 -1
  36. package/dist/cli-args.js.map +1 -1
  37. package/dist/data.js +1 -1
  38. package/dist/data.js.map +1 -1
  39. package/dist/hub.d.ts.map +1 -1
  40. package/dist/hub.js +15 -3
  41. package/dist/hub.js.map +1 -1
  42. package/dist/infra-read.d.ts +11 -0
  43. package/dist/infra-read.d.ts.map +1 -0
  44. package/dist/infra-read.js +30 -0
  45. package/dist/infra-read.js.map +1 -0
  46. package/dist/ingest.d.ts.map +1 -1
  47. package/dist/ingest.js +14 -3
  48. package/dist/ingest.js.map +1 -1
  49. package/dist/issues.d.ts +10 -0
  50. package/dist/issues.d.ts.map +1 -0
  51. package/dist/issues.js +34 -0
  52. package/dist/issues.js.map +1 -0
  53. package/dist/kit.d.ts +6 -0
  54. package/dist/kit.d.ts.map +1 -1
  55. package/dist/kit.js +4 -0
  56. package/dist/kit.js.map +1 -1
  57. package/dist/list-search.d.ts +10 -0
  58. package/dist/list-search.d.ts.map +1 -0
  59. package/dist/list-search.js +13 -0
  60. package/dist/list-search.js.map +1 -0
  61. package/dist/mcp.d.ts +3 -2
  62. package/dist/mcp.d.ts.map +1 -1
  63. package/dist/mcp.js +57 -11
  64. package/dist/mcp.js.map +1 -1
  65. package/dist/metrics-read.js +1 -1
  66. package/dist/metrics-read.js.map +1 -1
  67. package/dist/models-api.d.ts +11 -1
  68. package/dist/models-api.d.ts.map +1 -1
  69. package/dist/models-api.js +41 -15
  70. package/dist/models-api.js.map +1 -1
  71. package/dist/options.d.ts +23 -2
  72. package/dist/options.d.ts.map +1 -1
  73. package/dist/options.js +10 -1
  74. package/dist/options.js.map +1 -1
  75. package/dist/otlp/db-params.d.ts +7 -0
  76. package/dist/otlp/db-params.d.ts.map +1 -0
  77. package/dist/otlp/db-params.js +74 -0
  78. package/dist/otlp/db-params.js.map +1 -0
  79. package/dist/otlp/logs.d.ts +1 -1
  80. package/dist/otlp/logs.d.ts.map +1 -1
  81. package/dist/otlp/logs.js +8 -7
  82. package/dist/otlp/logs.js.map +1 -1
  83. package/dist/otlp/metrics.d.ts +3 -3
  84. package/dist/otlp/metrics.d.ts.map +1 -1
  85. package/dist/otlp/metrics.js +7 -6
  86. package/dist/otlp/metrics.js.map +1 -1
  87. package/dist/otlp/nested.d.ts +4 -0
  88. package/dist/otlp/nested.d.ts.map +1 -0
  89. package/dist/otlp/nested.js +19 -0
  90. package/dist/otlp/nested.js.map +1 -0
  91. package/dist/otlp/semconv.d.ts +17 -0
  92. package/dist/otlp/semconv.d.ts.map +1 -0
  93. package/dist/otlp/semconv.js +68 -0
  94. package/dist/otlp/semconv.js.map +1 -0
  95. package/dist/otlp/spans.d.ts +3 -3
  96. package/dist/otlp/spans.d.ts.map +1 -1
  97. package/dist/otlp/spans.js +15 -7
  98. package/dist/otlp/spans.js.map +1 -1
  99. package/dist/otlp/values.d.ts +5 -10
  100. package/dist/otlp/values.d.ts.map +1 -1
  101. package/dist/otlp/values.js +32 -24
  102. package/dist/otlp/values.js.map +1 -1
  103. package/dist/saved.d.ts +7 -0
  104. package/dist/saved.d.ts.map +1 -0
  105. package/dist/saved.js +49 -0
  106. package/dist/saved.js.map +1 -0
  107. package/dist/scale-exec.d.ts +2 -2
  108. package/dist/scale-exec.d.ts.map +1 -1
  109. package/dist/scale-exec.js +4 -4
  110. package/dist/scale-exec.js.map +1 -1
  111. package/dist/schema-saved.d.ts +15 -0
  112. package/dist/schema-saved.d.ts.map +1 -0
  113. package/dist/schema-saved.js +43 -0
  114. package/dist/schema-saved.js.map +1 -0
  115. package/dist/schema-scale.d.ts.map +1 -1
  116. package/dist/schema-scale.js +11 -1
  117. package/dist/schema-scale.js.map +1 -1
  118. package/dist/schema.d.ts +2 -2
  119. package/dist/schema.d.ts.map +1 -1
  120. package/dist/schema.js +20 -1
  121. package/dist/schema.js.map +1 -1
  122. package/dist/search-api.d.ts +1 -1
  123. package/dist/search-api.d.ts.map +1 -1
  124. package/dist/search-api.js +7 -5
  125. package/dist/search-api.js.map +1 -1
  126. package/dist/settings-prune.d.ts +12 -0
  127. package/dist/settings-prune.d.ts.map +1 -0
  128. package/dist/settings-prune.js +15 -0
  129. package/dist/settings-prune.js.map +1 -0
  130. package/dist/settings.d.ts +27 -0
  131. package/dist/settings.d.ts.map +1 -0
  132. package/dist/settings.js +64 -0
  133. package/dist/settings.js.map +1 -0
  134. package/dist/settle.d.ts +3 -3
  135. package/dist/settle.d.ts.map +1 -1
  136. package/dist/settle.js +12 -6
  137. package/dist/settle.js.map +1 -1
  138. package/dist/slos.d.ts +14 -0
  139. package/dist/slos.d.ts.map +1 -0
  140. package/dist/slos.js +73 -0
  141. package/dist/slos.js.map +1 -0
  142. package/dist/sourcemaps-api.d.ts +15 -0
  143. package/dist/sourcemaps-api.d.ts.map +1 -0
  144. package/dist/sourcemaps-api.js +55 -0
  145. package/dist/sourcemaps-api.js.map +1 -0
  146. package/dist/sourcemaps.d.ts +10 -0
  147. package/dist/sourcemaps.d.ts.map +1 -0
  148. package/dist/sourcemaps.js +41 -0
  149. package/dist/sourcemaps.js.map +1 -0
  150. package/dist/store-read.d.ts +2 -0
  151. package/dist/store-read.d.ts.map +1 -1
  152. package/dist/store-read.js +3 -1
  153. package/dist/store-read.js.map +1 -1
  154. package/dist/store.d.ts +13 -3
  155. package/dist/store.d.ts.map +1 -1
  156. package/dist/store.js +35 -10
  157. package/dist/store.js.map +1 -1
  158. package/dist/tags-api.d.ts +5 -0
  159. package/dist/tags-api.d.ts.map +1 -0
  160. package/dist/tags-api.js +94 -0
  161. package/dist/tags-api.js.map +1 -0
  162. package/dist/tags.d.ts +11 -0
  163. package/dist/tags.d.ts.map +1 -0
  164. package/dist/tags.js +31 -0
  165. package/dist/tags.js.map +1 -0
  166. package/dist/uptime/api.d.ts +5 -0
  167. package/dist/uptime/api.d.ts.map +1 -0
  168. package/dist/uptime/api.js +78 -0
  169. package/dist/uptime/api.js.map +1 -0
  170. package/dist/uptime/cert.d.ts +5 -0
  171. package/dist/uptime/cert.d.ts.map +1 -0
  172. package/dist/uptime/cert.js +26 -0
  173. package/dist/uptime/cert.js.map +1 -0
  174. package/dist/uptime/guard.d.ts +13 -0
  175. package/dist/uptime/guard.d.ts.map +1 -0
  176. package/dist/uptime/guard.js +38 -0
  177. package/dist/uptime/guard.js.map +1 -0
  178. package/dist/uptime/run.d.ts +11 -0
  179. package/dist/uptime/run.d.ts.map +1 -0
  180. package/dist/uptime/run.js +96 -0
  181. package/dist/uptime/run.js.map +1 -0
  182. package/dist/uptime/schedule.d.ts +15 -0
  183. package/dist/uptime/schedule.d.ts.map +1 -0
  184. package/dist/uptime/schedule.js +26 -0
  185. package/dist/uptime/schedule.js.map +1 -0
  186. package/dist/uptime/store.d.ts +25 -0
  187. package/dist/uptime/store.d.ts.map +1 -0
  188. package/dist/uptime/store.js +80 -0
  189. package/dist/uptime/store.js.map +1 -0
  190. package/package.json +4 -4
@@ -0,0 +1,5 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import { type HubAlertDeps } from "./evaluate.js";
3
+ /** Routes under `api/alerts`. */
4
+ export declare function handleAlerts(deps: HubAlertDeps, now: number, sub: string, req: IncomingMessage, res: ServerResponse, url: URL): Promise<void>;
5
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/alerts/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAMjE,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,eAAe,CAAC;AA2E7D,iCAAiC;AACjC,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAQnJ"}
@@ -0,0 +1,87 @@
1
+ import { MUTED_FOREVER, parseAlertRule } from "@wizeworks/lens-core";
2
+ import { sendJson } from "@wizeworks/lens-node/kit";
3
+ import { parseJson, readBody } from "../body.js";
4
+ import { sloById } from "../slos.js";
5
+ import { checkTarget } from "./target.js";
6
+ import { notifyHub } from "./evaluate.js";
7
+ import { addEvent, createRule, deleteRule, listEvents, listRules, ruleById, ruleEvents, ruleValues, saveRule } from "./store.js";
8
+ const DAY_MS = 86_400_000;
9
+ const body = async (req) => (parseJson(await readBody(req)) ?? {});
10
+ async function parsed(r, current) {
11
+ const b = { ...current, ...(await body(r.req)) };
12
+ const checkSlo = async (id) => (sloById(r.deps.store.db, r.project, id) ? null : "That SLO is not in this project.");
13
+ return parseAlertRule(b, { checkUrl: (url) => checkTarget(url, r.deps.outbox.allowPrivate), checkSlo });
14
+ }
15
+ async function create(r) {
16
+ const input = await parsed(r);
17
+ if (typeof input === "string")
18
+ return sendJson(r.res, 400, { error: input });
19
+ sendJson(r.res, 201, createRule(r.deps.store.db, r.project, input, r.now));
20
+ }
21
+ async function change(r, rule) {
22
+ const input = await parsed(r, rule);
23
+ if (typeof input === "string")
24
+ return sendJson(r.res, 400, { error: input });
25
+ const off = !input.enabled;
26
+ const next = { ...rule, ...input, ...(off ? { state: "ok", ackMs: null } : {}) };
27
+ saveRule(r.deps.store.db, next, r.now);
28
+ sendJson(r.res, 200, next);
29
+ }
30
+ async function mute(r, rule) {
31
+ const raw = (await body(r.req)).untilMs;
32
+ const untilMs = raw === null ? null : raw === -1 ? MUTED_FOREVER : Number(raw);
33
+ if (untilMs !== null && (!Number.isFinite(untilMs) || untilMs <= r.now))
34
+ return sendJson(r.res, 400, { error: "Set untilMs to a future time, -1 for until unmuted, or null to unmute." });
35
+ saveRule(r.deps.store.db, { ...rule, mutedUntilMs: untilMs }, r.now);
36
+ const message = untilMs === null ? "Unmuted" : untilMs === MUTED_FOREVER ? "Muted until unmuted" : `Muted until ${new Date(untilMs).toISOString().slice(0, 16).replace("T", " ")} UTC`;
37
+ addEvent(r.deps.store.db, rule, { kind: untilMs === null ? "unmute" : "mute", value: null, message, timeMs: r.now, delivery: "" });
38
+ sendJson(r.res, 200, { ...rule, mutedUntilMs: untilMs });
39
+ }
40
+ function ack(r, rule) {
41
+ if (rule.state !== "firing")
42
+ return sendJson(r.res, 400, { error: "Only a firing rule can be acknowledged." });
43
+ saveRule(r.deps.store.db, { ...rule, ackMs: r.now }, r.now);
44
+ addEvent(r.deps.store.db, rule, { kind: "ack", value: rule.lastValue, message: "Acknowledged", timeMs: r.now, delivery: "" });
45
+ sendJson(r.res, 200, { ...rule, ackMs: r.now });
46
+ }
47
+ function history(r, rule) {
48
+ const to = Number(r.url.searchParams.get("to")) || r.now + 1;
49
+ const from = Number(r.url.searchParams.get("from")) || to - DAY_MS;
50
+ const db = r.deps.store.db;
51
+ sendJson(r.res, 200, { rule, events: ruleEvents(db, rule.id, 100), values: ruleValues(db, rule.id, from, to) });
52
+ }
53
+ /** One rule's routes: `api/alerts/:id` and its actions. */
54
+ async function onRule(r, method, id, action) {
55
+ const rule = ruleById(r.deps.store.db, r.project, id);
56
+ if (!rule)
57
+ return sendJson(r.res, 404, { error: "Alert rule not found." });
58
+ if (!action && method === "GET")
59
+ return history(r, rule);
60
+ if (!action && method === "PATCH")
61
+ return change(r, rule);
62
+ if (!action && method === "DELETE")
63
+ return (deleteRule(r.deps.store.db, r.project, id), sendJson(r.res, 200, { ok: true }));
64
+ if (method !== "POST")
65
+ return sendJson(r.res, 405, { error: "method not allowed" });
66
+ if (action === "test")
67
+ return sendJson(r.res, 200, { delivery: await notifyHub(r.deps, rule, "test", rule.lastValue, r.now) });
68
+ if (action === "mute")
69
+ return mute(r, rule);
70
+ if (action === "ack")
71
+ return ack(r, rule);
72
+ sendJson(r.res, 404, { error: "not found" });
73
+ }
74
+ /** Routes under `api/alerts`. */
75
+ export async function handleAlerts(deps, now, sub, req, res, url) {
76
+ const method = req.method ?? "GET";
77
+ const r = { deps, now, project: url.searchParams.get("project") ?? "", req, res, url };
78
+ const [, , id, action] = sub.split("/");
79
+ if (id)
80
+ return onRule(r, method, decodeURIComponent(id), action);
81
+ if (method === "GET")
82
+ return sendJson(res, 200, { rules: listRules(deps.store.db, r.project), events: listEvents(deps.store.db, r.project, 100) });
83
+ if (method === "POST")
84
+ return create(r);
85
+ sendJson(res, 405, { error: "method not allowed" });
86
+ }
87
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/alerts/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import type { AlertChannel, AlertNoticeState } from "@wizeworks/lens-core";
2
+ export interface Notice {
3
+ ruleId: string;
4
+ rule: string;
5
+ project: string;
6
+ state: AlertNoticeState;
7
+ message: string;
8
+ value: number | null;
9
+ threshold: number;
10
+ timeMs: number;
11
+ /** Link to the rule in the dashboard. */
12
+ url: string;
13
+ /** For "above normal" rules: the normal value and the line it crossed. */
14
+ baseline?: {
15
+ normal: number;
16
+ upper: number;
17
+ } | null;
18
+ /** The problem this alert is part of, when one was found as it fired. */
19
+ problem?: NoticeProblem | null;
20
+ }
21
+ /** A problem card on the Problems page, named in a notice. */
22
+ export interface NoticeProblem {
23
+ id: string;
24
+ title: string;
25
+ /** The suspected cause in one sentence, or null. */
26
+ cause: string | null;
27
+ /** Link to the problem in the dashboard. */
28
+ url: string;
29
+ }
30
+ /** How notices leave: HTTP, and on the cloud a mail function that sends to members still allowed and says what it did. */
31
+ export interface Outbox {
32
+ http: typeof fetch;
33
+ allowPrivate: boolean;
34
+ email?: (to: readonly string[], n: Notice) => string;
35
+ /** PagerDuty's Events API v2; tests point it elsewhere. */
36
+ pagerDutyUrl?: string;
37
+ }
38
+ export declare const PAGERDUTY_EVENTS_URL = "https://events.pagerduty.com/v2/enqueue";
39
+ /** The notice in words, for chat and email. */
40
+ export declare function noticeLines(n: Notice): {
41
+ subject: string;
42
+ lines: string[];
43
+ };
44
+ type UrlChannel = Extract<AlertChannel, {
45
+ url: string;
46
+ }>;
47
+ /** The body each chat tool expects. Webhooks get the notice as JSON. */
48
+ export declare function chatBody(kind: UrlChannel["kind"], n: Notice): unknown;
49
+ /** PagerDuty events: fired and reminders trigger (one incident per rule), resolved resolves, and a test triggers then resolves its own key. */
50
+ export declare function pagerDutyEvents(routingKey: string, n: Notice): unknown[];
51
+ /** Send to every channel. Returns one line per channel, for the delivery note of the event. */
52
+ export declare function deliver(channels: readonly AlertChannel[], n: Notice, out: Outbox): Promise<string>;
53
+ export {};
54
+ //# sourceMappingURL=deliver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deliver.d.ts","sourceRoot":"","sources":["../../src/alerts/deliver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG3E,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,gBAAgB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,0EAA0E;IAC1E,QAAQ,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpD,yEAAyE;IACzE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;CAChC;AAED,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;CACb;AAED,0HAA0H;AAC1H,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,OAAO,KAAK,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACrD,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,oBAAoB,4CAA4C,CAAC;AAK9E,+CAA+C;AAC/C,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAK3E;AAED,KAAK,UAAU,GAAG,OAAO,CAAC,YAAY,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAQzD,wEAAwE;AACxE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAQrE;AAED,+IAA+I;AAC/I,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,CAMxE;AAsBD,+FAA+F;AAC/F,wBAAsB,OAAO,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAGxG"}
@@ -0,0 +1,66 @@
1
+ import { checkTarget } from "./target.js";
2
+ export const PAGERDUTY_EVENTS_URL = "https://events.pagerduty.com/v2/enqueue";
3
+ const VERB = { fired: "Alert", resolved: "Resolved", remind: "Still firing", test: "Test" };
4
+ const COLOR = { fired: "D93025", resolved: "1E8E3E", remind: "E37400", test: "5F6368" };
5
+ const SLACK_ICON = { fired: ":rotating_light:", resolved: ":white_check_mark:", remind: ":repeat:", test: ":bell:" };
6
+ /** The notice in words, for chat and email. */
7
+ export function noticeLines(n) {
8
+ const verb = VERB[n.state];
9
+ const p = n.problem;
10
+ const problem = p ? [`Part of a problem: ${p.title}.${p.cause ? ` Suspected cause: ${p.cause}` : ""}`] : [];
11
+ return { subject: `${verb}: ${n.rule} (${n.project})`, lines: [`${verb}: ${n.rule} in ${n.project}.`, n.message, ...problem] };
12
+ }
13
+ /** The problem line of a chat message, with its link written the chat tool's way; "" without a problem. */
14
+ function problemText(n, link) {
15
+ const p = n.problem;
16
+ return p ? `\nPart of a problem: ${link(p.url, p.title)}${p.cause ? `. Suspected cause: ${p.cause}` : ""}` : "";
17
+ }
18
+ /** The body each chat tool expects. Webhooks get the notice as JSON. */
19
+ export function chatBody(kind, n) {
20
+ const { subject } = noticeLines(n);
21
+ if (kind === "webhook")
22
+ return n;
23
+ if (kind === "slack")
24
+ return { text: `${SLACK_ICON[n.state]} *${subject}*\n${n.message}${problemText(n, (u, t) => `<${u}|${t}>`)}\n<${n.url}|Open WizeLens>` };
25
+ if (kind === "discord")
26
+ return { content: `**${subject}**\n${n.message}${problemText(n, (u, t) => `[${t}](${u})`)}\n${n.url}`, allowed_mentions: { parse: [] } };
27
+ const open = [{ "@type": "OpenUri", name: "Open WizeLens", targets: [{ os: "default", uri: n.url }] }];
28
+ const text = `${n.message}${problemText(n, (u, t) => `[${t}](${u})`)}`;
29
+ return { "@type": "MessageCard", "@context": "https://schema.org/extensions", summary: subject, themeColor: COLOR[n.state], title: subject, text, potentialAction: open };
30
+ }
31
+ /** PagerDuty events: fired and reminders trigger (one incident per rule), resolved resolves, and a test triggers then resolves its own key. */
32
+ export function pagerDutyEvents(routingKey, n) {
33
+ const key = n.state === "test" ? `wizelens-${n.ruleId}-test` : `wizelens-${n.ruleId}`;
34
+ const trigger = { routing_key: routingKey, event_action: "trigger", dedup_key: key, payload: { summary: `${n.rule}: ${n.message}`.slice(0, 1024), source: n.project, severity: "error", timestamp: new Date(n.timeMs).toISOString() }, links: [{ href: n.url, text: "Open WizeLens" }] };
35
+ const resolve = { routing_key: routingKey, event_action: "resolve", dedup_key: key };
36
+ if (n.state === "resolved")
37
+ return [resolve];
38
+ return n.state === "test" ? [trigger, resolve] : [trigger];
39
+ }
40
+ async function send(out, url, body) {
41
+ try {
42
+ const res = await out.http(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), signal: AbortSignal.timeout(5000), redirect: "error" });
43
+ return res.ok ? "sent" : `HTTP ${res.status}`;
44
+ }
45
+ catch (err) {
46
+ return err instanceof Error ? err.message : "failed";
47
+ }
48
+ }
49
+ async function deliverOne(c, n, out) {
50
+ if (c.kind === "email")
51
+ return out.email ? out.email(c.to, n) : "email: this host sends no email";
52
+ if (c.kind === "pagerduty") {
53
+ let result = "sent";
54
+ for (const event of pagerDutyEvents(c.routingKey, n))
55
+ result = await send(out, out.pagerDutyUrl ?? PAGERDUTY_EVENTS_URL, event);
56
+ return `pagerduty: ${result}`;
57
+ }
58
+ const problem = await checkTarget(c.url, out.allowPrivate);
59
+ return `${c.kind}: ${problem ?? (await send(out, c.url, chatBody(c.kind, n)))}`;
60
+ }
61
+ /** Send to every channel. Returns one line per channel, for the delivery note of the event. */
62
+ export async function deliver(channels, n, out) {
63
+ const results = await Promise.all(channels.map((c) => deliverOne(c, n, out)));
64
+ return results.join("; ") || "no channels";
65
+ }
66
+ //# sourceMappingURL=deliver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deliver.js","sourceRoot":"","sources":["../../src/alerts/deliver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { type AlertNoticeState, type AlertRule, type AnomalyAlertValue } from "@wizeworks/lens-core";
2
+ import type { HubStore } from "../store.js";
3
+ import { type Outbox } from "./deliver.js";
4
+ export interface HubAlertDeps {
5
+ store: HubStore;
6
+ outbox: Outbox;
7
+ /** The hub's address, for the link in each notice. */
8
+ baseUrl: () => string;
9
+ }
10
+ /** Send a notice through the rule's channels and keep it as an event. */
11
+ export declare function notifyHub(deps: HubAlertDeps, rule: AlertRule, state: AlertNoticeState, value: number | null, now: number, anomaly?: AnomalyAlertValue): Promise<string>;
12
+ /** Check one rule: keep its value, and notify when it starts or stops firing, or remind while it keeps firing. */
13
+ export declare function evaluateHubRule(deps: HubAlertDeps, rule: AlertRule, now: number): Promise<void>;
14
+ /** Check every enabled rule once. One failing rule does not stop the others. */
15
+ export declare function evaluateHubAlerts(deps: HubAlertDeps, now: number): Promise<void>;
16
+ //# sourceMappingURL=evaluate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../src/alerts/evaluate.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,gBAAgB,EAErB,KAAK,SAAS,EAGd,KAAK,iBAAiB,EAevB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAwB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAGjE,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,QAAQ,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,OAAO,EAAE,MAAM,MAAM,CAAC;CACvB;AAkCD,yEAAyE;AACzE,wBAAsB,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmB7K;AAKD,kHAAkH;AAClH,wBAAsB,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQrG;AAED,gFAAgF;AAChF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAItF"}
@@ -0,0 +1,76 @@
1
+ import { alertBreached, alertContext, alertMessage, alertPage, alertStep, alignNow, anomalyAlertMessage, anomalyAlertPage, computePage, metricAlertMessage, metricAlertSteps, metricAlertUnit, metricAlertValueOf, opHolds, runMetricSync, sloBurnMessage, sloBurnPage, sloContext, } from "@wizeworks/lens-core";
2
+ import { sloById } from "../slos.js";
3
+ import { hubExecutor } from "../scale-exec.js";
4
+ import { deliver } from "./deliver.js";
5
+ import { addEvent, addValue, enabledRules, saveRule } from "./store.js";
6
+ /** The OpenTelemetry metric of a rule over its window, from the metric rollups, and its unit. */
7
+ function measureMetric(store, rule, now) {
8
+ const at = alignNow(now);
9
+ const scope = { project: rule.projectId || undefined, env: rule.env || undefined, service: rule.metricService || undefined };
10
+ const steps = metricAlertSteps("sqlite", scope, rule.metricName, { from: at - rule.windowMs, to: at }, at);
11
+ const data = runMetricSync(steps, (q) => store.db.prepare(q.sql).all(...q.args));
12
+ const stat = rule.metricStat || "avg";
13
+ return { value: metricAlertValueOf(data, stat), unit: data.series[0] ? metricAlertUnit(data.series[0], stat) : "" };
14
+ }
15
+ async function measure(store, rule, now) {
16
+ if (rule.metric === "metric")
17
+ return measureMetric(store, rule, now).value;
18
+ if (rule.metric === "slo") {
19
+ const slo = sloById(store.db, rule.projectId, rule.sloId);
20
+ return slo ? computePage(sloBurnPage(slo), sloContext(rule.windowMs, alignNow(now)), hubExecutor(store, { project: rule.projectId || undefined })) : null;
21
+ }
22
+ const page = alertPage(rule.metric, { service: rule.service, endpoint: rule.endpoint }, rule.logSearch ?? {});
23
+ return computePage(page, alertContext(rule.windowMs, alignNow(now)), hubExecutor(store, { project: rule.projectId || undefined, env: rule.env || undefined }));
24
+ }
25
+ function messageOf(store, rule, state, value, now) {
26
+ if (rule.metric === "slo")
27
+ return sloBurnMessage(sloById(store.db, rule.projectId, rule.sloId)?.name ?? rule.sloId, rule.op, value, rule.threshold, state);
28
+ if (rule.metric !== "metric")
29
+ return alertMessage(rule.metric, rule.op, value, rule.threshold, state, rule.logSearch ?? {});
30
+ return metricAlertMessage(rule.metricName, rule.metricStat || "avg", rule.op, value, rule.threshold, measureMetric(store, rule, now).unit, state);
31
+ }
32
+ /** An "above normal" rule: every service and endpoint over the window against the same window in earlier weeks (or days). */
33
+ function measureAnomaly(store, rule, now) {
34
+ const page = anomalyAlertPage(rule.metric, rule.threshold);
35
+ return computePage(page, alertContext(rule.windowMs, alignNow(now)), hubExecutor(store, { project: rule.projectId || undefined, env: rule.env || undefined }));
36
+ }
37
+ /** Send a notice through the rule's channels and keep it as an event. */
38
+ export async function notifyHub(deps, rule, state, value, now, anomaly) {
39
+ const project = rule.projectId ? `?project=${encodeURIComponent(rule.projectId)}` : "";
40
+ const above = rule.op === "above_normal" ? (anomaly ?? (await measureAnomaly(deps.store, rule, now))) : null;
41
+ const breach = above?.breach ?? null;
42
+ const notice = {
43
+ ruleId: rule.id,
44
+ rule: rule.name,
45
+ project: rule.projectId || "hub",
46
+ state,
47
+ message: above ? anomalyAlertMessage(rule.metric, above, state) : messageOf(deps.store, rule, state, value, now),
48
+ value,
49
+ threshold: rule.threshold,
50
+ timeMs: now,
51
+ url: `${deps.baseUrl()}/_wizelens/#/alerts/${rule.id}${project}`,
52
+ baseline: breach ? { normal: breach.normal, upper: breach.upper } : null,
53
+ };
54
+ const delivery = await deliver(rule.channels, notice, deps.outbox);
55
+ addEvent(deps.store.db, rule, { kind: state, value, message: notice.message, timeMs: now, delivery });
56
+ return delivery;
57
+ }
58
+ const breaches = (rule, value) => rule.metric === "metric" || rule.metric === "slo" ? value !== null && opHolds(rule.op, value, rule.threshold) : alertBreached(rule.metric, rule.op, value, rule.threshold);
59
+ /** Check one rule: keep its value, and notify when it starts or stops firing, or remind while it keeps firing. */
60
+ export async function evaluateHubRule(deps, rule, now) {
61
+ const anomaly = rule.op === "above_normal" ? await measureAnomaly(deps.store, rule, now) : undefined;
62
+ const value = anomaly ? anomaly.value : await measure(deps.store, rule, now);
63
+ const step = alertStep(rule, anomaly ? anomaly.breach !== null : breaches(rule, value), now);
64
+ const next = { ...rule, state: step.state, ackMs: step.ackMs, lastValue: value, lastEvalMs: now, lastNotifiedMs: step.notice ? now : rule.lastNotifiedMs };
65
+ saveRule(deps.store.db, next, now);
66
+ addValue(deps.store.db, rule.id, now, value);
67
+ if (step.notice)
68
+ await notifyHub(deps, next, step.notice, value, now, anomaly);
69
+ }
70
+ /** Check every enabled rule once. One failing rule does not stop the others. */
71
+ export async function evaluateHubAlerts(deps, now) {
72
+ for (const rule of enabledRules(deps.store.db)) {
73
+ await evaluateHubRule(deps, rule, now).catch((err) => console.error(`[wizelens-hub] alert ${rule.id} failed:`, err));
74
+ }
75
+ }
76
+ //# sourceMappingURL=evaluate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../src/alerts/evaluate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ResolvedHubOptions } from "../options.js";
2
+ import type { HubStore } from "../store.js";
3
+ import { type HubAlertDeps } from "./evaluate.js";
4
+ /** What the hub's alerts need: its file, how to send, and its address (known once it listens). */
5
+ export declare function hubAlertDeps(store: HubStore, o: ResolvedHubOptions, base: {
6
+ url: string;
7
+ }): HubAlertDeps;
8
+ /** Start the loop; returns a function that stops it. */
9
+ export declare function startAlertLoop(deps: HubAlertDeps, o: ResolvedHubOptions): () => void;
10
+ //# sourceMappingURL=loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/alerts/loop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAGrE,kGAAkG;AAClG,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,kBAAkB,EAAE,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAExG;AAED,wDAAwD;AACxD,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAgBpF"}
@@ -0,0 +1,27 @@
1
+ import { evaluateHubAlerts } from "./evaluate.js";
2
+ import { pruneAlertValues } from "./store.js";
3
+ /** What the hub's alerts need: its file, how to send, and its address (known once it listens). */
4
+ export function hubAlertDeps(store, o, base) {
5
+ return { store, outbox: { http: o.fetch, allowPrivate: o.allowPrivateWebhooks, pagerDutyUrl: o.pagerDutyUrl }, baseUrl: () => base.url };
6
+ }
7
+ /** Start the loop; returns a function that stops it. */
8
+ export function startAlertLoop(deps, o) {
9
+ let running = false;
10
+ const round = async () => {
11
+ if (running)
12
+ return;
13
+ running = true;
14
+ try {
15
+ const now = o.now();
16
+ await evaluateHubAlerts(deps, now);
17
+ pruneAlertValues(deps.store.db, now);
18
+ }
19
+ finally {
20
+ running = false;
21
+ }
22
+ };
23
+ const timer = setInterval(() => void round(), o.alertIntervalMs);
24
+ timer.unref();
25
+ return () => clearInterval(timer);
26
+ }
27
+ //# sourceMappingURL=loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/alerts/loop.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAqB,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,kGAAkG;AAClG,MAAM,UAAU,YAAY,CAAC,KAAe,EAAE,CAAqB,EAAE,IAAqB;IACxF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC,oBAAoB,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;AAC3I,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,cAAc,CAAC,IAAkB,EAAE,CAAqB;IACtE,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE;QACvB,IAAI,OAAO;YAAE,OAAO;QACpB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YACpB,MAAM,iBAAiB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YACnC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QACvC,CAAC;gBAAS,CAAC;YACT,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;IACH,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC;IACjE,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ import type { AlertRule, AlertRuleInput } from "@wizeworks/lens-core";
3
+ export interface HubAlertEvent {
4
+ id: string;
5
+ ruleId: string;
6
+ ruleName: string;
7
+ kind: "fired" | "resolved" | "remind" | "test" | "ack" | "mute" | "unmute";
8
+ value: number | null;
9
+ threshold: number;
10
+ message: string;
11
+ timeMs: number;
12
+ delivery: string;
13
+ }
14
+ /** Evaluated values are kept this long. */
15
+ export declare const HUB_ALERT_VALUES_KEEP_MS: number;
16
+ export declare const listRules: (db: DatabaseSync, project: string) => AlertRule[];
17
+ export declare const enabledRules: (db: DatabaseSync) => AlertRule[];
18
+ export declare const ruleById: (db: DatabaseSync, project: string, id: string) => AlertRule | undefined;
19
+ export declare function saveRule(db: DatabaseSync, r: AlertRule, now: number): void;
20
+ /** A new rule from checked input, not firing. */
21
+ export declare function createRule(db: DatabaseSync, project: string, input: AlertRuleInput, now: number): AlertRule;
22
+ export declare function deleteRule(db: DatabaseSync, project: string, id: string): boolean;
23
+ export declare function addEvent(db: DatabaseSync, r: AlertRule, e: Pick<HubAlertEvent, "kind" | "value" | "message" | "timeMs" | "delivery">): void;
24
+ export declare const listEvents: (db: DatabaseSync, project: string, limit: number) => HubAlertEvent[];
25
+ export declare const ruleEvents: (db: DatabaseSync, id: string, limit: number) => HubAlertEvent[];
26
+ export declare function addValue(db: DatabaseSync, id: string, timeMs: number, value: number | null): void;
27
+ export declare const ruleValues: (db: DatabaseSync, id: string, from: number, to: number) => {
28
+ timeMs: number;
29
+ value: number | null;
30
+ }[];
31
+ export declare function pruneAlertValues(db: DatabaseSync, now: number): void;
32
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/alerts/store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC3E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,2CAA2C;AAC3C,eAAO,MAAM,wBAAwB,QAAkB,CAAC;AAIxD,eAAO,MAAM,SAAS,OAAQ,YAAY,WAAW,MAAM,KAAG,SAAS,EAA4G,CAAC;AAEpL,eAAO,MAAM,YAAY,OAAQ,YAAY,KAAG,SAAS,EAAwF,CAAC;AAElJ,eAAO,MAAM,QAAQ,OAAQ,YAAY,WAAW,MAAM,MAAM,MAAM,KAAG,SAAS,GAAG,SAAiH,CAAC;AAEvM,wBAAgB,QAAQ,CAAC,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAE1E;AAED,iDAAiD;AACjD,wBAAgB,UAAU,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAI3G;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAIjF;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC,GAAG,IAAI,CAY3I;AAOD,eAAO,MAAM,UAAU,OAAQ,YAAY,WAAW,MAAM,SAAS,MAAM,KAAG,aAAa,EAAkH,CAAC;AAE9M,eAAO,MAAM,UAAU,OAAQ,YAAY,MAAM,MAAM,SAAS,MAAM,KAAG,aAAa,EAA6G,CAAC;AAEpM,wBAAgB,QAAQ,CAAC,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEjG;AAED,eAAO,MAAM,UAAU,OAAQ,YAAY,MAAM,MAAM,QAAQ,MAAM,MAAM,MAAM,KAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACyE,CAAC;AAEtM,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAEpE"}
@@ -0,0 +1,38 @@
1
+ // Alert rules on the hub: one JSON row per rule, its events, and every evaluated value (for the rule's chart).
2
+ import { randomUUID } from "node:crypto";
3
+ /** Evaluated values are kept this long. */
4
+ export const HUB_ALERT_VALUES_KEEP_MS = 30 * 86_400_000;
5
+ const rulesOf = (rows) => rows.map((r) => JSON.parse(r.json));
6
+ export const listRules = (db, project) => rulesOf(db.prepare("SELECT json FROM alert_rules WHERE project = ? ORDER BY created_ms").all(project));
7
+ export const enabledRules = (db) => rulesOf(db.prepare("SELECT json FROM alert_rules").all()).filter((r) => r.enabled);
8
+ export const ruleById = (db, project, id) => rulesOf(db.prepare("SELECT json FROM alert_rules WHERE project = ? AND id = ?").all(project, id))[0];
9
+ export function saveRule(db, r, now) {
10
+ db.prepare("INSERT INTO alert_rules (id, project, json, created_ms) VALUES (?, ?, ?, ?) ON CONFLICT (id) DO UPDATE SET json = excluded.json").run(r.id, r.projectId, JSON.stringify(r), now);
11
+ }
12
+ /** A new rule from checked input, not firing. */
13
+ export function createRule(db, project, input, now) {
14
+ const rule = { ...input, id: randomUUID(), projectId: project, state: "ok", lastValue: null, lastEvalMs: null, mutedUntilMs: null, ackMs: null, lastNotifiedMs: null };
15
+ saveRule(db, rule, now);
16
+ return rule;
17
+ }
18
+ export function deleteRule(db, project, id) {
19
+ db.prepare("DELETE FROM alert_events WHERE rule_id = ?").run(id);
20
+ db.prepare("DELETE FROM alert_values WHERE rule_id = ?").run(id);
21
+ return Number(db.prepare("DELETE FROM alert_rules WHERE project = ? AND id = ?").run(project, id).changes) > 0;
22
+ }
23
+ export function addEvent(db, r, e) {
24
+ db.prepare("INSERT INTO alert_events (id, rule_id, project, kind, value, threshold, message, time_ms, delivery) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)").run(randomUUID(), r.id, r.projectId, e.kind, e.value, r.threshold, e.message, e.timeMs, e.delivery);
25
+ }
26
+ const EVENT_SQL = `SELECT e.id, e.rule_id AS ruleId, r.json AS rule, e.kind, e.value, e.threshold, e.message, e.time_ms AS timeMs, e.delivery
27
+ FROM alert_events e JOIN alert_rules r ON r.id = e.rule_id`;
28
+ const eventsOf = (rows) => rows.map(({ rule, ...e }) => ({ ...e, ruleName: JSON.parse(rule).name }));
29
+ export const listEvents = (db, project, limit) => eventsOf(db.prepare(`${EVENT_SQL} WHERE e.project = ? ORDER BY e.time_ms DESC LIMIT ?`).all(project, limit));
30
+ export const ruleEvents = (db, id, limit) => eventsOf(db.prepare(`${EVENT_SQL} WHERE e.rule_id = ? ORDER BY e.time_ms DESC LIMIT ?`).all(id, limit));
31
+ export function addValue(db, id, timeMs, value) {
32
+ db.prepare("INSERT INTO alert_values (rule_id, time_ms, value) VALUES (?, ?, ?) ON CONFLICT (rule_id, time_ms) DO UPDATE SET value = excluded.value").run(id, timeMs, value);
33
+ }
34
+ export const ruleValues = (db, id, from, to) => db.prepare("SELECT time_ms AS timeMs, value FROM alert_values WHERE rule_id = ? AND time_ms >= ? AND time_ms < ? ORDER BY time_ms").all(id, from, to);
35
+ export function pruneAlertValues(db, now) {
36
+ db.prepare("DELETE FROM alert_values WHERE time_ms < ?").run(now - HUB_ALERT_VALUES_KEEP_MS);
37
+ }
38
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/alerts/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** A webhook may not point into the service's own network (cloud metadata, databases). Self-hosts can allow it. */
2
+ export declare function checkTarget(url: string, allowPrivate: boolean): Promise<string | null>;
3
+ //# sourceMappingURL=target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"target.d.ts","sourceRoot":"","sources":["../../src/alerts/target.ts"],"names":[],"mappings":"AAKA,mHAAmH;AACnH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAY5F"}
@@ -0,0 +1,23 @@
1
+ // Where alert notices may go: an https URL that does not point into the host's own network.
2
+ import { lookup } from "node:dns/promises";
3
+ import { isIP } from "node:net";
4
+ import { isPrivateAddress } from "../uptime/guard.js";
5
+ /** A webhook may not point into the service's own network (cloud metadata, databases). Self-hosts can allow it. */
6
+ export async function checkTarget(url, allowPrivate) {
7
+ let u;
8
+ try {
9
+ u = new URL(url);
10
+ }
11
+ catch {
12
+ return "Not a valid URL.";
13
+ }
14
+ if (u.protocol !== "https:" && !(allowPrivate && u.protocol === "http:"))
15
+ return "Use an https:// URL.";
16
+ if (allowPrivate)
17
+ return null;
18
+ const addresses = isIP(u.hostname) ? [u.hostname] : (await lookup(u.hostname, { all: true }).catch(() => [])).map((a) => a.address);
19
+ if (addresses.length === 0)
20
+ return "The host name does not resolve.";
21
+ return addresses.some(isPrivateAddress) ? "Webhooks cannot point at private or local addresses." : null;
22
+ }
23
+ //# sourceMappingURL=target.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"target.js","sourceRoot":"","sources":["../../src/alerts/target.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,mHAAmH;AACnH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,YAAqB;IAClE,IAAI,CAAM,CAAC;IACX,IAAI,CAAC;QACH,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC;QAAE,OAAO,sBAAsB,CAAC;IACxG,IAAI,YAAY;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACpI,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,iCAAiC,CAAC;IACrE,OAAO,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,sDAAsD,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1G,CAAC"}
package/dist/api.d.ts CHANGED
@@ -1,13 +1,18 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
2
  import { type ServiceInfo } from "@wizeworks/lens-core";
3
+ import type { HubAlertDeps } from "./alerts/evaluate.js";
3
4
  import type { HubData } from "./data.js";
4
5
  import type { ResolvedHubOptions } from "./options.js";
6
+ import { type HubMaps } from "./sourcemaps-api.js";
5
7
  import { type TraceQuery } from "./store-read.js";
6
8
  export interface ApiContext {
7
9
  data: HubData;
10
+ alerts: HubAlertDeps;
8
11
  o: ResolvedHubOptions;
9
12
  version: string;
10
13
  startedMs: number;
14
+ /** Source maps per project: uploads, build folders, and dev servers. */
15
+ maps: HubMaps;
11
16
  }
12
17
  export declare function hubInfo(c: ApiContext): ServiceInfo;
13
18
  /** `api/traces`: summaries by default, full traces with `full=true`. Filters: since, before, env, project, session. */
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGpE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAKvD,OAAO,EAAuC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEvF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,CAAC,EAAE,kBAAkB,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,wBAAgB,OAAO,CAAC,CAAC,EAAE,UAAU,GAAG,WAAW,CAclD;AAED,uHAAuH;AACvH,wBAAgB,OAAO,CAAC,CAAC,EAAE,eAAe,GAAG;IAAE,CAAC,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAM5E;AAmCD,uCAAuC;AACvC,wBAAsB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9H"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAmC,KAAK,WAAW,EAA4C,MAAM,sBAAsB,CAAC;AAInI,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAKzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOvD,OAAO,EAAE,KAAK,OAAO,EAA0C,MAAM,qBAAqB,CAAC;AAE3F,OAAO,EAAuC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEvF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;IACrB,CAAC,EAAE,kBAAkB,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,IAAI,EAAE,OAAO,CAAC;CACf;AAKD,wBAAgB,OAAO,CAAC,CAAC,EAAE,UAAU,GAAG,WAAW,CAclD;AAED,uHAAuH;AACvH,wBAAgB,OAAO,CAAC,CAAC,EAAE,eAAe,GAAG;IAAE,CAAC,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAM5E;AAoCD,uCAAuC;AACvC,wBAAsB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CA6B9H"}