@auth/drizzle-adapter 0.9.0 → 1.0.0

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/lib/sqlite.js CHANGED
@@ -1,82 +1,93 @@
1
1
  import { eq, and } from "drizzle-orm";
2
- import { integer, sqliteTable as defaultSqliteTableFn, text, primaryKey, } from "drizzle-orm/sqlite-core";
3
- import { stripUndefined } from "./utils.js";
4
- export function createTables(sqliteTable) {
5
- const users = sqliteTable("user", {
6
- id: text("id").notNull().primaryKey(),
7
- name: text("name"),
8
- email: text("email").notNull(),
9
- emailVerified: integer("emailVerified", { mode: "timestamp_ms" }),
10
- image: text("image"),
11
- });
12
- const accounts = sqliteTable("account", {
13
- userId: text("userId")
14
- .notNull()
15
- .references(() => users.id, { onDelete: "cascade" }),
16
- type: text("type").$type().notNull(),
17
- provider: text("provider").notNull(),
18
- providerAccountId: text("providerAccountId").notNull(),
19
- refresh_token: text("refresh_token"),
20
- access_token: text("access_token"),
21
- expires_at: integer("expires_at"),
22
- token_type: text("token_type"),
23
- scope: text("scope"),
24
- id_token: text("id_token"),
25
- session_state: text("session_state"),
26
- }, (account) => ({
27
- compoundKey: primaryKey(account.provider, account.providerAccountId),
28
- }));
29
- const sessions = sqliteTable("session", {
30
- sessionToken: text("sessionToken").notNull().primaryKey(),
31
- userId: text("userId")
32
- .notNull()
33
- .references(() => users.id, { onDelete: "cascade" }),
34
- expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
35
- });
36
- const verificationTokens = sqliteTable("verificationToken", {
37
- identifier: text("identifier").notNull(),
38
- token: text("token").notNull(),
39
- expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
40
- }, (vt) => ({
41
- compoundKey: primaryKey(vt.identifier, vt.token),
42
- }));
43
- return { users, accounts, sessions, verificationTokens };
44
- }
45
- export function SQLiteDrizzleAdapter(client, tableFn = defaultSqliteTableFn) {
46
- const { users, accounts, sessions, verificationTokens } = createTables(tableFn);
2
+ import { integer, text, primaryKey, sqliteTable, index, } from "drizzle-orm/sqlite-core";
3
+ import { randomUUID } from "crypto";
4
+ export const sqliteUsersTable = sqliteTable("user", {
5
+ id: text("id")
6
+ .primaryKey()
7
+ .$defaultFn(() => randomUUID()),
8
+ name: text("name"),
9
+ email: text("email").notNull().unique(),
10
+ emailVerified: integer("emailVerified", { mode: "timestamp_ms" }),
11
+ image: text("image"),
12
+ });
13
+ export const sqliteAccountsTable = sqliteTable("account", {
14
+ userId: text("userId")
15
+ .notNull()
16
+ .references(() => sqliteUsersTable.id, { onDelete: "cascade" }),
17
+ type: text("type").notNull(),
18
+ provider: text("provider").notNull(),
19
+ providerAccountId: text("providerAccountId").notNull(),
20
+ refresh_token: text("refresh_token"),
21
+ access_token: text("access_token"),
22
+ expires_at: integer("expires_at"),
23
+ token_type: text("token_type"),
24
+ scope: text("scope"),
25
+ id_token: text("id_token"),
26
+ session_state: text("session_state"),
27
+ }, (account) => ({
28
+ userIdIdx: index("Account_userId_index").on(account.userId),
29
+ compositePk: primaryKey({
30
+ columns: [account.provider, account.providerAccountId],
31
+ }),
32
+ }));
33
+ export const sqliteSessionsTable = sqliteTable("session", {
34
+ id: text("id")
35
+ .primaryKey()
36
+ .$defaultFn(() => randomUUID()),
37
+ sessionToken: text("sessionToken").notNull().unique(),
38
+ userId: text("userId")
39
+ .notNull()
40
+ .references(() => sqliteUsersTable.id, { onDelete: "cascade" }),
41
+ expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
42
+ }, (table) => ({
43
+ userIdIdx: index("Session_userId_index").on(table.userId),
44
+ }));
45
+ export const sqliteVerificationTokensTable = sqliteTable("verificationToken", {
46
+ identifier: text("identifier").notNull(),
47
+ token: text("token").notNull().unique(),
48
+ expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
49
+ }, (vt) => ({
50
+ compositePk: primaryKey({ columns: [vt.identifier, vt.token] }),
51
+ }));
52
+ export function SQLiteDrizzleAdapter(client, schema = {
53
+ usersTable: sqliteUsersTable,
54
+ accountsTable: sqliteAccountsTable,
55
+ sessionsTable: sqliteSessionsTable,
56
+ verificationTokensTable: sqliteVerificationTokensTable,
57
+ }) {
58
+ const { usersTable, accountsTable, sessionsTable, verificationTokensTable } = schema;
47
59
  return {
48
60
  async createUser(data) {
49
- return await client
50
- .insert(users)
51
- .values({ ...data, id: crypto.randomUUID() })
52
- .returning()
53
- .get();
61
+ return client.insert(usersTable).values(data).returning().get();
54
62
  },
55
- async getUser(data) {
63
+ async getUser(userId) {
56
64
  const result = await client
57
65
  .select()
58
- .from(users)
59
- .where(eq(users.id, data))
66
+ .from(usersTable)
67
+ .where(eq(usersTable.id, userId))
60
68
  .get();
61
69
  return result ?? null;
62
70
  },
63
- async getUserByEmail(data) {
71
+ async getUserByEmail(email) {
64
72
  const result = await client
65
73
  .select()
66
- .from(users)
67
- .where(eq(users.email, data))
74
+ .from(usersTable)
75
+ .where(eq(usersTable.email, email))
68
76
  .get();
69
77
  return result ?? null;
70
78
  },
71
- createSession(data) {
72
- return client.insert(sessions).values(data).returning().get();
79
+ async createSession(data) {
80
+ return await client.insert(sessionsTable).values(data).returning().get();
73
81
  },
74
- async getSessionAndUser(data) {
82
+ async getSessionAndUser(sessionToken) {
75
83
  const result = await client
76
- .select({ session: sessions, user: users })
77
- .from(sessions)
78
- .where(eq(sessions.sessionToken, data))
79
- .innerJoin(users, eq(users.id, sessions.userId))
84
+ .select({
85
+ session: sessionsTable,
86
+ user: usersTable,
87
+ })
88
+ .from(sessionsTable)
89
+ .where(eq(sessionsTable.sessionToken, sessionToken))
90
+ .innerJoin(usersTable, eq(usersTable.id, sessionsTable.userId))
80
91
  .get();
81
92
  return result ?? null;
82
93
  },
@@ -85,78 +96,68 @@ export function SQLiteDrizzleAdapter(client, tableFn = defaultSqliteTableFn) {
85
96
  throw new Error("No user id.");
86
97
  }
87
98
  const result = await client
88
- .update(users)
99
+ .update(usersTable)
89
100
  .set(data)
90
- .where(eq(users.id, data.id))
101
+ .where(eq(usersTable.id, data.id))
91
102
  .returning()
92
103
  .get();
93
- return result ?? null;
104
+ if (!result) {
105
+ throw new Error("User not found.");
106
+ }
107
+ return result;
94
108
  },
95
109
  async updateSession(data) {
96
110
  const result = await client
97
- .update(sessions)
111
+ .update(sessionsTable)
98
112
  .set(data)
99
- .where(eq(sessions.sessionToken, data.sessionToken))
113
+ .where(eq(sessionsTable.sessionToken, data.sessionToken))
100
114
  .returning()
101
115
  .get();
102
116
  return result ?? null;
103
117
  },
104
- async linkAccount(rawAccount) {
105
- return stripUndefined(await client.insert(accounts).values(rawAccount).returning().get());
118
+ async linkAccount(data) {
119
+ await client.insert(accountsTable).values(data).run();
106
120
  },
107
121
  async getUserByAccount(account) {
108
- const results = await client
109
- .select()
110
- .from(accounts)
111
- .leftJoin(users, eq(users.id, accounts.userId))
112
- .where(and(eq(accounts.provider, account.provider), eq(accounts.providerAccountId, account.providerAccountId)))
122
+ const result = await client
123
+ .select({
124
+ account: accountsTable,
125
+ user: usersTable,
126
+ })
127
+ .from(accountsTable)
128
+ .innerJoin(usersTable, eq(accountsTable.userId, usersTable.id))
129
+ .where(and(eq(accountsTable.provider, account.provider), eq(accountsTable.providerAccountId, account.providerAccountId)))
113
130
  .get();
114
- if (!results) {
115
- return null;
116
- }
117
- return Promise.resolve(results).then((results) => results.user);
131
+ return result?.user ?? null;
118
132
  },
119
133
  async deleteSession(sessionToken) {
120
- const result = await client
121
- .delete(sessions)
122
- .where(eq(sessions.sessionToken, sessionToken))
134
+ await client
135
+ .delete(sessionsTable)
136
+ .where(eq(sessionsTable.sessionToken, sessionToken))
137
+ .run();
138
+ },
139
+ async createVerificationToken(data) {
140
+ return await client
141
+ .insert(verificationTokensTable)
142
+ .values(data)
123
143
  .returning()
124
144
  .get();
125
- return result ?? null;
126
145
  },
127
- async createVerificationToken(token) {
146
+ async useVerificationToken(params) {
128
147
  const result = await client
129
- .insert(verificationTokens)
130
- .values(token)
148
+ .delete(verificationTokensTable)
149
+ .where(and(eq(verificationTokensTable.identifier, params.identifier), eq(verificationTokensTable.token, params.token)))
131
150
  .returning()
132
151
  .get();
133
152
  return result ?? null;
134
153
  },
135
- async useVerificationToken(token) {
136
- try {
137
- const result = await client
138
- .delete(verificationTokens)
139
- .where(and(eq(verificationTokens.identifier, token.identifier), eq(verificationTokens.token, token.token)))
140
- .returning()
141
- .get();
142
- return result ?? null;
143
- }
144
- catch (err) {
145
- throw new Error("No verification token found.");
146
- }
147
- },
148
154
  async deleteUser(id) {
149
- const result = await client
150
- .delete(users)
151
- .where(eq(users.id, id))
152
- .returning()
153
- .get();
154
- return result ?? null;
155
+ await client.delete(usersTable).where(eq(usersTable.id, id)).run();
155
156
  },
156
- async unlinkAccount(account) {
157
+ async unlinkAccount(params) {
157
158
  await client
158
- .delete(accounts)
159
- .where(and(eq(accounts.providerAccountId, account.providerAccountId), eq(accounts.provider, account.provider)))
159
+ .delete(accountsTable)
160
+ .where(and(eq(accountsTable.provider, params.provider), eq(accountsTable.providerAccountId, params.providerAccountId)))
160
161
  .run();
161
162
  },
162
163
  };
package/lib/utils.d.ts CHANGED
@@ -1,26 +1,15 @@
1
1
  import { MySqlDatabase } from "drizzle-orm/mysql-core";
2
2
  import { PgDatabase } from "drizzle-orm/pg-core";
3
3
  import { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
4
- import type { AnyMySqlTable, MySqlTableFn } from "drizzle-orm/mysql-core";
5
- import type { AnyPgTable, PgTableFn } from "drizzle-orm/pg-core";
6
- import type { AnySQLiteTable, SQLiteTableFn } from "drizzle-orm/sqlite-core";
7
- import type { DefaultSchema as PgSchema } from "./pg.js";
8
- import type { DefaultSchema as MySqlSchema } from "./mysql.js";
9
- import type { DefaultSchema as SQLiteSchema } from "./sqlite.js";
10
- export type AnyMySqlDatabase = MySqlDatabase<any, any>;
11
- export type AnyPgDatabase = PgDatabase<any, any, any>;
12
- export type AnySQLiteDatabase = BaseSQLiteDatabase<any, any, any, any>;
13
- export interface MinimumSchema {
14
- mysql: MySqlSchema & Record<string, AnyMySqlTable>;
15
- pg: PgSchema & Record<string, AnyPgTable>;
16
- sqlite: SQLiteSchema & Record<string, AnySQLiteTable>;
17
- }
18
- export type SqlFlavorOptions = AnyMySqlDatabase | AnyPgDatabase | AnySQLiteDatabase;
19
- export type ClientFlavors<Flavor> = Flavor extends AnyMySqlDatabase ? MinimumSchema["mysql"] : Flavor extends AnyPgDatabase ? MinimumSchema["pg"] : Flavor extends AnySQLiteDatabase ? MinimumSchema["sqlite"] : never;
20
- export type TableFn<Flavor> = Flavor extends AnyMySqlDatabase ? MySqlTableFn : Flavor extends AnyPgDatabase ? PgTableFn : Flavor extends AnySQLiteDatabase ? SQLiteTableFn : AnySQLiteTable;
21
- type NonNullableProps<T> = {
22
- [P in keyof T]: null extends T[P] ? never : P;
23
- }[keyof T];
24
- export declare function stripUndefined<T>(obj: T): Pick<T, NonNullableProps<T>>;
4
+ import type { QueryResultHKT as MySQLQueryResultHKT, PreparedQueryHKTBase } from "drizzle-orm/mysql-core";
5
+ import type { QueryResultHKT as PostgresQueryResultHKT } from "drizzle-orm/pg-core";
6
+ import { DefaultSQLiteSchema } from "./sqlite";
7
+ import { DefaultPostgresSchema } from "./pg";
8
+ import { DefaultMySqlSchema } from "./mysql";
9
+ type AnyPostgresDatabase = PgDatabase<PostgresQueryResultHKT, any>;
10
+ type AnyMySqlDatabase = MySqlDatabase<MySQLQueryResultHKT, PreparedQueryHKTBase, any>;
11
+ type AnySQLiteDatabase = BaseSQLiteDatabase<"sync" | "async", any, any>;
12
+ export type SqlFlavorOptions = AnyPostgresDatabase | AnyMySqlDatabase | AnySQLiteDatabase;
13
+ export type DefaultSchema<Flavor> = Flavor extends AnyMySqlDatabase ? DefaultMySqlSchema : Flavor extends AnyPostgresDatabase ? DefaultPostgresSchema : Flavor extends AnySQLiteDatabase ? DefaultSQLiteSchema : never;
25
14
  export {};
26
15
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAC5E,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,SAAS,CAAA;AACxD,OAAO,KAAK,EAAE,aAAa,IAAI,WAAW,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,KAAK,EAAE,aAAa,IAAI,YAAY,EAAE,MAAM,aAAa,CAAA;AAEhE,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AACtD,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AACrD,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AAEtE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAClD,EAAE,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACzC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;CACtD;AAED,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,aAAa,GACb,iBAAiB,CAAA;AAErB,MAAM,MAAM,aAAa,CAAC,MAAM,IAAI,MAAM,SAAS,gBAAgB,GAC/D,aAAa,CAAC,OAAO,CAAC,GACtB,MAAM,SAAS,aAAa,GAC1B,aAAa,CAAC,IAAI,CAAC,GACnB,MAAM,SAAS,iBAAiB,GAC9B,aAAa,CAAC,QAAQ,CAAC,GACvB,KAAK,CAAA;AAEb,MAAM,MAAM,OAAO,CAAC,MAAM,IAAI,MAAM,SAAS,gBAAgB,GACzD,YAAY,GACZ,MAAM,SAAS,aAAa,GAC1B,SAAS,GACT,MAAM,SAAS,iBAAiB,GAC9B,aAAa,GACb,cAAc,CAAA;AAEtB,KAAK,gBAAgB,CAAC,CAAC,IAAI;KACxB,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC;CAC9C,CAAC,MAAM,CAAC,CAAC,CAAA;AAEV,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAItE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EACV,cAAc,IAAI,mBAAmB,EACrC,oBAAoB,EACrB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,cAAc,IAAI,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AACnF,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,MAAM,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAE5C,KAAK,mBAAmB,GAAG,UAAU,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAA;AAClE,KAAK,gBAAgB,GAAG,aAAa,CACnC,mBAAmB,EACnB,oBAAoB,EACpB,GAAG,CACJ,CAAA;AACD,KAAK,iBAAiB,GAAG,kBAAkB,CAAC,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AAEvE,MAAM,MAAM,gBAAgB,GACxB,mBAAmB,GACnB,gBAAgB,GAChB,iBAAiB,CAAA;AAErB,MAAM,MAAM,aAAa,CAAC,MAAM,IAAI,MAAM,SAAS,gBAAgB,GAC/D,kBAAkB,GAClB,MAAM,SAAS,mBAAmB,GAChC,qBAAqB,GACrB,MAAM,SAAS,iBAAiB,GAC9B,mBAAmB,GACnB,KAAK,CAAA"}
package/lib/utils.js CHANGED
@@ -1,7 +1 @@
1
- export function stripUndefined(obj) {
2
- const result = {};
3
- for (const key in obj)
4
- if (obj[key] !== undefined)
5
- result[key] = obj[key];
6
- return result;
7
- }
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@auth/drizzle-adapter",
3
- "version": "0.9.0",
3
+ "version": "1.0.0",
4
4
  "description": "Drizzle adapter for Auth.js.",
5
5
  "homepage": "https://authjs.dev",
6
6
  "repository": "https://github.com/nextauthjs/next-auth",
@@ -19,7 +19,8 @@
19
19
  "exports": {
20
20
  ".": {
21
21
  "types": "./index.d.ts",
22
- "import": "./index.js"
22
+ "import": "./index.js",
23
+ "require": "./index.js"
23
24
  }
24
25
  },
25
26
  "license": "ISC",
@@ -36,16 +37,15 @@
36
37
  "access": "public"
37
38
  },
38
39
  "dependencies": {
39
- "@auth/core": "0.29.0"
40
+ "@auth/core": "0.30.0"
40
41
  },
41
42
  "devDependencies": {
42
- "@libsql/client": "0.4.0-pre.5",
43
43
  "@types/better-sqlite3": "^7.6.4",
44
44
  "@types/uuid": "^8.3.3",
45
45
  "better-sqlite3": "^8.6.0",
46
- "drizzle-kit": "^0.20.6",
47
- "drizzle-orm": "^0.29.1",
48
- "mysql2": "^3.2.0",
46
+ "drizzle-kit": "^0.20.14",
47
+ "drizzle-orm": "^0.30.5",
48
+ "mysql2": "^3.9.4",
49
49
  "postgres": "^3.3.4",
50
50
  "tsx": "^4.7.0"
51
51
  },
package/src/index.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", padding: 16}}>
3
3
  * <p style={{fontWeight: "normal"}}>Official <a href="https://orm.drizzle.team">Drizzle ORM</a> adapter for Auth.js / NextAuth.js.</p>
4
4
  * <a href="https://orm.drizzle.team">
5
- * <img style={{display: "block"}} src="/img/adapters/drizzle-orm.png" width="38" />
5
+ * <img style={{display: "block"}} src="/img/adapters/drizzle.svg" width="38" />
6
6
  * </a>
7
7
  * </div>
8
8
  *
@@ -16,40 +16,69 @@
16
16
  * @module @auth/drizzle-adapter
17
17
  */
18
18
 
19
- import { MySqlDatabase, MySqlTableFn } from "drizzle-orm/mysql-core"
20
- import { PgDatabase, PgTableFn } from "drizzle-orm/pg-core"
21
- import { BaseSQLiteDatabase, SQLiteTableFn } from "drizzle-orm/sqlite-core"
22
- import { mySqlDrizzleAdapter } from "./lib/mysql.js"
23
- import { pgDrizzleAdapter } from "./lib/pg.js"
24
- import { SQLiteDrizzleAdapter } from "./lib/sqlite.js"
25
- import { SqlFlavorOptions, TableFn } from "./lib/utils.js"
26
19
  import { is } from "drizzle-orm"
20
+ import { MySqlDatabase } from "drizzle-orm/mysql-core"
21
+ import { PgDatabase } from "drizzle-orm/pg-core"
22
+ import { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core"
23
+ import { DefaultMySqlSchema, MySqlDrizzleAdapter } from "./lib/mysql.js"
24
+ import { DefaultPostgresSchema, PostgresDrizzleAdapter } from "./lib/pg.js"
25
+ import { DefaultSQLiteSchema, SQLiteDrizzleAdapter } from "./lib/sqlite.js"
26
+ import { DefaultSchema, SqlFlavorOptions } from "./lib/utils.js"
27
27
 
28
28
  import type { Adapter } from "@auth/core/adapters"
29
29
 
30
+ export {
31
+ postgresUsersTable,
32
+ postgresAccountsTable,
33
+ postgresSessionsTable,
34
+ postgresVerificationTokensTable,
35
+ } from "./lib/pg.js"
36
+ export {
37
+ sqliteUsersTable,
38
+ sqliteAccountsTable,
39
+ sqliteSessionsTable,
40
+ sqliteVerificationTokensTable,
41
+ } from "./lib/sqlite.js"
42
+ export {
43
+ mysqlUsersTable,
44
+ mysqlAccountsTable,
45
+ mysqlSessionsTable,
46
+ mysqlVerificationTokensTable,
47
+ } from "./lib/mysql.js"
30
48
  /**
31
- * Add the adapter to your `pages/api/[...nextauth].ts` next-auth configuration object.
49
+ * Add this adapter to your `auth.ts` Auth.js configuration object:
32
50
  *
33
- * ```ts title="pages/api/auth/[...nextauth].ts"
51
+ * ```ts title="auth.ts"
34
52
  * import NextAuth from "next-auth"
35
- * import GoogleProvider from "next-auth/providers/google"
53
+ * import Google from "next-auth/providers/google"
36
54
  * import { DrizzleAdapter } from "@auth/drizzle-adapter"
37
55
  * import { db } from "./schema"
38
56
  *
39
- * export default NextAuth({
57
+ * export const { handlers, auth } = NextAuth({
40
58
  * adapter: DrizzleAdapter(db),
41
59
  * providers: [
42
- * GoogleProvider({
43
- * clientId: process.env.GOOGLE_CLIENT_ID,
44
- * clientSecret: process.env.GOOGLE_CLIENT_SECRET,
45
- * }),
60
+ * Google,
46
61
  * ],
47
62
  * })
48
63
  * ```
49
64
  *
50
65
  * :::info
51
- * If you're using multi-project schemas, you can pass your table function as a second argument
66
+ * If you want to use your own tables, you can pass them as a second argument
52
67
  * :::
68
+ *
69
+ * ```ts title="auth.ts"
70
+ * import NextAuth from "next-auth"
71
+ * import Google from "next-auth/providers/google"
72
+ * import { DrizzleAdapter } from "@auth/drizzle-adapter"
73
+ * import { db, accounts, sessions, users, verificationTokens } from "./schema"
74
+ *
75
+ * export const { handlers, auth } = NextAuth({
76
+ * adapter: DrizzleAdapter(db, { usersTable: users, accountsTable: accounts, sessionsTable: sessions, verificationTokensTable: verificationTokens }),
77
+ * providers: [
78
+ * Google,
79
+ * ],
80
+ * })
81
+ * ```
53
82
  *
54
83
  * ## Setup
55
84
  *
@@ -71,11 +100,12 @@ import type { Adapter } from "@auth/core/adapters"
71
100
  * integer
72
101
  * } from "drizzle-orm/pg-core"
73
102
  * import type { AdapterAccount } from '@auth/core/adapters'
103
+ * import { randomUUID } from "crypto"
74
104
  *
75
105
  * export const users = pgTable("user", {
76
- * id: text("id").notNull().primaryKey(),
106
+ * id: text("id").primaryKey().$defaultFn(() => randomUUID()),
77
107
  * name: text("name"),
78
- * email: text("email").notNull(),
108
+ * email: text("email").notNull().unique(),
79
109
  * emailVerified: timestamp("emailVerified", { mode: "date" }),
80
110
  * image: text("image"),
81
111
  * })
@@ -86,7 +116,7 @@ import type { Adapter } from "@auth/core/adapters"
86
116
  * userId: text("userId")
87
117
  * .notNull()
88
118
  * .references(() => users.id, { onDelete: "cascade" }),
89
- * type: text("type").$type<AdapterAccount["type"]>().notNull(),
119
+ * type: text("type").notNull(),
90
120
  * provider: text("provider").notNull(),
91
121
  * providerAccountId: text("providerAccountId").notNull(),
92
122
  * refresh_token: text("refresh_token"),
@@ -98,23 +128,27 @@ import type { Adapter } from "@auth/core/adapters"
98
128
  * session_state: text("session_state"),
99
129
  * },
100
130
  * (account) => ({
131
+ * userIdIdx: index().on(account.userId),
101
132
  * compoundKey: primaryKey({ columns: [account.provider, account.providerAccountId] }),
102
133
  * })
103
134
  * )
104
135
  *
105
136
  * export const sessions = pgTable("session", {
106
- * sessionToken: text("sessionToken").notNull().primaryKey(),
137
+ * id: text("id").primaryKey().$defaultFn(() => randomUUID()),
138
+ * sessionToken: text("sessionToken").notNull().unique(),
107
139
  * userId: text("userId")
108
140
  * .notNull()
109
141
  * .references(() => users.id, { onDelete: "cascade" }),
110
142
  * expires: timestamp("expires", { mode: "date" }).notNull(),
111
- * })
143
+ * }, (session) => ({
144
+ * userIdIdx: index().on(session.userId)
145
+ * }))
112
146
  *
113
147
  * export const verificationTokens = pgTable(
114
148
  * "verificationToken",
115
149
  * {
116
150
  * identifier: text("identifier").notNull(),
117
- * token: text("token").notNull(),
151
+ * token: text("token").notNull().unique(),
118
152
  * expires: timestamp("expires", { mode: "date" }).notNull(),
119
153
  * },
120
154
  * (vt) => ({
@@ -136,10 +170,10 @@ import type { Adapter } from "@auth/core/adapters"
136
170
  * import type { AdapterAccount } from "@auth/core/adapters"
137
171
  *
138
172
  * export const users = mysqlTable("user", {
139
- * id: varchar("id", { length: 255 }).notNull().primaryKey(),
173
+ * id: varchar("id", { length: 255 }).primaryKey().$defaultFn(() => randomUUID()),
140
174
  * name: varchar("name", { length: 255 }),
141
- * email: varchar("email", { length: 255 }).notNull(),
142
- * emailVerified: timestamp("emailVerified", { mode: "date", fsp: 3 }).defaultNow(),
175
+ * email: varchar("email", { length: 255 }).notNull().unique(),
176
+ * emailVerified: timestamp("emailVerified", { mode: "date", fsp: 3 }),
143
177
  * image: varchar("image", { length: 255 }),
144
178
  * })
145
179
  *
@@ -149,8 +183,8 @@ import type { Adapter } from "@auth/core/adapters"
149
183
  * userId: varchar("userId", { length: 255 })
150
184
  * .notNull()
151
185
  * .references(() => users.id, { onDelete: "cascade" }),
152
- * type: varchar("type", { length: 255 }).$type<AdapterAccount["type"]>().notNull(),
153
- * provider: varchar("provider", { length: 255 }).notNull(),
186
+ * type: varchar("type", { length: 255 }).notNull(),
187
+ * provider: varchar("provider", { length: 255 }).notNull(),
154
188
  * providerAccountId: varchar("providerAccountId", { length: 255 }).notNull(),
155
189
  * refresh_token: varchar("refresh_token", { length: 255 }),
156
190
  * access_token: varchar("access_token", { length: 255 }),
@@ -164,22 +198,26 @@ import type { Adapter } from "@auth/core/adapters"
164
198
  * compoundKey: primaryKey({
165
199
  columns: [account.provider, account.providerAccountId],
166
200
  }),
201
+ userIdIdx: index('Account_userId_index').on(account.userId)
167
202
  * })
168
203
  * )
169
204
  *
170
205
  * export const sessions = mysqlTable("session", {
171
- * sessionToken: varchar("sessionToken", { length: 255 }).notNull().primaryKey(),
206
+ * id: varchar("id", { length: 255 }).primaryKey().$defaultFn(() => randomUUID()),
207
+ * sessionToken: varchar("sessionToken", { length: 255 }).notNull().unique(),
172
208
  * userId: varchar("userId", { length: 255 })
173
209
  * .notNull()
174
210
  * .references(() => users.id, { onDelete: "cascade" }),
175
211
  * expires: timestamp("expires", { mode: "date" }).notNull(),
176
- * })
212
+ * }, (session) => ({
213
+ * userIdIdx: index('Session_userId_index').on(session.userId)
214
+ * }))
177
215
  *
178
216
  * export const verificationTokens = mysqlTable(
179
217
  * "verificationToken",
180
218
  * {
181
219
  * identifier: varchar("identifier", { length: 255 }).notNull(),
182
- * token: varchar("token", { length: 255 }).notNull(),
220
+ * token: varchar("token", { length: 255 }).notNull().unique(),
183
221
  * expires: timestamp("expires", { mode: "date" }).notNull(),
184
222
  * },
185
223
  * (vt) => ({
@@ -195,9 +233,9 @@ import type { Adapter } from "@auth/core/adapters"
195
233
  * import type { AdapterAccount } from "@auth/core/adapters"
196
234
  *
197
235
  * export const users = sqliteTable("user", {
198
- * id: text("id").notNull().primaryKey(),
236
+ * id: text("id").primaryKey().$defaultFn(() => randomUUID()),
199
237
  * name: text("name"),
200
- * email: text("email").notNull(),
238
+ * email: text("email").notNull().unique(),
201
239
  * emailVerified: integer("emailVerified", { mode: "timestamp_ms" }),
202
240
  * image: text("image"),
203
241
  * })
@@ -208,7 +246,7 @@ import type { Adapter } from "@auth/core/adapters"
208
246
  * userId: text("userId")
209
247
  * .notNull()
210
248
  * .references(() => users.id, { onDelete: "cascade" }),
211
- * type: text("type").$type<AdapterAccount["type"]>().notNull(),
249
+ * type: text("type").notNull(),
212
250
  * provider: text("provider").notNull(),
213
251
  * providerAccountId: text("providerAccountId").notNull(),
214
252
  * refresh_token: text("refresh_token"),
@@ -223,22 +261,26 @@ import type { Adapter } from "@auth/core/adapters"
223
261
  * compoundKey: primaryKey({
224
262
  columns: [account.provider, account.providerAccountId],
225
263
  }),
264
+ userIdIdx: index('Account_userId_index').on(account.userId)
226
265
  * })
227
266
  * )
228
267
  *
229
268
  * export const sessions = sqliteTable("session", {
230
- * sessionToken: text("sessionToken").notNull().primaryKey(),
269
+ * id: text("id").primaryKey().$defaultFn(() => randomUUID())
270
+ * sessionToken: text("sessionToken").notNull().unique(),
231
271
  * userId: text("userId")
232
272
  * .notNull()
233
273
  * .references(() => users.id, { onDelete: "cascade" }),
234
274
  * expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
235
- * })
275
+ * }, (table) => ({
276
+ * userIdIdx: index('Session_userId_index').on(table.userId)
277
+ * }))
236
278
  *
237
279
  * export const verificationTokens = sqliteTable(
238
280
  * "verificationToken",
239
281
  * {
240
282
  * identifier: text("identifier").notNull(),
241
- * token: text("token").notNull(),
283
+ * token: text("token").notNull().unique(),
242
284
  * expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
243
285
  * },
244
286
  * (vt) => ({
@@ -257,14 +299,14 @@ import type { Adapter } from "@auth/core/adapters"
257
299
  **/
258
300
  export function DrizzleAdapter<SqlFlavor extends SqlFlavorOptions>(
259
301
  db: SqlFlavor,
260
- table?: TableFn<SqlFlavor>
302
+ schema?: DefaultSchema<SqlFlavor>
261
303
  ): Adapter {
262
304
  if (is(db, MySqlDatabase)) {
263
- return mySqlDrizzleAdapter(db, table as MySqlTableFn)
305
+ return MySqlDrizzleAdapter(db, schema as DefaultMySqlSchema)
264
306
  } else if (is(db, PgDatabase)) {
265
- return pgDrizzleAdapter(db, table as PgTableFn)
307
+ return PostgresDrizzleAdapter(db, schema as DefaultPostgresSchema)
266
308
  } else if (is(db, BaseSQLiteDatabase)) {
267
- return SQLiteDrizzleAdapter(db, table as SQLiteTableFn)
309
+ return SQLiteDrizzleAdapter(db, schema as DefaultSQLiteSchema)
268
310
  }
269
311
 
270
312
  throw new Error(