1import * as Cloudflare from "alchemy/Cloudflare";
2import * as Neon from "alchemy/Neon";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import { HttpServerRequest } from "effect/http/HttpServerRequest";
6import * as HttpServerResponse from "effect/http/HttpServerResponse";
7import { BetterAuth } from "../../../src/index.ts";
8import { Neon as NeonDatabase } from "../../../src/Neon.ts";
9
10export const PgProject = Neon.Project("BetterAuthNeonWorkerPg");
11
12// The serverless driver speaks WebSocket straight from the Worker — no
13// Hyperdrive, no pg, no TCP. The connectionUri Output binds into the
14// Worker env at deploy and drives the migration Action.
15const AuthDatabase = Layer.unwrap(
16 Effect.map(PgProject, (project) => NeonDatabase(project.connectionUri)),
17);
18
19export default class NeonAuthWorker extends Cloudflare.Worker<NeonAuthWorker>()(
20 "BetterAuthNeonWorker",
21 {
22 main: import.meta.url,
23 compatibility: {
24 date: "2026-03-17",
25 flags: ["nodejs_compat"],
26 },
27 },
28 Effect.gen(function* () {
29 const auth = yield* BetterAuth({
30 basePath: "/auth",
31 emailAndPassword: { enabled: true },
32 });
33
34 return {
35 fetch: Effect.gen(function* () {
36 const request = yield* HttpServerRequest;
37 if (request.url.startsWith("/auth")) {
38 return yield* auth.fetch;
39 }
40 if (request.url.startsWith("/me")) {
41 const session = yield* auth
42 .getSession()
43 .pipe(
44 Effect.catchTag("BetterAuthApiError", () => Effect.succeed(null)),
45 );
46 return yield* HttpServerResponse.json({
47 email: session?.user.email ?? null,
48 });
49 }
50 return HttpServerResponse.text("ok");
51 }),
52 };
53 }).pipe(Effect.provide(AuthDatabase)),
54) {}