Skip to content

Commit 07b7d93

Browse files
dvanmaliThangHuuVundom91
authored
feat(adapters): BREAKING CHANGE: transistion to surrealdb@^1.0.0 (#11911)
* feat: transition from surrealdb.js beta to [email protected] * fix: ensure correct adapter type is returned with verified is nulled if not provided * fix: remove log print on test * feat: more AnyAuth login variables, support HTTP rpc connection, add exponential backoff for disconnection events to example * restore: changes * restore: changes * doc: add all env variables available * fix: throw error not string * fix: uses surrealdb:^v1.3.0 for native reconnectivity, feat: add webauthn funcs to adapter * fix: creating user should use id() not randomUUID() * fix: ignored files from prettier * chore: upgrade lockfile as requested * fix: tsc build errors * fix: tsc build errors --------- Co-authored-by: Thang Vu <[email protected]> Co-authored-by: Nico Domino <[email protected]>
1 parent 22c1b8b commit 07b7d93

File tree

9 files changed

+653
-393
lines changed

9 files changed

+653
-393
lines changed

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
.prettierignore
12
.cache-loader
23
.DS_Store
34
.pnpm-debug.log
@@ -11,6 +12,7 @@ pnpm-lock.yaml
1112
.github/actions/issue-validator/index.mjs
1213
*.d.ts
1314
*.d.ts.map
15+
**/*.sh
1416

1517
.svelte-kit
1618
.next

docs/pages/getting-started/adapters/surrealdb.mdx

Lines changed: 165 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,27 @@ import { Code } from "@/components/Code"
1313
### Installation
1414

1515
```bash npm2yarn
16-
npm install @auth/surrealdb-adapter surrealdb.js
16+
npm install @auth/surrealdb-adapter surrealdb
1717
```
1818

1919
### Environment Variables
2020

21+
A valid authentication combination must be provided. The following authentication combinations are supported:
22+
23+
- RootAuth
24+
- NamespaceAuth
25+
- DatabaseAuth
26+
- ScopeAuth
27+
2128
```sh
22-
AUTH_SURREALDB_CONNECTION
23-
AUTH_SURREALDB_USERNAME
24-
AUTH_SURREALDB_PASSWORD
25-
AUTH_SURREALDB_NS
26-
AUTH_SURREALDB_DB
29+
AUTH_SURREAL_URL (required)
30+
AUTH_SURREAL_NS
31+
AUTH_SURREAL_DB
32+
AUTH_SURREAL_USER
33+
AUTH_SURREAL_PW
34+
AUTH_SURREAL_SCOPE
35+
SURREAL_NS (required when using RootAuth or NamespaceAuth)
36+
SURREAL_DB (required when using RootAuth or NamespaceAuth)
2737
```
2838

2939
### Configuration
@@ -97,84 +107,172 @@ app.use(
97107

98108
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.
99109

110+
### Utils File
111+
112+
```ts filename="./lib/surrealdb_utils.ts"
113+
import type { ConnectOptions, AnyAuth } from "surrealdb"
114+
import { Surreal, ConnectionStatus } from "surrealdb"
115+
116+
/**
117+
* Maintains a single instance of surrealdb.
118+
* Automatically reconnects unless options.reconnect is set to false manually.
119+
*/
120+
export class MySurreal {
121+
// A single instantiation of a surreal connection
122+
private _surrealdb: Surreal | undefined
123+
private _url: string | URL
124+
private _opts: ConnectOptions | undefined
125+
126+
constructor(
127+
url: Parameters<InstanceType<typeof Surreal>["connect"]>[0],
128+
opts?: ConnectOptions
129+
) {
130+
this._url = url
131+
if (opts && opts.reconnect === undefined) {
132+
opts.reconnect = true
133+
}
134+
this._opts = opts
135+
}
136+
137+
async surrealdb(): Promise<Surreal> {
138+
// Init Surreal
139+
if (!this._surrealdb) {
140+
this._surrealdb = new Surreal()
141+
}
142+
143+
if (this._surrealdb.status == ConnectionStatus.Connected) {
144+
return this._surrealdb
145+
} else if (this._surrealdb.status == ConnectionStatus.Disconnected) {
146+
try {
147+
// Connect as a database user
148+
await this._surrealdb.connect(this._url, this._opts)
149+
if (process.env.NODE_ENV === "development") {
150+
const str = this.toConnectionString(
151+
this._surrealdb.status,
152+
this._opts
153+
)
154+
console.info(str)
155+
}
156+
} catch (error) {
157+
if (error instanceof Error) throw error
158+
throw new Error(error as unknown as string)
159+
}
160+
}
161+
return this._surrealdb
162+
}
163+
164+
private toConnectionString(status: ConnectionStatus, opts?: ConnectOptions) {
165+
let str = `${status}`
166+
const auth = opts?.auth
167+
168+
if (auth && typeof auth !== "string") {
169+
if ("username" in auth) {
170+
str += ` as ${auth.username}`
171+
}
172+
if ("database" in auth && "namespace" in auth) {
173+
str += ` for ${auth.namespace} ${auth.database}`
174+
} else if ("namespace" in auth) {
175+
str += ` for ${auth.namespace}`
176+
} else if ("database" in auth) {
177+
str += ` for ${auth.database}`
178+
}
179+
}
180+
return str
181+
}
182+
}
183+
184+
/**
185+
* Converts environment variables to an AnyAuth type
186+
* to connect with the database
187+
* @param param0 - environment variables
188+
* @returns {RootAuth | NamespaceAuth | DatabaseAuth | ScopeAuth}
189+
*/
190+
export function toAnyAuth({
191+
username,
192+
password,
193+
namespace,
194+
database,
195+
scope,
196+
}: Record<string, string | undefined>) {
197+
let auth: AnyAuth
198+
if (username && password && namespace && database) {
199+
auth = {
200+
database,
201+
namespace,
202+
username,
203+
password,
204+
}
205+
} else if (username && password && namespace) {
206+
auth = {
207+
namespace,
208+
username,
209+
password,
210+
}
211+
} else if (username && password) {
212+
auth = {
213+
username,
214+
password,
215+
}
216+
} else if (scope) {
217+
auth = {
218+
namespace,
219+
database,
220+
username,
221+
password,
222+
scope,
223+
}
224+
} else {
225+
throw new Error("unsupported any auth configuration")
226+
}
227+
return auth
228+
}
229+
```
230+
100231
### Authorization
101232

102-
#### Option 1 – Using RPC:
233+
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.
103234

104235
```ts filename="./lib/surrealdb.ts"
105-
import { Surreal } from "surrealdb.js"
106-
107-
const connectionString = process.env.AUTH_SURREALDB_CONNECTION
108-
const username = process.env.AUTH_SURREALDB_USERNAME
109-
const password = process.env.AUTH_SURREALDB_PASSWORD
110-
const namespace = process.env.AUTH_SURREALDB_NAMESPACE
111-
const database = process.env.AUTH_SURREALDB_DATABASE
112-
if (!connectionString || !username || !password || !namespace || !database) {
113-
throw new Error(
114-
"SurrealDB connection string, username, password, namespace, and database are required"
115-
)
116-
}
236+
import { type Surreal } from "surrealdb"
237+
import { handleDisconnect, MySurreal, toAnyAuth } from "./lib/surrealdb_utils"
117238

118239
const clientPromise = new Promise<Surreal>(async (resolve, reject) => {
119-
const db = new Surreal()
120240
try {
121-
await db.connect(`${connectionString}/rpc`, {
241+
const {
242+
AUTH_SURREAL_URL: auth_url,
243+
AUTH_SURREAL_NS: auth_ns,
244+
AUTH_SURREAL_DB: auth_db,
245+
AUTH_SURREAL_USER: auth_user,
246+
AUTH_SURREAL_PW: auth_pw,
247+
AUTH_SURREAL_SCOPE: auth_scope,
248+
SURREAL_NS: namespace,
249+
SURREAL_DB: database,
250+
} = process.env
251+
if (!auth_url) throw new Error("required auth_url")
252+
const auth = toAnyAuth({
253+
namespace: auth_ns,
254+
database: auth_db,
255+
username: auth_user,
256+
password: auth_pw,
257+
scope: auth_scope,
258+
})
259+
const surreal = new MySurreal(auth_url, {
122260
namespace,
123261
database,
124-
auth: {
125-
username,
126-
password,
127-
},
262+
auth,
128263
})
264+
const db = await surreal.surrealdb()
129265
resolve(db)
130266
} catch (e) {
131267
reject(e)
132268
}
133269
})
134-
135-
// Export a module-scoped Promise<Surreal>. By doing this in a
136-
// separate module, the client can be shared across functions.
137-
export default clientPromise
138270
```
139271

140-
#### Option 2 – Using HTTP:
272+
#### HTTP ENGINE
141273

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

144-
```ts filename="./lib/surrealdb.ts"
145-
import { ExperimentalSurrealHTTP } from "surrealdb.js"
146-
147-
const connectionString = process.env.AUTH_SURREALDB_CONNECTION
148-
const username = process.env.AUTH_SURREALDB_USERNAME
149-
const password = process.env.AUTH_SURREALDB_PASSWORD
150-
const namespace = process.env.AUTH_SURREALDB_NAMESPACE
151-
const database = process.env.AUTH_SURREALDB_DATABASE
152-
if (!connectionString || !username || !password || !namespace || !database) {
153-
throw new Error(
154-
"SurrealDB connection string, username, password, namespace, and database are required"
155-
)
156-
}
276+
#### Websocket ENGINE
157277

158-
const clientPromise = new Promise<ExperimentalSurrealHTTP<typeof fetch>>(
159-
async (resolve, reject) => {
160-
try {
161-
const db = new ExperimentalSurrealHTTP(connectionString, {
162-
fetch,
163-
namespace,
164-
database,
165-
auth: {
166-
username,
167-
password,
168-
},
169-
})
170-
resolve(db)
171-
} catch (e) {
172-
reject(e)
173-
}
174-
}
175-
)
176-
177-
// Export a module-scoped Promise<Surreal>. By doing this in a
178-
// separate module, the client can be shared across functions.
179-
export default clientPromise
180-
```
278+
With this configuration, we can use the database's websocket endpoint. Thus, the `AUTH_SURREAL_URL` should begin with `ws` or `wss`.

packages/adapter-surrealdb/package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
{
22
"name": "@auth/surrealdb-adapter",
3-
"version": "1.9.1",
3+
"version": "2.0.0",
44
"description": "SurrealDB adapter for next-auth.",
55
"homepage": "https://authjs.dev",
66
"repository": "https://github.com/nextauthjs/next-auth",
77
"bugs": {
88
"url": "https://github.com/nextauthjs/next-auth/issues"
99
},
10-
"author": "Martin Schaer <martin@schaerweb.com>",
10+
"author": "Dylan Vanmali <https://github.com/dvanmali>",
1111
"contributors": [
12+
"Martin Schaer <[email protected]>",
1213
"Thang Huu Vu <[email protected]>"
1314
],
1415
"type": "module",
@@ -29,7 +30,7 @@
2930
"next-auth",
3031
"next.js",
3132
"oauth",
32-
"mongodb",
33+
"surrealdb",
3334
"adapter"
3435
],
3536
"private": false,
@@ -45,6 +46,6 @@
4546
"@auth/core": "workspace:*"
4647
},
4748
"peerDependencies": {
48-
"surrealdb.js": "^0.11.0"
49+
"surrealdb": "^1.3.0"
4950
}
5051
}

0 commit comments

Comments
 (0)