1import * as Lambda from "@/AWS/Lambda";
2import * as RedshiftServerless from "@/AWS/RedshiftServerless";
3import * as Duration from "effect/Duration";
4import * as Effect from "effect/Effect";
5import * as Redacted from "effect/Redacted";
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, "connect-handler.ts");
11
12export class ServerlessConnectFunction extends Lambda.Function<Lambda.Function>()(
13 "ServerlessConnectFunction",
14) {}
15
16export default ServerlessConnectFunction.make(
17 {
18 main,
19 functionUrl: true,
20 timeout: Duration.seconds(60),
21 },
22 Effect.gen(function* () {
23 const namespace = yield* RedshiftServerless.Namespace("ConnectNamespace", {
24 namespaceName: "alchemy-test-rsconn-ns",
25 dbName: "dev",
26 adminUsername: "alchemyadmin",
27 manageAdminPassword: true,
28 });
29 const workgroup = yield* RedshiftServerless.Workgroup("ConnectWorkgroup", {
30 workgroupName: "alchemy-test-rsconn-wg",
31 namespaceName: namespace.namespaceName,
32 baseCapacity: 8,
33 publiclyAccessible: false,
34 });
35
36 const connect = yield* RedshiftServerless.Connect(workgroup, {
37 database: "dev",
38 });
39
40 return {
41 fetch: Effect.gen(function* () {
42 const request = yield* HttpServerRequest;
43 const url = new URL(request.originalUrl);
44 const pathname = url.pathname;
45
46 if (request.method === "GET" && pathname === "/info") {
47 // Mints fresh temporary credentials via
48 // redshift-serverless:GetCredentials on every request.
49 const info = yield* connect;
50 return yield* HttpServerResponse.json({
51 host: info.host,
52 port: info.port,
53 database: info.database,
54 username: info.username,
55 hasPassword: info.password !== undefined,
56 ssl: info.ssl,
57 urlScheme: Redacted.value(info.url).split("://")[0],
58 expiresInFuture:
59 info.expiration !== undefined &&
60 info.expiration.getTime() > Date.now(),
61 });
62 }
63
64 return yield* HttpServerResponse.json(
65 { error: "Not found", method: request.method, pathname },
66 { status: 404 },
67 );
68 }).pipe(Effect.orDie),
69 };
70 }).pipe(Effect.provide(RedshiftServerless.ConnectHttp)),
71);