1import * as Provider from "@/Provider";
2import * as Stripe from "@/Stripe";
3import * as Test from "@/Test/Alchemy";
4import { GetRadarValueList } from "@distilled.cloud/stripe/stripe";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import { MinimumLogLevel } from "effect/References";
8import * as Schedule from "effect/Schedule";
9import { isMissingStripeResource } from "@/Stripe/missing.ts";
10
11const { test } = Test.make({ providers: Stripe.providers() });
12
13const logLevel = Effect.provideService(
14 MinimumLogLevel,
15 process.env.DEBUG ? "Debug" : "Info",
16);
17
18const waitUntilGone = (id: string) =>
19 GetRadarValueList({ value_list: id }).pipe(
20 Effect.as("found" as const),
21 Effect.catchIf(isMissingStripeResource, () =>
22 Effect.succeed("gone" as const),
23 ),
24 Effect.repeat({
25 schedule: Schedule.spaced("1 second"),
26 until: (status) => status === "gone",
27 times: 10,
28 }),
29 );
30
31test.provider(
32 "create, update, and delete a radar value list",
33 (stack) =>
34 Effect.gen(function* () {
35 yield* stack.destroy();
36
37 const created = yield* stack.deploy(
38 Effect.gen(function* () {
39 return yield* Stripe.RadarValueList("BlockedEmails", {
40 name: "Alchemy Blocked Emails",
41 itemType: "email",
42 metadata: { team: "fraud" },
43 });
44 }),
45 );
46
47 expect(created.id).toMatch(/^rsl_/);
48 expect(created.alias).toEqual(expect.any(String));
49 expect(created.name).toEqual("Alchemy Blocked Emails");
50 expect(created.itemType).toEqual("email");
51 expect(created.createdBy).toEqual(expect.any(String));
52 expect(created.metadata).toMatchObject({ team: "fraud" });
53 expect(created.created).toEqual(expect.any(Number));
54 expect(created.livemode).toEqual(false);
55
56 const fetched = yield* GetRadarValueList({
57 value_list: created.id,
58 });
59 expect(fetched.id).toEqual(created.id);
60 expect(fetched.alias).toEqual(created.alias);
61 expect(fetched.name).toEqual("Alchemy Blocked Emails");
62 expect(fetched.item_type).toEqual("email");
63 expect(fetched.metadata?.team).toEqual("fraud");
64 expect(
65 fetched.metadata?.[Stripe.alchemyMetadataKeys.stack],
66 ).toBeDefined();
67 expect(
68 fetched.metadata?.[Stripe.alchemyMetadataKeys.stage],
69 ).toBeDefined();
70 expect(fetched.metadata?.[Stripe.alchemyMetadataKeys.id]).toBeDefined();
71
72 const updated = yield* stack.deploy(
73 Effect.gen(function* () {
74 return yield* Stripe.RadarValueList("BlockedEmails", {
75 name: "Alchemy Blocked Emails Updated",
76 itemType: "email",
77 metadata: { team: "risk", sku: "rvl-2" },
78 });
79 }),
80 );
81
82 expect(updated.id).toEqual(created.id);
83 expect(updated.alias).toEqual(created.alias);
84 expect(updated.name).toEqual("Alchemy Blocked Emails Updated");
85 expect(updated.itemType).toEqual("email");
86 expect(updated.metadata).toEqual({ team: "risk", sku: "rvl-2" });
87
88 const refetched = yield* GetRadarValueList({
89 value_list: updated.id,
90 });
91 expect(refetched.id).toEqual(updated.id);
92 expect(refetched.alias).toEqual(created.alias);
93 expect(refetched.name).toEqual("Alchemy Blocked Emails Updated");
94 expect(refetched.item_type).toEqual("email");
95 expect(refetched.metadata?.team).toEqual("risk");
96 expect(refetched.metadata?.sku).toEqual("rvl-2");
97 expect(refetched.metadata?.[Stripe.alchemyMetadataKeys.id]).toBeDefined();
98
99 yield* stack.destroy();
100
101 const gone = yield* waitUntilGone(created.id);
102 expect(gone).toEqual("gone");
103 }).pipe(logLevel),
104 {
105 tags: ["provider:stripe", "provider:stripe:radarvaluelist", "live"],
106 timeout: 120_000,
107 },
108);
109
110test.provider(
111 "replace when item type changes",
112 (stack) =>
113 Effect.gen(function* () {
114 yield* stack.destroy();
115
116 const created = yield* stack.deploy(
117 Effect.gen(function* () {
118 return yield* Stripe.RadarValueList("ReplaceList", {
119 name: "Alchemy Replace List",
120 itemType: "email",
121 });
122 }),
123 );
124
125 expect(created.itemType).toEqual("email");
126
127 const replaced = yield* stack.deploy(
128 Effect.gen(function* () {
129 return yield* Stripe.RadarValueList("ReplaceList", {
130 name: "Alchemy Replace List",
131 itemType: "ip_address",
132 });
133 }),
134 );
135
136 expect(replaced.id).not.toEqual(created.id);
137 expect(replaced.itemType).toEqual("ip_address");
138 expect(replaced.name).toEqual("Alchemy Replace List");
139
140 const fetched = yield* GetRadarValueList({
141 value_list: replaced.id,
142 });
143 expect(fetched.id).toEqual(replaced.id);
144 expect(fetched.item_type).toEqual("ip_address");
145
146 const oldGone = yield* waitUntilGone(created.id);
147 expect(oldGone).toEqual("gone");
148
149 yield* stack.destroy();
150
151 const gone = yield* waitUntilGone(replaced.id);
152 expect(gone).toEqual("gone");
153 }).pipe(logLevel),
154 {
155 tags: ["provider:stripe", "provider:stripe:radarvaluelist", "live"],
156 timeout: 120_000,
157 },
158);
159
160test.provider(
161 "list enumerates the deployed radar value list",
162 (stack) =>
163 Effect.gen(function* () {
164 yield* stack.destroy();
165
166 const deployed = yield* stack.deploy(
167 Effect.gen(function* () {
168 return yield* Stripe.RadarValueList("ListValueList", {
169 name: "Alchemy List Value List",
170 itemType: "string",
171 metadata: { kind: "list" },
172 });
173 }),
174 );
175
176 const provider = yield* Provider.findProvider(Stripe.RadarValueList);
177 const all = yield* provider.list();
178 const found = all.find((list) => list.id === deployed.id);
179 expect(found).toBeDefined();
180 expect(found?.name).toEqual(deployed.name);
181 expect(found?.itemType).toEqual("string");
182 expect(found?.metadata).toMatchObject({ kind: "list" });
183
184 yield* stack.destroy();
185
186 const gone = yield* waitUntilGone(deployed.id);
187 expect(gone).toEqual("gone");
188 }).pipe(logLevel),
189 {
190 tags: ["provider:stripe", "provider:stripe:radarvaluelist", "live"],
191 timeout: 120_000,
192 },
193);