Skip to content

fix(adapter): transistion to surrealdb@^1.0.0 #11911

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ccefb64
feat: transition from surrealdb.js beta to [email protected]
dvanmali Sep 26, 2024
b0a7bf9
fix: ensure correct adapter type is returned with verified is nulled …
dvanmali Sep 26, 2024
fd4690b
merge: fix conflicts from conflicts
dvanmali Sep 26, 2024
9756ad1
fix: remove log print on test
dvanmali Oct 2, 2024
14efdfe
feat: more AnyAuth login variables, support HTTP rpc connection, add …
dvanmali Oct 2, 2024
395f827
merge: with upstream/main
dvanmali Oct 2, 2024
1ee3a30
Merge branch 'main' of github.com:nextauthjs/next-auth
dvanmali Oct 2, 2024
d3aabc9
restore: changes
dvanmali Oct 2, 2024
34ebb2c
restore: changes
dvanmali Oct 2, 2024
bd1116b
doc: add all env variables available
dvanmali Oct 2, 2024
bc6b85c
fix: throw error not string
dvanmali Oct 2, 2024
36a9f2d
merge: upstream main
dvanmali Oct 9, 2024
c1af8dc
Merge branch 'main' into main
dvanmali Oct 25, 2024
102c8f0
Merge branch 'main' into main
dvanmali Nov 8, 2024
f15a43a
Merge branch 'main' into main
dvanmali Jan 14, 2025
1885d62
Merge branch 'main' into main
dvanmali Feb 10, 2025
59df6a3
Merge branch 'main' into main
dvanmali Mar 14, 2025
c5d2b61
Merge branch 'main' into main
ThangHuuVu May 10, 2025
5aade68
Merge branch 'main' into main
ThangHuuVu May 10, 2025
7c19313
merge: upstream
dvanmali May 12, 2025
89f9467
fix: uses surrealdb:^v1.3.0 for native reconnectivity, feat: add weba…
dvanmali May 13, 2025
293c64b
fix: creating user should use id() not randomUUID()
dvanmali May 13, 2025
fe650dd
fix: ignored files from prettier
dvanmali May 13, 2025
12c90ab
chore: upgrade lockfile as requested
dvanmali May 13, 2025
f7935b4
Merge branch 'main' into main
dvanmali May 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.prettierignore
.cache-loader
.DS_Store
.pnpm-debug.log
Expand All @@ -11,6 +12,7 @@ pnpm-lock.yaml
.github/actions/issue-validator/index.mjs
*.d.ts
*.d.ts.map
**/*.sh

.svelte-kit
.next
Expand Down
232 changes: 165 additions & 67 deletions docs/pages/getting-started/adapters/surrealdb.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,27 @@ import { Code } from "@/components/Code"
### Installation

```bash npm2yarn
npm install @auth/surrealdb-adapter surrealdb.js
npm install @auth/surrealdb-adapter surrealdb
```

### Environment Variables

A valid authentication combination must be provided. The following authentication combinations are supported:

- RootAuth
- NamespaceAuth
- DatabaseAuth
- ScopeAuth

```sh
AUTH_SURREALDB_CONNECTION
AUTH_SURREALDB_USERNAME
AUTH_SURREALDB_PASSWORD
AUTH_SURREALDB_NS
AUTH_SURREALDB_DB
AUTH_SURREAL_URL (required)
AUTH_SURREAL_NS
AUTH_SURREAL_DB
AUTH_SURREAL_USER
AUTH_SURREAL_PW
AUTH_SURREAL_SCOPE
SURREAL_NS (required when using RootAuth or NamespaceAuth)
SURREAL_DB (required when using RootAuth or NamespaceAuth)
```

### Configuration
Expand Down Expand Up @@ -97,84 +107,172 @@ app.use(

The SurrealDB adapter does not handle connections automatically, so you will have to make sure that you pass the Adapter a `SurrealDBClient` that is connected already. Below you can see an example how to do this.

### Utils File

```ts filename="./lib/surrealdb_utils.ts"
import type { ConnectOptions, AnyAuth } from "surrealdb"
import { Surreal, ConnectionStatus } from "surrealdb"

/**
* Maintains a single instance of surrealdb.
* Automatically reconnects unless options.reconnect is set to false manually.
*/
export class MySurreal {
// A single instantiation of a surreal connection
private _surrealdb: Surreal | undefined
private _url: string | URL
private _opts: ConnectOptions | undefined

constructor(
url: Parameters<InstanceType<typeof Surreal>["connect"]>[0],
opts?: ConnectOptions
) {
this._url = url
if (opts && opts.reconnect === undefined) {
opts.reconnect = true
}
this._opts = opts
}

async surrealdb(): Promise<Surreal> {
// Init Surreal
if (!this._surrealdb) {
this._surrealdb = new Surreal()
}

if (this._surrealdb.status == ConnectionStatus.Connected) {
return this._surrealdb
} else if (this._surrealdb.status == ConnectionStatus.Disconnected) {
try {
// Connect as a database user
await this._surrealdb.connect(this._url, this._opts)
if (process.env.NODE_ENV === "development") {
const str = this.toConnectionString(
this._surrealdb.status,
this._opts
)
console.info(str)
}
} catch (error) {
if (error instanceof Error) throw error
throw new Error(error as unknown as string)
}
}
return this._surrealdb
}

private toConnectionString(status: ConnectionStatus, opts?: ConnectOptions) {
let str = `${status}`
const auth = opts?.auth

if (auth && typeof auth !== "string") {
if ("username" in auth) {
str += ` as ${auth.username}`
}
if ("database" in auth && "namespace" in auth) {
str += ` for ${auth.namespace} ${auth.database}`
} else if ("namespace" in auth) {
str += ` for ${auth.namespace}`
} else if ("database" in auth) {
str += ` for ${auth.database}`
}
}
return str
}
}

