1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { isDeployTarget, resolveDeployTarget } from "../../core/index.ts";
3import type { BuildOutput } from "../../core/index.ts";
4import * as Effect from "effect/Effect";
5import { describe, expect, it } from "vitest";
6import { makeCloudflareTarget, target } from "../cloudflare.ts";
7import type { SvelteKitTargetConfig } from "../index.ts";
8
9const emptyBuild: BuildOutput = {
10 clientDirectory: undefined,
11 serverModules: undefined,
12 externalWorkspaces: new Set(),
13};
14
15describe("makeCloudflareTarget", () => {
16 it("is a DeployTarget for the cloudflare platform carrying its config", () => {
17 const config: SvelteKitTargetConfig = {
18 compatibilityDate: "2026-03-10",
19 compatibilityFlags: ["nodejs_compat"],
20 adapter: { notFoundHandling: "404-page" },
21 };
22 const cloudflare = makeCloudflareTarget(config);
23 expect(isDeployTarget(cloudflare)).toBe(true);
24 expect(cloudflare.platform).toBe("cloudflare");
25 expect(cloudflare.config).toBe(config);
26 });
27
28 it("declares workerd bundle conditions and cloudflare: externals", () => {
29 const cloudflare = makeCloudflareTarget();
30 expect(cloudflare.bundle?.conditions).toEqual([
31 "workerd",
32 "worker",
33 "module",
34 "browser",
35 ]);
36 expect(cloudflare.bundle?.external).toEqual(["cloudflare:"]);
37 });
38
39 it("produces the in-memory kit adapter from the adapter hook", () => {
40 const cloudflare = makeCloudflareTarget({
41 adapter: { assetsBinding: "STATIC" },
42 });
43 const adapter = cloudflare.adapter({ root: "/tmp/project" });
44 expect(adapter.name).toBe("@alchemy.run/frontend-frameworks/sveltekit");
45 expect(adapter.result.current).toBeUndefined();
46 expect(typeof adapter.adapt).toBe("function");
47 });
48
49 it("constructs a dev adapter with a proxy emulator and a dispose hook", async () => {
50 const cloudflare = makeCloudflareTarget({
51 compatibilityDate: "2026-03-10",
52 });
53 const adapter = cloudflare.adapter({
54 root: "/tmp/project",
55 dev: { env: { SECRET: "value" }, bindings: ["binding-hook"] },
56 });
57 // The emulator is proxy-backed (behavior covered in Adapter.test.ts with
58 // an injected opener); here we only assert the wiring exists without
59 // opening a real workerd instance.
60 expect(typeof adapter.emulate).toBe("function");
61 expect(typeof adapter.dispose).toBe("function");
62 // dispose before any platform() call must not open (or await) a proxy
63 await adapter.dispose?.();
64 });
65
66 it("omits the dev platform for production builds", async () => {
67 const cloudflare = makeCloudflareTarget();
68 const adapter = cloudflare.adapter({ root: "/tmp/project" });
69 const emulator = await adapter.emulate?.();
70 const platform = (await emulator?.platform?.({
71 config: {},
72 prerender: false,
73 })) as { env: Record<string, unknown> };
74 expect(platform.env).toEqual({});
75 });
76
77 it("fails the finishing pass without an on-disk worker entry", async () => {
78 const cloudflare = makeCloudflareTarget();
79 const error = await Effect.runPromise(
80 Effect.flip(
81 cloudflare.finish!(emptyBuild, { root: "/tmp/project" }).pipe(
82 Effect.provide(NodeServices.layer),
83 ) as Effect.Effect<never, unknown>,
84 ),
85 );
86 expect(error).toMatchObject({
87 _tag: "DeployTargetError",
88 platform: "cloudflare",
89 });
90 expect(String((error as { message: string }).message)).toContain(
91 "worker entry",
92 );
93 });
94});
95
96describe("resolveDeployTarget interop", () => {
97 it("applies the factory form to the framework-assembled config", async () => {
98 const config: SvelteKitTargetConfig = { compatibilityDate: "2026-03-10" };
99 const resolved = await Effect.runPromise(
100 resolveDeployTarget("/tmp/project", makeCloudflareTarget, config),
101 );
102 expect(resolved.platform).toBe("cloudflare");
103 expect(resolved.config).toBe(config);
104 expect(typeof resolved.adapter).toBe("function");
105 });
106
107 it("accepts a prebuilt target value as-is", async () => {
108 const value = makeCloudflareTarget({
109 compatibilityFlags: ["nodejs_compat"],
110 });
111 const resolved = await Effect.runPromise(
112 resolveDeployTarget("/tmp/project", value, {}),
113 );
114 expect(resolved).toBe(value);
115 });
116
117 it("exposes the named `target` module export as the factory", () => {
118 expect(target).toBe(makeCloudflareTarget);
119 });
120});