1import * as iam from "@distilled.cloud/aws/iam";
2import * as Effect from "effect/Effect";
3import * as Layer from "effect/Layer";
4import * as Binding from "../../Binding.ts";
5import { isBindingHost } from "../Lambda/Function.ts";
6import type { AccessKey } from "./AccessKey.ts";
7import { GetAccessKeyLastUsed } from "./GetAccessKeyLastUsed.ts";
8
9/**
10 * Bespoke (resource-bound) IAM HTTP binding: unlike the account-level
11 * bindings built on `makeIamHttpBinding`, this one binds a canonical
12 * {@link AccessKey} and injects its `AccessKeyId` into every request.
13 */
14export const GetAccessKeyLastUsedHttp = Layer.effect(
15 GetAccessKeyLastUsed,
16 Effect.gen(function* () {
17 const op = yield* iam.getAccessKeyLastUsed;
18
19 return Effect.fn(function* <K extends AccessKey>(accessKey: K) {
20 const AccessKeyId = yield* accessKey.accessKeyId;
21 if (!globalThis.__ALCHEMY_RUNTIME__) {
22 const host = yield* Binding.Host;
23 if (isBindingHost(host)) {
24 yield* host.bind`Allow(${host}, AWS.IAM.GetAccessKeyLastUsed(${accessKey}))`(
25 {
26 policyStatements: [
27 {
28 Effect: "Allow",
29 Action: ["iam:GetAccessKeyLastUsed"],
30 // The action is evaluated against the owning *user*, whose
31 // path-qualified ARN is not derivable from the access key.
32 Resource: ["*"],
33 },
34 ],
35 },
36 );
37 }
38 }
39 return Effect.fn(`AWS.IAM.GetAccessKeyLastUsed(${accessKey.LogicalId})`)(
40 function* () {
41 return yield* op({ AccessKeyId: yield* AccessKeyId });
42 },
43 );
44 });
45 }),
46);