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