1import * as AWS from "@/AWS";
2import * as Context from "effect/Context";
3import * as Duration from "effect/Duration";
4import * as Effect from "effect/Effect";
5import * as Layer from "effect/Layer";
6import * as Stream from "effect/Stream";
7import * as HttpServerResponse from "effect/http/HttpServerResponse";
8import path from "pathe";
9
10const main = path.resolve(import.meta.dirname, "event-source-handler.ts");
11
12// End-to-end LogGroupEventSource fixture: the Lambda consumes log events from
13// a source log group via `consumeLogEvents` (which decodes the gzipped/base64
14// `awslogs.data` payload) and forwards each decoded message into a result SQS
15// queue via `QueueSink`, so the test can observe delivery out-of-band
16// (mirrors test/AWS/SQS/event-source-handler.ts).
17export class LogGroupEventSourceFunction extends AWS.Lambda.Function<AWS.Lambda.Function>()(
18 "LogGroupEventSourceFunction",
19) {}
20
21export class SourceGroupAndResultQueue extends Context.Service<
22 SourceGroupAndResultQueue,
23 {
24 source: AWS.Logs.LogGroup;
25 result: AWS.SQS.Queue;
26 }
27>()("SourceGroupAndResultQueue") {}
28
29export const SourceGroupAndResultQueueLive = Layer.effect(
30 SourceGroupAndResultQueue,
31 Effect.gen(function* () {
32 const source = yield* AWS.Logs.LogGroup("EventSourceLogGroup", {
33 retention: "1 day",
34 });
35 const result = yield* AWS.SQS.Queue("LogEventsResultQueue");
36 return { source, result };
37 }),
38);
39
40export default LogGroupEventSourceFunction.make(
41 {
42 main,
43 functionUrl: true,
44 timeout: Duration.seconds(30),
45 },
46 Effect.gen(function* () {
47 const { source, result } = yield* SourceGroupAndResultQueue;
48 const sink = yield* AWS.SQS.QueueSink(result);
49
50 yield* AWS.Logs.consumeLogEvents(source, { filterPattern: "" }, (events) =>
51 events.pipe(
52 Stream.map((event) => ({ MessageBody: event.message })),
53 Stream.run(sink),
54 Effect.orDie,
55 ),
56 );
57
58 const sourceLogGroupName = yield* source.logGroupName;
59 const resultQueueUrl = yield* result.queueUrl;
60
61 return {
62 fetch: Effect.gen(function* () {
63 return yield* HttpServerResponse.json({
64 ok: true,
65 sourceLogGroupName: yield* sourceLogGroupName,
66 resultQueueUrl: yield* resultQueueUrl,
67 });
68 }).pipe(Effect.orDie),
69 };
70 }).pipe(
71 Effect.provide(
72 Layer.provideMerge(
73 Layer.mergeAll(AWS.Lambda.LogGroupEventSource, AWS.SQS.QueueSinkHttp),
74 Layer.mergeAll(
75 AWS.SQS.SendMessageBatchHttp,
76 SourceGroupAndResultQueueLive,
77 ),
78 ),
79 ),
80 ),
81);