1/**
2 * Path-`main` Worker: the stack declares it as
3 * `Cloudflare.Worker("ApiWorker", { main: "./src/api-worker.ts", … })` and
4 * never imports this module. `bun --watch` therefore cannot see it, so an
5 * edit here travels the OTHER dev reload path — the local Worker
6 * provider's bundler watch loop rebuilds and hot-swaps the script while the
7 * exec child, the plan, and every other resource stay exactly as they are.
8 *
9 * Deliberately free of `alchemy` imports so the bundle graph is tiny and
10 * the measured rebuild latency is the dev server's, not rolldown's.
11 *
12 * Routes:
13 * - `GET /marker` → marker + the movable module's value
14 * - `GET /kv` → native KV binding roundtrip
15 * - `GET /env` → plain vars, including the cross-cloud Lambda URL
16 * - `GET /aws/*` → CROSS-CLOUD: fetches the AWS Lambda function URL
17 * served by the floci emulator over its own TLS cert
18 */
19import { API_MARKER } from "./api/marker.ts";
20import { message } from "./api/message.ts";
21
22interface KVNamespaceLike {
23 put(key: string, value: string): Promise<void>;
24 get(key: string): Promise<string | null>;
25}
26
27interface Env {
28 KV: KVNamespaceLike;
29 API_VARIABLE: string;
30 /** Added and removed by the binding-churn phase; absent most of the time. */
31 API_EXTRA?: string;
32 /** The cross-cloud edge; absent while the AWS half is deleted. */
33 AWS_LAMBDA_URL?: string;
34}
35
36export default {
37 fetch: async (request: Request, env: Env) => {
38 const url = new URL(request.url);
39
40 if (url.pathname === "/marker") {
41 return Response.json({ marker: API_MARKER, message: message() });
42 }
43
44 if (url.pathname === "/kv") {
45 const key = url.searchParams.get("key") ?? "hello";
46 await env.KV.put(key, `kv:${key}`);
47 return Response.json({ value: await env.KV.get(key) });
48 }
49
50 if (url.pathname === "/env") {
51 return Response.json({
52 API_VARIABLE: env.API_VARIABLE ?? null,
53 API_EXTRA: env.API_EXTRA ?? null,
54 AWS_LAMBDA_URL: env.AWS_LAMBDA_URL ?? null,
55 });
56 }
57
58 if (url.pathname.startsWith("/aws")) {
59 // Cross-cloud hop: local workerd → the AWS Lambda's function URL,
60 // which under `alchemy dev` is served by the floci emulator behind a
61 // self-signed cert. It only resolves because `alchemy dev` puts the
62 // emulator CA on NODE_EXTRA_CA_CERTS for every process it spawns.
63 const base = env.AWS_LAMBDA_URL;
64 if (!base) return Response.json({ error: "no lambda url" }, { status: 503 });
65 const target = new URL(url.pathname.slice("/aws".length) || "/", base);
66 target.search = url.search;
67 const upstream = await fetch(target, {
68 method: request.method,
69 headers: { "content-type": "application/json" },
70 body: request.method === "GET" ? undefined : await request.text(),
71 });
72 return new Response(await upstream.text(), {
73 status: upstream.status,
74 headers: { "content-type": "application/json" },
75 });
76 }
77
78 return Response.json({ marker: API_MARKER });
79 },
80};