1import * as Account from "@/AWS/Account";
2import * as Lambda from "@/AWS/Lambda";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import * as Redacted from "effect/Redacted";
6import { HttpServerRequest } from "effect/http/HttpServerRequest";
7import * as HttpServerResponse from "effect/http/HttpServerResponse";
8import path from "pathe";
9
10const main = path.resolve(import.meta.dirname, "handler.ts");
11
12// The Account API marks contact fields sensitive at the wire level, so
13// distilled returns them as `string | Redacted<string>`. The fixture never
14// echoes the PII itself — only presence/shape — so unwrap locally.
15const unwrap = (value: string | Redacted.Redacted<string> | undefined) =>
16 value === undefined
17 ? undefined
18 : typeof value === "string"
19 ? value
20 : Redacted.value(value);
21
22export class AccountTestFunction extends Lambda.Function<Lambda.Function>()(
23 "AccountTestFunction",
24) {}
25
26export default AccountTestFunction.make(
27 {
28 main,
29 functionUrl: true,
30 },
31 Effect.gen(function* () {
32 // --- account-level bindings (Account Management is an account
33 // singleton; these are the settings reads an ops/compliance function
34 // uses) ---
35 const getAccountInformation = yield* Account.GetAccountInformation();
36 const getContactInformation = yield* Account.GetContactInformation();
37 const getAlternateContact = yield* Account.GetAlternateContact();
38 const listRegions = yield* Account.ListRegions();
39 const getRegionOptStatus = yield* Account.GetRegionOptStatus();
40
41 const bound = {
42 getAccountInformation,
43 getContactInformation,
44 getAlternateContact,
45 listRegions,
46 getRegionOptStatus,
47 };
48
49 return {
50 fetch: Effect.gen(function* () {
51 const request = yield* HttpServerRequest;
52 const url = new URL(request.originalUrl);
53 const pathname = url.pathname;
54
55 if (request.method === "GET" && pathname === "/bindings") {
56 return yield* HttpServerResponse.json({
57 bound: Object.keys(bound),
58 });
59 }
60
61 if (request.method === "GET" && pathname === "/account-info") {
62 const result = yield* getAccountInformation().pipe(
63 Effect.map((r) => ({
64 ok: true as const,
65 accountId: r.AccountId ?? null,
66 accountState: r.AccountState ?? null,
67 hasAccountName: (unwrap(r.AccountName) ?? "").length > 0,
68 })),
69 Effect.catchTag("AccessDeniedException", (e) =>
70 Effect.succeed({ ok: false as const, tag: e._tag }),
71 ),
72 );
73 return yield* HttpServerResponse.json(result);
74 }
75
76 if (request.method === "GET" && pathname === "/contact-info") {
77 const result = yield* getContactInformation().pipe(
78 Effect.map((r) => ({
79 ok: true as const,
80 hasFullName:
81 (unwrap(r.ContactInformation?.FullName) ?? "").length > 0,
82 hasCountryCode:
83 (unwrap(r.ContactInformation?.CountryCode) ?? "").length > 0,
84 })),
85 Effect.catchTag(
86 ["AccessDeniedException", "ResourceNotFoundException"],
87 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
88 ),
89 );
90 return yield* HttpServerResponse.json(result);
91 }
92
93 if (request.method === "GET" && pathname === "/alternate-contact") {
94 // The BILLING alternate contact may or may not be set on the
95 // account — the typed ResourceNotFoundException proves the grant
96 // just as well as live data.
97 const result = yield* getAlternateContact({
98 AlternateContactType: "BILLING",
99 }).pipe(
100 Effect.map((r) => ({
101 ok: true as const,
102 contactType: r.AlternateContact?.AlternateContactType ?? null,
103 })),
104 Effect.catchTag(
105 ["AccessDeniedException", "ResourceNotFoundException"],
106 (e) => Effect.succeed({ ok: false as const, tag: e._tag }),
107 ),
108 );
109 return yield* HttpServerResponse.json(result);
110 }
111
112 if (request.method === "GET" && pathname === "/regions") {
113 // The default page size (20) cuts the alphabetical list off before
114 // us-east-1 — ask for the maximum page.
115 const result = yield* listRegions({ MaxResults: 50 }).pipe(
116 Effect.map((r) => ({
117 ok: true as const,
118 count: r.Regions?.length ?? 0,
119 regionNames: (r.Regions ?? [])
120 .map((region) => region.RegionName)
121 .filter((name): name is string => name !== undefined),
122 })),
123 Effect.catchTag("AccessDeniedException", (e) =>
124 Effect.succeed({ ok: false as const, tag: e._tag }),
125 ),
126 );
127 return yield* HttpServerResponse.json(result);
128 }
129
130 if (request.method === "GET" && pathname === "/region-opt-status") {
131 // us-east-1 is enabled by default in every account.
132 const result = yield* getRegionOptStatus({
133 RegionName: "us-east-1",
134 }).pipe(
135 Effect.map((r) => ({
136 ok: true as const,
137 regionName: r.RegionName ?? null,
138 regionOptStatus: r.RegionOptStatus ?? null,
139 })),
140 Effect.catchTag("AccessDeniedException", (e) =>
141 Effect.succeed({ ok: false as const, tag: e._tag }),
142 ),
143 );
144 return yield* HttpServerResponse.json(result);
145 }
146
147 return yield* HttpServerResponse.json(
148 { error: "Not found", method: request.method, pathname },
149 { status: 404 },
150 );
151 }).pipe(Effect.orDie),
152 };
153 }).pipe(
154 Effect.provide(
155 Layer.mergeAll(
156 Account.GetAccountInformationHttp,
157 Account.GetContactInformationHttp,
158 Account.GetAlternateContactHttp,
159 Account.ListRegionsHttp,
160 Account.GetRegionOptStatusHttp,
161 ),
162 ),
163 ),
164);