@convex-dev/better-auth 0.11.3 → 0.11.5
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/dist/client/create-client.d.ts.map +1 -1
- package/dist/client/create-client.js +19 -2
- package/dist/client/create-client.js.map +1 -1
- package/dist/component/_generated/component.d.ts +0 -1
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/_generated/server.d.ts.map +1 -1
- package/dist/component/adapterTest.d.ts +0 -1
- package/dist/component/adapterTest.d.ts.map +1 -1
- package/dist/component/adapterTest.js +11 -21
- package/dist/component/adapterTest.js.map +1 -1
- package/dist/nextjs/index.d.ts.map +1 -1
- package/dist/nextjs/index.js +4 -0
- package/dist/nextjs/index.js.map +1 -1
- package/dist/plugins/convex/index.d.ts +1 -1
- package/dist/plugins/convex/index.d.ts.map +1 -1
- package/dist/plugins/cross-domain/index.d.ts.map +1 -1
- package/dist/react-start/index.d.ts.map +1 -1
- package/dist/react-start/index.js +4 -0
- package/dist/react-start/index.js.map +1 -1
- package/dist/test/adapter-factory/auth-flow.d.ts +1 -21
- package/dist/test/adapter-factory/auth-flow.d.ts.map +1 -1
- package/dist/test/adapter-factory/auth-flow.js +32 -37
- package/dist/test/adapter-factory/auth-flow.js.map +1 -1
- package/dist/test/adapter-factory/basic.d.ts +11 -34
- package/dist/test/adapter-factory/basic.d.ts.map +1 -1
- package/dist/test/adapter-factory/basic.js +54 -2626
- package/dist/test/adapter-factory/basic.js.map +1 -1
- package/dist/test/adapter-factory/index.d.ts +0 -6
- package/dist/test/adapter-factory/index.d.ts.map +1 -1
- package/dist/test/adapter-factory/index.js +0 -6
- package/dist/test/adapter-factory/index.js.map +1 -1
- package/dist/test/adapter-factory/profile-additional-fields.d.ts.map +1 -1
- package/dist/test/adapter-factory/profile-additional-fields.js +14 -1
- package/dist/test/adapter-factory/profile-additional-fields.js.map +1 -1
- package/dist/test/adapter-factory/profile-plugin-table.d.ts.map +1 -1
- package/dist/test/adapter-factory/profile-plugin-table.js +8 -1
- package/dist/test/adapter-factory/profile-plugin-table.js.map +1 -1
- package/dist/test/adapter-factory/profile-rename-joins.d.ts +3 -3
- package/dist/test/adapter-factory/profile-rename-joins.d.ts.map +1 -1
- package/dist/test/adapter-factory/profile-rename-joins.js +11 -10
- package/dist/test/adapter-factory/profile-rename-joins.js.map +1 -1
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +14 -20
- package/src/client/adapter.test.ts +20 -5
- package/src/client/create-client.test.ts +40 -0
- package/src/client/create-client.ts +25 -2
- package/src/component/_generated/component.ts +0 -1
- package/src/component/_generated/server.ts +0 -5
- package/src/component/adapterTest.ts +12 -26
- package/src/nextjs/index.ts +4 -0
- package/src/react-start/index.ts +4 -0
- package/src/test/adapter-factory/auth-flow.ts +146 -160
- package/src/test/adapter-factory/basic.ts +185 -3187
- package/src/test/adapter-factory/index.ts +0 -6
- package/src/test/adapter-factory/profile-additional-fields.ts +75 -57
- package/src/test/adapter-factory/profile-plugin-table.ts +10 -2
- package/src/test/adapter-factory/profile-rename-joins.ts +13 -11
- package/src/utils/index.ts +2 -1
- package/dist/test/adapter-factory/joins.d.ts +0 -18
- package/dist/test/adapter-factory/joins.d.ts.map +0 -1
- package/dist/test/adapter-factory/joins.js +0 -22
- package/dist/test/adapter-factory/joins.js.map +0 -1
- package/dist/test/adapter-factory/number-id.d.ts +0 -18
- package/dist/test/adapter-factory/number-id.d.ts.map +0 -1
- package/dist/test/adapter-factory/number-id.js +0 -36
- package/dist/test/adapter-factory/number-id.js.map +0 -1
- package/dist/test/adapter-factory/transactions.d.ts +0 -21
- package/dist/test/adapter-factory/transactions.d.ts.map +0 -1
- package/dist/test/adapter-factory/transactions.js +0 -28
- package/dist/test/adapter-factory/transactions.js.map +0 -1
- package/dist/test/adapter-factory/uuid.d.ts +0 -18
- package/dist/test/adapter-factory/uuid.d.ts.map +0 -1
- package/dist/test/adapter-factory/uuid.js +0 -58
- package/dist/test/adapter-factory/uuid.js.map +0 -1
- package/src/test/adapter-factory/joins.ts +0 -28
- package/src/test/adapter-factory/number-id.ts +0 -45
- package/src/test/adapter-factory/transactions.ts +0 -38
- package/src/test/adapter-factory/uuid.ts +0 -67
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
/// <reference types="vite/client" />
|
|
2
2
|
|
|
3
|
-
import { describe } from "vitest";
|
|
3
|
+
import { describe, it } from "vitest";
|
|
4
4
|
import { convexTest } from "convex-test";
|
|
5
5
|
import { api } from "../component/_generated/api.js";
|
|
6
6
|
import schema from "../component/testProfiles/schema.profile-plugin-table.js";
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
const MIN_NODE_MAJOR = 24;
|
|
9
|
+
const currentNodeMajor = Number.parseInt(
|
|
10
|
+
process.versions.node.split(".")[0] ?? "0",
|
|
11
|
+
10
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
if (currentNodeMajor < MIN_NODE_MAJOR) {
|
|
15
|
+
describe("Better Auth Adapter Tests", () => {
|
|
16
|
+
it.skip(
|
|
17
|
+
`requires Node ${MIN_NODE_MAJOR}+ (adapter test-utils uses explicit resource management syntax)`,
|
|
18
|
+
() => {}
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
} else {
|
|
22
|
+
describe("Better Auth Adapter Tests", async () => {
|
|
23
|
+
const t = convexTest(schema, import.meta.glob("../component/**/*.*s"));
|
|
24
|
+
await t.action(api.adapterTest.runTests, {});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -109,6 +109,46 @@ describe("createClient route registration", () => {
|
|
|
109
109
|
expect(createAuth).toHaveBeenCalledTimes(2);
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
+
it("restores preserved forwarded host headers before calling auth.handler", async () => {
|
|
113
|
+
const client = createClient(component);
|
|
114
|
+
const http = httpRouter();
|
|
115
|
+
const handler = vi.fn(async (_request: Request) => new Response("ok"));
|
|
116
|
+
const createAuth = vi.fn(() => ({
|
|
117
|
+
handler,
|
|
118
|
+
options: {
|
|
119
|
+
trustedOrigins: ["https://app.example.com"],
|
|
120
|
+
},
|
|
121
|
+
$context: Promise.resolve({
|
|
122
|
+
options: {
|
|
123
|
+
trustedOrigins: ["https://app.example.com"],
|
|
124
|
+
},
|
|
125
|
+
}),
|
|
126
|
+
}));
|
|
127
|
+
|
|
128
|
+
client.registerRoutes(http, createAuth);
|
|
129
|
+
|
|
130
|
+
const getHandler = getRouteHandler(http, "/api/auth/test", "GET");
|
|
131
|
+
expect(getHandler).toBeTruthy();
|
|
132
|
+
await getHandler!._handler(
|
|
133
|
+
{},
|
|
134
|
+
new Request("https://adjective-animal-123.convex.site/api/auth/test", {
|
|
135
|
+
method: "GET",
|
|
136
|
+
headers: {
|
|
137
|
+
host: "deployment.convex.site",
|
|
138
|
+
"x-forwarded-host": "deployment.convex.site",
|
|
139
|
+
"x-forwarded-proto": "https",
|
|
140
|
+
"x-better-auth-forwarded-host": "app.example.com",
|
|
141
|
+
"x-better-auth-forwarded-proto": "https",
|
|
142
|
+
},
|
|
143
|
+
})
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
const forwardedRequest = handler.mock.calls[0]?.[0];
|
|
147
|
+
expect(forwardedRequest).toBeInstanceOf(Request);
|
|
148
|
+
expect(forwardedRequest.headers.get("x-forwarded-host")).toBe("app.example.com");
|
|
149
|
+
expect(forwardedRequest.headers.get("x-forwarded-proto")).toBe("https");
|
|
150
|
+
});
|
|
151
|
+
|
|
112
152
|
it("registerRoutesLazy resolves trustedOrigins lazily when needed", async () => {
|
|
113
153
|
const client = createClient(component);
|
|
114
154
|
const http = httpRouter();
|
|
@@ -87,6 +87,27 @@ type RegisterRoutesLazyOptions = {
|
|
|
87
87
|
cors?: RouteCorsOptions;
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
+
const restoreOriginalForwardedHeaders = (request: Request) => {
|
|
91
|
+
const originalHost = request.headers.get("x-better-auth-forwarded-host");
|
|
92
|
+
const originalProto = request.headers.get("x-better-auth-forwarded-proto");
|
|
93
|
+
|
|
94
|
+
if (!originalHost && !originalProto) {
|
|
95
|
+
return request;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const headers = new Headers(request.headers);
|
|
99
|
+
|
|
100
|
+
if (originalHost) {
|
|
101
|
+
headers.set("x-forwarded-host", originalHost);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (originalProto) {
|
|
105
|
+
headers.set("x-forwarded-proto", originalProto);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return new Request(request, { headers });
|
|
109
|
+
};
|
|
110
|
+
|
|
90
111
|
/**
|
|
91
112
|
* Backend API for the Better Auth component.
|
|
92
113
|
* Responsible for exposing the `client` and `triggers` APIs to the client, http
|
|
@@ -375,7 +396,8 @@ export const createClient = <
|
|
|
375
396
|
console.log("request headers", request.headers);
|
|
376
397
|
}
|
|
377
398
|
const auth = createAuth(ctx as any);
|
|
378
|
-
const
|
|
399
|
+
const normalizedRequest = restoreOriginalForwardedHeaders(request);
|
|
400
|
+
const response = await auth.handler(normalizedRequest);
|
|
379
401
|
if (config?.verbose) {
|
|
380
402
|
// eslint-disable-next-line no-console
|
|
381
403
|
console.log("response headers", response.headers);
|
|
@@ -494,7 +516,8 @@ export const createClient = <
|
|
|
494
516
|
console.log("request headers", request.headers);
|
|
495
517
|
}
|
|
496
518
|
const auth = createAuth(ctx as any);
|
|
497
|
-
const
|
|
519
|
+
const normalizedRequest = restoreOriginalForwardedHeaders(request);
|
|
520
|
+
const response = await auth.handler(normalizedRequest);
|
|
498
521
|
if (config?.verbose) {
|
|
499
522
|
// eslint-disable-next-line no-console
|
|
500
523
|
console.log("response headers", response.headers);
|
|
@@ -1825,7 +1825,6 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
|
|
|
1825
1825
|
>;
|
|
1826
1826
|
};
|
|
1827
1827
|
adapterTest: {
|
|
1828
|
-
runCustomTests: FunctionReference<"action", "internal", any, any, Name>;
|
|
1829
1828
|
runTests: FunctionReference<"action", "internal", any, any, Name>;
|
|
1830
1829
|
};
|
|
1831
1830
|
testProfiles: {
|
|
@@ -107,11 +107,6 @@ export const internalAction: ActionBuilder<DataModel, "internal"> =
|
|
|
107
107
|
*/
|
|
108
108
|
export const httpAction: HttpActionBuilder = httpActionGeneric;
|
|
109
109
|
|
|
110
|
-
type GenericCtx =
|
|
111
|
-
| GenericActionCtx<DataModel>
|
|
112
|
-
| GenericMutationCtx<DataModel>
|
|
113
|
-
| GenericQueryCtx<DataModel>;
|
|
114
|
-
|
|
115
110
|
/**
|
|
116
111
|
* A set of services for use within Convex query functions.
|
|
117
112
|
*
|
|
@@ -13,11 +13,18 @@ import type { ComponentApi } from "./_generated/component.js";
|
|
|
13
13
|
// globals are available through dynamic imports.
|
|
14
14
|
|
|
15
15
|
const NORMAL_DISABLED_TESTS = [
|
|
16
|
+
// dynamic-schema-plugin-table/dynamic-schema-additional-fields:
|
|
17
|
+
// Convex validators are static in this harness, so runtime schema mutation
|
|
18
|
+
// tests are validated in dedicated profiles instead.
|
|
16
19
|
"create - should apply default values to fields",
|
|
17
20
|
"create - should return null for nullable foreign keys",
|
|
18
21
|
"create - should support arrays",
|
|
19
22
|
"create - should support json",
|
|
23
|
+
// convex-id-generation:
|
|
24
|
+
// Convex controls generated IDs at write time.
|
|
20
25
|
"create - should use generateId if provided",
|
|
26
|
+
// offset-unsupported:
|
|
27
|
+
// Convex adapter rejects offset pagination.
|
|
21
28
|
"findMany - should be able to perform a complex limited join",
|
|
22
29
|
"findMany - should find many models with limit and offset",
|
|
23
30
|
"findMany - should find many models with offset",
|
|
@@ -32,6 +39,8 @@ const NORMAL_DISABLED_TESTS = [
|
|
|
32
39
|
"findMany - should return empty array when base records don't exist with joins",
|
|
33
40
|
"findMany - should return null for one-to-one join when joined records don't exist",
|
|
34
41
|
"findMany - should select fields with one-to-one join",
|
|
42
|
+
// profile-specific coverage:
|
|
43
|
+
// These are intentionally exercised in dedicated profile suites.
|
|
35
44
|
"findOne - backwards join with modified field name (session base, users-table join)",
|
|
36
45
|
"findOne - multiple joins should return result even when some joined tables have no matching rows",
|
|
37
46
|
"findOne - should find a model with modified field name",
|
|
@@ -102,7 +111,9 @@ const organizationJoinsProfileApi = profileApi("adapterOrganizationJoins");
|
|
|
102
111
|
export const runTests = action(
|
|
103
112
|
async (ctx: GenericActionCtx<DataModel>, _args: EmptyObject) => {
|
|
104
113
|
const testUtilsImport = "@better-auth/test-utils/adapter";
|
|
105
|
-
const { testAdapter } = await import(
|
|
114
|
+
const { testAdapter, transactionsTestSuite, uuidTestSuite } = await import(
|
|
115
|
+
testUtilsImport
|
|
116
|
+
);
|
|
106
117
|
const adapterFactoryImport = "../test/adapter-factory/index.js";
|
|
107
118
|
const {
|
|
108
119
|
coreNormalTestSuite,
|
|
@@ -114,8 +125,6 @@ export const runTests = action(
|
|
|
114
125
|
renameModelUserCustomTestSuite,
|
|
115
126
|
renameModelUserTableTestSuite,
|
|
116
127
|
multiJoinsMissingRowsTestSuite,
|
|
117
|
-
transactionsTestSuite,
|
|
118
|
-
uuidTestSuite,
|
|
119
128
|
convexCustomTestSuite,
|
|
120
129
|
} = await import(adapterFactoryImport);
|
|
121
130
|
|
|
@@ -264,26 +273,3 @@ export const runTests = action(
|
|
|
264
273
|
await executeOrganizationJoinsProfile();
|
|
265
274
|
}
|
|
266
275
|
);
|
|
267
|
-
|
|
268
|
-
// Keep this export during migration to avoid breaking generated component types.
|
|
269
|
-
export const runCustomTests = action(
|
|
270
|
-
async (ctx: GenericActionCtx<DataModel>, _args: EmptyObject) => {
|
|
271
|
-
const testUtilsImport = "@better-auth/test-utils/adapter";
|
|
272
|
-
const { testAdapter } = await import(testUtilsImport);
|
|
273
|
-
const adapterFactoryImport = "../test/adapter-factory/index.js";
|
|
274
|
-
const { convexCustomTestSuite } = await import(adapterFactoryImport);
|
|
275
|
-
const authComponent = createClient<DataModel>(baseProfileApi, {
|
|
276
|
-
verbose: false,
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
const { execute } = await testAdapter({
|
|
280
|
-
adapter: () => {
|
|
281
|
-
return authComponent.adapter(ctx);
|
|
282
|
-
},
|
|
283
|
-
runMigrations: () => {},
|
|
284
|
-
overrideBetterAuthOptions: getOverrideBetterAuthOptions,
|
|
285
|
-
tests: [convexCustomTestSuite()],
|
|
286
|
-
});
|
|
287
|
-
await execute();
|
|
288
|
-
}
|
|
289
|
-
);
|
package/src/nextjs/index.ts
CHANGED
|
@@ -46,6 +46,10 @@ const handler = (request: Request, siteUrl: string) => {
|
|
|
46
46
|
const newRequest = new Request(nextUrl, request);
|
|
47
47
|
newRequest.headers.set("accept-encoding", "application/json");
|
|
48
48
|
newRequest.headers.set("host", new URL(siteUrl).host);
|
|
49
|
+
newRequest.headers.set("x-forwarded-host", requestUrl.host);
|
|
50
|
+
newRequest.headers.set("x-forwarded-proto", requestUrl.protocol.replace(/:$/, ""));
|
|
51
|
+
newRequest.headers.set("x-better-auth-forwarded-host", requestUrl.host);
|
|
52
|
+
newRequest.headers.set("x-better-auth-forwarded-proto", requestUrl.protocol.replace(/:$/, ""));
|
|
49
53
|
return fetch(newRequest, { method: request.method, redirect: "manual" });
|
|
50
54
|
};
|
|
51
55
|
|
package/src/react-start/index.ts
CHANGED
|
@@ -65,6 +65,10 @@ const handler = (request: Request, opts: { convexSiteUrl: string }) => {
|
|
|
65
65
|
const headers = new Headers(request.headers);
|
|
66
66
|
headers.set("accept-encoding", "application/json");
|
|
67
67
|
headers.set("host", new URL(opts.convexSiteUrl).host);
|
|
68
|
+
headers.set("x-forwarded-host", requestUrl.host);
|
|
69
|
+
headers.set("x-forwarded-proto", requestUrl.protocol.replace(/:$/, ""));
|
|
70
|
+
headers.set("x-better-auth-forwarded-host", requestUrl.host);
|
|
71
|
+
headers.set("x-better-auth-forwarded-proto", requestUrl.protocol.replace(/:$/, ""));
|
|
68
72
|
return fetch(nextUrl, {
|
|
69
73
|
method: request.method,
|
|
70
74
|
headers,
|
|
@@ -1,170 +1,156 @@
|
|
|
1
1
|
import type { Session, User } from "@better-auth/core/db";
|
|
2
|
-
import { createTestSuite } from "@better-auth/test-utils/adapter";
|
|
2
|
+
import type { createTestSuite } from "@better-auth/test-utils/adapter";
|
|
3
3
|
import { setCookieToHeader } from "better-auth/cookies";
|
|
4
4
|
import { expect } from "vitest";
|
|
5
5
|
|
|
6
6
|
export const AUTH_FLOW_DEFAULT_BETTER_AUTH_OPTIONS = {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
emailAndPassword: {
|
|
8
|
+
enabled: true,
|
|
9
|
+
password: {
|
|
10
|
+
hash: async (password: string) => password,
|
|
11
|
+
async verify(data: { hash: string; password: string }) {
|
|
12
|
+
return data.hash === data.password;
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
export const getAuthFlowSuiteTests = (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
{
|
|
20
|
+
generate,
|
|
21
|
+
getAuth,
|
|
22
|
+
modifyBetterAuthOptions,
|
|
23
|
+
tryCatch,
|
|
24
|
+
}: Parameters<Parameters<typeof createTestSuite>[2]>[0],
|
|
25
25
|
) => ({
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
26
|
+
"should successfully sign up": async () => {
|
|
27
|
+
const auth = await getAuth();
|
|
28
|
+
const user = await generate("user");
|
|
29
|
+
const result = await auth.api.signUpEmail({
|
|
30
|
+
body: {
|
|
31
|
+
email: user.email,
|
|
32
|
+
password: crypto.randomUUID(),
|
|
33
|
+
name: user.name,
|
|
34
|
+
image: user.image || "",
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
expect(result.user).toBeDefined();
|
|
38
|
+
expect(result.user.email).toBe(user.email);
|
|
39
|
+
expect(result.user.name).toBe(user.name);
|
|
40
|
+
expect(result.user.image).toBe(user.image || "");
|
|
41
|
+
expect(result.user.emailVerified).toBe(false);
|
|
42
|
+
expect(result.user.createdAt).toBeDefined();
|
|
43
|
+
expect(result.user.updatedAt).toBeDefined();
|
|
44
|
+
},
|
|
45
|
+
"should successfully sign in": async () => {
|
|
46
|
+
const auth = await getAuth();
|
|
47
|
+
const user = await generate("user");
|
|
48
|
+
const password = crypto.randomUUID();
|
|
49
|
+
const signUpResult = await auth.api.signUpEmail({
|
|
50
|
+
body: {
|
|
51
|
+
email: user.email,
|
|
52
|
+
password,
|
|
53
|
+
name: user.name,
|
|
54
|
+
image: user.image || "",
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
const result = await auth.api.signInEmail({
|
|
58
|
+
body: { email: user.email, password },
|
|
59
|
+
});
|
|
60
|
+
expect(result.user).toBeDefined();
|
|
61
|
+
expect(result.user.id).toBe(signUpResult.user.id);
|
|
62
|
+
},
|
|
63
|
+
"should successfully get session": async () => {
|
|
64
|
+
const auth = await getAuth();
|
|
65
|
+
const user = await generate("user");
|
|
66
|
+
const password = crypto.randomUUID();
|
|
67
|
+
const response = await auth.api.signUpEmail({
|
|
68
|
+
body: {
|
|
69
|
+
email: user.email,
|
|
70
|
+
password,
|
|
71
|
+
name: user.name,
|
|
72
|
+
image: user.image || "",
|
|
73
|
+
},
|
|
74
|
+
asResponse: true,
|
|
75
|
+
});
|
|
76
|
+
const headers = new Headers();
|
|
77
|
+
setCookieToHeader(headers)({ response });
|
|
78
|
+
const result = await auth.api.getSession({
|
|
79
|
+
headers,
|
|
80
|
+
});
|
|
81
|
+
const signUpResult = (await response.json()) as {
|
|
82
|
+
user: User;
|
|
83
|
+
session: Session;
|
|
84
|
+
};
|
|
85
|
+
signUpResult.user.createdAt = new Date(signUpResult.user.createdAt).getTime() as unknown as Date;
|
|
86
|
+
signUpResult.user.updatedAt = new Date(signUpResult.user.updatedAt).getTime() as unknown as Date;
|
|
87
|
+
expect(result?.user).toBeDefined();
|
|
88
|
+
expect(result?.user).toStrictEqual(signUpResult.user);
|
|
89
|
+
expect(result?.session).toBeDefined();
|
|
90
|
+
},
|
|
91
|
+
"should not sign in with invalid email": async () => {
|
|
92
|
+
const auth = await getAuth();
|
|
93
|
+
const user = await generate("user");
|
|
94
|
+
const { data, error } = await tryCatch(
|
|
95
|
+
auth.api.signInEmail({
|
|
96
|
+
body: { email: user.email, password: crypto.randomUUID() },
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
expect(data).toBeNull();
|
|
100
|
+
expect(error).toBeDefined();
|
|
101
|
+
},
|
|
102
|
+
"should store and retrieve timestamps correctly across timezones": async () => {
|
|
103
|
+
const originalTZ = process.env.TZ;
|
|
104
|
+
try {
|
|
105
|
+
const auth = await getAuth();
|
|
106
|
+
const user = await generate("user");
|
|
107
|
+
const password = crypto.randomUUID();
|
|
108
|
+
const userSignUp = await auth.api.signUpEmail({
|
|
109
|
+
body: {
|
|
110
|
+
email: user.email,
|
|
111
|
+
password,
|
|
112
|
+
name: user.name,
|
|
113
|
+
image: user.image || "",
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
process.env.TZ = "Europe/London";
|
|
117
|
+
const userSignIn = await auth.api.signInEmail({
|
|
118
|
+
body: { email: user.email, password },
|
|
119
|
+
});
|
|
120
|
+
process.env.TZ = "America/Los_Angeles";
|
|
121
|
+
expect(userSignUp.user.createdAt).toStrictEqual(userSignIn.user.createdAt);
|
|
122
|
+
} finally {
|
|
123
|
+
if (originalTZ === undefined) {
|
|
124
|
+
delete process.env.TZ;
|
|
125
|
+
} else {
|
|
126
|
+
process.env.TZ = originalTZ;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"should sign up with additional fields": async () => {
|
|
131
|
+
await modifyBetterAuthOptions(
|
|
132
|
+
{ user: { additionalFields: { dateField: { type: "date" } } } },
|
|
133
|
+
true,
|
|
134
|
+
);
|
|
135
|
+
const auth = await getAuth();
|
|
136
|
+
const user = await generate("user");
|
|
137
|
+
const dateField = new Date();
|
|
138
|
+
const response = await auth.api.signUpEmail({
|
|
139
|
+
body: {
|
|
140
|
+
email: user.email,
|
|
141
|
+
name: user.name,
|
|
142
|
+
password: crypto.randomUUID(),
|
|
143
|
+
//@ts-expect-error - we are testing with additional fields
|
|
144
|
+
dateField: dateField.toISOString(),
|
|
145
|
+
},
|
|
146
|
+
asResponse: true,
|
|
147
|
+
});
|
|
148
|
+
const headers = new Headers();
|
|
149
|
+
setCookieToHeader(headers)({ response });
|
|
150
|
+
const result = await auth.api.getSession({
|
|
151
|
+
headers,
|
|
152
|
+
});
|
|
153
|
+
//@ts-expect-error - we are testing with additional fields
|
|
154
|
+
expect(result?.user.dateField).toStrictEqual(dateField.getTime());
|
|
155
|
+
},
|
|
150
156
|
});
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* This test suite tests basic authentication flow using the adapter.
|
|
154
|
-
*/
|
|
155
|
-
export const authFlowTestSuite = createTestSuite(
|
|
156
|
-
"auth-flow",
|
|
157
|
-
{
|
|
158
|
-
defaultBetterAuthOptions: AUTH_FLOW_DEFAULT_BETTER_AUTH_OPTIONS,
|
|
159
|
-
},
|
|
160
|
-
(helpers) => getAuthFlowSuiteTests(helpers),
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
function recoverProcessTZ() {
|
|
164
|
-
const originalTZ = process.env.TZ;
|
|
165
|
-
return {
|
|
166
|
-
[Symbol.dispose]: () => {
|
|
167
|
-
process.env.TZ = originalTZ;
|
|
168
|
-
},
|
|
169
|
-
};
|
|
170
|
-
}
|