1import * as frauddetector from "@distilled.cloud/aws/frauddetector";
2import * as Effect from "effect/Effect";
3import { diffTags } from "../../Tags.ts";
4
5/**
6 * Coerce a FraudDetector wire tag list (`{ key, value }[]`) into a plain
7 * `Record<string, string>`.
8 */
9export const toTagRecord = (
10 tags: frauddetector.Tag[] | undefined,
11): Record<string, string> =>
12 Object.fromEntries((tags ?? []).map((t) => [t.key, t.value] as const));
13
14/**
15 * Read the observed tags of a FraudDetector resource by ARN. Tag reads are
16 * best-effort — a failure (e.g. a race with deletion) reports no tags.
17 */
18export const readFraudDetectorTags = Effect.fn(function* (arn: string) {
19 const response = yield* frauddetector
20 .listTagsForResource({ resourceARN: arn })
21 .pipe(Effect.catch(() => Effect.succeed(undefined)));
22 return toTagRecord(response?.tags);
23});
24
25/**
26 * Sync tags on a FraudDetector resource: diff the OBSERVED cloud tags against
27 * the desired set and apply only the delta.
28 */
29export const syncFraudDetectorTags = Effect.fn(function* (
30 arn: string,
31 desiredTags: Record<string, string>,
32) {
33 const observedTags = yield* readFraudDetectorTags(arn);
34 const { removed, upsert } = diffTags(observedTags, desiredTags);
35 if (upsert.length > 0) {
36 yield* frauddetector.tagResource({
37 resourceARN: arn,
38 tags: upsert.map((t) => ({ key: t.Key, value: t.Value })),
39 });
40 }
41 if (removed.length > 0) {
42 yield* frauddetector.untagResource({ resourceARN: arn, tagKeys: removed });
43 }
44});