1import * as AWS from "@/AWS";
2import * as Context from "effect/Context";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import * as Stream from "effect/Stream";
6import * as HttpServerResponse from "effect/http/HttpServerResponse";
7
8export class KinesisStreamFunction extends AWS.Lambda.Function<AWS.Lambda.Function>()(
9 "KinesisStreamFunction",
10) {}
11
12export class StreamAndQueue extends Context.Service<
13 StreamAndQueue,
14 {
15 stream: AWS.Kinesis.Stream;
16 queue: AWS.SQS.Queue;
17 }
18>()("StreamAndQueue") {}
19
20export const StreamAndQueueLive = Layer.effect(
21 StreamAndQueue,
22 Effect.gen(function* () {
23 const stream = yield* AWS.Kinesis.Stream("EventSourceStream", {
24 streamMode: "PROVISIONED",
25 shardCount: 1,
26 });
27 const queue = yield* AWS.SQS.Queue("KinesisEventSinkQueue");
28
29 return {
30 stream,
31 queue,
32 };
33 }),
34);
35export default KinesisStreamFunction.make(
36 {
37 main: import.meta.url,
38 functionUrl: true,
39 },
40 Effect.gen(function* () {
41 const { stream, queue } = yield* StreamAndQueue;
42 const sink = yield* AWS.SQS.QueueSink(queue);
43
44 yield* AWS.Kinesis.consumeStreamRecords(
45 stream,
46 {
47 startingPosition: "LATEST",
48 batchSize: 10,
49 },
50 (records) =>
51 records.pipe(
52 Stream.map((record) => ({
53 MessageBody: JSON.stringify({
54 partitionKey: record.kinesis.partitionKey,
55 data: Buffer.from(record.kinesis.data, "base64").toString("utf8"),
56 eventID: record.eventID,
57 }),
58 })),
59 Stream.run(sink),
60 Effect.orDie,
61 ),
62 );
63
64 const streamName = yield* stream.streamName;
65 const streamArn = yield* stream.streamArn;
66 const queueUrl = yield* queue.queueUrl;
67
68 return {
69 fetch: Effect.gen(function* () {
70 return yield* HttpServerResponse.json({
71 ok: true,
72 streamArn: yield* streamArn,
73 streamName: yield* streamName,
74 queueUrl: yield* queueUrl,
75 });
76 }),
77 };
78 }).pipe(
79 Effect.provide(
80 Layer.provideMerge(
81 Layer.mergeAll(AWS.Lambda.StreamEventSource, AWS.SQS.QueueSinkHttp),
82 Layer.mergeAll(AWS.SQS.SendMessageBatchHttp, StreamAndQueueLive),
83 ),
84 ),
85 ),
86);