@factiii/auth 0.5.4 → 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.d.mts CHANGED
@@ -6,6 +6,7 @@ import * as zod from 'zod';
6
6
  import { CreateHTTPContextOptions } from '@trpc/server/adapters/standalone';
7
7
  import { S as SchemaExtensions, A as AuthHooks } from './hooks-yHGJ7C6_.mjs';
8
8
  export { C as ChangePasswordInput, L as LoginInput, O as OAuthLoginInput, R as ResetPasswordInput, a as SignupInput, T as TwoFaVerifyInput, V as VerifyEmailInput, b as biometricVerifySchema, c as changePasswordSchema, e as endAllSessionsSchema, l as loginSchema, o as oAuthLoginSchema, r as requestPasswordResetSchema, d as resetPasswordSchema, s as signupSchema, t as twoFaResetSchema, f as twoFaVerifySchema, v as verifyEmailSchema } from './hooks-yHGJ7C6_.mjs';
9
+ import { AnyPgTable, PgColumn, PgDatabase, PgQueryResultHKT } from 'drizzle-orm/pg-core';
9
10
 
10
11
  //# sourceMappingURL=TRPCError.d.ts.map
11
12
  //#endregion
@@ -294,35 +295,42 @@ interface DatabaseAdapter {
294
295
  };
295
296
  }
296
297
 
297
- type PrismaClient = any;
298
298
  /**
299
299
  * Creates a DatabaseAdapter backed by Prisma.
300
- * Each method is a direct extraction of existing Prisma calls from the procedures.
300
+ * Pass your generated PrismaClient instance its full types are preserved at the call site.
301
301
  */
302
- declare function createPrismaAdapter(prisma: PrismaClient): DatabaseAdapter;
302
+ declare function createPrismaAdapter(prisma: unknown): DatabaseAdapter;
303
303
 
304
+ /**
305
+ * A Postgres Drizzle table with column properties accessible by name.
306
+ * `AnyPgTable` is Drizzle's base Postgres table type; intersecting with
307
+ * `Record<string, Column>` exposes the column descriptors for index access.
308
+ */
309
+ type DrizzleTable = AnyPgTable & Record<string, PgColumn>;
304
310
  /**
305
311
  * Drizzle table references required by the adapter.
306
- * Consumers pass their Drizzle table objects so the adapter
312
+ * Consumers pass their Drizzle Postgres table objects so the adapter
307
313
  * can build queries without knowing the schema file location.
314
+ *
315
+ * **Note:** This adapter only supports PostgreSQL via `drizzle-orm/pg-core`.
308
316
  */
309
317
  interface DrizzleAdapterTables {
310
- users: any;
311
- sessions: any;
312
- otps: any;
313
- passwordResets: any;
314
- devices: any;
315
- admins: any;
318
+ users: DrizzleTable;
319
+ sessions: DrizzleTable;
320
+ otps: DrizzleTable;
321
+ passwordResets: DrizzleTable;
322
+ devices: DrizzleTable;
323
+ admins: DrizzleTable;
316
324
  /** Join table for many-to-many device↔user relation (if applicable). */
317
- devicesToUsers?: any;
325
+ devicesToUsers?: DrizzleTable;
318
326
  /** Join table for many-to-many device↔session relation (if applicable). */
319
- devicesToSessions?: any;
327
+ devicesToSessions?: DrizzleTable;
320
328
  }
321
329
  /**
322
- * Any Drizzle database instance (pg, mysql, better-sqlite3, etc.).
323
- * We keep this generic so consumers aren't locked into a specific driver.
330
+ * Any `PgDatabase` instance, regardless of the underlying driver
331
+ * (node-postgres, postgres.js, Neon, PGLite, etc.).
324
332
  */
325
- type DrizzleDB = any;
333
+ type AnyPgDatabase = PgDatabase<PgQueryResultHKT, Record<string, unknown>>;
326
334
  /**
327
335
  * Creates a DatabaseAdapter backed by Drizzle ORM.
328
336
  *
@@ -347,7 +355,7 @@ type DrizzleDB = any;
347
355
  * for joins and `db.insert/update/delete` for mutations. Make sure your Drizzle
348
356
  * instance is created with `{ schema }` so relational queries work.
349
357
  */
350
- declare function createDrizzleAdapter(db: DrizzleDB, tables: DrizzleAdapterTables): DatabaseAdapter;
358
+ declare function createDrizzleAdapter(db: AnyPgDatabase, tables: DrizzleAdapterTables): DatabaseAdapter;
351
359
 
352
360
  /**
353
361
  * JWT payload structure
@@ -505,9 +513,9 @@ declare function createAuthGuard(config: AuthConfig, t: TrpcBuilder): _trpc_serv
505
513
  userId: number;
506
514
  socketId: string | null;
507
515
  sessionId: number;
516
+ ip: string | undefined;
508
517
  headers: http.IncomingHttpHeaders;
509
518
  res: http.ServerResponse<http.IncomingMessage>;
510
- ip: string | undefined;
511
519
  }, unknown>;
512
520
 
513
521
  /**
@@ -1081,17 +1089,17 @@ declare function createAuthRouter<TExtensions extends SchemaExtensions = {}>(con
1081
1089
  sessionId: number;
1082
1090
  userId: number;
1083
1091
  socketId: string | null;
1092
+ ip: string | undefined;
1084
1093
  headers: http.IncomingHttpHeaders;
1085
1094
  res: http.ServerResponse<http.IncomingMessage>;
1086
- ip: string | undefined;
1087
1095
  }, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, false>;
1088
1096
  authProcedure: _trpc_server.TRPCProcedureBuilder<TrpcContext, Meta, {
1089
1097
  sessionId: number;
1090
1098
  userId: number;
1091
1099
  socketId: string | null;
1100
+ ip: string | undefined;
1092
1101
  headers: http.IncomingHttpHeaders;
1093
1102
  res: http.ServerResponse<http.IncomingMessage>;
1094
- ip: string | undefined;
1095
1103
  }, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, false>;
1096
1104
  createContext: ({ req, res }: CreateHTTPContextOptions) => TrpcContext;
1097
1105
  };
@@ -1222,6 +1230,54 @@ declare function validatePasswordStrength(password: string, minLength?: number):
1222
1230
  error?: string;
1223
1231
  };
1224
1232
 
1233
+ /**
1234
+ * Parameters for creating a session with a signed JWT token.
1235
+ */
1236
+ interface CreateSessionWithTokenParams {
1237
+ /** User ID to create the session for */
1238
+ userId: number;
1239
+ /** Browser name (from user-agent) */
1240
+ browserName: string;
1241
+ /** Socket ID for real-time connections */
1242
+ socketId: string | null;
1243
+ /** Device ID for push notifications */
1244
+ deviceId?: number;
1245
+ /** Extra fields to include in the session record (e.g., instanceId) */
1246
+ extraSessionData?: Record<string, unknown>;
1247
+ }
1248
+ /**
1249
+ * Result of creating a session with a token.
1250
+ */
1251
+ interface SessionWithTokenResult {
1252
+ /** Signed JWT access token */
1253
+ accessToken: string;
1254
+ /** Created session ID */
1255
+ sessionId: number;
1256
+ }
1257
+ /**
1258
+ * Create a session and sign a JWT token.
1259
+ *
1260
+ * Use this for programmatic auth flows (magic links, auto-login, test helpers)
1261
+ * where you need a token without going through the full login procedure.
1262
+ *
1263
+ * @param config - Resolved auth config (from createAuthConfig)
1264
+ * @param params - Session creation parameters
1265
+ * @returns Signed JWT and session ID
1266
+ */
1267
+ declare function createSessionWithToken(config: ResolvedAuthConfig, params: CreateSessionWithTokenParams): Promise<SessionWithTokenResult>;
1268
+ /**
1269
+ * Create a session, sign a JWT token, and set the auth cookie on the response.
1270
+ *
1271
+ * Convenience wrapper around {@link createSessionWithToken} for HTTP handlers
1272
+ * that need to set the cookie immediately.
1273
+ *
1274
+ * @param config - Resolved auth config (from createAuthConfig)
1275
+ * @param params - Session creation parameters
1276
+ * @param res - HTTP response to set the cookie on
1277
+ * @returns Signed JWT and session ID
1278
+ */
1279
+ declare function createSessionWithTokenAndCookie(config: ResolvedAuthConfig, params: CreateSessionWithTokenParams, res: CreateHTTPContextOptions['res']): Promise<SessionWithTokenResult>;
1280
+
1225
1281
  /**
1226
1282
  * Generate a random TOTP secret
1227
1283
  * @param length - Length of the secret (default: 16)
@@ -1256,4 +1312,4 @@ declare function verifyTotp(code: string, secret: string): Promise<boolean>;
1256
1312
  */
