@auth/drizzle-adapter 1.1.0 → 1.2.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
@@ -44,18 +44,40 @@ export function defineTables(schema = {}) {
44
44
  identifier: text("identifier").notNull(),
45
45
  token: text("token").notNull(),
46
46
  expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
47
- }, (vt) => ({
48
- compositePk: primaryKey({ columns: [vt.identifier, vt.token] }),
47
+ }, (verficationToken) => ({
48
+ compositePk: primaryKey({
49
+ columns: [verficationToken.identifier, verficationToken.token],
50
+ }),
51
+ })));
52
+ const authenticatorsTable = schema.authenticatorsTable ??
53
+ (sqliteTable("authenticator", {
54
+ credentialID: text("credentialID").notNull().unique(),
55
+ userId: text("userId")
56
+ .notNull()
57
+ .references(() => usersTable.id, { onDelete: "cascade" }),
58
+ providerAccountId: text("providerAccountId").notNull(),
59
+ credentialPublicKey: text("credentialPublicKey").notNull(),
60
+ counter: integer("counter").notNull(),
61
+ credentialDeviceType: text("credentialDeviceType").notNull(),
62
+ credentialBackedUp: integer("credentialBackedUp", {
63
+ mode: "boolean",
64
+ }).notNull(),
65
+ transports: text("transports"),
66
+ }, (authenticator) => ({
67
+ compositePK: primaryKey({
68
+ columns: [authenticator.userId, authenticator.credentialID],
69
+ }),
49
70
  })));
50
71
  return {
51
72
  usersTable,
52
73
  accountsTable,
53
74
  sessionsTable,
54
75
  verificationTokensTable,
76
+ authenticatorsTable,
55
77
  };
56
78
  }
