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 * A package version state, as reported in the EventBridge event detail.
11 */
12export type PackageVersionState =
13 | "Unfinished"
14 | "Published"
15 | "Unlisted"
16 | "Archived"
17 | "Disposed"
18 | "Deleted";
19
20/**
21 * The `detail` payload CodeArtifact delivers to EventBridge on every package
22 * version change (`CodeArtifact Package Version State Change`).
23 */
24export interface PackageVersionStateChangeDetail {
25 /** Name of the domain containing the repository. */
26 domainName: string;
27 /** AWS account ID that owns the domain. */
28 domainOwner?: string;
29 /** Name of the repository the package version changed in. */
30 repositoryName: string;
31 /** Package format (`npm`, `pypi`, `maven`, `nuget`, `generic`, …). */
32 packageFormat: string;
33 /** Namespace of the package, for formats that support one. */
34 packageNamespace?: string;
35 /** Name of the package. */
36 packageName: string;
37 /** Version of the package that changed. */
38 packageVersion: string;
39 /** The state the package version is now in. */
40 packageVersionState: PackageVersionState;
41 /** Revision of the package version after the change. */
42 packageVersionRevision?: string;
43 /** What changed on the version (assets added/removed, status, metadata). */
44 changes?: {
45 assetsAdded?: number;
46 assetsRemoved?: number;
47 assetsUpdated?: number;
48 metadataUpdated?: boolean;
49 statusChanged?: boolean;
50 };
51 /** Whether the version was `Created`, `Updated`, or `Deleted`. */
52 operationType?: "Created" | "Updated" | "Deleted";
53 /** Monotonic sequence number of changes to this package version. */
54 sequenceNumber?: number;
55 /** Deduplication id — identical for retried deliveries of one change. */
56 eventDeduplicationId?: string;
57 /** Additional event fields (the schema grows over time). */
58 [key: string]: unknown;
59}
60
61/**
62 * A CodeArtifact package version state change EventBridge event delivered to
63 * the handler.
64 */
65export type PackageVersionStateChangeEvent =
66 EventRecord<PackageVersionStateChangeDetail>;
67
68export interface PackageVersionStateChangesProps extends EventRouteProps {
69 /**
70 * Logical id for the backing EventBridge rule.
71 * @default "CodeArtifactPackageVersionStateChanges"
72 */
73 id?: string;
74 /**
75 * Only deliver events for these domains (by name).
76 * @default all domains
77 */
78 domains?: string[];
79 /**
80 * Only deliver events for these repositories (by name).
81 * @default all repositories
82 */
83 repositories?: string[];
84 /**
85 * Only deliver events for these package formats (e.g. `["npm"]`).
86 * @default all formats
87 */
88 formats?: string[];
89 /**
90 * Only deliver transitions into these states (e.g. `["Published"]`).
91 * @default all states
92 */
93 states?: PackageVersionState[];
94}
95
96/**
97 * Event source connecting CodeArtifact package version changes to the hosting
98 * compute. CodeArtifact publishes an event to the account's default
99 * EventBridge bus (source `aws.codeartifact`, detail-type `CodeArtifact
100 * Package Version State Change`) every time a package version is created,
101 * changes state (published, archived, disposed, …), or is deleted — including
102 * versions ingested from upstream and external connections; this subscribes
103 * the host Function to those events so it can react without polling.
104 *
105 * CodeArtifact publishes to EventBridge automatically — no additional
106 * resource is created besides the EventBridge rule targeting the host.
107 * Provide the host-specific implementation layer (e.g.
108 * `AWS.Lambda.EventSource`) on the Function effect.
109 *
110 * ### Consuming Package Version Events
111 * **Example:** React to Published Versions
112 * ```typescript
113 * import * as AWS from "alchemy/AWS";
114 *
115 * export default ReleaseBot.make(
116 * { main: import.meta.url },
117 * Effect.gen(function* () {
118 * yield* AWS.CodeArtifact.consumePackageVersionStateChanges(
119 * { states: ["Published"] },
120 * (events) =>
121 * Stream.runForEach(events, (event) =>
122 * Effect.log(
123 * `${event.detail.packageName}@${event.detail.packageVersion} → ${event.detail.packageVersionState}`,
124 * ),
125 * ),
126 * );
127 * return {};
128 * }).pipe(Effect.provide(AWS.Lambda.EventSource)),
129 * );
130 * ```
131 */
132export const consumePackageVersionStateChanges = <
133 StreamReq = never,
134 Req = never,
135>(
136 props: PackageVersionStateChangesProps,
137 process: (
138 events: Stream.Stream<PackageVersionStateChangeEvent, never, StreamReq>,
139 ) => Effect.Effect<void, never, Req>,
140) =>
141 consumeBusEvents(
142 props.id ?? "CodeArtifactPackageVersionStateChanges",
143 {
144 source: ["aws.codeartifact"],
145 "detail-type": ["CodeArtifact Package Version State Change"],
146 ...(props.domains || props.repositories || props.formats || props.states
147 ? {
148 detail: {
149 ...(props.domains ? { domainName: [...props.domains] } : {}),
150 ...(props.repositories
151 ? { repositoryName: [...props.repositories] }
152 : {}),
153 ...(props.formats ? { packageFormat: [...props.formats] } : {}),
154 ...(props.states
155 ? { packageVersionState: [...props.states] }
156 : {}),
157 },
158 }
159 : {}),
160 },
161 { description: props.description, state: props.state },
162 process,
163 );