1257
1313
  declare function generateOtp(min?: number, max?: number): number;
1258
1314
 
1259
- export { type AuthConfig, type AuthFeatures, AuthHooks, type AuthOTP, type AuthPasswordReset, type AuthRouter, type AuthSession, type AuthUser, type CreateSessionData, type CreateUserData, DEFAULT_STORAGE_KEYS, type DatabaseAdapter, type DrizzleAdapterTables, type EmailAdapter, type OAuthKeys, type OAuthProvider, type OAuthResult, OAuthVerificationError, SchemaExtensions, type SessionWithDevice, type SessionWithUser, type TokenSettings, type TrpcContext, cleanBase32String, clearAuthCookie, comparePassword, createAuthConfig, createAuthGuard, createAuthRouter, createAuthToken, createConsoleEmailAdapter, createDrizzleAdapter, createNoopEmailAdapter, createOAuthVerifier, createPrismaAdapter, decodeToken, defaultAuthConfig, defaultCookieSettings, defaultStorageKeys, defaultTokenSettings, detectBrowser, generateOtp, generateTotpCode, generateTotpSecret, hashPassword, isMobileDevice, isNativeApp, isTokenExpiredError, isTokenInvalidError, parseAuthCookie, setAuthCookie, validatePasswordStrength, verifyAuthToken, verifyTotp };
1315
+ export { type AuthConfig, type AuthFeatures, AuthHooks, type AuthOTP, type AuthPasswordReset, type AuthRouter, type AuthSession, type AuthUser, type CreateSessionData, type CreateSessionWithTokenParams, type CreateUserData, DEFAULT_STORAGE_KEYS, type DatabaseAdapter, type DrizzleAdapterTables, type EmailAdapter, type OAuthKeys, type OAuthProvider, type OAuthResult, OAuthVerificationError, type ResolvedAuthConfig, SchemaExtensions, type SessionWithDevice, type SessionWithTokenResult, type SessionWithUser, type TokenSettings, type TrpcContext, cleanBase32String, clearAuthCookie, comparePassword, createAuthConfig, createAuthGuard, createAuthRouter, createAuthToken, createConsoleEmailAdapter, createDrizzleAdapter, createNoopEmailAdapter, createOAuthVerifier, createPrismaAdapter, createSessionWithToken, createSessionWithTokenAndCookie, decodeToken, defaultAuthConfig, defaultCookieSettings, defaultStorageKeys, defaultTokenSettings, detectBrowser, generateOtp, generateTotpCode, generateTotpSecret, hashPassword, isMobileDevice, isNativeApp, isTokenExpiredError, isTokenInvalidError, parseAuthCookie, setAuthCookie, validatePasswordStrength, verifyAuthToken, verifyTotp };
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ import * as zod from 'zod';
6
6
  import { CreateHTTPContextOptions } from '@trpc/server/adapters/standalone';
7
7
  import { S as SchemaExtensions, A as AuthHooks } from './hooks-yHGJ7C6_.js';
8
8
  export { C as ChangePasswordInput, L as LoginInput, O as OAuthLoginInput, R as ResetPasswordInput, a as SignupInput, T as TwoFaVerifyInput, V as VerifyEmailInput, b as biometricVerifySchema, c as changePasswordSchema, e as endAllSessionsSchema, l as loginSchema, o as oAuthLoginSchema, r as requestPasswordResetSchema, d as resetPasswordSchema, s as signupSchema, t as twoFaResetSchema, f as twoFaVerifySchema, v as verifyEmailSchema } from './hooks-yHGJ7C6_.js';
9
+ import { AnyPgTable, PgColumn, PgDatabase, PgQueryResultHKT } from 'drizzle-orm/pg-core';
9
10
 
10
11
  //# sourceMappingURL=TRPCError.d.ts.map
11
12
  //#endregion
@@ -294,35 +295,42 @@ interface DatabaseAdapter {
294
295
  };
295
296
  }
296
297
 
297
- type PrismaClient = any;
298
298
  /**
299
299
  * Creates a DatabaseAdapter backed by Prisma.
300
- * Each method is a direct extraction of existing Prisma calls from the procedures.
300
+ * Pass your generated PrismaClient instance its full types are preserved at the call site.
301
301
  */
302
- declare function createPrismaAdapter(prisma: PrismaClient): DatabaseAdapter;
302
+ declare function createPrismaAdapter(prisma: unknown): DatabaseAdapter;
303
303
 
304
+ /**
305
+ * A Postgres Drizzle table with column properties accessible by name.
306
+ * `AnyPgTable` is Drizzle's base Postgres table type; intersecting with
307
+ * `Record<string, Column>` exposes the column descriptors for index access.
308
+ */
309
+ type DrizzleTable = AnyPgTable & Record<string, PgColumn>;
304
310
  /**
305
311
  * Drizzle table references required by the adapter.
306
- * Consumers pass their Drizzle table objects so the adapter
312
+ * Consumers pass their Drizzle Postgres table objects so the adapter
307
313
  * can build queries without knowing the schema file location.
314
+ *
315
+ * **Note:** This adapter only supports PostgreSQL via `drizzle-orm/pg-core`.
308
316
  */
309
317
  interface DrizzleAdapterTables {
310
- users: any;
311
- sessions: any;
312
- otps: any;
313
- passwordResets: any;
314
- devices: any;
315
- admins: any;
318
+ users: DrizzleTable;
319
+ sessions: DrizzleTable;
320
+ otps: DrizzleTable;
321
+ passwordResets: DrizzleTable;
322
+ devices: DrizzleTable;
323
+ admins: DrizzleTable;
316
324
  /** Join table for many-to-many device↔user relation (if applicable). */
317
- devicesToUsers?: any;
325
+ devicesToUsers?: DrizzleTable;
318
326
  /** Join table for many-to-many device↔session relation (if applicable). */
319
- devicesToSessions?: any;
327
+ devicesToSessions?: DrizzleTable;
320
328
  }
321
329
  /**
322
- * Any Drizzle database instance (pg, mysql, better-sqlite3, etc.).
323
- * We keep this generic so consumers aren't locked into a specific driver.
330
+ * Any `PgDatabase` instance, regardless of the underlying driver
331
+ * (node-postgres, postgres.js, Neon, PGLite, etc.).
324
332
  */
325
- type DrizzleDB = any;
333
+ type AnyPgDatabase = PgDatabase<PgQueryResultHKT, Record<string, unknown>>;
326
334
  /**
327
335
  * Creates a DatabaseAdapter backed by Drizzle ORM.
328
336
  *
@@ -347,7 +355,7 @@ type DrizzleDB = any;
347
355
  * for joins and `db.insert/update/delete` for mutations. Make sure your Drizzle
348
356
  * instance is created with `{ schema }` so relational queries work.
349
357
  */
350
- declare function createDrizzleAdapter(db: DrizzleDB, tables: DrizzleAdapterTables): DatabaseAdapter;
358
+ declare function createDrizzleAdapter(db: AnyPgDatabase, tables: DrizzleAdapterTables): DatabaseAdapter;
351
359
 
