1import * as wafv2 from "@distilled.cloud/aws/wafv2";
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 { IPSet } from "./IPSet.ts";
7import { retryOptimisticLock, withWafScope } from "./internal.ts";
8import { UpdateIPSet, type UpdateIPSetRequest } from "./UpdateIPSet.ts";
9
10/**
11 * Bespoke (multi-op) binding: reads the IP set for a fresh `LockToken`,
12 * applies the full-replacement update, and retries optimistic-lock
13 * conflicts by re-reading.
14 */
15export const UpdateIPSetHttp = Layer.effect(
16 UpdateIPSet,
17 Effect.gen(function* () {
18 const get = yield* wafv2.getIPSet;
19 const update = yield* wafv2.updateIPSet;
20
21 return Effect.fn(function* (ipSet: IPSet) {
22 const Name = yield* ipSet.ipSetName;
23 const Id = yield* ipSet.ipSetId;
24 const Scope = yield* ipSet.scope;
25 if (!globalThis.__ALCHEMY_RUNTIME__) {
26 const host = yield* Binding.Host;
27 if (isBindingHost(host)) {
28 yield* host.bind`Allow(${host}, AWS.WAFv2.UpdateIPSet(${ipSet}))`({
29 policyStatements: [
30 {
31 Effect: "Allow",
32 Action: ["wafv2:GetIPSet", "wafv2:UpdateIPSet"],
33 Resource: [ipSet.ipSetArn],
34 },
35 ],
36 });
37 }
38 }
39 return Effect.fn(`AWS.WAFv2.UpdateIPSet(${ipSet.LogicalId})`)(function* (
40 request: UpdateIPSetRequest,
41 ) {
42 const scope = yield* Scope;
43 const key = { Name: yield* Name, Scope: scope, Id: yield* Id };
44 return yield* retryOptimisticLock(
45 withWafScope(
46 scope,
47 Effect.gen(function* () {
48 const fresh = yield* get(key);
49 return yield* update({
50 ...key,
51 Addresses: request.addresses,
52 Description: request.description ?? fresh.IPSet?.Description,
53 LockToken: fresh.LockToken ?? "",
54 });
55 }),
56 ),
57 );
58 });
59 });
60 }),
61);