1import * as Cloudflare from "@/Cloudflare";
2import * as Effect from "effect/Effect";
3import * as HttpClientRequest from "effect/http/HttpClientRequest";
4
5/**
6 * Deterministic port the test's host-side HTTP server listens on. It stands
7 * in for a local dev database (e.g. the `@prisma/dev` server) bound to the
8 * developer machine's loopback — the container must be able to reach it even
9 * though `localhost` inside the container is the container itself.
10 */
11export const HOST_PROBE_PORT = 42117;
12
13/**
14 * A literal local Prisma Postgres URL shape (`@prisma/dev` hands these out
15 * in dev). Prisma's client only speaks plain HTTP to `prisma+postgres://`
16 * hosts that look local (`localhost`/`127.0.0.1`/`[::1]`), so whatever the
17 * dev runtime rewrites the host to must still contain "localhost".
18 */
19export const PPG_URL = "prisma+postgres://localhost:51216/?api_key=test-key";
20
21/**
22 * Cloud SQL URLs (Neon pooled, PlanetScale Postgres pooled, PlanetScale
23 * MySQL). The rewrite must leave these hosts alone — they are not loopback,
24 * and mangling them is how a "fix localhost" change would break Neon /
25 * PlanetScale from a container.
26 */
27export const NEON_URL =
28 "postgres://neondb_owner:secret@ep-cool-name-123456-pooler.us-east-1.aws.neon.tech/neondb?sslmode=require";
29export const PLANETSCALE_PG_URL =
30 "postgresql://user:secret@xxxx.pg.psdb.cloud:6432/postgres?sslmode=verify-full";
31export const PLANETSCALE_MYSQL_URL =
32 "mysql://user:secret@aws.connect.psdb.cloud:3306/db?sslaccept=strict";
33
34class HostReachContainer extends Cloudflare.Container<HostReachContainer>()(
35 "HostReachContainer",
36 {
37 // Template string, not `path.join(import.meta.dirname, …)`: this module is
38 // bundled into the Worker and `import.meta.dirname` is undefined there.
39 context: `${import.meta.dirname}/context`,
40 env: {
41 TARGET_URL: `http://localhost:${HOST_PROBE_PORT}/hello`,
42 PPG_URL,
43 NEON_URL,
44 PLANETSCALE_PG_URL,
45 PLANETSCALE_MYSQL_URL,
46 },
47 observability: { logs: { enabled: true } },
48 },
49) {}
50
51/**
52 * Durable Object that binds the {@link HostReachContainer} and exposes the
53 * probe server's routes to the Worker.
54 */
55export class HostReachContainerObject extends Cloudflare.DurableObject<HostReachContainerObject>()(
56 "HostReachContainerObject",
57 Effect.gen(function* () {
58 const container = yield* HostReachContainer;
59
60 return Effect.gen(function* () {
61 const { fetch } = yield* container.getTcpPort(8080);
62
63 const get = (path: string) =>
64 Effect.gen(function* () {
65 const response = yield* fetch(
66 HttpClientRequest.get(`http://container${path}`),
67 );
68 return yield* response.text;
69 });
70
71 return {
72 getEnv: () => get("/env"),
73 getProbe: () => get("/probe"),
74 };
75 });
76 }).pipe(
77 Effect.provide(
78 Cloudflare.Containers.layer(HostReachContainer, {
79 enableInternet: true,
80 }),
81 ),
82 ),
83) {}