352
360
  /**
353
361
  * JWT payload structure
@@ -505,9 +513,9 @@ declare function createAuthGuard(config: AuthConfig, t: TrpcBuilder): _trpc_serv
505
513
  userId: number;
506
514
  socketId: string | null;
507
515
  sessionId: number;
516
+ ip: string | undefined;
508
517
  headers: http.IncomingHttpHeaders;
509
518
  res: http.ServerResponse<http.IncomingMessage>;
510
- ip: string | undefined;
511
519
  }, unknown>;
512
520
 
513
521
  /**
@@ -1081,17 +1089,17 @@ declare function createAuthRouter<TExtensions extends SchemaExtensions = {}>(con
1081
1089
  sessionId: number;
1082
1090
  userId: number;
1083
1091
  socketId: string | null;
1092
+ ip: string | undefined;
1084
1093
  headers: http.IncomingHttpHeaders;
1085
1094
  res: http.ServerResponse<http.IncomingMessage>;
1086
- ip: string | undefined;
1087
1095
  }, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, false>;
1088
1096
  authProcedure: _trpc_server.TRPCProcedureBuilder<TrpcContext, Meta, {
1089
1097
  sessionId: number;
1090
1098
  userId: number;
1091
1099
  socketId: string | null;
1100
+ ip: string | undefined;
1092
1101
  headers: http.IncomingHttpHeaders;
1093
1102
  res: http.ServerResponse<http.IncomingMessage>;
1094
- ip: string | undefined;
1095
1103
  }, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, _trpc_server.TRPCUnsetMarker, false>;
1096
1104
  createContext: ({ req, res }: CreateHTTPContextOptions) => TrpcContext;
1097
1105
  };
@@ -1222,6 +1230,54 @@ declare function validatePasswordStrength(password: string, minLength?: number):
1222
1230
  error?: string;
1223
1231
  };
1224
1232
 
1233
+ /**
1234
+ * Parameters for creating a session with a signed JWT token.
1235
+ */
1236
+ interface CreateSessionWithTokenParams {
1237
+ /** User ID to create the session for */
1238
+ userId: number;
1239
+ /** Browser name (from user-agent) */
1240
+ browserName: string;
1241
+ /** Socket ID for real-time connections */
1242
+ socketId: string | null;
1243
+ /** Device ID for push notifications */
1244
+ deviceId?: number;
1245
+ /** Extra fields to include in the session record (e.g., instanceId) */
1246
+ extraSessionData?: Record<string, unknown>;
1247
+ }
1248
+ /**
1249
+ * Result of creating a session with a token.
1250
+ */
1251
+ interface SessionWithTokenResult {
1252
+ /** Signed JWT access token */
1253
+ accessToken: string;
1254
+ /** Created session ID */
1255
+ sessionId: number;
1256
+ }
1257
+ /**
1258
+ * Create a session and sign a JWT token.
1259
+ *
1260
+ * Use this for programmatic auth flows (magic links, auto-login, test helpers)
1261
+ * where you need a token without going through the full login procedure.
1262
+ *
1263
+ * @param config - Resolved auth config (from createAuthConfig)
1264
+ * @param params - Session creation parameters
1265
+ * @returns Signed JWT and session ID
1266
+ */
1267
+ declare function createSessionWithToken(config: ResolvedAuthConfig, params: CreateSessionWithTokenParams): Promise<SessionWithTokenResult>;
1268
+ /**
1269
+ * Create a session, sign a JWT token, and set the auth cookie on the response.
1270
+ *
1271
+ * Convenience wrapper around {@link createSessionWithToken} for HTTP handlers
1272
+ * that need to set the cookie immediately.
1273
+ *
1274
+ * @param config - Resolved auth config (from createAuthConfig)
1275
+ * @param params - Session creation parameters
1276
+ * @param res - HTTP response to set the cookie on
1277
+ * @returns Signed JWT and session ID
1278
+ */
1279
+ declare function createSessionWithTokenAndCookie(config: ResolvedAuthConfig, params: CreateSessionWithTokenParams, res: CreateHTTPContextOptions['res']): Promise<SessionWithTokenResult>;
1280
+
1225
1281
  /**
1226
1282
  * Generate a random TOTP secret
1227
1283
  * @param length - Length of the secret (default: 16)
@@ -1256,4 +1312,4 @@ declare function verifyTotp(code: string, secret: string): Promise<boolean>;
1256
1312
  */
1257
1313
  declare function generateOtp(min?: number, max?: number): number;
1258
1314
 
