# schema/schema _(no submodules)_ ## Purpose The schema module owns the SurrealQL DDL the user plugin ships — a small extension to Better-Auth's `user` table that adds optional profile columns operators configure via `UserPluginOptions.profileFields`. Every statement uses `DEFINE FIELD OVERWRITE` so re-applying the schema across plugin restarts is idempotent — the field definitions are replaced, existing rows are untouched. ## Features - `DEFAULT_USER_PROFILE_FIELDS` — the canonical four-field set the plugin ships out of the box. - `renderUserProfileSchema(fields)` — pure function that returns the DDL string. Validates each field against the SurrealQL identifier grammar so the output cannot drift into a parser error. - `USER_PROFILE_SCHEMA` — the rendered DDL for the canonical default field set; the most common operator path. - `applyUserProfileSchema({ profileFields, migrationRunner?, db? })` — chooses the migration runner when present (so the apply is recorded in the migration tracking table) and falls back to an inline `db.execute`. Failures wrap into `UserError(USER_SCHEMA_APPLY_FAILED)`. ## Usage: Basic ```ts import { USER_PROFILE_SCHEMA, applyUserProfileSchema, } from "@suaveplan/api-plugin-user/schema/schema"; await applyUserProfileSchema({ profileFields: ["displayName", "avatarUrl", "locale", "timezone"], db: surrealAdapter, }); ``` ## Usage: Advanced Operators who manage migrations externally render the DDL once and write it to disk for their own tooling to apply: ```ts import { renderUserProfileSchema } from "@suaveplan/api-plugin-user/schema/schema"; import { writeFileSync } from "node:fs"; const ddl = renderUserProfileSchema(["displayName", "avatarUrl", "bio"]); writeFileSync("migrations/0001_user_profile.surql", ddl); ``` The plugin's `applySchemaOnInit: false` flag disables the in-plugin apply step when the externally-applied schema is the source of truth. ## API Reference ### `DEFAULT_USER_PROFILE_FIELDS: readonly string[]` Frozen list of the four default field names. ### `renderUserProfileSchema(profileFields): string` Returns the DDL string. Throws `UserError(USER_INVALID_INPUT)` when any field name fails the SurrealQL identifier grammar or the list is empty. ### `USER_PROFILE_SCHEMA: string` `renderUserProfileSchema(DEFAULT_USER_PROFILE_FIELDS)` — pre-rendered. ### `ApplyUserProfileSchemaOptions` `{ profileFields, migrationRunner?, db? }`. ### `applyUserProfileSchema(options): Promise` Applies the DDL via the migration runner (preferred) or the adapter (fallback). Throws `USER_SCHEMA_APPLY_FAILED` on runtime failure, `USER_SERVICE_NOT_AVAILABLE` when neither transport is supplied. ## Implementation Notes - The `DEFINE FIELD OVERWRITE` form is the SurrealDB idiomatic idempotent definition — `DEFINE FIELD ... IF NOT EXISTS` does not exist in SurrealDB 2.x. - The renderer is intentionally pure so operators can diff DDL across plugin upgrades by comparing strings. - The migration name (`0001-user-profile-schema`) lives in the migration-tracking table so re-applies become no-ops once the apply is recorded.