/**
* Converts environment variables to an AnyAuth type
* to connect with the database
* @param param0 - environment variables
* @returns {RootAuth | NamespaceAuth | DatabaseAuth | ScopeAuth}
*/
export function toAnyAuth({
username,
password,
namespace,
database,
scope,
}: Record<string, string | undefined>) {
let auth: AnyAuth
if (username && password && namespace && database) {
auth = {
database,
namespace,
username,
password,
}
} else if (username && password && namespace) {
auth = {
namespace,
username,
password,
}
} else if (username && password) {
auth = {
username,
password,
}
} else if (scope) {
auth = {
namespace,
database,
username,
password,
scope,
}
} else {
throw new Error("unsupported any auth configuration")
}
return auth
}
```

### Authorization

#### Option 1 – Using RPC:
The clientPromise provides a connection to the database. You could use any connect option you wish. For quick setup, use the DatabaseAuth method. For best security, we recommend creating a Record Access method if you know how to properly setup access table permissions.

```ts filename="./lib/surrealdb.ts"
import { Surreal } from "surrealdb.js"

const connectionString = process.env.AUTH_SURREALDB_CONNECTION
const username = process.env.AUTH_SURREALDB_USERNAME
const password = process.env.AUTH_SURREALDB_PASSWORD
const namespace = process.env.AUTH_SURREALDB_NAMESPACE
const database = process.env.AUTH_SURREALDB_DATABASE
if (!connectionString || !username || !password || !namespace || !database) {
throw new Error(
"SurrealDB connection string, username, password, namespace, and database are required"
)
}
import { type Surreal } from "surrealdb"
import { handleDisconnect, MySurreal, toAnyAuth } from "./lib/surrealdb_utils"

const clientPromise = new Promise<Surreal>(async (resolve, reject) => {
const db = new Surreal()
try {
await db.connect(`${connectionString}/rpc`, {
const {
AUTH_SURREAL_URL: auth_url,
AUTH_SURREAL_NS: auth_ns,
AUTH_SURREAL_DB: auth_db,
AUTH_SURREAL_USER: auth_user,
AUTH_SURREAL_PW: auth_pw,
AUTH_SURREAL_SCOPE: auth_scope,
SURREAL_NS: namespace,
SURREAL_DB: database,
} = process.env
if (!auth_url) throw new Error("required auth_url")
const auth = toAnyAuth({
namespace: auth_ns,
database: auth_db,
username: auth_user,
password: auth_pw,
scope: auth_scope,
})
const surreal = new MySurreal(auth_url, {
namespace,
database,
auth: {
username,
password,
},
auth,
})
const db = await surreal.surrealdb()
resolve(db)
} catch (e) {
reject(e)
}
})

// Export a module-scoped Promise<Surreal>. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise
```

#### Option 2 – Using HTTP:
#### HTTP ENGINE

Useful in serverless environments like Vercel.
With this configuration, we can use the database's http endpoint. Thus, the `AUTH_SURREAL_URL` should begin with `http` or `https`.

```ts filename="./lib/surrealdb.ts"
import { ExperimentalSurrealHTTP } from "surrealdb.js"

const connectionString = process.env.AUTH_SURREALDB_CONNECTION
const username = process.env.AUTH_SURREALDB_USERNAME
const password = process.env.AUTH_SURREALDB_PASSWORD
const namespace = process.env.AUTH_SURREALDB_NAMESPACE
const database = process.env.AUTH_SURREALDB_DATABASE
if (!connectionString || !username || !password || !namespace || !database) {
throw new Error(
"SurrealDB connection string, username, password, namespace, and database are required"
)
}
#### Websocket ENGINE

const clientPromise = new Promise<ExperimentalSurrealHTTP<typeof fetch>>(
async (resolve, reject) => {
try {
const db = new ExperimentalSurrealHTTP(connectionString, {
fetch,
namespace,
database,
auth: {
username,
password,
},
})
resolve(db)
} catch (e) {
reject(e)
}
}
)

// Export a module-scoped Promise<Surreal>. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise
```
With this configuration, we can use the database's websocket endpoint. Thus, the `AUTH_SURREAL_URL` should begin with `ws` or `wss`.
9 changes: 5 additions & 4 deletions packages/adapter-surrealdb/package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
{
"name": "@auth/surrealdb-adapter",
"version": "1.9.1",
"version": "2.0.0",
"description": "SurrealDB adapter for next-auth.",
"homepage": "https://authjs.dev",
"repository": "https://github.com/nextauthjs/next-auth",
"bugs": {
"url": "https://github.com/nextauthjs/next-auth/issues"
},
"author": "Martin Schaer <martin@schaerweb.com>",
"author": "Dylan Vanmali <https://github.com/dvanmali>",
"contributors": [
"Martin Schaer <[email protected]>",
"Thang Huu Vu <[email protected]>"
],
"type": "module",
Expand All @@ -29,7 +30,7 @@
"next-auth",
"next.js",
"oauth",
"mongodb",
"surrealdb",
"adapter"
],
"private": false,
Expand All @@ -45,6 +46,6 @@
"@auth/core": "workspace:*"
},
"peerDependencies": {
"surrealdb.js": "^0.11.0"
"surrealdb": "^1.3.0"
}
}
Loading