@auth/drizzle-adapter 1.0.1 → 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/src/lib/sqlite.ts CHANGED
@@ -12,84 +12,134 @@ import {
12
12
  import type {
13
13
  Adapter,
14
14
  AdapterAccount,
15
+ AdapterAccountType,
16
+ AdapterAuthenticator,
15
17
  AdapterSession,
16
18
  AdapterUser,
17
19
  VerificationToken,
18
20
  } from "@auth/core/adapters"
19
21
 
20
- export const sqliteUsersTable = sqliteTable("user", {
21
- id: text("id")
22
- .primaryKey()
23
- .$defaultFn(() => crypto.randomUUID()),
24
- name: text("name"),
25
- email: text("email").notNull(),
26
- emailVerified: integer("emailVerified", { mode: "timestamp_ms" }),
27
- image: text("image"),
28
- }) satisfies DefaultSQLiteUsersTable
22
+ export function defineTables(
23
+ schema: Partial<DefaultSQLiteSchema> = {}
24
+ ): Required<DefaultSQLiteSchema> {
25
+ const usersTable =
26
+ schema.usersTable ??
27
+ (sqliteTable("user", {
28
+ id: text("id")
29
+ .primaryKey()
30
+ .$defaultFn(() => crypto.randomUUID()),
31
+ name: text("name"),
32
+ email: text("email").notNull(),
33
+ emailVerified: integer("emailVerified", { mode: "timestamp_ms" }),
34
+ image: text("image"),
35
+ }) satisfies DefaultSQLiteUsersTable)
29
36
 
30
- export const sqliteAccountsTable = sqliteTable(
31
- "account",
32
- {
33
- userId: text("userId")
34
- .notNull()
35
- .references(() => sqliteUsersTable.id, { onDelete: "cascade" }),
36
- type: text("type").$type<AdapterAccount["type"]>().notNull(),
37
- provider: text("provider").notNull(),
38
- providerAccountId: text("providerAccountId").notNull(),
39
- refresh_token: text("refresh_token"),
40
- access_token: text("access_token"),
41
- expires_at: integer("expires_at"),
42
- token_type: text("token_type"),
43
- scope: text("scope"),
44
- id_token: text("id_token"),
45
- session_state: text("session_state"),
46
- },
47
- (account) => ({
48
- compositePk: primaryKey({
49
- columns: [account.provider, account.providerAccountId],
50
- }),
51
- })
52
- ) satisfies DefaultSQLiteAccountsTable
37
+ const accountsTable =
38
+ schema.accountsTable ??
39
+ (sqliteTable(
40
+ "account",
41
+ {
42
+ userId: text("userId")
43
+ .notNull()
44
+ .references(() => usersTable.id, { onDelete: "cascade" }),
45
+ type: text("type").$type<AdapterAccountType>().notNull(),
46
+ provider: text("provider").notNull(),
47
+ providerAccountId: text("providerAccountId").notNull(),
48
+ refresh_token: text("refresh_token"),
49
+ access_token: text("access_token"),
50
+ expires_at: integer("expires_at"),
51
+ token_type: text("token_type"),
52
+ scope: text("scope"),
53
+ id_token: text("id_token"),
54
+ session_state: text("session_state"),
55
+ },
56
+ (account) => ({
57
+ compositePk: primaryKey({
58
+ columns: [account.provider, account.providerAccountId],
59
+ }),
60
+ })
61
+ ) satisfies DefaultSQLiteAccountsTable)
53
62
 
54
- export const sqliteSessionsTable = sqliteTable("session", {
55
- sessionToken: text("sessionToken").primaryKey(),
56
- userId: text("userId")
57
- .notNull()
58
- .references(() => sqliteUsersTable.id, { onDelete: "cascade" }),
59
- expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
60
- }) satisfies DefaultSQLiteSessionsTable
63
+ const sessionsTable =
64
+ schema.sessionsTable ??
65
+ (sqliteTable("session", {
66
+ sessionToken: text("sessionToken").primaryKey(),
67
+ userId: text("userId")
68
+ .notNull()
69
+ .references(() => usersTable.id, { onDelete: "cascade" }),
70
+ expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
71
+ }) satisfies DefaultSQLiteSessionsTable)
61
72
 
62
- export const sqliteVerificationTokensTable = sqliteTable(
63
- "verificationToken",
64
- {
65
- identifier: text("identifier").notNull(),
66
- token: text("token").notNull(),
67
- expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
68
- },
69
- (vt) => ({
70
- compositePk: primaryKey({ columns: [vt.identifier, vt.token] }),
71
- })
72
- ) satisfies DefaultSQLiteVerificationTokenTable
73
+ const verificationTokensTable =
74
+ schema.verificationTokensTable ??
75
+ (sqliteTable(
76
+ "verificationToken",
77
+ {
78
+ identifier: text("identifier").notNull(),
79
+ token: text("token").notNull(),
80
+ expires: integer("expires", { mode: "timestamp_ms" }).notNull(),
81
+ },
82
+ (verficationToken) => ({
83
+ compositePk: primaryKey({
84
+ columns: [verficationToken.identifier, verficationToken.token],
85
+ }),
86
+ })
87
+ ) satisfies DefaultSQLiteVerificationTokenTable)
88
+
89
+ const authenticatorsTable =
90
+ schema.authenticatorsTable ??
91
+ (sqliteTable(
92
+ "authenticator",
93
+ {
94
+ credentialID: text("credentialID").notNull().unique(),
95
+ userId: text("userId")
96
+ .notNull()
97
+ .references(() => usersTable.id, { onDelete: "cascade" }),
98
+ providerAccountId: text("providerAccountId").notNull(),
99
+ credentialPublicKey: text("credentialPublicKey").notNull(),
100
+ counter: integer("counter").notNull(),
101
+ credentialDeviceType: text("credentialDeviceType").notNull(),
102
+ credentialBackedUp: integer("credentialBackedUp", {
103
+ mode: "boolean",
104
+ }).notNull(),
105
+ transports: text("transports"),
106
+ },
107
+ (authenticator) => ({
108
+ compositePK: primaryKey({
109
+ columns: [authenticator.userId, authenticator.credentialID],
110
+ }),
111
+ })
112
+ ) satisfies DefaultSQLiteAuthenticatorTable)
113
+
114
+ return {
115
+ usersTable,
116
+ accountsTable,
117
+ sessionsTable,
118
+ verificationTokensTable,
119
+ authenticatorsTable,
120
+ }
121
+ }
73
122
 
74
123
  export function SQLiteDrizzleAdapter(
75
124
  client: BaseSQLiteDatabase<"sync" | "async", any, any>,
76
- schema: DefaultSQLiteSchema = {
77
- usersTable: sqliteUsersTable,
78
- accountsTable: sqliteAccountsTable,
79
- sessionsTable: sqliteSessionsTable,
80
- verificationTokensTable: sqliteVerificationTokensTable,
81
- }
125
+ schema?: DefaultSQLiteSchema
82
126
  ): Adapter {
83
- const { usersTable, accountsTable, sessionsTable, verificationTokensTable } =
84
- schema
127
+ const {
128
+ usersTable,
129
+ accountsTable,
130
+ sessionsTable,
131
+ verificationTokensTable,
132
+ authenticatorsTable,
133
+ } = defineTables(schema)
85
134
 
86
135
  return {
87
136
  async createUser(data: AdapterUser) {
137
+ const { id, ...insertData } = data
88
138
  const hasDefaultId = getTableColumns(usersTable)["id"]["hasDefault"]
89
139
 
90
140
  return client
91
141
  .insert(usersTable)
92
- .values(hasDefaultId ? data : { ...data, id: crypto.randomUUID() })
142
+ .values(hasDefaultId ? insertData : { ...insertData, id })
93
143
  .returning()
94
144
  .get()
95
145
  },
@@ -116,7 +166,7 @@ export function SQLiteDrizzleAdapter(
116
166
  userId: string
117
167
  expires: Date
118
168
  }) {
119
- return await client.insert(sessionsTable).values(data).returning().get()
169
+ return client.insert(sessionsTable).values(data).returning().get()
120
170
  },
121
171
  async getSessionAndUser(sessionToken: string) {
122
172
  const result = await client
@@ -191,7 +241,7 @@ export function SQLiteDrizzleAdapter(
191
241
  .run()
192
242
  },
193
243
  async createVerificationToken(data: VerificationToken) {
194
- return await client
244
+ return client
195
245
  .insert(verificationTokensTable)
196
246
  .values(data)
197
247
  .returning()
@@ -227,21 +277,70 @@ export function SQLiteDrizzleAdapter(
227
277
  )
228
278
  .run()
229
279
  },
280
+ async getAccount(providerAccountId: string, provider: string) {
281
+ return client
282
+ .select()
283
+ .from(accountsTable)
284
+ .where(
285
+ and(
286
+ eq(accountsTable.provider, provider),
287
+ eq(accountsTable.providerAccountId, providerAccountId)
288
+ )
289
+ )
290
+ .then((res) => res[0] ?? null) as Promise<AdapterAccount | null>
291
+ },
292
+ async createAuthenticator(data: AdapterAuthenticator) {
293
+ return client
294
+ .insert(authenticatorsTable)
295
+ .values(data)
296
+ .returning()
297
+ .then((res) => res[0] ?? null)
298
+ },
299
+ async getAuthenticator(credentialID: string) {
300
+ return client
301
+ .select()
302
+ .from(authenticatorsTable)
303
+ .where(eq(authenticatorsTable.credentialID, credentialID))
304
+ .then((res) => res[0] ?? null)
305
+ },
306
+ async listAuthenticatorsByUserId(userId: string) {
307
+ return client
308
+ .select()
309
+ .from(authenticatorsTable)
310
+ .where(eq(authenticatorsTable.userId, userId))
311
+ .then((res) => res)
312
+ },
313
+ async updateAuthenticatorCounter(credentialID: string, newCounter: number) {
314
+ const authenticator = await client
315
+ .update(authenticatorsTable)
316
+ .set({ counter: newCounter })
317
+ .where(eq(authenticatorsTable.credentialID, credentialID))
318
+ .returning()
319
+ .then((res) => res[0])
320
+
321
+ if (!authenticator) throw new Error("Authenticator not found.")
322
+
323
+ return authenticator
324
+ },
230
325
  }
231
326
  }
232
327
 
233
328
  type DefaultSQLiteColumn<
234
329
  T extends {
235
- data: string | number | Date
236
- dataType: "string" | "number" | "date"
330
+ data: string | boolean | number | Date
331
+ dataType: "string" | "boolean" | "number" | "date"
237
332
  notNull: boolean
238
- columnType: "SQLiteText" | "SQLiteTimestamp" | "SQLiteInteger"
333
+ columnType:
334
+ | "SQLiteText"
335
+ | "SQLiteBoolean"
336
+ | "SQLiteTimestamp"
337
+ | "SQLiteInteger"
239
338
  },
240
339
  > = SQLiteColumn<{
241
340
  name: string
242
341
  columnType: T["columnType"]
243
342
  data: T["data"]
244
- driverParam: string | number
343
+ driverParam: string | number | boolean
245
344
  notNull: T["notNull"]
246
345
  hasDefault: boolean
247
346
  enumValues: any
@@ -413,9 +512,66 @@ export type DefaultSQLiteVerificationTokenTable = SQLiteTableWithColumns<{
413
512
  schema: string | undefined
414
513
  }>
415
514
 
515
+ export type DefaultSQLiteAuthenticatorTable = SQLiteTableWithColumns<{
516
+ name: string
517
+ columns: {
518
+ credentialID: DefaultSQLiteColumn<{
519
+ columnType: "SQLiteText"
520
+ data: string
521
+ notNull: true
522
+ dataType: "string"
523
+ }>
524
+ userId: DefaultSQLiteColumn<{
525
+ columnType: "SQLiteText"
526
+ data: string
527
+ notNull: true
528
+ dataType: "string"
529
+ }>
530
+ providerAccountId: DefaultSQLiteColumn<{
531
+ columnType: "SQLiteText"
532
+ data: string
533
+ notNull: true
534
+ dataType: "string"
535
+ }>
536
+ credentialPublicKey: DefaultSQLiteColumn<{
537
+ columnType: "SQLiteText"
538
+ data: string
539
+ notNull: true
540
+ dataType: "string"
541
+ }>
542
+ counter: DefaultSQLiteColumn<{
543
+ columnType: "SQLiteInteger"
544
+ data: number
545
+ notNull: true
546
+ dataType: "number"
547
+ }>
548
+ credentialDeviceType: DefaultSQLiteColumn<{
549
+ columnType: "SQLiteText"
550
+ data: string
551
+ notNull: true
552
+ dataType: "string"
553
+ }>
554
+ credentialBackedUp: DefaultSQLiteColumn<{
555
+ columnType: "SQLiteBoolean"
556
+ data: boolean
557
+ notNull: true
558
+ dataType: "boolean"
559
+ }>
560
+ transports: DefaultSQLiteColumn<{
561
+ columnType: "SQLiteText"
562
+ data: string
563
+ notNull: false
564
+ dataType: "string"
565
+ }>
566
+ }
567
+ dialect: "sqlite"
568
+ schema: string | undefined
569
+ }>
570
+
416
571
  export type DefaultSQLiteSchema = {
417
572
  usersTable: DefaultSQLiteUsersTable
418
573
  accountsTable: DefaultSQLiteAccountsTable
419
- sessionsTable: DefaultSQLiteSessionsTable
420
- verificationTokensTable: DefaultSQLiteVerificationTokenTable
574
+ sessionsTable?: DefaultSQLiteSessionsTable
575
+ verificationTokensTable?: DefaultSQLiteVerificationTokenTable
576
+ authenticatorsTable?: DefaultSQLiteAuthenticatorTable
421
577
  }