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 MediaLive delivers to EventBridge.
11 * State-change events carry the channel's new `state`; alert events carry
12 * an `alarm_state`/`alert_type` pair plus a human `message`. Fields not
13 * shared by every event kind are optional (the schema grows over time).
14 */
15export interface MediaLiveChannelEventDetail {
16 /** The ARN of the channel (or multiplex) the event is about. */
17 channel_arn?: string;
18 /** State-change events: the channel's new state (e.g. `RUNNING`). */
19 state?: string;
20 /** Alert events: `SET` when the alert is raised, `CLEARED` when it clears. */
21 alarm_state?: string;
22 /** Alert events: a stable id for the alert instance. */
23 alarm_id?: string;
24 /** Alert events: the kind of problem (e.g. `Video Not Detected`). */
25 alert_type?: string;
26 /** Alert events: the pipeline the alert applies to (e.g. `0`). */
27 pipeline?: string;
28 /** A human-readable description of the event. */
29 message?: string;
30 /** State-change events: how many pipelines are currently running. */
31 pipelines_running_count?: number;
32 /** Additional event fields (the schema grows over time). */
33 [key: string]: unknown;
34}
35
36/** A MediaLive EventBridge event delivered to the handler. */
37export type MediaLiveChannelEvent = EventRecord<MediaLiveChannelEventDetail>;
38
39/** Which MediaLive notifications to subscribe to. */
40export type MediaLiveChannelEventKind =
41 | "state-change"
42 | "alert"
43 | "input-change"
44 | "multiplex-state-change"
45 | "multiplex-alert";
46
47const DETAIL_TYPES: Record<MediaLiveChannelEventKind, string> = {
48 "state-change": "MediaLive Channel State Change",
49 alert: "MediaLive Channel Alert",
50 "input-change": "MediaLive Channel Input Change",
51 "multiplex-state-change": "MediaLive Multiplex State Change",
52 "multiplex-alert": "MediaLive Multiplex Alert",
53};
54
55export interface ChannelEventSourceProps extends EventRouteProps {
56 /**
57 * Logical id for the backing EventBridge rule.
58 * @default "MediaLiveChannelEvents"
59 */
60 id?: string;
61 /**
62 * Which notifications to subscribe to: channel state changes
63 * (IDLE/STARTING/RUNNING/STOPPING transitions and create/update
64 * progress), channel alerts (raised/cleared error conditions such as a
65 * lost input), input changes (which attached input is active), and the
66 * multiplex equivalents.
67 * @default ["state-change"]
68 */
69 kinds?: readonly MediaLiveChannelEventKind[];
70 /**
71 * Restrict to events about specific channels (matched against the
72 * event's top-level `resources`, which contains the channel's ARN).
73 */
74 channelArns?: readonly string[];
75}
76
77/**
78 * Event source connecting AWS Elemental MediaLive notifications to the
79 * hosting compute. MediaLive publishes channel state changes
80 * (IDLE/STARTING/RUNNING/STOPPING transitions), channel alerts (a lost
81 * input, a failed output — SET and CLEARED), active-input changes, and
82 * their multiplex equivalents to the account's default EventBridge bus
83 * (source `aws.medialive`); this subscribes the host Function to those
84 * events so it can page an operator, trigger automated pipeline recovery,
85 * or reconcile a broadcast schedule.
86 *
87 * MediaLive 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 Channel Events
93 * **Example:** Page an Operator When a Channel Raises an Alert
94 * ```typescript
95 * import * as AWS from "alchemy/AWS";
96 *
97 * export default MonitorFunction.make(
98 * { main: import.meta.url },
99 * Effect.gen(function* () {
100 * yield* AWS.MediaLive.consumeChannelEvents(
101 * { kinds: ["alert", "state-change"] },
102 * (events) =>
103 * Stream.runForEach(events, (event) =>
104 * event.detail.alarm_state === "SET"
105 * ? Effect.log(`channel alert: ${event.detail.message}`)
106 * : Effect.void,
107 * ),
108 * );
109 * return {};
110 * }).pipe(Effect.provide(AWS.Lambda.EventSource)),
111 * );
112 * ```
113 */
114export const consumeChannelEvents = <StreamReq = never, Req = never>(
115 props: ChannelEventSourceProps,
116 process: (
117 events: Stream.Stream<MediaLiveChannelEvent, never, StreamReq>,
118 ) => Effect.Effect<void, never, Req>,
119) =>
120 consumeBusEvents(
121 props.id ?? "MediaLiveChannelEvents",
122 {
123 source: ["aws.medialive"],
124 "detail-type": (props.kinds ?? (["state-change"] as const)).map(
125 (kind) => DETAIL_TYPES[kind],
126 ),
127 ...(props.channelArns !== undefined
128 ? { resources: [...props.channelArns] }
129 : {}),
130 },
131 { description: props.description, state: props.state },
132 process,
133 );