1259
- export { type AuthConfig, type AuthFeatures, AuthHooks, type AuthOTP, type AuthPasswordReset, type AuthRouter, type AuthSession, type AuthUser, type CreateSessionData, type CreateUserData, DEFAULT_STORAGE_KEYS, type DatabaseAdapter, type DrizzleAdapterTables, type EmailAdapter, type OAuthKeys, type OAuthProvider, type OAuthResult, OAuthVerificationError, SchemaExtensions, type SessionWithDevice, type SessionWithUser, type TokenSettings, type TrpcContext, cleanBase32String, clearAuthCookie, comparePassword, createAuthConfig, createAuthGuard, createAuthRouter, createAuthToken, createConsoleEmailAdapter, createDrizzleAdapter, createNoopEmailAdapter, createOAuthVerifier, createPrismaAdapter, decodeToken, defaultAuthConfig, defaultCookieSettings, defaultStorageKeys, defaultTokenSettings, detectBrowser, generateOtp, generateTotpCode, generateTotpSecret, hashPassword, isMobileDevice, isNativeApp, isTokenExpiredError, isTokenInvalidError, parseAuthCookie, setAuthCookie, validatePasswordStrength, verifyAuthToken, verifyTotp };
1315
+ export { type AuthConfig, type AuthFeatures, AuthHooks, type AuthOTP, type AuthPasswordReset, type AuthRouter, type AuthSession, type AuthUser, type CreateSessionData, type CreateSessionWithTokenParams, type CreateUserData, DEFAULT_STORAGE_KEYS, type DatabaseAdapter, type DrizzleAdapterTables, type EmailAdapter, type OAuthKeys, type OAuthProvider, type OAuthResult, OAuthVerificationError, type ResolvedAuthConfig, SchemaExtensions, type SessionWithDevice, type SessionWithTokenResult, type SessionWithUser, type TokenSettings, type TrpcContext, cleanBase32String, clearAuthCookie, comparePassword, createAuthConfig, createAuthGuard, createAuthRouter, createAuthToken, createConsoleEmailAdapter, createDrizzleAdapter, createNoopEmailAdapter, createOAuthVerifier, createPrismaAdapter, createSessionWithToken, createSessionWithTokenAndCookie, decodeToken, defaultAuthConfig, defaultCookieSettings, defaultStorageKeys, defaultTokenSettings, detectBrowser, generateOtp, generateTotpCode, generateTotpSecret, hashPassword, isMobileDevice, isNativeApp, isTokenExpiredError, isTokenInvalidError, parseAuthCookie, setAuthCookie, validatePasswordStrength, verifyAuthToken, verifyTotp };
package/dist/index.js CHANGED
@@ -46,6 +46,8 @@ __export(index_exports, {
46
46
  createNoopEmailAdapter: () => createNoopEmailAdapter,
47
47
  createOAuthVerifier: () => createOAuthVerifier,
48
48
  createPrismaAdapter: () => createPrismaAdapter,
49
+ createSessionWithToken: () => createSessionWithToken,
50
+ createSessionWithTokenAndCookie: () => createSessionWithTokenAndCookie,
49
51
  decodeToken: () => decodeToken,
50
52
  defaultAuthConfig: () => defaultAuthConfig,
51
53
  defaultCookieSettings: () => defaultCookieSettings,
@@ -82,20 +84,21 @@ var import_server = require("@trpc/server");
82
84
 
83
85
  // src/adapters/prismaAdapter.ts
84
86
  function createPrismaAdapter(prisma) {
87
+ const db = prisma;
85
88
  return {
86
89
  user: {
87
90
  async findByEmailInsensitive(email) {
88
- return prisma.user.findFirst({
91
+ return db.user.findFirst({
89
92
  where: { email: { equals: email, mode: "insensitive" } }
90
93
  });
91
94
  },
92
95
  async findByUsernameInsensitive(username) {
93
- return prisma.user.findFirst({
96
+ return db.user.findFirst({
94
97
  where: { username: { equals: username, mode: "insensitive" } }
95
98
  });
96
99
  },
97
100
  async findByEmailOrUsernameInsensitive(identifier) {
98
- return prisma.user.findFirst({
101
+ return db.user.findFirst({
99
102
  where: {
100
103
  OR: [
101
104
  { email: { equals: identifier, mode: "insensitive" } },
@@ -105,7 +108,7 @@ function createPrismaAdapter(prisma) {
105
108
  });
106
109
  },
107
110
  async findByEmailOrOAuthId(email, oauthId) {
108
- return prisma.user.findFirst({
111
+ return db.user.findFirst({
109
112
  where: {
110
113
  OR: [
111
114
  { email: { equals: email, mode: "insensitive" } },
@@ -115,23 +118,23 @@ function createPrismaAdapter(prisma) {
115
118
  });
116
119
  },
117
120
  async findById(id) {
118
- return prisma.user.findUnique({ where: { id } });
121
+ return db.user.findUnique({ where: { id } });
119
122
  },
120
123
  async findActiveById(id) {
121
- return prisma.user.findUnique({
124
+ return db.user.findUnique({
122
125
  where: { id, status: "ACTIVE" }
123
126
  });
124
127
  },
125
128
  async create(data) {
126
- return prisma.user.create({ data });
129
+ return db.user.create({ data });
127
130
  },
128
131
  async update(id, data) {
129
- return prisma.user.update({ where: { id }, data });
132
+ return db.user.update({ where: { id }, data });
130
133
  }
131
134
  },
132
135
  session: {
133
136
  async findById(id) {
134
- const session = await prisma.session.findUnique({
137
+ const session = await db.session.findUnique({
135
138
  where: { id },
136
139
  select: {
137
140
  id: true,
@@ -149,13 +152,13 @@ function createPrismaAdapter(prisma) {
149
152
  return session;
150
153
  },
151
154
  async create(data) {
152
- return prisma.session.create({ data });
155
+ return db.session.create({ data });
153
156
  },
154
157
  async update(id, data) {
155
- return prisma.session.update({ where: { id }, data });
158
+ return db.session.update({ where: { id }, data });
156
159
  },
157
160
  async updateLastUsed(id) {
158
- const session = await prisma.session.update({
161
+ const session = await db.session.update({
159
162
  where: { id },
160
163
  data: { lastUsed: /* @__PURE__ */ new Date() },
161
164
  select: {
@@ -174,13 +177,13 @@ function createPrismaAdapter(prisma) {
174
177
  return session;
175
178
  },
176
179
  async revoke(id) {
177
- await prisma.session.update({
180
+ await db.session.update({
178
181
  where: { id },
179
182
  data: { revokedAt: /* @__PURE__ */ new Date() }
180
183
  });
181
184
  },
182
185
  async findActiveByUserId(userId, excludeSessionId) {
183
- return prisma.session.findMany({
186
+ return db.session.findMany({
184
187
  where: {
185
188
  userId,
186
189
  revokedAt: null,
@@ -190,7 +193,7 @@ function createPrismaAdapter(prisma) {
190
193
  });
191
194
  },
192
195
  async revokeAllByUserId(userId, excludeSessionId) {
193
- await prisma.session.updateMany({
196
+ await db.session.updateMany({
194
197
  where: {
195
198
  userId,
196
199
  revokedAt: null,
@@ -200,13 +203,13 @@ function createPrismaAdapter(prisma) {
200
203
  });
201
204
  },
202
205
  async findTwoFaSecretsByUserId(userId) {
203
- return prisma.session.findMany({
206
+ return db.session.findMany({
204
207
  where: { userId, twoFaSecret: { not: null } },
205
208
  select: { twoFaSecret: true }
206
209
  });
207
210
  },
208
211
  async clearTwoFaSecrets(userId, excludeSessionId) {
209
- await prisma.session.updateMany({
212
+ await db.session.updateMany({
210
213
  where: {
211
214
  userId,
212
215
  ...excludeSessionId ? { NOT: { id: excludeSessionId } } : {}
@@ -215,7 +218,7 @@ function createPrismaAdapter(prisma) {
215
218
  });
216
219
  },
217
220
  async findByIdWithDevice(id, userId) {
218
- const session = await prisma.session.findUnique({
221
+ const session = await db.session.findUnique({
219
222
  where: { id, userId },
220
223
  select: {
221
224
  twoFaSecret: true,
@@ -226,7 +229,7 @@ function createPrismaAdapter(prisma) {
226
229
  return session;
227
230
  },
228
231
  async revokeByDevicePushToken(userId, pushToken, excludeSessionId) {
229
- await prisma.session.updateMany({
232
+ await db.session.updateMany({
230
233
  where: {
231
234
  userId,
232
235
  id: { not: excludeSessionId },
@@ -237,7 +240,7 @@ function createPrismaAdapter(prisma) {
237
240
  });
238
241
  },
239
242
  async clearDeviceId(userId, deviceId) {
240
- await prisma.session.updateMany({
243
+ await db.session.updateMany({
241
244
  where: { userId, deviceId },
242
245
  data: { deviceId: null }
243
246
  });
@@ -245,39 +248,39 @@ function createPrismaAdapter(prisma) {
245
248
  },
246
249
  otp: {
247
250
  async findValidByUserAndCode(userId, code) {
248
- return prisma.oTP.findFirst({
251
+ return db.oTP.findFirst({
249
252
  where: { userId, code, expiresAt: { gte: /* @__PURE__ */ new Date() } }
250
253
  });
251
254
  },
252
255
  async create(data) {
253
- return prisma.oTP.create({ data });
256
+ return db.oTP.create({ data });
254
257
  },
255
258
  async delete(id) {
256
- await prisma.oTP.delete({ where: { id } });
259
+ await db.oTP.delete({ where: { id } });
257
260
  }
258
261
  },
259
262
  passwordReset: {
260
263
  async findById(id) {
261
- return prisma.passwordReset.findUnique({
264
+ return db.passwordReset.findUnique({
262
265
  where: { id },
263
266
  select: { id: true, createdAt: true, userId: true }
264
267
  });
265
268
  },
266
269
  async create(userId) {
267
- return prisma.passwordReset.create({
270
+ return db.passwordReset.create({
268
271
  data: { userId }
269
272
  });
270
273
  },
271
274
  async delete(id) {
272
- await prisma.passwordReset.delete({ where: { id } });
275
+ await db.passwordReset.delete({ where: { id } });
273
276
  },
274
277
  async deleteAllByUserId(userId) {
275
- await prisma.passwordReset.deleteMany({ where: { userId } });
278
+ await db.passwordReset.deleteMany({ where: { userId } });
276
279
  }
277
280
  },
278
281
  device: {
279
282
  async findByTokenSessionAndUser(pushToken, sessionId, userId) {
280
- return prisma.device.findFirst({
283
+ return db.device.findFirst({
281
284
  where: {
282
285
  pushToken,
283
286
  sessions: { some: { id: sessionId } },
@@ -287,7 +290,7 @@ function createPrismaAdapter(prisma) {
287
290
  });
288
291
  },
289
292
  async upsertByPushToken(pushToken, sessionId, userId) {
290
- await prisma.device.upsert({
293
+ await db.device.upsert({
291
294
  where: { pushToken },
292
295
  create: {
293
296
  pushToken,
@@ -301,31 +304,31 @@ function createPrismaAdapter(prisma) {
301
304
  });
302
305
  },
303
306
  async findByUserAndToken(userId, pushToken) {
304
- return prisma.device.findFirst({
307
+ return db.device.findFirst({
305
308
  where: { users: { some: { id: userId } }, pushToken },
306
309
  select: { id: true }
307
310
  });
308
311
  },
309
312
  async disconnectUser(deviceId, userId) {
310
- await prisma.device.update({
313
+ await db.device.update({
311
314
  where: { id: deviceId },
312
315
  data: { users: { disconnect: { id: userId } } }
313
316
  });
314
317
  },
315
318
  async hasRemainingUsers(deviceId) {
316
- const result = await prisma.device.findUnique({
319
+ const result = await db.device.findUnique({
317
320
  where: { id: deviceId },
318
321
  select: { users: { select: { id: true }, take: 1 } }
319
322
  });
320
323
  return (result?.users.length ?? 0) > 0;
321
324
  },
322
325
  async delete(id) {
323
- await prisma.device.delete({ where: { id } });
326
+ await db.device.delete({ where: { id } });
324
327
  }
325
328
  },
326
329
  admin: {
327
330
  async findByUserId(userId) {
328
- return prisma.admin.findFirst({
331
+ return db.admin.findFirst({
329
332
  where: { userId },
330
333
  select: { ip: true }
331
334
  });
@@ -498,11 +501,12 @@ function createDrizzleAdapter(db, tables) {
498
501
  if (excludeSessionId !== void 0) {
499
502
  conditions.push(ne(sessions.id, excludeSessionId));
500
503
  }
501
- return db.select({
504
+ const activeRows = await db.select({
502
505
  id: sessions.id,
503
506
  socketId: sessions.socketId,
504
507
  userId: sessions.userId
505
508
  }).from(sessions).where(and(...conditions));
509
+ return activeRows;
506
510
  },
507
511
  async revokeAllByUserId(userId, excludeSessionId) {
508
512
  const conditions = [eq(sessions.userId, userId), isNull(sessions.revokedAt)];
@@ -512,7 +516,8 @@ function createDrizzleAdapter(db, tables) {
512
516
  await db.update(sessions).set({ revokedAt: /* @__PURE__ */ new Date() }).where(and(...conditions));
513
517
  },
514
518
  async findTwoFaSecretsByUserId(userId) {
515
- return db.select({ twoFaSecret: sessions.twoFaSecret }).from(sessions).where(and(eq(sessions.userId, userId), isNotNull(sessions.twoFaSecret)));
519
+ const secretRows = await db.select({ twoFaSecret: sessions.twoFaSecret }).from(sessions).where(and(eq(sessions.userId, userId), isNotNull(sessions.twoFaSecret)));
520
+ return secretRows;
516
521
  },
517
522
  async clearTwoFaSecrets(userId, excludeSessionId) {
518
523
  const conditions = [eq(sessions.userId, userId)];
@@ -531,10 +536,11 @@ function createDrizzleAdapter(db, tables) {
531
536
  }).from(sessions).leftJoin(devices, eq(sessions.deviceId, devices.id)).where(and(eq(sessions.id, id), eq(sessions.userId, userId))).limit(1);
532
537
  if (!rows[0]) return null;
533
538
  const row = rows[0];
539
+ const device = row.device;
534
540
  return {
535
541
  twoFaSecret: row.twoFaSecret,
536
542
  deviceId: row.deviceId,
537
- device: row.device?.pushToken ? { pushToken: row.device.pushToken } : null
543
+ device: device?.pushToken ? { pushToken: device.pushToken } : null
538
544
  };
539
545
  },
540
546
  async revokeByDevicePushToken(userId, pushToken, excludeSessionId) {
@@ -615,8 +621,8 @@ function createDrizzleAdapter(db, tables) {
615
621
  if (existing[0]) {
616
622
  deviceId = existing[0].id;
617
623
  } else {
618
- const rows = await db.insert(devices).values({ pushToken }).returning({ id: devices.id });
619
- deviceId = rows[0].id;
624
+ const insertedRows = await db.insert(devices).values({ pushToken }).returning({ id: devices.id });
625
+ deviceId = insertedRows[0].id;
620
626
  }
621
627
  if (tables.devicesToSessions) {
622
628
  await db.insert(tables.devicesToSessions).values({ deviceId, sessionId }).onConflictDoNothing();
@@ -628,7 +634,7 @@ function createDrizzleAdapter(db, tables) {
628
634
  },
629
635
  async findByUserAndToken(userId, pushToken) {
630
636
  if (tables.devicesToUsers) {
631
- const rows2 = await db.select({ id: devices.id }).from(devices).innerJoin(
637
+ const joinRows = await db.select({ id: devices.id }).from(devices).innerJoin(
632
638
  tables.devicesToUsers,
633
639
  eq(devices.id, tables.devicesToUsers.deviceId)
634
640
  ).where(
@@ -637,7 +643,7 @@ function createDrizzleAdapter(db, tables) {
637
643
  eq(tables.devicesToUsers.userId, userId)
638
644
  )
639
645
  ).limit(1);
640
- return rows2[0] ? { id: rows2[0].id } : null;
646
+ return joinRows[0] ? { id: joinRows[0].id } : null;
641
647
  }
642
648
  const rows = await db.select({ id: devices.id }).from(devices).where(eq(devices.pushToken, pushToken)).limit(1);
643
649
  return rows[0] ? { id: rows[0].id } : null;
@@ -654,8 +660,8 @@ function createDrizzleAdapter(db, tables) {
654
660
  },
655
661
  async hasRemainingUsers(deviceId) {
656
662
  if (tables.devicesToUsers) {
657
- const rows = await db.select({ userId: tables.devicesToUsers.userId }).from(tables.devicesToUsers).where(eq(tables.devicesToUsers.deviceId, deviceId)).limit(1);
658
- return rows.length > 0;
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;
659
665
  }
660
666
  return false;
661
667
  },
@@ -1137,6 +1143,36 @@ function validatePasswordStrength(password, minLength = 6) {
1137
1143
  return { valid: true };
1138
1144
  }
1139
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
+
1140
1176
  // src/utilities/totp.ts
1141
1177
  var import_crypto = __toESM(require("crypto"));
1142
1178
  var import_totp_generator = require("totp-generator");
@@ -2098,13 +2134,15 @@ var TwoFaProcedureFactory = class {
2098
2134
  var import_server7 = require("@trpc/server");
2099
2135
  var import_superjson = __toESM(require("superjson"));
2100
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
+ }
2101
2140
  function isPrismaConnectionError(error) {
2102
2141
  if (!error || typeof error !== "object") {
2103
2142
  return false;
2104
2143
  }
2105
- const errorCode = error.code;
2106
- if (errorCode && typeof errorCode === "string") {
2107
- const codeMatch = errorCode.match(/^P(\d+)$/);
2144
+ if (hasStringProp(error, "code")) {
2145
+ const codeMatch = error.code.match(/^P(\d+)$/);
2108
2146
  if (codeMatch) {
2109
2147
  const codeNum = parseInt(codeMatch[1], 10);
2110
2148
  if (codeNum >= 1e3 && codeNum <= 1003) {
@@ -2114,14 +2152,13 @@ function isPrismaConnectionError(error) {
2114
2152
  }
2115
2153
  const constructorName = error.constructor?.name || "";
2116
2154
  if (constructorName.includes("Prisma")) {
2117
- const errorMessage = error.message?.toLowerCase() || "";
2155
+ const errorMessage = hasStringProp(error, "message") ? error.message.toLowerCase() : "";
2118
2156
  if (errorMessage.includes("can't reach database") || errorMessage.includes("authentication failed") || errorMessage.includes("database server") || errorMessage.includes("timeout") || errorMessage.includes("connection")) {
2119
2157
  return true;
2120
2158
  }
2121
2159
  }
2122
- const cause = error.cause;
2123
- if (cause) {
2124
- return isPrismaConnectionError(cause);
2160
+ if ("cause" in error) {
2161
+ return isPrismaConnectionError(error.cause);
2125
2162
  }
2126
2163
  return false;
2127
2164
  }
@@ -2167,8 +2204,9 @@ function createBaseProcedure(t, authGuard) {
2167
2204
  }
2168
2205
  function getClientIp(req) {
2169
2206
  const forwarded = req.headers["x-forwarded-for"];
2170
- if (forwarded) {
2171
- return forwarded.split(",")[0]?.trim();
2207
+ const forwardedStr = Array.isArray(forwarded) ? forwarded[0] : forwarded;
2208
+ if (forwardedStr) {
2209
+ return forwardedStr.split(",")[0]?.trim();
2172
2210
  }
2173
2211
  return req.socket.remoteAddress || void 0;
2174
2212
  }
@@ -2186,7 +2224,7 @@ var AuthRouterFactory = class {
2186
2224
  constructor(userConfig) {
2187
2225
  this.userConfig = userConfig;
2188
2226
  this.config = createAuthConfig(this.userConfig);
2189
- this.schemas = createSchemas(this.config.schemaExtensions);
2227
+ this.schemas = createSchemas(this.userConfig.schemaExtensions);
2190
2228
  this.t = createTrpcBuilder(this.config);
2191
2229
  this.authGuard = createAuthGuard(this.config, this.t);
2192
2230
  this.procedure = createBaseProcedure(this.t, this.authGuard);
@@ -2248,6 +2286,8 @@ function createAuthRouter(config) {
2248
2286
  createNoopEmailAdapter,
2249
2287
  createOAuthVerifier,
2250
2288
  createPrismaAdapter,
2289
+ createSessionWithToken,
2290
+ createSessionWithTokenAndCookie,
2251
2291
  decodeToken,
2252
2292
  defaultAuthConfig,
2253
2293
  defaultCookieSettings,
package/dist/index.mjs CHANGED
@@ -25,20 +25,21 @@ import { TRPCError } from "@trpc/server";
25
25
 
26
26
  // src/adapters/prismaAdapter.ts
27
27
  function createPrismaAdapter(prisma) {
28
+ const db = prisma;
28
29
  return {
29
30
  user: {
30
31
  async findByEmailInsensitive(email) {
31
- return prisma.user.findFirst({
32
+ return db.user.findFirst({
32
33
  where: { email: { equals: email, mode: "insensitive" } }
33
34
  });
34
35
  },
35
36
  async findByUsernameInsensitive(username) {
36
- return prisma.user.findFirst({
37
+ return db.user.findFirst({
37
38
  where: { username: { equals: username, mode: "insensitive" } }
38
39
  });
39
40
  },
40
41
  async findByEmailOrUsernameInsensitive(identifier) {
41
- return prisma.user.findFirst({
42
+ return db.user.findFirst({
42
43
  where: {
43
44
  OR: [
44
45
  { email: { equals: identifier, mode: "insensitive" } },
@@ -48,7 +49,7 @@ function createPrismaAdapter(prisma) {
48
49
  });
49
50
  },
50
51
  async findByEmailOrOAuthId(email, oauthId) {
51
- return prisma.user.findFirst({
52
+ return db.user.findFirst({
52
53
  where: {
53
54
  OR: [
54
55
  { email: { equals: email, mode: "insensitive" } },
@@ -58,23 +59,23 @@ function createPrismaAdapter(prisma) {
58
59
  });
59
60
  },
60
61
  async findById(id) {
61
- return prisma.user.findUnique({ where: { id } });
62
+ return db.user.findUnique({ where: { id } });
62
63
  },
63
64
  async findActiveById(id) {
64
- return prisma.user.findUnique({
65
+ return db.user.findUnique({
65
66
  where: { id, status: "ACTIVE" }
66
67
  });
67
68
  },
68
69
  async create(data) {
69
- return prisma.user.create({ data });
70
+ return db.user.create({ data });
70
71
  },
71
72
  async update(id, data) {
72
- return prisma.user.update({ where: { id }, data });
73
+ return db.user.update({ where: { id }, data });
73
74
  }
74
75
  },
75
76
  session: {
76
77
  async findById(id) {
77
- const session = await prisma.session.findUnique({
78
+ const session = await db.session.findUnique({
78
79
  where: { id },
79
80
  select: {
80
81
  id: true,
@@ -92,13 +93,13 @@ function createPrismaAdapter(prisma) {
92
93
  return session;
93
94
  },
94
95
  async create(data) {
95
- return prisma.session.create({ data });
96
+ return db.session.create({ data });
96
97
  },
97
98
  async update(id, data) {
98
- return prisma.session.update({ where: { id }, data });
99
+ return db.session.update({ where: { id }, data });
99
100
  },
100
101
  async updateLastUsed(id) {
101
- const session = await prisma.session.update({
102
+ const session = await db.session.update({
102
103
  where: { id },
103
104
  data: { lastUsed: /* @__PURE__ */ new Date() },
104
105
  select: {
@@ -117,13 +118,13 @@ function createPrismaAdapter(prisma) {
117
118
  return session;
118
119
  },
119
120
  async revoke(id) {
120
- await prisma.session.update({
121
+ await db.session.update({
121
122
  where: { id },
122
123
  data: { revokedAt: /* @__PURE__ */ new Date() }
123
124
  });
124
125
  },
125
126
  async findActiveByUserId(userId, excludeSessionId) {
126
- return prisma.session.findMany({
127
+ return db.session.findMany({
127
128
  where: {
128
129
  userId,
129
130
  revokedAt: null,
@@ -133,7 +134,7 @@ function createPrismaAdapter(prisma) {
133
134
  });
134
135
  },
135
136
  async revokeAllByUserId(userId, excludeSessionId) {
136
- await prisma.session.updateMany({
137
+ await db.session.updateMany({
137
138
  where: {
138
139
  userId,
139
140
  revokedAt: null,
@@ -143,13 +144,13 @@ function createPrismaAdapter(prisma) {
143
144
  });
144
145
  },
145
146
  async findTwoFaSecretsByUserId(userId) {
146
- return prisma.session.findMany({
147
+ return db.session.findMany({
147
148
  where: { userId, twoFaSecret: { not: null } },
148
149
  select: { twoFaSecret: true }
149
150
  });
150
151
  },
151
152
  async clearTwoFaSecrets(userId, excludeSessionId) {
152
- await prisma.session.updateMany({
153
+ await db.session.updateMany({
153
154
  where: {
154
155
  userId,
155
156
  ...excludeSessionId ? { NOT: { id: excludeSessionId } } : {}
@@ -158,7 +159,7 @@ function createPrismaAdapter(prisma) {
158
159
  });
159
160
  },
160
161
  async findByIdWithDevice(id, userId) {
161
- const session = await prisma.session.findUnique({
162
+ const session = await db.session.findUnique({
162
163
  where: { id, userId },
163
164
  select: {
164
165
  twoFaSecret: true,
@@ -169,7 +170,7 @@ function createPrismaAdapter(prisma) {
169
170
  return session;
170
171
  },
171
172
  async revokeByDevicePushToken(userId, pushToken, excludeSessionId) {
172
- await prisma.session.updateMany({
173
+ await db.session.updateMany({
173
174
  where: {
174
175
  userId,
175
176
  id: { not: excludeSessionId },
@@ -180,7 +181,7 @@ function createPrismaAdapter(prisma) {
180
181
  });
181
182
  },
182
183
  async clearDeviceId(userId, deviceId) {
183
- await prisma.session.updateMany({
184
+ await db.session.updateMany({
184
185
  where: { userId, deviceId },
185
186
  data: { deviceId: null }
186
187
  });
@@ -188,39 +189,39 @@ function createPrismaAdapter(prisma) {
188
189
  },
189
190
  otp: {
190
191
  async findValidByUserAndCode(userId, code) {
191
- return prisma.oTP.findFirst({
192
+ return db.oTP.findFirst({
192
193
  where: { userId, code, expiresAt: { gte: /* @__PURE__ */ new Date() } }
193
194
  });
194
195
  },
195
196
  async create(data) {
196
- return prisma.oTP.create({ data });
197
+ return db.oTP.create({ data });
197
198
  },
198
199
  async delete(id) {
199
- await prisma.oTP.delete({ where: { id } });
200
+ await db.oTP.delete({ where: { id } });
200
201
  }
201
202
  },
202
203
  passwordReset: {
203
204
  async findById(id) {
204
- return prisma.passwordReset.findUnique({
205
+ return db.passwordReset.findUnique({
205
206
  where: { id },
206
207
  select: { id: true, createdAt: true, userId: true }
207
208
  });
208
209
  },
209
210
  async create(userId) {
210
- return prisma.passwordReset.create({
211
+ return db.passwordReset.create({
211
212
  data: { userId }
212
213
  });
213
214
  },
214
215
  async delete(id) {
215
- await prisma.passwordReset.delete({ where: { id } });
216
+ await db.passwordReset.delete({ where: { id } });
216
217
  },
217
218
  async deleteAllByUserId(userId) {
218
- await prisma.passwordReset.deleteMany({ where: { userId } });
219
+ await db.passwordReset.deleteMany({ where: { userId } });
219
220
  }
220
221
  },
221
222
  device: {
222
223
  async findByTokenSessionAndUser(pushToken, sessionId, userId) {
223
- return prisma.device.findFirst({
224
+ return db.device.findFirst({
224
225
  where: {
225
226
  pushToken,
226
227
  sessions: { some: { id: sessionId } },
@@ -230,7 +231,7 @@ function createPrismaAdapter(prisma) {
230
231
  });
231
232
  },
232
233
  async upsertByPushToken(pushToken, sessionId, userId) {
233
- await prisma.device.upsert({
234
+ await db.device.upsert({
234
235
  where: { pushToken },
235
236
  create: {
236
237
  pushToken,
@@ -244,31 +245,31 @@ function createPrismaAdapter(prisma) {
244
245
  });
245
246
  },
246
247
  async findByUserAndToken(userId, pushToken) {
247
- return prisma.device.findFirst({
248
+ return db.device.findFirst({
248
249
  where: { users: { some: { id: userId } }, pushToken },
249
250
  select: { id: true }
250
251
  });
251
252
  },
252
253
  async disconnectUser(deviceId, userId) {
253
- await prisma.device.update({
254
+ await db.device.update({
254
255
  where: { id: deviceId },
255
256
  data: { users: { disconnect: { id: userId } } }
256
257
  });
257
258
  },
258
259
  async hasRemainingUsers(deviceId) {
259
- const result = await prisma.device.findUnique({
260
+ const result = await db.device.findUnique({
260
261
  where: { id: deviceId },
261
262
  select: { users: { select: { id: true }, take: 1 } }
262
263
  });
263
264
  return (result?.users.length ?? 0) > 0;
264
265
  },
265
266
  async delete(id) {
266
- await prisma.device.delete({ where: { id } });
267
+ await db.device.delete({ where: { id } });
267
268
  }
268
269
  },
269
270
  admin: {
270
271
  async findByUserId(userId) {
271
- return prisma.admin.findFirst({
272
+ return db.admin.findFirst({
272
273
  where: { userId },
273
274
  select: { ip: true }
274
275
  });
@@ -441,11 +442,12 @@ function createDrizzleAdapter(db, tables) {
441
442
  if (excludeSessionId !== void 0) {
442
443
  conditions.push(ne(sessions.id, excludeSessionId));
443
444
  }
444
- return db.select({
445
+ const activeRows = await db.select({
445
446
  id: sessions.id,
446
447
  socketId: sessions.socketId,
447
448
  userId: sessions.userId
448
449
  }).from(sessions).where(and(...conditions));
450
+ return activeRows;
449
451
  },
450
452
  async revokeAllByUserId(userId, excludeSessionId) {
451
453
  const conditions = [eq(sessions.userId, userId), isNull(sessions.revokedAt)];
@@ -455,7 +457,8 @@ function createDrizzleAdapter(db, tables) {
455
457
  await db.update(sessions).set({ revokedAt: /* @__PURE__ */ new Date() }).where(and(...conditions));
456
458
  },
457
459
  async findTwoFaSecretsByUserId(userId) {
458
- return db.select({ twoFaSecret: sessions.twoFaSecret }).from(sessions).where(and(eq(sessions.userId, userId), isNotNull(sessions.twoFaSecret)));
460
+ const secretRows = await db.select({ twoFaSecret: sessions.twoFaSecret }).from(sessions).where(and(eq(sessions.userId, userId), isNotNull(sessions.twoFaSecret)));
461
+ return secretRows;
459
462
  },
460
463
  async clearTwoFaSecrets(userId, excludeSessionId) {
461
464
  const conditions = [eq(sessions.userId, userId)];
@@ -474,10 +477,11 @@ function createDrizzleAdapter(db, tables) {
474
477
  }).from(sessions).leftJoin(devices, eq(sessions.deviceId, devices.id)).where(and(eq(sessions.id, id), eq(sessions.userId, userId))).limit(1);
475
478
  if (!rows[0]) return null;
476
479
  const row = rows[0];
480
+ const device = row.device;
477
481
  return {
478
482
  twoFaSecret: row.twoFaSecret,
479
483
  deviceId: row.deviceId,
480
- device: row.device?.pushToken ? { pushToken: row.device.pushToken } : null
484
+ device: device?.pushToken ? { pushToken: device.pushToken } : null
481
485
  };
482
486
  },
483
487
  async revokeByDevicePushToken(userId, pushToken, excludeSessionId) {
@@ -558,8 +562,8 @@ function createDrizzleAdapter(db, tables) {
558
562
  if (existing[0]) {
559
563
  deviceId = existing[0].id;
560
564
  } else {
561
- const rows = await db.insert(devices).values({ pushToken }).returning({ id: devices.id });
562
- deviceId = rows[0].id;
565
+ const insertedRows = await db.insert(devices).values({ pushToken }).returning({ id: devices.id });
566
+ deviceId = insertedRows[0].id;
563
567
  }
564
568
  if (tables.devicesToSessions) {
565
569
  await db.insert(tables.devicesToSessions).values({ deviceId, sessionId }).onConflictDoNothing();
@@ -571,7 +575,7 @@ function createDrizzleAdapter(db, tables) {
571
575
  },
572
576
  async findByUserAndToken(userId, pushToken) {
573
577
  if (tables.devicesToUsers) {
574
- const rows2 = await db.select({ id: devices.id }).from(devices).innerJoin(
578
+ const joinRows = await db.select({ id: devices.id }).from(devices).innerJoin(
575
579
  tables.devicesToUsers,
576
580
  eq(devices.id, tables.devicesToUsers.deviceId)
577
581
  ).where(
@@ -580,7 +584,7 @@ function createDrizzleAdapter(db, tables) {
580
584
  eq(tables.devicesToUsers.userId, userId)
581
585
  )
582
586
  ).limit(1);
583
- return rows2[0] ? { id: rows2[0].id } : null;
587
+ return joinRows[0] ? { id: joinRows[0].id } : null;
584
588
  }
585
589
  const rows = await db.select({ id: devices.id }).from(devices).where(eq(devices.pushToken, pushToken)).limit(1);
586
590
  return rows[0] ? { id: rows[0].id } : null;
@@ -597,8 +601,8 @@ function createDrizzleAdapter(db, tables) {
597
601
  },
598
602
  async hasRemainingUsers(deviceId) {
599
603
  if (tables.devicesToUsers) {
600
- const rows = await db.select({ userId: tables.devicesToUsers.userId }).from(tables.devicesToUsers).where(eq(tables.devicesToUsers.deviceId, deviceId)).limit(1);
601
- return rows.length > 0;
604
+ const remainingRows = await db.select({ userId: tables.devicesToUsers.userId }).from(tables.devicesToUsers).where(eq(tables.devicesToUsers.deviceId, deviceId)).limit(1);
605
+ return remainingRows.length > 0;
602
606
  }
603
607
  return false;
604
608
  },
@@ -1080,6 +1084,36 @@ function validatePasswordStrength(password, minLength = 6) {
1080
1084
  return { valid: true };
1081
1085
  }
1082
1086
 
1087
+ // src/utilities/session.ts
1088
+ async function createSessionWithToken(config, params) {
1089
+ const { userId, browserName, socketId, deviceId, extraSessionData } = params;
1090
+ const session = await config.database.session.create({
1091
+ userId,
1092
+ browserName,
1093
+ socketId,
1094
+ ...deviceId != null ? { deviceId } : {},
1095
+ ...extraSessionData
1096
+ });
1097
+ const user = await config.database.user.findById(userId);
1098
+ const accessToken = createAuthToken(
1099
+ {
1100
+ id: session.id,
1101
+ userId: session.userId,
1102
+ verifiedHumanAt: user?.verifiedHumanAt ?? null
1103
+ },
1104
+ {
1105
+ secret: config.secrets.jwt,
1106
+ expiresIn: config.tokenSettings.jwtExpiry
1107
+ }
1108
+ );
1109
+ return { accessToken, sessionId: session.id };
1110
+ }
1111
+ async function createSessionWithTokenAndCookie(config, params, res) {
1112
+ const result = await createSessionWithToken(config, params);
1113
+ setAuthCookie(res, result.accessToken, config.cookieSettings, config.storageKeys);
1114
+ return result;
1115
+ }
1116
+
1083
1117
  // src/utilities/totp.ts
1084
1118
  import crypto from "crypto";
1085
1119
  import { TOTP } from "totp-generator";
@@ -1963,13 +1997,15 @@ var TwoFaProcedureFactory = class {
1963
1997
  import { initTRPC } from "@trpc/server";
1964
1998
  import SuperJSON from "superjson";
1965
1999
  import { ZodError } from "zod";
2000
+ function hasStringProp(obj, key) {
2001
+ return typeof obj === "object" && obj !== null && key in obj && typeof obj[key] === "string";
2002
+ }
1966
2003
  function isPrismaConnectionError(error) {
1967
2004
  if (!error || typeof error !== "object") {
1968
2005
  return false;
1969
2006
  }
1970
- const errorCode = error.code;
1971
- if (errorCode && typeof errorCode === "string") {
1972
- const codeMatch = errorCode.match(/^P(\d+)$/);
2007
+ if (hasStringProp(error, "code")) {
2008
+ const codeMatch = error.code.match(/^P(\d+)$/);
1973
2009
  if (codeMatch) {
1974
2010
  const codeNum = parseInt(codeMatch[1], 10);
1975
2011
  if (codeNum >= 1e3 && codeNum <= 1003) {
@@ -1979,14 +2015,13 @@ function isPrismaConnectionError(error) {
1979
2015
  }
1980
2016
  const constructorName = error.constructor?.name || "";
1981
2017
  if (constructorName.includes("Prisma")) {
1982
- const errorMessage = error.message?.toLowerCase() || "";
2018
+ const errorMessage = hasStringProp(error, "message") ? error.message.toLowerCase() : "";
1983
2019
  if (errorMessage.includes("can't reach database") || errorMessage.includes("authentication failed") || errorMessage.includes("database server") || errorMessage.includes("timeout") || errorMessage.includes("connection")) {
1984
2020
  return true;
1985
2021
  }
1986
2022
  }
1987
- const cause = error.cause;
1988
- if (cause) {
1989
- return isPrismaConnectionError(cause);
2023
+ if ("cause" in error) {
2024
+ return isPrismaConnectionError(error.cause);
1990
2025
  }
1991
2026
  return false;
1992
2027
  }
@@ -2032,8 +2067,9 @@ function createBaseProcedure(t, authGuard) {
2032
2067
  }
2033
2068
  function getClientIp(req) {
2034
2069
  const forwarded = req.headers["x-forwarded-for"];
2035
- if (forwarded) {
2036
- return forwarded.split(",")[0]?.trim();
2070
+ const forwardedStr = Array.isArray(forwarded) ? forwarded[0] : forwarded;
2071
+ if (forwardedStr) {
2072
+ return forwardedStr.split(",")[0]?.trim();
2037
2073
  }
2038
2074
  return req.socket.remoteAddress || void 0;
2039
2075
  }
@@ -2051,7 +2087,7 @@ var AuthRouterFactory = class {
2051
2087
  constructor(userConfig) {
2052
2088
  this.userConfig = userConfig;
2053
2089
  this.config = createAuthConfig(this.userConfig);
2054
- this.schemas = createSchemas(this.config.schemaExtensions);
2090
+ this.schemas = createSchemas(this.userConfig.schemaExtensions);
2055
2091
  this.t = createTrpcBuilder(this.config);
2056
2092
  this.authGuard = createAuthGuard(this.config, this.t);
2057
2093
  this.procedure = createBaseProcedure(this.t, this.authGuard);
@@ -2112,6 +2148,8 @@ export {
2112
2148
  createNoopEmailAdapter,
2113
2149
  createOAuthVerifier,
2114
2150
  createPrismaAdapter,
2151
+ createSessionWithToken,
2152
+ createSessionWithTokenAndCookie,
2115
2153
  decodeToken,
2116
2154
  defaultAuthConfig,
2117
2155
  defaultCookieSettings,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@factiii/auth",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -50,26 +50,8 @@
50
50
  "prisma",
51
51
  "README.md"
52
52
  ],
53
- "scripts": {
54
- "build": "tsup",
55
- "dev": "tsup --watch",
56
- "check-types": "tsc --noEmit",
57
- "lint": "eslint src",
58
- "lint:fix": "eslint src --fix",
59
- "format": "prettier --check src",
60
- "format:fix": "prettier --write src",
61
- "test": "vitest run",
62
- "test:watch": "vitest",
63
- "seed": "tsx e2e/seed.ts",
64
- "clean": "rm -rf dist node_modules/.cache .turbo",
65
- "prepublishOnly": "npm run build",
66
- "e2e": "pnpm e2e:db:up && playwright test --reporter=list; pnpm e2e:db:down",
67
- "e2e:ui": "pnpm e2e:db:up && playwright test --ui",
68
- "e2e:db:up": "docker compose -f e2e/docker-compose.yml up -d --wait && prisma generate --schema=e2e/server/schema.prisma --config=e2e/server/prisma.config.ts && prisma migrate reset --schema=e2e/server/schema.prisma --config=e2e/server/prisma.config.ts --force",
69
- "e2e:db:down": "docker compose -f e2e/docker-compose.yml down"
70
- },
71
53
  "dependencies": {
72
- "@trpc/server": "11.8.0",
54
+ "@trpc/server": "^11.8.0",
73
55
  "apple-signin-auth": "^2.0.0",
74
56
  "bcryptjs": "^2.4.3",
75
57
  "google-auth-library": "^10.5.0",
@@ -102,7 +84,7 @@
102
84
  "@prisma/adapter-pg": "^7.3.0",
103
85
  "@prisma/client": "^7.1.0",
104
86
  "@trpc/client": "^11.8.0",
105
- "@trpc/server": "11.8.0",
87
+ "@trpc/server": "^11.8.0",
106
88
  "@types/bcryptjs": "^2.4.6",
107
89
  "@types/better-sqlite3": "^7.6.13",
108
90
  "@types/jsonwebtoken": "^9.0.9",
@@ -133,16 +115,21 @@
133
115
  "engines": {
134
116
  "node": ">=18.0.0"
135
117
  },
136
- "packageManager": "pnpm@10.26.0",
137
- "pnpm": {
138
- "overrides": {
139
- "hono": ">=4.12.7",
140
- "@hono/node-server": ">=1.19.10",
141
- "minimatch": ">=9.0.7",
142
- "lodash": ">=4.17.23",
143
- "flatted": ">=3.4.0",
144
- "rollup": ">=4.59.0",
145
- "ajv": ">=6.14.0"
146
- }
118
+ "scripts": {
119
+ "build": "tsup",
120
+ "dev": "tsup --watch",
121
+ "check-types": "tsc --noEmit",
122
+ "lint": "eslint src",
123
+ "lint:fix": "eslint src --fix",
124
+ "format": "prettier --check src",
125
+ "format:fix": "prettier --write src",
126
+ "test": "vitest run",
127
+ "test:watch": "vitest",
128
+ "seed": "tsx e2e/seed.ts",
129
+ "clean": "rm -rf dist node_modules/.cache .turbo",
130
+ "e2e": "pnpm e2e:db:up && playwright test --reporter=list; pnpm e2e:db:down",
131
+ "e2e:ui": "pnpm e2e:db:up && playwright test --ui",
132
+ "e2e:db:up": "docker compose -f e2e/docker-compose.yml up -d --wait && prisma generate --schema=e2e/server/schema.prisma --config=e2e/server/prisma.config.ts && prisma migrate reset --schema=e2e/server/schema.prisma --config=e2e/server/prisma.config.ts --force",
133
+ "e2e:db:down": "docker compose -f e2e/docker-compose.yml down"
147
134
  }
148
- }
135
+ }