1import { normalizeTransferredFrom } from "@/Cloudflare/Workers/DurableObject.ts";
2import { Worker } from "@/Cloudflare/Workers/Worker.ts";
3import {
4 Platform,
5 type PlatformIdentity,
6 type PlatformProps,
7} from "@/Platform.ts";
8import type { Resource } from "@/Resource.ts";
9import type { BaseRuntimeContext } from "@/RuntimeContext.ts";
10import { expect, test } from "alchemy-test";
11import * as Effect from "effect/Effect";
12
13interface TestProps extends PlatformProps {
14 env?: Record<string, string>;
15}
16interface TestResource extends Resource<
17 "Test.PlatformIdentity",
18 TestProps,
19 {}
20> {}
21
22const identity = <const Id extends string>(
23 declaration: PlatformIdentity<Id>,
24): Id => declaration.LogicalId;
25
26test(
27 "Platform declarations expose their logical id without evaluating effects",
28 () => {
29 const TestPlatform: Platform<TestResource, never, {}, BaseRuntimeContext> =
30 Platform<TestResource>("Test.PlatformIdentity", {
31 createRuntimeContext: () => {
32 throw new Error("Reading identity must not create a runtime context");
33 },
34 });
35 const props = Effect.sync(() => {
36 throw new Error("Reading identity must not evaluate props");
37 });
38 const impl = Effect.sync(() => {
39 throw new Error("Reading identity must not evaluate the implementation");
40 });
41
42 class Modular extends TestPlatform<Modular, {}>()("Modular") {}
43 class Bare extends TestPlatform<Bare>()("Bare") {}
44 class Inline extends TestPlatform<Inline>()("Inline", {}, impl) {}
45 class EffectProps extends TestPlatform<EffectProps>()(
46 "EffectProps",
47 props,
48 impl,
49 ) {}
50 const External = TestPlatform("External", {});
51 const ExternalEffect = TestPlatform("ExternalEffect", props);
52 const Functional = TestPlatform("Functional", {}, impl);
53 const FunctionalEffect = TestPlatform("FunctionalEffect", props, impl);
54
55 Modular.make(props, impl);
56 Bare.make(props, impl);
57
58 for (const [id, declaration] of Object.entries({
59 Modular,
60 Bare,
61 Inline,
62 EffectProps,
63 External,
64 ExternalEffect,
65 Functional,
66 FunctionalEffect,
67 })) {
68 expect(identity(declaration)).toBe(id);
69 expect(Effect.isEffect(declaration)).toBe(true);
70 }
71 expect(Modular.of({})).not.toHaveProperty("LogicalId");
72 expect(TestPlatform).not.toHaveProperty("LogicalId");
73 },
74 { tags: ["unit", "local"] },
75);
76
77test(
78 "ordinary Worker declarations retain logical ids before yielding",
79 () => {
80 const props = Effect.sync(() => {
81 throw new Error("Reading identity must not evaluate Worker props");
82 });
83 const impl = Effect.sync(() => {
84 throw new Error(
85 "Reading identity must not evaluate Worker implementation",
86 );
87 });
88
89 class Modular extends Worker<Modular, {}>()("Modular") {}
90 class Inline extends Worker<Inline>()("Inline", {}, impl) {}
91 class EffectProps extends Worker<EffectProps>()(
92 "EffectProps",
93 props,
94 impl,
95 ) {}
96 class External extends Worker<External>()("External", {}) {}
97 class ExternalEffect extends Worker<ExternalEffect>()(
98 "ExternalEffect",
99 props,
100 ) {}
101 const Functional = Worker("Functional", {}, impl);
102 const ExternalFunctional = Worker("ExternalFunctional", {});
103 const ExternalFunctionalEffect = Worker("ExternalFunctionalEffect", props);
104
105 Modular.make(props, impl);
106
107 for (const [id, declaration] of Object.entries({
108 Modular,
109 Inline,
110 EffectProps,
111 External,
112 ExternalEffect,
113 Functional,
114 ExternalFunctional,
115 ExternalFunctionalEffect,
116 })) {
117 expect(identity(declaration)).toBe(id);
118 expect(Effect.isEffect(declaration)).toBe(true);
119 expect(normalizeTransferredFrom(declaration)).toEqual([id]);
120 }
121 expect(Modular.of({})).not.toHaveProperty("LogicalId");
122 expect(Worker).not.toHaveProperty("LogicalId");
123 },
124 {
125 tags: [
126 "unit",
127 "provider:cloudflare",
128 "provider:cloudflare:worker",
129 "local",
130 ],
131 },
132);