| 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 | */ |
| 5 | import { BetterAuth } from "@alchemy.run/better-auth"; |
| 6 | import { apiKey } from "@better-auth/api-key"; |
| 7 | import * as Cloudflare from "alchemy/Cloudflare"; |
| 8 | import * as Context from "effect/Context"; |
| 9 | import * as Schema from "effect/Schema"; |
| 10 | |
| 11 | /** Better Auth's users, sessions, and API keys. */ |
| 12 | export const AuthDb = Cloudflare.D1.Database("AuthDb"); |
| 13 | |
| 14 | /** Better Auth, yielded wherever it is needed; the engine de-dupes the declaration. */ |
| 15 | export const Auth = BetterAuth({ |
| 16 | basePath: "/api/auth", |
| 17 | emailAndPassword: { enabled: true }, |
| 18 | plugins: [apiKey()], |
| 19 | }); |
| 20 | |
| 21 | /** The user record routes see. */ |
| 22 | export 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. */ |
| 28 | export 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 | */ |
| 38 | export class Session extends Context.Service< |
| 39 | Session, |
| 40 | { readonly user: typeof User.Type | null } |
| 41 | >()("app/Session") {} |