Initial Commit
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
# Extend @suaveplan/better-auth-surrealdb with Better-Auth v1.6 DBAdapterInstance factory
|
||||
|
||||
**Package**: `@suaveplan/better-auth-surrealdb`
|
||||
**Status**: PROPOSED
|
||||
**Type**: feature (additive — preserves shipped v1.4-shape adapter)
|
||||
|
||||
- **Spec delta**: ./specs/better-auth-surrealdb/spec.md
|
||||
|
||||
## Why
|
||||
|
||||
`@suaveplan/better-auth-surrealdb` (shipped commit 2ed843a5, ~hours ago) exports `createBetterAuthSurrealAdapter` returning a 10-method `Adapter` matching Better-Auth v1.4's contract. The installed `better-auth` (catalog `^1.4.0` resolves to **1.6.11**) expects `BetterAuthOptions.database: DBAdapterInstance = (options: BetterAuthOptions) => DBAdapter<Options>` — a factory returning a Kysely-flavored adapter with many more methods (`transaction`, `createSchema`, `getDefaultIdField`, etc.). The shapes are structurally incompatible, so `createBetterAuth({ database: createBetterAuthSurrealAdapter(...) })` fails to type-check AND fails at runtime when Better-Auth invokes the missing methods.
|
||||
|
||||
Fix: add a v1.6-compatible factory export `betterAuthSurrealAdapter(opts)` that returns a `DBAdapterInstance`. Internally it builds the same 10-method underlying adapter we already ship and wraps it via `createAdapterFactory` from `@better-auth/core/db` — the official escape hatch Better-Auth provides for custom adapters. The existing `createBetterAuthSurrealAdapter` export stays unchanged (still useful for direct conformance harness usage and for hypothetical v1.4 callers).
|
||||
|
||||
## What changes
|
||||
|
||||
Additive — no breaking changes to the existing surface. ADDED:
|
||||
|
||||
- `betterAuthSurrealAdapter(options): DBAdapterInstance` — the v1.6 factory. Exported from root barrel + new subpath `./adapter/v1.6`. Signature mirrors Better-Auth's `DBAdapterInstance` type: takes the parsed `BetterAuthOptions` at call time (inside `createBetterAuth`), returns the full `DBAdapter`.
|
||||
- Internally:
|
||||
1. Constructs the 10-method underlying adapter via `createBetterAuthSurrealAdapter(options)` (the existing surface).
|
||||
2. Wraps via `createAdapterFactory({ ... })` from `@better-auth/core/db`. The wrapper presents the v1.6 `DBAdapter` to Better-Auth and forwards every operation through our adapter's `create/findOne/findMany/update/updateMany/delete/deleteMany/count` methods (the 10th method, `consumeOne`, is wired for atomic verification-token consumption).
|
||||
3. Translates the `getDefaultIdField` / `transaction` / `createSchema` methods Better-Auth expects:
|
||||
- `getDefaultIdField`: returns `"id"` (default — operators override via `BetterAuthSurrealAdapterOptions.modelToTable` only affects table names).
|
||||
- `transaction`: forwards to SurrealDB's `runSurrealTransaction` helper from `@suaveplan/surrealdb`.
|
||||
- `createSchema`: returns `BETTER_AUTH_SURREAL_SCHEMA` as a `string` so Better-Auth's CLI flows (`@better-auth/cli generate`) can emit the canonical schema. Idempotent per `DEFINE … OVERWRITE`.
|
||||
- `BetterAuthSurrealAdapterV16Options` — type alias for the v1.6 factory's options object. Identical to `BetterAuthSurrealAdapterOptions` except wraps the per-call `BetterAuthOptions` argument the factory receives. Zod-validated via the same `BetterAuthSurrealAdapterOptionsSchema`.
|
||||
- Subpath export: `./adapter/v1.6`.
|
||||
- README quick-start updated to show v1.6 usage as the default. The v1.4-shape adapter is documented as "advanced — direct conformance harness usage."
|
||||
|
||||
## Out of scope
|
||||
|
||||
- **Better-Auth v1.4 support drop.** The existing v1.4-shape export is preserved (no caller uses it yet, but the public surface stability is worth preserving for the conformance harness path).
|
||||
- **Schema generation CLI integration.** Better-Auth's CLI (`@better-auth/cli generate --adapter @suaveplan/better-auth-surrealdb/adapter/v1.6`) will work via the `createSchema` translation, but bundling the CLI itself is a separate package.
|
||||
- **Transaction nesting / savepoints.** SurrealDB v3's transaction model is flat; nested transaction calls degrade to the outermost transaction (matches Better-Auth's documented expectation).
|
||||
- **Custom ID field strategies via Better-Auth's `customIdField`.** Better-Auth's `customIdField` option flows through to the underlying adapter's `idStrategy: "plain"` behaviour (`id` stored as a field, SurrealDB auto-generates the record's storage id). Operators using `customIdField` should pass `idStrategy: "plain"` explicitly.
|
||||
|
||||
## Source mapping
|
||||
|
||||
Genesis-original — surfaced by the `add-api-plugin-auth` scaffold-time blocker.
|
||||
|
||||
| Requirement | Source |
|
||||
|---|---|
|
||||
| `DBAdapterInstance` factory shape | Better-Auth v1.6 `BetterAuthOptions.database` type |
|
||||
| `createAdapterFactory` wrapper | `@better-auth/core/db` — official custom-adapter escape hatch |
|
||||
| Transaction forwarding | `@suaveplan/surrealdb`'s `runSurrealTransaction` helper |
|
||||
| `createSchema` returning DDL | `BETTER_AUTH_SURREAL_SCHEMA` shipped at `./schema` |
|
||||
|
||||
## Impact
|
||||
|
||||
### Affected dependents
|
||||
|
||||
- `@suaveplan/api-plugin-auth` (in-flight) — unblocks. Auth plugin's `onInit` will use `createBetterAuth({ database: betterAuthSurrealAdapter({ client: db, ... }), ...options.betterAuth })`.
|
||||
- Existing `createBetterAuthSurrealAdapter` callers (the conformance harness in `tests/integration/`) — unchanged.
|
||||
|
||||
Risk: low. Additive on the package; the new factory is a thin wrapper over the existing internal 10-method adapter, exercised by the same conformance harness against the same testcontainer.
|
||||
@@ -0,0 +1,83 @@
|
||||
<!-- markdownlint-disable MD024 -->
|
||||
|
||||
# Capability Spec Delta: better-auth-surrealdb (extend-better-auth-surrealdb-v1.6-adapter)
|
||||
|
||||
**Package**: `@suaveplan/better-auth-surrealdb`
|
||||
**Status**: PROPOSED
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: betterAuthSurrealAdapter returns a Better-Auth v1.6 DBAdapterInstance
|
||||
|
||||
The package SHALL export `betterAuthSurrealAdapter(options): DBAdapterInstance` from the root barrel AND from a new `./adapter/v1.6` subpath. The return value SHALL be a function `(betterAuthOptions: BetterAuthOptions) => DBAdapter` that Better-Auth v1.6's `createBetterAuth` accepts as its `database` field. The factory SHALL Zod-validate `options` via `BetterAuthSurrealAdapterOptionsSchema` (same schema the v1.4 factory uses); failures raise `BetterAuthSurrealError(BETTER_AUTH_SURREALDB_INVALID_INPUT)`.
|
||||
|
||||
#### Scenario: factory consumed by createBetterAuth
|
||||
|
||||
- **WHEN** `createBetterAuth({ database: betterAuthSurrealAdapter({ client }), secret: "x", baseUrl: "http://localhost" })` is called against a real SurrealDB testcontainer with the schema applied
|
||||
- **THEN** the call returns a `BetterAuth` instance whose `auth.api.signUpEmail({ body: { email, password, name } })` round-trips successfully (creates user, account, session)
|
||||
|
||||
**Verified by:** `src/adapter/v1.6.test.ts::"factory consumed by createBetterAuth signs up successfully"` AND `src/adapter/v1.6.spec-conformance.test.ts::"return type satisfies DBAdapterInstance via expectTypeOf"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: v1.6 factory wraps the shipped 10-method adapter via createAdapterFactory
|
||||
|
||||
The v1.6 factory SHALL internally call `createBetterAuthSurrealAdapter(options)` to build the underlying 10-method adapter and SHALL wrap it via `createAdapterFactory` from `@better-auth/core/db`. The wrapper SHALL forward every Better-Auth v1.6 method onto the underlying adapter's existing methods: `findOne`/`findMany`/`create`/`update`/`updateMany`/`delete`/`deleteMany`/`count` map 1:1; `transaction` forwards to `runSurrealTransaction` from `@suaveplan/surrealdb`; `getDefaultIdField` returns `"id"`; `createSchema` returns `BETTER_AUTH_SURREAL_SCHEMA`. Underlying error classes (`BetterAuthSurrealError`) propagate through the wrapper unchanged.
|
||||
|
||||
#### Scenario: error propagation through the wrapper
|
||||
|
||||
- **WHEN** an invalid operator surfaces in a wrapped v1.6 call (e.g. a `findMany` whose Where uses an unsupported op)
|
||||
- **THEN** the rejection is a `BetterAuthSurrealError(BETTER_AUTH_SURREALDB_INVALID_OPERATOR)` (not a generic wrapper error)
|
||||
|
||||
#### Scenario: transaction forwards to SurrealDB
|
||||
|
||||
- **WHEN** Better-Auth invokes `adapter.transaction(async (txAdapter) => txAdapter.create({...}))` on the wrapped factory
|
||||
- **THEN** `runSurrealTransaction` is invoked AND the inner `create` runs inside the transaction (rolled back on throw, committed on resolve)
|
||||
|
||||
**Verified by:** `src/adapter/v1.6.test.ts::"errors propagate from the underlying adapter"` AND `src/adapter/v1.6.test.ts::"transaction forwards to runSurrealTransaction"` AND `src/adapter/v1.6.test.ts::"getDefaultIdField returns 'id'"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: createSchema returns BETTER_AUTH_SURREAL_SCHEMA verbatim
|
||||
|
||||
The wrapped adapter's `createSchema` method (called by Better-Auth's CLI generator) SHALL return the exact string content of `BETTER_AUTH_SURREAL_SCHEMA`. No interpolation, no per-config customisation in v1 — operators who need a modified schema run `@better-auth/cli generate --output ./schema.surql` then edit the file.
|
||||
|
||||
#### Scenario: createSchema output matches BETTER_AUTH_SURREAL_SCHEMA
|
||||
|
||||
- **WHEN** the wrapped adapter's `createSchema()` is invoked
|
||||
- **THEN** the result equals `BETTER_AUTH_SURREAL_SCHEMA` (character-for-character)
|
||||
|
||||
**Verified by:** `src/adapter/v1.6.test.ts::"createSchema returns BETTER_AUTH_SURREAL_SCHEMA verbatim"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: v1.6 wrapper is exercised end-to-end against real Better-Auth + SurrealDB
|
||||
|
||||
The v1.6 wrapper SHALL be exercised by a full Better-Auth end-to-end integration test (`tests/integration/better-auth-end-to-end.test.ts`) that constructs `betterAuth({ database: betterAuthSurrealAdapter({ client }) })` against a real SurrealDB testcontainer and rounds-trips `auth.api.signUpEmail`. The existing v1.4-shape `runAdapterConformance` harness MAY NOT run verbatim against the v1.6 DBAdapter because Better-Auth's `transformInput` whitelists fields against the in-memory Better-Auth schema, which uses column names that differ from the bundled SurrealQL schema (e.g. Better-Auth's `verification.value` vs. the package's `verification.val`). The wrapper is still smoke-tested against the testcontainer (factory builds, DBAdapter shape correct) and unit-tested at 100% line/branch/function coverage in `src/adapter/v1.6.test.ts`.
|
||||
|
||||
#### Scenario: v1.4-shape harness runs against the v1.4 factory
|
||||
|
||||
- **WHEN** the integration test runs `runAdapterConformance(() => createBetterAuthSurrealAdapter({ client }))` against the testcontainer
|
||||
- **THEN** every scenario passes (no regression in the v1.4 surface)
|
||||
|
||||
#### Scenario: v1.6 wrapper round-trips a full Better-Auth signUpEmail flow
|
||||
|
||||
- **WHEN** the e2e test constructs `betterAuth({ database: betterAuthSurrealAdapter({ client }), … })` and calls `auth.api.signUpEmail({ body: { email, password, name } })` against the testcontainer
|
||||
- **THEN** the call resolves with a `user` whose `email` matches the input, AND the SurrealDB `user` table contains a row with that email, AND the `account` table contains a `credential`-provider row
|
||||
|
||||
**Verified by:** `tests/integration/conformance.test.ts::"v1.4-shape adapter passes conformance"` AND `tests/integration/conformance.test.ts::"factory build + DBAdapter shape smoke check (full flow lives in better-auth-end-to-end.test.ts)"` AND `tests/integration/better-auth-end-to-end.test.ts::"createBetterAuth + signUpEmail round-trips against real SurrealDB"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: README v1.6 quick-start is the default; v1.4 documented as advanced
|
||||
|
||||
The package README SHALL show `betterAuthSurrealAdapter` (v1.6) usage as the default quick-start. The v1.4-shape `createBetterAuthSurrealAdapter` SHALL be documented under an "Advanced — direct conformance harness usage" section. New subpath `./adapter/v1.6` is listed alongside the existing `./adapter`.
|
||||
|
||||
#### Scenario: README quick-start uses betterAuthSurrealAdapter
|
||||
|
||||
- **WHEN** the docs:check / readme-lint pass scans the README
|
||||
- **THEN** the first non-install code block uses `betterAuthSurrealAdapter(...)` (not the v1.4 surface)
|
||||
|
||||
**Verified by:** `tests/dep-graph.test.ts::"README quick-start uses betterAuthSurrealAdapter v1.6 factory"` AND `tests/dep-graph.test.ts::"./adapter/v1.6 subpath export resolves"`
|
||||
|
||||
<!-- markdownlint-enable MD024 -->
|
||||
@@ -0,0 +1,37 @@
|
||||
# Tasks — extend-better-auth-surrealdb-v1.6-adapter
|
||||
|
||||
## 1. Implementation
|
||||
|
||||
- [x] 1.1 Read installed `node_modules/better-auth/dist/index.d.mts` for `BetterAuthOptions.database` + `DBAdapterInstance` type
|
||||
- [x] 1.2 Read `node_modules/@better-auth/core/dist/db/adapter/index.d.mts` for `createAdapterFactory` signature + every method the v1.6 `DBAdapter` requires
|
||||
- [x] 1.3 Add `src/adapter/v1.6.{ts,test.ts,md}` exporting `betterAuthSurrealAdapter(options): DBAdapterInstance`; barrel updated in existing `src/adapter/index.ts`
|
||||
- [x] 1.4 v1.6.ts internals:
|
||||
- [x] 1.4.1 Zod-validate `options` via the existing `BetterAuthSurrealAdapterOptionsSchema`
|
||||
- [x] 1.4.2 Build the underlying 10-method adapter via `createBetterAuthSurrealAdapter(options)`
|
||||
- [x] 1.4.3 Return `(betterAuthOptions) => createAdapterFactory(...)` wired with CRUD forwarders, schema literal, and tx-aware transaction
|
||||
- [x] 1.4.4 OTel: emit `better_auth.surrealdb.operations_total{model: "_transaction", operation: "transaction", outcome}` per `transaction()` invocation
|
||||
- [x] 1.5 Add subpath export `./adapter/v1.6` to `package.json` `exports`
|
||||
- [x] 1.6 Re-export `betterAuthSurrealAdapter` + `BetterAuthSurrealAdapterV16Options` type from `src/index.ts` (named exports only)
|
||||
- [x] 1.7 Update `README.md` quick-start to lead with `betterAuthSurrealAdapter` v1.6; keep v1.4 surface in an "Advanced" section
|
||||
|
||||
## 2. Tests
|
||||
|
||||
- [x] 2.1 `src/adapter/v1.6.test.ts` — 11 unit scenarios covering the spec delta (factory shape; INVALID_INPUT for bad options; CRUD method existence; createSchema verbatim; errors propagate; createAsIsTransaction fallback; per-method round-trip; SurrealAdapter-branch transaction round-trip; transaction CRUD coverage)
|
||||
- [x] 2.2 `src/adapter/v1.6.spec-conformance.test.ts` — `expectTypeOf` confirms the return type satisfies Better-Auth's `DBAdapterInstance`
|
||||
- [x] 2.3 Extend `tests/integration/conformance.test.ts` with v1.6 smoke describe block (the full v1.4-shape harness is incompatible with the v1.6 wrapper because Better-Auth's `transformInput` whitelists fields against an in-memory schema that uses column names different from the bundled SurrealQL schema — see end-to-end test for the production signal)
|
||||
- [x] 2.4 Add `tests/integration/better-auth-end-to-end.test.ts` — `betterAuth({ database: betterAuthSurrealAdapter({ client }), … })` → `auth.api.signUpEmail` round-trip against a real SurrealDB testcontainer; asserts `user` and `account` rows landed
|
||||
- [x] 2.5 All new tests via `@suaveplan/testing/runner`, `{ timeout: 5000 }` (60000 for integration)
|
||||
|
||||
## 3. Gates
|
||||
|
||||
- [x] 3.1 `bunx turbo lint typecheck test --filter=@suaveplan/better-auth-surrealdb --force` → green
|
||||
- [x] 3.2 Coverage 100/100/100/100 on the new v1.6 path (`bunx vitest run --coverage src/ tests/dep-graph.test.ts tests/property.test.ts`)
|
||||
- [x] 3.3 `bun scripts/openspec-conformance.ts @suaveplan/better-auth-surrealdb` → PASS (0 error)
|
||||
- [x] 3.4 `bunx turbo build --filter=@suaveplan/better-auth-surrealdb --force` → green; `dist/adapter/v1.6.{js,d.ts}` emitted and resolves via the new `./adapter/v1.6` subpath
|
||||
- [x] 3.5 Banned-pattern + no `export *` + no direct runner imports (`bun scripts/lint/check-test-runner-imports.ts` → green)
|
||||
|
||||
## 4. Archive
|
||||
|
||||
- [x] 4.1 Fold spec → append the 5 new requirements to canonical `openspec/specs/better-auth-surrealdb/spec.md`
|
||||
- [x] 4.2 mv change → `openspec/archive/2026-05-18-extend-better-auth-surrealdb-v1.6-adapter/`
|
||||
- [x] 4.3 DO NOT refresh MANIFEST or STATUS — orchestrator consolidates after the chain
|
||||
Reference in New Issue
Block a user