1import * as Cloudflare from "@/Cloudflare";
2import * as Effect from "effect/Effect";
3import * as HttpClientRequest from "effect/http/HttpClientRequest";
4import { HttpServerRequest } from "effect/http/HttpServerRequest";
5import * as HttpServerResponse from "effect/http/HttpServerResponse";
6import FetchTargetWorker from "./fetch-target.ts";
7
8/**
9 * Effect-native worker that calls {@link FetchTargetWorker} over an HTTP
10 * service binding via the `Cloudflare.Workers.Fetch` capability (the
11 * HttpClient-shaped sibling of `bindWorker`'s RPC stubs).
12 *
13 * GET /?name=foo → forwards to the target and pipes its body back, prefixed
14 * with `caller saw:` so the test can assert the response crossed both hops.
15 * Upstream HTTP statuses are preserved. Effect failures return 500 with the cause.
16 */
17export default class FetchCallerWorker extends Cloudflare.Worker<FetchCallerWorker>()(
18 "FetchCallerWorker",
19 {
20 main: import.meta.url,
21 },
22 Effect.gen(function* () {
23 const fetchTarget = yield* Cloudflare.Workers.Fetch(FetchTargetWorker);
24
25 return {
26 fetch: Effect.gen(function* () {
27 const request = yield* HttpServerRequest;
28 const name =
29 new URL(request.url, "http://x").searchParams.get("name") ?? "world";
30 const res = yield* fetchTarget(
31 HttpClientRequest.get("https://target/").pipe(
32 HttpClientRequest.setUrlParam("name", name),
33 ),
34 );
35 const body = yield* res.text;
36 return HttpServerResponse.text(`caller saw: ${body}`, {
37 status: res.status,
38 });
39 }).pipe(
40 Effect.catchCause((cause) =>
41 Effect.succeed(
42 HttpServerResponse.text(`caller failed: ${String(cause)}`, {
43 status: 500,
44 }),
45 ),
46 ),
47 ),
48 };
49 }).pipe(Effect.provide(Cloudflare.Workers.FetchBinding)),
50) {}