1import * as Effect from "effect/Effect";
2import * as Binding from "../../Binding.ts";
3import { isBindingHost } from "../Lambda/Function.ts";
4import { withPricingRegion } from "./internal.ts";
5
6/**
7 * Shared HTTP scaffolding for the AWS Price List runtime bindings.
8 *
9 * NOT exported from `index.ts` — every `{Op}Http.ts` in this service is a
10 * thin `Layer.effect(Cap, makePricingHttpBinding({ … }))` over the builder
11 * below. Everything except the operation and the IAM action is boilerplate.
12 *
13 * The Price List Query API is a global, data-only service served from
14 * `us-east-1` (and `ap-south-1`) only, so every operation is resolved with
15 * the Region pinned via {@link withPricingRegion}. None of the `pricing:*`
16 * actions support resource-level IAM, so every grant is on
17 * `Resource: ["*"]`.
18 */
19export const makePricingHttpBinding = <I extends object, A, E, R>(options: {
20 /**
21 * Short capability name used in the binding sid and runtime span, e.g.
22 * `"GetProducts"`.
23 */
24 capability: string;
25 /** IAM actions granted on `Resource: ["*"]` (no resource-level IAM). */
26 iamActions: readonly string[];
27 /** The distilled operation implementing the capability. */
28 operation: Effect.Effect<(input: I) => Effect.Effect<A, E>, never, R>;
29}) =>
30 Effect.gen(function* () {
31 // Capture the client with the region pinned to us-east-1 — the Price
32 // List Query API is not served from most regions.
33 const op = yield* withPricingRegion(options.operation);
34
35 return Effect.fn(function* () {
36 if (!globalThis.__ALCHEMY_RUNTIME__) {
37 const host = yield* Binding.Host;
38 if (isBindingHost(host)) {
39 yield* host.bind`Allow(${host}, AWS.Pricing.${options.capability}())`(
40 {
41 policyStatements: [
42 {
43 Effect: "Allow",
44 Action: [...options.iamActions],
45 Resource: ["*"],
46 },
47 ],
48 },
49 );
50 }
51 }
52 return Effect.fn(`AWS.Pricing.${options.capability}`)(function* (
53 request?: I,
54 ) {
55 // The region must also be pinned at the call site: the yield-time
56 // snapshot is only a fallback — the calling fiber's ambient Region
57 // (the host Function's own region) wins over it.
58 return yield* withPricingRegion(op((request ?? {}) as I));
59 });
60 });
61 });