1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import { isBindingHost } from "../Lambda/Function.ts";
4import type { Room } from "./Room.ts";
5
6/**
7 * Shared scaffolding for Amazon IVS Chat HTTP bindings.
8 *
9 * NOT exported from `index.ts` — every thin `{Op}Http.ts` in this service is
10 * a `Layer.effect(Cap, makeIvsChatRoomHttpBinding({ … }))` over the builder
11 * below. Everything except the operation, the IAM action list, and an
12 * optional request-shape mapper is boilerplate.
13 */
14
15/**
16 * Build the impl Effect for an IVS Chat data-plane operation scoped to a
17 * {@link Room}: the deploy-time half grants `actions` on the bound room's
18 * ARN, and the runtime half injects the room's ARN as the `roomIdentifier`
19 * of every request.
20 *
21 * `prepare` (optional) maps a friendlier public request shape onto the wire
22 * request — e.g. `CreateChatToken` converts a `Duration.Input` into the wire
23 * `sessionDurationInMinutes`. It defaults to identity.
24 */
25export const makeIvsChatRoomHttpBinding = <
26 I extends { roomIdentifier: string },
27 A,
28 E,
29 R,
30 Req = Omit<I, "roomIdentifier">,
31>(options: {
32 /** Fully-qualified binding tag, e.g. `AWS.IVSChat.SendEvent`. */
33 tag: string;
34 /** The distilled operation. */
35 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
36 /** IAM actions granted on the room ARN. */
37 actions: readonly string[];
38 /** Map the public request shape to the wire request (defaults to identity). */
39 prepare?: (request: Req) => Omit<I, "roomIdentifier">;
40}) =>
41 Effect.gen(function* () {
42 const op = yield* options.operation;
43
44 return Effect.fn(function* (room: Room) {
45 // Output yields a DEFERRED effect — resolve again per invocation below.
46 const RoomArn = yield* room.roomArn;
47 if (!globalThis.__ALCHEMY_RUNTIME__) {
48 const host = yield* Binding.Host;
49 if (isBindingHost(host)) {
50 yield* host.bind`Allow(${host}, ${options.tag}(${room}))`({
51 policyStatements: [
52 {
53 Effect: "Allow",
54 Action: [...options.actions],
55 Resource: [room.roomArn],
56 },
57 ],
58 });
59 }
60 }
61 return Effect.fn(`${options.tag}(${room.LogicalId})`)(function* (
62 request: Req,
63 ) {
64 const roomIdentifier = yield* RoomArn;
65 const wire = options.prepare
66 ? options.prepare(request)
67 : (request as unknown as Omit<I, "roomIdentifier">);
68 return yield* op({ ...wire, roomIdentifier } as I);
69 });
70 });
71 });