1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import * as Output from "../../Output.ts";
4import { isBindingHost } from "../Lambda/Function.ts";
5import type { KxEnvironment } from "./KxEnvironment.ts";
6
7/**
8 * Shared scaffolding for Amazon FinSpace Managed kdb HTTP bindings.
9 *
10 * NOT exported from `index.ts` — every `{Op}Http.ts` in this service is a
11 * thin `Layer.effect(Cap, makeFinSpaceKxHttpBinding({ … }))` over the builder
12 * below. Everything except the operation and the IAM action list is
13 * boilerplate.
14 */
15
16/**
17 * Build the impl Effect for a kdb operation scoped to a {@link KxEnvironment}.
18 *
19 * Every Managed kdb data-plane operation is addressed by `environmentId`,
20 * and kdb sub-resources (databases, clusters, dataviews, users, changesets)
21 * live under the environment's ARN
22 * (`arn:…:kxEnvironment/{envId}/kxDatabase/{db}`, …). The deploy-time half
23 * therefore grants `actions` on the bound environment's ARN plus its `/*`
24 * sub-resource wildcard; the runtime callable injects the environment's id
25 * into every request.
26 */
27export const makeFinSpaceKxHttpBinding = <
28 I extends { environmentId: string },
29 A,
30 E,
31 R,
32>(options: {
33 /** Fully-qualified binding tag, e.g. `AWS.FinSpace.GetKxConnectionString`. */
34 tag: string;
35 /** The distilled operation. */
36 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
37 /** IAM actions granted on the environment ARN and its sub-resources. */
38 actions: readonly string[];
39}) =>
40 Effect.gen(function* () {
41 const op = yield* options.operation;
42
43 return Effect.fn(function* <K extends KxEnvironment>(environment: K) {
44 // Outputs yield a DEFERRED effect — resolve again per invocation below.
45 const EnvironmentId = yield* environment.environmentId;
46 if (!globalThis.__ALCHEMY_RUNTIME__) {
47 const host = yield* Binding.Host;
48 if (isBindingHost(host)) {
49 yield* host.bind`Allow(${host}, ${options.tag}(${environment}))`({
50 policyStatements: [
51 {
52 Effect: "Allow",
53 Action: [...options.actions],
54 Resource: [
55 Output.interpolate`${environment.environmentArn}`,
56 Output.interpolate`${environment.environmentArn}/*`,
57 ],
58 },
59 ],
60 });
61 }
62 }
63 return Effect.fn(`${options.tag}(${environment.LogicalId})`)(function* (
64 request?: Omit<I, "environmentId">,
65 ) {
66 return yield* op({
67 ...request,
68 environmentId: yield* EnvironmentId,
69 } as I);
70 });
71 });
72 });