@factiii/auth 0.5.3 → 0.5.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/index.js CHANGED
@@ -42,8 +42,12 @@ __export(index_exports, {
42
42
  createAuthRouter: () => createAuthRouter,
43
43
  createAuthToken: () => createAuthToken,
44
44
  createConsoleEmailAdapter: () => createConsoleEmailAdapter,
45
+ createDrizzleAdapter: () => createDrizzleAdapter,
45
46
  createNoopEmailAdapter: () => createNoopEmailAdapter,
46
47
  createOAuthVerifier: () => createOAuthVerifier,
48
+ createPrismaAdapter: () => createPrismaAdapter,
49
+ createSessionWithToken: () => createSessionWithToken,
50
+ createSessionWithTokenAndCookie: () => createSessionWithTokenAndCookie,
47
51
  decodeToken: () => decodeToken,
48
52
  defaultAuthConfig: () => defaultAuthConfig,
49
53
  defaultCookieSettings: () => defaultCookieSettings,
@@ -78,6 +82,261 @@ module.exports = __toCommonJS(index_exports);
78
82
  // src/middleware/authGuard.ts
79
83
  var import_server = require("@trpc/server");
80
84
 
85
+ // src/adapters/prismaAdapter.ts
86
+ function createPrismaAdapter(prisma) {
87
+ const db = prisma;
88
+ return {
89
+ user: {
90
+ async findByEmailInsensitive(email) {
91
+ return db.user.findFirst({
92
+ where: { email: { equals: email, mode: "insensitive" } }
93
+ });
94
+ },
95
+ async findByUsernameInsensitive(username) {
96
+ return db.user.findFirst({
97
+ where: { username: { equals: username, mode: "insensitive" } }
98
+ });
99
+ },
100
+ async findByEmailOrUsernameInsensitive(identifier) {
101
+ return db.user.findFirst({
102
+ where: {
103
+ OR: [
104
+ { email: { equals: identifier, mode: "insensitive" } },
105
+ { username: { equals: identifier, mode: "insensitive" } }
106
+ ]
107
+ }
108
+ });
109
+ },
110
+ async findByEmailOrOAuthId(email, oauthId) {
111
+ return db.user.findFirst({
112
+ where: {
113
+ OR: [
114
+ { email: { equals: email, mode: "insensitive" } },
115
+ { oauthId: { equals: oauthId } }
116
+ ]
117
+ }
118
+ });
119
+ },
120
+ async findById(id) {
121
+ return db.user.findUnique({ where: { id } });
122
+ },
123
+ async findActiveById(id) {
124
+ return db.user.findUnique({
125
+ where: { id, status: "ACTIVE" }
126
+ });
127
+ },
128
+ async create(data) {
129
+ return db.user.create({ data });
130
+ },
131
+ async update(id, data) {
132
+ return db.user.update({ where: { id }, data });
133
+ }
134
+ },
135
+ session: {
136
+ async findById(id) {
137
+ const session = await db.session.findUnique({
138
+ where: { id },
139
+ select: {
140
+ id: true,
141
+ userId: true,
142
+ socketId: true,
143
+ twoFaSecret: true,
144
+ browserName: true,
145
+ issuedAt: true,
146
+ lastUsed: true,
147
+ revokedAt: true,
148
+ deviceId: true,
149
+ user: { select: { status: true, verifiedHumanAt: true } }
150
+ }
151
+ });
152
+ return session;
153
+ },
154
+ async create(data) {
155
+ return db.session.create({ data });
156
+ },
157
+ async update(id, data) {
158
+ return db.session.update({ where: { id }, data });
159
+ },
160
+ async updateLastUsed(id) {
161
+ const session = await db.session.update({
162
+ where: { id },
163
+ data: { lastUsed: /* @__PURE__ */ new Date() },
164
+ select: {
165
+ id: true,
166
+ userId: true,
167
+ socketId: true,
168
+ twoFaSecret: true,
169
+ browserName: true,
170
+ issuedAt: true,
171
+ lastUsed: true,
172
+ revokedAt: true,
173
+ deviceId: true,
174
+ user: { select: { verifiedHumanAt: true } }
175
+ }
176
+ });
177
+ return session;
178
+ },
179
+ async revoke(id) {
180
+ await db.session.update({
181
+ where: { id },
182
+ data: { revokedAt: /* @__PURE__ */ new Date() }
183
+ });
184
+ },
185
+ async findActiveByUserId(userId, excludeSessionId) {
186
+ return db.session.findMany({
187
+ where: {
188
+ userId,
189
+ revokedAt: null,
190
+ ...excludeSessionId ? { NOT: { id: excludeSessionId } } : {}
191
+ },
192
+ select: { id: true, socketId: true, userId: true }
193
+ });
194
+ },
195
+ async revokeAllByUserId(userId, excludeSessionId) {
196
+ await db.session.updateMany({
197
+ where: {
198
+ userId,
199
+ revokedAt: null,
200
+ ...excludeSessionId ? { NOT: { id: excludeSessionId } } : {}
201
+ },
202
+ data: { revokedAt: /* @__PURE__ */ new Date() }
203
+ });
204
+ },
205
+ async findTwoFaSecretsByUserId(userId) {
206
+ return db.session.findMany({
207
+ where: { userId, twoFaSecret: { not: null } },
208
+ select: { twoFaSecret: true }
209
+ });
210
+ },
211
+ async clearTwoFaSecrets(userId, excludeSessionId) {
212
+ await db.session.updateMany({
213
+ where: {
214
+ userId,
215
+ ...excludeSessionId ? { NOT: { id: excludeSessionId } } : {}
216
+ },
217
+ data: { twoFaSecret: null }
218
+ });
219
+ },
220
+ async findByIdWithDevice(id, userId) {
221
+ const session = await db.session.findUnique({
222
+ where: { id, userId },
223
+ select: {
224
+ twoFaSecret: true,
225
+ deviceId: true,
226
+ device: { select: { pushToken: true } }
227
+ }
228
+ });
229
+ return session;
230
+ },
231
+ async revokeByDevicePushToken(userId, pushToken, excludeSessionId) {
232
+ await db.session.updateMany({
233
+ where: {
234
+ userId,
235
+ id: { not: excludeSessionId },
236
+ revokedAt: null,
237
+ device: { pushToken }
238
+ },
239
+ data: { revokedAt: /* @__PURE__ */ new Date() }
240
+ });
241
+ },
242
+ async clearDeviceId(userId, deviceId) {
243
+ await db.session.updateMany({
244
+ where: { userId, deviceId },
245
+ data: { deviceId: null }
246
+ });
247
+ }
248
+ },
249
+ otp: {
250
+ async findValidByUserAndCode(userId, code) {
251
+ return db.oTP.findFirst({
252
+ where: { userId, code, expiresAt: { gte: /* @__PURE__ */ new Date() } }
253
+ });
254
+ },
255
+ async create(data) {
256
+ return db.oTP.create({ data });
257
+ },
258
+ async delete(id) {
259
+ await db.oTP.delete({ where: { id } });
260
+ }
261
+ },
262
+ passwordReset: {
263
+ async findById(id) {
264
+ return db.passwordReset.findUnique({
265
+ where: { id },
266
+ select: { id: true, createdAt: true, userId: true }
267
+ });
268
+ },
269
+ async create(userId) {
270
+ return db.passwordReset.create({
271
+ data: { userId }
272
+ });
273
+ },
274
+ async delete(id) {
275
+ await db.passwordReset.delete({ where: { id } });
276
+ },
277
+ async deleteAllByUserId(userId) {
278
+ await db.passwordReset.deleteMany({ where: { userId } });
279
+ }
280
+ },
281
+ device: {
282
+ async findByTokenSessionAndUser(pushToken, sessionId, userId) {
283
+ return db.device.findFirst({
284
+ where: {
285
+ pushToken,
286
+ sessions: { some: { id: sessionId } },
287
+ users: { some: { id: userId } }
288
+ },
289
+ select: { id: true }
290
+ });
291
+ },
292
+ async upsertByPushToken(pushToken, sessionId, userId) {
293
+ await db.device.upsert({
294
+ where: { pushToken },
295
+ create: {
296
+ pushToken,
297
+ sessions: { connect: { id: sessionId } },
298
+ users: { connect: { id: userId } }
299
+ },
300
+ update: {
301
+ sessions: { connect: { id: sessionId } },
302
+ users: { connect: { id: userId } }
303
+ }
304
+ });
305
+ },
306
+ async findByUserAndToken(userId, pushToken) {
307
+ return db.device.findFirst({
308
+ where: { users: { some: { id: userId } }, pushToken },
309
+ select: { id: true }
310
+ });
311
+ },
312
+ async disconnectUser(deviceId, userId) {
313
+ await db.device.update({
314
+ where: { id: deviceId },
315
+ data: { users: { disconnect: { id: userId } } }
316
+ });
317
+ },
318
+ async hasRemainingUsers(deviceId) {
319
+ const result = await db.device.findUnique({
320
+ where: { id: deviceId },
321
+ select: { users: { select: { id: true }, take: 1 } }
322
+ });
323
+ return (result?.users.length ?? 0) > 0;
324
+ },
325
+ async delete(id) {
326
+ await db.device.delete({ where: { id } });
327
+ }
328
+ },
329
+ admin: {
330
+ async findByUserId(userId) {
331
+ return db.admin.findFirst({
332
+ where: { userId },
333
+ select: { ip: true }
334
+ });
335
+ }
336
+ }
337
+ };
338
+ }
339
+
81
340
  // src/adapters/email.ts
82
341
  function createNoopEmailAdapter() {
83
342
  return {
@@ -131,6 +390,294 @@ function createConsoleEmailAdapter() {
131
390
  };
132
391
  }
133
392
 
393
+ // src/adapters/drizzleAdapter.ts
394
+ function createDrizzleAdapter(db, tables) {
395
+ const {
396
+ eq,
397
+ and,
398
+ or,
399
+ isNull,
400
+ isNotNull,
401
+ gte,
402
+ ne,
403
+ sql
404
+ } = require("drizzle-orm");
405
+ const { users, sessions, otps, passwordResets, devices, admins } = tables;
406
+ return {
407
+ user: {
408
+ async findByEmailInsensitive(email) {
409
+ const rows = await db.select().from(users).where(sql`lower(${users.email}) = lower(${email})`).limit(1);
410
+ return rows[0] ?? null;
411
+ },
412
+ async findByUsernameInsensitive(username) {
413
+ const rows = await db.select().from(users).where(sql`lower(${users.username}) = lower(${username})`).limit(1);
414
+ return rows[0] ?? null;
415
+ },
416
+ async findByEmailOrUsernameInsensitive(identifier) {
417
+ const rows = await db.select().from(users).where(
418
+ or(
419
+ sql`lower(${users.email}) = lower(${identifier})`,
420
+ sql`lower(${users.username}) = lower(${identifier})`
421
+ )
422
+ ).limit(1);
423
+ return rows[0] ?? null;
424
+ },
425
+ async findByEmailOrOAuthId(email, oauthId) {
426
+ const rows = await db.select().from(users).where(
427
+ or(
428
+ sql`lower(${users.email}) = lower(${email})`,
429
+ eq(users.oauthId, oauthId)
430
+ )
431
+ ).limit(1);
432
+ return rows[0] ?? null;
433
+ },
434
+ async findById(id) {
435
+ const rows = await db.select().from(users).where(eq(users.id, id)).limit(1);
436
+ return rows[0] ?? null;
437
+ },
438
+ async findActiveById(id) {
439
+ const rows = await db.select().from(users).where(and(eq(users.id, id), eq(users.status, "ACTIVE"))).limit(1);
440
+ return rows[0] ?? null;
441
+ },
442
+ async create(data) {
443
+ const rows = await db.insert(users).values(data).returning();
444
+ return rows[0];
445
+ },
446
+ async update(id, data) {
447
+ const rows = await db.update(users).set(data).where(eq(users.id, id)).returning();
448
+ return rows[0];
449
+ }
450
+ },
451
+ session: {
452
+ async findById(id) {
453
+ const rows = await db.select({
454
+ id: sessions.id,
455
+ userId: sessions.userId,
456
+ socketId: sessions.socketId,
457
+ twoFaSecret: sessions.twoFaSecret,
458
+ browserName: sessions.browserName,
459
+ issuedAt: sessions.issuedAt,
460
+ lastUsed: sessions.lastUsed,
461
+ revokedAt: sessions.revokedAt,
462
+ deviceId: sessions.deviceId,
463
+ user: {
464
+ status: users.status,
465
+ verifiedHumanAt: users.verifiedHumanAt
466
+ }
467
+ }).from(sessions).innerJoin(users, eq(sessions.userId, users.id)).where(eq(sessions.id, id)).limit(1);
468
+ return rows[0] ?? null;
469
+ },
470
+ async create(data) {
471
+ const rows = await db.insert(sessions).values(data).returning();
472
+ return rows[0];
473
+ },
474
+ async update(id, data) {
475
+ const rows = await db.update(sessions).set(data).where(eq(sessions.id, id)).returning();
476
+ return rows[0];
477
+ },
478
+ async updateLastUsed(id) {
479
+ await db.update(sessions).set({ lastUsed: /* @__PURE__ */ new Date() }).where(eq(sessions.id, id));
480
+ const rows = await db.select({
481
+ id: sessions.id,
482
+ userId: sessions.userId,
483
+ socketId: sessions.socketId,
484
+ twoFaSecret: sessions.twoFaSecret,
485
+ browserName: sessions.browserName,
486
+ issuedAt: sessions.issuedAt,
487
+ lastUsed: sessions.lastUsed,
488
+ revokedAt: sessions.revokedAt,
489
+ deviceId: sessions.deviceId,
490
+ user: {
491
+ verifiedHumanAt: users.verifiedHumanAt
492
+ }
493
+ }).from(sessions).innerJoin(users, eq(sessions.userId, users.id)).where(eq(sessions.id, id)).limit(1);
494
+ return rows[0];
495
+ },
496
+ async revoke(id) {
497
+ await db.update(sessions).set({ revokedAt: /* @__PURE__ */ new Date() }).where(eq(sessions.id, id));
498
+ },
499
+ async findActiveByUserId(userId, excludeSessionId) {
500
+ const conditions = [eq(sessions.userId, userId), isNull(sessions.revokedAt)];
501
+ if (excludeSessionId !== void 0) {
502
+ conditions.push(ne(sessions.id, excludeSessionId));
503
+ }
504
+ const activeRows = await db.select({
505
+ id: sessions.id,
506
+ socketId: sessions.socketId,
507
+ userId: sessions.userId
508
+ }).from(sessions).where(and(...conditions));
509
+ return activeRows;
510
+ },
511
+ async revokeAllByUserId(userId, excludeSessionId) {
512
+ const conditions = [eq(sessions.userId, userId), isNull(sessions.revokedAt)];
513
+ if (excludeSessionId !== void 0) {
514
+ conditions.push(ne(sessions.id, excludeSessionId));
515
+ }
516
+ await db.update(sessions).set({ revokedAt: /* @__PURE__ */ new Date() }).where(and(...conditions));
517
+ },
518
+ async findTwoFaSecretsByUserId(userId) {
519
+ const secretRows = await db.select({ twoFaSecret: sessions.twoFaSecret }).from(sessions).where(and(eq(sessions.userId, userId), isNotNull(sessions.twoFaSecret)));
520
+ return secretRows;
521
+ },
522
+ async clearTwoFaSecrets(userId, excludeSessionId) {
523
+ const conditions = [eq(sessions.userId, userId)];
524
+ if (excludeSessionId !== void 0) {
525
+ conditions.push(ne(sessions.id, excludeSessionId));
526
+ }
527
+ await db.update(sessions).set({ twoFaSecret: null }).where(and(...conditions));
528
+ },
529
+ async findByIdWithDevice(id, userId) {
530
+ const rows = await db.select({
531
+ twoFaSecret: sessions.twoFaSecret,
532
+ deviceId: sessions.deviceId,
533
+ device: {
534
+ pushToken: devices.pushToken
535
+ }
536
+ }).from(sessions).leftJoin(devices, eq(sessions.deviceId, devices.id)).where(and(eq(sessions.id, id), eq(sessions.userId, userId))).limit(1);
537
+ if (!rows[0]) return null;
538
+ const row = rows[0];
539
+ const device = row.device;
540
+ return {
541
+ twoFaSecret: row.twoFaSecret,
542
+ deviceId: row.deviceId,
543
+ device: device?.pushToken ? { pushToken: device.pushToken } : null
544
+ };
545
+ },
546
+ async revokeByDevicePushToken(userId, pushToken, excludeSessionId) {
547
+ const deviceRows = await db.select({ id: devices.id }).from(devices).where(eq(devices.pushToken, pushToken)).limit(1);
548
+ if (!deviceRows[0]) return;
549
+ await db.update(sessions).set({ revokedAt: /* @__PURE__ */ new Date() }).where(
550
+ and(
551
+ eq(sessions.userId, userId),
552
+ ne(sessions.id, excludeSessionId),
553
+ isNull(sessions.revokedAt),
554
+ eq(sessions.deviceId, deviceRows[0].id)
555
+ )
556
+ );
557
+ },
558
+ async clearDeviceId(userId, deviceId) {
559
+ await db.update(sessions).set({ deviceId: null }).where(and(eq(sessions.userId, userId), eq(sessions.deviceId, deviceId)));
560
+ }
561
+ },
562
+ otp: {
563
+ async findValidByUserAndCode(userId, code) {
564
+ const rows = await db.select().from(otps).where(
565
+ and(eq(otps.userId, userId), eq(otps.code, code), gte(otps.expiresAt, /* @__PURE__ */ new Date()))
566
+ ).limit(1);
567
+ return rows[0] ?? null;
568
+ },
569
+ async create(data) {
570
+ const rows = await db.insert(otps).values(data).returning();
571
+ return rows[0];
572
+ },
573
+ async delete(id) {
574
+ await db.delete(otps).where(eq(otps.id, id));
575
+ }
576
+ },
577
+ passwordReset: {
578
+ async findById(id) {
579
+ const rows = await db.select({
580
+ id: passwordResets.id,
581
+ createdAt: passwordResets.createdAt,
582
+ userId: passwordResets.userId
583
+ }).from(passwordResets).where(eq(passwordResets.id, id)).limit(1);
584
+ return rows[0] ?? null;
585
+ },
586
+ async create(userId) {
587
+ const rows = await db.insert(passwordResets).values({ userId }).returning();
588
+ return rows[0];
589
+ },
590
+ async delete(id) {
591
+ await db.delete(passwordResets).where(eq(passwordResets.id, id));
592
+ },
593
+ async deleteAllByUserId(userId) {
594
+ await db.delete(passwordResets).where(eq(passwordResets.userId, userId));
595
+ }
596
+ },
597
+ device: {
598
+ async findByTokenSessionAndUser(pushToken, sessionId, userId) {
599
+ const rows = await db.select({ id: devices.id }).from(devices).where(eq(devices.pushToken, pushToken)).limit(1);
600
+ if (!rows[0]) return null;
601
+ if (tables.devicesToSessions && tables.devicesToUsers) {
602
+ const sessionLink = await db.select().from(tables.devicesToSessions).where(
603
+ and(
604
+ eq(tables.devicesToSessions.deviceId, rows[0].id),
605
+ eq(tables.devicesToSessions.sessionId, sessionId)
606
+ )
607
+ ).limit(1);
608
+ const userLink = await db.select().from(tables.devicesToUsers).where(
609
+ and(
610
+ eq(tables.devicesToUsers.deviceId, rows[0].id),
611
+ eq(tables.devicesToUsers.userId, userId)
612
+ )
613
+ ).limit(1);
614
+ if (!sessionLink[0] || !userLink[0]) return null;
615
+ }
616
+ return { id: rows[0].id };
617
+ },
618
+ async upsertByPushToken(pushToken, sessionId, userId) {
619
+ const existing = await db.select({ id: devices.id }).from(devices).where(eq(devices.pushToken, pushToken)).limit(1);
620
+ let deviceId;
621
+ if (existing[0]) {
622
+ deviceId = existing[0].id;
623
+ } else {
624
+ const insertedRows = await db.insert(devices).values({ pushToken }).returning({ id: devices.id });
625
+ deviceId = insertedRows[0].id;
626
+ }
627
+ if (tables.devicesToSessions) {
628
+ await db.insert(tables.devicesToSessions).values({ deviceId, sessionId }).onConflictDoNothing();
629
+ }
630
+ if (tables.devicesToUsers) {
631
+ await db.insert(tables.devicesToUsers).values({ deviceId, userId }).onConflictDoNothing();
632
+ }
633
+ await db.update(sessions).set({ deviceId }).where(eq(sessions.id, sessionId));
634
+ },
635
+ async findByUserAndToken(userId, pushToken) {
636
+ if (tables.devicesToUsers) {
637
+ const joinRows = await db.select({ id: devices.id }).from(devices).innerJoin(
638
+ tables.devicesToUsers,
639
+ eq(devices.id, tables.devicesToUsers.deviceId)
640
+ ).where(
641
+ and(
642
+ eq(devices.pushToken, pushToken),
643
+ eq(tables.devicesToUsers.userId, userId)
644
+ )
645
+ ).limit(1);
646
+ return joinRows[0] ? { id: joinRows[0].id } : null;
647
+ }
648
+ const rows = await db.select({ id: devices.id }).from(devices).where(eq(devices.pushToken, pushToken)).limit(1);
649
+ return rows[0] ? { id: rows[0].id } : null;
650
+ },
651
+ async disconnectUser(deviceId, userId) {
652
+ if (tables.devicesToUsers) {
653
+ await db.delete(tables.devicesToUsers).where(
654
+ and(
655
+ eq(tables.devicesToUsers.deviceId, deviceId),
656
+ eq(tables.devicesToUsers.userId, userId)
657
+ )
658
+ );
659
+ }
660
+ },
661
+ async hasRemainingUsers(deviceId) {
662
+ if (tables.devicesToUsers) {
663
+ const remainingRows = await db.select({ userId: tables.devicesToUsers.userId }).from(tables.devicesToUsers).where(eq(tables.devicesToUsers.deviceId, deviceId)).limit(1);
664
+ return remainingRows.length > 0;
665
+ }
666
+ return false;
667
+ },
668
+ async delete(id) {
669
+ await db.delete(devices).where(eq(devices.id, id));
670
+ }
671
+ },
672
+ admin: {
673
+ async findByUserId(userId) {
674
+ const rows = await db.select({ ip: admins.ip }).from(admins).where(eq(admins.userId, userId)).limit(1);
675
+ return rows[0] ?? null;
676
+ }
677
+ }
678
+ };
679
+ }
680
+
134
681
  // src/utilities/config.ts
135
682
  var defaultTokenSettings = {
136
683
  jwtExpiry: 30 * 24 * 60 * 60,
@@ -161,9 +708,16 @@ var defaultFeatures = {
161
708
  otpLogin: true
162
709
  };
163
710
  function createAuthConfig(config) {
711
+ if (!config.database && !config.prisma) {
712
+ throw new Error(
713
+ "@factiii/auth: Provide either a `database` adapter or a `prisma` client in config."
714
+ );
715
+ }
716
+ const database = config.database ?? createPrismaAdapter(config.prisma);
164
717
  const emailService = config.emailService ?? createNoopEmailAdapter();
165
718
  return {
166
719
  ...config,
720
+ database,
167
721
  features: { ...defaultFeatures, ...config.features },
168
722
  tokenSettings: { ...defaultTokenSettings, ...config.tokenSettings },
169
723
  cookieSettings: { ...defaultCookieSettings, ...config.cookieSettings },
@@ -281,6 +835,7 @@ function isTokenInvalidError(error) {
281
835
  function createAuthGuard(config, t) {
282
836
  const storageKeys = config.storageKeys ?? defaultStorageKeys;
283
837
  const cookieSettings = { ...defaultCookieSettings, ...config.cookieSettings };
838
+ const database = config.database ?? createPrismaAdapter(config.prisma);
284
839
  const revokeSession = async (ctx, sessionId, description, errorStack, path) => {
285
840
  clearAuthCookie(ctx.res, cookieSettings, storageKeys);
286
841
  if (config.hooks?.logError) {
@@ -317,15 +872,9 @@ ${errorStack}` : null,
317
872
  }
318
873
  if (sessionId) {
319
874
  try {
320
- await config.prisma.session.update({
321
- where: { id: sessionId },
322
- data: { revokedAt: /* @__PURE__ */ new Date() }
323
- });
875
+ await database.session.revoke(sessionId);
324
876
  if (config.hooks?.onSessionRevoked) {
325
- const session = await config.prisma.session.findUnique({
326
- where: { id: sessionId },
327
- select: { id: true, userId: true, socketId: true }
328
- });
877
+ const session = await database.session.findById(sessionId);
329
878
  if (session) {
330
879
  await config.hooks.onSessionRevoked(session.userId, session.socketId, description);
331
880
  }
@@ -350,23 +899,7 @@ ${errorStack}` : null,
350
899
  secret: config.secrets.jwt,
351
900
  ignoreExpiration: meta?.ignoreExpiration ?? false
352
901
  });
353
- const session = await config.prisma.session.findUnique({
354
- where: {
355
- id: decodedToken.id
356
- },
357
- select: {
358
- userId: true,
359
- user: {
360
- select: {
361
- status: true,
362
- verifiedHumanAt: true
363
- }
364
- },
365
- revokedAt: true,
366
- socketId: true,
367
- id: true
368
- }
369
- });
902
+ const session = await database.session.findById(decodedToken.id);
370
903
  if (!session) {
371
904
  await revokeSession(
372
905
  ctx,
@@ -420,10 +953,7 @@ ${errorStack}` : null,
420
953
  });
421
954
  }
422
955
  if (meta?.adminRequired) {
423
- const admin = await config.prisma.admin.findFirst({
424
- where: { userId: session.userId },
425
- select: { ip: true }
426
- });
956
+ const admin = await database.admin.findByUserId(session.userId);
427
957
  if (!admin || admin.ip !== ctx.ip) {
428
958
  await revokeSession(
429
959
  ctx,
@@ -613,6 +1143,36 @@ function validatePasswordStrength(password, minLength = 6) {
613
1143
  return { valid: true };
614
1144
  }
615
1145
 
1146
+ // src/utilities/session.ts
1147
+ async function createSessionWithToken(config, params) {
1148
+ const { userId, browserName, socketId, deviceId, extraSessionData } = params;
1149
+ const session = await config.database.session.create({
1150
+ userId,
1151
+ browserName,
1152
+ socketId,
1153
+ ...deviceId != null ? { deviceId } : {},
1154
+ ...extraSessionData
1155
+ });
1156
+ const user = await config.database.user.findById(userId);
1157
+ const accessToken = createAuthToken(
1158
+ {
1159
+ id: session.id,
1160
+ userId: session.userId,
1161
+ verifiedHumanAt: user?.verifiedHumanAt ?? null
1162
+ },
1163
+ {
1164
+ secret: config.secrets.jwt,
1165
+ expiresIn: config.tokenSettings.jwtExpiry
1166
+ }
1167
+ );
1168
+ return { accessToken, sessionId: session.id };
1169
+ }
1170
+ async function createSessionWithTokenAndCookie(config, params, res) {
1171
+ const result = await createSessionWithToken(config, params);
1172
+ setAuthCookie(res, result.accessToken, config.cookieSettings, config.storageKeys);
1173
+ return result;
1174
+ }
1175
+
616
1176
  // src/utilities/totp.ts
617
1177
  var import_crypto = __toESM(require("crypto"));
618
1178
  var import_totp_generator = require("totp-generator");
@@ -756,19 +1316,14 @@ var BaseProcedureFactory = class {
756
1316
  if (this.config.hooks?.beforeRegister) {
757
1317
  await this.config.hooks.beforeRegister(typedInput);
758
1318
  }
759
- const usernameCheck = await this.config.prisma.user.findFirst({
760
- where: { username: { equals: username, mode: "insensitive" } }
761
- });
1319
+ const usernameCheck = await this.config.database.user.findByUsernameInsensitive(username);
762
1320
  if (usernameCheck) {
763
1321
  throw new import_server2.TRPCError({
764
1322
  code: "CONFLICT",
765
1323
  message: "An account already exists with that username."
766
1324
  });
767
1325
  }
768
- const emailCheck = await this.config.prisma.user.findFirst({
769
- where: { email: { equals: email, mode: "insensitive" } },
770
- select: { id: true }
771
- });
1326
+ const emailCheck = await this.config.database.user.findByEmailInsensitive(email);
772
1327
  if (emailCheck) {
773
1328
  throw new import_server2.TRPCError({
774
1329
  code: "CONFLICT",
@@ -776,30 +1331,25 @@ var BaseProcedureFactory = class {
776
1331
  });
777
1332
  }
778
1333
  const hashedPassword = await hashPassword(password);
779
- const user = await this.config.prisma.user.create({
780
- data: {
781
- username,
782
- email,
783
- password: hashedPassword,
784
- status: "ACTIVE",
785
- tag: this.config.features.biometric ? "BOT" : "HUMAN",
786
- twoFaEnabled: false,
787
- emailVerificationStatus: "UNVERIFIED",
788
- verifiedHumanAt: null
789
- }
1334
+ const user = await this.config.database.user.create({
1335
+ username,
1336
+ email,
1337
+ password: hashedPassword,
1338
+ status: "ACTIVE",
1339
+ tag: this.config.features.biometric ? "BOT" : "HUMAN",
1340
+ twoFaEnabled: false,
1341
+ emailVerificationStatus: "UNVERIFIED",
1342
+ verifiedHumanAt: null
790
1343
  });
791
1344
  if (this.config.hooks?.onUserCreated) {
792
1345
  await this.config.hooks.onUserCreated(user.id, typedInput);
793
1346
  }
794
1347
  const extraSessionData = this.config.hooks?.getSessionData ? await this.config.hooks.getSessionData(typedInput) : {};
795
- const session = await this.config.prisma.session.create({
796
- data: {
797
- userId: user.id,
798
- browserName: detectBrowser(userAgent),
799
- socketId: null,
800
- ...extraSessionData
801
- },
802
- select: { id: true, userId: true }
1348
+ const session = await this.config.database.session.create({
1349
+ userId: user.id,
1350
+ browserName: detectBrowser(userAgent),
1351
+ socketId: null,
1352
+ ...extraSessionData
803
1353
  });
804
1354
  if (this.config.hooks?.onSessionCreated) {
805
1355
  await this.config.hooks.onSessionCreated(session.id, typedInput);
@@ -837,24 +1387,7 @@ var BaseProcedureFactory = class {
837
1387
  if (this.config.hooks?.beforeLogin) {
838
1388
  await this.config.hooks.beforeLogin(typedInput);
839
1389
  }
840
- const user = await this.config.prisma.user.findFirst({
841
- where: {
842
- OR: [
843
- { email: { equals: username, mode: "insensitive" } },
844
- { username: { equals: username, mode: "insensitive" } }
845
- ]
846
- },
847
- select: {
848
- id: true,
849
- status: true,
850
- password: true,
851
- twoFaEnabled: true,
852
- email: true,
853
- username: true,
854
- oauthProvider: true,
855
- verifiedHumanAt: true
856
- }
857
- });
1390
+ const user = await this.config.database.user.findByEmailOrUsernameInsensitive(username);
858
1391
  if (!user) {
859
1392
  throw new import_server2.TRPCError({
860
1393
  code: "FORBIDDEN",
@@ -895,10 +1428,7 @@ var BaseProcedureFactory = class {
895
1428
  };
896
1429
  }
897
1430
  let validCode = false;
898
- const secrets = await this.config.prisma.session.findMany({
899
- where: { userId: user.id, twoFaSecret: { not: null } },
900
- select: { twoFaSecret: true }
901
- });
1431
+ const secrets = await this.config.database.session.findTwoFaSecretsByUserId(user.id);
902
1432
  for (const s of secrets) {
903
1433
  if (s.twoFaSecret && await verifyTotp(code, cleanBase32String(s.twoFaSecret))) {
904
1434
  validCode = true;
@@ -906,14 +1436,13 @@ var BaseProcedureFactory = class {
906
1436
  }
907
1437
  }
908
1438
  if (!validCode) {
909
- const checkOTP = await this.config.prisma.oTP.findFirst({
910
- where: { userId: user.id, code: Number(code), expiresAt: { gte: /* @__PURE__ */ new Date() } }
911
- });
1439
+ const checkOTP = await this.config.database.otp.findValidByUserAndCode(
1440
+ user.id,
1441
+ Number(code)
1442
+ );
912
1443
  if (checkOTP) {
913
1444
  validCode = true;
914
- await this.config.prisma.oTP.delete({
915
- where: { id: checkOTP.id }
916
- });
1445
+ await this.config.database.otp.delete(checkOTP.id);
917
1446
  }
918
1447
  }
919
1448
  if (!validCode) {
@@ -924,24 +1453,11 @@ var BaseProcedureFactory = class {
924
1453
  }
925
1454
  }
926
1455
  const extraSessionData = this.config.hooks?.getSessionData ? await this.config.hooks.getSessionData(typedInput) : {};
927
- const session = await this.config.prisma.session.create({
928
- data: {
929
- userId: user.id,
930
- browserName: detectBrowser(userAgent),
931
- socketId: null,
932
- ...extraSessionData
933
- },
934
- select: {
935
- id: true,
936
- userId: true,
937
- socketId: true,
938
- browserName: true,
939
- issuedAt: true,
940
- lastUsed: true,
941
- revokedAt: true,
942
- deviceId: true,
943
- twoFaSecret: true
944
- }
1456
+ const session = await this.config.database.session.create({
1457
+ userId: user.id,
1458
+ browserName: detectBrowser(userAgent),
1459
+ socketId: null,
1460
+ ...extraSessionData
945
1461
  });
946
1462
  if (this.config.hooks?.onUserLogin) {
947
1463
  await this.config.hooks.onUserLogin(user.id, session.id);
@@ -972,15 +1488,9 @@ var BaseProcedureFactory = class {
972
1488
  return this.authProcedure.meta({ ignoreExpiration: true }).mutation(async ({ ctx }) => {
973
1489
  const { userId, sessionId } = ctx;
974
1490
  if (sessionId) {
975
- await this.config.prisma.session.update({
976
- where: { id: sessionId },
977
- data: { revokedAt: /* @__PURE__ */ new Date() }
978
- });
1491
+ await this.config.database.session.revoke(sessionId);
979
1492
  if (userId) {
980
- await this.config.prisma.user.update({
981
- where: { id: userId },
982
- data: { isActive: false }
983
- });
1493
+ await this.config.database.user.update(userId, { isActive: false });
984
1494
  }
985
1495
  if (this.config.hooks?.afterLogout) {
986
1496
  await this.config.hooks.afterLogout(userId, sessionId, ctx.socketId);
@@ -992,15 +1502,7 @@ var BaseProcedureFactory = class {
992
1502
  }
993
1503
  refresh() {
994
1504
  return this.authProcedure.query(async ({ ctx }) => {
995
- const session = await this.config.prisma.session.update({
996
- where: { id: ctx.sessionId },
997
- data: { lastUsed: /* @__PURE__ */ new Date() },
998
- select: {
999
- id: true,
1000
- userId: true,
1001
- user: { select: { verifiedHumanAt: true } }
1002
- }
1003
- });
1505
+ const session = await this.config.database.session.updateLastUsed(ctx.sessionId);
1004
1506
  if (this.config.hooks?.onRefresh) {
1005
1507
  this.config.hooks.onRefresh(session.userId).catch(() => {
1006
1508
  });
@@ -1025,22 +1527,14 @@ var BaseProcedureFactory = class {
1025
1527
  return this.authProcedure.input(endAllSessionsSchema).mutation(async ({ ctx, input }) => {
1026
1528
  const { skipCurrentSession } = input;
1027
1529
  const { userId, sessionId } = ctx;
1028
- const sessionsToRevoke = await this.config.prisma.session.findMany({
1029
- where: {
1030
- userId,
1031
- revokedAt: null,
1032
- ...skipCurrentSession ? { NOT: { id: sessionId } } : {}
1033
- },
1034
- select: { socketId: true, id: true, userId: true }
1035
- });
1036
- await this.config.prisma.session.updateMany({
1037
- where: {
1038
- userId,
1039
- revokedAt: null,
1040
- ...skipCurrentSession ? { NOT: { id: sessionId } } : {}
1041
- },
1042
- data: { revokedAt: /* @__PURE__ */ new Date() }
1043
- });
1530
+ const sessionsToRevoke = await this.config.database.session.findActiveByUserId(
1531
+ userId,
1532
+ skipCurrentSession ? sessionId : void 0
1533
+ );
1534
+ await this.config.database.session.revokeAllByUserId(
1535
+ userId,
1536
+ skipCurrentSession ? sessionId : void 0
1537
+ );
1044
1538
  for (const session of sessionsToRevoke) {
1045
1539
  if (this.config.hooks?.onSessionRevoked) {
1046
1540
  await this.config.hooks.onSessionRevoked(
@@ -1051,10 +1545,7 @@ var BaseProcedureFactory = class {
1051
1545
  }
1052
1546
  }
1053
1547
  if (!skipCurrentSession) {
1054
- await this.config.prisma.user.update({
1055
- where: { id: userId },
1056
- data: { isActive: false }
1057
- });
1548
+ await this.config.database.user.update(userId, { isActive: false });
1058
1549
  }
1059
1550
  return { success: true, revokedCount: sessionsToRevoke.length };
1060
1551
  });
@@ -1069,10 +1560,7 @@ var BaseProcedureFactory = class {
1069
1560
  message: "New password cannot be the same as current password"
1070
1561
  });
1071
1562
  }
1072
- const user = await this.config.prisma.user.findUnique({
1073
- where: { id: userId },
1074
- select: { password: true }
1075
- });
1563
+ const user = await this.config.database.user.findById(userId);
1076
1564
  if (!user) {
1077
1565
  throw new import_server2.TRPCError({ code: "NOT_FOUND", message: "User not found" });
1078
1566
  }
@@ -1090,14 +1578,8 @@ var BaseProcedureFactory = class {
1090
1578
  });
1091
1579
  }
1092
1580
  const hashedPassword = await hashPassword(newPassword);
1093
- await this.config.prisma.user.update({
1094
- where: { id: userId },
1095
- data: { password: hashedPassword }
1096
- });
1097
- await this.config.prisma.session.updateMany({
1098
- where: { userId, revokedAt: null, NOT: { id: sessionId } },
1099
- data: { revokedAt: /* @__PURE__ */ new Date() }
1100
- });
1581
+ await this.config.database.user.update(userId, { password: hashedPassword });
1582
+ await this.config.database.session.revokeAllByUserId(userId, sessionId);
1101
1583
  if (this.config.hooks?.onPasswordChanged) {
1102
1584
  await this.config.hooks.onPasswordChanged(userId);
1103
1585
  }
@@ -1110,11 +1592,8 @@ var BaseProcedureFactory = class {
1110
1592
  sendPasswordResetEmail() {
1111
1593
  return this.procedure.input(requestPasswordResetSchema).mutation(async ({ input }) => {
1112
1594
  const { email } = input;
1113
- const user = await this.config.prisma.user.findFirst({
1114
- where: { email: { equals: email, mode: "insensitive" }, status: "ACTIVE" },
1115
- select: { id: true, password: true, email: true }
1116
- });
1117
- if (!user) {
1595
+ const user = await this.config.database.user.findByEmailInsensitive(email);
1596
+ if (!user || user.status !== "ACTIVE") {
1118
1597
  return { message: "If an account exists with that email, a reset link has been sent." };
1119
1598
  }
1120
1599
  if (!user.password) {
@@ -1123,10 +1602,8 @@ var BaseProcedureFactory = class {
1123
1602
  message: "This account uses social login. Please use that method."
1124
1603
  });
1125
1604
  }
1126
- await this.config.prisma.passwordReset.deleteMany({ where: { userId: user.id } });
1127
- const passwordReset = await this.config.prisma.passwordReset.create({
1128
- data: { userId: user.id }
1129
- });
1605
+ await this.config.database.passwordReset.deleteAllByUserId(user.id);
1606
+ const passwordReset = await this.config.database.passwordReset.create(user.id);
1130
1607
  if (this.config.emailService) {
1131
1608
  await this.config.emailService.sendPasswordResetEmail(user.email, String(passwordReset.id));
1132
1609
  }
@@ -1136,15 +1613,12 @@ var BaseProcedureFactory = class {
1136
1613
  checkPasswordReset() {
1137
1614
  return this.procedure.input(checkPasswordResetSchema).query(async ({ input }) => {
1138
1615
  const { token } = input;
1139
- const passwordReset = await this.config.prisma.passwordReset.findUnique({
1140
- where: { id: token },
1141
- select: { id: true, createdAt: true, userId: true }
1142
- });
1616
+ const passwordReset = await this.config.database.passwordReset.findById(token);
1143
1617
  if (!passwordReset) {
1144
1618
  throw new import_server2.TRPCError({ code: "NOT_FOUND", message: "Invalid reset token." });
1145
1619
  }
1146
1620
  if (passwordReset.createdAt.getTime() + this.config.tokenSettings.passwordResetExpiryMs < Date.now()) {
1147
- await this.config.prisma.passwordReset.delete({ where: { id: token } });
1621
+ await this.config.database.passwordReset.delete(token);
1148
1622
  throw new import_server2.TRPCError({ code: "FORBIDDEN", message: "Reset token expired." });
1149
1623
  }
1150
1624
  return { valid: true };
@@ -1153,31 +1627,23 @@ var BaseProcedureFactory = class {
1153
1627
  resetPassword() {
1154
1628
  return this.procedure.input(resetPasswordSchema).mutation(async ({ input }) => {
1155
1629
  const { token, password } = input;
1156
- const passwordReset = await this.config.prisma.passwordReset.findFirst({
1157
- where: { id: token },
1158
- select: { id: true, createdAt: true, userId: true }
1159
- });
1630
+ const passwordReset = await this.config.database.passwordReset.findById(token);
1160
1631
  if (!passwordReset) {
1161
1632
  throw new import_server2.TRPCError({ code: "NOT_FOUND", message: "Invalid reset token." });
1162
1633
  }
1163
1634
  if (passwordReset.createdAt.getTime() + this.config.tokenSettings.passwordResetExpiryMs < Date.now()) {
1164
- await this.config.prisma.passwordReset.delete({ where: { id: token } });
1635
+ await this.config.database.passwordReset.delete(token);
1165
1636
  throw new import_server2.TRPCError({ code: "FORBIDDEN", message: "Reset token expired." });
1166
1637
  }
1167
1638
  const hashedPassword = await hashPassword(password);
1168
- await this.config.prisma.user.update({
1169
- where: { id: passwordReset.userId },
1170
- data: { password: hashedPassword }
1171
- });
1172
- await this.config.prisma.passwordReset.delete({ where: { id: token } });
1173
- const sessionsToRevoke = await this.config.prisma.session.findMany({
1174
- where: { userId: passwordReset.userId, revokedAt: null },
1175
- select: { id: true, socketId: true, userId: true }
1176
- });
1177
- await this.config.prisma.session.updateMany({
1178
- where: { userId: passwordReset.userId, revokedAt: null },
1179
- data: { revokedAt: /* @__PURE__ */ new Date() }
1639
+ await this.config.database.user.update(passwordReset.userId, {
1640
+ password: hashedPassword
1180
1641
  });
1642
+ await this.config.database.passwordReset.delete(token);
1643
+ const sessionsToRevoke = await this.config.database.session.findActiveByUserId(
1644
+ passwordReset.userId
1645
+ );
1646
+ await this.config.database.session.revokeAllByUserId(passwordReset.userId);
1181
1647
  for (const session of sessionsToRevoke) {
1182
1648
  if (this.config.hooks?.onSessionRevoked) {
1183
1649
  await this.config.hooks.onSessionRevoked(
@@ -1214,9 +1680,9 @@ var BiometricProcedureFactory = class {
1214
1680
  return this.authProcedure.input(biometricVerifySchema).mutation(async ({ ctx }) => {
1215
1681
  this.checkConfig();
1216
1682
  const { userId } = ctx;
1217
- await this.config.prisma.user.update({
1218
- where: { id: userId },
1219
- data: { verifiedHumanAt: /* @__PURE__ */ new Date(), tag: "HUMAN" }
1683
+ await this.config.database.user.update(userId, {
1684
+ verifiedHumanAt: /* @__PURE__ */ new Date(),
1685
+ tag: "HUMAN"
1220
1686
  });
1221
1687
  if (this.config.hooks?.onBiometricVerified) {
1222
1688
  await this.config.hooks.onBiometricVerified(userId);
@@ -1228,10 +1694,7 @@ var BiometricProcedureFactory = class {
1228
1694
  return this.authProcedure.query(async ({ ctx }) => {
1229
1695
  this.checkConfig();
1230
1696
  const { userId } = ctx;
1231
- const user = await this.config.prisma.user.findUnique({
1232
- where: { id: userId },
1233
- select: { verifiedHumanAt: true }
1234
- });
1697
+ const user = await this.config.database.user.findById(userId);
1235
1698
  if (!user) {
1236
1699
  throw new import_server3.TRPCError({ code: "NOT_FOUND", message: "User not found" });
1237
1700
  }
@@ -1278,10 +1741,7 @@ var EmailVerificationProcedureFactory = class {
1278
1741
  return this.authProcedure.mutation(async ({ ctx }) => {
1279
1742
  this.checkConfig();
1280
1743
  const { userId } = ctx;
1281
- const user = await this.config.prisma.user.findUnique({
1282
- where: { id: userId, status: "ACTIVE" },
1283
- select: { id: true, email: true, emailVerificationStatus: true }
1284
- });
1744
+ const user = await this.config.database.user.findActiveById(userId);
1285
1745
  if (!user) {
1286
1746
  throw new import_server4.TRPCError({ code: "NOT_FOUND", message: "User not found" });
1287
1747
  }
@@ -1289,9 +1749,9 @@ var EmailVerificationProcedureFactory = class {
1289
1749
  return { message: "Email is already verified", emailSent: false };
1290
1750
  }
1291
1751
  const otp = (0, import_node_crypto.randomUUID)();
1292
- await this.config.prisma.user.update({
1293
- where: { id: userId },
1294
- data: { emailVerificationStatus: "PENDING", otpForEmailVerification: otp }
1752
+ await this.config.database.user.update(userId, {
1753
+ emailVerificationStatus: "PENDING",
1754
+ otpForEmailVerification: otp
1295
1755
  });
1296
1756
  if (this.config.emailService) {
1297
1757
  try {
@@ -1309,10 +1769,7 @@ var EmailVerificationProcedureFactory = class {
1309
1769
  this.checkConfig();
1310
1770
  const { userId } = ctx;
1311
1771
  const { code } = input;
1312
- const user = await this.config.prisma.user.findUnique({
1313
- where: { id: userId, status: "ACTIVE" },
1314
- select: { id: true, emailVerificationStatus: true, otpForEmailVerification: true }
1315
- });
1772
+ const user = await this.config.database.user.findActiveById(userId);
1316
1773
  if (!user) {
1317
1774
  throw new import_server4.TRPCError({ code: "NOT_FOUND", message: "User not found" });
1318
1775
  }
@@ -1322,9 +1779,9 @@ var EmailVerificationProcedureFactory = class {
1322
1779
  if (code !== user.otpForEmailVerification) {
1323
1780
  throw new import_server4.TRPCError({ code: "BAD_REQUEST", message: "Invalid verification code" });
1324
1781
  }
1325
- await this.config.prisma.user.update({
1326
- where: { id: userId },
1327
- data: { emailVerificationStatus: "VERIFIED", otpForEmailVerification: null }
1782
+ await this.config.database.user.update(userId, {
1783
+ emailVerificationStatus: "VERIFIED",
1784
+ otpForEmailVerification: null
1328
1785
  });
1329
1786
  if (this.config.hooks?.onEmailVerified) {
1330
1787
  await this.config.hooks.onEmailVerified(userId);
@@ -1336,10 +1793,7 @@ var EmailVerificationProcedureFactory = class {
1336
1793
  return this.authProcedure.query(async ({ ctx }) => {
1337
1794
  this.checkConfig();
1338
1795
  const { userId } = ctx;
1339
- const user = await this.config.prisma.user.findUnique({
1340
- where: { id: userId },
1341
- select: { emailVerificationStatus: true, email: true }
1342
- });
1796
+ const user = await this.config.database.user.findById(userId);
1343
1797
  if (!user) {
1344
1798
  throw new import_server4.TRPCError({ code: "NOT_FOUND", message: "User not found" });
1345
1799
  }
@@ -1393,23 +1847,7 @@ var OAuthLoginProcedureFactory = class {
1393
1847
  message: "Email not provided by OAuth provider"
1394
1848
  });
1395
1849
  }
1396
- let user = await this.config.prisma.user.findFirst({
1397
- where: {
1398
- OR: [{ email: { equals: email, mode: "insensitive" } }, { oauthId: { equals: oauthId } }]
1399
- },
1400
- select: {
1401
- id: true,
1402
- status: true,
1403
- email: true,
1404
- username: true,
1405
- password: true,
1406
- oauthProvider: true,
1407
- oauthId: true,
1408
- twoFaEnabled: true,
1409
- verifiedHumanAt: true,
1410
- emailVerificationStatus: true
1411
- }
1412
- });
1850
+ let user = await this.config.database.user.findByEmailOrOAuthId(email, oauthId);
1413
1851
  if (user?.oauthProvider && user.oauthProvider !== provider) {
1414
1852
  throw new import_server5.TRPCError({
1415
1853
  code: "BAD_REQUEST",
@@ -1424,19 +1862,17 @@ var OAuthLoginProcedureFactory = class {
1424
1862
  }
1425
1863
  if (!user) {
1426
1864
  const generateUsername = this.config.generateUsername ?? (() => `user_${Date.now()}`);
1427
- user = await this.config.prisma.user.create({
1428
- data: {
1429
- username: generateUsername(),
1430
- email,
1431
- password: null,
1432
- emailVerificationStatus: "VERIFIED",
1433
- oauthProvider: provider,
1434
- oauthId,
1435
- status: "ACTIVE",
1436
- tag: this.config.features.biometric ? "BOT" : "HUMAN",
1437
- twoFaEnabled: false,
1438
- verifiedHumanAt: null
1439
- }
1865
+ user = await this.config.database.user.create({
1866
+ username: generateUsername(),
1867
+ email,
1868
+ password: null,
1869
+ emailVerificationStatus: "VERIFIED",
1870
+ oauthProvider: provider,
1871
+ oauthId,
1872
+ status: "ACTIVE",
1873
+ tag: this.config.features.biometric ? "BOT" : "HUMAN",
1874
+ twoFaEnabled: false,
1875
+ verifiedHumanAt: null
1440
1876
  });
1441
1877
  if (this.config.hooks?.onUserCreated) {
1442
1878
  await this.config.hooks.onUserCreated(user.id, typedInput);
@@ -1452,24 +1888,11 @@ var OAuthLoginProcedureFactory = class {
1452
1888
  throw new import_server5.TRPCError({ code: "FORBIDDEN", message: "Your account has been banned." });
1453
1889
  }
1454
1890
  const extraSessionData = this.config.hooks?.getSessionData ? await this.config.hooks.getSessionData(typedInput) : {};
1455
- const session = await this.config.prisma.session.create({
1456
- data: {
1457
- userId: user.id,
1458
- browserName: detectBrowser(userAgent),
1459
- socketId: null,
1460
- ...extraSessionData
1461
- },
1462
- select: {
1463
- id: true,
1464
- userId: true,
1465
- socketId: true,
1466
- browserName: true,
1467
- issuedAt: true,
1468
- lastUsed: true,
1469
- revokedAt: true,
1470
- deviceId: true,
1471
- twoFaSecret: true
1472
- }
1891
+ const session = await this.config.database.session.create({
1892
+ userId: user.id,
1893
+ browserName: detectBrowser(userAgent),
1894
+ socketId: null,
1895
+ ...extraSessionData
1473
1896
  });
1474
1897
  if (this.config.hooks?.onUserLogin) {
1475
1898
  await this.config.hooks.onUserLogin(user.id, session.id);
@@ -1526,10 +1949,7 @@ var TwoFaProcedureFactory = class {
1526
1949
  return this.authProcedure.mutation(async ({ ctx }) => {
1527
1950
  this.checkConfig();
1528
1951
  const { userId, sessionId } = ctx;
1529
- const user = await this.config.prisma.user.findFirst({
1530
- where: { id: userId },
1531
- select: { twoFaEnabled: true, oauthProvider: true, password: true }
1532
- });
1952
+ const user = await this.config.database.user.findById(userId);
1533
1953
  if (!user) {
1534
1954
  throw new import_server6.TRPCError({ code: "NOT_FOUND", message: "User not found." });
1535
1955
  }
@@ -1543,10 +1963,7 @@ var TwoFaProcedureFactory = class {
1543
1963
  throw new import_server6.TRPCError({ code: "BAD_REQUEST", message: "2FA already enabled." });
1544
1964
  }
1545
1965
  if (this.config.features.twoFaRequiresDevice !== false) {
1546
- const checkSession = await this.config.prisma.session.findFirst({
1547
- where: { userId, id: sessionId },
1548
- select: { deviceId: true }
1549
- });
1966
+ const checkSession = await this.config.database.session.findById(sessionId);
1550
1967
  if (!checkSession?.deviceId) {
1551
1968
  throw new import_server6.TRPCError({
1552
1969
  code: "BAD_REQUEST",
@@ -1554,23 +1971,11 @@ var TwoFaProcedureFactory = class {
1554
1971
  });
1555
1972
  }
1556
1973
  }
1557
- await this.config.prisma.session.updateMany({
1558
- where: { userId, revokedAt: null, NOT: { id: sessionId } },
1559
- data: { revokedAt: /* @__PURE__ */ new Date() }
1560
- });
1561
- await this.config.prisma.session.updateMany({
1562
- where: { userId, NOT: { id: sessionId } },
1563
- data: { twoFaSecret: null }
1564
- });
1974
+ await this.config.database.session.revokeAllByUserId(userId, sessionId);
1975
+ await this.config.database.session.clearTwoFaSecrets(userId, sessionId);
1565
1976
  const secret = generateTotpSecret();
1566
- await this.config.prisma.user.update({
1567
- where: { id: userId },
1568
- data: { twoFaEnabled: true }
1569
- });
1570
- await this.config.prisma.session.update({
1571
- where: { id: sessionId },
1572
- data: { twoFaSecret: secret }
1573
- });
1977
+ await this.config.database.user.update(userId, { twoFaEnabled: true });
1978
+ await this.config.database.session.update(sessionId, { twoFaSecret: secret });
1574
1979
  if (this.config.hooks?.onTwoFaStatusChanged) {
1575
1980
  await this.config.hooks.onTwoFaStatusChanged(userId, true);
1576
1981
  }
@@ -1582,10 +1987,7 @@ var TwoFaProcedureFactory = class {
1582
1987
  this.checkConfig();
1583
1988
  const { userId, sessionId } = ctx;
1584
1989
  const { password } = input;
1585
- const user = await this.config.prisma.user.findFirst({
1586
- where: { id: userId },
1587
- select: { password: true, status: true, oauthProvider: true }
1588
- });
1990
+ const user = await this.config.database.user.findById(userId);
1589
1991
  if (!user) {
1590
1992
  throw new import_server6.TRPCError({ code: "NOT_FOUND", message: "User not found." });
1591
1993
  }
@@ -1608,14 +2010,8 @@ var TwoFaProcedureFactory = class {
1608
2010
  if (!isMatch) {
1609
2011
  throw new import_server6.TRPCError({ code: "FORBIDDEN", message: "Incorrect password." });
1610
2012
  }
1611
- await this.config.prisma.user.update({
1612
- where: { id: userId },
1613
- data: { twoFaEnabled: false }
1614
- });
1615
- await this.config.prisma.session.update({
1616
- where: { id: sessionId },
1617
- data: { twoFaSecret: null }
1618
- });
2013
+ await this.config.database.user.update(userId, { twoFaEnabled: false });
2014
+ await this.config.database.session.update(sessionId, { twoFaSecret: null });
1619
2015
  if (this.config.hooks?.onTwoFaStatusChanged) {
1620
2016
  await this.config.hooks.onTwoFaStatusChanged(userId, false);
1621
2017
  }
@@ -1627,10 +2023,7 @@ var TwoFaProcedureFactory = class {
1627
2023
  this.checkConfig();
1628
2024
  const { userId, sessionId } = ctx;
1629
2025
  const { pushCode } = input;
1630
- const user = await this.config.prisma.user.findFirst({
1631
- where: { id: userId },
1632
- select: { twoFaEnabled: true, oauthProvider: true }
1633
- });
2026
+ const user = await this.config.database.user.findById(userId);
1634
2027
  if (user?.oauthProvider) {
1635
2028
  throw new import_server6.TRPCError({
1636
2029
  code: "FORBIDDEN",
@@ -1640,10 +2033,7 @@ var TwoFaProcedureFactory = class {
1640
2033
  if (!user?.twoFaEnabled) {
1641
2034
  throw new import_server6.TRPCError({ code: "BAD_REQUEST", message: "2FA not enabled." });
1642
2035
  }
1643
- const session = await this.config.prisma.session.findUnique({
1644
- where: { id: sessionId, userId },
1645
- select: { twoFaSecret: true, device: { select: { pushToken: true } } }
1646
- });
2036
+ const session = await this.config.database.session.findByIdWithDevice(sessionId, userId);
1647
2037
  if (!session?.device) {
1648
2038
  throw new import_server6.TRPCError({ code: "BAD_REQUEST", message: "Invalid request" });
1649
2039
  }
@@ -1655,10 +2045,7 @@ var TwoFaProcedureFactory = class {
1655
2045
  return { secret: session.twoFaSecret };
1656
2046
  }
1657
2047
  const secret = generateTotpSecret();
1658
- await this.config.prisma.session.update({
1659
- where: { id: sessionId },
1660
- data: { twoFaSecret: secret }
1661
- });
2048
+ await this.config.database.session.update(sessionId, { twoFaSecret: secret });
1662
2049
  return { secret };
1663
2050
  });
1664
2051
  }
@@ -1666,11 +2053,8 @@ var TwoFaProcedureFactory = class {
1666
2053
  return this.procedure.input(twoFaResetSchema).mutation(async ({ input }) => {
1667
2054
  this.checkConfig();
1668
2055
  const { username, password } = input;
1669
- const user = await this.config.prisma.user.findFirst({
1670
- where: { username: { equals: username, mode: "insensitive" }, twoFaEnabled: true },
1671
- select: { id: true, password: true, email: true }
1672
- });
1673
- if (!user) {
2056
+ const user = await this.config.database.user.findByUsernameInsensitive(username);
2057
+ if (!user || !user.twoFaEnabled) {
1674
2058
  throw new import_server6.TRPCError({ code: "UNAUTHORIZED", message: "Invalid credentials." });
1675
2059
  }
1676
2060
  if (!user.password) {
@@ -1685,9 +2069,7 @@ var TwoFaProcedureFactory = class {
1685
2069
  }
1686
2070
  const otp = generateOtp();
1687
2071
  const expiresAt = new Date(Date.now() + this.config.tokenSettings.otpValidityMs);
1688
- await this.config.prisma.oTP.create({
1689
- data: { userId: user.id, code: otp, expiresAt }
1690
- });
2072
+ await this.config.database.otp.create({ userId: user.id, code: otp, expiresAt });
1691
2073
  if (this.config.emailService) {
1692
2074
  await this.config.emailService.sendOTPEmail(user.email, otp);
1693
2075
  }
@@ -1698,30 +2080,17 @@ var TwoFaProcedureFactory = class {
1698
2080
  return this.procedure.input(twoFaResetVerifySchema).mutation(async ({ input }) => {
1699
2081
  this.checkConfig();
1700
2082
  const { code, username } = input;
1701
- const user = await this.config.prisma.user.findFirst({
1702
- where: { username: { equals: username, mode: "insensitive" } },
1703
- select: { id: true }
1704
- });
2083
+ const user = await this.config.database.user.findByUsernameInsensitive(username);
1705
2084
  if (!user) {
1706
2085
  throw new import_server6.TRPCError({ code: "NOT_FOUND", message: "User not found" });
1707
2086
  }
1708
- const otp = await this.config.prisma.oTP.findFirst({
1709
- where: { userId: user.id, code, expiresAt: { gte: /* @__PURE__ */ new Date() } }
1710
- });
2087
+ const otp = await this.config.database.otp.findValidByUserAndCode(user.id, code);
1711
2088
  if (!otp) {
1712
2089
  throw new import_server6.TRPCError({ code: "FORBIDDEN", message: "Invalid or expired OTP" });
1713
2090
  }
1714
- await this.config.prisma.oTP.delete({
1715
- where: { id: otp.id }
1716
- });
1717
- await this.config.prisma.user.update({
1718
- where: { id: user.id },
1719
- data: { twoFaEnabled: false }
1720
- });
1721
- await this.config.prisma.session.updateMany({
1722
- where: { userId: user.id },
1723
- data: { twoFaSecret: null }
1724
- });
2091
+ await this.config.database.otp.delete(otp.id);
2092
+ await this.config.database.user.update(user.id, { twoFaEnabled: false });
2093
+ await this.config.database.session.clearTwoFaSecrets(user.id);
1725
2094
  return { success: true, message: "2FA has been reset." };
1726
2095
  });
1727
2096
  }
@@ -1730,36 +2099,14 @@ var TwoFaProcedureFactory = class {
1730
2099
  this.checkConfig();
1731
2100
  const { userId, sessionId } = ctx;
1732
2101
  const { pushToken } = input;
1733
- await this.config.prisma.session.updateMany({
1734
- where: {
1735
- userId,
1736
- id: { not: sessionId },
1737
- revokedAt: null,
1738
- device: { pushToken }
1739
- },
1740
- data: { revokedAt: /* @__PURE__ */ new Date() }
1741
- });
1742
- const checkDevice = await this.config.prisma.device.findFirst({
1743
- where: {
1744
- pushToken,
1745
- sessions: { some: { id: sessionId } },
1746
- users: { some: { id: userId } }
1747
- },
1748
- select: { id: true }
1749
- });
2102
+ await this.config.database.session.revokeByDevicePushToken(userId, pushToken, sessionId);
2103
+ const checkDevice = await this.config.database.device.findByTokenSessionAndUser(
2104
+ pushToken,
2105
+ sessionId,
2106
+ userId
2107
+ );
1750
2108
  if (!checkDevice) {
1751
- await this.config.prisma.device.upsert({
1752
- where: { pushToken },
1753
- create: {
1754
- pushToken,
1755
- sessions: { connect: { id: sessionId } },
1756
- users: { connect: { id: userId } }
1757
- },
1758
- update: {
1759
- sessions: { connect: { id: sessionId } },
1760
- users: { connect: { id: userId } }
1761
- }
1762
- });
2109
+ await this.config.database.device.upsertByPushToken(pushToken, sessionId, userId);
1763
2110
  }
1764
2111
  return { registered: true };
1765
2112
  });
@@ -1769,30 +2116,13 @@ var TwoFaProcedureFactory = class {
1769
2116
  this.checkConfig();
1770
2117
  const { userId } = ctx;
1771
2118
  const { pushToken } = input;
1772
- const device = await this.config.prisma.device.findFirst({
1773
- where: {
1774
- users: { some: { id: userId } },
1775
- pushToken
1776
- },
1777
- select: { id: true }
1778
- });
2119
+ const device = await this.config.database.device.findByUserAndToken(userId, pushToken);
1779
2120
  if (device) {
1780
- await this.config.prisma.session.updateMany({
1781
- where: { userId, deviceId: device.id },
1782
- data: { deviceId: null }
1783
- });
1784
- await this.config.prisma.device.update({
1785
- where: { id: device.id },
1786
- data: { users: { disconnect: { id: userId } } }
1787
- });
1788
- const remainingUsers = await this.config.prisma.device.findUnique({
1789
- where: { id: device.id },
1790
- select: { users: { select: { id: true }, take: 1 } }
1791
- });
1792
- if (!remainingUsers?.users.length) {
1793
- await this.config.prisma.device.delete({
1794
- where: { id: device.id }
1795
- });
2121
+ await this.config.database.session.clearDeviceId(userId, device.id);
2122
+ await this.config.database.device.disconnectUser(device.id, userId);
2123
+ const hasUsers = await this.config.database.device.hasRemainingUsers(device.id);
2124
+ if (!hasUsers) {
2125
+ await this.config.database.device.delete(device.id);
1796
2126
  }
1797
2127
  }
1798
2128
  return { deregistered: true };
@@ -1804,13 +2134,15 @@ var TwoFaProcedureFactory = class {
1804
2134
  var import_server7 = require("@trpc/server");
1805
2135
  var import_superjson = __toESM(require("superjson"));
1806
2136
  var import_zod2 = require("zod");
2137
+ function hasStringProp(obj, key) {
2138
+ return typeof obj === "object" && obj !== null && key in obj && typeof obj[key] === "string";
2139
+ }
1807
2140
  function isPrismaConnectionError(error) {
1808
2141
  if (!error || typeof error !== "object") {
1809
2142
  return false;
1810
2143
  }
1811
- const errorCode = error.code;
1812
- if (errorCode && typeof errorCode === "string") {
1813
- const codeMatch = errorCode.match(/^P(\d+)$/);
2144
+ if (hasStringProp(error, "code")) {
2145
+ const codeMatch = error.code.match(/^P(\d+)$/);
1814
2146
  if (codeMatch) {
1815
2147
  const codeNum = parseInt(codeMatch[1], 10);
1816
2148
  if (codeNum >= 1e3 && codeNum <= 1003) {
@@ -1820,14 +2152,13 @@ function isPrismaConnectionError(error) {
1820
2152
  }
1821
2153
  const constructorName = error.constructor?.name || "";
1822
2154
  if (constructorName.includes("Prisma")) {
1823
- const errorMessage = error.message?.toLowerCase() || "";
2155
+ const errorMessage = hasStringProp(error, "message") ? error.message.toLowerCase() : "";
1824
2156
  if (errorMessage.includes("can't reach database") || errorMessage.includes("authentication failed") || errorMessage.includes("database server") || errorMessage.includes("timeout") || errorMessage.includes("connection")) {
1825
2157
  return true;
1826
2158
  }
1827
2159
  }
1828
- const cause = error.cause;
1829
- if (cause) {
1830
- return isPrismaConnectionError(cause);
2160
+ if ("cause" in error) {
2161
+ return isPrismaConnectionError(error.cause);
1831
2162
  }
1832
2163
  return false;
1833
2164
  }
@@ -1873,8 +2204,9 @@ function createBaseProcedure(t, authGuard) {
1873
2204
  }
1874
2205
  function getClientIp(req) {
1875
2206
  const forwarded = req.headers["x-forwarded-for"];
1876
- if (forwarded) {
1877
- return forwarded.split(",")[0]?.trim();
2207
+ const forwardedStr = Array.isArray(forwarded) ? forwarded[0] : forwarded;
2208
+ if (forwardedStr) {
2209
+ return forwardedStr.split(",")[0]?.trim();
1878
2210
  }
1879
2211
  return req.socket.remoteAddress || void 0;
1880
2212
  }
@@ -1892,7 +2224,7 @@ var AuthRouterFactory = class {
1892
2224
  constructor(userConfig) {
1893
2225
  this.userConfig = userConfig;
1894
2226
  this.config = createAuthConfig(this.userConfig);
1895
- this.schemas = createSchemas(this.config.schemaExtensions);
2227
+ this.schemas = createSchemas(this.userConfig.schemaExtensions);
1896
2228
  this.t = createTrpcBuilder(this.config);
1897
2229
  this.authGuard = createAuthGuard(this.config, this.t);
1898
2230
  this.procedure = createBaseProcedure(this.t, this.authGuard);
@@ -1950,8 +2282,12 @@ function createAuthRouter(config) {
1950
2282
  createAuthRouter,
1951
2283
  createAuthToken,
1952
2284
  createConsoleEmailAdapter,
2285
+ createDrizzleAdapter,
1953
2286
  createNoopEmailAdapter,
1954
2287
  createOAuthVerifier,
2288
+ createPrismaAdapter,
2289
+ createSessionWithToken,
2290
+ createSessionWithTokenAndCookie,
1955
2291
  decodeToken,
1956
2292
  defaultAuthConfig,
1957
2293
  defaultCookieSettings,