1import * as Lambda from "@/AWS/Lambda";
2import * as VpcLattice from "@/AWS/VpcLattice";
3import * as Duration from "effect/Duration";
4import * as Effect from "effect/Effect";
5import * as Layer from "effect/Layer";
6import { HttpServerRequest } from "effect/http/HttpServerRequest";
7import * as HttpServerResponse from "effect/http/HttpServerResponse";
8import path from "pathe";
9
10const main = path.resolve(import.meta.dirname, "handler.ts");
11
12export class LatticeTestFunction extends Lambda.Function<Lambda.Function>()(
13 "LatticeTestFunction",
14) {}
15
16export default LatticeTestFunction.make(
17 {
18 main,
19 functionUrl: true,
20 timeout: Duration.seconds(30),
21 },
22 Effect.gen(function* () {
23 // A LAMBDA-type target group the function manages its own registration
24 // in at runtime — the self-registration data plane.
25 const targetGroup = yield* VpcLattice.TargetGroup("BindingTargetGroup", {
26 type: "LAMBDA",
27 });
28
29 const listTargets = yield* VpcLattice.ListTargets(targetGroup);
30 const registerTargets = yield* VpcLattice.RegisterTargets(targetGroup);
31 const deregisterTargets = yield* VpcLattice.DeregisterTargets(targetGroup);
32
33 const bound = { deregisterTargets, listTargets, registerTargets };
34
35 return {
36 fetch: Effect.gen(function* () {
37 const request = yield* HttpServerRequest;
38 const url = new URL(request.originalUrl);
39 const pathname = url.pathname;
40
41 if (request.method === "GET" && pathname === "/bindings") {
42 return yield* HttpServerResponse.json({
43 bound: Object.keys(bound).sort(),
44 });
45 }
46
47 // List the target group's registered targets (the target group id
48 // is injected from the binding).
49 if (request.method === "GET" && pathname === "/targets") {
50 const { items } = yield* listTargets({});
51 return yield* HttpServerResponse.json({
52 targets: items.map((t) => ({ id: t.id, status: t.status })),
53 });
54 }
55
56 // Register a target (for a LAMBDA group: a function ARN).
57 if (request.method === "POST" && pathname === "/register") {
58 const body = (yield* request.json) as unknown as { id: string };
59 const { successful = [], unsuccessful = [] } = yield* registerTargets(
60 { targets: [{ id: body.id }] },
61 );
62 return yield* HttpServerResponse.json({
63 successful: successful.map((t) => t.id),
64 unsuccessful: unsuccessful.map((t) => ({
65 failureCode: t.failureCode,
66 id: t.id,
67 })),
68 });
69 }
70
71 // Deregister a target.
72 if (request.method === "POST" && pathname === "/deregister") {
73 const body = (yield* request.json) as unknown as { id: string };
74 const { successful = [], unsuccessful = [] } =
75 yield* deregisterTargets({ targets: [{ id: body.id }] });
76 return yield* HttpServerResponse.json({
77 successful: successful.map((t) => t.id),
78 unsuccessful: unsuccessful.map((t) => ({
79 failureCode: t.failureCode,
80 id: t.id,
81 })),
82 });
83 }
84
85 return yield* HttpServerResponse.json(
86 { error: "Not found", method: request.method, pathname },
87 { status: 404 },
88 );
89 }).pipe(Effect.orDie),
90 };
91 }).pipe(
92 Effect.provide(
93 Layer.mergeAll(
94 VpcLattice.ListTargetsHttp,
95 VpcLattice.RegisterTargetsHttp,
96 VpcLattice.DeregisterTargetsHttp,
97 ),
98 ),
99 ),
100);