1import * as Effect from "effect/Effect";
2import * as Output from "../../Output.ts";
3import type { Instance } from "./Instance.ts";
4import type { User } from "./User.ts";
5import { bindGcpHost } from "../Host.ts";
6import { type BindingIam, type GcpHttpOp, grantFor } from "../HttpBinding.ts";
7
8/**
9 * Shared HTTP scaffolding for Cloud SQL instance and user bindings.
10 * Distilled ops are OperationMethods: yield them once at Layer
11 * construction so the inner
12 * runtime Effect is `Effect<A, E>` and does not leak `GcpOpContext`.
13 * NOT exported from index.ts.
14 */
15export const makeSqlInstanceHttpBinding = <
16 I extends { instance?: string; project?: string },
17 A,
18 E,
19>(options: {
20 tag: string;
21 iam: BindingIam;
22 operation: GcpHttpOp<I, A, E>;
23}) =>
24 Effect.gen(function* () {
25 const run = yield* options.operation;
26 return Effect.fn(function* (instance: Instance) {
27 yield* bindGcpHost({
28 tag: options.tag,
29 resource: instance,
30 iam: [
31 grantFor(
32 options.iam,
33 Output.interpolate`projects/${instance.project}/instances/${instance.instanceName}`,
34 ),
35 ],
36 });
37 const instanceName = yield* instance.instanceName;
38 const project = yield* instance.project;
39 return Effect.fn(`${options.tag}(${instance.LogicalId})`)(function* (
40 request?: Omit<I, "instance" | "project">,
41 ) {
42 return yield* run({
43 ...(request ?? {}),
44 instance: yield* instanceName,
45 project: yield* project,
46 } as I);
47 });
48 });
49 });
50
51export const makeSqlUserHttpBinding = <
52 I extends {
53 name?: string;
54 instance?: string;
55 project?: string;
56 host?: string;
57 },
58 A,
59 E,
60>(options: {
61 tag: string;
62 iam: BindingIam;
63 operation: GcpHttpOp<I, A, E>;
64}) =>
65 Effect.gen(function* () {
66 const run = yield* options.operation;
67 return Effect.fn(function* (user: User) {
68 yield* bindGcpHost({
69 tag: options.tag,
70 resource: user,
71 iam: [
72 grantFor(
73 options.iam,
74 Output.interpolate`projects/${user.project}/instances/${user.instance}`,
75 ),
76 ],
77 });
78 const userName = yield* user.userName;
79 const instance = yield* user.instance;
80 const project = yield* user.project;
81 const host = yield* user.host;
82 return Effect.fn(`${options.tag}(${user.LogicalId})`)(function* (
83 request?: Omit<I, "name" | "instance" | "project">,
84 ) {
85 const resolvedHost = request?.host ?? (yield* host);
86 return yield* run({
87 ...(request ?? {}),
88 name: yield* userName,
89 instance: yield* instance,
90 project: yield* project,
91 ...(resolvedHost ? { host: resolvedHost } : {}),
92 } as I);
93 });
94 });
95 });