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 `event` values RAM publishes inside the `Resource Sharing State
11 * Change` detail — which sharing activity changed state.
12 */
13export type ResourceShareEventName =
14 | "Resource Share Association"
15 | "Resource Share Invitation"
16 | (string & {});
17
18/**
19 * The `detail` payload AWS RAM delivers to EventBridge for
20 * `Resource Sharing State Change` events. RAM emits these on a best-effort
21 * basis for changes to resource shares — for both the share owner and the
22 * principals granted access.
23 */
24export interface ResourceShareEventDetail {
25 /** Which sharing activity changed state, e.g. `Resource Share Association`. */
26 event?: ResourceShareEventName;
27 /** The new status, e.g. `associated`, `disassociated`, or `failed`. */
28 status?: string;
29 /** Additional fields RAM includes (the schema grows over time). */
30 [key: string]: unknown;
31}
32
33/** An AWS RAM EventBridge event delivered to the handler. */
34export type ResourceShareEvent = EventRecord<ResourceShareEventDetail>;
35
36export interface ResourceShareEventSourceProps extends EventRouteProps {
37 /**
38 * Logical id for the backing EventBridge rule.
39 * @default "ResourceShareEvents"
40 */
41 id?: string;
42 /**
43 * Which sharing activities to subscribe to (matched against
44 * `detail.event`), e.g. `["Resource Share Association"]`.
45 * @default all RAM events
46 */
47 events?: readonly ResourceShareEventName[];
48 /**
49 * Which statuses to subscribe to (matched against `detail.status`),
50 * e.g. `["failed"]` to alert on sharing failures.
51 * @default all statuses
52 */
53 statuses?: readonly string[];
54}
55
56/**
57 * Event source connecting AWS RAM resource-sharing events to the hosting
58 * compute. RAM publishes `Resource Sharing State Change` events (source
59 * `aws.ram`) to the default EventBridge bus in near-real time — for both the
60 * share owner and the principals granted access — whenever a resource share
61 * changes state; this subscribes the host Function to those events so it can
62 * drive invitation-acceptance or failure-alerting automation.
63 *
64 * RAM publishes to EventBridge automatically (best effort — events can be
65 * dropped) — no additional resource is created besides the EventBridge rule
66 * targeting the host. Provide the host-specific implementation layer (e.g.
67 * `AWS.Lambda.EventSource`) on the Function effect.
68 *
69 * ### Consuming Resource Sharing Events
70 * **Example:** Alert on Resource Share Failures
71 * ```typescript
72 * import * as AWS from "alchemy/AWS";
73 *
74 * export default SharingMonitor.make(
75 * { main: import.meta.url },
76 * Effect.gen(function* () {
77 * yield* AWS.RAM.consumeResourceShareEvents(
78 * { events: ["Resource Share Association"], statuses: ["failed"] },
79 * (events) =>
80 * Stream.runForEach(events, (event) =>
81 * Effect.log(`sharing failed: ${JSON.stringify(event.detail)}`),
82 * ),
83 * );
84 * return {};
85 * }).pipe(Effect.provide(AWS.Lambda.EventSource)),
86 * );
87 * ```
88 */
89export const consumeResourceShareEvents = <StreamReq = never, Req = never>(
90 props: ResourceShareEventSourceProps,
91 process: (
92 events: Stream.Stream<ResourceShareEvent, never, StreamReq>,
93 ) => Effect.Effect<void, never, Req>,
94) =>
95 consumeBusEvents(
96 props.id ?? "ResourceShareEvents",
97 {
98 source: ["aws.ram"],
99 "detail-type": ["Resource Sharing State Change"],
100 ...(props.events !== undefined || props.statuses !== undefined
101 ? {
102 detail: {
103 ...(props.events !== undefined
104 ? { event: [...props.events] }
105 : {}),
106 ...(props.statuses !== undefined
107 ? { status: [...props.statuses] }
108 : {}),
109 },
110 }
111 : {}),
112 },
113 { description: props.description, state: props.state },
114 process,
115 );