1import type * as Effect from "effect/Effect";
2import type * as Stream from "effect/Stream";
3import {
4 consumeBusEvents,
5 type EventRecord,
6 type EventRouteProps,
7} from "../EventBridge/EventSource.ts";
8
9/**
10 * The `detail` payload Amazon DevOps Guru delivers to EventBridge. All
11 * notifications share the insight envelope; anomaly/recommendation events
12 * add their own arrays. Fields not shared by every event kind are optional
13 * (the schema grows over time).
14 */
15export interface InsightEventDetail {
16 /** The id of the insight the event is about. */
17 insightId?: string;
18 /** Human-readable insight summary. */
19 insightDescription?: string;
20 /** Insight type: `REACTIVE` or `PROACTIVE`. */
21 insightType?: string;
22 /** Insight severity: `LOW`, `MEDIUM`, or `HIGH`. */
23 insightSeverity?: string;
24 /** Console deep-link to the insight. */
25 insightUrl?: string;
26 /** The notification kind, e.g. `NEW_INSIGHT`, `CLOSED_INSIGHT`. */
27 messageType?: string;
28 /** Epoch millis the insight started. */
29 startTime?: number;
30 /** Epoch millis the insight ended (closed events). */
31 endTime?: number;
32 /** The anomalies associated with the insight (anomaly events). */
33 anomalies?: unknown[];
34 /** The recommendations created for the insight (recommendation events). */
35 recommendations?: unknown[];
36 /** Additional event fields (the schema grows over time). */
37 [key: string]: unknown;
38}
39
40/** A DevOps Guru EventBridge event delivered to the handler. */
41export type InsightEvent = EventRecord<InsightEventDetail>;
42
43/** Which DevOps Guru notifications to subscribe to. */
44export type InsightEventKind =
45 | "new-insight"
46 | "severity-upgraded"
47 | "insight-closed"
48 | "new-anomaly"
49 | "new-recommendation";
50
51const DETAIL_TYPES: Record<InsightEventKind, string> = {
52 "new-insight": "DevOps Guru New Insight Open",
53 "severity-upgraded": "DevOps Guru Insight Severity Upgraded",
54 "insight-closed": "DevOps Guru Insight Closed",
55 "new-anomaly": "DevOps Guru New Anomaly Association",
56 "new-recommendation": "DevOps Guru New Recommendation Created",
57};
58
59export interface InsightEventSourceProps extends EventRouteProps {
60 /**
61 * Logical id for the backing EventBridge rule.
62 * @default "DevOpsGuruInsightEvents"
63 */
64 id?: string;
65 /**
66 * Which notifications to subscribe to: insights opening, upgrading
67 * severity, closing, new anomaly associations, and/or new
68 * recommendations.
69 * @default ["new-insight"]
70 */
71 kinds?: readonly InsightEventKind[];
72 /**
73 * Restrict to insights of the given severities (matched against the
74 * event detail's `insightSeverity`: `LOW`, `MEDIUM`, `HIGH`).
75 */
76 severities?: readonly string[];
77}
78
79/**
80 * Event source connecting Amazon DevOps Guru notifications to the hosting
81 * compute. DevOps Guru publishes insight lifecycle events (an insight
82 * opening, upgrading severity, or closing, plus new anomaly associations
83 * and recommendations) to the account's default EventBridge bus (source
84 * `aws.devops-guru`); this subscribes the host Function to those events so
85 * it can page, annotate incidents, or drive remediation.
86 *
87 * DevOps Guru publishes to EventBridge automatically — no additional
88 * resource is created besides the EventBridge rule targeting the host.
89 * Provide the host-specific implementation layer (e.g.
90 * `AWS.Lambda.EventSource`) on the Function effect.
91 *
92 * ### Consuming Insight Events
93 * **Example:** Page on High-Severity Insights
94 * ```typescript
95 * import * as AWS from "alchemy/AWS";
96 *
97 * export default AlertFunction.make(
98 * { main: import.meta.url },
99 * Effect.gen(function* () {
100 * yield* AWS.DevOpsGuru.consumeInsightEvents(
101 * { kinds: ["new-insight", "severity-upgraded"], severities: ["HIGH"] },
102 * (events) =>
103 * Stream.runForEach(events, (event) =>
104 * Effect.logError(
105 * `DevOps Guru insight: ${event.detail.insightDescription} (${event.detail.insightUrl})`,
106 * ),
107 * ),
108 * );
109 * return {};
110 * }).pipe(Effect.provide(AWS.Lambda.EventSource)),
111 * );
112 * ```
113 */
114export const consumeInsightEvents = <StreamReq = never, Req = never>(
115 props: InsightEventSourceProps,
116 process: (
117 events: Stream.Stream<InsightEvent, never, StreamReq>,
118 ) => Effect.Effect<void, never, Req>,
119) =>
120 consumeBusEvents(
121 props.id ?? "DevOpsGuruInsightEvents",
122 {
123 source: ["aws.devops-guru"],
124 "detail-type": (props.kinds ?? (["new-insight"] as const)).map(
125 (kind) => DETAIL_TYPES[kind],
126 ),
127 ...(props.severities !== undefined
128 ? { detail: { insightSeverity: [...props.severities] } }
129 : {}),
130 },
131 { description: props.description, state: props.state },
132 process,
133 );