1import * as Cloudflare from "alchemy/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 { SandboxContainer } from "./SandboxContainer.ts";
7
8/**
9 * Durable Object that fronts {@link SandboxContainer} — the only way a
10 * Worker reaches a Container. `EchoWorker` proxies `GET /sandbox` here.
11 */
12export default class SandboxDO extends Cloudflare.DurableObject<SandboxDO>()(
13 "SandboxDO",
14 Effect.gen(function* () {
15 const container = yield* SandboxContainer;
16
17 return Effect.gen(function* () {
18 return {
19 fetch: Effect.gen(function* () {
20 const request = yield* HttpServerRequest;
21 const url = new URL(request.url, "http://container");
22 // Forward the subpath: `/sandbox/host-fetch` → `/host-fetch`.
23 const path = url.pathname.replace(/^\/sandbox/, "") || "/";
24 const { fetch } = yield* container.getTcpPort(3000);
25 const response = yield* fetch(
26 HttpClientRequest.get(`http://container${path}`),
27 );
28 return HttpServerResponse.text(yield* response.text, {
29 status: response.status,
30 headers: response.headers,
31 });
32 }),
33 };
34 });
35 }).pipe(
36 Effect.provide(
37 Cloudflare.Containers.layer(SandboxContainer, { enableInternet: true }),
38 ),
39 ),
40) {}