1import * 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/** S3 object attributes attached to B2BI EventBridge event details. */
10export interface TransformationFileS3Attributes {
11 /** The bucket containing the object. */
12 bucket?: string;
13 /** The object's key. */
14 "object-key"?: string;
15 /** The object's size in bytes. */
16 "object-size-bytes"?: number;
17}
18
19/**
20 * The `detail` payload B2BI delivers to EventBridge when a transformation
21 * finishes (`Transformation Completed` / `Transformation Failed`). Split
22 * transformations additionally carry `split-attributes`.
23 */
24export interface TransformationEventDetail {
25 /** The system-generated identifier of the transformer run. */
26 "transformer-job-id"?: string;
27 /** The system-generated identifier of the trading partner. */
28 "trading-partner-id"?: string;
29 /** When the transformation began processing. */
30 "start-timestamp"?: string;
31 /** When the transformation finished processing. */
32 "end-timestamp"?: string;
33 /** The X12 transaction set of the document, e.g. `X12_850`. */
34 "x12-transaction-set"?: string;
35 /** The X12 version of the document, e.g. `VERSION_4010`. */
36 "x12-version"?: string;
37 /** Location and size of the input file. */
38 "input-file-s3-attributes"?: TransformationFileS3Attributes;
39 /** Location and size of the output file. */
40 "output-file-s3-attributes"?: TransformationFileS3Attributes;
41 /** For failed transformations, why the transformation failed. */
42 "failure-message"?: string;
43 /** For failed transformations, the failure reason code. */
44 "failure-code"?: string;
45 /**
46 * Status of acknowledgement generation (`NOT_ATTEMPTED`, `COMPLETED`, or
47 * `FAILED`); only populated when the transformation generates one.
48 */
49 "ack-generation-status"?: string;
50 /** Whether an error code was detected while generating the acknowledgement. */
51 "ack-error-code-detected"?: boolean;
52 /** Source format (`JSON` or `XML`); outbound transformations only. */
53 "input-format"?: string;
54 /** Output format (`X12`); outbound transformations only. */
55 "output-format"?: string;
56 /** Validation outcome: `SUCCEEDED`, `FAILED`, or `NOT_ATTEMPTED`. */
57 "validation-status"?: string;
58 /** Where the validation report is stored in S3. */
59 "validation-report-s3-location"?: {
60 bucket?: string;
61 "object-key"?: string;
62 };
63 /** Split-file details; only present for split transformations. */
64 "split-attributes"?: {
65 /** 1-indexed number of this split. */
66 "split-number"?: number;
67 /** Total number of splits. */
68 "total-split-count"?: number;
69 /** Whether this split is valid per the X12 standard. */
70 "split-is-valid"?: boolean;
71 };
72}
73
74/**
75 * The `detail` payload B2BI delivers to EventBridge when acknowledgement
76 * generation finishes (`Acknowledgement Completed` / `Acknowledgement
77 * Failed`).
78 */
79export interface AcknowledgementEventDetail {
80 /** The system-generated identifier of the transformer run. */
81 "transformer-job-id"?: string;
82 /** The system-generated identifier of the trading partner. */
83 "trading-partner-id"?: string;
84 /** When the acknowledgement began processing. */
85 "start-timestamp"?: string;
86 /** When the acknowledgement finished processing. */
87 "end-timestamp"?: string;
88 /** The X12 transaction set of the input file. */
89 "input-x12-transaction-set"?: string;
90 /** The X12 version of the input file. */
91 "input-x12-version"?: string;
92 /** Location and size of the input file. */
93 "input-file-s3-attributes"?: TransformationFileS3Attributes;
94 /** X12 type of the acknowledgement, e.g. `997`. */
95 "ack-x12-type"?: string;
96 /** X12 version of the acknowledgement. */
97 "ack-x12-version"?: string;
98 /** Location and size of the acknowledgement file (completed events only). */
99 "ack-file-s3-attributes"?: TransformationFileS3Attributes;
100 /** Whether an error code was detected (completed events only). */
101 "ack-error-code-detected"?: boolean;
102 /** For failed acknowledgements, why the acknowledgement failed. */
103 "failure-message"?: string;
104 /** For failed acknowledgements, the failure reason code. */
105 "failure-code"?: string;
106}
107
108/** A transformation EventBridge event delivered to the handler. */
109export type TransformationEvent = EventRecord<TransformationEventDetail>;
110
111/** An acknowledgement EventBridge event delivered to the handler. */
112export type AcknowledgementEvent = EventRecord<AcknowledgementEventDetail>;
113
114export type TransformationEventType =
115 | "Transformation Completed"
116 | "Transformation Failed";
117
118export type AcknowledgementEventType =
119 | "Acknowledgement Completed"
120 | "Acknowledgement Failed";
121
122export interface TransformationEventSourceProps extends EventRouteProps {
123 /**
124 * Logical id prefix for the backing EventBridge rule.
125 * @default "B2BI"
126 */
127 id?: string;
128 /**
129 * Only deliver these event types.
130 * @default both `Transformation Completed` and `Transformation Failed`
131 */
132 events?: TransformationEventType[];
133}
134
135export interface AcknowledgementEventSourceProps extends EventRouteProps {
136 /**
137 * Logical id prefix for the backing EventBridge rule.
138 * @default "B2BI"
139 */
140 id?: string;
141 /**
142 * Only deliver these event types.
143 * @default both `Acknowledgement Completed` and `Acknowledgement Failed`
144 */
145 events?: AcknowledgementEventType[];
146}
147
148/**
149 * Deliver B2BI transformation results (`aws.b2bi` / `"Transformation
150 * Completed"` and `"Transformation Failed"` EventBridge events) to the host
151 * Function — B2BI emits one for every transformer run, whether started by a
152 * capability's S3 trigger or {@link StartTransformerJob}.
153 *
154 * The EventBridge pattern matches every transformation in the account and
155 * region (the pattern must be literal — `Output` values do not resolve
156 * inside the deployed bundle); inspect `event.detail["trading-partner-id"]`
157 * or the resource ARNs in `event.resources` in the handler if multiple
158 * partnerships share the Function. Provide `AWS.Lambda.EventSource` on the
159 * Function effect to implement the subscription.
160 *
161 * ### Reacting to Transformations
162 * **Example:** Post-Process Completed Transformations
163 * ```typescript
164 * yield* AWS.B2BI.consumeTransformationEvents(
165 * { events: ["Transformation Completed"] },
166 * (events) =>
167 * Stream.runForEach(events, (event) =>
168 * Effect.log(
169 * `transformed -> s3://${event.detail["output-file-s3-attributes"]?.bucket}/${event.detail["output-file-s3-attributes"]?.["object-key"]}`,
170 * ),
171 * ),
172 * );
173 * ```
174 */
175export const consumeTransformationEvents = <StreamReq = never, Req = never>(
176 props: TransformationEventSourceProps,
177 process: (
178 events: Stream.Stream<TransformationEvent, never, StreamReq>,
179 ) => Effect.Effect<void, never, Req>,
180) =>
181 Effect.gen(function* () {
182 const { id, events, ...routeProps } = props;
183
184 yield* consumeBusEvents(
185 `${id ?? "B2BI"}-TransformationEvents`,
186 {
187 source: ["aws.b2bi"],
188 "detail-type":
189 events && events.length > 0
190 ? events
191 : ["Transformation Completed", "Transformation Failed"],
192 },
193 routeProps,
194 process,
195 );
196 });
197
198/**
199 * Deliver B2BI acknowledgement results (`aws.b2bi` / `"Acknowledgement
200 * Completed"` and `"Acknowledgement Failed"` EventBridge events) to the host
201 * Function — emitted when B2BI generates (or fails to generate) an X12
202 * acknowledgement such as a 997 for an inbound document.
203 *
204 * Provide `AWS.Lambda.EventSource` on the Function effect to implement the
205 * subscription.
206 *
207 * ### Reacting to Acknowledgements
208 * **Example:** Alert on Failed Acknowledgements
209 * ```typescript
210 * yield* AWS.B2BI.consumeAcknowledgementEvents(
211 * { events: ["Acknowledgement Failed"] },
212 * (events) =>
213 * Stream.runForEach(events, (event) =>
214 * Effect.log(`ack failed: ${event.detail["failure-message"]}`),
215 * ),
216 * );
217 * ```
218 */
219export const consumeAcknowledgementEvents = <StreamReq = never, Req = never>(
220 props: AcknowledgementEventSourceProps,
221 process: (
222 events: Stream.Stream<AcknowledgementEvent, never, StreamReq>,
223 ) => Effect.Effect<void, never, Req>,
224) =>
225 Effect.gen(function* () {
226 const { id, events, ...routeProps } = props;
227
228 yield* consumeBusEvents(
229 `${id ?? "B2BI"}-AcknowledgementEvents`,
230 {
231 source: ["aws.b2bi"],
232 "detail-type":
233 events && events.length > 0
234 ? events
235 : ["Acknowledgement Completed", "Acknowledgement Failed"],
236 },
237 routeProps,
238 process,
239 );
240 });