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 { Application } from "./Application.ts";
6
7/**
8 * Shared scaffolding for AWS Kinesis Analytics v2 (Managed Service for
9 * Apache Flink) HTTP bindings.
10 *
11 * NOT exported from `index.ts` — every `{Op}Http.ts` in this service is a
12 * thin `Layer.effect(Cap, makeKinesisAnalyticsHttpBinding({ … }))` over the
13 * builder below. Everything except the operation and the IAM action list is
14 * boilerplate.
15 *
16 * Every bound operation addresses a single application: the request carries
17 * an `ApplicationName` field which the runtime callable injects from the
18 * bound {@link Application}, and the deploy-time half grants `actions` on
19 * the application's ARN (all `kinesisanalytics:*Application*` actions
20 * authorize against the application resource).
21 */
22/**
23 * Account-level variant of {@link makeKinesisAnalyticsHttpBinding} for
24 * operations that take no application argument (`ListApplications`). The
25 * deploy-time half grants `actions` on `*` — Kinesis Analytics list calls
26 * are not resource-scoped.
27 */
28export const makeKinesisAnalyticsAccountHttpBinding = <I, A, E, R>(options: {
29 /** Fully-qualified binding tag, e.g. `AWS.KinesisAnalyticsV2.ListApplications`. */
30 tag: string;
31 /** The distilled operation, invoked with the caller's request as-is. */
32 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
33 /** IAM actions granted on `*`. */
34 actions: readonly string[];
35}) =>
36 Effect.gen(function* () {
37 const op = yield* options.operation;
38
39 return Effect.fn(function* () {
40 if (!globalThis.__ALCHEMY_RUNTIME__) {
41 const host = yield* Binding.Host;
42 if (isBindingHost(host)) {
43 yield* host.bind`Allow(${host}, ${options.tag}())`({
44 policyStatements: [
45 {
46 Effect: "Allow",
47 Action: [...options.actions],
48 Resource: ["*"],
49 },
50 ],
51 });
52 }
53 }
54 return Effect.fn(options.tag)(function* (request?: I) {
55 return yield* op((request ?? {}) as I);
56 });
57 });
58 });
59
60export const makeKinesisAnalyticsHttpBinding = <
61 I extends { ApplicationName?: string },
62 A,
63 E,
64 R,
65>(options: {
66 /** Fully-qualified binding tag, e.g. `AWS.KinesisAnalyticsV2.StartApplication`. */
67 tag: string;
68 /** The distilled operation; `ApplicationName` is injected from the application. */
69 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
70 /** IAM actions granted on the application ARN. */
71 actions: readonly string[];
72}) =>
73 Effect.gen(function* () {
74 const op = yield* options.operation;
75
76 return Effect.fn(function* <App extends Application>(application: App) {
77 // Outputs yield a DEFERRED effect — resolve again per invocation below.
78 const ApplicationName = yield* application.applicationName;
79 if (!globalThis.__ALCHEMY_RUNTIME__) {
80 const host = yield* Binding.Host;
81 if (isBindingHost(host)) {
82 yield* host.bind`Allow(${host}, ${options.tag}(${application}))`({
83 policyStatements: [
84 {
85 Effect: "Allow",
86 Action: [...options.actions],
87 Resource: [Output.interpolate`${application.applicationArn}`],
88 },
89 ],
90 });
91 }
92 }
93 return Effect.fn(`${options.tag}(${application.LogicalId})`)(function* (
94 request?: Omit<I, "ApplicationName">,
95 ) {
96 return yield* op({
97 ...request,
98 ApplicationName: yield* ApplicationName,
99 } as I);
100 });
101 });
102 });