1import type * as iam from "@distilled.cloud/aws/iam";
2import * as Redacted from "effect/Redacted";
3import { toWireDays, toWireSeconds } from "../../Util/Duration.ts";
4import type { PolicyDocument } from "./Policy.ts";
5
6/**
7 * Convert an optional `Duration.Input` prop to whole wire seconds.
8 *
9 * @deprecated Import {@link toWireSeconds} from `Util/Duration.ts` directly.
10 * Kept as an alias because several other AWS services still import it from
11 * here.
12 */
13export const durationToSeconds = toWireSeconds;
14
15/**
16 * Convert an optional `Duration.Input` prop to whole wire days.
17 *
18 * @deprecated Import {@link toWireDays} from `Util/Duration.ts` directly.
19 * Kept as an alias because several other AWS services still import it from
20 * here.
21 */
22export const durationToDays = toWireDays;
23
24export const toTagRecord = (
25 tags: Array<{ Key?: string; Value?: string }> | undefined,
26): Record<string, string> =>
27 Object.fromEntries(
28 (tags ?? [])
29 .filter(
30 (tag): tag is { Key: string; Value: string } =>
31 typeof tag.Key === "string" && typeof tag.Value === "string",
32 )
33 .map((tag) => [tag.Key, tag.Value]),
34 );
35
36const decodePolicyString = (value: string) => {
37 try {
38 return decodeURIComponent(value);
39 } catch {
40 return value;
41 }
42};
43
44export const parsePolicyDocument = (
45 value: string | undefined,
46): PolicyDocument | undefined => {
47 if (!value) {
48 return undefined;
49 }
50
51 const decoded = decodePolicyString(value);
52 return JSON.parse(decoded) as PolicyDocument;
53};
54
55export const stringifyPolicyDocument = (value: PolicyDocument) =>
56 JSON.stringify(value);
57
58export const normalizeIamPath = (value: string | undefined) => {
59 const path = value ?? "/";
60 const withLeadingSlash = path.startsWith("/") ? path : `/${path}`;
61 return withLeadingSlash.endsWith("/")
62 ? withLeadingSlash
63 : `${withLeadingSlash}/`;
64};
65
66export const policyArnFromParts = ({
67 accountId,
68 path,
69 policyName,
70}: {
71 accountId: string;
72 path: string | undefined;
73 policyName: string;
74}) => `arn:aws:iam::${accountId}:policy${normalizeIamPath(path)}${policyName}`;
75
76export const oldestNondefaultPolicyVersion = (
77 versions: iam.PolicyVersion[] | undefined,
78) =>
79 [...(versions ?? [])]
80 .filter((version) => !version.IsDefaultVersion && version.VersionId)
81 .sort(
82 (a, b) => (a.CreateDate?.getTime() ?? 0) - (b.CreateDate?.getTime() ?? 0),
83 )[0];
84
85export const toRedactedString = (
86 value: string | Redacted.Redacted<string> | undefined,
87): Redacted.Redacted<string> | undefined =>
88 value === undefined
89 ? undefined
90 : typeof value === "string"
91 ? Redacted.make(value)
92 : value;
93
94export const toRedactedBytes = (
95 value:
96 | Uint8Array<ArrayBufferLike>
97 | Redacted.Redacted<Uint8Array<ArrayBufferLike>>
98 | undefined,
99): Redacted.Redacted<Uint8Array<ArrayBufferLike>> | undefined =>
100 value === undefined
101 ? undefined
102 : value instanceof Uint8Array
103 ? Redacted.make(value)
104 : value;
105
106export const unwrapRedactedString = (
107 value: string | Redacted.Redacted<string>,
108): string => (typeof value === "string" ? value : Redacted.value(value));