1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import { isBindingHost } from "../Lambda/Function.ts";
4import type { Channel } from "./Channel.ts";
5import type { Input } from "./Input.ts";
6
7/**
8 * Shared scaffolding for AWS Elemental MediaLive HTTP bindings.
9 *
10 * NOT exported from `index.ts` — every thin `{Op}Http.ts` in this service
11 * is a `Layer.effect(Cap, make…HttpBinding({ … }))` over one of the three
12 * builders below. Everything except the operation and the IAM action list
13 * is boilerplate: channel-scoped bindings inject the bound channel's
14 * server-assigned id as the request's `ChannelId` and grant `actions` on
15 * the channel ARN; input-scoped bindings do the same with `InputId` and
16 * the input ARN; account-scoped bindings pass the request through and
17 * grant `actions` on `*`.
18 */
19
20/**
21 * Build the impl Effect for a MediaLive operation scoped to a
22 * {@link Channel}: the deploy-time half grants `actions` on the bound
23 * channel's ARN, and the runtime half injects the channel's id into every
24 * request as `ChannelId`.
25 */
26export const makeMediaLiveChannelHttpBinding = <
27 I extends { ChannelId: string },
28 A,
29 E,
30 R,
31>(options: {
32 /** Fully-qualified binding tag, e.g. `AWS.MediaLive.StartChannel`. */
33 tag: string;
34 /** The distilled operation; `ChannelId` is injected from the channel. */
35 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
36 /** IAM actions granted on the channel ARN. */
37 actions: readonly string[];
38}) =>
39 Effect.gen(function* () {
40 const op = yield* options.operation;
41
42 return Effect.fn(function* (channel: Channel) {
43 const ChannelId = yield* channel.channelId;
44 if (!globalThis.__ALCHEMY_RUNTIME__) {
45 const host = yield* Binding.Host;
46 if (isBindingHost(host)) {
47 yield* host.bind`Allow(${host}, ${options.tag}(${channel}))`({
48 policyStatements: [
49 {
50 Effect: "Allow",
51 Action: [...options.actions],
52 Resource: [channel.channelArn],
53 },
54 ],
55 });
56 }
57 }
58 return Effect.fn(`${options.tag}(${channel.LogicalId})`)(function* (
59 request?: Omit<I, "ChannelId">,
60 ) {
61 const channelId = yield* ChannelId;
62 return yield* op({ ...request, ChannelId: channelId } as I);
63 });
64 });
65 });
66
67/**
68 * Build the impl Effect for a MediaLive operation scoped to an
69 * {@link Input}: the deploy-time half grants `actions` on the bound
70 * input's ARN, and the runtime half injects the input's id into every
71 * request as `InputId`.
72 */
73export const makeMediaLiveInputHttpBinding = <
74 I extends { InputId: string },
75 A,
76 E,
77 R,
78>(options: {
79 /** Fully-qualified binding tag, e.g. `AWS.MediaLive.DescribeInput`. */
80 tag: string;
81 /** The distilled operation; `InputId` is injected from the input. */
82 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
83 /** IAM actions granted on the input ARN. */
84 actions: readonly string[];
85}) =>
86 Effect.gen(function* () {
87 const op = yield* options.operation;
88
89 return Effect.fn(function* (input: Input) {
90 const InputId = yield* input.inputId;
91 if (!globalThis.__ALCHEMY_RUNTIME__) {
92 const host = yield* Binding.Host;
93 if (isBindingHost(host)) {
94 yield* host.bind`Allow(${host}, ${options.tag}(${input}))`({
95 policyStatements: [
96 {
97 Effect: "Allow",
98 Action: [...options.actions],
99 Resource: [input.inputArn],
100 },
101 ],
102 });
103 }
104 }
105 return Effect.fn(`${options.tag}(${input.LogicalId})`)(function* (
106 request?: Omit<I, "InputId">,
107 ) {
108 const inputId = yield* InputId;
109 return yield* op({ ...request, InputId: inputId } as I);
110 });
111 });
112 });
113
114/**
115 * Build the impl Effect for an account-level MediaLive operation (e.g.
116 * enumerating the account's channels or inputs). The deploy-time half
117 * grants `actions` on `*` — these list operations are not scoped to a
118 * single resource.
119 */
120export const makeMediaLiveAccountHttpBinding = <I, A, E, R>(options: {
121 /** Fully-qualified binding tag, e.g. `AWS.MediaLive.ListChannels`. */
122 tag: string;
123 /** The distilled operation, invoked with the caller's request as-is. */
124 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
125 /** IAM actions granted on `*`. */
126 actions: readonly string[];
127}) =>
128 Effect.gen(function* () {
129 const op = yield* options.operation;
130
131 return Effect.fn(function* () {
132 if (!globalThis.__ALCHEMY_RUNTIME__) {
133 const host = yield* Binding.Host;
134 if (isBindingHost(host)) {
135 yield* host.bind`Allow(${host}, ${options.tag}())`({
136 policyStatements: [
137 {
138 Effect: "Allow",
139 Action: [...options.actions],
140 Resource: ["*"],
141 },
142 ],
143 });
144 }
145 }
146 return Effect.fn(options.tag)(function* (request?: I) {
147 return yield* op((request ?? {}) as I);
148 });
149 });
150 });