1import * as Cloudflare from "@/Cloudflare";
2import { CloudflareEnvironment } from "@/Cloudflare/CloudflareEnvironment";
3import { findZoneByName } from "@/Cloudflare/Zone/lookup";
4import * as Provider from "@/Provider";
5import * as Test from "@/Test/Alchemy";
6import * as emailRouting from "@distilled.cloud/cloudflare/email-routing";
7import { describe, expect } from "alchemy-test";
8import * as Effect from "effect/Effect";
9import { MinimumLogLevel } from "effect/References";
10import * as Schedule from "effect/Schedule";
11import { emailRoutingScoped } from "./scope.ts";
12const { test } = Test.make({ providers: Cloudflare.providers() });
13
14const logLevel = Effect.provideService(
15 MinimumLogLevel,
16 process.env.DEBUG ? "Debug" : "Info",
17);
18
19const zoneName =
20 process.env.CLOUDFLARE_TEST_DNS_ZONE_NAME ?? "alchemy-test-2.us";
21
22const resolveZoneId = Effect.gen(function* () {
23 const { accountId } = yield* yield* CloudflareEnvironment;
24 const zone = yield* findZoneByName({ accountId, name: zoneName });
25 if (!zone) {
26 return yield* Effect.die(
27 new Error(`zone "${zoneName}" not found in account`),
28 );
29 }
30 return zone.id;
31});
32
33// The scoped API token the test harness mints propagates eventually-
34// consistently across Cloudflare's edge — a fresh token intermittently 403s.
35// Ride out the blips on the test's own out-of-band calls by retrying the
36// typed `Forbidden` error (part of each email-routing operation's error union
37// via distilled patches).
38const forbiddenRetrySchedule = Schedule.exponential("500 millis");
39
40const getEmailRouting = (zoneId: string) =>
41 emailRouting.getEmailRouting({ zoneId }).pipe(
42 Effect.retry({
43 while: (e) => e._tag === "Forbidden",
44 schedule: forbiddenRetrySchedule,
45 times: 8,
46 }),
47 );
48
49const setEnabled = (zoneId: string, enabled: boolean) =>
50 (enabled
51 ? emailRouting.enableEmailRouting({ zoneId })
52 : emailRouting.disableEmailRouting({ zoneId })
53 ).pipe(
54 Effect.retry({
55 while: (e) => e._tag === "Forbidden",
56 schedule: forbiddenRetrySchedule,
57 times: 8,
58 }),
59 );
60
61describe.sequential.skipIf(!emailRoutingScoped)(
62 "EmailRouting",
63 {
64 tags: [
65 "provider:cloudflare",
66 "provider:cloudflare:email",
67 "provider:cloudflare:zone",
68 "live",
69 ],
70 },
71 () => {
72 // Canonical `list()` test (zone-scoped singleton): there is no account-wide
73 // API for these per-zone settings, so `list()` enumerates every zone via
74 // `listAllZones` and reads the singleton in each. Assert the result is
75 // non-empty and contains the standing test zone. Capture-and-restore the
76 // zone's `enabled` state so the run leaves no residue.
77 test.provider("list enumerates email routing across all zones", (stack) =>
78 Effect.gen(function* () {
79 const zoneId = yield* resolveZoneId;
80
81 yield* stack.destroy();
82
83 // Capture the pre-test enabled state to restore at the end.
84 const before = yield* getEmailRouting(zoneId);
85
86 const provider = yield* Provider.findProvider(Cloudflare.Email.Routing);
87 const all = yield* provider.list();
88
89 expect(all.length).toBeGreaterThan(0);
90 const entry = all.find((r) => r.zoneId === zoneId);
91 expect(entry).toBeDefined();
92 expect(entry!.name).toEqual(zoneName);
93
94 // Restore the captured state.
95 yield* setEnabled(zoneId, before.enabled);
96
97 yield* stack.destroy();
98 }).pipe(logLevel),
99 );
100 },
101);