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 AWS Elemental MediaConnect delivers to EventBridge.
11 * Alert events carry an `error-code`/`errored` pair plus a human `message`;
12 * health and status-change events carry the changed state. Fields not
13 * shared by every event kind are optional (the schema grows over time).
14 */
15export interface MediaConnectFlowEventDetail {
16 /** Alert events: the MediaConnect error code (e.g. `NoSource`). */
17 "error-code"?: string;
18 /** Alert events: `true` when the alert is raised, `false` when cleared. */
19 errored?: boolean;
20 /** Alert events: a human-readable description of the issue. */
21 message?: string;
22 /** Status-change events: the flow's new status (e.g. `ACTIVE`). */
23 status?: string;
24 /** Health events: the name of the health metric that changed. */
25 name?: string;
26 /** Additional event fields (the schema grows over time). */
27 [key: string]: unknown;
28}
29
30/** A MediaConnect EventBridge event delivered to the handler. */
31export type MediaConnectFlowEvent = EventRecord<MediaConnectFlowEventDetail>;
32
33/** Which MediaConnect notifications to subscribe to. */
34export type MediaConnectFlowEventKind =
35 | "alert"
36 | "flow-status-change"
37 | "flow-health"
38 | "flow-maintenance"
39 | "flow-content-quality"
40 | "source-health"
41 | "output-health"
42 | "output-status-change";
43
44const DETAIL_TYPES: Record<MediaConnectFlowEventKind, string> = {
45 alert: "MediaConnect Alert",
46 "flow-status-change": "MediaConnect Flow Status Change",
47 "flow-health": "MediaConnect Flow Health",
48 "flow-maintenance": "MediaConnect Flow Maintenance",
49 "flow-content-quality": "MediaConnect Flow Content Quality",
50 "source-health": "MediaConnect Source Health",
51 "output-health": "MediaConnect Output Health",
52 "output-status-change": "MediaConnect Output Status Change",
53};
54
55export interface FlowEventSourceProps extends EventRouteProps {
56 /**
57 * Logical id for the backing EventBridge rule.
58 * @default "MediaConnectFlowEvents"
59 */
60 id?: string;
61 /**
62 * Which notifications to subscribe to: alerts (raised/cleared error
63 * conditions such as a disconnected source), flow status changes
64 * (STANDBY/ACTIVE transitions), flow/source/output health, scheduled
65 * flow maintenance, and content-quality events.
66 * @default ["alert"]
67 */
68 kinds?: readonly MediaConnectFlowEventKind[];
69 /**
70 * Restrict to events about specific flows (matched against the event's
71 * top-level `resources`, which contains the flow's ARN).
72 */
73 flowArns?: readonly string[];
74}
75
76/**
77 * Event source connecting AWS Elemental MediaConnect flow notifications to
78 * the hosting compute. MediaConnect publishes alerts (a source
79 * disconnecting, failover firing), flow status changes (STANDBY/ACTIVE
80 * transitions), flow/source/output health, scheduled maintenance, and
81 * content-quality events to the account's default EventBridge bus (source
82 * `aws.mediaconnect`); this subscribes the host Function to those events
83 * so it can page an operator or trigger automated failover handling.
84 *
85 * MediaConnect publishes to EventBridge automatically — no additional
86 * resource is created besides the EventBridge rule targeting the host.
87 * Provide the host-specific implementation layer (e.g.
88 * `AWS.Lambda.EventSource`) on the Function effect.
89 *
90 * ### Consuming Flow Events
91 * **Example:** Page an Operator When a Flow Raises an Alert
92 * ```typescript
93 * import * as AWS from "alchemy/AWS";
94 *
95 * export default MonitorFunction.make(
96 * { main: import.meta.url },
97 * Effect.gen(function* () {
98 * yield* AWS.MediaConnect.consumeFlowEvents(
99 * { kinds: ["alert", "flow-status-change"] },
100 * (events) =>
101 * Stream.runForEach(events, (event) =>
102 * event.detail.errored === true
103 * ? Effect.log(`flow alert: ${event.detail.message}`)
104 * : Effect.void,
105 * ),
106 * );
107 * return {};
108 * }).pipe(Effect.provide(AWS.Lambda.EventSource)),
109 * );
110 * ```
111 */
112export const consumeFlowEvents = <StreamReq = never, Req = never>(
113 props: FlowEventSourceProps,
114 process: (
115 events: Stream.Stream<MediaConnectFlowEvent, never, StreamReq>,
116 ) => Effect.Effect<void, never, Req>,
117) =>
118 consumeBusEvents(
119 props.id ?? "MediaConnectFlowEvents",
120 {
121 source: ["aws.mediaconnect"],
122 "detail-type": (props.kinds ?? (["alert"] as const)).map(
123 (kind) => DETAIL_TYPES[kind],
124 ),
125 ...(props.flowArns !== undefined
126 ? { resources: [...props.flowArns] }
127 : {}),
128 },
129 { description: props.description, state: props.state },
130 process,
131 );