1import type * as Credentials from "@distilled.cloud/aws/Credentials";
2import type * as Region from "@distilled.cloud/aws/Region";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import * as Binding from "../../Binding.ts";
6import { generateDbAuthToken } from "../Connection/DbAuthToken.ts";
7import type { SqlConnectionInfo } from "../Connection/internal.ts";
8import { formatSqlConnectionUrl } from "../Connection/internal.ts";
9import { isBindingHost } from "../Lambda/Function.ts";
10import type { Cluster } from "./Cluster.ts";
11import { Connect, connectEnvPrefix, type ConnectOptions } from "./Connect.ts";
12
13const DSQL_PORT = 5432;
14
15/**
16 * IAM-token implementation of {@link Connect}. At deploy time it grants
17 * `dsql:DbConnect` (or `dsql:DbConnectAdmin`) on the cluster to the host
18 * Function and publishes the endpoint as `DSQL_{LOGICAL_ID}_HOST`; at runtime
19 * it presigns a fresh auth token (client-side SigV4 — no API call) with the
20 * Function's own credentials and formats the full connection descriptor.
21 */
22export const ConnectHttp = Layer.effect(
23 Connect,
24 Effect.gen(function* () {
25 // Captured at layer build so the runtime callable only requires
26 // RuntimeContext — the presign resolves credentials lazily from the
27 // service on every mint, so refreshed execution-role creds are honored.
28 const services = yield* Effect.context<
29 Credentials.Credentials | Region.Region
30 >();
31
32 return Effect.fn(function* (cluster: Cluster, options?: ConnectOptions) {
33 const Host = yield* cluster.endpoint;
34 const admin = options?.admin ?? false;
35
36 if (!globalThis.__ALCHEMY_RUNTIME__) {
37 const host = yield* Binding.Host;
38 if (isBindingHost(host)) {
39 const prefix = connectEnvPrefix(cluster.LogicalId);
40 yield* host.bind`Allow(${host}, AWS.DSQL.Connect(${cluster}))`({
41 env: {
42 [`${prefix}_HOST`]: cluster.endpoint,
43 },
44 policyStatements: [
45 {
46 Effect: "Allow",
47 Action: [admin ? "dsql:DbConnectAdmin" : "dsql:DbConnect"],
48 Resource: [cluster.clusterArn],
49 },
50 ],
51 });
52 }
53 }
54
55 const username = admin ? "admin" : options?.username;
56 const database = options?.database ?? "postgres";
57
58 return Effect.gen(function* () {
59 const host = yield* Host;
60 if (!host) {
61 return yield* Effect.die(
62 `DSQL endpoint for '${cluster.LogicalId}' is not available yet`,
63 );
64 }
65 const password = yield* generateDbAuthToken({
66 service: "dsql",
67 hostname: host,
68 action: admin ? "DbConnectAdmin" : "DbConnect",
69 }).pipe(Effect.provideContext(services));
70 return {
71 host,
72 port: DSQL_PORT,
73 database,
74 username,
75 password,
76 ssl: true,
77 url: formatSqlConnectionUrl({
78 host,
79 port: DSQL_PORT,
80 database,
81 username,
82 password,
83 ssl: true,
84 }),
85 } satisfies SqlConnectionInfo;
86 });
87 });
88 }),
89);