Skip to content

Commit 23fff28

Browse files
authored
Merge branch 'main' into docs-guide-rbac
2 parents b90c363 + 9866f71 commit 23fff28

File tree

14 files changed

+695
-404
lines changed

14 files changed

+695
-404
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`.

docs/pages/getting-started/providers/mailgun.mdx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ AUTH_MAILGUN_KEY=abc
4141

4242
If you name your environment variable `AUTH_MAILGUN_KEY`, the provider will pick it up automatically and your Auth.js configuration object can be simpler. If you'd like to rename it to something else, however, you'll have to manually pass it into the provider in your Auth.js configuration.
4343

44+
3. If you are using the EU Mailgun server, you will need to include `region: "EU"` in the provider options. If you are using the US Mailgun server you can remove this option.
45+
4446
<Code>
4547
<Code.Next>
4648

@@ -53,8 +55,9 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
5355
providers: [
5456
Mailgun({
5557
// If your environment variable is named differently than default
56-
apiKey: import.meta.env.AUTH_MAILGUN_KEY,
57-
58+
apiKey: process.env.AUTH_MAILGUN_KEY,
59+
60+
region: "EU", // Optional
5861
}),
5962
],
6063
})
@@ -74,6 +77,7 @@ export const { onRequest, useSession, useSignIn, useSignOut } = QwikAuth$(
7477
// If your environment variable is named differently than default
7578
apiKey: import.meta.env.AUTH_MAILGUN_KEY,
7679
80+
region: "EU", // Optional
7781
}),
7882
],
7983
})
@@ -95,6 +99,7 @@ export const { handle, signIn, signOut } = SvelteKitAuth({
9599
// If your environment variable is named differently than default
96100
apiKey: env.AUTH_MAILGUN_KEY,
97101
102+
region: "EU", // Optional
98103
}),
99104
],
100105
})

docs/pages/guides/extending-the-session.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ To have access to the user id, add the following to your Auth.js configuration:
3434
```
3535

3636
During sign-in, the `jwt` callback exposes the user's profile information coming from the provider.
37-
You can leverage this to add the user's id to the JWT token. Then, on subsequent calls of this API will have access to the user's id via `token.id`.
37+
You can leverage this to add the user's id to the JWT token. Then, on subsequent calls of this API you will have access to the user's id via `token.id`.
3838
Then, to expose the user's id in the actual session, you can access `token.id` in the `session` callback and save it on `session.user.id`.
3939

4040
Calls to `auth()` or `useSession()` will now have access to the user's id.

packages/adapter-prisma/src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*
1616
* @module @auth/prisma-adapter
1717
*/
18-
import { Prisma, type PrismaClient } from "@prisma/client"
18+
import type { PrismaClient } from "@prisma/client"
1919
import type {
2020
Adapter,
2121
AdapterAccount,
@@ -89,7 +89,9 @@ export function PrismaAdapter(
8989
// If token already used/deleted, just return null
9090
// https://www.prisma.io/docs/reference/api-reference/error-reference#p2025
9191
if (
92-
error instanceof Prisma.PrismaClientKnownRequestError &&
92+
error &&
93+
typeof error === "object" &&
94+
"code" in error &&
9395
error.code === "P2025"
9496
)
9597
return null

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)