Files
2026-05-27 23:47:53 +01:00

5.1 KiB

betterAuthSurrealAdapter — Better-Auth v1.6 factory

Purpose

betterAuthSurrealAdapter(options) is the Better-Auth v1.6 integration surface for @suaveplan/better-auth-surrealdb. It returns a DBAdapterInstance — a function (BetterAuthOptions) => DBAdapter — that betterAuth({ database }) accepts directly. The factory is a thin, type-safe wrapper around createBetterAuthSurrealAdapter (the v1.4 shape this package has always exported) plus createAdapterFactory from @better-auth/core/db, the official escape-hatch Better-Auth provides for custom database adapters.

The wrapper does no real work of its own beyond schema validation, forwarding, transaction setup, and exposing the bundled SurrealQL DDL via createSchema() so Better-Auth's CLI generator (@better-auth/cli generate) can emit a canonical schema file.

Features

  • Better-Auth v1.6 DBAdapterInstance return type — works with betterAuth({ database: betterAuthSurrealAdapter({ client }) }) out of the box.
  • Same BetterAuthSurrealAdapterOptions shape and Zod schema as the v1.4 surface — client, modelToTable, idStrategy, linkFields, logger are all honoured identically.
  • Transaction support: when options.client is a SurrealAdapter, the factory wires config.transaction to delegate into SurrealAdapter.transaction (a BEGIN/COMMIT/CANCEL TRANSACTION block). The transaction-scoped DBTransactionAdapter is built by re-instantiating the underlying adapter against the transaction's DatabaseLike handle so writes inside transaction(fn) participate in the surrounding transaction.
  • createSchema() returns BETTER_AUTH_SURREAL_SCHEMA verbatim — the same 17-table DDL string this package ships under ./schema. Wrapped in DBAdapterSchemaCreation shape ({ code, path: "./schema.surql", overwrite: true }).
  • OTel: emits a better_auth.surrealdb.operations_total{model: "_transaction", operation: "transaction", outcome} counter point per transaction(...) invocation. The underlying CRUD methods continue to emit their own per-operation counter points unchanged; the wrapper layer never double-counts.

Usage: Basic

import { SurrealAdapter } from "@suaveplan/surrealdb";
import { betterAuthSurrealAdapter } from "@suaveplan/better-auth-surrealdb/adapter/v1.6";
import { applyBetterAuthSchema } from "@suaveplan/better-auth-surrealdb/schema";
import { betterAuth } from "better-auth";

const client = new SurrealAdapter({
    url: "ws://localhost:8000",
    namespace: "auth",
    database: "auth",
    username: "root",
    password: process.env.SURREAL_PASSWORD,
});
await client.connect();
await applyBetterAuthSchema(client);

export const auth = betterAuth({
    database: betterAuthSurrealAdapter({ client }),
    secret: process.env.BETTER_AUTH_SECRET,
    baseURL: "http://localhost:3000",
    emailAndPassword: { enabled: true },
});

Usage: Advanced

import { betterAuthSurrealAdapter } from "@suaveplan/better-auth-surrealdb/adapter/v1.6";

// Custom model-to-table mapping + link-field overrides
const adapter = betterAuthSurrealAdapter({
    client,
    modelToTable: (model) => (model === "user" ? "people" : model),
    linkFields: {
        session: { userId: "people" },
        member: { userId: "people", organizationId: "tenant" },
    },
    idStrategy: "ulid",
});

// Pass to Better-Auth — supports the full v1.6 surface including
// `auth.api.signUpEmail`, `auth.api.signInEmail`, `auth.api.getSession`,
// transactions, schema generation via `@better-auth/cli generate`, etc.

API Reference

  • betterAuthSurrealAdapter(options: BetterAuthSurrealAdapterV16Options): DBAdapterInstance — the factory. Options are validated through BetterAuthSurrealAdapterOptionsSchema; failures throw BetterAuthSurrealError(BETTER_AUTH_SURREALDB_INVALID_INPUT).
  • BetterAuthSurrealAdapterV16Options — type alias for BetterAuthSurrealAdapterOptions. Re-exported for clarity at the v1.6 call site.

Implementation Notes

  • The wrapper construction is two-step: (1) build the 10-method underlying adapter via createBetterAuthSurrealAdapter once at factory call time; (2) inside the per-call (options) => DBAdapter returned by createAdapterFactory, return a CustomAdapter whose methods forward to the cached underlying adapter. Better-Auth's factory adds transformInput/transformOutput field whitelisting, default-value application, and date/boolean/JSON normalisation on top — that's the whole point of the wrapper layer.
  • disableIdGeneration: true is set in the factory config so user-provided id values survive Better-Auth's id-handling layer. The underlying adapter still applies its idStrategy (record-id / plain / ulid).
  • create calls forward with forceAllowId: true so the user-supplied id field is preserved end-to-end (Better-Auth otherwise nulls it on the v1.6 create path).
  • transaction is only wired when the client is a SurrealAdapter instance. For generic SurrealClientView callers, the factory falls back to createAsIsTransaction (sequential execution against the outer adapter, matching Better-Auth's documented degraded-transaction behaviour).