1/**
2 * Who a user is. Better Auth holds the users, their sessions (browsers),
3 * and their API keys (`git` clients, `gh`); the engine holds none of it.
4 */
5import { BetterAuth } from "@alchemy.run/better-auth";
6import { apiKey } from "@better-auth/api-key";
7import * as Cloudflare from "alchemy/Cloudflare";
8import * as Context from "effect/Context";
9import * as Schema from "effect/Schema";
10
11/** Better Auth's users, sessions, and API keys. */
12export const AuthDb = Cloudflare.D1.Database("AuthDb");
13
14/** Better Auth, yielded wherever it is needed; the engine de-dupes the declaration. */
15export const Auth = BetterAuth({
16 basePath: "/api/auth",
17 emailAndPassword: { enabled: true },
18 plugins: [apiKey()],
19});
20
21/** The user record routes see. */
22export const User = Schema.Struct({
23 id: Schema.String,
24 name: Schema.optional(Schema.String),
25});
26
27/** 401 — no usable credential, on a route that needs one. */
28export class Unauthorized extends Schema.TaggedError<Unauthorized>()(
29 "Unauthorized",
30 {},
31 { httpApiStatus: 401 },
32) {}
33
34/**
35 * Who is calling: the signed-in user, or `null` on an anonymous read of
36 * a public repository. Every route runs with it in context.
37 */
38export class Session extends Context.Service<
39 Session,
40 { readonly user: typeof User.Type | null }
41>()("app/Session") {}