@@ -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
98108The 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
118239const 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 ` .
0 commit comments