1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import { isBindingHost } from "../Lambda/Function.ts";
4
5/**
6 * Shared scaffolding for X-Ray HTTP bindings.
7 *
8 * NOT exported from `index.ts` — every single-operation `{Op}Http.ts` in
9 * this service is a thin `Layer.effect(Cap, makeXRayHttpBinding({ … }))`
10 * over the builder below. Everything except the operation and the IAM
11 * action is boilerplate.
12 *
13 * X-Ray's trace, sampling, graph, and insight actions do not support
14 * resource-level permissions, so the deploy-time half of every binding
15 * grants its `actions` on `*` and the runtime callable passes the caller's
16 * request through unchanged.
17 */
18export const makeXRayHttpBinding = <I, A, E, R>(options: {
19 /** Fully-qualified binding tag, e.g. `AWS.XRay.GetServiceGraph`. */
20 tag: string;
21 /** The distilled operation, invoked with the caller's request as-is. */
22 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
23 /** IAM actions granted on `*` (X-Ray has no resource-level permissions). */
24 actions: readonly string[];
25}) =>
26 Effect.gen(function* () {
27 const op = yield* options.operation;
28
29 return Effect.fn(function* () {
30 if (!globalThis.__ALCHEMY_RUNTIME__) {
31 const host = yield* Binding.Host;
32 if (isBindingHost(host)) {
33 yield* host.bind`Allow(${host}, ${options.tag}())`({
34 policyStatements: [
35 {
36 Effect: "Allow",
37 Action: [...options.actions],
38 Resource: ["*"],
39 },
40 ],
41 });
42 }
43 }
44 return Effect.fn(options.tag)(function* (request?: I) {
45 return yield* op((request ?? {}) as I);
46 });
47 });
48 });