surreal-better-auth 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Surreal Adapter for Better Auth
2
+ This adapter allows you to use [SurrealDB](https://surrealist.app/referral?code=4pn5aba943lpbn8l) as a database for your [Better Auth](https://better-auth.com) implementation.
3
+
4
+ ## Feedback
5
+ ⭐ Found this project helpful? Show some love with a star and consider to be a [SPONSOR](https://github.com/sponsors/oskar-gmerek)! Your support keeps the code evolving. 🚀
6
+
7
+ ## Free Database
8
+ ✨✨✨ Grab [FREE SurrealDB Cloud instance + something extra](https://surrealist.app/referral?code=4pn5aba943lpbn8l) ✨✨✨
9
+
10
+ ## » Installation
11
+ ```bash
12
+ bun add surreal-better-auth
13
+ ```
14
+
15
+ ## » Configuration
16
+ ```ts
17
+ import { surrealAdapter } from 'surreal-better-auth'
18
+ import { databaseInstance } from './your-surreal-singleton'
19
+
20
+ ...
21
+ export const auth = betterAuth({
22
+ ...
23
+ database: surrealAdapter(databaseInstance)
24
+ ...
25
+ })
26
+ ```
27
+
28
+ ## ✨ Contributions
29
+ Contributions are welcome! Please open an issue or a pull request if you have any suggestions or improvements.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "surreal-better-auth",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "author": {
5
5
  "name": "Oskar Gmerek",
6
6
  "url": "https://oskargmerek.com",
@@ -26,6 +26,11 @@
26
26
  },
27
27
  "license": "MIT",
28
28
  "main": "src/index.ts",
29
+ "files": [
30
+ "src/index.ts",
31
+ "README.md",
32
+ "LICENSE"
33
+ ],
29
34
  "devDependencies": {
30
35
  "@types/bun": "^1.1.14"
31
36
  },
@@ -1,59 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
-
8
- jobs:
9
- test:
10
- name: Run Tests with SurrealDB
11
- runs-on: ubuntu-latest
12
-
13
- steps:
14
- # Checkout code
15
- - name: Checkout repository
16
- uses: actions/checkout@v4
17
- # Setup SurrealDB
18
- - name: Start SurrealDB
19
- uses: surrealdb/setup-surreal@v2
20
- with:
21
- surrealdb_version: latest
22
- surrealdb_port: 8000
23
- surrealdb_username: root
24
- surrealdb_password: root
25
- surrealdb_auth: false
26
- surrealdb_strict: false
27
- surrealdb_log: info
28
- surrealdb_additional_args: --allow-all
29
- surrealdb_retry_count: 30
30
- # Checkout code
31
- - name: Checkout repository
32
- uses: actions/checkout@v4
33
-
34
- # Setup Bun
35
- - name: Setup Bun
36
- uses: oven-sh/setup-bun@v1
37
-
38
- # Install dependencies
39
- - name: Install dependencies
40
- run: bun install
41
-
42
- # Wait for SurrealDB
43
- - name: Wait for SurrealDB
44
- run: |
45
- echo "Waiting for SurrealDB to become healthy..."
46
- until curl --fail http://localhost:8000/status; do
47
- echo "Waiting for SurrealDB..."
48
- sleep 1
49
- done
50
- echo "SurrealDB is up and running!"
51
-
52
- # Run tests
53
- - name: Run tests
54
- run: bun test
55
-
56
- # Stop SurrealDB and cleanup
57
- - name: Stop SurrealDB
58
- if: always()
59
- run: echo "Cleaning up... SurrealDB service will stop automatically."
@@ -1,79 +0,0 @@
1
- name: Release
2
-
3
- on:
4
- workflow_run:
5
- workflows:
6
- - ci
7
- types:
8
- - completed
9
-
10
- jobs:
11
- release:
12
- name: Create Release
13
- runs-on: ubuntu-latest
14
-
15
- if: ${{ github.event.workflow_run.conclusion == 'success' }}
16
-
17
- steps:
18
- # Checkout code
19
- - name: Checkout repository
20
- uses: actions/checkout@v4
21
-
22
- # Setup Bun
23
- - name: Setup Bun
24
- uses: oven-sh/setup-bun@v1
25
-
26
- # Install dependencies
27
- - name: Install dependencies
28
- run: bun install
29
-
30
- # Check version change
31
- - name: Get current and previous version
32
- id: version
33
- run: |
34
- PREV_VERSION=$(git tag --list --sort=-v:refname 'v*' | head -n 1 | sed 's/v//')
35
- CURR_VERSION=$(node -p "require('./package.json').version")
36
- echo "Previous Version: $PREV_VERSION"
37
- echo "Current Version: $CURR_VERSION"
38
- if [ "$PREV_VERSION" = "$CURR_VERSION" ]; then
39
- echo "Version unchanged. Exiting..."
40
- exit 1
41
- fi
42
- echo "version=$CURR_VERSION" >> $GITHUB_OUTPUT
43
-
44
- # Generate Changelog
45
- - name: Generate Changelog
46
- id: changelog
47
- uses: orhun/git-cliff-action@v2
48
- with:
49
- args: --output CHANGELOG.md
50
- env:
51
- GIT_CLIFF_CONFIG: |
52
- [changelog]
53
- header = "## Changelog"
54
- footer = ""
55
- trim = true
56
-
57
- [commit-types]
58
- feat = "✨ Features"
59
- fix = "🐛 Bug Fixes"
60
- docs = "📝 Documentation"
61
- chore = "📦 Chores"
62
- refactor = "♻️ Refactors"
63
-
64
- # Create GitHub Release
65
- - name: Create GitHub Release
66
- uses: softprops/action-gh-release@v1
67
- with:
68
- tag_name: v${{ steps.version.outputs.version }}
69
- name: Release v${{ steps.version.outputs.version }}
70
- body_path: CHANGELOG.md
71
- token: ${{ secrets.GITHUB_TOKEN }}
72
-
73
- # Publish to npm
74
- - name: Publish to npm
75
- run: |
76
- echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc
77
- bun publish
78
- env:
79
- NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
package/CHANGELOG.md DELETED
@@ -1 +0,0 @@
1
- []
package/db/surreal.ts DELETED
@@ -1,46 +0,0 @@
1
- import Surreal from "surrealdb";
2
-
3
- // Define the database configuration interface
4
- interface DatabaseConfig {
5
- url: string;
6
- namespace: string;
7
- database: string;
8
- auth: {
9
- username: string;
10
- password: string;
11
- };
12
- }
13
-
14
- // Define the default database configuration
15
- const DEFAULT_CONFIG: DatabaseConfig = {
16
- url: "http://127.0.0.1:8000/rpc",
17
- namespace: "better_auth",
18
- database: "better_auth",
19
- auth: {
20
- username: "root",
21
- password: "root",
22
- },
23
- };
24
-
25
- // Define the function to get the database instance
26
- export async function getDatabase(
27
- config: DatabaseConfig = DEFAULT_CONFIG,
28
- ): Promise<Surreal> {
29
- const db = new Surreal();
30
-
31
- try {
32
- await db.connect(config.url, {
33
- namespace: config.namespace,
34
- database: config.database,
35
- auth: { username: config.auth.username, password: config.auth.password },
36
- });
37
- return db;
38
- } catch (err) {
39
- console.error(
40
- "Failed to connect to SurrealDB:",
41
- err instanceof Error ? err.message : String(err),
42
- );
43
- await db.close();
44
- throw err;
45
- }
46
- }
@@ -1,443 +0,0 @@
1
- import { expect, test } from "bun:test";
2
- import { generateId } from "better-auth";
3
- import type { Adapter, BetterAuthOptions, User } from "better-auth/types";
4
-
5
- interface AdapterTestOptions {
6
- getAdapter: (
7
- customOptions?: Omit<BetterAuthOptions, "database">,
8
- ) => Promise<Adapter>;
9
- skipGenerateIdTest?: boolean;
10
- }
11
-
12
- export async function runAdapterTest(opts: AdapterTestOptions) {
13
- const adapter = await opts.getAdapter();
14
- const user = {
15
- id: "1",
16
- name: "user",
17
- email: "user@email.com",
18
- emailVerified: true,
19
- createdAt: new Date(),
20
- updatedAt: new Date(),
21
- };
22
-
23
- test("create model", async () => {
24
- const res = await adapter.create({
25
- model: "user",
26
- data: user,
27
- });
28
-
29
- expect({
30
- name: res.name,
31
- email: res.email,
32
- }).toEqual({
33
- name: user.name,
34
- email: user.email,
35
- });
36
- user.id = res.id;
37
- });
38
-
39
- test("find model", async () => {
40
- const res = await adapter.findOne<User>({
41
- model: "user",
42
- where: [
43
- {
44
- field: "id",
45
- value: user.id,
46
- },
47
- ],
48
- });
49
- expect({
50
- name: res?.name,
51
- email: res?.email,
52
- }).toEqual({
53
- name: user.name,
54
- email: user.email,
55
- });
56
- });
57
-
58
- test("find model without id", async () => {
59
- const res = await adapter.findOne<User>({
60
- model: "user",
61
- where: [
62
- {
63
- field: "email",
64
- value: user.email,
65
- },
66
- ],
67
- });
68
- expect({
69
- name: res?.name,
70
- email: res?.email,
71
- }).toEqual({
72
- name: user.name,
73
- email: user.email,
74
- });
75
- });
76
-
77
- test("find model with select", async () => {
78
- const res = await adapter.findOne({
79
- model: "user",
80
- where: [
81
- {
82
- field: "id",
83
- value: user.id,
84
- },
85
- ],
86
- select: ["email"],
87
- });
88
- expect(res).toEqual({ email: user.email });
89
- });
90
-
91
- test("update model", async () => {
92
- const newEmail = "updated@email.com";
93
-
94
- const res = await adapter.update<User>({
95
- model: "user",
96
- where: [
97
- {
98
- field: "id",
99
- value: user.id,
100
- },
101
- ],
102
- update: {
103
- email: newEmail,
104
- },
105
- });
106
- expect(res).toMatchObject({
107
- email: newEmail,
108
- name: user.name,
109
- });
110
- });
111
-
112
- test("should find many", async () => {
113
- const res = await adapter.findMany({
114
- model: "user",
115
- });
116
- expect(res.length).toBe(1);
117
- });
118
-
119
- test("should find many with where", async () => {
120
- const user = await adapter.create<User>({
121
- model: "user",
122
- data: {
123
- id: "2",
124
- name: "user2",
125
- email: "test@email.com",
126
- emailVerified: true,
127
- createdAt: new Date(),
128
- updatedAt: new Date(),
129
- },
130
- });
131
- const res = await adapter.findMany({
132
- model: "user",
133
- where: [
134
- {
135
- field: "id",
136
- value: user.id,
137
- },
138
- ],
139
- });
140
- expect(res.length).toBe(1);
141
- });
142
-
143
- test("should find many with operators", async () => {
144
- const newUser = await adapter.create<User>({
145
- model: "user",
146
- data: {
147
- id: "3",
148
- name: "user",
149
- email: "test-email2@email.com",
150
- emailVerified: true,
151
- createdAt: new Date(),
152
- updatedAt: new Date(),
153
- },
154
- });
155
- const res = await adapter.findMany({
156
- model: "user",
157
- where: [
158
- {
159
- field: "id",
160
- operator: "in",
161
- value: [user.id, newUser.id],
162
- },
163
- ],
164
- });
165
- expect(res.length).toBe(2);
166
- });
167
-
168
- test("should work with reference fields", async () => {
169
- const user = await adapter.create<{ id: string } & Record<string, any>>({
170
- model: "user",
171
- data: {
172
- id: "4",
173
- name: "user",
174
- email: "my-email@email.com",
175
- emailVerified: true,
176
- createdAt: new Date(),
177
- updatedAt: new Date(),
178
- },
179
- });
180
- await adapter.create({
181
- model: "session",
182
- data: {
183
- id: "1",
184
- token: generateId(),
185
- createdAt: new Date(),
186
- updatedAt: new Date(),
187
- userId: user.id,
188
- expiresAt: new Date(),
189
- },
190
- });
191
- const res = await adapter.findOne({
192
- model: "session",
193
- where: [
194
- {
195
- field: "userId",
196
- value: user.id,
197
- },
198
- ],
199
- });
200
- expect(res).toMatchObject({
201
- userId: user.id,
202
- });
203
- });
204
-
205
- test("should find many with sortBy", async () => {
206
- await adapter.create({
207
- model: "user",
208
- data: {
209
- id: "5",
210
- name: "a",
211
- email: "a@email.com",
212
- emailVerified: true,
213
- createdAt: new Date(),
214
- updatedAt: new Date(),
215
- },
216
- });
217
- const res = await adapter.findMany<User>({
218
- model: "user",
219
- sortBy: {
220
- field: "name",
221
- direction: "asc",
222
- },
223
- });
224
- expect(res[0].name).toBe("a");
225
-
226
- const res2 = await adapter.findMany<User>({
227
- model: "user",
228
- sortBy: {
229
- field: "name",
230
- direction: "desc",
231
- },
232
- });
233
-
234
- expect(res2[res2.length - 1].name).toBe("a");
235
- });
236
-
237
- test("should find many with limit", async () => {
238
- const res = await adapter.findMany({
239
- model: "user",
240
- limit: 1,
241
- });
242
- expect(res.length).toBe(1);
243
- });
244
-
245
- test("should find many with offset", async () => {
246
- const res = await adapter.findMany({
247
- model: "user",
248
- offset: 2,
249
- });
250
- expect(res.length).toBe(3);
251
- });
252
-
253
- test("should update with multiple where", async () => {
254
- await adapter.updateMany({
255
- model: "user",
256
- where: [
257
- {
258
- field: "name",
259
- value: user.name,
260
- },
261
- {
262
- field: "email",
263
- value: user.email,
264
- },
265
- ],
266
- update: {
267
- email: "updated@email.com",
268
- },
269
- });
270
- const updatedUser = await adapter.findOne<User>({
271
- model: "user",
272
- where: [
273
- {
274
- field: "email",
275
- value: "updated@email.com",
276
- },
277
- ],
278
- });
279
- expect(updatedUser).toMatchObject({
280
- name: user.name,
281
- email: "updated@email.com",
282
- });
283
- });
284
-
285
- test("delete model", async () => {
286
- await adapter.delete({
287
- model: "user",
288
- where: [
289
- {
290
- field: "id",
291
- value: user.id,
292
- },
293
- ],
294
- });
295
- const findRes = await adapter.findOne({
296
- model: "user",
297
- where: [
298
- {
299
- field: "id",
300
- value: user.id,
301
- },
302
- ],
303
- });
304
- expect(findRes).toBeNull();
305
- });
306
-
307
- test("should delete many", async () => {
308
- for (const id of ["to-be-delete1", "to-be-delete2", "to-be-delete3"]) {
309
- await adapter.create({
310
- model: "user",
311
- data: {
312
- id,
313
- name: "to-be-deleted",
314
- email: `email@test-${id}.com`,
315
- emailVerified: true,
316
- createdAt: new Date(),
317
- updatedAt: new Date(),
318
- },
319
- });
320
- }
321
- const findResFirst = await adapter.findMany({
322
- model: "user",
323
- where: [
324
- {
325
- field: "name",
326
- value: "to-be-deleted",
327
- },
328
- ],
329
- });
330
- expect(findResFirst.length).toBe(3);
331
- await adapter.deleteMany({
332
- model: "user",
333
- where: [
334
- {
335
- field: "name",
336
- value: "to-be-deleted",
337
- },
338
- ],
339
- });
340
- const findRes = await adapter.findMany({
341
- model: "user",
342
- where: [
343
- {
344
- field: "name",
345
- value: "to-be-deleted",
346
- },
347
- ],
348
- });
349
- expect(findRes.length).toBe(0);
350
- });
351
-
352
- test("shouldn't throw on delete record not found", async () => {
353
- await adapter.delete({
354
- model: "user",
355
- where: [
356
- {
357
- field: "id",
358
- value: "5",
359
- },
360
- ],
361
- });
362
- });
363
-
364
- test("shouldn't throw on record not found", async () => {
365
- const res = await adapter.findOne({
366
- model: "user",
367
- where: [
368
- {
369
- field: "id",
370
- value: "5",
371
- },
372
- ],
373
- });
374
- expect(res).toBeNull();
375
- });
376
-
377
- test("should find many with contains operator", async () => {
378
- const res = await adapter.findMany({
379
- model: "user",
380
- where: [
381
- {
382
- field: "name",
383
- operator: "contains",
384
- value: "user2",
385
- },
386
- ],
387
- });
388
- expect(res.length).toBe(1);
389
- });
390
-
391
- test("should search users with startsWith", async () => {
392
- const res = await adapter.findMany({
393
- model: "user",
394
- where: [
395
- {
396
- field: "name",
397
- operator: "starts_with",
398
- value: "us",
399
- },
400
- ],
401
- });
402
- expect(res.length).toBe(3);
403
- });
404
-
405
- test("should search users with endsWith", async () => {
406
- const res = await adapter.findMany({
407
- model: "user",
408
- where: [
409
- {
410
- field: "name",
411
- operator: "ends_with",
412
- value: "er2",
413
- },
414
- ],
415
- });
416
- expect(res.length).toBe(1);
417
- });
418
-
419
- test.skipIf(opts.skipGenerateIdTest || false)(
420
- "should prefer generateId if provided",
421
- async () => {
422
- const customAdapter = await opts.getAdapter({
423
- advanced: {
424
- generateId: () => "mocked-id",
425
- },
426
- });
427
-
428
- const res = await customAdapter.create({
429
- model: "user",
430
- data: {
431
- id: "1",
432
- name: "user4",
433
- email: "user4@email.com",
434
- emailVerified: true,
435
- createdAt: new Date(),
436
- updatedAt: new Date(),
437
- },
438
- });
439
-
440
- expect(res.id).toBe("mocked-id");
441
- },
442
- );
443
- }
@@ -1,94 +0,0 @@
1
- import { beforeAll, describe, expect, it } from "bun:test";
2
- import { surrealAdapter } from "../src";
3
- import { getDatabase } from "../db/surreal";
4
- import { runAdapterTest } from "./runAdapterTest";
5
- import { getTestInstance } from "./testInstance";
6
-
7
- describe("adapter test", async () => {
8
- const db = await getDatabase();
9
-
10
- async function setupDB() {
11
- await db.query(
12
- `
13
- DEFINE NAMESPACE IF NOT EXISTS better_auth;
14
- DEFINE DATABASE IF NOT EXISTS better_auth;
15
- DELETE user;
16
- DELETE session
17
- `,
18
- );
19
- }
20
-
21
- beforeAll(async () => {
22
- await setupDB();
23
- });
24
-
25
- const adapter = surrealAdapter(db);
26
- await runAdapterTest({
27
- getAdapter: async (customOptions = {}) => {
28
- return adapter({
29
- user: {
30
- fields: {
31
- email: "email_address",
32
- },
33
- additionalFields: {
34
- test: {
35
- type: "string",
36
- defaultValue: "test",
37
- },
38
- },
39
- },
40
- session: {
41
- modelName: "sessions",
42
- },
43
- ...customOptions,
44
- });
45
- },
46
- skipGenerateIdTest: true,
47
- });
48
- });
49
-
50
- describe("simple-flow", async () => {
51
- const { auth, client, sessionSetter } = await getTestInstance(
52
- {},
53
- {
54
- disableTestUser: true,
55
- testWith: "surreal",
56
- },
57
- );
58
- const testUser = {
59
- email: "test-eamil@email.com",
60
- password: "password",
61
- name: "Test Name",
62
- };
63
-
64
- it("should sign up", async () => {
65
- const user = await auth.api.signUpEmail({
66
- body: testUser,
67
- });
68
- expect(user).toBeDefined();
69
- });
70
-
71
- it("should sign in", async () => {
72
- const user = await auth.api.signInEmail({
73
- body: testUser,
74
- });
75
- expect(user).toBeDefined();
76
- });
77
-
78
- it("should get session", async () => {
79
- const headers = new Headers();
80
- await client.signIn.email(
81
- {
82
- email: testUser.email,
83
- password: testUser.password,
84
- },
85
- {
86
- onSuccess: sessionSetter(headers),
87
- },
88
- );
89
- const { data: session } = await client.getSession({
90
- fetchOptions: { headers },
91
- });
92
- expect(session?.user).toBeDefined();
93
- });
94
- });
@@ -1,222 +0,0 @@
1
- import { afterAll } from "bun:test";
2
- import type { SuccessContext } from "@better-fetch/fetch";
3
- import { betterAuth } from "better-auth";
4
- import { createAuthClient } from "better-auth/client";
5
- import { parseSetCookieHeader } from "better-auth/cookies";
6
- import { getAdapter } from "better-auth/db";
7
- import type {
8
- BetterAuthOptions,
9
- ClientOptions,
10
- Session,
11
- User,
12
- } from "better-auth/types";
13
-
14
- import { getBaseURL } from "../utlis/getBaseURL";
15
-
16
- import { surrealAdapter } from "..";
17
- import { getDatabase } from "../db/surreal";
18
-
19
- export async function getTestInstance<
20
- O extends Partial<BetterAuthOptions>,
21
- C extends ClientOptions,
22
- >(
23
- options?: O,
24
- config?: {
25
- clientOptions?: C;
26
- port?: number;
27
- disableTestUser?: boolean;
28
- testUser?: Partial<User>;
29
- testWith?: "surreal";
30
- },
31
- ) {
32
- const db = await getDatabase({
33
- url: "http://127.0.0.1:8000/rpc",
34
- namespace: "better_auth_test",
35
- database: "better_auth_test",
36
- auth: { username: "root", password: "root" },
37
- });
38
-
39
- const opts = {
40
- socialProviders: {
41
- github: {
42
- clientId: "test",
43
- clientSecret: "test",
44
- },
45
- google: {
46
- clientId: "test",
47
- clientSecret: "test",
48
- },
49
- },
50
- secret: "better-auth.secret",
51
- database: surrealAdapter(db),
52
- emailAndPassword: {
53
- enabled: true,
54
- },
55
- rateLimit: {
56
- enabled: false,
57
- },
58
- advanced: {
59
- cookies: {},
60
- },
61
- } satisfies BetterAuthOptions;
62
-
63
- const auth = betterAuth({
64
- baseURL: `http://localhost:${config?.port || 3000}`,
65
- ...opts,
66
- ...options,
67
- advanced: {
68
- disableCSRFCheck: true,
69
- ...options?.advanced,
70
- },
71
- } as O extends undefined ? typeof opts : O & typeof opts);
72
-
73
- const testUser = {
74
- email: "test@test.com",
75
- password: "test123456",
76
- name: "test user",
77
- ...config?.testUser,
78
- };
79
- async function createTestUser() {
80
- if (config?.disableTestUser) {
81
- return;
82
- }
83
- //@ts-expect-error
84
- await auth.api.signUpEmail({
85
- body: testUser,
86
- });
87
- }
88
-
89
- await createTestUser();
90
-
91
- afterAll(async () => {
92
- await db.query("DELETE account; DELETE session; DELETE user;");
93
- return;
94
- });
95
-
96
- async function signInWithTestUser() {
97
- if (config?.disableTestUser) {
98
- throw new Error("Test user is disabled");
99
- }
100
- const headers = new Headers();
101
- const setCookie = (name: string, value: string) => {
102
- const current = headers.get("cookie");
103
- headers.set("cookie", `${current || ""}; ${name}=${value}`);
104
- };
105
- //@ts-expect-error
106
- const { data } = await client.signIn.email({
107
- email: testUser.email,
108
- password: testUser.password,
109
-
110
- fetchOptions: {
111
- // @ts-expect-error
112
- onSuccess(context) {
113
- const header = context.response.headers.get("set-cookie");
114
- const cookies = parseSetCookieHeader(header || "");
115
- const signedCookie = cookies.get("better-auth.session_token")?.value;
116
- headers.set("cookie", `better-auth.session_token=${signedCookie}`);
117
- },
118
- },
119
- });
120
- return {
121
- session: data.session as Session,
122
- user: data.user as User,
123
- headers,
124
- setCookie,
125
- };
126
- }
127
- async function signInWithUser(email: string, password: string) {
128
- const headers = new Headers();
129
- //@ts-expect-error
130
- const { data } = await client.signIn.email({
131
- email,
132
- password,
133
- fetchOptions: {
134
- //@ts-expect-error
135
- onSuccess(context) {
136
- const header = context.response.headers.get("set-cookie");
137
- const cookies = parseSetCookieHeader(header || "");
138
- const signedCookie = cookies.get("better-auth.session_token")?.value;
139
- headers.set("cookie", `better-auth.session_token=${signedCookie}`);
140
- },
141
- },
142
- });
143
- return {
144
- res: data as {
145
- user: User;
146
- session: Session;
147
- },
148
- headers,
149
- };
150
- }
151
-
152
- const customFetchImpl = async (
153
- url: string | URL | Request,
154
- init?: RequestInit,
155
- ) => {
156
- const req = new Request(url.toString(), init);
157
- return auth.handler(req);
158
- };
159
-
160
- function sessionSetter(headers: Headers) {
161
- return (context: SuccessContext) => {
162
- const header = context.response.headers.get("set-cookie");
163
- if (header) {
164
- const cookies = parseSetCookieHeader(header || "");
165
- const signedCookie = cookies.get("better-auth.session_token")?.value;
166
- headers.set("cookie", `better-auth.session_token=${signedCookie}`);
167
- }
168
- };
169
- }
170
- function cookieSetter(headers: Headers) {
171
- return (context: { response: Response }) => {
172
- const setCookieHeader = context.response.headers.get("set-cookie");
173
- if (!setCookieHeader) {
174
- return;
175
- }
176
-
177
- const cookieMap = new Map<string, string>();
178
-
179
- const existingCookiesHeader = headers.get("cookie") || "";
180
- existingCookiesHeader.split(";").forEach((cookie) => {
181
- const [name, ...rest] = cookie.trim().split("=");
182
- if (name && rest.length > 0) {
183
- cookieMap.set(name, rest.join("="));
184
- }
185
- });
186
-
187
- const setCookieHeaders = setCookieHeader.split(",");
188
- setCookieHeaders.forEach((header) => {
189
- const cookies = parseSetCookieHeader(header);
190
- cookies.forEach((value, name) => {
191
- cookieMap.set(name, value.value);
192
- });
193
- });
194
-
195
- const updatedCookies = Array.from(cookieMap.entries())
196
- .map(([name, value]) => `${name}=${value}`)
197
- .join("; ");
198
- headers.set("cookie", updatedCookies);
199
- };
200
- }
201
- const client = createAuthClient({
202
- ...(config?.clientOptions as C extends undefined ? {} : C),
203
- baseURL: getBaseURL(
204
- options?.baseURL || "http://localhost:" + (config?.port || 3000),
205
- options?.basePath || "/api/auth",
206
- ),
207
- fetchOptions: {
208
- customFetchImpl,
209
- },
210
- });
211
- return {
212
- auth,
213
- client,
214
- testUser,
215
- signInWithTestUser,
216
- signInWithUser,
217
- cookieSetter,
218
- customFetchImpl,
219
- sessionSetter,
220
- db: await getAdapter(auth.options),
221
- };
222
- }
package/tsconfig.json DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2021",
4
- "module": "ES2022",
5
- "moduleResolution": "node",
6
- "esModuleInterop": true,
7
- "forceConsistentCasingInFileNames": true,
8
- "strict": true,
9
- "skipLibCheck": true
10
- }
11
- }
@@ -1,32 +0,0 @@
1
- import { BetterAuthError } from "better-auth";
2
-
3
- function checkHasPath(url: string): boolean {
4
- try {
5
- const parsedUrl = new URL(url);
6
- return parsedUrl.pathname !== "/";
7
- } catch (error) {
8
- throw new BetterAuthError(
9
- `Invalid base URL: ${url}. Please provide a valid base URL.`,
10
- );
11
- }
12
- }
13
-
14
- function withPath(url: string, path = "/api/auth") {
15
- const hasPath = checkHasPath(url);
16
- if (hasPath) {
17
- return url;
18
- }
19
- path = path.startsWith("/") ? path : `/${path}`;
20
- return `${url}${path}`;
21
- }
22
-
23
- export function getBaseURL(url?: string, path?: string) {
24
- if (url) {
25
- return withPath(url, path);
26
- }
27
-
28
- if (typeof window !== "undefined" && window.location) {
29
- return withPath(window.location.origin, path);
30
- }
31
- return undefined;
32
- }