57
79
  export function SQLiteDrizzleAdapter(client, schema) {
58
- const { usersTable, accountsTable, sessionsTable, verificationTokensTable } = defineTables(schema);
80
+ const { usersTable, accountsTable, sessionsTable, verificationTokensTable, authenticatorsTable, } = defineTables(schema);
59
81
  return {
60
82
  async createUser(data) {
61
83
  const { id, ...insertData } = data;
@@ -83,7 +105,7 @@ export function SQLiteDrizzleAdapter(client, schema) {
83
105
  return result ?? null;
84
106
  },
85
107
  async createSession(data) {
86
- return await client.insert(sessionsTable).values(data).returning().get();
108
+ return client.insert(sessionsTable).values(data).returning().get();
87
109
  },
88
110
  async getSessionAndUser(sessionToken) {
89
111
  const result = await client
@@ -143,7 +165,7 @@ export function SQLiteDrizzleAdapter(client, schema) {
143
165
  .run();
144
166
  },
145
167
  async createVerificationToken(data) {
146
- return await client
168
+ return client
147
169
  .insert(verificationTokensTable)
148
170
  .values(data)
149
171
  .returning()
@@ -166,5 +188,44 @@ export function SQLiteDrizzleAdapter(client, schema) {
166
188
  .where(and(eq(accountsTable.provider, params.provider), eq(accountsTable.providerAccountId, params.providerAccountId)))
167
189
  .run();
168
190
  },
191
+ async getAccount(providerAccountId, provider) {
192
+ return client
193
+ .select()
194
+ .from(accountsTable)
195
+ .where(and(eq(accountsTable.provider, provider), eq(accountsTable.providerAccountId, providerAccountId)))
196
+ .then((res) => res[0] ?? null);
197
+ },
198
+ async createAuthenticator(data) {
199
+ return client
200
+ .insert(authenticatorsTable)
201
+ .values(data)
202
+ .returning()
203
+ .then((res) => res[0] ?? null);
204
+ },
205
+ async getAuthenticator(credentialID) {
206
+ return client
207
+ .select()
208
+ .from(authenticatorsTable)
209
+ .where(eq(authenticatorsTable.credentialID, credentialID))
210
+ .then((res) => res[0] ?? null);
211
+ },
212
+ async listAuthenticatorsByUserId(userId) {
213
+ return client
214
+ .select()
215
+ .from(authenticatorsTable)
216
+ .where(eq(authenticatorsTable.userId, userId))
217
+ .then((res) => res);
218
+ },
219
+ async updateAuthenticatorCounter(credentialID, newCounter) {
220
+ const authenticator = await client
221
+ .update(authenticatorsTable)
222
+ .set({ counter: newCounter })
223
+ .where(eq(authenticatorsTable.credentialID, credentialID))
224
+ .returning()
225
+ .then((res) => res[0]);
226
+ if (!authenticator)
227
+ throw new Error("Authenticator not found.");
228
+ return authenticator;
229
+ },
169
230
  };
170
231
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@auth/drizzle-adapter",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Drizzle adapter for Auth.js.",
5
5
  "homepage": "https://authjs.dev",
6
6
  "repository": "https://github.com/nextauthjs/next-auth",
@@ -37,7 +37,7 @@
37
37
  "access": "public"
38
38
  },
39
39
  "dependencies": {
40
- "@auth/core": "0.31.0"
40
+ "@auth/core": "0.32.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/uuid": "^8.3.3",
package/src/lib/mysql.ts CHANGED
@@ -2,14 +2,15 @@ import { and, eq, getTableColumns } from "drizzle-orm"
2
2
  import {
3
3
  MySqlColumn,
4
4
  MySqlDatabase,
5
- MySqlTableWithColumns,
6
- PreparedQueryHKTBase,
7
- QueryResultHKT,
5
+ boolean,
8
6
  int,
9
7
  mysqlTable,
10
8
  primaryKey,
11
9
  timestamp,
12
10
  varchar,
11
+ QueryResultHKT,
12
+ PreparedQueryHKTBase,
13
+ MySqlTableWithColumns,
13
14
  } from "drizzle-orm/mysql-core"
14
15
 
15
16
  import type {
@@ -19,6 +20,7 @@ import type {
19
20
  AdapterSession,
20
21
  AdapterUser,
21
22
  VerificationToken,
23
+ AdapterAuthenticator,
22
24
  } from "@auth/core/adapters"
23
25
 
24
26
  export function defineTables(
@@ -85,16 +87,50 @@ export function defineTables(
85
87
  token: varchar("token", { length: 255 }).notNull(),
86
88
  expires: timestamp("expires", { mode: "date" }).notNull(),
87
89
  },
88
- (vt) => ({
89
- compositePk: primaryKey({ columns: [vt.identifier, vt.token] }),
90
+ (verficationToken) => ({
91
+ compositePk: primaryKey({
92
+ columns: [verficationToken.identifier, verficationToken.token],
93
+ }),
90
94
  })
91
95
  ) satisfies DefaultMySqlVerificationTokenTable)
92
96
 
97
+ const authenticatorsTable =
98
+ schema.authenticatorsTable ??
99
+ (mysqlTable(
100
+ "authenticator",
101
+ {
102
+ credentialID: varchar("credentialID", { length: 255 })
103
+ .notNull()
104
+ .unique(),
105
+ userId: varchar("userId", { length: 255 })
106
+ .notNull()
107
+ .references(() => usersTable.id, { onDelete: "cascade" }),
108
+ providerAccountId: varchar("providerAccountId", {
109
+ length: 255,
110
+ }).notNull(),
111
+ credentialPublicKey: varchar("credentialPublicKey", {
112
+ length: 255,
113
+ }).notNull(),
114
+ counter: int("counter").notNull(),
115
+ credentialDeviceType: varchar("credentialDeviceType", {
116
+ length: 255,
117
+ }).notNull(),
118
+ credentialBackedUp: boolean("credentialBackedUp").notNull(),
119
+ transports: varchar("transports", { length: 255 }),
120
+ },
121
+ (authenticator) => ({
122
+ compositePk: primaryKey({
123
+ columns: [authenticator.userId, authenticator.credentialID],
124
+ }),
125
+ })
126
+ ) satisfies DefaultMySqlAuthenticatorTable)
127
+
93
128
  return {
94
129
  usersTable,
95
130
  accountsTable,
96
131
  sessionsTable,
97
132
  verificationTokensTable,
133
+ authenticatorsTable,
98
134
  }
99
135
  }
100
136
 
@@ -102,8 +138,13 @@ export function MySqlDrizzleAdapter(
102
138
  client: MySqlDatabase<QueryResultHKT, PreparedQueryHKTBase, any>,
103
139
  schema?: DefaultMySqlSchema
104
140
  ): Adapter {
105
- const { usersTable, accountsTable, sessionsTable, verificationTokensTable } =
106
- defineTables(schema)
141
+ const {
142
+ usersTable,
143
+ accountsTable,
144
+ sessionsTable,
145
+ verificationTokensTable,
146
+ authenticatorsTable,
147
+ } = defineTables(schema)
107
148
 
108
149
  return {
109
150
  async createUser(data: AdapterUser) {
@@ -270,21 +311,77 @@ export function MySqlDrizzleAdapter(
270
311
  )
271
312
  )
272
313
  },
314
+ async getAccount(providerAccountId: string, provider: string) {
315
+ return client
316
+ .select()
317
+ .from(accountsTable)
318
+ .where(
319
+ and(
320
+ eq(accountsTable.provider, provider),
321
+ eq(accountsTable.providerAccountId, providerAccountId)
322
+ )
323
+ )
324
+ .then((res) => res[0] ?? null) as Promise<AdapterAccount | null>
325
+ },
326
+ async createAuthenticator(data: AdapterAuthenticator) {
327
+ await client.insert(authenticatorsTable).values(data)
328
+
329
+ return await client
330
+ .select()
331
+ .from(authenticatorsTable)
332
+ .where(eq(authenticatorsTable.credentialID, data.credentialID))
333
+ .then((res) => res[0] ?? null)
334
+ },
335
+ async getAuthenticator(credentialID: string) {
336
+ return await client
337
+ .select()
338
+ .from(authenticatorsTable)
339
+ .where(eq(authenticatorsTable.credentialID, credentialID))
340
+ .then((res) => res[0] ?? null)
341
+ },
342
+ async listAuthenticatorsByUserId(userId: string) {
343
+ return await client
344
+ .select()
345
+ .from(authenticatorsTable)
346
+ .where(eq(authenticatorsTable.userId, userId))
347
+ .then((res) => res)
348
+ },
349
+ async updateAuthenticatorCounter(credentialID: string, newCounter: number) {
350
+ await client
351
+ .update(authenticatorsTable)
352
+ .set({ counter: newCounter })
353
+ .where(eq(authenticatorsTable.credentialID, credentialID))
354
+
355
+ const authenticator = await client
356
+ .select()
357
+ .from(authenticatorsTable)
358
+ .where(eq(authenticatorsTable.credentialID, credentialID))
359
+ .then((res) => res[0])
360
+
361
+ if (!authenticator) throw new Error("Authenticator not found.")
362
+
363
+ return authenticator
364
+ },
273
365
  }
274
366
  }
275
367
 
276
368
  type DefaultMyqlColumn<
277
369
  T extends {
278
- data: string | number | Date
279
- dataType: "string" | "number" | "date"
370
+ data: string | number | boolean | Date
371
+ dataType: "string" | "number" | "boolean" | "date"
280
372
  notNull: boolean
281
- columnType: "MySqlVarChar" | "MySqlText" | "MySqlTimestamp" | "MySqlInt"
373
+ columnType:
374
+ | "MySqlVarChar"
375
+ | "MySqlText"
376
+ | "MySqlBoolean"
377
+ | "MySqlTimestamp"
378
+ | "MySqlInt"
282
379
  },
283
380
  > = MySqlColumn<{
284
381
  name: string
285
382
  columnType: T["columnType"]
286
383
  data: T["data"]
287
- driverParam: string | number
384
+ driverParam: string | number | boolean
288
385
  notNull: T["notNull"]
289
386
  hasDefault: boolean
290
387
  enumValues: any
@@ -457,9 +554,66 @@ export type DefaultMySqlVerificationTokenTable = MySqlTableWithColumns<{
457
554
  schema: string | undefined
458
555
  }>
459
556
 
557
+ export type DefaultMySqlAuthenticatorTable = MySqlTableWithColumns<{
558
+ name: string
559
+ columns: {
560
+ credentialID: DefaultMyqlColumn<{
561
+ columnType: "MySqlVarChar" | "MySqlText"
562
+ data: string
563
+ notNull: true
564
+ dataType: "string"
565
+ }>
566
+ userId: DefaultMyqlColumn<{
567
+ columnType: "MySqlVarChar" | "MySqlText"
568
+ data: string
569
+ notNull: true
570
+ dataType: "string"
571
+ }>
572
+ providerAccountId: DefaultMyqlColumn<{
573
+ columnType: "MySqlVarChar" | "MySqlText"
574
+ data: string
575
+ notNull: true
576
+ dataType: "string"
577
+ }>
578
+ credentialPublicKey: DefaultMyqlColumn<{
579
+ columnType: "MySqlVarChar" | "MySqlText"
580
+ data: string
581
+ notNull: true
582
+ dataType: "string"
583
+ }>
584
+ counter: DefaultMyqlColumn<{
585
+ columnType: "MySqlInt"
586
+ data: number
587
+ notNull: true
588
+ dataType: "number"
589
+ }>
590
+ credentialDeviceType: DefaultMyqlColumn<{
591
+ columnType: "MySqlVarChar" | "MySqlText"
592
+ data: string
593
+ notNull: true
594
+ dataType: "string"
595
+ }>
596
+ credentialBackedUp: DefaultMyqlColumn<{
597
+ columnType: "MySqlBoolean"
598
+ data: boolean
599
+ notNull: true
600
+ dataType: "boolean"
601
+ }>
602
+ transports: DefaultMyqlColumn<{
603
+ columnType: "MySqlVarChar" | "MySqlText"
604
+ data: string
605
+ notNull: false
606
+ dataType: "string"
607
+ }>
608
+ }
609
+ dialect: "mysql"
610
+ schema: string | undefined
611
+ }>
612
+
460
613
  export type DefaultMySqlSchema = {
461
614
  usersTable: DefaultMySqlUsersTable
462
615
  accountsTable: DefaultMySqlAccountsTable
463
616
  sessionsTable?: DefaultMySqlSessionsTable
464
617
  verificationTokensTable?: DefaultMySqlVerificationTokenTable
618
+ authenticatorsTable?: DefaultMySqlAuthenticatorTable
465
619
  }
package/src/lib/pg.ts CHANGED
@@ -1,9 +1,10 @@
1
- import { and, eq, getTableColumns } from "drizzle-orm"
1
+ import { InferInsertModel, and, eq, getTableColumns } from "drizzle-orm"
2
2
  import {
3
3
  PgColumn,
4
4
  PgDatabase,
5
5
  PgTableWithColumns,
6
6
  QueryResultHKT,
7
+ boolean,
7
8
  integer,
8
9
  pgTable,
9
10
  primaryKey,
@@ -15,6 +16,7 @@ import type {
15
16
  Adapter,
16
17
  AdapterAccount,
17
18
  AdapterAccountType,
19
+ AdapterAuthenticator,
18
20
  AdapterSession,
19
21
  AdapterUser,
20
22
  VerificationToken,
@@ -54,13 +56,11 @@ export function defineTables(
54
56
  id_token: text("id_token"),
55
57
  session_state: text("session_state"),
56
58
  },
57
- (table) => {
58
- return {
59
- compositePk: primaryKey({
60
- columns: [table.provider, table.providerAccountId],
61
- }),
62
- }
63
- }
59
+ (account) => ({
60
+ compositePk: primaryKey({
61
+ columns: [account.provider, account.providerAccountId],
62
+ }),
63
+ })
64
64
  ) satisfies DefaultPostgresAccountsTable)
65
65
 
66
66
  const sessionsTable =
@@ -82,18 +82,42 @@ export function defineTables(
82
82
  token: text("token").notNull(),
83
83
  expires: timestamp("expires", { mode: "date" }).notNull(),
84
84
  },
85
- (table) => {
86
- return {
87
- compositePk: primaryKey({ columns: [table.identifier, table.token] }),
88
- }
89
- }
85
+ (verficationToken) => ({
86
+ compositePk: primaryKey({
87
+ columns: [verficationToken.identifier, verficationToken.token],
88
+ }),
89
+ })
90
90
  ) satisfies DefaultPostgresVerificationTokenTable)
91
91
 
92
+ const authenticatorsTable =
93
+ schema.authenticatorsTable ??
94
+ (pgTable(
95
+ "authenticator",
96
+ {
97
+ credentialID: text("credentialID").notNull().unique(),
98
+ userId: text("userId")
99
+ .notNull()
100
+ .references(() => usersTable.id, { onDelete: "cascade" }),
101
+ providerAccountId: text("providerAccountId").notNull(),
102
+ credentialPublicKey: text("credentialPublicKey").notNull(),
103
+ counter: integer("counter").notNull(),
104
+ credentialDeviceType: text("credentialDeviceType").notNull(),
105
+ credentialBackedUp: boolean("credentialBackedUp").notNull(),
106
+ transports: text("transports"),
107
+ },
108
+ (authenticator) => ({
109
+ compositePK: primaryKey({
110
+ columns: [authenticator.userId, authenticator.credentialID],
111
+ }),
112
+ })
113
+ ) satisfies DefaultPostgresAuthenticatorTable)
114
+
92
115
  return {
93
116
  usersTable,
94
117
  accountsTable,
95
118
  sessionsTable,
96
119
  verificationTokensTable,
120
+ authenticatorsTable,
97
121
  }
98
122
  }
99
123
 
@@ -101,8 +125,13 @@ export function PostgresDrizzleAdapter(
101
125
  client: PgDatabase<QueryResultHKT, any>,
102
126
  schema?: DefaultPostgresSchema
103
127
  ): Adapter {
104
- const { usersTable, accountsTable, sessionsTable, verificationTokensTable } =
105
- defineTables(schema)
128
+ const {
129
+ usersTable,
130
+ accountsTable,
131
+ sessionsTable,
132
+ verificationTokensTable,
133
+ authenticatorsTable,
134
+ } = defineTables(schema)
106
135
 
107
136
  return {
108
137
  async createUser(data: AdapterUser) {
@@ -240,21 +269,72 @@ export function PostgresDrizzleAdapter(
240
269
  )
241
270
  )
242
271
  },
272
+ async getAccount(providerAccountId: string, provider: string) {
273
+ return client
274
+ .select()
275
+ .from(accountsTable)
276
+ .where(
277
+ and(
278
+ eq(accountsTable.provider, provider),
279
+ eq(accountsTable.providerAccountId, providerAccountId)
280
+ )
281
+ )
282
+ .then((res) => res[0] ?? null) as Promise<AdapterAccount | null>
283
+ },
284
+ async createAuthenticator(data: AdapterAuthenticator) {
285
+ return client
286
+ .insert(authenticatorsTable)
287
+ .values(data)
288
+ .returning()
289
+ .then((res) => res[0] ?? null)
290
+ },
291
+ async getAuthenticator(credentialID: string) {
292
+ return client
293
+ .select()
294
+ .from(authenticatorsTable)
295
+ .where(eq(authenticatorsTable.credentialID, credentialID))
296
+ .then((res) => res[0] ?? null)
297
+ },
298
+ async listAuthenticatorsByUserId(userId: string) {
299
+ return client
300
+ .select()
301
+ .from(authenticatorsTable)
302
+ .where(eq(authenticatorsTable.userId, userId))
303
+ .then((res) => res)
304
+ },
305
+ async updateAuthenticatorCounter(credentialID: string, newCounter: number) {
306
+ const authenticator = await client
307
+ .update(authenticatorsTable)
308
+ .set({ counter: newCounter })
309
+ .where(eq(authenticatorsTable.credentialID, credentialID))
310
+ .returning()
311
+ .then((res) => res[0])
312
+
313
+ if (!authenticator) throw new Error("Authenticator not found.")
314
+
315
+ return authenticator
316
+ },
243
317
  }
244
318
  }
245
319
 
246
320
  type DefaultPostgresColumn<
247
321
  T extends {
248
- data: string | number | Date
249
- dataType: "string" | "number" | "date"
322
+ data: string | number | boolean | Date
323
+ dataType: "string" | "number" | "boolean" | "date"
250
324
  notNull: boolean
251
- columnType: "PgVarchar" | "PgText" | "PgTimestamp" | "PgInteger" | "PgUUID"
325
+ columnType:
326
+ | "PgVarchar"
327
+ | "PgText"
328
+ | "PgBoolean"
329
+ | "PgTimestamp"
330
+ | "PgInteger"
331
+ | "PgUUID"
252
332
  },
253
333
  > = PgColumn<{
254
334
  name: string
255
335
  columnType: T["columnType"]
256
336
  data: T["data"]
257
- driverParam: string | number
337
+ driverParam: string | number | boolean
258
338
  notNull: T["notNull"]
259
339
  hasDefault: boolean
260
340
  enumValues: any
@@ -426,9 +506,66 @@ export type DefaultPostgresVerificationTokenTable = PgTableWithColumns<{
426
506
  schema: string | undefined
427
507
  }>
428
508
 
509
+ export type DefaultPostgresAuthenticatorTable = PgTableWithColumns<{
510
+ name: string
511
+ columns: {
512
+ credentialID: DefaultPostgresColumn<{
513
+ columnType: "PgVarchar" | "PgText"
514
+ data: string
515
+ notNull: true
516
+ dataType: "string"
517
+ }>
518
+ userId: DefaultPostgresColumn<{
519
+ columnType: "PgVarchar" | "PgText"
520
+ data: string
521
+ notNull: true
522
+ dataType: "string"
523
+ }>
524
+ providerAccountId: DefaultPostgresColumn<{
525
+ columnType: "PgVarchar" | "PgText"
526
+ data: string
527
+ notNull: true
528
+ dataType: "string"
529
+ }>
530
+ credentialPublicKey: DefaultPostgresColumn<{
531
+ columnType: "PgVarchar" | "PgText"
532
+ data: string
533
+ notNull: true
534
+ dataType: "string"
535
+ }>
536
+ counter: DefaultPostgresColumn<{
537
+ columnType: "PgInteger"
538
+ data: number
539
+ notNull: true
540
+ dataType: "number"
541
+ }>
542
+ credentialDeviceType: DefaultPostgresColumn<{
543
+ columnType: "PgVarchar" | "PgText"
544
+ data: string
545
+ notNull: true
546
+ dataType: "string"
547
+ }>
548
+ credentialBackedUp: DefaultPostgresColumn<{
549
+ columnType: "PgBoolean"
550
+ data: boolean
551
+ notNull: true
552
+ dataType: "boolean"
553
+ }>
554
+ transports: DefaultPostgresColumn<{
555
+ columnType: "PgVarchar" | "PgText"
556
+ data: string
557
+ notNull: false
558
+ dataType: "string"
559
+ }>
560
+ }
561
+ dialect: "pg"
562
+ schema: string | undefined
563
+ }>
564
+
429
565
  export type DefaultPostgresSchema = {
430
566
  usersTable: DefaultPostgresUsersTable
431
567
  accountsTable: DefaultPostgresAccountsTable
432
568
  sessionsTable?: DefaultPostgresSessionsTable
433
569
  verificationTokensTable?: DefaultPostgresVerificationTokenTable
570
+ authenticatorsTable?: DefaultPostgresAuthenticatorTable
434
571
  }