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 Private CA delivers to EventBridge. Success
11 * events (certificate issued, certificate revoked, CRL generated, audit
12 * report created) carry no detail — the CA ARN and the certificate/report
13 * ARN ride in the event's top-level `resources` array. Failure events
14 * (e.g. a CRL that could not be written to S3) describe the failure here.
15 */
16export interface CertificateAuthorityEventDetail {
17 /** Failure events: `"failure"`. Absent on success events. */
18 result?: string;
19 /** Additional event fields (the schema grows over time). */
20 [key: string]: unknown;
21}
22
23/** An AWS Private CA EventBridge event delivered to the handler. */
24export type CertificateAuthorityEvent =
25 EventRecord<CertificateAuthorityEventDetail>;
26
27/** Which AWS Private CA notifications to subscribe to. */
28export type CertificateAuthorityEventKind =
29 | "issuance"
30 | "revocation"
31 | "crl"
32 | "auditReport";
33
34const DETAIL_TYPES: Record<CertificateAuthorityEventKind, string> = {
35 issuance: "ACM Private CA Certificate Issuance",
36 revocation: "ACM Private CA Certificate Revocation",
37 crl: "ACM Private CA CRL Generation",
38 auditReport: "ACM Private CA Audit Report Generation",
39};
40
41export interface CertificateAuthorityEventSourceProps extends EventRouteProps {
42 /**
43 * Logical id for the backing EventBridge rule.
44 * @default "ACMPCAEvents"
45 */
46 id?: string;
47 /**
48 * Which notifications to subscribe to: certificate issuance, certificate
49 * revocation, CRL generation, audit report generation, or any subset.
50 * @default ["issuance"]
51 */
52 kinds?: readonly CertificateAuthorityEventKind[];
53 /**
54 * Restrict to events about specific CAs (matched against the event's
55 * top-level `resources`, which always includes the CA's ARN).
56 */
57 certificateAuthorityArns?: readonly string[];
58}
59
60/**
61 * Event source connecting AWS Private CA notifications to the hosting
62 * compute. AWS Private CA publishes certificate issuance/revocation, CRL
63 * generation, and audit report completion to the account's default
64 * EventBridge bus (source `aws.acm-pca`); this subscribes the host Function
65 * to those events so it can distribute freshly issued certificates, alert
66 * on revocations, or track CRL/audit failures.
67 *
68 * AWS Private CA publishes to EventBridge automatically — no additional
69 * resource is created besides the EventBridge rule targeting the host.
70 * Provide the host-specific implementation layer (e.g.
71 * `AWS.Lambda.EventSource`) on the Function effect.
72 *
73 * Success events carry the CA ARN and the certificate (or audit report)
74 * ARN in the event's top-level `resources` array; `detail` is empty.
75 * Failure events set `detail.result` to `"failure"`.
76 *
77 * ### Consuming Certificate Authority Events
78 * **Example:** React To Issued Certificates
79 * ```typescript
80 * import * as AWS from "alchemy/AWS";
81 *
82 * export default CertFunction.make(
83 * { main: import.meta.url },
84 * Effect.gen(function* () {
85 * yield* AWS.ACMPCA.consumeCertificateAuthorityEvents(
86 * { kinds: ["issuance", "revocation"] },
87 * (events) =>
88 * Stream.runForEach(events, (event) =>
89 * Effect.log(`${event["detail-type"]}: ${event.resources[1]}`),
90 * ),
91 * );
92 * return {};
93 * }).pipe(Effect.provide(AWS.Lambda.EventSource)),
94 * );
95 * ```
96 */
97export const consumeCertificateAuthorityEvents = <
98 StreamReq = never,
99 Req = never,
100>(
101 props: CertificateAuthorityEventSourceProps,
102 process: (
103 events: Stream.Stream<CertificateAuthorityEvent, never, StreamReq>,
104 ) => Effect.Effect<void, never, Req>,
105) =>
106 consumeBusEvents(
107 props.id ?? "ACMPCAEvents",
108 {
109 source: ["aws.acm-pca"],
110 "detail-type": (props.kinds ?? (["issuance"] as const)).map(
111 (kind) => DETAIL_TYPES[kind],
112 ),
113 ...(props.certificateAuthorityArns !== undefined
114 ? { resources: [...props.certificateAuthorityArns] }
115 : {}),
116 },
117 { description: props.description, state: props.state },
118 process,
119 );