1import type { Credentials } from "@distilled.cloud/aws/Credentials";
2import type { Region as AwsRegion } from "@distilled.cloud/aws/Region";
3import * as Effect from "effect/Effect";
4import type * as HttpClient from "effect/http/HttpClient";
5import * as Binding from "../../Binding.ts";
6import { isBindingHost } from "../Lambda/Function.ts";
7import type { BotAlias } from "./BotAlias.ts";
8
9/**
10 * Shared HTTP scaffolding for the Lex V2 runtime bindings.
11 *
12 * Every Lex V2 conversation capability follows the same shape — resolve the
13 * distilled `lex-runtime-v2` operation, register a `lex:*` IAM policy
14 * statement on the binding host scoped to the bot alias, and return a
15 * runtime callable that injects the alias's `botId` + `botAliasId`. The only
16 * variation is the operation and the IAM action, so those are the inputs.
17 *
18 * @internal — not exported from `index.ts`.
19 */
20
21type LexRequirements = Credentials | AwsRegion | HttpClient.HttpClient;
22
23export interface LexAliasHttpBindingConfig<Req extends object, Out, Err> {
24 /**
25 * Short capability name used in the binding sid and runtime span, e.g.
26 * `"RecognizeText"`.
27 */
28 capability: string;
29 /**
30 * IAM actions granted to the binding host on the alias ARN, e.g.
31 * `["lex:RecognizeText"]`.
32 */
33 iamActions: readonly string[];
34 /**
35 * The distilled `lex-runtime-v2` operation implementing the capability.
36 */
37 operation: Effect.Effect<
38 (
39 input: Req & { botId: string; botAliasId: string },
40 ) => Effect.Effect<Out, Err>,
41 never,
42 LexRequirements
43 >;
44}
45
46/**
47 * Build the implementation effect for a bot-alias-scoped Lex V2 runtime
48 * capability: `Layer.effect(Cap, makeLexAliasHttpBinding({ ... }))`.
49 *
50 * The runtime callable injects the bound alias's `botId` and `botAliasId`,
51 * so `Req` is the operation's request type without those fields.
52 */
53export const makeLexAliasHttpBinding = <Req extends object, Out, Err>(
54 config: LexAliasHttpBindingConfig<Req, Out, Err>,
55) =>
56 Effect.gen(function* () {
57 const op = yield* config.operation;
58
59 return Effect.fn(function* (alias: BotAlias) {
60 const BotId = yield* alias.botId;
61 const BotAliasId = yield* alias.botAliasId;
62 if (!globalThis.__ALCHEMY_RUNTIME__) {
63 const host = yield* Binding.Host;
64 if (isBindingHost(host)) {
65 yield* host.bind`Allow(${host}, AWS.LexV2.${config.capability}(${alias}))`(
66 {
67 policyStatements: [
68 {
69 Effect: "Allow",
70 Action: [...config.iamActions],
71 Resource: [alias.botAliasArn],
72 },
73 ],
74 },
75 );
76 }
77 }
78 return Effect.fn(`AWS.LexV2.${config.capability}(${alias.LogicalId})`)(
79 function* (request: Req) {
80 return yield* op({
81 ...request,
82 botId: yield* BotId,
83 botAliasId: yield* BotAliasId,
84 });
85 },
86 );
87 });
88 });