# adapter _(no submodules)_ ## Purpose The package's flagship export. `createBetterAuthSurrealAdapter(options)` returns a Better-Auth `Adapter` whose 8 contract methods plus `consumeOne` and `id` are wired against a SurrealDB v3 connection. The adapter validates options through Zod at the boundary, dispatches every CRUD method through OTel-instrumented spans, applies link-field prefix/strip on writes/reads, and compiles `Where[]` filters into parameterised SurrealQL — no string interpolation, no mocks, no `vi.mock`. ## Features - Stable `id` constant `"@suaveplan/better-auth-surrealdb"`. - All 8 Better-Auth methods: `create`, `findOne`, `findMany`, `count`, `update`, `updateMany`, `delete`, `deleteMany`, plus the `consumeOne` primitive Better-Auth v1.6+ adds atop the older 8 methods. - Link-field-aware writes and reads — `userId: "u1"` becomes `userId: "user:u1"` at rest for `record` columns. - Three id-strategies (`record-id` default, `plain`, `ulid`). - OTel counter + histogram via `instrument()`. - Zod-validated options at the boundary; failures raise `BetterAuthSurrealError(INVALID_INPUT)` with the `ZodError` as `cause`. - Connection-readiness check: every method validates `client.isConnected` and raises `CONNECTION_NOT_READY` when the underlying SurrealAdapter has not connected. - Underlying `SurrealError` failures wrap in `QUERY_FAILED` preserving the `cause` chain. ## Usage: Basic ```ts import { SurrealAdapter } from "@suaveplan/surrealdb"; import { applyBetterAuthSchema } from "@suaveplan/better-auth-surrealdb/schema"; import { createBetterAuthSurrealAdapter } from "@suaveplan/better-auth-surrealdb/adapter"; const client = new SurrealAdapter({ url: "ws://localhost:8000" }); await client.connect(); await applyBetterAuthSchema(client); const adapter = createBetterAuthSurrealAdapter({ client }); await adapter.create({ model: "session", data: { id: "s1", userId: "u1", token: "t" }, }); ``` ## Usage: Advanced ```ts import { createBetterAuthSurrealAdapter } from "@suaveplan/better-auth-surrealdb/adapter"; const adapter = createBetterAuthSurrealAdapter({ client: surrealAdapter, idStrategy: "ulid", modelToTable: (m) => `bauth_${m}`, linkFields: { // override default — match a flat-string schema: session: {}, member: { organizationId: "organization" }, }, }); const user = await adapter.findOne({ model: "user", where: [{ field: "email", value: "x@y" }], select: ["id", "email"], }); ``` ## API Reference - `createBetterAuthSurrealAdapter(options): BetterAuthSurrealAdapter` - `BETTER_AUTH_SURREAL_ADAPTER_ID = "@suaveplan/better-auth-surrealdb"` - `BetterAuthSurrealAdapter` — structural type satisfying Better-Auth's `DBAdapter` minus `transaction` / `createSchema` (the host's own transaction primitive remains reachable via `SurrealAdapter.transaction`). ## Implementation Notes The adapter's `client.query()` calls pass the binding record as `[vars]` so both `SurrealAdapter` (which flattens a trailing record) and hand-rolled `SurrealClientView` implementations receive the same shape. `update` is implemented atop `updateMany`'s `RETURN AFTER` row stream and returns the first row — `count() FROM WHERE … GROUP ALL` returns a `{ c: }` row by aliasing; bare `count()` returns the count unnamed which trips SurrealDB v3's stricter row shape. `consumeOne` fetches the row first, then deletes by the same predicate; this is the fallback path Better-Auth's factory installs when an adapter does not expose a native consume primitive, and gives the same race semantics under SurrealDB's read-then-delete pipeline.